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 VfatGetStandardInformation(PVFATFCB FCB
,
68 PFILE_STANDARD_INFORMATION StandardInfo
,
71 * FUNCTION: Retrieve the standard file information
75 if (*BufferLength
< sizeof(FILE_STANDARD_INFORMATION
))
76 return STATUS_BUFFER_OVERFLOW
;
79 ASSERT(StandardInfo
!= NULL
);
82 if (vfatFCBIsDirectory(FCB
))
84 StandardInfo
->AllocationSize
.QuadPart
= 0;
85 StandardInfo
->EndOfFile
.QuadPart
= 0;
86 StandardInfo
->Directory
= TRUE
;
90 StandardInfo
->AllocationSize
= FCB
->RFCB
.AllocationSize
;
91 StandardInfo
->EndOfFile
= FCB
->RFCB
.FileSize
;
92 StandardInfo
->Directory
= FALSE
;
94 StandardInfo
->NumberOfLinks
= 1;
95 StandardInfo
->DeletePending
= FCB
->Flags
& FCB_DELETE_PENDING
? TRUE
: FALSE
;
97 *BufferLength
-= sizeof(FILE_STANDARD_INFORMATION
);
98 return(STATUS_SUCCESS
);
102 VfatSetPositionInformation(PFILE_OBJECT FileObject
,
103 PFILE_POSITION_INFORMATION PositionInfo
)
105 DPRINT ("FsdSetPositionInformation()\n");
107 DPRINT ("PositionInfo %p\n", PositionInfo
);
108 DPRINT ("Setting position %d\n", PositionInfo
->CurrentByteOffset
.u
.LowPart
);
110 FileObject
->CurrentByteOffset
.QuadPart
=
111 PositionInfo
->CurrentByteOffset
.QuadPart
;
113 return (STATUS_SUCCESS
);
117 VfatGetPositionInformation(PFILE_OBJECT FileObject
,
119 PDEVICE_OBJECT DeviceObject
,
120 PFILE_POSITION_INFORMATION PositionInfo
,
123 UNREFERENCED_PARAMETER(FileObject
);
124 UNREFERENCED_PARAMETER(FCB
);
125 UNREFERENCED_PARAMETER(DeviceObject
);
127 DPRINT ("VfatGetPositionInformation()\n");
129 if (*BufferLength
< sizeof(FILE_POSITION_INFORMATION
))
130 return STATUS_BUFFER_OVERFLOW
;
132 PositionInfo
->CurrentByteOffset
.QuadPart
=
133 FileObject
->CurrentByteOffset
.QuadPart
;
135 DPRINT("Getting position %I64x\n",
136 PositionInfo
->CurrentByteOffset
.QuadPart
);
138 *BufferLength
-= sizeof(FILE_POSITION_INFORMATION
);
139 return(STATUS_SUCCESS
);
143 VfatSetBasicInformation(PFILE_OBJECT FileObject
,
145 PDEVICE_EXTENSION DeviceExt
,
146 PFILE_BASIC_INFORMATION BasicInfo
)
148 DPRINT("VfatSetBasicInformation()\n");
150 ASSERT(NULL
!= FileObject
);
152 ASSERT(NULL
!= DeviceExt
);
153 ASSERT(NULL
!= BasicInfo
);
154 /* Check volume label bit */
155 ASSERT(0 == (*FCB
->Attributes
& _A_VOLID
));
157 if (FCB
->Flags
& FCB_IS_FATX_ENTRY
)
159 FsdSystemTimeToDosDateTime(DeviceExt
,
160 &BasicInfo
->CreationTime
,
161 &FCB
->entry
.FatX
.CreationDate
,
162 &FCB
->entry
.FatX
.CreationTime
);
163 FsdSystemTimeToDosDateTime(DeviceExt
,
164 &BasicInfo
->LastAccessTime
,
165 &FCB
->entry
.FatX
.AccessDate
,
166 &FCB
->entry
.FatX
.AccessTime
);
167 FsdSystemTimeToDosDateTime(DeviceExt
,
168 &BasicInfo
->LastWriteTime
,
169 &FCB
->entry
.FatX
.UpdateDate
,
170 &FCB
->entry
.FatX
.UpdateTime
);
174 FsdSystemTimeToDosDateTime(DeviceExt
,
175 &BasicInfo
->CreationTime
,
176 &FCB
->entry
.Fat
.CreationDate
,
177 &FCB
->entry
.Fat
.CreationTime
);
178 FsdSystemTimeToDosDateTime(DeviceExt
,
179 &BasicInfo
->LastAccessTime
,
180 &FCB
->entry
.Fat
.AccessDate
,
182 FsdSystemTimeToDosDateTime(DeviceExt
,
183 &BasicInfo
->LastWriteTime
,
184 &FCB
->entry
.Fat
.UpdateDate
,
185 &FCB
->entry
.Fat
.UpdateTime
);
188 *FCB
->Attributes
= (unsigned char)((*FCB
->Attributes
&
189 (FILE_ATTRIBUTE_DIRECTORY
| 0x48)) |
190 (BasicInfo
->FileAttributes
&
191 (FILE_ATTRIBUTE_ARCHIVE
|
192 FILE_ATTRIBUTE_SYSTEM
|
193 FILE_ATTRIBUTE_HIDDEN
|
194 FILE_ATTRIBUTE_READONLY
)));
195 DPRINT("Setting attributes 0x%02x\n", *FCB
->Attributes
);
197 VfatUpdateEntry(FCB
);
199 return(STATUS_SUCCESS
);
203 VfatGetBasicInformation(PFILE_OBJECT FileObject
,
205 PDEVICE_OBJECT DeviceObject
,
206 PFILE_BASIC_INFORMATION BasicInfo
,
209 PDEVICE_EXTENSION DeviceExt
;
211 UNREFERENCED_PARAMETER(FileObject
);
213 DPRINT("VfatGetBasicInformation()\n");
215 DeviceExt
= (PDEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
217 if (*BufferLength
< sizeof(FILE_BASIC_INFORMATION
))
218 return STATUS_BUFFER_OVERFLOW
;
220 if (FCB
->Flags
& FCB_IS_FATX_ENTRY
)
222 FsdDosDateTimeToSystemTime(DeviceExt
,
223 FCB
->entry
.FatX
.CreationDate
,
224 FCB
->entry
.FatX
.CreationTime
,
225 &BasicInfo
->CreationTime
);
226 FsdDosDateTimeToSystemTime(DeviceExt
,
227 FCB
->entry
.FatX
.AccessDate
,
228 FCB
->entry
.FatX
.AccessTime
,
229 &BasicInfo
->LastAccessTime
);
230 FsdDosDateTimeToSystemTime(DeviceExt
,
231 FCB
->entry
.FatX
.UpdateDate
,
232 FCB
->entry
.FatX
.UpdateTime
,
233 &BasicInfo
->LastWriteTime
);
234 BasicInfo
->ChangeTime
= BasicInfo
->LastWriteTime
;
238 FsdDosDateTimeToSystemTime(DeviceExt
,
239 FCB
->entry
.Fat
.CreationDate
,
240 FCB
->entry
.Fat
.CreationTime
,
241 &BasicInfo
->CreationTime
);
242 FsdDosDateTimeToSystemTime(DeviceExt
,
243 FCB
->entry
.Fat
.AccessDate
,
245 &BasicInfo
->LastAccessTime
);
246 FsdDosDateTimeToSystemTime(DeviceExt
,
247 FCB
->entry
.Fat
.UpdateDate
,
248 FCB
->entry
.Fat
.UpdateTime
,
249 &BasicInfo
->LastWriteTime
);
250 BasicInfo
->ChangeTime
= BasicInfo
->LastWriteTime
;
253 BasicInfo
->FileAttributes
= *FCB
->Attributes
& 0x3f;
254 /* Synthesize FILE_ATTRIBUTE_NORMAL */
255 if (0 == (BasicInfo
->FileAttributes
& (FILE_ATTRIBUTE_DIRECTORY
|
256 FILE_ATTRIBUTE_ARCHIVE
|
257 FILE_ATTRIBUTE_SYSTEM
|
258 FILE_ATTRIBUTE_HIDDEN
|
259 FILE_ATTRIBUTE_READONLY
)))
261 DPRINT("Synthesizing FILE_ATTRIBUTE_NORMAL\n");
262 BasicInfo
->FileAttributes
|= FILE_ATTRIBUTE_NORMAL
;
264 DPRINT("Getting attributes 0x%02x\n", BasicInfo
->FileAttributes
);
266 *BufferLength
-= sizeof(FILE_BASIC_INFORMATION
);
267 return(STATUS_SUCCESS
);
272 VfatSetDispositionInformation(PFILE_OBJECT FileObject
,
274 PDEVICE_OBJECT DeviceObject
,
275 PFILE_DISPOSITION_INFORMATION DispositionInfo
)
278 PDEVICE_EXTENSION DeviceExt
= DeviceObject
->DeviceExtension
;
281 DPRINT ("FsdSetDispositionInformation(<%wZ>, Delete %d)\n", &FCB
->PathNameU
, DispositionInfo
->DeleteFile
);
283 ASSERT(DeviceExt
!= NULL
);
284 ASSERT(DeviceExt
->FatInfo
.BytesPerCluster
!= 0);
287 if (!DispositionInfo
->DeleteFile
)
289 /* undelete the file */
290 FCB
->Flags
&= ~FCB_DELETE_PENDING
;
291 FileObject
->DeletePending
= FALSE
;
292 return STATUS_SUCCESS
;
295 if (FCB
->Flags
& FCB_DELETE_PENDING
)
297 /* stream already marked for deletion. just update the file object */
298 FileObject
->DeletePending
= TRUE
;
299 return STATUS_SUCCESS
;
302 if (*FCB
->Attributes
& FILE_ATTRIBUTE_READONLY
)
304 return STATUS_CANNOT_DELETE
;
307 if (vfatFCBIsRoot(FCB
) ||
308 (FCB
->LongNameU
.Length
== sizeof(WCHAR
) && FCB
->LongNameU
.Buffer
[0] == L
'.') ||
309 (FCB
->LongNameU
.Length
== 2 * sizeof(WCHAR
) && FCB
->LongNameU
.Buffer
[0] == L
'.' && FCB
->LongNameU
.Buffer
[1] == L
'.'))
311 // we cannot delete a '.', '..' or the root directory
312 return STATUS_ACCESS_DENIED
;
316 if (!MmFlushImageSection (FileObject
->SectionObjectPointer
, MmFlushForDelete
))
318 /* can't delete a file if its mapped into a process */
320 DPRINT("MmFlushImageSection returned FALSE\n");
321 return STATUS_CANNOT_DELETE
;
324 if (vfatFCBIsDirectory(FCB
) && !VfatIsDirectoryEmpty(FCB
))
326 /* can't delete a non-empty directory */
328 return STATUS_DIRECTORY_NOT_EMPTY
;
332 FCB
->Flags
|= FCB_DELETE_PENDING
;
333 FileObject
->DeletePending
= TRUE
;
335 return STATUS_SUCCESS
;
339 VfatGetNameInformation(PFILE_OBJECT FileObject
,
341 PDEVICE_OBJECT DeviceObject
,
342 PFILE_NAME_INFORMATION NameInfo
,
345 * FUNCTION: Retrieve the file name information
350 UNREFERENCED_PARAMETER(FileObject
);
351 UNREFERENCED_PARAMETER(DeviceObject
);
353 ASSERT(NameInfo
!= NULL
);
356 /* If buffer can't hold at least the file name length, bail out */
357 if (*BufferLength
< FIELD_OFFSET(FILE_NAME_INFORMATION
, FileName
[0]))
358 return STATUS_BUFFER_OVERFLOW
;
360 /* Save file name length, and as much file len, as buffer length allows */
361 NameInfo
->FileNameLength
= FCB
->PathNameU
.Length
;
363 /* Calculate amount of bytes to copy not to overflow the buffer */
364 BytesToCopy
= min(FCB
->PathNameU
.Length
,
365 *BufferLength
- FIELD_OFFSET(FILE_NAME_INFORMATION
, FileName
[0]));
367 /* Fill in the bytes */
368 RtlCopyMemory(NameInfo
->FileName
, FCB
->PathNameU
.Buffer
, BytesToCopy
);
370 /* Check if we could write more but are not able to */
371 if (*BufferLength
< FCB
->PathNameU
.Length
+ (ULONG
)FIELD_OFFSET(FILE_NAME_INFORMATION
, FileName
[0]))
373 /* Return number of bytes written */
374 *BufferLength
-= FIELD_OFFSET(FILE_NAME_INFORMATION
, FileName
[0]) + BytesToCopy
;
375 return STATUS_BUFFER_OVERFLOW
;
378 /* We filled up as many bytes, as needed */
379 *BufferLength
-= (FIELD_OFFSET(FILE_NAME_INFORMATION
, FileName
[0]) + FCB
->PathNameU
.Length
);
381 return STATUS_SUCCESS
;
385 VfatGetInternalInformation(PVFATFCB Fcb
,
386 PFILE_INTERNAL_INFORMATION InternalInfo
,
389 ASSERT(InternalInfo
);
392 if (*BufferLength
< sizeof(FILE_INTERNAL_INFORMATION
))
393 return STATUS_BUFFER_OVERFLOW
;
394 // FIXME: get a real index, that can be used in a create operation
395 InternalInfo
->IndexNumber
.QuadPart
= 0;
396 *BufferLength
-= sizeof(FILE_INTERNAL_INFORMATION
);
397 return STATUS_SUCCESS
;
402 VfatGetNetworkOpenInformation(PVFATFCB Fcb
,
403 PDEVICE_EXTENSION DeviceExt
,
404 PFILE_NETWORK_OPEN_INFORMATION NetworkInfo
,
407 * FUNCTION: Retrieve the file network open information
413 if (*BufferLength
< sizeof(FILE_NETWORK_OPEN_INFORMATION
))
414 return(STATUS_BUFFER_OVERFLOW
);
416 if (Fcb
->Flags
& FCB_IS_FATX_ENTRY
)
418 FsdDosDateTimeToSystemTime(DeviceExt
,
419 Fcb
->entry
.FatX
.CreationDate
,
420 Fcb
->entry
.FatX
.CreationTime
,
421 &NetworkInfo
->CreationTime
);
422 FsdDosDateTimeToSystemTime(DeviceExt
,
423 Fcb
->entry
.FatX
.AccessDate
,
424 Fcb
->entry
.FatX
.AccessTime
,
425 &NetworkInfo
->LastAccessTime
);
426 FsdDosDateTimeToSystemTime(DeviceExt
,
427 Fcb
->entry
.FatX
.UpdateDate
,
428 Fcb
->entry
.FatX
.UpdateTime
,
429 &NetworkInfo
->LastWriteTime
);
430 NetworkInfo
->ChangeTime
.QuadPart
= NetworkInfo
->LastWriteTime
.QuadPart
;
434 FsdDosDateTimeToSystemTime(DeviceExt
,
435 Fcb
->entry
.Fat
.CreationDate
,
436 Fcb
->entry
.Fat
.CreationTime
,
437 &NetworkInfo
->CreationTime
);
438 FsdDosDateTimeToSystemTime(DeviceExt
,
439 Fcb
->entry
.Fat
.AccessDate
,
441 &NetworkInfo
->LastAccessTime
);
442 FsdDosDateTimeToSystemTime(DeviceExt
,
443 Fcb
->entry
.Fat
.UpdateDate
,
444 Fcb
->entry
.Fat
.UpdateTime
,
445 &NetworkInfo
->LastWriteTime
);
446 NetworkInfo
->ChangeTime
.QuadPart
= NetworkInfo
->LastWriteTime
.QuadPart
;
448 if (vfatFCBIsDirectory(Fcb
))
450 NetworkInfo
->EndOfFile
.QuadPart
= 0L;
451 NetworkInfo
->AllocationSize
.QuadPart
= 0L;
455 NetworkInfo
->AllocationSize
= Fcb
->RFCB
.AllocationSize
;
456 NetworkInfo
->EndOfFile
= Fcb
->RFCB
.FileSize
;
458 NetworkInfo
->FileAttributes
= *Fcb
->Attributes
& 0x3f;
459 /* Synthesize FILE_ATTRIBUTE_NORMAL */
460 if (0 == (NetworkInfo
->FileAttributes
& (FILE_ATTRIBUTE_DIRECTORY
|
461 FILE_ATTRIBUTE_ARCHIVE
|
462 FILE_ATTRIBUTE_SYSTEM
|
463 FILE_ATTRIBUTE_HIDDEN
|
464 FILE_ATTRIBUTE_READONLY
)))
466 DPRINT("Synthesizing FILE_ATTRIBUTE_NORMAL\n");
467 NetworkInfo
->FileAttributes
|= FILE_ATTRIBUTE_NORMAL
;
470 *BufferLength
-= sizeof(FILE_NETWORK_OPEN_INFORMATION
);
471 return STATUS_SUCCESS
;
476 VfatGetEaInformation(PFILE_OBJECT FileObject
,
478 PDEVICE_OBJECT DeviceObject
,
479 PFILE_EA_INFORMATION Info
,
482 PDEVICE_EXTENSION DeviceExt
= DeviceObject
->DeviceExtension
;
484 UNREFERENCED_PARAMETER(FileObject
);
485 UNREFERENCED_PARAMETER(Fcb
);
487 /* FIXME - use SEH to access the buffer! */
489 *BufferLength
-= sizeof(*Info
);
490 if (DeviceExt
->FatInfo
.FatType
== FAT12
||
491 DeviceExt
->FatInfo
.FatType
== FAT16
)
494 DPRINT1("VFAT: FileEaInformation not implemented!\n");
496 return STATUS_SUCCESS
;
501 VfatGetAllInformation(PFILE_OBJECT FileObject
,
503 PDEVICE_OBJECT DeviceObject
,
504 PFILE_ALL_INFORMATION Info
,
507 * FUNCTION: Retrieve the all file information
511 ULONG InitialBufferLength
= *BufferLength
;
516 if (*BufferLength
< sizeof(FILE_ALL_INFORMATION
) + Fcb
->PathNameU
.Length
+ sizeof(WCHAR
))
517 return(STATUS_BUFFER_OVERFLOW
);
519 /* Basic Information */
520 Status
= VfatGetBasicInformation(FileObject
, Fcb
, DeviceObject
, &Info
->BasicInformation
, BufferLength
);
521 if (!NT_SUCCESS(Status
)) return Status
;
522 /* Standard Information */
523 Status
= VfatGetStandardInformation(Fcb
, &Info
->StandardInformation
, BufferLength
);
524 if (!NT_SUCCESS(Status
)) return Status
;
525 /* Internal Information */
526 Status
= VfatGetInternalInformation(Fcb
, &Info
->InternalInformation
, BufferLength
);
527 if (!NT_SUCCESS(Status
)) return Status
;
529 Info
->EaInformation
.EaSize
= 0;
530 /* Access Information: The IO-Manager adds this information */
531 /* Position Information */
532 Status
= VfatGetPositionInformation(FileObject
, Fcb
, DeviceObject
, &Info
->PositionInformation
, BufferLength
);
533 if (!NT_SUCCESS(Status
)) return Status
;
534 /* Mode Information: The IO-Manager adds this information */
535 /* Alignment Information: The IO-Manager adds this information */
536 /* Name Information */
537 Status
= VfatGetNameInformation(FileObject
, Fcb
, DeviceObject
, &Info
->NameInformation
, BufferLength
);
538 if (!NT_SUCCESS(Status
)) return Status
;
540 *BufferLength
= InitialBufferLength
- (sizeof(FILE_ALL_INFORMATION
) + Fcb
->PathNameU
.Length
+ sizeof(WCHAR
));
542 return STATUS_SUCCESS
;
545 static VOID
UpdateFileSize(PFILE_OBJECT FileObject
, PVFATFCB Fcb
, ULONG Size
, ULONG ClusterSize
)
549 Fcb
->RFCB
.AllocationSize
.QuadPart
= ROUND_UP(Size
, ClusterSize
);
553 Fcb
->RFCB
.AllocationSize
.QuadPart
= (LONGLONG
)0;
555 if (!vfatFCBIsDirectory(Fcb
))
557 if (Fcb
->Flags
& FCB_IS_FATX_ENTRY
)
558 Fcb
->entry
.FatX
.FileSize
= Size
;
560 Fcb
->entry
.Fat
.FileSize
= Size
;
562 Fcb
->RFCB
.FileSize
.QuadPart
= Size
;
563 Fcb
->RFCB
.ValidDataLength
.QuadPart
= Size
;
565 CcSetFileSizes(FileObject
, (PCC_FILE_SIZES
)&Fcb
->RFCB
.AllocationSize
);
569 VfatSetAllocationSizeInformation(PFILE_OBJECT FileObject
,
571 PDEVICE_EXTENSION DeviceExt
,
572 PLARGE_INTEGER AllocationSize
)
575 ULONG Cluster
, FirstCluster
;
578 ULONG ClusterSize
= DeviceExt
->FatInfo
.BytesPerCluster
;
579 ULONG NewSize
= AllocationSize
->u
.LowPart
;
581 BOOLEAN AllocSizeChanged
= FALSE
;
583 DPRINT("VfatSetAllocationSizeInformation(File <%wZ>, AllocationSize %d %d)\n", &Fcb
->PathNameU
,
584 AllocationSize
->HighPart
, AllocationSize
->LowPart
);
586 if (Fcb
->Flags
& FCB_IS_FATX_ENTRY
)
587 OldSize
= Fcb
->entry
.FatX
.FileSize
;
589 OldSize
= Fcb
->entry
.Fat
.FileSize
;
590 if (AllocationSize
->u
.HighPart
> 0)
592 return STATUS_INVALID_PARAMETER
;
594 if (OldSize
== NewSize
)
596 return(STATUS_SUCCESS
);
599 FirstCluster
= vfatDirEntryGetFirstCluster (DeviceExt
, &Fcb
->entry
);
601 if (NewSize
> Fcb
->RFCB
.AllocationSize
.u
.LowPart
)
603 AllocSizeChanged
= TRUE
;
604 if (FirstCluster
== 0)
606 Fcb
->LastCluster
= Fcb
->LastOffset
= 0;
607 Status
= NextCluster (DeviceExt
, FirstCluster
, &FirstCluster
, TRUE
);
608 if (!NT_SUCCESS(Status
))
610 DPRINT1("NextCluster failed. Status = %x\n", Status
);
613 if (FirstCluster
== 0xffffffff)
615 return STATUS_DISK_FULL
;
617 Status
= OffsetToCluster(DeviceExt
, FirstCluster
,
618 ROUND_DOWN(NewSize
- 1, ClusterSize
),
620 if (NCluster
== 0xffffffff || !NT_SUCCESS(Status
))
623 NCluster
= Cluster
= FirstCluster
;
624 Status
= STATUS_SUCCESS
;
625 while (NT_SUCCESS(Status
) && Cluster
!= 0xffffffff && Cluster
> 1)
627 Status
= NextCluster (DeviceExt
, FirstCluster
, &NCluster
, FALSE
);
628 WriteCluster (DeviceExt
, Cluster
, 0);
631 return STATUS_DISK_FULL
;
633 if (Fcb
->Flags
& FCB_IS_FATX_ENTRY
)
635 Fcb
->entry
.FatX
.FirstCluster
= FirstCluster
;
639 if (DeviceExt
->FatInfo
.FatType
== FAT32
)
641 Fcb
->entry
.Fat
.FirstCluster
= (unsigned short)(FirstCluster
& 0x0000FFFF);
642 Fcb
->entry
.Fat
.FirstClusterHigh
= FirstCluster
>> 16;
646 ASSERT((FirstCluster
>> 16) == 0);
647 Fcb
->entry
.Fat
.FirstCluster
= (unsigned short)(FirstCluster
& 0x0000FFFF);
653 if (Fcb
->LastCluster
> 0)
655 if (Fcb
->RFCB
.AllocationSize
.u
.LowPart
- ClusterSize
== Fcb
->LastOffset
)
657 Cluster
= Fcb
->LastCluster
;
658 Status
= STATUS_SUCCESS
;
662 Status
= OffsetToCluster(DeviceExt
, Fcb
->LastCluster
,
663 Fcb
->RFCB
.AllocationSize
.u
.LowPart
- ClusterSize
- Fcb
->LastOffset
,
669 Status
= OffsetToCluster(DeviceExt
, FirstCluster
,
670 Fcb
->RFCB
.AllocationSize
.u
.LowPart
- ClusterSize
,
673 if (!NT_SUCCESS(Status
))
678 Fcb
->LastCluster
= Cluster
;
679 Fcb
->LastOffset
= Fcb
->RFCB
.AllocationSize
.u
.LowPart
- ClusterSize
;
681 /* FIXME: Check status */
682 /* Cluster points now to the last cluster within the chain */
683 Status
= OffsetToCluster(DeviceExt
, Cluster
,
684 ROUND_DOWN(NewSize
- 1, ClusterSize
) - Fcb
->LastOffset
,
686 if (NCluster
== 0xffffffff || !NT_SUCCESS(Status
))
690 Status
= NextCluster (DeviceExt
, FirstCluster
, &NCluster
, FALSE
);
691 WriteCluster(DeviceExt
, Cluster
, 0xffffffff);
693 while (NT_SUCCESS(Status
) && Cluster
!= 0xffffffff && Cluster
> 1)
695 Status
= NextCluster (DeviceExt
, FirstCluster
, &NCluster
, FALSE
);
696 WriteCluster (DeviceExt
, Cluster
, 0);
699 return STATUS_DISK_FULL
;
702 UpdateFileSize(FileObject
, Fcb
, NewSize
, ClusterSize
);
704 else if (NewSize
+ ClusterSize
<= Fcb
->RFCB
.AllocationSize
.u
.LowPart
)
707 DPRINT("Check for the ability to set file size\n");
708 if (!MmCanFileBeTruncated
709 (FileObject
->SectionObjectPointer
,
710 (PLARGE_INTEGER
)AllocationSize
))
712 DPRINT("Couldn't set file size!\n");
713 return STATUS_USER_MAPPED_FILE
;
715 DPRINT("Can set file size\n");
717 AllocSizeChanged
= TRUE
;
718 /* FIXME: Use the cached cluster/offset better way. */
719 Fcb
->LastCluster
= Fcb
->LastOffset
= 0;
720 UpdateFileSize(FileObject
, Fcb
, NewSize
, ClusterSize
);
723 Status
= OffsetToCluster(DeviceExt
, FirstCluster
,
724 ROUND_DOWN(NewSize
- 1, ClusterSize
),
728 Status
= NextCluster (DeviceExt
, FirstCluster
, &NCluster
, FALSE
);
729 WriteCluster(DeviceExt
, Cluster
, 0xffffffff);
734 if (Fcb
->Flags
& FCB_IS_FATX_ENTRY
)
736 Fcb
->entry
.FatX
.FirstCluster
= 0;
740 if (DeviceExt
->FatInfo
.FatType
== FAT32
)
742 Fcb
->entry
.Fat
.FirstCluster
= 0;
743 Fcb
->entry
.Fat
.FirstClusterHigh
= 0;
747 Fcb
->entry
.Fat
.FirstCluster
= 0;
751 NCluster
= Cluster
= FirstCluster
;
752 Status
= STATUS_SUCCESS
;
754 while (NT_SUCCESS(Status
) && 0xffffffff != Cluster
&& Cluster
> 1)
756 Status
= NextCluster (DeviceExt
, FirstCluster
, &NCluster
, FALSE
);
757 WriteCluster (DeviceExt
, Cluster
, 0);
763 UpdateFileSize(FileObject
, Fcb
, NewSize
, ClusterSize
);
765 /* Update the on-disk directory entry */
766 Fcb
->Flags
|= FCB_IS_DIRTY
;
767 if (AllocSizeChanged
)
769 VfatUpdateEntry(Fcb
);
771 return STATUS_SUCCESS
;
774 NTSTATUS
VfatQueryInformation(PVFAT_IRP_CONTEXT IrpContext
)
776 * FUNCTION: Retrieve the specified file information
779 FILE_INFORMATION_CLASS FileInformationClass
;
782 NTSTATUS Status
= STATUS_SUCCESS
;
790 FileInformationClass
= IrpContext
->Stack
->Parameters
.QueryFile
.FileInformationClass
;
791 FCB
= (PVFATFCB
) IrpContext
->FileObject
->FsContext
;
793 DPRINT("VfatQueryInformation is called for '%s'\n",
794 FileInformationClass
>= FileMaximumInformation
- 1 ? "????" : FileInformationClassNames
[FileInformationClass
]);
797 SystemBuffer
= IrpContext
->Irp
->AssociatedIrp
.SystemBuffer
;
798 BufferLength
= IrpContext
->Stack
->Parameters
.QueryFile
.Length
;
800 if (!(FCB
->Flags
& FCB_IS_PAGE_FILE
))
802 if (!ExAcquireResourceSharedLite(&FCB
->MainResource
,
803 (BOOLEAN
)(IrpContext
->Flags
& IRPCONTEXT_CANWAIT
)))
805 return VfatQueueRequest (IrpContext
);
810 switch (FileInformationClass
)
812 case FileStandardInformation
:
813 Status
= VfatGetStandardInformation(FCB
,
817 case FilePositionInformation
:
818 Status
= VfatGetPositionInformation(IrpContext
->FileObject
,
820 IrpContext
->DeviceObject
,
824 case FileBasicInformation
:
825 Status
= VfatGetBasicInformation(IrpContext
->FileObject
,
827 IrpContext
->DeviceObject
,
831 case FileNameInformation
:
832 Status
= VfatGetNameInformation(IrpContext
->FileObject
,
834 IrpContext
->DeviceObject
,
838 case FileInternalInformation
:
839 Status
= VfatGetInternalInformation(FCB
,
843 case FileNetworkOpenInformation
:
844 Status
= VfatGetNetworkOpenInformation(FCB
,
845 IrpContext
->DeviceExt
,
849 case FileAllInformation
:
850 Status
= VfatGetAllInformation(IrpContext
->FileObject
,
852 IrpContext
->DeviceObject
,
857 case FileEaInformation
:
858 Status
= VfatGetEaInformation(IrpContext
->FileObject
,
860 IrpContext
->DeviceObject
,
865 case FileAlternateNameInformation
:
866 Status
= STATUS_NOT_IMPLEMENTED
;
869 Status
= STATUS_INVALID_PARAMETER
;
872 if (!(FCB
->Flags
& FCB_IS_PAGE_FILE
))
874 ExReleaseResourceLite(&FCB
->MainResource
);
876 IrpContext
->Irp
->IoStatus
.Status
= Status
;
877 if (NT_SUCCESS(Status
) || Status
== STATUS_BUFFER_OVERFLOW
)
878 IrpContext
->Irp
->IoStatus
.Information
=
879 IrpContext
->Stack
->Parameters
.QueryFile
.Length
- BufferLength
;
881 IrpContext
->Irp
->IoStatus
.Information
= 0;
882 IoCompleteRequest(IrpContext
->Irp
, IO_NO_INCREMENT
);
883 VfatFreeIrpContext(IrpContext
);
888 NTSTATUS
VfatSetInformation(PVFAT_IRP_CONTEXT IrpContext
)
890 * FUNCTION: Retrieve the specified file information
893 FILE_INFORMATION_CLASS FileInformationClass
;
895 NTSTATUS RC
= STATUS_SUCCESS
;
897 BOOLEAN CanWait
= (IrpContext
->Flags
& IRPCONTEXT_CANWAIT
) != 0;
902 DPRINT("VfatSetInformation(IrpContext %p)\n", IrpContext
);
905 FileInformationClass
=
906 IrpContext
->Stack
->Parameters
.SetFile
.FileInformationClass
;
907 FCB
= (PVFATFCB
) IrpContext
->FileObject
->FsContext
;
908 SystemBuffer
= IrpContext
->Irp
->AssociatedIrp
.SystemBuffer
;
910 DPRINT("VfatSetInformation is called for '%s'\n",
911 FileInformationClass
>= FileMaximumInformation
- 1 ? "????" : FileInformationClassNames
[ FileInformationClass
]);
913 DPRINT("FileInformationClass %d\n", FileInformationClass
);
914 DPRINT("SystemBuffer %p\n", SystemBuffer
);
916 /* Special: We should call MmCanFileBeTruncated here to determine if changing
917 the file size would be allowed. If not, we bail with the right error.
918 We must do this before acquiring the lock. */
919 if (FileInformationClass
== FileEndOfFileInformation
)
921 DPRINT("Check for the ability to set file size\n");
922 if (!MmCanFileBeTruncated
923 (IrpContext
->FileObject
->SectionObjectPointer
,
924 (PLARGE_INTEGER
)SystemBuffer
))
926 DPRINT("Couldn't set file size!\n");
927 IrpContext
->Irp
->IoStatus
.Status
= STATUS_USER_MAPPED_FILE
;
928 IrpContext
->Irp
->IoStatus
.Information
= 0;
929 IoCompleteRequest(IrpContext
->Irp
, IO_NO_INCREMENT
);
930 VfatFreeIrpContext(IrpContext
);
931 return STATUS_USER_MAPPED_FILE
;
933 DPRINT("Can set file size\n");
936 if (!(FCB
->Flags
& FCB_IS_PAGE_FILE
))
938 if (!ExAcquireResourceExclusiveLite(&FCB
->MainResource
,
941 return(VfatQueueRequest (IrpContext
));
945 switch (FileInformationClass
)
947 case FilePositionInformation
:
948 RC
= VfatSetPositionInformation(IrpContext
->FileObject
,
951 case FileDispositionInformation
:
952 RC
= VfatSetDispositionInformation(IrpContext
->FileObject
,
954 IrpContext
->DeviceObject
,
957 case FileAllocationInformation
:
958 case FileEndOfFileInformation
:
959 RC
= VfatSetAllocationSizeInformation(IrpContext
->FileObject
,
961 IrpContext
->DeviceExt
,
962 (PLARGE_INTEGER
)SystemBuffer
);
964 case FileBasicInformation
:
965 RC
= VfatSetBasicInformation(IrpContext
->FileObject
,
967 IrpContext
->DeviceExt
,
970 case FileRenameInformation
:
971 RC
= STATUS_NOT_IMPLEMENTED
;
974 RC
= STATUS_NOT_SUPPORTED
;
977 if (!(FCB
->Flags
& FCB_IS_PAGE_FILE
))
979 ExReleaseResourceLite(&FCB
->MainResource
);
982 IrpContext
->Irp
->IoStatus
.Status
= RC
;
983 IrpContext
->Irp
->IoStatus
.Information
= 0;
984 IoCompleteRequest(IrpContext
->Irp
, IO_NO_INCREMENT
);
985 VfatFreeIrpContext(IrpContext
);