2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: drivers/fs/vfat/finfo.c
5 * PURPOSE: VFAT Filesystem
6 * PROGRAMMER: Jason Filby (jasonfilby@yahoo.com)
7 * Herve Poussineau (reactos@poussine.freesurf.fr)
11 /* INCLUDES *****************************************************************/
16 /* GLOBALS ******************************************************************/
18 const char* FileInformationClassNames
[] =
21 "FileDirectoryInformation",
22 "FileFullDirectoryInformation",
23 "FileBothDirectoryInformation",
24 "FileBasicInformation",
25 "FileStandardInformation",
26 "FileInternalInformation",
28 "FileAccessInformation",
29 "FileNameInformation",
30 "FileRenameInformation",
31 "FileLinkInformation",
32 "FileNamesInformation",
33 "FileDispositionInformation",
34 "FilePositionInformation",
35 "FileFullEaInformation",
36 "FileModeInformation",
37 "FileAlignmentInformation",
39 "FileAllocationInformation",
40 "FileEndOfFileInformation",
41 "FileAlternateNameInformation",
42 "FileStreamInformation",
43 "FilePipeInformation",
44 "FilePipeLocalInformation",
45 "FilePipeRemoteInformation",
46 "FileMailslotQueryInformation",
47 "FileMailslotSetInformation",
48 "FileCompressionInformation",
49 "FileObjectIdInformation",
50 "FileCompletionInformation",
51 "FileMoveClusterInformation",
52 "FileQuotaInformation",
53 "FileReparsePointInformation",
54 "FileNetworkOpenInformation",
55 "FileAttributeTagInformation",
56 "FileTrackingInformation",
57 "FileIdBothDirectoryInformation",
58 "FileIdFullDirectoryInformation",
59 "FileValidDataLengthInformation",
60 "FileShortNameInformation",
61 "FileMaximumInformation"
64 /* FUNCTIONS ****************************************************************/
67 * FUNCTION: Retrieve the standard file information
71 VfatGetStandardInformation(
73 PFILE_STANDARD_INFORMATION StandardInfo
,
76 if (*BufferLength
< sizeof(FILE_STANDARD_INFORMATION
))
77 return STATUS_BUFFER_OVERFLOW
;
80 ASSERT(StandardInfo
!= NULL
);
83 if (vfatFCBIsDirectory(FCB
))
85 StandardInfo
->AllocationSize
.QuadPart
= 0;
86 StandardInfo
->EndOfFile
.QuadPart
= 0;
87 StandardInfo
->Directory
= TRUE
;
91 StandardInfo
->AllocationSize
= FCB
->RFCB
.AllocationSize
;
92 StandardInfo
->EndOfFile
= FCB
->RFCB
.FileSize
;
93 StandardInfo
->Directory
= FALSE
;
95 StandardInfo
->NumberOfLinks
= 1;
96 StandardInfo
->DeletePending
= FCB
->Flags
& FCB_DELETE_PENDING
? TRUE
: FALSE
;
98 *BufferLength
-= sizeof(FILE_STANDARD_INFORMATION
);
99 return STATUS_SUCCESS
;
104 VfatSetPositionInformation(
105 PFILE_OBJECT FileObject
,
106 PFILE_POSITION_INFORMATION PositionInfo
)
108 DPRINT("FsdSetPositionInformation()\n");
110 DPRINT("PositionInfo %p\n", PositionInfo
);
111 DPRINT("Setting position %u\n", PositionInfo
->CurrentByteOffset
.u
.LowPart
);
113 FileObject
->CurrentByteOffset
.QuadPart
=
114 PositionInfo
->CurrentByteOffset
.QuadPart
;
116 return STATUS_SUCCESS
;
121 VfatGetPositionInformation(
122 PFILE_OBJECT FileObject
,
124 PDEVICE_OBJECT DeviceObject
,
125 PFILE_POSITION_INFORMATION PositionInfo
,
128 UNREFERENCED_PARAMETER(FileObject
);
129 UNREFERENCED_PARAMETER(FCB
);
130 UNREFERENCED_PARAMETER(DeviceObject
);
132 DPRINT("VfatGetPositionInformation()\n");
134 if (*BufferLength
< sizeof(FILE_POSITION_INFORMATION
))
135 return STATUS_BUFFER_OVERFLOW
;
137 PositionInfo
->CurrentByteOffset
.QuadPart
=
138 FileObject
->CurrentByteOffset
.QuadPart
;
140 DPRINT("Getting position %I64x\n",
141 PositionInfo
->CurrentByteOffset
.QuadPart
);
143 *BufferLength
-= sizeof(FILE_POSITION_INFORMATION
);
144 return STATUS_SUCCESS
;
149 VfatSetBasicInformation(
150 PFILE_OBJECT FileObject
,
152 PDEVICE_EXTENSION DeviceExt
,
153 PFILE_BASIC_INFORMATION BasicInfo
)
155 DPRINT("VfatSetBasicInformation()\n");
157 ASSERT(NULL
!= FileObject
);
159 ASSERT(NULL
!= DeviceExt
);
160 ASSERT(NULL
!= BasicInfo
);
161 /* Check volume label bit */
162 ASSERT(0 == (*FCB
->Attributes
& _A_VOLID
));
164 if (FCB
->Flags
& FCB_IS_FATX_ENTRY
)
166 if (BasicInfo
->CreationTime
.QuadPart
!= 0 && BasicInfo
->CreationTime
.QuadPart
!= -1)
168 FsdSystemTimeToDosDateTime(DeviceExt
,
169 &BasicInfo
->CreationTime
,
170 &FCB
->entry
.FatX
.CreationDate
,
171 &FCB
->entry
.FatX
.CreationTime
);
174 if (BasicInfo
->LastAccessTime
.QuadPart
!= 0 && BasicInfo
->LastAccessTime
.QuadPart
!= -1)
176 FsdSystemTimeToDosDateTime(DeviceExt
,
177 &BasicInfo
->LastAccessTime
,
178 &FCB
->entry
.FatX
.AccessDate
,
179 &FCB
->entry
.FatX
.AccessTime
);
182 if (BasicInfo
->LastWriteTime
.QuadPart
!= 0 && BasicInfo
->LastWriteTime
.QuadPart
!= -1)
184 FsdSystemTimeToDosDateTime(DeviceExt
,
185 &BasicInfo
->LastWriteTime
,
186 &FCB
->entry
.FatX
.UpdateDate
,
187 &FCB
->entry
.FatX
.UpdateTime
);
192 if (BasicInfo
->CreationTime
.QuadPart
!= 0 && BasicInfo
->CreationTime
.QuadPart
!= -1)
194 FsdSystemTimeToDosDateTime(DeviceExt
,
195 &BasicInfo
->CreationTime
,
196 &FCB
->entry
.Fat
.CreationDate
,
197 &FCB
->entry
.Fat
.CreationTime
);
200 if (BasicInfo
->LastAccessTime
.QuadPart
!= 0 && BasicInfo
->LastAccessTime
.QuadPart
!= -1)
202 FsdSystemTimeToDosDateTime(DeviceExt
,
203 &BasicInfo
->LastAccessTime
,
204 &FCB
->entry
.Fat
.AccessDate
,
208 if (BasicInfo
->LastWriteTime
.QuadPart
!= 0 && BasicInfo
->LastWriteTime
.QuadPart
!= -1)
210 FsdSystemTimeToDosDateTime(DeviceExt
,
211 &BasicInfo
->LastWriteTime
,
212 &FCB
->entry
.Fat
.UpdateDate
,
213 &FCB
->entry
.Fat
.UpdateTime
);
217 if (BasicInfo
->FileAttributes
)
219 *FCB
->Attributes
= (unsigned char)((*FCB
->Attributes
&
220 (FILE_ATTRIBUTE_DIRECTORY
| 0x48)) |
221 (BasicInfo
->FileAttributes
&
222 (FILE_ATTRIBUTE_ARCHIVE
|
223 FILE_ATTRIBUTE_SYSTEM
|
224 FILE_ATTRIBUTE_HIDDEN
|
225 FILE_ATTRIBUTE_READONLY
)));
226 DPRINT("Setting attributes 0x%02x\n", *FCB
->Attributes
);
229 VfatUpdateEntry(FCB
);
231 return STATUS_SUCCESS
;
236 VfatGetBasicInformation(
237 PFILE_OBJECT FileObject
,
239 PDEVICE_OBJECT DeviceObject
,
240 PFILE_BASIC_INFORMATION BasicInfo
,
243 PDEVICE_EXTENSION DeviceExt
;
245 UNREFERENCED_PARAMETER(FileObject
);
247 DPRINT("VfatGetBasicInformation()\n");
249 DeviceExt
= (PDEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
251 if (*BufferLength
< sizeof(FILE_BASIC_INFORMATION
))
252 return STATUS_BUFFER_OVERFLOW
;
254 if (FCB
->Flags
& FCB_IS_FATX_ENTRY
)
256 FsdDosDateTimeToSystemTime(DeviceExt
,
257 FCB
->entry
.FatX
.CreationDate
,
258 FCB
->entry
.FatX
.CreationTime
,
259 &BasicInfo
->CreationTime
);
260 FsdDosDateTimeToSystemTime(DeviceExt
,
261 FCB
->entry
.FatX
.AccessDate
,
262 FCB
->entry
.FatX
.AccessTime
,
263 &BasicInfo
->LastAccessTime
);
264 FsdDosDateTimeToSystemTime(DeviceExt
,
265 FCB
->entry
.FatX
.UpdateDate
,
266 FCB
->entry
.FatX
.UpdateTime
,
267 &BasicInfo
->LastWriteTime
);
268 BasicInfo
->ChangeTime
= BasicInfo
->LastWriteTime
;
272 FsdDosDateTimeToSystemTime(DeviceExt
,
273 FCB
->entry
.Fat
.CreationDate
,
274 FCB
->entry
.Fat
.CreationTime
,
275 &BasicInfo
->CreationTime
);
276 FsdDosDateTimeToSystemTime(DeviceExt
,
277 FCB
->entry
.Fat
.AccessDate
,
279 &BasicInfo
->LastAccessTime
);
280 FsdDosDateTimeToSystemTime(DeviceExt
,
281 FCB
->entry
.Fat
.UpdateDate
,
282 FCB
->entry
.Fat
.UpdateTime
,
283 &BasicInfo
->LastWriteTime
);
284 BasicInfo
->ChangeTime
= BasicInfo
->LastWriteTime
;
287 BasicInfo
->FileAttributes
= *FCB
->Attributes
& 0x3f;
288 /* Synthesize FILE_ATTRIBUTE_NORMAL */
289 if (0 == (BasicInfo
->FileAttributes
& (FILE_ATTRIBUTE_DIRECTORY
|
290 FILE_ATTRIBUTE_ARCHIVE
|
291 FILE_ATTRIBUTE_SYSTEM
|
292 FILE_ATTRIBUTE_HIDDEN
|
293 FILE_ATTRIBUTE_READONLY
)))
295 DPRINT("Synthesizing FILE_ATTRIBUTE_NORMAL\n");
296 BasicInfo
->FileAttributes
|= FILE_ATTRIBUTE_NORMAL
;
298 DPRINT("Getting attributes 0x%02x\n", BasicInfo
->FileAttributes
);
300 *BufferLength
-= sizeof(FILE_BASIC_INFORMATION
);
301 return STATUS_SUCCESS
;
307 VfatSetDispositionInformation(
308 PFILE_OBJECT FileObject
,
310 PDEVICE_OBJECT DeviceObject
,
311 PFILE_DISPOSITION_INFORMATION DispositionInfo
)
314 PDEVICE_EXTENSION DeviceExt
= DeviceObject
->DeviceExtension
;
317 DPRINT("FsdSetDispositionInformation(<%wZ>, Delete %u)\n", &FCB
->PathNameU
, DispositionInfo
->DeleteFile
);
319 ASSERT(DeviceExt
!= NULL
);
320 ASSERT(DeviceExt
->FatInfo
.BytesPerCluster
!= 0);
323 if (!DispositionInfo
->DeleteFile
)
325 /* undelete the file */
326 FCB
->Flags
&= ~FCB_DELETE_PENDING
;
327 FileObject
->DeletePending
= FALSE
;
328 return STATUS_SUCCESS
;
331 if (FCB
->Flags
& FCB_DELETE_PENDING
)
333 /* stream already marked for deletion. just update the file object */
334 FileObject
->DeletePending
= TRUE
;
335 return STATUS_SUCCESS
;
338 if (*FCB
->Attributes
& FILE_ATTRIBUTE_READONLY
)
340 return STATUS_CANNOT_DELETE
;
343 if (vfatFCBIsRoot(FCB
) ||
344 (FCB
->LongNameU
.Length
== sizeof(WCHAR
) && FCB
->LongNameU
.Buffer
[0] == L
'.') ||
345 (FCB
->LongNameU
.Length
== 2 * sizeof(WCHAR
) && FCB
->LongNameU
.Buffer
[0] == L
'.' && FCB
->LongNameU
.Buffer
[1] == L
'.'))
347 // we cannot delete a '.', '..' or the root directory
348 return STATUS_ACCESS_DENIED
;
352 if (!MmFlushImageSection (FileObject
->SectionObjectPointer
, MmFlushForDelete
))
354 /* can't delete a file if its mapped into a process */
356 DPRINT("MmFlushImageSection returned FALSE\n");
357 return STATUS_CANNOT_DELETE
;
360 if (vfatFCBIsDirectory(FCB
) && !VfatIsDirectoryEmpty(FCB
))
362 /* can't delete a non-empty directory */
364 return STATUS_DIRECTORY_NOT_EMPTY
;
368 FCB
->Flags
|= FCB_DELETE_PENDING
;
369 FileObject
->DeletePending
= TRUE
;
371 return STATUS_SUCCESS
;
375 * FUNCTION: Retrieve the file name information
379 VfatGetNameInformation(
380 PFILE_OBJECT FileObject
,
382 PDEVICE_OBJECT DeviceObject
,
383 PFILE_NAME_INFORMATION NameInfo
,
388 UNREFERENCED_PARAMETER(FileObject
);
389 UNREFERENCED_PARAMETER(DeviceObject
);
391 ASSERT(NameInfo
!= NULL
);
394 /* If buffer can't hold at least the file name length, bail out */
395 if (*BufferLength
< (ULONG
)FIELD_OFFSET(FILE_NAME_INFORMATION
, FileName
[0]))
396 return STATUS_BUFFER_OVERFLOW
;
398 /* Save file name length, and as much file len, as buffer length allows */
399 NameInfo
->FileNameLength
= FCB
->PathNameU
.Length
;
401 /* Calculate amount of bytes to copy not to overflow the buffer */
402 BytesToCopy
= min(FCB
->PathNameU
.Length
,
403 *BufferLength
- FIELD_OFFSET(FILE_NAME_INFORMATION
, FileName
[0]));
405 /* Fill in the bytes */
406 RtlCopyMemory(NameInfo
->FileName
, FCB
->PathNameU
.Buffer
, BytesToCopy
);
408 /* Check if we could write more but are not able to */
409 if (*BufferLength
< FCB
->PathNameU
.Length
+ (ULONG
)FIELD_OFFSET(FILE_NAME_INFORMATION
, FileName
[0]))
411 /* Return number of bytes written */
412 *BufferLength
-= FIELD_OFFSET(FILE_NAME_INFORMATION
, FileName
[0]) + BytesToCopy
;
413 return STATUS_BUFFER_OVERFLOW
;
416 /* We filled up as many bytes, as needed */
417 *BufferLength
-= (FIELD_OFFSET(FILE_NAME_INFORMATION
, FileName
[0]) + FCB
->PathNameU
.Length
);
419 return STATUS_SUCCESS
;
424 VfatGetInternalInformation(
426 PFILE_INTERNAL_INFORMATION InternalInfo
,
429 ASSERT(InternalInfo
);
432 if (*BufferLength
< sizeof(FILE_INTERNAL_INFORMATION
))
433 return STATUS_BUFFER_OVERFLOW
;
434 // FIXME: get a real index, that can be used in a create operation
435 InternalInfo
->IndexNumber
.QuadPart
= 0;
436 *BufferLength
-= sizeof(FILE_INTERNAL_INFORMATION
);
437 return STATUS_SUCCESS
;
442 * FUNCTION: Retrieve the file network open information
446 VfatGetNetworkOpenInformation(
448 PDEVICE_EXTENSION DeviceExt
,
449 PFILE_NETWORK_OPEN_INFORMATION NetworkInfo
,
455 if (*BufferLength
< sizeof(FILE_NETWORK_OPEN_INFORMATION
))
456 return(STATUS_BUFFER_OVERFLOW
);
458 if (Fcb
->Flags
& FCB_IS_FATX_ENTRY
)
460 FsdDosDateTimeToSystemTime(DeviceExt
,
461 Fcb
->entry
.FatX
.CreationDate
,
462 Fcb
->entry
.FatX
.CreationTime
,
463 &NetworkInfo
->CreationTime
);
464 FsdDosDateTimeToSystemTime(DeviceExt
,
465 Fcb
->entry
.FatX
.AccessDate
,
466 Fcb
->entry
.FatX
.AccessTime
,
467 &NetworkInfo
->LastAccessTime
);
468 FsdDosDateTimeToSystemTime(DeviceExt
,
469 Fcb
->entry
.FatX
.UpdateDate
,
470 Fcb
->entry
.FatX
.UpdateTime
,
471 &NetworkInfo
->LastWriteTime
);
472 NetworkInfo
->ChangeTime
.QuadPart
= NetworkInfo
->LastWriteTime
.QuadPart
;
476 FsdDosDateTimeToSystemTime(DeviceExt
,
477 Fcb
->entry
.Fat
.CreationDate
,
478 Fcb
->entry
.Fat
.CreationTime
,
479 &NetworkInfo
->CreationTime
);
480 FsdDosDateTimeToSystemTime(DeviceExt
,
481 Fcb
->entry
.Fat
.AccessDate
,
483 &NetworkInfo
->LastAccessTime
);
484 FsdDosDateTimeToSystemTime(DeviceExt
,
485 Fcb
->entry
.Fat
.UpdateDate
,
486 Fcb
->entry
.Fat
.UpdateTime
,
487 &NetworkInfo
->LastWriteTime
);
488 NetworkInfo
->ChangeTime
.QuadPart
= NetworkInfo
->LastWriteTime
.QuadPart
;
491 if (vfatFCBIsDirectory(Fcb
))
493 NetworkInfo
->EndOfFile
.QuadPart
= 0L;
494 NetworkInfo
->AllocationSize
.QuadPart
= 0L;
498 NetworkInfo
->AllocationSize
= Fcb
->RFCB
.AllocationSize
;
499 NetworkInfo
->EndOfFile
= Fcb
->RFCB
.FileSize
;
502 NetworkInfo
->FileAttributes
= *Fcb
->Attributes
& 0x3f;
503 /* Synthesize FILE_ATTRIBUTE_NORMAL */
504 if (0 == (NetworkInfo
->FileAttributes
& (FILE_ATTRIBUTE_DIRECTORY
|
505 FILE_ATTRIBUTE_ARCHIVE
|
506 FILE_ATTRIBUTE_SYSTEM
|
507 FILE_ATTRIBUTE_HIDDEN
|
508 FILE_ATTRIBUTE_READONLY
)))
510 DPRINT("Synthesizing FILE_ATTRIBUTE_NORMAL\n");
511 NetworkInfo
->FileAttributes
|= FILE_ATTRIBUTE_NORMAL
;
514 *BufferLength
-= sizeof(FILE_NETWORK_OPEN_INFORMATION
);
515 return STATUS_SUCCESS
;
521 VfatGetEaInformation(
522 PFILE_OBJECT FileObject
,
524 PDEVICE_OBJECT DeviceObject
,
525 PFILE_EA_INFORMATION Info
,
528 PDEVICE_EXTENSION DeviceExt
= DeviceObject
->DeviceExtension
;
530 UNREFERENCED_PARAMETER(FileObject
);
531 UNREFERENCED_PARAMETER(Fcb
);
533 /* FIXME - use SEH to access the buffer! */
535 *BufferLength
-= sizeof(*Info
);
536 if (DeviceExt
->FatInfo
.FatType
== FAT12
||
537 DeviceExt
->FatInfo
.FatType
== FAT16
)
540 DPRINT1("VFAT: FileEaInformation not implemented!\n");
542 return STATUS_SUCCESS
;
547 * FUNCTION: Retrieve the all file information
551 VfatGetAllInformation(
552 PFILE_OBJECT FileObject
,
554 PDEVICE_OBJECT DeviceObject
,
555 PFILE_ALL_INFORMATION Info
,
559 ULONG InitialBufferLength
= *BufferLength
;
564 if (*BufferLength
< sizeof(FILE_ALL_INFORMATION
) + Fcb
->PathNameU
.Length
+ sizeof(WCHAR
))
565 return(STATUS_BUFFER_OVERFLOW
);
567 /* Basic Information */
568 Status
= VfatGetBasicInformation(FileObject
, Fcb
, DeviceObject
, &Info
->BasicInformation
, BufferLength
);
569 if (!NT_SUCCESS(Status
)) return Status
;
570 /* Standard Information */
571 Status
= VfatGetStandardInformation(Fcb
, &Info
->StandardInformation
, BufferLength
);
572 if (!NT_SUCCESS(Status
)) return Status
;
573 /* Internal Information */
574 Status
= VfatGetInternalInformation(Fcb
, &Info
->InternalInformation
, BufferLength
);
575 if (!NT_SUCCESS(Status
)) return Status
;
577 Info
->EaInformation
.EaSize
= 0;
578 /* Access Information: The IO-Manager adds this information */
579 /* Position Information */
580 Status
= VfatGetPositionInformation(FileObject
, Fcb
, DeviceObject
, &Info
->PositionInformation
, BufferLength
);
581 if (!NT_SUCCESS(Status
)) return Status
;
582 /* Mode Information: The IO-Manager adds this information */
583 /* Alignment Information: The IO-Manager adds this information */
584 /* Name Information */
585 Status
= VfatGetNameInformation(FileObject
, Fcb
, DeviceObject
, &Info
->NameInformation
, BufferLength
);
586 if (!NT_SUCCESS(Status
)) return Status
;
588 *BufferLength
= InitialBufferLength
- (sizeof(FILE_ALL_INFORMATION
) + Fcb
->PathNameU
.Length
+ sizeof(WCHAR
));
590 return STATUS_SUCCESS
;
596 PFILE_OBJECT FileObject
,
603 Fcb
->RFCB
.AllocationSize
.QuadPart
= ROUND_UP(Size
, ClusterSize
);
607 Fcb
->RFCB
.AllocationSize
.QuadPart
= (LONGLONG
)0;
609 if (!vfatFCBIsDirectory(Fcb
))
611 if (Fcb
->Flags
& FCB_IS_FATX_ENTRY
)
612 Fcb
->entry
.FatX
.FileSize
= Size
;
614 Fcb
->entry
.Fat
.FileSize
= Size
;
616 Fcb
->RFCB
.FileSize
.QuadPart
= Size
;
617 Fcb
->RFCB
.ValidDataLength
.QuadPart
= Size
;
619 CcSetFileSizes(FileObject
, (PCC_FILE_SIZES
)&Fcb
->RFCB
.AllocationSize
);
623 VfatSetAllocationSizeInformation(
624 PFILE_OBJECT FileObject
,
626 PDEVICE_EXTENSION DeviceExt
,
627 PLARGE_INTEGER AllocationSize
)
630 ULONG Cluster
, FirstCluster
;
633 ULONG ClusterSize
= DeviceExt
->FatInfo
.BytesPerCluster
;
634 ULONG NewSize
= AllocationSize
->u
.LowPart
;
636 BOOLEAN AllocSizeChanged
= FALSE
;
638 DPRINT("VfatSetAllocationSizeInformation(File <%wZ>, AllocationSize %d %u)\n",
639 &Fcb
->PathNameU
, AllocationSize
->HighPart
, AllocationSize
->LowPart
);
641 if (Fcb
->Flags
& FCB_IS_FATX_ENTRY
)
642 OldSize
= Fcb
->entry
.FatX
.FileSize
;
644 OldSize
= Fcb
->entry
.Fat
.FileSize
;
646 if (AllocationSize
->u
.HighPart
> 0)
648 return STATUS_INVALID_PARAMETER
;
651 if (OldSize
== NewSize
)
653 return STATUS_SUCCESS
;
656 FirstCluster
= vfatDirEntryGetFirstCluster(DeviceExt
, &Fcb
->entry
);
658 if (NewSize
> Fcb
->RFCB
.AllocationSize
.u
.LowPart
)
660 AllocSizeChanged
= TRUE
;
661 if (FirstCluster
== 0)
663 Fcb
->LastCluster
= Fcb
->LastOffset
= 0;
664 Status
= NextCluster(DeviceExt
, FirstCluster
, &FirstCluster
, TRUE
);
665 if (!NT_SUCCESS(Status
))
667 DPRINT1("NextCluster failed. Status = %x\n", Status
);
671 if (FirstCluster
== 0xffffffff)
673 return STATUS_DISK_FULL
;
676 Status
= OffsetToCluster(DeviceExt
, FirstCluster
,
677 ROUND_DOWN(NewSize
- 1, ClusterSize
),
679 if (NCluster
== 0xffffffff || !NT_SUCCESS(Status
))
682 NCluster
= Cluster
= FirstCluster
;
683 Status
= STATUS_SUCCESS
;
684 while (NT_SUCCESS(Status
) && Cluster
!= 0xffffffff && Cluster
> 1)
686 Status
= NextCluster(DeviceExt
, FirstCluster
, &NCluster
, FALSE
);
687 WriteCluster(DeviceExt
, Cluster
, 0);
690 return STATUS_DISK_FULL
;
693 if (Fcb
->Flags
& FCB_IS_FATX_ENTRY
)
695 Fcb
->entry
.FatX
.FirstCluster
= FirstCluster
;
699 if (DeviceExt
->FatInfo
.FatType
== FAT32
)
701 Fcb
->entry
.Fat
.FirstCluster
= (unsigned short)(FirstCluster
& 0x0000FFFF);
702 Fcb
->entry
.Fat
.FirstClusterHigh
= FirstCluster
>> 16;
706 ASSERT((FirstCluster
>> 16) == 0);
707 Fcb
->entry
.Fat
.FirstCluster
= (unsigned short)(FirstCluster
& 0x0000FFFF);
713 if (Fcb
->LastCluster
> 0)
715 if (Fcb
->RFCB
.AllocationSize
.u
.LowPart
- ClusterSize
== Fcb
->LastOffset
)
717 Cluster
= Fcb
->LastCluster
;
718 Status
= STATUS_SUCCESS
;
722 Status
= OffsetToCluster(DeviceExt
, Fcb
->LastCluster
,
723 Fcb
->RFCB
.AllocationSize
.u
.LowPart
- ClusterSize
- Fcb
->LastOffset
,
729 Status
= OffsetToCluster(DeviceExt
, FirstCluster
,
730 Fcb
->RFCB
.AllocationSize
.u
.LowPart
- ClusterSize
,
734 if (!NT_SUCCESS(Status
))
739 Fcb
->LastCluster
= Cluster
;
740 Fcb
->LastOffset
= Fcb
->RFCB
.AllocationSize
.u
.LowPart
- ClusterSize
;
742 /* FIXME: Check status */
743 /* Cluster points now to the last cluster within the chain */
744 Status
= OffsetToCluster(DeviceExt
, Cluster
,
745 ROUND_DOWN(NewSize
- 1, ClusterSize
) - Fcb
->LastOffset
,
747 if (NCluster
== 0xffffffff || !NT_SUCCESS(Status
))
751 Status
= NextCluster(DeviceExt
, FirstCluster
, &NCluster
, FALSE
);
752 WriteCluster(DeviceExt
, Cluster
, 0xffffffff);
754 while (NT_SUCCESS(Status
) && Cluster
!= 0xffffffff && Cluster
> 1)
756 Status
= NextCluster(DeviceExt
, FirstCluster
, &NCluster
, FALSE
);
757 WriteCluster(DeviceExt
, Cluster
, 0);
760 return STATUS_DISK_FULL
;
763 UpdateFileSize(FileObject
, Fcb
, NewSize
, ClusterSize
);
765 else if (NewSize
+ ClusterSize
<= Fcb
->RFCB
.AllocationSize
.u
.LowPart
)
767 DPRINT("Check for the ability to set file size\n");
768 if (!MmCanFileBeTruncated(FileObject
->SectionObjectPointer
,
769 (PLARGE_INTEGER
)AllocationSize
))
771 DPRINT("Couldn't set file size!\n");
772 return STATUS_USER_MAPPED_FILE
;
774 DPRINT("Can set file size\n");
776 AllocSizeChanged
= TRUE
;
777 /* FIXME: Use the cached cluster/offset better way. */
778 Fcb
->LastCluster
= Fcb
->LastOffset
= 0;
779 UpdateFileSize(FileObject
, Fcb
, NewSize
, ClusterSize
);
782 Status
= OffsetToCluster(DeviceExt
, FirstCluster
,
783 ROUND_DOWN(NewSize
- 1, ClusterSize
),
787 Status
= NextCluster(DeviceExt
, FirstCluster
, &NCluster
, FALSE
);
788 WriteCluster(DeviceExt
, Cluster
, 0xffffffff);
793 if (Fcb
->Flags
& FCB_IS_FATX_ENTRY
)
795 Fcb
->entry
.FatX
.FirstCluster
= 0;
799 if (DeviceExt
->FatInfo
.FatType
== FAT32
)
801 Fcb
->entry
.Fat
.FirstCluster
= 0;
802 Fcb
->entry
.Fat
.FirstClusterHigh
= 0;
806 Fcb
->entry
.Fat
.FirstCluster
= 0;
810 NCluster
= Cluster
= FirstCluster
;
811 Status
= STATUS_SUCCESS
;
814 while (NT_SUCCESS(Status
) && 0xffffffff != Cluster
&& Cluster
> 1)
816 Status
= NextCluster(DeviceExt
, FirstCluster
, &NCluster
, FALSE
);
817 WriteCluster(DeviceExt
, Cluster
, 0);
823 UpdateFileSize(FileObject
, Fcb
, NewSize
, ClusterSize
);
826 /* Update the on-disk directory entry */
827 Fcb
->Flags
|= FCB_IS_DIRTY
;
828 if (AllocSizeChanged
)
830 VfatUpdateEntry(Fcb
);
832 return STATUS_SUCCESS
;
836 * FUNCTION: Retrieve the specified file information
839 VfatQueryInformation(
840 PVFAT_IRP_CONTEXT IrpContext
)
842 FILE_INFORMATION_CLASS FileInformationClass
;
845 NTSTATUS Status
= STATUS_SUCCESS
;
853 FileInformationClass
= IrpContext
->Stack
->Parameters
.QueryFile
.FileInformationClass
;
854 FCB
= (PVFATFCB
) IrpContext
->FileObject
->FsContext
;
856 DPRINT("VfatQueryInformation is called for '%s'\n",
857 FileInformationClass
>= FileMaximumInformation
- 1 ? "????" : FileInformationClassNames
[FileInformationClass
]);
860 SystemBuffer
= IrpContext
->Irp
->AssociatedIrp
.SystemBuffer
;
861 BufferLength
= IrpContext
->Stack
->Parameters
.QueryFile
.Length
;
863 if (!(FCB
->Flags
& FCB_IS_PAGE_FILE
))
865 if (!ExAcquireResourceSharedLite(&FCB
->MainResource
,
866 (BOOLEAN
)(IrpContext
->Flags
& IRPCONTEXT_CANWAIT
)))
868 return VfatQueueRequest(IrpContext
);
872 switch (FileInformationClass
)
874 case FileStandardInformation
:
875 Status
= VfatGetStandardInformation(FCB
,
880 case FilePositionInformation
:
881 Status
= VfatGetPositionInformation(IrpContext
->FileObject
,
883 IrpContext
->DeviceObject
,
888 case FileBasicInformation
:
889 Status
= VfatGetBasicInformation(IrpContext
->FileObject
,
891 IrpContext
->DeviceObject
,
896 case FileNameInformation
:
897 Status
= VfatGetNameInformation(IrpContext
->FileObject
,
899 IrpContext
->DeviceObject
,
904 case FileInternalInformation
:
905 Status
= VfatGetInternalInformation(FCB
,
910 case FileNetworkOpenInformation
:
911 Status
= VfatGetNetworkOpenInformation(FCB
,
912 IrpContext
->DeviceExt
,
917 case FileAllInformation
:
918 Status
= VfatGetAllInformation(IrpContext
->FileObject
,
920 IrpContext
->DeviceObject
,
925 case FileEaInformation
:
926 Status
= VfatGetEaInformation(IrpContext
->FileObject
,
928 IrpContext
->DeviceObject
,
933 case FileAlternateNameInformation
:
934 Status
= STATUS_NOT_IMPLEMENTED
;
938 Status
= STATUS_INVALID_PARAMETER
;
941 if (!(FCB
->Flags
& FCB_IS_PAGE_FILE
))
943 ExReleaseResourceLite(&FCB
->MainResource
);
946 IrpContext
->Irp
->IoStatus
.Status
= Status
;
947 if (NT_SUCCESS(Status
) || Status
== STATUS_BUFFER_OVERFLOW
)
948 IrpContext
->Irp
->IoStatus
.Information
=
949 IrpContext
->Stack
->Parameters
.QueryFile
.Length
- BufferLength
;
951 IrpContext
->Irp
->IoStatus
.Information
= 0;
952 IoCompleteRequest(IrpContext
->Irp
, IO_NO_INCREMENT
);
953 VfatFreeIrpContext(IrpContext
);
959 * FUNCTION: Retrieve the specified file information
963 PVFAT_IRP_CONTEXT IrpContext
)
965 FILE_INFORMATION_CLASS FileInformationClass
;
967 NTSTATUS Status
= STATUS_SUCCESS
;
973 DPRINT("VfatSetInformation(IrpContext %p)\n", IrpContext
);
976 FileInformationClass
=
977 IrpContext
->Stack
->Parameters
.SetFile
.FileInformationClass
;
978 FCB
= (PVFATFCB
) IrpContext
->FileObject
->FsContext
;
979 SystemBuffer
= IrpContext
->Irp
->AssociatedIrp
.SystemBuffer
;
981 DPRINT("VfatSetInformation is called for '%s'\n",
982 FileInformationClass
>= FileMaximumInformation
- 1 ? "????" : FileInformationClassNames
[ FileInformationClass
]);
984 DPRINT("FileInformationClass %d\n", FileInformationClass
);
985 DPRINT("SystemBuffer %p\n", SystemBuffer
);
987 /* Special: We should call MmCanFileBeTruncated here to determine if changing
988 the file size would be allowed. If not, we bail with the right error.
989 We must do this before acquiring the lock. */
990 if (FileInformationClass
== FileEndOfFileInformation
)
992 DPRINT("Check for the ability to set file size\n");
993 if (!MmCanFileBeTruncated(IrpContext
->FileObject
->SectionObjectPointer
,
994 (PLARGE_INTEGER
)SystemBuffer
))
996 DPRINT("Couldn't set file size!\n");
997 IrpContext
->Irp
->IoStatus
.Status
= STATUS_USER_MAPPED_FILE
;
998 IrpContext
->Irp
->IoStatus
.Information
= 0;
999 IoCompleteRequest(IrpContext
->Irp
, IO_NO_INCREMENT
);
1000 VfatFreeIrpContext(IrpContext
);
1001 return STATUS_USER_MAPPED_FILE
;
1003 DPRINT("Can set file size\n");
1006 if (!(FCB
->Flags
& FCB_IS_PAGE_FILE
))
1008 if (!ExAcquireResourceExclusiveLite(&FCB
->MainResource
,
1009 (BOOLEAN
)(IrpContext
->Flags
& IRPCONTEXT_CANWAIT
)))
1011 return VfatQueueRequest(IrpContext
);
1015 switch (FileInformationClass
)
1017 case FilePositionInformation
:
1018 Status
= VfatSetPositionInformation(IrpContext
->FileObject
,
1022 case FileDispositionInformation
:
1023 Status
= VfatSetDispositionInformation(IrpContext
->FileObject
,
1025 IrpContext
->DeviceObject
,
1029 case FileAllocationInformation
:
1030 case FileEndOfFileInformation
:
1031 Status
= VfatSetAllocationSizeInformation(IrpContext
->FileObject
,
1033 IrpContext
->DeviceExt
,
1034 (PLARGE_INTEGER
)SystemBuffer
);
1037 case FileBasicInformation
:
1038 Status
= VfatSetBasicInformation(IrpContext
->FileObject
,
1040 IrpContext
->DeviceExt
,
1044 case FileRenameInformation
:
1045 Status
= STATUS_NOT_IMPLEMENTED
;
1049 Status
= STATUS_NOT_SUPPORTED
;
1052 if (!(FCB
->Flags
& FCB_IS_PAGE_FILE
))
1054 ExReleaseResourceLite(&FCB
->MainResource
);
1057 IrpContext
->Irp
->IoStatus
.Status
= Status
;
1058 IrpContext
->Irp
->IoStatus
.Information
= 0;
1059 IoCompleteRequest(IrpContext
->Irp
, IO_NO_INCREMENT
);
1060 VfatFreeIrpContext(IrpContext
);