2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: drivers/fs/vfat/volume.c
5 * PURPOSE: VFAT Filesystem
6 * PROGRAMMER: Jason Filby (jasonfilby@yahoo.com)
7 * Herve Poussineau (reactos@poussine.freesurf.fr)
10 /* INCLUDES *****************************************************************/
17 /* FUNCTIONS ****************************************************************/
21 FsdGetFsVolumeInformation(
22 PDEVICE_OBJECT DeviceObject
,
23 PFILE_FS_VOLUME_INFORMATION FsVolumeInfo
,
26 PDEVICE_EXTENSION DeviceExt
;
28 DPRINT("FsdGetFsVolumeInformation()\n");
29 DPRINT("FsVolumeInfo = %p\n", FsVolumeInfo
);
30 DPRINT("BufferLength %lu\n", *BufferLength
);
32 DPRINT("Required length %lu\n", (sizeof(FILE_FS_VOLUME_INFORMATION
) + DeviceObject
->Vpb
->VolumeLabelLength
));
33 DPRINT("LabelLength %hu\n", DeviceObject
->Vpb
->VolumeLabelLength
);
34 DPRINT("Label %*.S\n", DeviceObject
->Vpb
->VolumeLabelLength
/ sizeof(WCHAR
), DeviceObject
->Vpb
->VolumeLabel
);
36 if (*BufferLength
< sizeof(FILE_FS_VOLUME_INFORMATION
))
37 return STATUS_INFO_LENGTH_MISMATCH
;
39 if (*BufferLength
< (sizeof(FILE_FS_VOLUME_INFORMATION
) + DeviceObject
->Vpb
->VolumeLabelLength
))
40 return STATUS_BUFFER_OVERFLOW
;
42 DeviceExt
= DeviceObject
->DeviceExtension
;
45 FsVolumeInfo
->VolumeSerialNumber
= DeviceObject
->Vpb
->SerialNumber
;
46 FsVolumeInfo
->VolumeLabelLength
= DeviceObject
->Vpb
->VolumeLabelLength
;
47 RtlCopyMemory(FsVolumeInfo
->VolumeLabel
, DeviceObject
->Vpb
->VolumeLabel
, FsVolumeInfo
->VolumeLabelLength
);
49 if (DeviceExt
->VolumeFcb
->Flags
& FCB_IS_FATX_ENTRY
)
51 FsdDosDateTimeToSystemTime(DeviceExt
,
52 DeviceExt
->VolumeFcb
->entry
.FatX
.CreationDate
,
53 DeviceExt
->VolumeFcb
->entry
.FatX
.CreationTime
,
54 &FsVolumeInfo
->VolumeCreationTime
);
58 FsdDosDateTimeToSystemTime(DeviceExt
,
59 DeviceExt
->VolumeFcb
->entry
.Fat
.CreationDate
,
60 DeviceExt
->VolumeFcb
->entry
.Fat
.CreationTime
,
61 &FsVolumeInfo
->VolumeCreationTime
);
64 FsVolumeInfo
->SupportsObjects
= FALSE
;
66 DPRINT("Finished FsdGetFsVolumeInformation()\n");
68 *BufferLength
-= (sizeof(FILE_FS_VOLUME_INFORMATION
) + DeviceObject
->Vpb
->VolumeLabelLength
);
70 DPRINT("BufferLength %lu\n", *BufferLength
);
72 return STATUS_SUCCESS
;
78 FsdGetFsAttributeInformation(
79 PDEVICE_EXTENSION DeviceExt
,
80 PFILE_FS_ATTRIBUTE_INFORMATION FsAttributeInfo
,
83 PCWSTR pName
; ULONG Length
;
84 DPRINT("FsdGetFsAttributeInformation()\n");
85 DPRINT("FsAttributeInfo = %p\n", FsAttributeInfo
);
86 DPRINT("BufferLength %lu\n", *BufferLength
);
88 if (*BufferLength
< sizeof (FILE_FS_ATTRIBUTE_INFORMATION
))
89 return STATUS_INFO_LENGTH_MISMATCH
;
91 if (DeviceExt
->FatInfo
.FatType
== FAT32
)
102 DPRINT("Required length %lu\n", (sizeof(FILE_FS_ATTRIBUTE_INFORMATION
) + Length
));
104 if (*BufferLength
< (sizeof(FILE_FS_ATTRIBUTE_INFORMATION
) + Length
))
105 return STATUS_BUFFER_OVERFLOW
;
107 FsAttributeInfo
->FileSystemAttributes
=
108 FILE_CASE_PRESERVED_NAMES
| FILE_UNICODE_ON_DISK
;
110 FsAttributeInfo
->MaximumComponentNameLength
= 255;
112 FsAttributeInfo
->FileSystemNameLength
= Length
;
114 RtlCopyMemory(FsAttributeInfo
->FileSystemName
, pName
, Length
);
116 DPRINT("Finished FsdGetFsAttributeInformation()\n");
118 *BufferLength
-= (sizeof(FILE_FS_ATTRIBUTE_INFORMATION
) + Length
);
119 DPRINT("BufferLength %lu\n", *BufferLength
);
121 return STATUS_SUCCESS
;
127 FsdGetFsSizeInformation(
128 PDEVICE_OBJECT DeviceObject
,
129 PFILE_FS_SIZE_INFORMATION FsSizeInfo
,
132 PDEVICE_EXTENSION DeviceExt
;
135 DPRINT("FsdGetFsSizeInformation()\n");
136 DPRINT("FsSizeInfo = %p\n", FsSizeInfo
);
138 if (*BufferLength
< sizeof(FILE_FS_SIZE_INFORMATION
))
139 return STATUS_BUFFER_OVERFLOW
;
141 DeviceExt
= DeviceObject
->DeviceExtension
;
142 Status
= CountAvailableClusters(DeviceExt
, &FsSizeInfo
->AvailableAllocationUnits
);
144 FsSizeInfo
->TotalAllocationUnits
.QuadPart
= DeviceExt
->FatInfo
.NumberOfClusters
;
145 FsSizeInfo
->SectorsPerAllocationUnit
= DeviceExt
->FatInfo
.SectorsPerCluster
;
146 FsSizeInfo
->BytesPerSector
= DeviceExt
->FatInfo
.BytesPerSector
;
148 DPRINT("Finished FsdGetFsSizeInformation()\n");
149 if (NT_SUCCESS(Status
))
150 *BufferLength
-= sizeof(FILE_FS_SIZE_INFORMATION
);
158 FsdGetFsDeviceInformation(
159 PDEVICE_OBJECT DeviceObject
,
160 PFILE_FS_DEVICE_INFORMATION FsDeviceInfo
,
163 DPRINT("FsdGetFsDeviceInformation()\n");
164 DPRINT("FsDeviceInfo = %p\n", FsDeviceInfo
);
165 DPRINT("BufferLength %lu\n", *BufferLength
);
166 DPRINT("Required length %lu\n", sizeof(FILE_FS_DEVICE_INFORMATION
));
168 if (*BufferLength
< sizeof(FILE_FS_DEVICE_INFORMATION
))
169 return STATUS_BUFFER_OVERFLOW
;
171 FsDeviceInfo
->DeviceType
= FILE_DEVICE_DISK
;
172 FsDeviceInfo
->Characteristics
= DeviceObject
->Characteristics
;
174 DPRINT("FsdGetFsDeviceInformation() finished.\n");
176 *BufferLength
-= sizeof(FILE_FS_DEVICE_INFORMATION
);
177 DPRINT("BufferLength %lu\n", *BufferLength
);
179 return STATUS_SUCCESS
;
185 FsdGetFsFullSizeInformation(
186 PDEVICE_OBJECT DeviceObject
,
187 PFILE_FS_FULL_SIZE_INFORMATION FsSizeInfo
,
190 PDEVICE_EXTENSION DeviceExt
;
193 DPRINT("FsdGetFsFullSizeInformation()\n");
194 DPRINT("FsSizeInfo = %p\n", FsSizeInfo
);
196 if (*BufferLength
< sizeof(FILE_FS_FULL_SIZE_INFORMATION
))
197 return STATUS_BUFFER_OVERFLOW
;
199 DeviceExt
= DeviceObject
->DeviceExtension
;
200 Status
= CountAvailableClusters(DeviceExt
, &FsSizeInfo
->CallerAvailableAllocationUnits
);
202 FsSizeInfo
->TotalAllocationUnits
.QuadPart
= DeviceExt
->FatInfo
.NumberOfClusters
;
203 FsSizeInfo
->ActualAvailableAllocationUnits
.QuadPart
= FsSizeInfo
->CallerAvailableAllocationUnits
.QuadPart
;
204 FsSizeInfo
->SectorsPerAllocationUnit
= DeviceExt
->FatInfo
.SectorsPerCluster
;
205 FsSizeInfo
->BytesPerSector
= DeviceExt
->FatInfo
.BytesPerSector
;
207 DPRINT("Finished FsdGetFsFullSizeInformation()\n");
208 if (NT_SUCCESS(Status
))
209 *BufferLength
-= sizeof(FILE_FS_FULL_SIZE_INFORMATION
);
217 FsdSetFsLabelInformation(
218 PDEVICE_OBJECT DeviceObject
,
219 PFILE_FS_LABEL_INFORMATION FsLabelInfo
)
221 PDEVICE_EXTENSION DeviceExt
;
222 PVOID Context
= NULL
;
226 LARGE_INTEGER FileOffset
;
227 BOOLEAN LabelFound
= FALSE
;
228 DIR_ENTRY VolumeLabelDirEntry
;
229 ULONG VolumeLabelDirIndex
;
231 NTSTATUS Status
= STATUS_UNSUCCESSFUL
;
233 UNICODE_STRING StringW
;
236 ULONG EntriesPerPage
;
238 DPRINT("FsdSetFsLabelInformation()\n");
240 DeviceExt
= (PDEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
242 if (sizeof(DeviceObject
->Vpb
->VolumeLabel
) < FsLabelInfo
->VolumeLabelLength
)
244 return STATUS_NAME_TOO_LONG
;
247 if (DeviceExt
->Flags
& VCB_IS_FATX
)
249 if (FsLabelInfo
->VolumeLabelLength
/ sizeof(WCHAR
) > 42)
250 return STATUS_NAME_TOO_LONG
;
252 SizeDirEntry
= sizeof(FATX_DIR_ENTRY
);
253 EntriesPerPage
= FATX_ENTRIES_PER_PAGE
;
257 if (FsLabelInfo
->VolumeLabelLength
/ sizeof(WCHAR
) > 11)
258 return STATUS_NAME_TOO_LONG
;
260 SizeDirEntry
= sizeof(FAT_DIR_ENTRY
);
261 EntriesPerPage
= FAT_ENTRIES_PER_PAGE
;
264 /* Create Volume label dir entry */
265 LabelLen
= FsLabelInfo
->VolumeLabelLength
/ sizeof(WCHAR
);
266 RtlZeroMemory(&VolumeLabelDirEntry
, SizeDirEntry
);
267 StringW
.Buffer
= FsLabelInfo
->VolumeLabel
;
268 StringW
.Length
= StringW
.MaximumLength
= (USHORT
)FsLabelInfo
->VolumeLabelLength
;
269 StringO
.Buffer
= cString
;
271 StringO
.MaximumLength
= 42;
272 Status
= RtlUnicodeStringToOemString(&StringO
, &StringW
, FALSE
);
273 if (!NT_SUCCESS(Status
))
276 if (DeviceExt
->Flags
& VCB_IS_FATX
)
278 RtlCopyMemory(VolumeLabelDirEntry
.FatX
.Filename
, cString
, LabelLen
);
279 memset(&VolumeLabelDirEntry
.FatX
.Filename
[LabelLen
], ' ', 42 - LabelLen
);
280 VolumeLabelDirEntry
.FatX
.Attrib
= _A_VOLID
;
284 RtlCopyMemory(VolumeLabelDirEntry
.Fat
.Filename
, cString
, max(sizeof(VolumeLabelDirEntry
.Fat
.Filename
), LabelLen
));
285 if (LabelLen
> sizeof(VolumeLabelDirEntry
.Fat
.Filename
))
287 memset(VolumeLabelDirEntry
.Fat
.Ext
, ' ', sizeof(VolumeLabelDirEntry
.Fat
.Ext
));
288 RtlCopyMemory(VolumeLabelDirEntry
.Fat
.Ext
, cString
+ sizeof(VolumeLabelDirEntry
.Fat
.Filename
), LabelLen
- sizeof(VolumeLabelDirEntry
.Fat
.Filename
));
292 memset(&VolumeLabelDirEntry
.Fat
.Filename
[LabelLen
], ' ', sizeof(VolumeLabelDirEntry
.Fat
.Filename
) - LabelLen
);
294 VolumeLabelDirEntry
.Fat
.Attrib
= _A_VOLID
;
297 pRootFcb
= vfatOpenRootFCB(DeviceExt
);
299 /* Search existing volume entry on disk */
300 FileOffset
.QuadPart
= 0;
301 if (CcPinRead(pRootFcb
->FileObject
, &FileOffset
, SizeDirEntry
, TRUE
, &Context
, (PVOID
*)&Entry
))
305 if (ENTRY_VOLUME(DeviceExt
, Entry
))
309 RtlCopyMemory(Entry
, &VolumeLabelDirEntry
, SizeDirEntry
);
310 CcSetDirtyPinnedData(Context
, NULL
);
311 Status
= STATUS_SUCCESS
;
315 if (ENTRY_END(DeviceExt
, Entry
))
321 Entry
= (PDIR_ENTRY
)((ULONG_PTR
)Entry
+ SizeDirEntry
);
322 if ((DirIndex
% EntriesPerPage
) == 0)
324 CcUnpinData(Context
);
325 FileOffset
.u
.LowPart
+= PAGE_SIZE
;
326 if (!CcPinRead(pRootFcb
->FileObject
, &FileOffset
, SizeDirEntry
, TRUE
, &Context
, (PVOID
*)&Entry
))
336 CcUnpinData(Context
);
342 /* Add new entry for label */
343 if (!vfatFindDirSpace(DeviceExt
, pRootFcb
, 1, &VolumeLabelDirIndex
))
344 Status
= STATUS_DISK_FULL
;
347 FileOffset
.u
.HighPart
= 0;
348 FileOffset
.u
.LowPart
= VolumeLabelDirIndex
* SizeDirEntry
;
349 if (!CcPinRead(pRootFcb
->FileObject
, &FileOffset
, SizeDirEntry
,
350 TRUE
, &Context
, (PVOID
*)&Entry
))
352 Status
= STATUS_UNSUCCESSFUL
;
356 RtlCopyMemory(Entry
, &VolumeLabelDirEntry
, SizeDirEntry
);
357 CcSetDirtyPinnedData(Context
, NULL
);
358 CcUnpinData(Context
);
359 Status
= STATUS_SUCCESS
;
364 vfatReleaseFCB(DeviceExt
, pRootFcb
);
365 if (!NT_SUCCESS(Status
))
370 /* Update volume label in memory */
371 DeviceObject
->Vpb
->VolumeLabelLength
= (USHORT
)FsLabelInfo
->VolumeLabelLength
;
372 RtlCopyMemory(DeviceObject
->Vpb
->VolumeLabel
, FsLabelInfo
->VolumeLabel
, DeviceObject
->Vpb
->VolumeLabelLength
);
379 * FUNCTION: Retrieve the specified volume information
382 VfatQueryVolumeInformation(
383 PVFAT_IRP_CONTEXT IrpContext
)
385 FS_INFORMATION_CLASS FsInformationClass
;
386 NTSTATUS RC
= STATUS_SUCCESS
;
393 DPRINT("VfatQueryVolumeInformation(IrpContext %p)\n", IrpContext
);
395 if (!ExAcquireResourceSharedLite(&((PDEVICE_EXTENSION
)IrpContext
->DeviceObject
->DeviceExtension
)->DirResource
,
396 BooleanFlagOn(IrpContext
->Flags
, IRPCONTEXT_CANWAIT
)))
398 DPRINT1("DirResource failed!\n");
399 return VfatMarkIrpContextForQueue(IrpContext
);
403 FsInformationClass
= IrpContext
->Stack
->Parameters
.QueryVolume
.FsInformationClass
;
404 BufferLength
= IrpContext
->Stack
->Parameters
.QueryVolume
.Length
;
405 SystemBuffer
= IrpContext
->Irp
->AssociatedIrp
.SystemBuffer
;
407 DPRINT("FsInformationClass %d\n", FsInformationClass
);
408 DPRINT("SystemBuffer %p\n", SystemBuffer
);
410 switch (FsInformationClass
)
412 case FileFsVolumeInformation
:
413 RC
= FsdGetFsVolumeInformation(IrpContext
->DeviceObject
,
418 case FileFsAttributeInformation
:
419 RC
= FsdGetFsAttributeInformation(IrpContext
->DeviceObject
->DeviceExtension
,
424 case FileFsSizeInformation
:
425 RC
= FsdGetFsSizeInformation(IrpContext
->DeviceObject
,
430 case FileFsDeviceInformation
:
431 RC
= FsdGetFsDeviceInformation(IrpContext
->DeviceObject
,
436 case FileFsFullSizeInformation
:
437 RC
= FsdGetFsFullSizeInformation(IrpContext
->DeviceObject
,
443 RC
= STATUS_NOT_SUPPORTED
;
446 ExReleaseResourceLite(&((PDEVICE_EXTENSION
)IrpContext
->DeviceObject
->DeviceExtension
)->DirResource
);
449 IrpContext
->Irp
->IoStatus
.Information
=
450 IrpContext
->Stack
->Parameters
.QueryVolume
.Length
- BufferLength
;
452 IrpContext
->Irp
->IoStatus
.Information
= 0;
459 * FUNCTION: Set the specified volume information
462 VfatSetVolumeInformation(
463 PVFAT_IRP_CONTEXT IrpContext
)
465 FS_INFORMATION_CLASS FsInformationClass
;
466 NTSTATUS Status
= STATUS_SUCCESS
;
469 PIO_STACK_LOCATION Stack
= IrpContext
->Stack
;
474 DPRINT("VfatSetVolumeInformation(IrpContext %p)\n", IrpContext
);
476 if (!ExAcquireResourceExclusiveLite(&((PDEVICE_EXTENSION
)IrpContext
->DeviceObject
->DeviceExtension
)->DirResource
,
477 BooleanFlagOn(IrpContext
->Flags
, IRPCONTEXT_CANWAIT
)))
479 return VfatMarkIrpContextForQueue(IrpContext
);
482 FsInformationClass
= Stack
->Parameters
.SetVolume
.FsInformationClass
;
483 BufferLength
= Stack
->Parameters
.SetVolume
.Length
;
484 SystemBuffer
= IrpContext
->Irp
->AssociatedIrp
.SystemBuffer
;
486 DPRINT("FsInformationClass %d\n", FsInformationClass
);
487 DPRINT("BufferLength %u\n", BufferLength
);
488 DPRINT("SystemBuffer %p\n", SystemBuffer
);
490 switch (FsInformationClass
)
492 case FileFsLabelInformation
:
493 Status
= FsdSetFsLabelInformation(IrpContext
->DeviceObject
,
498 Status
= STATUS_NOT_SUPPORTED
;
501 ExReleaseResourceLite(&((PDEVICE_EXTENSION
)IrpContext
->DeviceObject
->DeviceExtension
)->DirResource
);
502 IrpContext
->Irp
->IoStatus
.Information
= 0;