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 if (BasicInfo
->CreationTime
.QuadPart
!= 0 && BasicInfo
->CreationTime
.QuadPart
!= -1)
161 FsdSystemTimeToDosDateTime(DeviceExt
,
162 &BasicInfo
->CreationTime
,
163 &FCB
->entry
.FatX
.CreationDate
,
164 &FCB
->entry
.FatX
.CreationTime
);
167 if (BasicInfo
->LastAccessTime
.QuadPart
!= 0 && BasicInfo
->LastAccessTime
.QuadPart
!= -1)
169 FsdSystemTimeToDosDateTime(DeviceExt
,
170 &BasicInfo
->LastAccessTime
,
171 &FCB
->entry
.FatX
.AccessDate
,
172 &FCB
->entry
.FatX
.AccessTime
);
175 if (BasicInfo
->LastWriteTime
.QuadPart
!= 0 && BasicInfo
->LastWriteTime
.QuadPart
!= -1)
177 FsdSystemTimeToDosDateTime(DeviceExt
,
178 &BasicInfo
->LastWriteTime
,
179 &FCB
->entry
.FatX
.UpdateDate
,
180 &FCB
->entry
.FatX
.UpdateTime
);
185 if (BasicInfo
->CreationTime
.QuadPart
!= 0 && BasicInfo
->CreationTime
.QuadPart
!= -1)
187 FsdSystemTimeToDosDateTime(DeviceExt
,
188 &BasicInfo
->CreationTime
,
189 &FCB
->entry
.Fat
.CreationDate
,
190 &FCB
->entry
.Fat
.CreationTime
);
193 if (BasicInfo
->LastAccessTime
.QuadPart
!= 0 && BasicInfo
->LastAccessTime
.QuadPart
!= -1)
195 FsdSystemTimeToDosDateTime(DeviceExt
,
196 &BasicInfo
->LastAccessTime
,
197 &FCB
->entry
.Fat
.AccessDate
,
201 if (BasicInfo
->LastWriteTime
.QuadPart
!= 0 && BasicInfo
->LastWriteTime
.QuadPart
!= -1)
203 FsdSystemTimeToDosDateTime(DeviceExt
,
204 &BasicInfo
->LastWriteTime
,
205 &FCB
->entry
.Fat
.UpdateDate
,
206 &FCB
->entry
.Fat
.UpdateTime
);
210 if (BasicInfo
->FileAttributes
)
212 *FCB
->Attributes
= (unsigned char)((*FCB
->Attributes
&
213 (FILE_ATTRIBUTE_DIRECTORY
| 0x48)) |
214 (BasicInfo
->FileAttributes
&
215 (FILE_ATTRIBUTE_ARCHIVE
|
216 FILE_ATTRIBUTE_SYSTEM
|
217 FILE_ATTRIBUTE_HIDDEN
|
218 FILE_ATTRIBUTE_READONLY
)));
219 DPRINT("Setting attributes 0x%02x\n", *FCB
->Attributes
);
222 VfatUpdateEntry(FCB
);
224 return(STATUS_SUCCESS
);
228 VfatGetBasicInformation(PFILE_OBJECT FileObject
,
230 PDEVICE_OBJECT DeviceObject
,
231 PFILE_BASIC_INFORMATION BasicInfo
,
234 PDEVICE_EXTENSION DeviceExt
;
236 UNREFERENCED_PARAMETER(FileObject
);
238 DPRINT("VfatGetBasicInformation()\n");
240 DeviceExt
= (PDEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
242 if (*BufferLength
< sizeof(FILE_BASIC_INFORMATION
))
243 return STATUS_BUFFER_OVERFLOW
;
245 if (FCB
->Flags
& FCB_IS_FATX_ENTRY
)
247 FsdDosDateTimeToSystemTime(DeviceExt
,
248 FCB
->entry
.FatX
.CreationDate
,
249 FCB
->entry
.FatX
.CreationTime
,
250 &BasicInfo
->CreationTime
);
251 FsdDosDateTimeToSystemTime(DeviceExt
,
252 FCB
->entry
.FatX
.AccessDate
,
253 FCB
->entry
.FatX
.AccessTime
,
254 &BasicInfo
->LastAccessTime
);
255 FsdDosDateTimeToSystemTime(DeviceExt
,
256 FCB
->entry
.FatX
.UpdateDate
,
257 FCB
->entry
.FatX
.UpdateTime
,
258 &BasicInfo
->LastWriteTime
);
259 BasicInfo
->ChangeTime
= BasicInfo
->LastWriteTime
;
263 FsdDosDateTimeToSystemTime(DeviceExt
,
264 FCB
->entry
.Fat
.CreationDate
,
265 FCB
->entry
.Fat
.CreationTime
,
266 &BasicInfo
->CreationTime
);
267 FsdDosDateTimeToSystemTime(DeviceExt
,
268 FCB
->entry
.Fat
.AccessDate
,
270 &BasicInfo
->LastAccessTime
);
271 FsdDosDateTimeToSystemTime(DeviceExt
,
272 FCB
->entry
.Fat
.UpdateDate
,
273 FCB
->entry
.Fat
.UpdateTime
,
274 &BasicInfo
->LastWriteTime
);
275 BasicInfo
->ChangeTime
= BasicInfo
->LastWriteTime
;
278 BasicInfo
->FileAttributes
= *FCB
->Attributes
& 0x3f;
279 /* Synthesize FILE_ATTRIBUTE_NORMAL */
280 if (0 == (BasicInfo
->FileAttributes
& (FILE_ATTRIBUTE_DIRECTORY
|
281 FILE_ATTRIBUTE_ARCHIVE
|
282 FILE_ATTRIBUTE_SYSTEM
|
283 FILE_ATTRIBUTE_HIDDEN
|
284 FILE_ATTRIBUTE_READONLY
)))
286 DPRINT("Synthesizing FILE_ATTRIBUTE_NORMAL\n");
287 BasicInfo
->FileAttributes
|= FILE_ATTRIBUTE_NORMAL
;
289 DPRINT("Getting attributes 0x%02x\n", BasicInfo
->FileAttributes
);
291 *BufferLength
-= sizeof(FILE_BASIC_INFORMATION
);
292 return(STATUS_SUCCESS
);
297 VfatSetDispositionInformation(PFILE_OBJECT FileObject
,
299 PDEVICE_OBJECT DeviceObject
,
300 PFILE_DISPOSITION_INFORMATION DispositionInfo
)
303 PDEVICE_EXTENSION DeviceExt
= DeviceObject
->DeviceExtension
;
306 DPRINT ("FsdSetDispositionInformation(<%wZ>, Delete %d)\n", &FCB
->PathNameU
, DispositionInfo
->DeleteFile
);
308 ASSERT(DeviceExt
!= NULL
);
309 ASSERT(DeviceExt
->FatInfo
.BytesPerCluster
!= 0);
312 if (!DispositionInfo
->DeleteFile
)
314 /* undelete the file */
315 FCB
->Flags
&= ~FCB_DELETE_PENDING
;
316 FileObject
->DeletePending
= FALSE
;
317 return STATUS_SUCCESS
;
320 if (FCB
->Flags
& FCB_DELETE_PENDING
)
322 /* stream already marked for deletion. just update the file object */
323 FileObject
->DeletePending
= TRUE
;
324 return STATUS_SUCCESS
;
327 if (*FCB
->Attributes
& FILE_ATTRIBUTE_READONLY
)
329 return STATUS_CANNOT_DELETE
;
332 if (vfatFCBIsRoot(FCB
) ||
333 (FCB
->LongNameU
.Length
== sizeof(WCHAR
) && FCB
->LongNameU
.Buffer
[0] == L
'.') ||
334 (FCB
->LongNameU
.Length
== 2 * sizeof(WCHAR
) && FCB
->LongNameU
.Buffer
[0] == L
'.' && FCB
->LongNameU
.Buffer
[1] == L
'.'))
336 // we cannot delete a '.', '..' or the root directory
337 return STATUS_ACCESS_DENIED
;
341 if (!MmFlushImageSection (FileObject
->SectionObjectPointer
, MmFlushForDelete
))
343 /* can't delete a file if its mapped into a process */
345 DPRINT("MmFlushImageSection returned FALSE\n");
346 return STATUS_CANNOT_DELETE
;
349 if (vfatFCBIsDirectory(FCB
) && !VfatIsDirectoryEmpty(FCB
))
351 /* can't delete a non-empty directory */
353 return STATUS_DIRECTORY_NOT_EMPTY
;
357 FCB
->Flags
|= FCB_DELETE_PENDING
;
358 FileObject
->DeletePending
= TRUE
;
360 return STATUS_SUCCESS
;
364 VfatGetNameInformation(PFILE_OBJECT FileObject
,
366 PDEVICE_OBJECT DeviceObject
,
367 PFILE_NAME_INFORMATION NameInfo
,
370 * FUNCTION: Retrieve the file name information
375 UNREFERENCED_PARAMETER(FileObject
);
376 UNREFERENCED_PARAMETER(DeviceObject
);
378 ASSERT(NameInfo
!= NULL
);
381 /* If buffer can't hold at least the file name length, bail out */
382 if (*BufferLength
< (ULONG
)FIELD_OFFSET(FILE_NAME_INFORMATION
, FileName
[0]))
383 return STATUS_BUFFER_OVERFLOW
;
385 /* Save file name length, and as much file len, as buffer length allows */
386 NameInfo
->FileNameLength
= FCB
->PathNameU
.Length
;
388 /* Calculate amount of bytes to copy not to overflow the buffer */
389 BytesToCopy
= min(FCB
->PathNameU
.Length
,
390 *BufferLength
- FIELD_OFFSET(FILE_NAME_INFORMATION
, FileName
[0]));
392 /* Fill in the bytes */
393 RtlCopyMemory(NameInfo
->FileName
, FCB
->PathNameU
.Buffer
, BytesToCopy
);
395 /* Check if we could write more but are not able to */
396 if (*BufferLength
< FCB
->PathNameU
.Length
+ (ULONG
)FIELD_OFFSET(FILE_NAME_INFORMATION
, FileName
[0]))
398 /* Return number of bytes written */
399 *BufferLength
-= FIELD_OFFSET(FILE_NAME_INFORMATION
, FileName
[0]) + BytesToCopy
;
400 return STATUS_BUFFER_OVERFLOW
;
403 /* We filled up as many bytes, as needed */
404 *BufferLength
-= (FIELD_OFFSET(FILE_NAME_INFORMATION
, FileName
[0]) + FCB
->PathNameU
.Length
);
406 return STATUS_SUCCESS
;
410 VfatGetInternalInformation(PVFATFCB Fcb
,
411 PFILE_INTERNAL_INFORMATION InternalInfo
,
414 ASSERT(InternalInfo
);
417 if (*BufferLength
< sizeof(FILE_INTERNAL_INFORMATION
))
418 return STATUS_BUFFER_OVERFLOW
;
419 // FIXME: get a real index, that can be used in a create operation
420 InternalInfo
->IndexNumber
.QuadPart
= 0;
421 *BufferLength
-= sizeof(FILE_INTERNAL_INFORMATION
);
422 return STATUS_SUCCESS
;
427 VfatGetNetworkOpenInformation(PVFATFCB Fcb
,
428 PDEVICE_EXTENSION DeviceExt
,
429 PFILE_NETWORK_OPEN_INFORMATION NetworkInfo
,
432 * FUNCTION: Retrieve the file network open information
438 if (*BufferLength
< sizeof(FILE_NETWORK_OPEN_INFORMATION
))
439 return(STATUS_BUFFER_OVERFLOW
);
441 if (Fcb
->Flags
& FCB_IS_FATX_ENTRY
)
443 FsdDosDateTimeToSystemTime(DeviceExt
,
444 Fcb
->entry
.FatX
.CreationDate
,
445 Fcb
->entry
.FatX
.CreationTime
,
446 &NetworkInfo
->CreationTime
);
447 FsdDosDateTimeToSystemTime(DeviceExt
,
448 Fcb
->entry
.FatX
.AccessDate
,
449 Fcb
->entry
.FatX
.AccessTime
,
450 &NetworkInfo
->LastAccessTime
);
451 FsdDosDateTimeToSystemTime(DeviceExt
,
452 Fcb
->entry
.FatX
.UpdateDate
,
453 Fcb
->entry
.FatX
.UpdateTime
,
454 &NetworkInfo
->LastWriteTime
);
455 NetworkInfo
->ChangeTime
.QuadPart
= NetworkInfo
->LastWriteTime
.QuadPart
;
459 FsdDosDateTimeToSystemTime(DeviceExt
,
460 Fcb
->entry
.Fat
.CreationDate
,
461 Fcb
->entry
.Fat
.CreationTime
,
462 &NetworkInfo
->CreationTime
);
463 FsdDosDateTimeToSystemTime(DeviceExt
,
464 Fcb
->entry
.Fat
.AccessDate
,
466 &NetworkInfo
->LastAccessTime
);
467 FsdDosDateTimeToSystemTime(DeviceExt
,
468 Fcb
->entry
.Fat
.UpdateDate
,
469 Fcb
->entry
.Fat
.UpdateTime
,
470 &NetworkInfo
->LastWriteTime
);
471 NetworkInfo
->ChangeTime
.QuadPart
= NetworkInfo
->LastWriteTime
.QuadPart
;
473 if (vfatFCBIsDirectory(Fcb
))
475 NetworkInfo
->EndOfFile
.QuadPart
= 0L;
476 NetworkInfo
->AllocationSize
.QuadPart
= 0L;
480 NetworkInfo
->AllocationSize
= Fcb
->RFCB
.AllocationSize
;
481 NetworkInfo
->EndOfFile
= Fcb
->RFCB
.FileSize
;
483 NetworkInfo
->FileAttributes
= *Fcb
->Attributes
& 0x3f;
484 /* Synthesize FILE_ATTRIBUTE_NORMAL */
485 if (0 == (NetworkInfo
->FileAttributes
& (FILE_ATTRIBUTE_DIRECTORY
|
486 FILE_ATTRIBUTE_ARCHIVE
|
487 FILE_ATTRIBUTE_SYSTEM
|
488 FILE_ATTRIBUTE_HIDDEN
|
489 FILE_ATTRIBUTE_READONLY
)))
491 DPRINT("Synthesizing FILE_ATTRIBUTE_NORMAL\n");
492 NetworkInfo
->FileAttributes
|= FILE_ATTRIBUTE_NORMAL
;
495 *BufferLength
-= sizeof(FILE_NETWORK_OPEN_INFORMATION
);
496 return STATUS_SUCCESS
;
501 VfatGetEaInformation(PFILE_OBJECT FileObject
,
503 PDEVICE_OBJECT DeviceObject
,
504 PFILE_EA_INFORMATION Info
,
507 PDEVICE_EXTENSION DeviceExt
= DeviceObject
->DeviceExtension
;
509 UNREFERENCED_PARAMETER(FileObject
);
510 UNREFERENCED_PARAMETER(Fcb
);
512 /* FIXME - use SEH to access the buffer! */
514 *BufferLength
-= sizeof(*Info
);
515 if (DeviceExt
->FatInfo
.FatType
== FAT12
||
516 DeviceExt
->FatInfo
.FatType
== FAT16
)
519 DPRINT1("VFAT: FileEaInformation not implemented!\n");
521 return STATUS_SUCCESS
;
526 VfatGetAllInformation(PFILE_OBJECT FileObject
,
528 PDEVICE_OBJECT DeviceObject
,
529 PFILE_ALL_INFORMATION Info
,
532 * FUNCTION: Retrieve the all file information
536 ULONG InitialBufferLength
= *BufferLength
;
541 if (*BufferLength
< sizeof(FILE_ALL_INFORMATION
) + Fcb
->PathNameU
.Length
+ sizeof(WCHAR
))
542 return(STATUS_BUFFER_OVERFLOW
);
544 /* Basic Information */
545 Status
= VfatGetBasicInformation(FileObject
, Fcb
, DeviceObject
, &Info
->BasicInformation
, BufferLength
);
546 if (!NT_SUCCESS(Status
)) return Status
;
547 /* Standard Information */
548 Status
= VfatGetStandardInformation(Fcb
, &Info
->StandardInformation
, BufferLength
);
549 if (!NT_SUCCESS(Status
)) return Status
;
550 /* Internal Information */
551 Status
= VfatGetInternalInformation(Fcb
, &Info
->InternalInformation
, BufferLength
);
552 if (!NT_SUCCESS(Status
)) return Status
;
554 Info
->EaInformation
.EaSize
= 0;
555 /* Access Information: The IO-Manager adds this information */
556 /* Position Information */
557 Status
= VfatGetPositionInformation(FileObject
, Fcb
, DeviceObject
, &Info
->PositionInformation
, BufferLength
);
558 if (!NT_SUCCESS(Status
)) return Status
;
559 /* Mode Information: The IO-Manager adds this information */
560 /* Alignment Information: The IO-Manager adds this information */
561 /* Name Information */
562 Status
= VfatGetNameInformation(FileObject
, Fcb
, DeviceObject
, &Info
->NameInformation
, BufferLength
);
563 if (!NT_SUCCESS(Status
)) return Status
;
565 *BufferLength
= InitialBufferLength
- (sizeof(FILE_ALL_INFORMATION
) + Fcb
->PathNameU
.Length
+ sizeof(WCHAR
));
567 return STATUS_SUCCESS
;
570 static VOID
UpdateFileSize(PFILE_OBJECT FileObject
, PVFATFCB Fcb
, ULONG Size
, ULONG ClusterSize
)
574 Fcb
->RFCB
.AllocationSize
.QuadPart
= ROUND_UP(Size
, ClusterSize
);
578 Fcb
->RFCB
.AllocationSize
.QuadPart
= (LONGLONG
)0;
580 if (!vfatFCBIsDirectory(Fcb
))
582 if (Fcb
->Flags
& FCB_IS_FATX_ENTRY
)
583 Fcb
->entry
.FatX
.FileSize
= Size
;
585 Fcb
->entry
.Fat
.FileSize
= Size
;
587 Fcb
->RFCB
.FileSize
.QuadPart
= Size
;
588 Fcb
->RFCB
.ValidDataLength
.QuadPart
= Size
;
590 CcSetFileSizes(FileObject
, (PCC_FILE_SIZES
)&Fcb
->RFCB
.AllocationSize
);
594 VfatSetAllocationSizeInformation(PFILE_OBJECT FileObject
,
596 PDEVICE_EXTENSION DeviceExt
,
597 PLARGE_INTEGER AllocationSize
)
600 ULONG Cluster
, FirstCluster
;
603 ULONG ClusterSize
= DeviceExt
->FatInfo
.BytesPerCluster
;
604 ULONG NewSize
= AllocationSize
->u
.LowPart
;
606 BOOLEAN AllocSizeChanged
= FALSE
;
608 DPRINT("VfatSetAllocationSizeInformation(File <%wZ>, AllocationSize %d %d)\n", &Fcb
->PathNameU
,
609 AllocationSize
->HighPart
, AllocationSize
->LowPart
);
611 if (Fcb
->Flags
& FCB_IS_FATX_ENTRY
)
612 OldSize
= Fcb
->entry
.FatX
.FileSize
;
614 OldSize
= Fcb
->entry
.Fat
.FileSize
;
615 if (AllocationSize
->u
.HighPart
> 0)
617 return STATUS_INVALID_PARAMETER
;
619 if (OldSize
== NewSize
)
621 return(STATUS_SUCCESS
);
624 FirstCluster
= vfatDirEntryGetFirstCluster (DeviceExt
, &Fcb
->entry
);
626 if (NewSize
> Fcb
->RFCB
.AllocationSize
.u
.LowPart
)
628 AllocSizeChanged
= TRUE
;
629 if (FirstCluster
== 0)
631 Fcb
->LastCluster
= Fcb
->LastOffset
= 0;
632 Status
= NextCluster (DeviceExt
, FirstCluster
, &FirstCluster
, TRUE
);
633 if (!NT_SUCCESS(Status
))
635 DPRINT1("NextCluster failed. Status = %x\n", Status
);
638 if (FirstCluster
== 0xffffffff)
640 return STATUS_DISK_FULL
;
642 Status
= OffsetToCluster(DeviceExt
, FirstCluster
,
643 ROUND_DOWN(NewSize
- 1, ClusterSize
),
645 if (NCluster
== 0xffffffff || !NT_SUCCESS(Status
))
648 NCluster
= Cluster
= FirstCluster
;
649 Status
= STATUS_SUCCESS
;
650 while (NT_SUCCESS(Status
) && Cluster
!= 0xffffffff && Cluster
> 1)
652 Status
= NextCluster (DeviceExt
, FirstCluster
, &NCluster
, FALSE
);
653 WriteCluster (DeviceExt
, Cluster
, 0);
656 return STATUS_DISK_FULL
;
658 if (Fcb
->Flags
& FCB_IS_FATX_ENTRY
)
660 Fcb
->entry
.FatX
.FirstCluster
= FirstCluster
;
664 if (DeviceExt
->FatInfo
.FatType
== FAT32
)
666 Fcb
->entry
.Fat
.FirstCluster
= (unsigned short)(FirstCluster
& 0x0000FFFF);
667 Fcb
->entry
.Fat
.FirstClusterHigh
= FirstCluster
>> 16;
671 ASSERT((FirstCluster
>> 16) == 0);
672 Fcb
->entry
.Fat
.FirstCluster
= (unsigned short)(FirstCluster
& 0x0000FFFF);
678 if (Fcb
->LastCluster
> 0)
680 if (Fcb
->RFCB
.AllocationSize
.u
.LowPart
- ClusterSize
== Fcb
->LastOffset
)
682 Cluster
= Fcb
->LastCluster
;
683 Status
= STATUS_SUCCESS
;
687 Status
= OffsetToCluster(DeviceExt
, Fcb
->LastCluster
,
688 Fcb
->RFCB
.AllocationSize
.u
.LowPart
- ClusterSize
- Fcb
->LastOffset
,
694 Status
= OffsetToCluster(DeviceExt
, FirstCluster
,
695 Fcb
->RFCB
.AllocationSize
.u
.LowPart
- ClusterSize
,
698 if (!NT_SUCCESS(Status
))
703 Fcb
->LastCluster
= Cluster
;
704 Fcb
->LastOffset
= Fcb
->RFCB
.AllocationSize
.u
.LowPart
- ClusterSize
;
706 /* FIXME: Check status */
707 /* Cluster points now to the last cluster within the chain */
708 Status
= OffsetToCluster(DeviceExt
, Cluster
,
709 ROUND_DOWN(NewSize
- 1, ClusterSize
) - Fcb
->LastOffset
,
711 if (NCluster
== 0xffffffff || !NT_SUCCESS(Status
))
715 Status
= NextCluster (DeviceExt
, FirstCluster
, &NCluster
, FALSE
);
716 WriteCluster(DeviceExt
, Cluster
, 0xffffffff);
718 while (NT_SUCCESS(Status
) && Cluster
!= 0xffffffff && Cluster
> 1)
720 Status
= NextCluster (DeviceExt
, FirstCluster
, &NCluster
, FALSE
);
721 WriteCluster (DeviceExt
, Cluster
, 0);
724 return STATUS_DISK_FULL
;
727 UpdateFileSize(FileObject
, Fcb
, NewSize
, ClusterSize
);
729 else if (NewSize
+ ClusterSize
<= Fcb
->RFCB
.AllocationSize
.u
.LowPart
)
732 DPRINT("Check for the ability to set file size\n");
733 if (!MmCanFileBeTruncated
734 (FileObject
->SectionObjectPointer
,
735 (PLARGE_INTEGER
)AllocationSize
))
737 DPRINT("Couldn't set file size!\n");
738 return STATUS_USER_MAPPED_FILE
;
740 DPRINT("Can set file size\n");
742 AllocSizeChanged
= TRUE
;
743 /* FIXME: Use the cached cluster/offset better way. */
744 Fcb
->LastCluster
= Fcb
->LastOffset
= 0;
745 UpdateFileSize(FileObject
, Fcb
, NewSize
, ClusterSize
);
748 Status
= OffsetToCluster(DeviceExt
, FirstCluster
,
749 ROUND_DOWN(NewSize
- 1, ClusterSize
),
753 Status
= NextCluster (DeviceExt
, FirstCluster
, &NCluster
, FALSE
);
754 WriteCluster(DeviceExt
, Cluster
, 0xffffffff);
759 if (Fcb
->Flags
& FCB_IS_FATX_ENTRY
)
761 Fcb
->entry
.FatX
.FirstCluster
= 0;
765 if (DeviceExt
->FatInfo
.FatType
== FAT32
)
767 Fcb
->entry
.Fat
.FirstCluster
= 0;
768 Fcb
->entry
.Fat
.FirstClusterHigh
= 0;
772 Fcb
->entry
.Fat
.FirstCluster
= 0;
776 NCluster
= Cluster
= FirstCluster
;
777 Status
= STATUS_SUCCESS
;
779 while (NT_SUCCESS(Status
) && 0xffffffff != Cluster
&& Cluster
> 1)
781 Status
= NextCluster (DeviceExt
, FirstCluster
, &NCluster
, FALSE
);
782 WriteCluster (DeviceExt
, Cluster
, 0);
788 UpdateFileSize(FileObject
, Fcb
, NewSize
, ClusterSize
);
790 /* Update the on-disk directory entry */
791 Fcb
->Flags
|= FCB_IS_DIRTY
;
792 if (AllocSizeChanged
)
794 VfatUpdateEntry(Fcb
);
796 return STATUS_SUCCESS
;
799 NTSTATUS
VfatQueryInformation(PVFAT_IRP_CONTEXT IrpContext
)
801 * FUNCTION: Retrieve the specified file information
804 FILE_INFORMATION_CLASS FileInformationClass
;
807 NTSTATUS Status
= STATUS_SUCCESS
;
815 FileInformationClass
= IrpContext
->Stack
->Parameters
.QueryFile
.FileInformationClass
;
816 FCB
= (PVFATFCB
) IrpContext
->FileObject
->FsContext
;
818 DPRINT("VfatQueryInformation is called for '%s'\n",
819 FileInformationClass
>= FileMaximumInformation
- 1 ? "????" : FileInformationClassNames
[FileInformationClass
]);
822 SystemBuffer
= IrpContext
->Irp
->AssociatedIrp
.SystemBuffer
;
823 BufferLength
= IrpContext
->Stack
->Parameters
.QueryFile
.Length
;
825 if (!(FCB
->Flags
& FCB_IS_PAGE_FILE
))
827 if (!ExAcquireResourceSharedLite(&FCB
->MainResource
,
828 (BOOLEAN
)(IrpContext
->Flags
& IRPCONTEXT_CANWAIT
)))
830 return VfatQueueRequest (IrpContext
);
835 switch (FileInformationClass
)
837 case FileStandardInformation
:
838 Status
= VfatGetStandardInformation(FCB
,
842 case FilePositionInformation
:
843 Status
= VfatGetPositionInformation(IrpContext
->FileObject
,
845 IrpContext
->DeviceObject
,
849 case FileBasicInformation
:
850 Status
= VfatGetBasicInformation(IrpContext
->FileObject
,
852 IrpContext
->DeviceObject
,
856 case FileNameInformation
:
857 Status
= VfatGetNameInformation(IrpContext
->FileObject
,
859 IrpContext
->DeviceObject
,
863 case FileInternalInformation
:
864 Status
= VfatGetInternalInformation(FCB
,
868 case FileNetworkOpenInformation
:
869 Status
= VfatGetNetworkOpenInformation(FCB
,
870 IrpContext
->DeviceExt
,
874 case FileAllInformation
:
875 Status
= VfatGetAllInformation(IrpContext
->FileObject
,
877 IrpContext
->DeviceObject
,
882 case FileEaInformation
:
883 Status
= VfatGetEaInformation(IrpContext
->FileObject
,
885 IrpContext
->DeviceObject
,
890 case FileAlternateNameInformation
:
891 Status
= STATUS_NOT_IMPLEMENTED
;
894 Status
= STATUS_INVALID_PARAMETER
;
897 if (!(FCB
->Flags
& FCB_IS_PAGE_FILE
))
899 ExReleaseResourceLite(&FCB
->MainResource
);
901 IrpContext
->Irp
->IoStatus
.Status
= Status
;
902 if (NT_SUCCESS(Status
) || Status
== STATUS_BUFFER_OVERFLOW
)
903 IrpContext
->Irp
->IoStatus
.Information
=
904 IrpContext
->Stack
->Parameters
.QueryFile
.Length
- BufferLength
;
906 IrpContext
->Irp
->IoStatus
.Information
= 0;
907 IoCompleteRequest(IrpContext
->Irp
, IO_NO_INCREMENT
);
908 VfatFreeIrpContext(IrpContext
);
913 NTSTATUS
VfatSetInformation(PVFAT_IRP_CONTEXT IrpContext
)
915 * FUNCTION: Retrieve the specified file information
918 FILE_INFORMATION_CLASS FileInformationClass
;
920 NTSTATUS RC
= STATUS_SUCCESS
;
922 BOOLEAN CanWait
= (IrpContext
->Flags
& IRPCONTEXT_CANWAIT
) != 0;
927 DPRINT("VfatSetInformation(IrpContext %p)\n", IrpContext
);
930 FileInformationClass
=
931 IrpContext
->Stack
->Parameters
.SetFile
.FileInformationClass
;
932 FCB
= (PVFATFCB
) IrpContext
->FileObject
->FsContext
;
933 SystemBuffer
= IrpContext
->Irp
->AssociatedIrp
.SystemBuffer
;
935 DPRINT("VfatSetInformation is called for '%s'\n",
936 FileInformationClass
>= FileMaximumInformation
- 1 ? "????" : FileInformationClassNames
[ FileInformationClass
]);
938 DPRINT("FileInformationClass %d\n", FileInformationClass
);
939 DPRINT("SystemBuffer %p\n", SystemBuffer
);
941 /* Special: We should call MmCanFileBeTruncated here to determine if changing
942 the file size would be allowed. If not, we bail with the right error.
943 We must do this before acquiring the lock. */
944 if (FileInformationClass
== FileEndOfFileInformation
)
946 DPRINT("Check for the ability to set file size\n");
947 if (!MmCanFileBeTruncated
948 (IrpContext
->FileObject
->SectionObjectPointer
,
949 (PLARGE_INTEGER
)SystemBuffer
))
951 DPRINT("Couldn't set file size!\n");
952 IrpContext
->Irp
->IoStatus
.Status
= STATUS_USER_MAPPED_FILE
;
953 IrpContext
->Irp
->IoStatus
.Information
= 0;
954 IoCompleteRequest(IrpContext
->Irp
, IO_NO_INCREMENT
);
955 VfatFreeIrpContext(IrpContext
);
956 return STATUS_USER_MAPPED_FILE
;
958 DPRINT("Can set file size\n");
961 if (!(FCB
->Flags
& FCB_IS_PAGE_FILE
))
963 if (!ExAcquireResourceExclusiveLite(&FCB
->MainResource
,
966 return(VfatQueueRequest (IrpContext
));
970 switch (FileInformationClass
)
972 case FilePositionInformation
:
973 RC
= VfatSetPositionInformation(IrpContext
->FileObject
,
976 case FileDispositionInformation
:
977 RC
= VfatSetDispositionInformation(IrpContext
->FileObject
,
979 IrpContext
->DeviceObject
,
982 case FileAllocationInformation
:
983 case FileEndOfFileInformation
:
984 RC
= VfatSetAllocationSizeInformation(IrpContext
->FileObject
,
986 IrpContext
->DeviceExt
,
987 (PLARGE_INTEGER
)SystemBuffer
);
989 case FileBasicInformation
:
990 RC
= VfatSetBasicInformation(IrpContext
->FileObject
,
992 IrpContext
->DeviceExt
,
995 case FileRenameInformation
:
996 RC
= STATUS_NOT_IMPLEMENTED
;
999 RC
= STATUS_NOT_SUPPORTED
;
1002 if (!(FCB
->Flags
& FCB_IS_PAGE_FILE
))
1004 ExReleaseResourceLite(&FCB
->MainResource
);
1007 IrpContext
->Irp
->IoStatus
.Status
= RC
;
1008 IrpContext
->Irp
->IoStatus
.Information
= 0;
1009 IoCompleteRequest(IrpContext
->Irp
, IO_NO_INCREMENT
);
1010 VfatFreeIrpContext(IrpContext
);