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 *****************************************************************/
18 /* GLOBALS ******************************************************************/
20 const char* FileInformationClassNames
[] =
23 "FileDirectoryInformation",
24 "FileFullDirectoryInformation",
25 "FileBothDirectoryInformation",
26 "FileBasicInformation",
27 "FileStandardInformation",
28 "FileInternalInformation",
30 "FileAccessInformation",
31 "FileNameInformation",
32 "FileRenameInformation",
33 "FileLinkInformation",
34 "FileNamesInformation",
35 "FileDispositionInformation",
36 "FilePositionInformation",
37 "FileFullEaInformation",
38 "FileModeInformation",
39 "FileAlignmentInformation",
41 "FileAllocationInformation",
42 "FileEndOfFileInformation",
43 "FileAlternateNameInformation",
44 "FileStreamInformation",
45 "FilePipeInformation",
46 "FilePipeLocalInformation",
47 "FilePipeRemoteInformation",
48 "FileMailslotQueryInformation",
49 "FileMailslotSetInformation",
50 "FileCompressionInformation",
51 "FileObjectIdInformation",
52 "FileCompletionInformation",
53 "FileMoveClusterInformation",
54 "FileQuotaInformation",
55 "FileReparsePointInformation",
56 "FileNetworkOpenInformation",
57 "FileAttributeTagInformation",
58 "FileTrackingInformation",
59 "FileIdBothDirectoryInformation",
60 "FileIdFullDirectoryInformation",
61 "FileValidDataLengthInformation",
62 "FileShortNameInformation",
63 "FileMaximumInformation"
66 /* FUNCTIONS ****************************************************************/
69 * FUNCTION: Retrieve the standard file information
73 VfatGetStandardInformation(
75 PFILE_STANDARD_INFORMATION StandardInfo
,
78 if (*BufferLength
< sizeof(FILE_STANDARD_INFORMATION
))
79 return STATUS_BUFFER_OVERFLOW
;
82 ASSERT(StandardInfo
!= NULL
);
85 if (vfatFCBIsDirectory(FCB
))
87 StandardInfo
->AllocationSize
.QuadPart
= 0;
88 StandardInfo
->EndOfFile
.QuadPart
= 0;
89 StandardInfo
->Directory
= TRUE
;
93 StandardInfo
->AllocationSize
= FCB
->RFCB
.AllocationSize
;
94 StandardInfo
->EndOfFile
= FCB
->RFCB
.FileSize
;
95 StandardInfo
->Directory
= FALSE
;
97 StandardInfo
->NumberOfLinks
= 1;
98 StandardInfo
->DeletePending
= FCB
->Flags
& FCB_DELETE_PENDING
? TRUE
: FALSE
;
100 *BufferLength
-= sizeof(FILE_STANDARD_INFORMATION
);
101 return STATUS_SUCCESS
;
106 VfatSetPositionInformation(
107 PFILE_OBJECT FileObject
,
108 PFILE_POSITION_INFORMATION PositionInfo
)
110 DPRINT("FsdSetPositionInformation()\n");
112 DPRINT("PositionInfo %p\n", PositionInfo
);
113 DPRINT("Setting position %u\n", PositionInfo
->CurrentByteOffset
.u
.LowPart
);
115 FileObject
->CurrentByteOffset
.QuadPart
=
116 PositionInfo
->CurrentByteOffset
.QuadPart
;
118 return STATUS_SUCCESS
;
123 VfatGetPositionInformation(
124 PFILE_OBJECT FileObject
,
126 PDEVICE_OBJECT DeviceObject
,
127 PFILE_POSITION_INFORMATION PositionInfo
,
130 UNREFERENCED_PARAMETER(FileObject
);
131 UNREFERENCED_PARAMETER(FCB
);
132 UNREFERENCED_PARAMETER(DeviceObject
);
134 DPRINT("VfatGetPositionInformation()\n");
136 if (*BufferLength
< sizeof(FILE_POSITION_INFORMATION
))
137 return STATUS_BUFFER_OVERFLOW
;
139 PositionInfo
->CurrentByteOffset
.QuadPart
=
140 FileObject
->CurrentByteOffset
.QuadPart
;
142 DPRINT("Getting position %I64x\n",
143 PositionInfo
->CurrentByteOffset
.QuadPart
);
145 *BufferLength
-= sizeof(FILE_POSITION_INFORMATION
);
146 return STATUS_SUCCESS
;
151 VfatSetBasicInformation(
152 PFILE_OBJECT FileObject
,
154 PDEVICE_EXTENSION DeviceExt
,
155 PFILE_BASIC_INFORMATION BasicInfo
)
157 DPRINT("VfatSetBasicInformation()\n");
159 ASSERT(NULL
!= FileObject
);
161 ASSERT(NULL
!= DeviceExt
);
162 ASSERT(NULL
!= BasicInfo
);
163 /* Check volume label bit */
164 ASSERT(0 == (*FCB
->Attributes
& _A_VOLID
));
166 if (FCB
->Flags
& FCB_IS_FATX_ENTRY
)
168 if (BasicInfo
->CreationTime
.QuadPart
!= 0 && BasicInfo
->CreationTime
.QuadPart
!= -1)
170 FsdSystemTimeToDosDateTime(DeviceExt
,
171 &BasicInfo
->CreationTime
,
172 &FCB
->entry
.FatX
.CreationDate
,
173 &FCB
->entry
.FatX
.CreationTime
);
176 if (BasicInfo
->LastAccessTime
.QuadPart
!= 0 && BasicInfo
->LastAccessTime
.QuadPart
!= -1)
178 FsdSystemTimeToDosDateTime(DeviceExt
,
179 &BasicInfo
->LastAccessTime
,
180 &FCB
->entry
.FatX
.AccessDate
,
181 &FCB
->entry
.FatX
.AccessTime
);
184 if (BasicInfo
->LastWriteTime
.QuadPart
!= 0 && BasicInfo
->LastWriteTime
.QuadPart
!= -1)
186 FsdSystemTimeToDosDateTime(DeviceExt
,
187 &BasicInfo
->LastWriteTime
,
188 &FCB
->entry
.FatX
.UpdateDate
,
189 &FCB
->entry
.FatX
.UpdateTime
);
194 if (BasicInfo
->CreationTime
.QuadPart
!= 0 && BasicInfo
->CreationTime
.QuadPart
!= -1)
196 FsdSystemTimeToDosDateTime(DeviceExt
,
197 &BasicInfo
->CreationTime
,
198 &FCB
->entry
.Fat
.CreationDate
,
199 &FCB
->entry
.Fat
.CreationTime
);
202 if (BasicInfo
->LastAccessTime
.QuadPart
!= 0 && BasicInfo
->LastAccessTime
.QuadPart
!= -1)
204 FsdSystemTimeToDosDateTime(DeviceExt
,
205 &BasicInfo
->LastAccessTime
,
206 &FCB
->entry
.Fat
.AccessDate
,
210 if (BasicInfo
->LastWriteTime
.QuadPart
!= 0 && BasicInfo
->LastWriteTime
.QuadPart
!= -1)
212 FsdSystemTimeToDosDateTime(DeviceExt
,
213 &BasicInfo
->LastWriteTime
,
214 &FCB
->entry
.Fat
.UpdateDate
,
215 &FCB
->entry
.Fat
.UpdateTime
);
219 if (BasicInfo
->FileAttributes
)
221 *FCB
->Attributes
= (unsigned char)((*FCB
->Attributes
&
222 (FILE_ATTRIBUTE_DIRECTORY
| 0x48)) |
223 (BasicInfo
->FileAttributes
&
224 (FILE_ATTRIBUTE_ARCHIVE
|
225 FILE_ATTRIBUTE_SYSTEM
|
226 FILE_ATTRIBUTE_HIDDEN
|
227 FILE_ATTRIBUTE_READONLY
)));
228 DPRINT("Setting attributes 0x%02x\n", *FCB
->Attributes
);
231 VfatUpdateEntry(FCB
);
233 return STATUS_SUCCESS
;
238 VfatGetBasicInformation(
239 PFILE_OBJECT FileObject
,
241 PDEVICE_OBJECT DeviceObject
,
242 PFILE_BASIC_INFORMATION BasicInfo
,
245 PDEVICE_EXTENSION DeviceExt
;
247 UNREFERENCED_PARAMETER(FileObject
);
249 DPRINT("VfatGetBasicInformation()\n");
251 DeviceExt
= (PDEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
253 if (*BufferLength
< sizeof(FILE_BASIC_INFORMATION
))
254 return STATUS_BUFFER_OVERFLOW
;
256 if (FCB
->Flags
& FCB_IS_FATX_ENTRY
)
258 FsdDosDateTimeToSystemTime(DeviceExt
,
259 FCB
->entry
.FatX
.CreationDate
,
260 FCB
->entry
.FatX
.CreationTime
,
261 &BasicInfo
->CreationTime
);
262 FsdDosDateTimeToSystemTime(DeviceExt
,
263 FCB
->entry
.FatX
.AccessDate
,
264 FCB
->entry
.FatX
.AccessTime
,
265 &BasicInfo
->LastAccessTime
);
266 FsdDosDateTimeToSystemTime(DeviceExt
,
267 FCB
->entry
.FatX
.UpdateDate
,
268 FCB
->entry
.FatX
.UpdateTime
,
269 &BasicInfo
->LastWriteTime
);
270 BasicInfo
->ChangeTime
= BasicInfo
->LastWriteTime
;
274 FsdDosDateTimeToSystemTime(DeviceExt
,
275 FCB
->entry
.Fat
.CreationDate
,
276 FCB
->entry
.Fat
.CreationTime
,
277 &BasicInfo
->CreationTime
);
278 FsdDosDateTimeToSystemTime(DeviceExt
,
279 FCB
->entry
.Fat
.AccessDate
,
281 &BasicInfo
->LastAccessTime
);
282 FsdDosDateTimeToSystemTime(DeviceExt
,
283 FCB
->entry
.Fat
.UpdateDate
,
284 FCB
->entry
.Fat
.UpdateTime
,
285 &BasicInfo
->LastWriteTime
);
286 BasicInfo
->ChangeTime
= BasicInfo
->LastWriteTime
;
289 BasicInfo
->FileAttributes
= *FCB
->Attributes
& 0x3f;
290 /* Synthesize FILE_ATTRIBUTE_NORMAL */
291 if (0 == (BasicInfo
->FileAttributes
& (FILE_ATTRIBUTE_DIRECTORY
|
292 FILE_ATTRIBUTE_ARCHIVE
|
293 FILE_ATTRIBUTE_SYSTEM
|
294 FILE_ATTRIBUTE_HIDDEN
|
295 FILE_ATTRIBUTE_READONLY
)))
297 DPRINT("Synthesizing FILE_ATTRIBUTE_NORMAL\n");
298 BasicInfo
->FileAttributes
|= FILE_ATTRIBUTE_NORMAL
;
300 DPRINT("Getting attributes 0x%02x\n", BasicInfo
->FileAttributes
);
302 *BufferLength
-= sizeof(FILE_BASIC_INFORMATION
);
303 return STATUS_SUCCESS
;
309 VfatSetDispositionInformation(
310 PFILE_OBJECT FileObject
,
312 PDEVICE_OBJECT DeviceObject
,
313 PFILE_DISPOSITION_INFORMATION DispositionInfo
)
316 PDEVICE_EXTENSION DeviceExt
= DeviceObject
->DeviceExtension
;
319 DPRINT("FsdSetDispositionInformation(<%wZ>, Delete %u)\n", &FCB
->PathNameU
, DispositionInfo
->DeleteFile
);
321 ASSERT(DeviceExt
!= NULL
);
322 ASSERT(DeviceExt
->FatInfo
.BytesPerCluster
!= 0);
325 if (!DispositionInfo
->DeleteFile
)
327 /* undelete the file */
328 FCB
->Flags
&= ~FCB_DELETE_PENDING
;
329 FileObject
->DeletePending
= FALSE
;
330 return STATUS_SUCCESS
;
333 if (FCB
->Flags
& FCB_DELETE_PENDING
)
335 /* stream already marked for deletion. just update the file object */
336 FileObject
->DeletePending
= TRUE
;
337 return STATUS_SUCCESS
;
340 if (*FCB
->Attributes
& FILE_ATTRIBUTE_READONLY
)
342 return STATUS_CANNOT_DELETE
;
345 if (vfatFCBIsRoot(FCB
) ||
346 (FCB
->LongNameU
.Length
== sizeof(WCHAR
) && FCB
->LongNameU
.Buffer
[0] == L
'.') ||
347 (FCB
->LongNameU
.Length
== 2 * sizeof(WCHAR
) && FCB
->LongNameU
.Buffer
[0] == L
'.' && FCB
->LongNameU
.Buffer
[1] == L
'.'))
349 // we cannot delete a '.', '..' or the root directory
350 return STATUS_ACCESS_DENIED
;
354 if (!MmFlushImageSection (FileObject
->SectionObjectPointer
, MmFlushForDelete
))
356 /* can't delete a file if its mapped into a process */
358 DPRINT("MmFlushImageSection returned FALSE\n");
359 return STATUS_CANNOT_DELETE
;
362 if (vfatFCBIsDirectory(FCB
) && !VfatIsDirectoryEmpty(FCB
))
364 /* can't delete a non-empty directory */
366 return STATUS_DIRECTORY_NOT_EMPTY
;
370 FCB
->Flags
|= FCB_DELETE_PENDING
;
371 FileObject
->DeletePending
= TRUE
;
373 return STATUS_SUCCESS
;
377 * FUNCTION: Retrieve the file name information
381 VfatGetNameInformation(
382 PFILE_OBJECT FileObject
,
384 PDEVICE_OBJECT DeviceObject
,
385 PFILE_NAME_INFORMATION NameInfo
,
390 UNREFERENCED_PARAMETER(FileObject
);
391 UNREFERENCED_PARAMETER(DeviceObject
);
393 ASSERT(NameInfo
!= NULL
);
396 /* If buffer can't hold at least the file name length, bail out */
397 if (*BufferLength
< (ULONG
)FIELD_OFFSET(FILE_NAME_INFORMATION
, FileName
[0]))
398 return STATUS_BUFFER_OVERFLOW
;
400 /* Save file name length, and as much file len, as buffer length allows */
401 NameInfo
->FileNameLength
= FCB
->PathNameU
.Length
;
403 /* Calculate amount of bytes to copy not to overflow the buffer */
404 BytesToCopy
= min(FCB
->PathNameU
.Length
,
405 *BufferLength
- FIELD_OFFSET(FILE_NAME_INFORMATION
, FileName
[0]));
407 /* Fill in the bytes */
408 RtlCopyMemory(NameInfo
->FileName
, FCB
->PathNameU
.Buffer
, BytesToCopy
);
410 /* Check if we could write more but are not able to */
411 if (*BufferLength
< FCB
->PathNameU
.Length
+ (ULONG
)FIELD_OFFSET(FILE_NAME_INFORMATION
, FileName
[0]))
413 /* Return number of bytes written */
414 *BufferLength
-= FIELD_OFFSET(FILE_NAME_INFORMATION
, FileName
[0]) + BytesToCopy
;
415 return STATUS_BUFFER_OVERFLOW
;
418 /* We filled up as many bytes, as needed */
419 *BufferLength
-= (FIELD_OFFSET(FILE_NAME_INFORMATION
, FileName
[0]) + FCB
->PathNameU
.Length
);
421 return STATUS_SUCCESS
;
426 VfatGetInternalInformation(
428 PFILE_INTERNAL_INFORMATION InternalInfo
,
431 ASSERT(InternalInfo
);
434 if (*BufferLength
< sizeof(FILE_INTERNAL_INFORMATION
))
435 return STATUS_BUFFER_OVERFLOW
;
436 // FIXME: get a real index, that can be used in a create operation
437 InternalInfo
->IndexNumber
.QuadPart
= 0;
438 *BufferLength
-= sizeof(FILE_INTERNAL_INFORMATION
);
439 return STATUS_SUCCESS
;
444 * FUNCTION: Retrieve the file network open information
448 VfatGetNetworkOpenInformation(
450 PDEVICE_EXTENSION DeviceExt
,
451 PFILE_NETWORK_OPEN_INFORMATION NetworkInfo
,
457 if (*BufferLength
< sizeof(FILE_NETWORK_OPEN_INFORMATION
))
458 return(STATUS_BUFFER_OVERFLOW
);
460 if (Fcb
->Flags
& FCB_IS_FATX_ENTRY
)
462 FsdDosDateTimeToSystemTime(DeviceExt
,
463 Fcb
->entry
.FatX
.CreationDate
,
464 Fcb
->entry
.FatX
.CreationTime
,
465 &NetworkInfo
->CreationTime
);
466 FsdDosDateTimeToSystemTime(DeviceExt
,
467 Fcb
->entry
.FatX
.AccessDate
,
468 Fcb
->entry
.FatX
.AccessTime
,
469 &NetworkInfo
->LastAccessTime
);
470 FsdDosDateTimeToSystemTime(DeviceExt
,
471 Fcb
->entry
.FatX
.UpdateDate
,
472 Fcb
->entry
.FatX
.UpdateTime
,
473 &NetworkInfo
->LastWriteTime
);
474 NetworkInfo
->ChangeTime
.QuadPart
= NetworkInfo
->LastWriteTime
.QuadPart
;
478 FsdDosDateTimeToSystemTime(DeviceExt
,
479 Fcb
->entry
.Fat
.CreationDate
,
480 Fcb
->entry
.Fat
.CreationTime
,
481 &NetworkInfo
->CreationTime
);
482 FsdDosDateTimeToSystemTime(DeviceExt
,
483 Fcb
->entry
.Fat
.AccessDate
,
485 &NetworkInfo
->LastAccessTime
);
486 FsdDosDateTimeToSystemTime(DeviceExt
,
487 Fcb
->entry
.Fat
.UpdateDate
,
488 Fcb
->entry
.Fat
.UpdateTime
,
489 &NetworkInfo
->LastWriteTime
);
490 NetworkInfo
->ChangeTime
.QuadPart
= NetworkInfo
->LastWriteTime
.QuadPart
;
493 if (vfatFCBIsDirectory(Fcb
))
495 NetworkInfo
->EndOfFile
.QuadPart
= 0L;
496 NetworkInfo
->AllocationSize
.QuadPart
= 0L;
500 NetworkInfo
->AllocationSize
= Fcb
->RFCB
.AllocationSize
;
501 NetworkInfo
->EndOfFile
= Fcb
->RFCB
.FileSize
;
504 NetworkInfo
->FileAttributes
= *Fcb
->Attributes
& 0x3f;
505 /* Synthesize FILE_ATTRIBUTE_NORMAL */
506 if (0 == (NetworkInfo
->FileAttributes
& (FILE_ATTRIBUTE_DIRECTORY
|
507 FILE_ATTRIBUTE_ARCHIVE
|
508 FILE_ATTRIBUTE_SYSTEM
|
509 FILE_ATTRIBUTE_HIDDEN
|
510 FILE_ATTRIBUTE_READONLY
)))
512 DPRINT("Synthesizing FILE_ATTRIBUTE_NORMAL\n");
513 NetworkInfo
->FileAttributes
|= FILE_ATTRIBUTE_NORMAL
;
516 *BufferLength
-= sizeof(FILE_NETWORK_OPEN_INFORMATION
);
517 return STATUS_SUCCESS
;
523 VfatGetEaInformation(
524 PFILE_OBJECT FileObject
,
526 PDEVICE_OBJECT DeviceObject
,
527 PFILE_EA_INFORMATION Info
,
530 PDEVICE_EXTENSION DeviceExt
= DeviceObject
->DeviceExtension
;
532 UNREFERENCED_PARAMETER(FileObject
);
533 UNREFERENCED_PARAMETER(Fcb
);
535 /* FIXME - use SEH to access the buffer! */
537 *BufferLength
-= sizeof(*Info
);
538 if (DeviceExt
->FatInfo
.FatType
== FAT12
||
539 DeviceExt
->FatInfo
.FatType
== FAT16
)
542 DPRINT1("VFAT: FileEaInformation not implemented!\n");
544 return STATUS_SUCCESS
;
549 * FUNCTION: Retrieve the all file information
553 VfatGetAllInformation(
554 PFILE_OBJECT FileObject
,
556 PDEVICE_OBJECT DeviceObject
,
557 PFILE_ALL_INFORMATION Info
,
561 ULONG InitialBufferLength
= *BufferLength
;
566 if (*BufferLength
< sizeof(FILE_ALL_INFORMATION
) + Fcb
->PathNameU
.Length
+ sizeof(WCHAR
))
567 return(STATUS_BUFFER_OVERFLOW
);
569 /* Basic Information */
570 Status
= VfatGetBasicInformation(FileObject
, Fcb
, DeviceObject
, &Info
->BasicInformation
, BufferLength
);
571 if (!NT_SUCCESS(Status
)) return Status
;
572 /* Standard Information */
573 Status
= VfatGetStandardInformation(Fcb
, &Info
->StandardInformation
, BufferLength
);
574 if (!NT_SUCCESS(Status
)) return Status
;
575 /* Internal Information */
576 Status
= VfatGetInternalInformation(Fcb
, &Info
->InternalInformation
, BufferLength
);
577 if (!NT_SUCCESS(Status
)) return Status
;
579 Info
->EaInformation
.EaSize
= 0;
580 /* Access Information: The IO-Manager adds this information */
581 /* Position Information */
582 Status
= VfatGetPositionInformation(FileObject
, Fcb
, DeviceObject
, &Info
->PositionInformation
, BufferLength
);
583 if (!NT_SUCCESS(Status
)) return Status
;
584 /* Mode Information: The IO-Manager adds this information */
585 /* Alignment Information: The IO-Manager adds this information */
586 /* Name Information */
587 Status
= VfatGetNameInformation(FileObject
, Fcb
, DeviceObject
, &Info
->NameInformation
, BufferLength
);
588 if (!NT_SUCCESS(Status
)) return Status
;
590 *BufferLength
= InitialBufferLength
- (sizeof(FILE_ALL_INFORMATION
) + Fcb
->PathNameU
.Length
+ sizeof(WCHAR
));
592 return STATUS_SUCCESS
;
598 PFILE_OBJECT FileObject
,
605 Fcb
->RFCB
.AllocationSize
.QuadPart
= ROUND_UP(Size
, ClusterSize
);
609 Fcb
->RFCB
.AllocationSize
.QuadPart
= (LONGLONG
)0;
611 if (!vfatFCBIsDirectory(Fcb
))
613 if (Fcb
->Flags
& FCB_IS_FATX_ENTRY
)
614 Fcb
->entry
.FatX
.FileSize
= Size
;
616 Fcb
->entry
.Fat
.FileSize
= Size
;
618 Fcb
->RFCB
.FileSize
.QuadPart
= Size
;
619 Fcb
->RFCB
.ValidDataLength
.QuadPart
= Size
;
621 CcSetFileSizes(FileObject
, (PCC_FILE_SIZES
)&Fcb
->RFCB
.AllocationSize
);
625 VfatSetAllocationSizeInformation(
626 PFILE_OBJECT FileObject
,
628 PDEVICE_EXTENSION DeviceExt
,
629 PLARGE_INTEGER AllocationSize
)
632 ULONG Cluster
, FirstCluster
;
635 ULONG ClusterSize
= DeviceExt
->FatInfo
.BytesPerCluster
;
636 ULONG NewSize
= AllocationSize
->u
.LowPart
;
638 BOOLEAN AllocSizeChanged
= FALSE
;
640 DPRINT("VfatSetAllocationSizeInformation(File <%wZ>, AllocationSize %d %u)\n",
641 &Fcb
->PathNameU
, AllocationSize
->HighPart
, AllocationSize
->LowPart
);
643 if (Fcb
->Flags
& FCB_IS_FATX_ENTRY
)
644 OldSize
= Fcb
->entry
.FatX
.FileSize
;
646 OldSize
= Fcb
->entry
.Fat
.FileSize
;
648 if (AllocationSize
->u
.HighPart
> 0)
650 return STATUS_INVALID_PARAMETER
;
653 if (OldSize
== NewSize
)
655 return STATUS_SUCCESS
;
658 FirstCluster
= vfatDirEntryGetFirstCluster(DeviceExt
, &Fcb
->entry
);
660 if (NewSize
> Fcb
->RFCB
.AllocationSize
.u
.LowPart
)
662 AllocSizeChanged
= TRUE
;
663 if (FirstCluster
== 0)
665 Fcb
->LastCluster
= Fcb
->LastOffset
= 0;
666 Status
= NextCluster(DeviceExt
, FirstCluster
, &FirstCluster
, TRUE
);
667 if (!NT_SUCCESS(Status
))
669 DPRINT1("NextCluster failed. Status = %x\n", Status
);
673 if (FirstCluster
== 0xffffffff)
675 return STATUS_DISK_FULL
;
678 Status
= OffsetToCluster(DeviceExt
, FirstCluster
,
679 ROUND_DOWN(NewSize
- 1, ClusterSize
),
681 if (NCluster
== 0xffffffff || !NT_SUCCESS(Status
))
684 NCluster
= Cluster
= FirstCluster
;
685 Status
= STATUS_SUCCESS
;
686 while (NT_SUCCESS(Status
) && Cluster
!= 0xffffffff && Cluster
> 1)
688 Status
= NextCluster(DeviceExt
, FirstCluster
, &NCluster
, FALSE
);
689 WriteCluster(DeviceExt
, Cluster
, 0);
692 return STATUS_DISK_FULL
;
695 if (Fcb
->Flags
& FCB_IS_FATX_ENTRY
)
697 Fcb
->entry
.FatX
.FirstCluster
= FirstCluster
;
701 if (DeviceExt
->FatInfo
.FatType
== FAT32
)
703 Fcb
->entry
.Fat
.FirstCluster
= (unsigned short)(FirstCluster
& 0x0000FFFF);
704 Fcb
->entry
.Fat
.FirstClusterHigh
= FirstCluster
>> 16;
708 ASSERT((FirstCluster
>> 16) == 0);
709 Fcb
->entry
.Fat
.FirstCluster
= (unsigned short)(FirstCluster
& 0x0000FFFF);
715 if (Fcb
->LastCluster
> 0)
717 if (Fcb
->RFCB
.AllocationSize
.u
.LowPart
- ClusterSize
== Fcb
->LastOffset
)
719 Cluster
= Fcb
->LastCluster
;
720 Status
= STATUS_SUCCESS
;
724 Status
= OffsetToCluster(DeviceExt
, Fcb
->LastCluster
,
725 Fcb
->RFCB
.AllocationSize
.u
.LowPart
- ClusterSize
- Fcb
->LastOffset
,
731 Status
= OffsetToCluster(DeviceExt
, FirstCluster
,
732 Fcb
->RFCB
.AllocationSize
.u
.LowPart
- ClusterSize
,
736 if (!NT_SUCCESS(Status
))
741 Fcb
->LastCluster
= Cluster
;
742 Fcb
->LastOffset
= Fcb
->RFCB
.AllocationSize
.u
.LowPart
- ClusterSize
;
744 /* FIXME: Check status */
745 /* Cluster points now to the last cluster within the chain */
746 Status
= OffsetToCluster(DeviceExt
, Cluster
,
747 ROUND_DOWN(NewSize
- 1, ClusterSize
) - Fcb
->LastOffset
,
749 if (NCluster
== 0xffffffff || !NT_SUCCESS(Status
))
753 Status
= NextCluster(DeviceExt
, FirstCluster
, &NCluster
, FALSE
);
754 WriteCluster(DeviceExt
, Cluster
, 0xffffffff);
756 while (NT_SUCCESS(Status
) && Cluster
!= 0xffffffff && Cluster
> 1)
758 Status
= NextCluster(DeviceExt
, FirstCluster
, &NCluster
, FALSE
);
759 WriteCluster(DeviceExt
, Cluster
, 0);
762 return STATUS_DISK_FULL
;
765 UpdateFileSize(FileObject
, Fcb
, NewSize
, ClusterSize
);
767 else if (NewSize
+ ClusterSize
<= Fcb
->RFCB
.AllocationSize
.u
.LowPart
)
769 DPRINT("Check for the ability to set file size\n");
770 if (!MmCanFileBeTruncated(FileObject
->SectionObjectPointer
,
771 (PLARGE_INTEGER
)AllocationSize
))
773 DPRINT("Couldn't set file size!\n");
774 return STATUS_USER_MAPPED_FILE
;
776 DPRINT("Can set file size\n");
778 AllocSizeChanged
= TRUE
;
779 /* FIXME: Use the cached cluster/offset better way. */
780 Fcb
->LastCluster
= Fcb
->LastOffset
= 0;
781 UpdateFileSize(FileObject
, Fcb
, NewSize
, ClusterSize
);
784 Status
= OffsetToCluster(DeviceExt
, FirstCluster
,
785 ROUND_DOWN(NewSize
- 1, ClusterSize
),
789 Status
= NextCluster(DeviceExt
, FirstCluster
, &NCluster
, FALSE
);
790 WriteCluster(DeviceExt
, Cluster
, 0xffffffff);
795 if (Fcb
->Flags
& FCB_IS_FATX_ENTRY
)
797 Fcb
->entry
.FatX
.FirstCluster
= 0;
801 if (DeviceExt
->FatInfo
.FatType
== FAT32
)
803 Fcb
->entry
.Fat
.FirstCluster
= 0;
804 Fcb
->entry
.Fat
.FirstClusterHigh
= 0;
808 Fcb
->entry
.Fat
.FirstCluster
= 0;
812 NCluster
= Cluster
= FirstCluster
;
813 Status
= STATUS_SUCCESS
;
816 while (NT_SUCCESS(Status
) && 0xffffffff != Cluster
&& Cluster
> 1)
818 Status
= NextCluster(DeviceExt
, FirstCluster
, &NCluster
, FALSE
);
819 WriteCluster(DeviceExt
, Cluster
, 0);
825 UpdateFileSize(FileObject
, Fcb
, NewSize
, ClusterSize
);
828 /* Update the on-disk directory entry */
829 Fcb
->Flags
|= FCB_IS_DIRTY
;
830 if (AllocSizeChanged
)
832 VfatUpdateEntry(Fcb
);
834 return STATUS_SUCCESS
;
838 * FUNCTION: Retrieve the specified file information
841 VfatQueryInformation(
842 PVFAT_IRP_CONTEXT IrpContext
)
844 FILE_INFORMATION_CLASS FileInformationClass
;
847 NTSTATUS Status
= STATUS_SUCCESS
;
855 FileInformationClass
= IrpContext
->Stack
->Parameters
.QueryFile
.FileInformationClass
;
856 FCB
= (PVFATFCB
) IrpContext
->FileObject
->FsContext
;
858 DPRINT("VfatQueryInformation is called for '%s'\n",
859 FileInformationClass
>= FileMaximumInformation
- 1 ? "????" : FileInformationClassNames
[FileInformationClass
]);
862 SystemBuffer
= IrpContext
->Irp
->AssociatedIrp
.SystemBuffer
;
863 BufferLength
= IrpContext
->Stack
->Parameters
.QueryFile
.Length
;
865 if (!(FCB
->Flags
& FCB_IS_PAGE_FILE
))
867 if (!ExAcquireResourceSharedLite(&FCB
->MainResource
,
868 (BOOLEAN
)(IrpContext
->Flags
& IRPCONTEXT_CANWAIT
)))
870 return VfatQueueRequest(IrpContext
);
874 switch (FileInformationClass
)
876 case FileStandardInformation
:
877 Status
= VfatGetStandardInformation(FCB
,
882 case FilePositionInformation
:
883 Status
= VfatGetPositionInformation(IrpContext
->FileObject
,
885 IrpContext
->DeviceObject
,
890 case FileBasicInformation
:
891 Status
= VfatGetBasicInformation(IrpContext
->FileObject
,
893 IrpContext
->DeviceObject
,
898 case FileNameInformation
:
899 Status
= VfatGetNameInformation(IrpContext
->FileObject
,
901 IrpContext
->DeviceObject
,
906 case FileInternalInformation
:
907 Status
= VfatGetInternalInformation(FCB
,
912 case FileNetworkOpenInformation
:
913 Status
= VfatGetNetworkOpenInformation(FCB
,
914 IrpContext
->DeviceExt
,
919 case FileAllInformation
:
920 Status
= VfatGetAllInformation(IrpContext
->FileObject
,
922 IrpContext
->DeviceObject
,
927 case FileEaInformation
:
928 Status
= VfatGetEaInformation(IrpContext
->FileObject
,
930 IrpContext
->DeviceObject
,
935 case FileAlternateNameInformation
:
936 Status
= STATUS_NOT_IMPLEMENTED
;
940 Status
= STATUS_INVALID_PARAMETER
;
943 if (!(FCB
->Flags
& FCB_IS_PAGE_FILE
))
945 ExReleaseResourceLite(&FCB
->MainResource
);
948 IrpContext
->Irp
->IoStatus
.Status
= Status
;
949 if (NT_SUCCESS(Status
) || Status
== STATUS_BUFFER_OVERFLOW
)
950 IrpContext
->Irp
->IoStatus
.Information
=
951 IrpContext
->Stack
->Parameters
.QueryFile
.Length
- BufferLength
;
953 IrpContext
->Irp
->IoStatus
.Information
= 0;
954 IoCompleteRequest(IrpContext
->Irp
, IO_NO_INCREMENT
);
955 VfatFreeIrpContext(IrpContext
);
961 * FUNCTION: Retrieve the specified file information
965 PVFAT_IRP_CONTEXT IrpContext
)
967 FILE_INFORMATION_CLASS FileInformationClass
;
969 NTSTATUS Status
= STATUS_SUCCESS
;
975 DPRINT("VfatSetInformation(IrpContext %p)\n", IrpContext
);
978 FileInformationClass
=
979 IrpContext
->Stack
->Parameters
.SetFile
.FileInformationClass
;
980 FCB
= (PVFATFCB
) IrpContext
->FileObject
->FsContext
;
981 SystemBuffer
= IrpContext
->Irp
->AssociatedIrp
.SystemBuffer
;
983 DPRINT("VfatSetInformation is called for '%s'\n",
984 FileInformationClass
>= FileMaximumInformation
- 1 ? "????" : FileInformationClassNames
[ FileInformationClass
]);
986 DPRINT("FileInformationClass %d\n", FileInformationClass
);
987 DPRINT("SystemBuffer %p\n", SystemBuffer
);
989 /* Special: We should call MmCanFileBeTruncated here to determine if changing
990 the file size would be allowed. If not, we bail with the right error.
991 We must do this before acquiring the lock. */
992 if (FileInformationClass
== FileEndOfFileInformation
)
994 DPRINT("Check for the ability to set file size\n");
995 if (!MmCanFileBeTruncated(IrpContext
->FileObject
->SectionObjectPointer
,
996 (PLARGE_INTEGER
)SystemBuffer
))
998 DPRINT("Couldn't set file size!\n");
999 IrpContext
->Irp
->IoStatus
.Status
= STATUS_USER_MAPPED_FILE
;
1000 IrpContext
->Irp
->IoStatus
.Information
= 0;
1001 IoCompleteRequest(IrpContext
->Irp
, IO_NO_INCREMENT
);
1002 VfatFreeIrpContext(IrpContext
);
1003 return STATUS_USER_MAPPED_FILE
;
1005 DPRINT("Can set file size\n");
1008 if (!(FCB
->Flags
& FCB_IS_PAGE_FILE
))
1010 if (!ExAcquireResourceExclusiveLite(&FCB
->MainResource
,
1011 (BOOLEAN
)(IrpContext
->Flags
& IRPCONTEXT_CANWAIT
)))
1013 return VfatQueueRequest(IrpContext
);
1017 switch (FileInformationClass
)
1019 case FilePositionInformation
:
1020 Status
= VfatSetPositionInformation(IrpContext
->FileObject
,
1024 case FileDispositionInformation
:
1025 Status
= VfatSetDispositionInformation(IrpContext
->FileObject
,
1027 IrpContext
->DeviceObject
,
1031 case FileAllocationInformation
:
1032 case FileEndOfFileInformation
:
1033 Status
= VfatSetAllocationSizeInformation(IrpContext
->FileObject
,
1035 IrpContext
->DeviceExt
,
1036 (PLARGE_INTEGER
)SystemBuffer
);
1039 case FileBasicInformation
:
1040 Status
= VfatSetBasicInformation(IrpContext
->FileObject
,
1042 IrpContext
->DeviceExt
,
1046 case FileRenameInformation
:
1047 Status
= STATUS_NOT_IMPLEMENTED
;
1051 Status
= STATUS_NOT_SUPPORTED
;
1054 if (!(FCB
->Flags
& FCB_IS_PAGE_FILE
))
1056 ExReleaseResourceLite(&FCB
->MainResource
);
1059 IrpContext
->Irp
->IoStatus
.Status
= Status
;
1060 IrpContext
->Irp
->IoStatus
.Information
= 0;
1061 IoCompleteRequest(IrpContext
->Irp
, IO_NO_INCREMENT
);
1062 VfatFreeIrpContext(IrpContext
);