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
,
27 PDEVICE_EXTENSION DeviceExt
;
29 DPRINT("FsdGetFsVolumeInformation()\n");
30 DPRINT("FsVolumeInfo = %p\n", FsVolumeInfo
);
31 DPRINT("BufferLength %lu\n", *BufferLength
);
33 DPRINT("Required length %lu\n", FIELD_OFFSET(FILE_FS_VOLUME_INFORMATION
, VolumeLabel
) + DeviceObject
->Vpb
->VolumeLabelLength
);
34 DPRINT("LabelLength %hu\n", DeviceObject
->Vpb
->VolumeLabelLength
);
35 DPRINT("Label %.*S\n", DeviceObject
->Vpb
->VolumeLabelLength
/ sizeof(WCHAR
), DeviceObject
->Vpb
->VolumeLabel
);
37 ASSERT(*BufferLength
>= sizeof(FILE_FS_VOLUME_INFORMATION
));
38 *BufferLength
-= FIELD_OFFSET(FILE_FS_VOLUME_INFORMATION
, VolumeLabel
);
40 DeviceExt
= DeviceObject
->DeviceExtension
;
43 FsVolumeInfo
->VolumeSerialNumber
= DeviceObject
->Vpb
->SerialNumber
;
44 FsVolumeInfo
->VolumeLabelLength
= DeviceObject
->Vpb
->VolumeLabelLength
;
45 if (*BufferLength
< DeviceObject
->Vpb
->VolumeLabelLength
)
47 Status
= STATUS_BUFFER_OVERFLOW
;
48 RtlCopyMemory(FsVolumeInfo
->VolumeLabel
,
49 DeviceObject
->Vpb
->VolumeLabel
,
55 Status
= STATUS_SUCCESS
;
56 RtlCopyMemory(FsVolumeInfo
->VolumeLabel
,
57 DeviceObject
->Vpb
->VolumeLabel
,
58 FsVolumeInfo
->VolumeLabelLength
);
59 *BufferLength
-= DeviceObject
->Vpb
->VolumeLabelLength
;
62 if (vfatVolumeIsFatX(DeviceExt
))
64 FsdDosDateTimeToSystemTime(DeviceExt
,
65 DeviceExt
->VolumeFcb
->entry
.FatX
.CreationDate
,
66 DeviceExt
->VolumeFcb
->entry
.FatX
.CreationTime
,
67 &FsVolumeInfo
->VolumeCreationTime
);
71 FsdDosDateTimeToSystemTime(DeviceExt
,
72 DeviceExt
->VolumeFcb
->entry
.Fat
.CreationDate
,
73 DeviceExt
->VolumeFcb
->entry
.Fat
.CreationTime
,
74 &FsVolumeInfo
->VolumeCreationTime
);
77 FsVolumeInfo
->SupportsObjects
= FALSE
;
79 DPRINT("Finished FsdGetFsVolumeInformation()\n");
80 DPRINT("BufferLength %lu\n", *BufferLength
);
88 FsdGetFsAttributeInformation(
89 PDEVICE_EXTENSION DeviceExt
,
90 PFILE_FS_ATTRIBUTE_INFORMATION FsAttributeInfo
,
97 DPRINT("FsdGetFsAttributeInformation()\n");
98 DPRINT("FsAttributeInfo = %p\n", FsAttributeInfo
);
99 DPRINT("BufferLength %lu\n", *BufferLength
);
101 ASSERT(*BufferLength
>= sizeof(FILE_FS_ATTRIBUTE_INFORMATION
));
102 *BufferLength
-= FIELD_OFFSET(FILE_FS_ATTRIBUTE_INFORMATION
, FileSystemName
);
104 if (DeviceExt
->FatInfo
.FatType
== FAT32
)
113 Length
= wcslen(pName
) * sizeof(WCHAR
);
114 DPRINT("Required length %lu\n", (FIELD_OFFSET(FILE_FS_ATTRIBUTE_INFORMATION
, FileSystemName
) + Length
));
116 if (*BufferLength
< Length
)
118 Status
= STATUS_BUFFER_OVERFLOW
;
119 Length
= *BufferLength
;
123 Status
= STATUS_SUCCESS
;
126 FsAttributeInfo
->FileSystemAttributes
=
127 FILE_CASE_PRESERVED_NAMES
| FILE_UNICODE_ON_DISK
;
129 FsAttributeInfo
->MaximumComponentNameLength
= 255;
131 FsAttributeInfo
->FileSystemNameLength
= Length
;
133 RtlCopyMemory(FsAttributeInfo
->FileSystemName
, pName
, Length
);
135 DPRINT("Finished FsdGetFsAttributeInformation()\n");
137 *BufferLength
-= Length
;
138 DPRINT("BufferLength %lu\n", *BufferLength
);
146 FsdGetFsSizeInformation(
147 PDEVICE_OBJECT DeviceObject
,
148 PFILE_FS_SIZE_INFORMATION FsSizeInfo
,
151 PDEVICE_EXTENSION DeviceExt
;
154 DPRINT("FsdGetFsSizeInformation()\n");
155 DPRINT("FsSizeInfo = %p\n", FsSizeInfo
);
157 ASSERT(*BufferLength
>= sizeof(FILE_FS_SIZE_INFORMATION
));
159 DeviceExt
= DeviceObject
->DeviceExtension
;
160 Status
= CountAvailableClusters(DeviceExt
, &FsSizeInfo
->AvailableAllocationUnits
);
162 FsSizeInfo
->TotalAllocationUnits
.QuadPart
= DeviceExt
->FatInfo
.NumberOfClusters
;
163 FsSizeInfo
->SectorsPerAllocationUnit
= DeviceExt
->FatInfo
.SectorsPerCluster
;
164 FsSizeInfo
->BytesPerSector
= DeviceExt
->FatInfo
.BytesPerSector
;
166 DPRINT("Finished FsdGetFsSizeInformation()\n");
167 if (NT_SUCCESS(Status
))
168 *BufferLength
-= sizeof(FILE_FS_SIZE_INFORMATION
);
176 FsdGetFsDeviceInformation(
177 PDEVICE_OBJECT DeviceObject
,
178 PFILE_FS_DEVICE_INFORMATION FsDeviceInfo
,
181 DPRINT("FsdGetFsDeviceInformation()\n");
182 DPRINT("FsDeviceInfo = %p\n", FsDeviceInfo
);
183 DPRINT("BufferLength %lu\n", *BufferLength
);
184 DPRINT("Required length %lu\n", sizeof(FILE_FS_DEVICE_INFORMATION
));
186 ASSERT(*BufferLength
>= sizeof(FILE_FS_DEVICE_INFORMATION
));
188 FsDeviceInfo
->DeviceType
= FILE_DEVICE_DISK
;
189 FsDeviceInfo
->Characteristics
= DeviceObject
->Characteristics
;
191 DPRINT("FsdGetFsDeviceInformation() finished.\n");
193 *BufferLength
-= sizeof(FILE_FS_DEVICE_INFORMATION
);
194 DPRINT("BufferLength %lu\n", *BufferLength
);
196 return STATUS_SUCCESS
;
202 FsdGetFsFullSizeInformation(
203 PDEVICE_OBJECT DeviceObject
,
204 PFILE_FS_FULL_SIZE_INFORMATION FsSizeInfo
,
207 PDEVICE_EXTENSION DeviceExt
;
210 DPRINT("FsdGetFsFullSizeInformation()\n");
211 DPRINT("FsSizeInfo = %p\n", FsSizeInfo
);
213 ASSERT(*BufferLength
>= sizeof(FILE_FS_FULL_SIZE_INFORMATION
));
215 DeviceExt
= DeviceObject
->DeviceExtension
;
216 Status
= CountAvailableClusters(DeviceExt
, &FsSizeInfo
->CallerAvailableAllocationUnits
);
218 FsSizeInfo
->TotalAllocationUnits
.QuadPart
= DeviceExt
->FatInfo
.NumberOfClusters
;
219 FsSizeInfo
->ActualAvailableAllocationUnits
.QuadPart
= FsSizeInfo
->CallerAvailableAllocationUnits
.QuadPart
;
220 FsSizeInfo
->SectorsPerAllocationUnit
= DeviceExt
->FatInfo
.SectorsPerCluster
;
221 FsSizeInfo
->BytesPerSector
= DeviceExt
->FatInfo
.BytesPerSector
;
223 DPRINT("Finished FsdGetFsFullSizeInformation()\n");
224 if (NT_SUCCESS(Status
))
225 *BufferLength
-= sizeof(FILE_FS_FULL_SIZE_INFORMATION
);
233 FsdSetFsLabelInformation(
234 PDEVICE_OBJECT DeviceObject
,
235 PFILE_FS_LABEL_INFORMATION FsLabelInfo
)
237 PDEVICE_EXTENSION DeviceExt
;
238 PVOID Context
= NULL
;
242 LARGE_INTEGER FileOffset
;
243 BOOLEAN LabelFound
= FALSE
;
244 DIR_ENTRY VolumeLabelDirEntry
;
245 ULONG VolumeLabelDirIndex
;
247 NTSTATUS Status
= STATUS_UNSUCCESSFUL
;
249 UNICODE_STRING StringW
;
252 ULONG EntriesPerPage
;
255 DPRINT("FsdSetFsLabelInformation()\n");
257 DeviceExt
= (PDEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
258 IsFatX
= vfatVolumeIsFatX(DeviceExt
);
260 if (sizeof(DeviceObject
->Vpb
->VolumeLabel
) < FsLabelInfo
->VolumeLabelLength
)
262 return STATUS_NAME_TOO_LONG
;
267 if (FsLabelInfo
->VolumeLabelLength
/ sizeof(WCHAR
) > 42)
268 return STATUS_NAME_TOO_LONG
;
270 SizeDirEntry
= sizeof(FATX_DIR_ENTRY
);
271 EntriesPerPage
= FATX_ENTRIES_PER_PAGE
;
275 if (FsLabelInfo
->VolumeLabelLength
/ sizeof(WCHAR
) > 11)
276 return STATUS_NAME_TOO_LONG
;
278 SizeDirEntry
= sizeof(FAT_DIR_ENTRY
);
279 EntriesPerPage
= FAT_ENTRIES_PER_PAGE
;
282 /* Create Volume label dir entry */
283 LabelLen
= FsLabelInfo
->VolumeLabelLength
/ sizeof(WCHAR
);
284 RtlZeroMemory(&VolumeLabelDirEntry
, SizeDirEntry
);
285 StringW
.Buffer
= FsLabelInfo
->VolumeLabel
;
286 StringW
.Length
= StringW
.MaximumLength
= (USHORT
)FsLabelInfo
->VolumeLabelLength
;
287 StringO
.Buffer
= cString
;
289 StringO
.MaximumLength
= 42;
290 Status
= RtlUnicodeStringToOemString(&StringO
, &StringW
, FALSE
);
291 if (!NT_SUCCESS(Status
))
296 RtlCopyMemory(VolumeLabelDirEntry
.FatX
.Filename
, cString
, LabelLen
);
297 memset(&VolumeLabelDirEntry
.FatX
.Filename
[LabelLen
], ' ', 42 - LabelLen
);
298 VolumeLabelDirEntry
.FatX
.Attrib
= _A_VOLID
;
302 RtlCopyMemory(VolumeLabelDirEntry
.Fat
.Filename
, cString
, max(sizeof(VolumeLabelDirEntry
.Fat
.Filename
), LabelLen
));
303 if (LabelLen
> sizeof(VolumeLabelDirEntry
.Fat
.Filename
))
305 memset(VolumeLabelDirEntry
.Fat
.Ext
, ' ', sizeof(VolumeLabelDirEntry
.Fat
.Ext
));
306 RtlCopyMemory(VolumeLabelDirEntry
.Fat
.Ext
, cString
+ sizeof(VolumeLabelDirEntry
.Fat
.Filename
), LabelLen
- sizeof(VolumeLabelDirEntry
.Fat
.Filename
));
310 memset(&VolumeLabelDirEntry
.Fat
.Filename
[LabelLen
], ' ', sizeof(VolumeLabelDirEntry
.Fat
.Filename
) - LabelLen
);
312 VolumeLabelDirEntry
.Fat
.Attrib
= _A_VOLID
;
315 pRootFcb
= vfatOpenRootFCB(DeviceExt
);
317 /* Search existing volume entry on disk */
318 FileOffset
.QuadPart
= 0;
321 CcPinRead(pRootFcb
->FileObject
, &FileOffset
, SizeDirEntry
, PIN_WAIT
, &Context
, (PVOID
*)&Entry
);
323 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
325 Status
= _SEH2_GetExceptionCode();
329 if (NT_SUCCESS(Status
))
333 if (ENTRY_VOLUME(IsFatX
, Entry
))
337 RtlCopyMemory(Entry
, &VolumeLabelDirEntry
, SizeDirEntry
);
338 CcSetDirtyPinnedData(Context
, NULL
);
339 Status
= STATUS_SUCCESS
;
343 if (ENTRY_END(IsFatX
, Entry
))
349 Entry
= (PDIR_ENTRY
)((ULONG_PTR
)Entry
+ SizeDirEntry
);
350 if ((DirIndex
% EntriesPerPage
) == 0)
352 CcUnpinData(Context
);
353 FileOffset
.u
.LowPart
+= PAGE_SIZE
;
356 CcPinRead(pRootFcb
->FileObject
, &FileOffset
, SizeDirEntry
, PIN_WAIT
, &Context
, (PVOID
*)&Entry
);
358 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
360 Status
= _SEH2_GetExceptionCode();
364 if (!NT_SUCCESS(Status
))
374 CcUnpinData(Context
);
380 /* Add new entry for label */
381 if (!vfatFindDirSpace(DeviceExt
, pRootFcb
, 1, &VolumeLabelDirIndex
))
382 Status
= STATUS_DISK_FULL
;
385 FileOffset
.u
.HighPart
= 0;
386 FileOffset
.u
.LowPart
= VolumeLabelDirIndex
* SizeDirEntry
;
388 Status
= STATUS_SUCCESS
;
391 CcPinRead(pRootFcb
->FileObject
, &FileOffset
, SizeDirEntry
, PIN_WAIT
, &Context
, (PVOID
*)&Entry
);
393 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
395 Status
= _SEH2_GetExceptionCode();
399 if (NT_SUCCESS(Status
))
401 RtlCopyMemory(Entry
, &VolumeLabelDirEntry
, SizeDirEntry
);
402 CcSetDirtyPinnedData(Context
, NULL
);
403 CcUnpinData(Context
);
404 Status
= STATUS_SUCCESS
;
409 vfatReleaseFCB(DeviceExt
, pRootFcb
);
410 if (!NT_SUCCESS(Status
))
415 /* Update volume label in memory */
416 DeviceObject
->Vpb
->VolumeLabelLength
= (USHORT
)FsLabelInfo
->VolumeLabelLength
;
417 RtlCopyMemory(DeviceObject
->Vpb
->VolumeLabel
, FsLabelInfo
->VolumeLabel
, DeviceObject
->Vpb
->VolumeLabelLength
);
424 * FUNCTION: Retrieve the specified volume information
427 VfatQueryVolumeInformation(
428 PVFAT_IRP_CONTEXT IrpContext
)
430 FS_INFORMATION_CLASS FsInformationClass
;
431 NTSTATUS RC
= STATUS_SUCCESS
;
438 DPRINT("VfatQueryVolumeInformation(IrpContext %p)\n", IrpContext
);
440 if (!ExAcquireResourceSharedLite(&((PDEVICE_EXTENSION
)IrpContext
->DeviceObject
->DeviceExtension
)->DirResource
,
441 BooleanFlagOn(IrpContext
->Flags
, IRPCONTEXT_CANWAIT
)))
443 DPRINT1("DirResource failed!\n");
444 return VfatMarkIrpContextForQueue(IrpContext
);
448 FsInformationClass
= IrpContext
->Stack
->Parameters
.QueryVolume
.FsInformationClass
;
449 BufferLength
= IrpContext
->Stack
->Parameters
.QueryVolume
.Length
;
450 SystemBuffer
= IrpContext
->Irp
->AssociatedIrp
.SystemBuffer
;
452 DPRINT("FsInformationClass %d\n", FsInformationClass
);
453 DPRINT("SystemBuffer %p\n", SystemBuffer
);
455 switch (FsInformationClass
)
457 case FileFsVolumeInformation
:
458 RC
= FsdGetFsVolumeInformation(IrpContext
->DeviceObject
,
463 case FileFsAttributeInformation
:
464 RC
= FsdGetFsAttributeInformation(IrpContext
->DeviceObject
->DeviceExtension
,
469 case FileFsSizeInformation
:
470 RC
= FsdGetFsSizeInformation(IrpContext
->DeviceObject
,
475 case FileFsDeviceInformation
:
476 RC
= FsdGetFsDeviceInformation(IrpContext
->DeviceObject
,
481 case FileFsFullSizeInformation
:
482 RC
= FsdGetFsFullSizeInformation(IrpContext
->DeviceObject
,
488 RC
= STATUS_NOT_SUPPORTED
;
491 ExReleaseResourceLite(&((PDEVICE_EXTENSION
)IrpContext
->DeviceObject
->DeviceExtension
)->DirResource
);
493 IrpContext
->Irp
->IoStatus
.Information
=
494 IrpContext
->Stack
->Parameters
.QueryVolume
.Length
- BufferLength
;
501 * FUNCTION: Set the specified volume information
504 VfatSetVolumeInformation(
505 PVFAT_IRP_CONTEXT IrpContext
)
507 FS_INFORMATION_CLASS FsInformationClass
;
508 NTSTATUS Status
= STATUS_SUCCESS
;
511 PIO_STACK_LOCATION Stack
= IrpContext
->Stack
;
516 DPRINT("VfatSetVolumeInformation(IrpContext %p)\n", IrpContext
);
518 if (!ExAcquireResourceExclusiveLite(&((PDEVICE_EXTENSION
)IrpContext
->DeviceObject
->DeviceExtension
)->DirResource
,
519 BooleanFlagOn(IrpContext
->Flags
, IRPCONTEXT_CANWAIT
)))
521 return VfatMarkIrpContextForQueue(IrpContext
);
524 FsInformationClass
= Stack
->Parameters
.SetVolume
.FsInformationClass
;
525 BufferLength
= Stack
->Parameters
.SetVolume
.Length
;
526 SystemBuffer
= IrpContext
->Irp
->AssociatedIrp
.SystemBuffer
;
528 DPRINT("FsInformationClass %d\n", FsInformationClass
);
529 DPRINT("BufferLength %u\n", BufferLength
);
530 DPRINT("SystemBuffer %p\n", SystemBuffer
);
532 switch (FsInformationClass
)
534 case FileFsLabelInformation
:
535 Status
= FsdSetFsLabelInformation(IrpContext
->DeviceObject
,
540 Status
= STATUS_NOT_SUPPORTED
;
543 ExReleaseResourceLite(&((PDEVICE_EXTENSION
)IrpContext
->DeviceObject
->DeviceExtension
)->DirResource
);
544 IrpContext
->Irp
->IoStatus
.Information
= 0;