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 if (FileObject
->SectionObjectPointer
->SharedCacheMap
!= NULL
)
553 CcSetFileSizes(FileObject
, (PCC_FILE_SIZES
)&Fcb
->RFCB
.AllocationSize
);
558 VfatSetAllocationSizeInformation(PFILE_OBJECT FileObject
,
560 PDEVICE_EXTENSION DeviceExt
,
561 PLARGE_INTEGER AllocationSize
)
564 ULONG Cluster
, FirstCluster
;
567 ULONG ClusterSize
= DeviceExt
->FatInfo
.BytesPerCluster
;
568 ULONG NewSize
= AllocationSize
->u
.LowPart
;
570 BOOLEAN AllocSizeChanged
= FALSE
;
572 DPRINT("VfatSetAllocationSizeInformation(File <%wZ>, AllocationSize %d %d)\n", &Fcb
->PathNameU
,
573 AllocationSize
->HighPart
, AllocationSize
->LowPart
);
575 if (Fcb
->Flags
& FCB_IS_FATX_ENTRY
)
576 OldSize
= Fcb
->entry
.FatX
.FileSize
;
578 OldSize
= Fcb
->entry
.Fat
.FileSize
;
579 if (AllocationSize
->u
.HighPart
> 0)
581 return STATUS_INVALID_PARAMETER
;
583 if (OldSize
== NewSize
)
585 return(STATUS_SUCCESS
);
588 FirstCluster
= vfatDirEntryGetFirstCluster (DeviceExt
, &Fcb
->entry
);
590 if (NewSize
> Fcb
->RFCB
.AllocationSize
.u
.LowPart
)
592 AllocSizeChanged
= TRUE
;
593 if (FirstCluster
== 0)
595 Fcb
->LastCluster
= Fcb
->LastOffset
= 0;
596 Status
= NextCluster (DeviceExt
, FirstCluster
, &FirstCluster
, TRUE
);
597 if (!NT_SUCCESS(Status
))
599 DPRINT1("NextCluster failed. Status = %x\n", Status
);
602 if (FirstCluster
== 0xffffffff)
604 return STATUS_DISK_FULL
;
606 Status
= OffsetToCluster(DeviceExt
, FirstCluster
,
607 ROUND_DOWN(NewSize
- 1, ClusterSize
),
609 if (NCluster
== 0xffffffff || !NT_SUCCESS(Status
))
612 NCluster
= Cluster
= FirstCluster
;
613 Status
= STATUS_SUCCESS
;
614 while (NT_SUCCESS(Status
) && Cluster
!= 0xffffffff && Cluster
> 1)
616 Status
= NextCluster (DeviceExt
, FirstCluster
, &NCluster
, FALSE
);
617 WriteCluster (DeviceExt
, Cluster
, 0);
620 return STATUS_DISK_FULL
;
622 if (Fcb
->Flags
& FCB_IS_FATX_ENTRY
)
624 Fcb
->entry
.FatX
.FirstCluster
= FirstCluster
;
628 if (DeviceExt
->FatInfo
.FatType
== FAT32
)
630 Fcb
->entry
.Fat
.FirstCluster
= (unsigned short)(FirstCluster
& 0x0000FFFF);
631 Fcb
->entry
.Fat
.FirstClusterHigh
= FirstCluster
>> 16;
635 ASSERT((FirstCluster
>> 16) == 0);
636 Fcb
->entry
.Fat
.FirstCluster
= (unsigned short)(FirstCluster
& 0x0000FFFF);
643 if (Fcb
->LastCluster
> 0)
645 if (Fcb
->RFCB
.AllocationSize
.u
.LowPart
- ClusterSize
== Fcb
->LastOffset
)
647 Cluster
= Fcb
->LastCluster
;
648 Status
= STATUS_SUCCESS
;
652 Status
= OffsetToCluster(DeviceExt
, Fcb
->LastCluster
,
653 Fcb
->RFCB
.AllocationSize
.u
.LowPart
- ClusterSize
- Fcb
->LastOffset
,
659 Status
= OffsetToCluster(DeviceExt
, FirstCluster
,
660 Fcb
->RFCB
.AllocationSize
.u
.LowPart
- ClusterSize
,
663 if (!NT_SUCCESS(Status
))
668 if (Fcb
->LastCluster
== 0)
670 Fcb
->LastCluster
= Cluster
;
671 Fcb
->LastOffset
= Fcb
->RFCB
.AllocationSize
.u
.LowPart
- ClusterSize
;
674 /* FIXME: Check status */
675 /* Cluster points now to the last cluster within the chain */
676 Status
= OffsetToCluster(DeviceExt
, Cluster
,
677 ROUND_DOWN(NewSize
- 1, ClusterSize
) - Fcb
->LastOffset
,
680 Status
= OffsetToCluster(DeviceExt
, FirstCluster
,
681 ROUND_DOWN(NewSize
- 1, ClusterSize
),
685 if (NCluster
== 0xffffffff || !NT_SUCCESS(Status
))
689 Status
= NextCluster (DeviceExt
, FirstCluster
, &NCluster
, FALSE
);
690 WriteCluster(DeviceExt
, Cluster
, 0xffffffff);
692 while (NT_SUCCESS(Status
) && Cluster
!= 0xffffffff && Cluster
> 1)
694 Status
= NextCluster (DeviceExt
, FirstCluster
, &NCluster
, FALSE
);
695 WriteCluster (DeviceExt
, Cluster
, 0);
698 return STATUS_DISK_FULL
;
701 UpdateFileSize(FileObject
, Fcb
, NewSize
, ClusterSize
);
703 else if (NewSize
+ ClusterSize
<= Fcb
->RFCB
.AllocationSize
.u
.LowPart
)
705 AllocSizeChanged
= TRUE
;
706 /* FIXME: Use the cached cluster/offset better way. */
707 Fcb
->LastCluster
= Fcb
->LastOffset
= 0;
708 UpdateFileSize(FileObject
, Fcb
, NewSize
, ClusterSize
);
711 Status
= OffsetToCluster(DeviceExt
, FirstCluster
,
712 ROUND_DOWN(NewSize
- 1, ClusterSize
),
716 Status
= NextCluster (DeviceExt
, FirstCluster
, &NCluster
, FALSE
);
717 WriteCluster(DeviceExt
, Cluster
, 0xffffffff);
722 if (Fcb
->Flags
& FCB_IS_FATX_ENTRY
)
724 Fcb
->entry
.FatX
.FirstCluster
= 0;
728 if (DeviceExt
->FatInfo
.FatType
== FAT32
)
730 Fcb
->entry
.Fat
.FirstCluster
= 0;
731 Fcb
->entry
.Fat
.FirstClusterHigh
= 0;
735 Fcb
->entry
.Fat
.FirstCluster
= 0;
739 NCluster
= Cluster
= FirstCluster
;
740 Status
= STATUS_SUCCESS
;
742 while (NT_SUCCESS(Status
) && 0xffffffff != Cluster
&& Cluster
> 1)
744 Status
= NextCluster (DeviceExt
, FirstCluster
, &NCluster
, FALSE
);
745 WriteCluster (DeviceExt
, Cluster
, 0);
751 UpdateFileSize(FileObject
, Fcb
, NewSize
, ClusterSize
);
753 /* Update the on-disk directory entry */
754 Fcb
->Flags
|= FCB_IS_DIRTY
;
755 if (AllocSizeChanged
)
757 VfatUpdateEntry(Fcb
);
759 return STATUS_SUCCESS
;
762 NTSTATUS
VfatQueryInformation(PVFAT_IRP_CONTEXT IrpContext
)
764 * FUNCTION: Retrieve the specified file information
767 FILE_INFORMATION_CLASS FileInformationClass
;
770 NTSTATUS Status
= STATUS_SUCCESS
;
778 FileInformationClass
= IrpContext
->Stack
->Parameters
.QueryFile
.FileInformationClass
;
779 FCB
= (PVFATFCB
) IrpContext
->FileObject
->FsContext
;
781 DPRINT("VfatQueryInformation is called for '%s'\n",
782 FileInformationClass
>= FileMaximumInformation
- 1 ? "????" : FileInformationClassNames
[FileInformationClass
]);
785 SystemBuffer
= IrpContext
->Irp
->AssociatedIrp
.SystemBuffer
;
786 BufferLength
= IrpContext
->Stack
->Parameters
.QueryFile
.Length
;
788 if (!(FCB
->Flags
& FCB_IS_PAGE_FILE
))
790 if (!ExAcquireResourceSharedLite(&FCB
->MainResource
,
791 (BOOLEAN
)(IrpContext
->Flags
& IRPCONTEXT_CANWAIT
)))
793 return VfatQueueRequest (IrpContext
);
798 switch (FileInformationClass
)
800 case FileStandardInformation
:
801 Status
= VfatGetStandardInformation(FCB
,
805 case FilePositionInformation
:
806 Status
= VfatGetPositionInformation(IrpContext
->FileObject
,
808 IrpContext
->DeviceObject
,
812 case FileBasicInformation
:
813 Status
= VfatGetBasicInformation(IrpContext
->FileObject
,
815 IrpContext
->DeviceObject
,
819 case FileNameInformation
:
820 Status
= VfatGetNameInformation(IrpContext
->FileObject
,
822 IrpContext
->DeviceObject
,
826 case FileInternalInformation
:
827 Status
= VfatGetInternalInformation(FCB
,
831 case FileNetworkOpenInformation
:
832 Status
= VfatGetNetworkOpenInformation(FCB
,
833 IrpContext
->DeviceExt
,
837 case FileAllInformation
:
838 Status
= VfatGetAllInformation(IrpContext
->FileObject
,
840 IrpContext
->DeviceObject
,
845 case FileEaInformation
:
846 Status
= VfatGetEaInformation(IrpContext
->FileObject
,
848 IrpContext
->DeviceObject
,
853 case FileAlternateNameInformation
:
854 Status
= STATUS_NOT_IMPLEMENTED
;
857 Status
= STATUS_INVALID_PARAMETER
;
860 if (!(FCB
->Flags
& FCB_IS_PAGE_FILE
))
862 ExReleaseResourceLite(&FCB
->MainResource
);
864 IrpContext
->Irp
->IoStatus
.Status
= Status
;
865 if (NT_SUCCESS(Status
) || Status
== STATUS_BUFFER_OVERFLOW
)
866 IrpContext
->Irp
->IoStatus
.Information
=
867 IrpContext
->Stack
->Parameters
.QueryFile
.Length
- BufferLength
;
869 IrpContext
->Irp
->IoStatus
.Information
= 0;
870 IoCompleteRequest(IrpContext
->Irp
, IO_NO_INCREMENT
);
871 VfatFreeIrpContext(IrpContext
);
876 NTSTATUS
VfatSetInformation(PVFAT_IRP_CONTEXT IrpContext
)
878 * FUNCTION: Retrieve the specified file information
881 FILE_INFORMATION_CLASS FileInformationClass
;
883 NTSTATUS RC
= STATUS_SUCCESS
;
885 BOOLEAN CanWait
= (IrpContext
->Flags
& IRPCONTEXT_CANWAIT
) != 0;
890 DPRINT("VfatSetInformation(IrpContext %p)\n", IrpContext
);
893 FileInformationClass
=
894 IrpContext
->Stack
->Parameters
.SetFile
.FileInformationClass
;
895 FCB
= (PVFATFCB
) IrpContext
->FileObject
->FsContext
;
896 SystemBuffer
= IrpContext
->Irp
->AssociatedIrp
.SystemBuffer
;
898 DPRINT("VfatSetInformation is called for '%s'\n",
899 FileInformationClass
>= FileMaximumInformation
- 1 ? "????" : FileInformationClassNames
[ FileInformationClass
]);
901 DPRINT("FileInformationClass %d\n", FileInformationClass
);
902 DPRINT("SystemBuffer %p\n", SystemBuffer
);
904 if (!(FCB
->Flags
& FCB_IS_PAGE_FILE
))
906 if (!ExAcquireResourceExclusiveLite(&FCB
->MainResource
,
909 return(VfatQueueRequest (IrpContext
));
913 switch (FileInformationClass
)
915 case FilePositionInformation
:
916 RC
= VfatSetPositionInformation(IrpContext
->FileObject
,
919 case FileDispositionInformation
:
920 RC
= VfatSetDispositionInformation(IrpContext
->FileObject
,
922 IrpContext
->DeviceObject
,
925 case FileAllocationInformation
:
926 case FileEndOfFileInformation
:
927 RC
= VfatSetAllocationSizeInformation(IrpContext
->FileObject
,
929 IrpContext
->DeviceExt
,
930 (PLARGE_INTEGER
)SystemBuffer
);
932 case FileBasicInformation
:
933 RC
= VfatSetBasicInformation(IrpContext
->FileObject
,
935 IrpContext
->DeviceExt
,
938 case FileRenameInformation
:
939 RC
= STATUS_NOT_IMPLEMENTED
;
942 RC
= STATUS_NOT_SUPPORTED
;
945 if (!(FCB
->Flags
& FCB_IS_PAGE_FILE
))
947 ExReleaseResourceLite(&FCB
->MainResource
);
950 IrpContext
->Irp
->IoStatus
.Status
= RC
;
951 IrpContext
->Irp
->IoStatus
.Information
= 0;
952 IoCompleteRequest(IrpContext
->Irp
, IO_NO_INCREMENT
);
953 VfatFreeIrpContext(IrpContext
);