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 DPRINT ("VfatGetPositionInformation()\n");
125 if (*BufferLength
< sizeof(FILE_POSITION_INFORMATION
))
126 return STATUS_BUFFER_OVERFLOW
;
128 PositionInfo
->CurrentByteOffset
.QuadPart
=
129 FileObject
->CurrentByteOffset
.QuadPart
;
131 DPRINT("Getting position %I64x\n",
132 PositionInfo
->CurrentByteOffset
.QuadPart
);
134 *BufferLength
-= sizeof(FILE_POSITION_INFORMATION
);
135 return(STATUS_SUCCESS
);
139 VfatSetBasicInformation(PFILE_OBJECT FileObject
,
141 PDEVICE_EXTENSION DeviceExt
,
142 PFILE_BASIC_INFORMATION BasicInfo
)
144 DPRINT("VfatSetBasicInformation()\n");
146 ASSERT(NULL
!= FileObject
);
148 ASSERT(NULL
!= DeviceExt
);
149 ASSERT(NULL
!= BasicInfo
);
150 /* Check volume label bit */
151 ASSERT(0 == (*FCB
->Attributes
& 0x08));
153 if (FCB
->Flags
& FCB_IS_FATX_ENTRY
)
155 FsdSystemTimeToDosDateTime(DeviceExt
,
156 &BasicInfo
->CreationTime
,
157 &FCB
->entry
.FatX
.CreationDate
,
158 &FCB
->entry
.FatX
.CreationTime
);
159 FsdSystemTimeToDosDateTime(DeviceExt
,
160 &BasicInfo
->LastAccessTime
,
161 &FCB
->entry
.FatX
.AccessDate
,
162 &FCB
->entry
.FatX
.AccessTime
);
163 FsdSystemTimeToDosDateTime(DeviceExt
,
164 &BasicInfo
->LastWriteTime
,
165 &FCB
->entry
.FatX
.UpdateDate
,
166 &FCB
->entry
.FatX
.UpdateTime
);
170 FsdSystemTimeToDosDateTime(DeviceExt
,
171 &BasicInfo
->CreationTime
,
172 &FCB
->entry
.Fat
.CreationDate
,
173 &FCB
->entry
.Fat
.CreationTime
);
174 FsdSystemTimeToDosDateTime(DeviceExt
,
175 &BasicInfo
->LastAccessTime
,
176 &FCB
->entry
.Fat
.AccessDate
,
178 FsdSystemTimeToDosDateTime(DeviceExt
,
179 &BasicInfo
->LastWriteTime
,
180 &FCB
->entry
.Fat
.UpdateDate
,
181 &FCB
->entry
.Fat
.UpdateTime
);
184 *FCB
->Attributes
= (unsigned char)((*FCB
->Attributes
&
185 (FILE_ATTRIBUTE_DIRECTORY
| 0x48)) |
186 (BasicInfo
->FileAttributes
&
187 (FILE_ATTRIBUTE_ARCHIVE
|
188 FILE_ATTRIBUTE_SYSTEM
|
189 FILE_ATTRIBUTE_HIDDEN
|
190 FILE_ATTRIBUTE_READONLY
)));
191 DPRINT("Setting attributes 0x%02x\n", *FCB
->Attributes
);
193 VfatUpdateEntry(FCB
);
195 return(STATUS_SUCCESS
);
199 VfatGetBasicInformation(PFILE_OBJECT FileObject
,
201 PDEVICE_OBJECT DeviceObject
,
202 PFILE_BASIC_INFORMATION BasicInfo
,
205 PDEVICE_EXTENSION DeviceExt
;
206 DPRINT("VfatGetBasicInformation()\n");
208 DeviceExt
= (PDEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
210 if (*BufferLength
< sizeof(FILE_BASIC_INFORMATION
))
211 return STATUS_BUFFER_OVERFLOW
;
213 if (FCB
->Flags
& FCB_IS_FATX_ENTRY
)
215 FsdDosDateTimeToSystemTime(DeviceExt
,
216 FCB
->entry
.FatX
.CreationDate
,
217 FCB
->entry
.FatX
.CreationTime
,
218 &BasicInfo
->CreationTime
);
219 FsdDosDateTimeToSystemTime(DeviceExt
,
220 FCB
->entry
.FatX
.AccessDate
,
221 FCB
->entry
.FatX
.AccessTime
,
222 &BasicInfo
->LastAccessTime
);
223 FsdDosDateTimeToSystemTime(DeviceExt
,
224 FCB
->entry
.FatX
.UpdateDate
,
225 FCB
->entry
.FatX
.UpdateTime
,
226 &BasicInfo
->LastWriteTime
);
227 BasicInfo
->ChangeTime
= BasicInfo
->LastWriteTime
;
231 FsdDosDateTimeToSystemTime(DeviceExt
,
232 FCB
->entry
.Fat
.CreationDate
,
233 FCB
->entry
.Fat
.CreationTime
,
234 &BasicInfo
->CreationTime
);
235 FsdDosDateTimeToSystemTime(DeviceExt
,
236 FCB
->entry
.Fat
.AccessDate
,
238 &BasicInfo
->LastAccessTime
);
239 FsdDosDateTimeToSystemTime(DeviceExt
,
240 FCB
->entry
.Fat
.UpdateDate
,
241 FCB
->entry
.Fat
.UpdateTime
,
242 &BasicInfo
->LastWriteTime
);
243 BasicInfo
->ChangeTime
= BasicInfo
->LastWriteTime
;
246 BasicInfo
->FileAttributes
= *FCB
->Attributes
& 0x3f;
247 /* Synthesize FILE_ATTRIBUTE_NORMAL */
248 if (0 == (BasicInfo
->FileAttributes
& (FILE_ATTRIBUTE_DIRECTORY
|
249 FILE_ATTRIBUTE_ARCHIVE
|
250 FILE_ATTRIBUTE_SYSTEM
|
251 FILE_ATTRIBUTE_HIDDEN
|
252 FILE_ATTRIBUTE_READONLY
)))
254 DPRINT("Synthesizing FILE_ATTRIBUTE_NORMAL\n");
255 BasicInfo
->FileAttributes
|= FILE_ATTRIBUTE_NORMAL
;
257 DPRINT("Getting attributes 0x%02x\n", BasicInfo
->FileAttributes
);
259 *BufferLength
-= sizeof(FILE_BASIC_INFORMATION
);
260 return(STATUS_SUCCESS
);
265 VfatSetDispositionInformation(PFILE_OBJECT FileObject
,
267 PDEVICE_OBJECT DeviceObject
,
268 PFILE_DISPOSITION_INFORMATION DispositionInfo
)
271 PDEVICE_EXTENSION DeviceExt
= DeviceObject
->DeviceExtension
;
274 DPRINT ("FsdSetDispositionInformation(<%wZ>, Delete %d)\n", &FCB
->PathNameU
, DispositionInfo
->DeleteFile
);
276 ASSERT(DeviceExt
!= NULL
);
277 ASSERT(DeviceExt
->FatInfo
.BytesPerCluster
!= 0);
280 if (!DispositionInfo
->DeleteFile
)
282 /* undelete the file */
283 FCB
->Flags
&= ~FCB_DELETE_PENDING
;
284 FileObject
->DeletePending
= FALSE
;
285 return STATUS_SUCCESS
;
288 if (FCB
->Flags
& FCB_DELETE_PENDING
)
290 /* stream already marked for deletion. just update the file object */
291 FileObject
->DeletePending
= TRUE
;
292 return STATUS_SUCCESS
;
295 if (*FCB
->Attributes
& FILE_ATTRIBUTE_READONLY
)
297 return STATUS_CANNOT_DELETE
;
300 if (vfatFCBIsRoot(FCB
) ||
301 (FCB
->LongNameU
.Length
== sizeof(WCHAR
) && FCB
->LongNameU
.Buffer
[0] == L
'.') ||
302 (FCB
->LongNameU
.Length
== 2 * sizeof(WCHAR
) && FCB
->LongNameU
.Buffer
[0] == L
'.' && FCB
->LongNameU
.Buffer
[1] == L
'.'))
304 // we cannot delete a '.', '..' or the root directory
305 return STATUS_ACCESS_DENIED
;
309 if (!MmFlushImageSection (FileObject
->SectionObjectPointer
, MmFlushForDelete
))
311 /* can't delete a file if its mapped into a process */
313 DPRINT("MmFlushImageSection returned FALSE\n");
314 return STATUS_CANNOT_DELETE
;
317 if (vfatFCBIsDirectory(FCB
) && !VfatIsDirectoryEmpty(FCB
))
319 /* can't delete a non-empty directory */
321 return STATUS_DIRECTORY_NOT_EMPTY
;
325 FCB
->Flags
|= FCB_DELETE_PENDING
;
326 FileObject
->DeletePending
= TRUE
;
328 return STATUS_SUCCESS
;
332 VfatGetNameInformation(PFILE_OBJECT FileObject
,
334 PDEVICE_OBJECT DeviceObject
,
335 PFILE_NAME_INFORMATION NameInfo
,
338 * FUNCTION: Retrieve the file name information
342 ASSERT(NameInfo
!= NULL
);
345 /* If buffer can't hold at least the file name length, bail out */
346 if (*BufferLength
< FIELD_OFFSET(FILE_NAME_INFORMATION
, FileName
[0]))
347 return STATUS_BUFFER_OVERFLOW
;
349 /* Save file name length, and as much file len, as buffer length allows */
350 NameInfo
->FileNameLength
= FCB
->PathNameU
.Length
;
352 /* Calculate amount of bytes to copy not to overflow the buffer */
353 BytesToCopy
= min(FCB
->PathNameU
.Length
,
354 *BufferLength
- FIELD_OFFSET(FILE_NAME_INFORMATION
, FileName
[0]));
356 /* Fill in the bytes */
357 RtlCopyMemory(NameInfo
->FileName
, FCB
->PathNameU
.Buffer
, BytesToCopy
);
359 /* Check if we could write more but are not able to */
360 if (*BufferLength
< FCB
->PathNameU
.Length
+ (ULONG
)FIELD_OFFSET(FILE_NAME_INFORMATION
, FileName
[0]))
362 /* Return number of bytes written */
363 *BufferLength
-= FIELD_OFFSET(FILE_NAME_INFORMATION
, FileName
[0]) + BytesToCopy
;
364 return STATUS_BUFFER_OVERFLOW
;
367 /* We filled up as many bytes, as needed */
368 *BufferLength
-= (FIELD_OFFSET(FILE_NAME_INFORMATION
, FileName
[0]) + FCB
->PathNameU
.Length
);
370 return STATUS_SUCCESS
;
374 VfatGetInternalInformation(PVFATFCB Fcb
,
375 PFILE_INTERNAL_INFORMATION InternalInfo
,
378 ASSERT(InternalInfo
);
381 if (*BufferLength
< sizeof(FILE_INTERNAL_INFORMATION
))
382 return STATUS_BUFFER_OVERFLOW
;
383 // FIXME: get a real index, that can be used in a create operation
384 InternalInfo
->IndexNumber
.QuadPart
= 0;
385 *BufferLength
-= sizeof(FILE_INTERNAL_INFORMATION
);
386 return STATUS_SUCCESS
;
391 VfatGetNetworkOpenInformation(PVFATFCB Fcb
,
392 PDEVICE_EXTENSION DeviceExt
,
393 PFILE_NETWORK_OPEN_INFORMATION NetworkInfo
,
396 * FUNCTION: Retrieve the file network open information
402 if (*BufferLength
< sizeof(FILE_NETWORK_OPEN_INFORMATION
))
403 return(STATUS_BUFFER_OVERFLOW
);
405 if (Fcb
->Flags
& FCB_IS_FATX_ENTRY
)
407 FsdDosDateTimeToSystemTime(DeviceExt
,
408 Fcb
->entry
.FatX
.CreationDate
,
409 Fcb
->entry
.FatX
.CreationTime
,
410 &NetworkInfo
->CreationTime
);
411 FsdDosDateTimeToSystemTime(DeviceExt
,
412 Fcb
->entry
.FatX
.AccessDate
,
413 Fcb
->entry
.FatX
.AccessTime
,
414 &NetworkInfo
->LastAccessTime
);
415 FsdDosDateTimeToSystemTime(DeviceExt
,
416 Fcb
->entry
.FatX
.UpdateDate
,
417 Fcb
->entry
.FatX
.UpdateTime
,
418 &NetworkInfo
->LastWriteTime
);
419 NetworkInfo
->ChangeTime
.QuadPart
= NetworkInfo
->LastWriteTime
.QuadPart
;
423 FsdDosDateTimeToSystemTime(DeviceExt
,
424 Fcb
->entry
.Fat
.CreationDate
,
425 Fcb
->entry
.Fat
.CreationTime
,
426 &NetworkInfo
->CreationTime
);
427 FsdDosDateTimeToSystemTime(DeviceExt
,
428 Fcb
->entry
.Fat
.AccessDate
,
430 &NetworkInfo
->LastAccessTime
);
431 FsdDosDateTimeToSystemTime(DeviceExt
,
432 Fcb
->entry
.Fat
.UpdateDate
,
433 Fcb
->entry
.Fat
.UpdateTime
,
434 &NetworkInfo
->LastWriteTime
);
435 NetworkInfo
->ChangeTime
.QuadPart
= NetworkInfo
->LastWriteTime
.QuadPart
;
437 if (vfatFCBIsDirectory(Fcb
))
439 NetworkInfo
->EndOfFile
.QuadPart
= 0L;
440 NetworkInfo
->AllocationSize
.QuadPart
= 0L;
444 NetworkInfo
->AllocationSize
= Fcb
->RFCB
.AllocationSize
;
445 NetworkInfo
->EndOfFile
= Fcb
->RFCB
.FileSize
;
447 NetworkInfo
->FileAttributes
= *Fcb
->Attributes
& 0x3f;
448 /* Synthesize FILE_ATTRIBUTE_NORMAL */
449 if (0 == (NetworkInfo
->FileAttributes
& (FILE_ATTRIBUTE_DIRECTORY
|
450 FILE_ATTRIBUTE_ARCHIVE
|
451 FILE_ATTRIBUTE_SYSTEM
|
452 FILE_ATTRIBUTE_HIDDEN
|
453 FILE_ATTRIBUTE_READONLY
)))
455 DPRINT("Synthesizing FILE_ATTRIBUTE_NORMAL\n");
456 NetworkInfo
->FileAttributes
|= FILE_ATTRIBUTE_NORMAL
;
459 *BufferLength
-= sizeof(FILE_NETWORK_OPEN_INFORMATION
);
460 return STATUS_SUCCESS
;
465 VfatGetEaInformation(PFILE_OBJECT FileObject
,
467 PDEVICE_OBJECT DeviceObject
,
468 PFILE_EA_INFORMATION Info
,
471 PDEVICE_EXTENSION DeviceExt
= DeviceObject
->DeviceExtension
;
473 /* FIXME - use SEH to access the buffer! */
475 *BufferLength
-= sizeof(*Info
);
476 if (DeviceExt
->FatInfo
.FatType
== FAT12
||
477 DeviceExt
->FatInfo
.FatType
== FAT16
)
480 DPRINT1("VFAT: FileEaInformation not implemented!\n");
482 return STATUS_SUCCESS
;
487 VfatGetAllInformation(PFILE_OBJECT FileObject
,
489 PDEVICE_OBJECT DeviceObject
,
490 PFILE_ALL_INFORMATION Info
,
493 * FUNCTION: Retrieve the all file information
497 ULONG InitialBufferLength
= *BufferLength
;
502 if (*BufferLength
< sizeof(FILE_ALL_INFORMATION
) + Fcb
->PathNameU
.Length
+ sizeof(WCHAR
))
503 return(STATUS_BUFFER_OVERFLOW
);
505 /* Basic Information */
506 Status
= VfatGetBasicInformation(FileObject
, Fcb
, DeviceObject
, &Info
->BasicInformation
, BufferLength
);
507 if (!NT_SUCCESS(Status
)) return Status
;
508 /* Standard Information */
509 Status
= VfatGetStandardInformation(Fcb
, &Info
->StandardInformation
, BufferLength
);
510 if (!NT_SUCCESS(Status
)) return Status
;
511 /* Internal Information */
512 Status
= VfatGetInternalInformation(Fcb
, &Info
->InternalInformation
, BufferLength
);
513 if (!NT_SUCCESS(Status
)) return Status
;
515 Info
->EaInformation
.EaSize
= 0;
516 /* Access Information: The IO-Manager adds this information */
517 /* Position Information */
518 Status
= VfatGetPositionInformation(FileObject
, Fcb
, DeviceObject
, &Info
->PositionInformation
, BufferLength
);
519 if (!NT_SUCCESS(Status
)) return Status
;
520 /* Mode Information: The IO-Manager adds this information */
521 /* Alignment Information: The IO-Manager adds this information */
522 /* Name Information */
523 Status
= VfatGetNameInformation(FileObject
, Fcb
, DeviceObject
, &Info
->NameInformation
, BufferLength
);
524 if (!NT_SUCCESS(Status
)) return Status
;
526 *BufferLength
= InitialBufferLength
- (sizeof(FILE_ALL_INFORMATION
) + Fcb
->PathNameU
.Length
+ sizeof(WCHAR
));
528 return STATUS_SUCCESS
;
531 static VOID
UpdateFileSize(PFILE_OBJECT FileObject
, PVFATFCB Fcb
, ULONG Size
, ULONG ClusterSize
)
535 Fcb
->RFCB
.AllocationSize
.QuadPart
= ROUND_UP(Size
, ClusterSize
);
539 Fcb
->RFCB
.AllocationSize
.QuadPart
= (LONGLONG
)0;
541 if (!vfatFCBIsDirectory(Fcb
))
543 if (Fcb
->Flags
& FCB_IS_FATX_ENTRY
)
544 Fcb
->entry
.FatX
.FileSize
= Size
;
546 Fcb
->entry
.Fat
.FileSize
= Size
;
548 Fcb
->RFCB
.FileSize
.QuadPart
= Size
;
549 Fcb
->RFCB
.ValidDataLength
.QuadPart
= Size
;
551 CcSetFileSizes(FileObject
, (PCC_FILE_SIZES
)&Fcb
->RFCB
.AllocationSize
);
555 VfatSetAllocationSizeInformation(PFILE_OBJECT FileObject
,
557 PDEVICE_EXTENSION DeviceExt
,
558 PLARGE_INTEGER AllocationSize
)
561 ULONG Cluster
, FirstCluster
;
564 ULONG ClusterSize
= DeviceExt
->FatInfo
.BytesPerCluster
;
565 ULONG NewSize
= AllocationSize
->u
.LowPart
;
567 BOOLEAN AllocSizeChanged
= FALSE
;
569 DPRINT("VfatSetAllocationSizeInformation(File <%wZ>, AllocationSize %d %d)\n", &Fcb
->PathNameU
,
570 AllocationSize
->HighPart
, AllocationSize
->LowPart
);
572 if (Fcb
->Flags
& FCB_IS_FATX_ENTRY
)
573 OldSize
= Fcb
->entry
.FatX
.FileSize
;
575 OldSize
= Fcb
->entry
.Fat
.FileSize
;
576 if (AllocationSize
->u
.HighPart
> 0)
578 return STATUS_INVALID_PARAMETER
;
580 if (OldSize
== NewSize
)
582 return(STATUS_SUCCESS
);
585 FirstCluster
= vfatDirEntryGetFirstCluster (DeviceExt
, &Fcb
->entry
);
587 if (NewSize
> Fcb
->RFCB
.AllocationSize
.u
.LowPart
)
589 AllocSizeChanged
= TRUE
;
590 if (FirstCluster
== 0)
592 Fcb
->LastCluster
= Fcb
->LastOffset
= 0;
593 Status
= NextCluster (DeviceExt
, FirstCluster
, &FirstCluster
, TRUE
);
594 if (!NT_SUCCESS(Status
))
596 DPRINT1("NextCluster failed. Status = %x\n", Status
);
599 if (FirstCluster
== 0xffffffff)
601 return STATUS_DISK_FULL
;
603 Status
= OffsetToCluster(DeviceExt
, FirstCluster
,
604 ROUND_DOWN(NewSize
- 1, ClusterSize
),
606 if (NCluster
== 0xffffffff || !NT_SUCCESS(Status
))
609 NCluster
= Cluster
= FirstCluster
;
610 Status
= STATUS_SUCCESS
;
611 while (NT_SUCCESS(Status
) && Cluster
!= 0xffffffff && Cluster
> 1)
613 Status
= NextCluster (DeviceExt
, FirstCluster
, &NCluster
, FALSE
);
614 WriteCluster (DeviceExt
, Cluster
, 0);
617 return STATUS_DISK_FULL
;
619 if (Fcb
->Flags
& FCB_IS_FATX_ENTRY
)
621 Fcb
->entry
.FatX
.FirstCluster
= FirstCluster
;
625 if (DeviceExt
->FatInfo
.FatType
== FAT32
)
627 Fcb
->entry
.Fat
.FirstCluster
= (unsigned short)(FirstCluster
& 0x0000FFFF);
628 Fcb
->entry
.Fat
.FirstClusterHigh
= FirstCluster
>> 16;
632 ASSERT((FirstCluster
>> 16) == 0);
633 Fcb
->entry
.Fat
.FirstCluster
= (unsigned short)(FirstCluster
& 0x0000FFFF);
639 if (Fcb
->LastCluster
> 0)
641 if (Fcb
->RFCB
.AllocationSize
.u
.LowPart
- ClusterSize
== Fcb
->LastOffset
)
643 Cluster
= Fcb
->LastCluster
;
644 Status
= STATUS_SUCCESS
;
648 Status
= OffsetToCluster(DeviceExt
, Fcb
->LastCluster
,
649 Fcb
->RFCB
.AllocationSize
.u
.LowPart
- ClusterSize
- Fcb
->LastOffset
,
655 Status
= OffsetToCluster(DeviceExt
, FirstCluster
,
656 Fcb
->RFCB
.AllocationSize
.u
.LowPart
- ClusterSize
,
659 if (!NT_SUCCESS(Status
))
664 Fcb
->LastCluster
= Cluster
;
665 Fcb
->LastOffset
= Fcb
->RFCB
.AllocationSize
.u
.LowPart
- ClusterSize
;
667 /* FIXME: Check status */
668 /* Cluster points now to the last cluster within the chain */
669 Status
= OffsetToCluster(DeviceExt
, Cluster
,
670 ROUND_DOWN(NewSize
- 1, ClusterSize
) - Fcb
->LastOffset
,
672 if (NCluster
== 0xffffffff || !NT_SUCCESS(Status
))
676 Status
= NextCluster (DeviceExt
, FirstCluster
, &NCluster
, FALSE
);
677 WriteCluster(DeviceExt
, Cluster
, 0xffffffff);
679 while (NT_SUCCESS(Status
) && Cluster
!= 0xffffffff && Cluster
> 1)
681 Status
= NextCluster (DeviceExt
, FirstCluster
, &NCluster
, FALSE
);
682 WriteCluster (DeviceExt
, Cluster
, 0);
685 return STATUS_DISK_FULL
;
688 UpdateFileSize(FileObject
, Fcb
, NewSize
, ClusterSize
);
690 else if (NewSize
+ ClusterSize
<= Fcb
->RFCB
.AllocationSize
.u
.LowPart
)
693 DPRINT("Check for the ability to set file size\n");
694 if (!MmCanFileBeTruncated
695 (FileObject
->SectionObjectPointer
,
696 (PLARGE_INTEGER
)AllocationSize
))
698 DPRINT("Couldn't set file size!\n");
699 return STATUS_USER_MAPPED_FILE
;
701 DPRINT("Can set file size\n");
703 AllocSizeChanged
= TRUE
;
704 /* FIXME: Use the cached cluster/offset better way. */
705 Fcb
->LastCluster
= Fcb
->LastOffset
= 0;
706 UpdateFileSize(FileObject
, Fcb
, NewSize
, ClusterSize
);
709 Status
= OffsetToCluster(DeviceExt
, FirstCluster
,
710 ROUND_DOWN(NewSize
- 1, ClusterSize
),
714 Status
= NextCluster (DeviceExt
, FirstCluster
, &NCluster
, FALSE
);
715 WriteCluster(DeviceExt
, Cluster
, 0xffffffff);
720 if (Fcb
->Flags
& FCB_IS_FATX_ENTRY
)
722 Fcb
->entry
.FatX
.FirstCluster
= 0;
726 if (DeviceExt
->FatInfo
.FatType
== FAT32
)
728 Fcb
->entry
.Fat
.FirstCluster
= 0;
729 Fcb
->entry
.Fat
.FirstClusterHigh
= 0;
733 Fcb
->entry
.Fat
.FirstCluster
= 0;
737 NCluster
= Cluster
= FirstCluster
;
738 Status
= STATUS_SUCCESS
;
740 while (NT_SUCCESS(Status
) && 0xffffffff != Cluster
&& Cluster
> 1)
742 Status
= NextCluster (DeviceExt
, FirstCluster
, &NCluster
, FALSE
);
743 WriteCluster (DeviceExt
, Cluster
, 0);
749 UpdateFileSize(FileObject
, Fcb
, NewSize
, ClusterSize
);
751 /* Update the on-disk directory entry */
752 Fcb
->Flags
|= FCB_IS_DIRTY
;
753 if (AllocSizeChanged
)
755 VfatUpdateEntry(Fcb
);
757 return STATUS_SUCCESS
;
760 NTSTATUS
VfatQueryInformation(PVFAT_IRP_CONTEXT IrpContext
)
762 * FUNCTION: Retrieve the specified file information
765 FILE_INFORMATION_CLASS FileInformationClass
;
768 NTSTATUS Status
= STATUS_SUCCESS
;
776 FileInformationClass
= IrpContext
->Stack
->Parameters
.QueryFile
.FileInformationClass
;
777 FCB
= (PVFATFCB
) IrpContext
->FileObject
->FsContext
;
779 DPRINT("VfatQueryInformation is called for '%s'\n",
780 FileInformationClass
>= FileMaximumInformation
- 1 ? "????" : FileInformationClassNames
[FileInformationClass
]);
783 SystemBuffer
= IrpContext
->Irp
->AssociatedIrp
.SystemBuffer
;
784 BufferLength
= IrpContext
->Stack
->Parameters
.QueryFile
.Length
;
786 if (!(FCB
->Flags
& FCB_IS_PAGE_FILE
))
788 if (!ExAcquireResourceSharedLite(&FCB
->MainResource
,
789 (BOOLEAN
)(IrpContext
->Flags
& IRPCONTEXT_CANWAIT
)))
791 return VfatQueueRequest (IrpContext
);
796 switch (FileInformationClass
)
798 case FileStandardInformation
:
799 Status
= VfatGetStandardInformation(FCB
,
803 case FilePositionInformation
:
804 Status
= VfatGetPositionInformation(IrpContext
->FileObject
,
806 IrpContext
->DeviceObject
,
810 case FileBasicInformation
:
811 Status
= VfatGetBasicInformation(IrpContext
->FileObject
,
813 IrpContext
->DeviceObject
,
817 case FileNameInformation
:
818 Status
= VfatGetNameInformation(IrpContext
->FileObject
,
820 IrpContext
->DeviceObject
,
824 case FileInternalInformation
:
825 Status
= VfatGetInternalInformation(FCB
,
829 case FileNetworkOpenInformation
:
830 Status
= VfatGetNetworkOpenInformation(FCB
,
831 IrpContext
->DeviceExt
,
835 case FileAllInformation
:
836 Status
= VfatGetAllInformation(IrpContext
->FileObject
,
838 IrpContext
->DeviceObject
,
843 case FileEaInformation
:
844 Status
= VfatGetEaInformation(IrpContext
->FileObject
,
846 IrpContext
->DeviceObject
,
851 case FileAlternateNameInformation
:
852 Status
= STATUS_NOT_IMPLEMENTED
;
855 Status
= STATUS_INVALID_PARAMETER
;
858 if (!(FCB
->Flags
& FCB_IS_PAGE_FILE
))
860 ExReleaseResourceLite(&FCB
->MainResource
);
862 IrpContext
->Irp
->IoStatus
.Status
= Status
;
863 if (NT_SUCCESS(Status
) || Status
== STATUS_BUFFER_OVERFLOW
)
864 IrpContext
->Irp
->IoStatus
.Information
=
865 IrpContext
->Stack
->Parameters
.QueryFile
.Length
- BufferLength
;
867 IrpContext
->Irp
->IoStatus
.Information
= 0;
868 IoCompleteRequest(IrpContext
->Irp
, IO_NO_INCREMENT
);
869 VfatFreeIrpContext(IrpContext
);
874 NTSTATUS
VfatSetInformation(PVFAT_IRP_CONTEXT IrpContext
)
876 * FUNCTION: Retrieve the specified file information
879 FILE_INFORMATION_CLASS FileInformationClass
;
881 NTSTATUS RC
= STATUS_SUCCESS
;
883 BOOLEAN CanWait
= (IrpContext
->Flags
& IRPCONTEXT_CANWAIT
) != 0;
888 DPRINT("VfatSetInformation(IrpContext %p)\n", IrpContext
);
891 FileInformationClass
=
892 IrpContext
->Stack
->Parameters
.SetFile
.FileInformationClass
;
893 FCB
= (PVFATFCB
) IrpContext
->FileObject
->FsContext
;
894 SystemBuffer
= IrpContext
->Irp
->AssociatedIrp
.SystemBuffer
;
896 DPRINT("VfatSetInformation is called for '%s'\n",
897 FileInformationClass
>= FileMaximumInformation
- 1 ? "????" : FileInformationClassNames
[ FileInformationClass
]);
899 DPRINT("FileInformationClass %d\n", FileInformationClass
);
900 DPRINT("SystemBuffer %p\n", SystemBuffer
);
902 /* Special: We should call MmCanFileBeTruncated here to determine if changing
903 the file size would be allowed. If not, we bail with the right error.
904 We must do this before acquiring the lock. */
905 if (FileInformationClass
== FileEndOfFileInformation
)
907 DPRINT("Check for the ability to set file size\n");
908 if (!MmCanFileBeTruncated
909 (IrpContext
->FileObject
->SectionObjectPointer
,
910 (PLARGE_INTEGER
)SystemBuffer
))
912 DPRINT("Couldn't set file size!\n");
913 IrpContext
->Irp
->IoStatus
.Status
= STATUS_USER_MAPPED_FILE
;
914 IrpContext
->Irp
->IoStatus
.Information
= 0;
915 IoCompleteRequest(IrpContext
->Irp
, IO_NO_INCREMENT
);
916 VfatFreeIrpContext(IrpContext
);
917 return STATUS_USER_MAPPED_FILE
;
919 DPRINT("Can set file size\n");
922 if (!(FCB
->Flags
& FCB_IS_PAGE_FILE
))
924 if (!ExAcquireResourceExclusiveLite(&FCB
->MainResource
,
927 return(VfatQueueRequest (IrpContext
));
931 switch (FileInformationClass
)
933 case FilePositionInformation
:
934 RC
= VfatSetPositionInformation(IrpContext
->FileObject
,
937 case FileDispositionInformation
:
938 RC
= VfatSetDispositionInformation(IrpContext
->FileObject
,
940 IrpContext
->DeviceObject
,
943 case FileAllocationInformation
:
944 case FileEndOfFileInformation
:
945 RC
= VfatSetAllocationSizeInformation(IrpContext
->FileObject
,
947 IrpContext
->DeviceExt
,
948 (PLARGE_INTEGER
)SystemBuffer
);
950 case FileBasicInformation
:
951 RC
= VfatSetBasicInformation(IrpContext
->FileObject
,
953 IrpContext
->DeviceExt
,
956 case FileRenameInformation
:
957 RC
= STATUS_NOT_IMPLEMENTED
;
960 RC
= STATUS_NOT_SUPPORTED
;
963 if (!(FCB
->Flags
& FCB_IS_PAGE_FILE
))
965 ExReleaseResourceLite(&FCB
->MainResource
);
968 IrpContext
->Irp
->IoStatus
.Status
= RC
;
969 IrpContext
->Irp
->IoStatus
.Information
= 0;
970 IoCompleteRequest(IrpContext
->Irp
, IO_NO_INCREMENT
);
971 VfatFreeIrpContext(IrpContext
);