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 *****************************************************************/
15 /* FUNCTIONS ****************************************************************/
19 FsdGetFsVolumeInformation(
20 PDEVICE_OBJECT DeviceObject
,
21 PFILE_FS_VOLUME_INFORMATION FsVolumeInfo
,
24 DPRINT("FsdGetFsVolumeInformation()\n");
25 DPRINT("FsVolumeInfo = %p\n", FsVolumeInfo
);
26 DPRINT("BufferLength %lu\n", *BufferLength
);
28 DPRINT("Required length %lu\n", (sizeof(FILE_FS_VOLUME_INFORMATION
) + DeviceObject
->Vpb
->VolumeLabelLength
));
29 DPRINT("LabelLength %hu\n", DeviceObject
->Vpb
->VolumeLabelLength
);
30 DPRINT("Label %*.S\n", DeviceObject
->Vpb
->VolumeLabelLength
/ sizeof(WCHAR
), DeviceObject
->Vpb
->VolumeLabel
);
32 if (*BufferLength
< sizeof(FILE_FS_VOLUME_INFORMATION
))
33 return STATUS_INFO_LENGTH_MISMATCH
;
35 if (*BufferLength
< (sizeof(FILE_FS_VOLUME_INFORMATION
) + DeviceObject
->Vpb
->VolumeLabelLength
))
36 return STATUS_BUFFER_OVERFLOW
;
39 FsVolumeInfo
->VolumeSerialNumber
= DeviceObject
->Vpb
->SerialNumber
;
40 FsVolumeInfo
->VolumeLabelLength
= DeviceObject
->Vpb
->VolumeLabelLength
;
41 RtlCopyMemory(FsVolumeInfo
->VolumeLabel
, DeviceObject
->Vpb
->VolumeLabel
, FsVolumeInfo
->VolumeLabelLength
);
44 FsVolumeInfo
->VolumeCreationTime
.QuadPart
= 0;
45 FsVolumeInfo
->SupportsObjects
= FALSE
;
47 DPRINT("Finished FsdGetFsVolumeInformation()\n");
49 *BufferLength
-= (sizeof(FILE_FS_VOLUME_INFORMATION
) + DeviceObject
->Vpb
->VolumeLabelLength
);
51 DPRINT("BufferLength %lu\n", *BufferLength
);
53 return STATUS_SUCCESS
;
59 FsdGetFsAttributeInformation(
60 PDEVICE_EXTENSION DeviceExt
,
61 PFILE_FS_ATTRIBUTE_INFORMATION FsAttributeInfo
,
64 PCWSTR pName
; ULONG Length
;
65 DPRINT("FsdGetFsAttributeInformation()\n");
66 DPRINT("FsAttributeInfo = %p\n", FsAttributeInfo
);
67 DPRINT("BufferLength %lu\n", *BufferLength
);
69 if (*BufferLength
< sizeof (FILE_FS_ATTRIBUTE_INFORMATION
))
70 return STATUS_INFO_LENGTH_MISMATCH
;
72 if (DeviceExt
->FatInfo
.FatType
== FAT32
)
83 DPRINT("Required length %lu\n", (sizeof(FILE_FS_ATTRIBUTE_INFORMATION
) + Length
));
85 if (*BufferLength
< (sizeof(FILE_FS_ATTRIBUTE_INFORMATION
) + Length
))
86 return STATUS_BUFFER_OVERFLOW
;
88 FsAttributeInfo
->FileSystemAttributes
=
89 FILE_CASE_PRESERVED_NAMES
| FILE_UNICODE_ON_DISK
;
91 FsAttributeInfo
->MaximumComponentNameLength
= 255;
93 FsAttributeInfo
->FileSystemNameLength
= Length
;
95 RtlCopyMemory(FsAttributeInfo
->FileSystemName
, pName
, Length
);
97 DPRINT("Finished FsdGetFsAttributeInformation()\n");
99 *BufferLength
-= (sizeof(FILE_FS_ATTRIBUTE_INFORMATION
) + Length
);
100 DPRINT("BufferLength %lu\n", *BufferLength
);
102 return STATUS_SUCCESS
;
108 FsdGetFsSizeInformation(
109 PDEVICE_OBJECT DeviceObject
,
110 PFILE_FS_SIZE_INFORMATION FsSizeInfo
,
113 PDEVICE_EXTENSION DeviceExt
;
116 DPRINT("FsdGetFsSizeInformation()\n");
117 DPRINT("FsSizeInfo = %p\n", FsSizeInfo
);
119 if (*BufferLength
< sizeof(FILE_FS_SIZE_INFORMATION
))
120 return STATUS_BUFFER_OVERFLOW
;
122 DeviceExt
= DeviceObject
->DeviceExtension
;
123 Status
= CountAvailableClusters(DeviceExt
, &FsSizeInfo
->AvailableAllocationUnits
);
125 FsSizeInfo
->TotalAllocationUnits
.QuadPart
= DeviceExt
->FatInfo
.NumberOfClusters
;
126 FsSizeInfo
->SectorsPerAllocationUnit
= DeviceExt
->FatInfo
.SectorsPerCluster
;
127 FsSizeInfo
->BytesPerSector
= DeviceExt
->FatInfo
.BytesPerSector
;
129 DPRINT("Finished FsdGetFsSizeInformation()\n");
130 if (NT_SUCCESS(Status
))
131 *BufferLength
-= sizeof(FILE_FS_SIZE_INFORMATION
);
139 FsdGetFsDeviceInformation(
140 PDEVICE_OBJECT DeviceObject
,
141 PFILE_FS_DEVICE_INFORMATION FsDeviceInfo
,
144 DPRINT("FsdGetFsDeviceInformation()\n");
145 DPRINT("FsDeviceInfo = %p\n", FsDeviceInfo
);
146 DPRINT("BufferLength %lu\n", *BufferLength
);
147 DPRINT("Required length %lu\n", sizeof(FILE_FS_DEVICE_INFORMATION
));
149 if (*BufferLength
< sizeof(FILE_FS_DEVICE_INFORMATION
))
150 return STATUS_BUFFER_OVERFLOW
;
152 FsDeviceInfo
->DeviceType
= FILE_DEVICE_DISK
;
153 FsDeviceInfo
->Characteristics
= DeviceObject
->Characteristics
;
155 DPRINT("FsdGetFsDeviceInformation() finished.\n");
157 *BufferLength
-= sizeof(FILE_FS_DEVICE_INFORMATION
);
158 DPRINT("BufferLength %lu\n", *BufferLength
);
160 return STATUS_SUCCESS
;
166 FsdSetFsLabelInformation(
167 PDEVICE_OBJECT DeviceObject
,
168 PFILE_FS_LABEL_INFORMATION FsLabelInfo
)
170 PDEVICE_EXTENSION DeviceExt
;
171 PVOID Context
= NULL
;
175 LARGE_INTEGER FileOffset
;
176 BOOLEAN LabelFound
= FALSE
;
177 DIR_ENTRY VolumeLabelDirEntry
;
178 ULONG VolumeLabelDirIndex
;
180 NTSTATUS Status
= STATUS_UNSUCCESSFUL
;
182 UNICODE_STRING StringW
;
185 ULONG EntriesPerPage
;
187 DPRINT("FsdSetFsLabelInformation()\n");
189 DeviceExt
= (PDEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
191 if (sizeof(DeviceObject
->Vpb
->VolumeLabel
) < FsLabelInfo
->VolumeLabelLength
)
193 return STATUS_NAME_TOO_LONG
;
196 if (DeviceExt
->Flags
& VCB_IS_FATX
)
198 if (FsLabelInfo
->VolumeLabelLength
/ sizeof(WCHAR
) > 42)
199 return STATUS_NAME_TOO_LONG
;
201 SizeDirEntry
= sizeof(FATX_DIR_ENTRY
);
202 EntriesPerPage
= FATX_ENTRIES_PER_PAGE
;
206 if (FsLabelInfo
->VolumeLabelLength
/ sizeof(WCHAR
) > 11)
207 return STATUS_NAME_TOO_LONG
;
209 SizeDirEntry
= sizeof(FAT_DIR_ENTRY
);
210 EntriesPerPage
= FAT_ENTRIES_PER_PAGE
;
213 /* Create Volume label dir entry */
214 LabelLen
= FsLabelInfo
->VolumeLabelLength
/ sizeof(WCHAR
);
215 RtlZeroMemory(&VolumeLabelDirEntry
, SizeDirEntry
);
216 StringW
.Buffer
= FsLabelInfo
->VolumeLabel
;
217 StringW
.Length
= StringW
.MaximumLength
= (USHORT
)FsLabelInfo
->VolumeLabelLength
;
218 StringO
.Buffer
= cString
;
220 StringO
.MaximumLength
= 42;
221 Status
= RtlUnicodeStringToOemString(&StringO
, &StringW
, FALSE
);
222 if (!NT_SUCCESS(Status
))
225 if (DeviceExt
->Flags
& VCB_IS_FATX
)
227 RtlCopyMemory(VolumeLabelDirEntry
.FatX
.Filename
, cString
, LabelLen
);
228 memset(&VolumeLabelDirEntry
.FatX
.Filename
[LabelLen
], ' ', 42 - LabelLen
);
229 VolumeLabelDirEntry
.FatX
.Attrib
= _A_VOLID
;
233 RtlCopyMemory(VolumeLabelDirEntry
.Fat
.Filename
, cString
, max(sizeof(VolumeLabelDirEntry
.Fat
.Filename
), LabelLen
));
234 if (LabelLen
> sizeof(VolumeLabelDirEntry
.Fat
.Filename
))
236 memset(VolumeLabelDirEntry
.Fat
.Ext
, ' ', sizeof(VolumeLabelDirEntry
.Fat
.Ext
));
237 RtlCopyMemory(VolumeLabelDirEntry
.Fat
.Ext
, cString
+ sizeof(VolumeLabelDirEntry
.Fat
.Filename
), LabelLen
- sizeof(VolumeLabelDirEntry
.Fat
.Filename
));
241 memset(&VolumeLabelDirEntry
.Fat
.Filename
[LabelLen
], ' ', sizeof(VolumeLabelDirEntry
.Fat
.Filename
) - LabelLen
);
243 VolumeLabelDirEntry
.Fat
.Attrib
= _A_VOLID
;
246 pRootFcb
= vfatOpenRootFCB(DeviceExt
);
248 /* Search existing volume entry on disk */
249 FileOffset
.QuadPart
= 0;
250 if (CcPinRead(pRootFcb
->FileObject
, &FileOffset
, SizeDirEntry
, TRUE
, &Context
, (PVOID
*)&Entry
))
254 if (ENTRY_VOLUME(DeviceExt
, Entry
))
258 RtlCopyMemory(Entry
, &VolumeLabelDirEntry
, SizeDirEntry
);
259 CcSetDirtyPinnedData(Context
, NULL
);
260 Status
= STATUS_SUCCESS
;
264 if (ENTRY_END(DeviceExt
, Entry
))
270 Entry
= (PDIR_ENTRY
)((ULONG_PTR
)Entry
+ SizeDirEntry
);
271 if ((DirIndex
% EntriesPerPage
) == 0)
273 CcUnpinData(Context
);
274 FileOffset
.u
.LowPart
+= PAGE_SIZE
;
275 if (!CcPinRead(pRootFcb
->FileObject
, &FileOffset
, SizeDirEntry
, TRUE
, &Context
, (PVOID
*)&Entry
))
285 CcUnpinData(Context
);
291 /* Add new entry for label */
292 if (!vfatFindDirSpace(DeviceExt
, pRootFcb
, 1, &VolumeLabelDirIndex
))
293 Status
= STATUS_DISK_FULL
;
296 FileOffset
.u
.HighPart
= 0;
297 FileOffset
.u
.LowPart
= VolumeLabelDirIndex
* SizeDirEntry
;
298 if (!CcPinRead(pRootFcb
->FileObject
, &FileOffset
, SizeDirEntry
,
299 TRUE
, &Context
, (PVOID
*)&Entry
))
301 Status
= STATUS_UNSUCCESSFUL
;
305 RtlCopyMemory(Entry
, &VolumeLabelDirEntry
, SizeDirEntry
);
306 CcSetDirtyPinnedData(Context
, NULL
);
307 CcUnpinData(Context
);
308 Status
= STATUS_SUCCESS
;
313 vfatReleaseFCB(DeviceExt
, pRootFcb
);
314 if (!NT_SUCCESS(Status
))
319 /* Update volume label in memory */
320 DeviceObject
->Vpb
->VolumeLabelLength
= (USHORT
)FsLabelInfo
->VolumeLabelLength
;
321 RtlCopyMemory(DeviceObject
->Vpb
->VolumeLabel
, FsLabelInfo
->VolumeLabel
, DeviceObject
->Vpb
->VolumeLabelLength
);
328 VfatQueryVolumeInformation(
329 PVFAT_IRP_CONTEXT IrpContext
)
331 * FUNCTION: Retrieve the specified volume information
334 FS_INFORMATION_CLASS FsInformationClass
;
335 NTSTATUS RC
= STATUS_SUCCESS
;
342 DPRINT("VfatQueryVolumeInformation(IrpContext %p)\n", IrpContext
);
344 if (!ExAcquireResourceSharedLite(&((PDEVICE_EXTENSION
)IrpContext
->DeviceObject
->DeviceExtension
)->DirResource
,
345 (BOOLEAN
)(IrpContext
->Flags
& IRPCONTEXT_CANWAIT
)))
347 return VfatQueueRequest(IrpContext
);
351 FsInformationClass
= IrpContext
->Stack
->Parameters
.QueryVolume
.FsInformationClass
;
352 BufferLength
= IrpContext
->Stack
->Parameters
.QueryVolume
.Length
;
353 SystemBuffer
= IrpContext
->Irp
->AssociatedIrp
.SystemBuffer
;
355 DPRINT("FsInformationClass %d\n", FsInformationClass
);
356 DPRINT("SystemBuffer %p\n", SystemBuffer
);
358 switch (FsInformationClass
)
360 case FileFsVolumeInformation
:
361 RC
= FsdGetFsVolumeInformation(IrpContext
->DeviceObject
,
366 case FileFsAttributeInformation
:
367 RC
= FsdGetFsAttributeInformation(IrpContext
->DeviceObject
->DeviceExtension
,
372 case FileFsSizeInformation
:
373 RC
= FsdGetFsSizeInformation(IrpContext
->DeviceObject
,
378 case FileFsDeviceInformation
:
379 RC
= FsdGetFsDeviceInformation(IrpContext
->DeviceObject
,
385 RC
= STATUS_NOT_SUPPORTED
;
388 ExReleaseResourceLite(&((PDEVICE_EXTENSION
)IrpContext
->DeviceObject
->DeviceExtension
)->DirResource
);
389 IrpContext
->Irp
->IoStatus
.Status
= RC
;
391 IrpContext
->Irp
->IoStatus
.Information
=
392 IrpContext
->Stack
->Parameters
.QueryVolume
.Length
- BufferLength
;
394 IrpContext
->Irp
->IoStatus
.Information
= 0;
395 IoCompleteRequest(IrpContext
->Irp
, IO_NO_INCREMENT
);
396 VfatFreeIrpContext(IrpContext
);
403 VfatSetVolumeInformation(
404 PVFAT_IRP_CONTEXT IrpContext
)
406 * FUNCTION: Set the specified volume information
409 FS_INFORMATION_CLASS FsInformationClass
;
410 NTSTATUS Status
= STATUS_SUCCESS
;
413 PIO_STACK_LOCATION Stack
= IrpContext
->Stack
;
418 DPRINT("VfatSetVolumeInformation(IrpContext %p)\n", IrpContext
);
420 if (!ExAcquireResourceExclusiveLite(&((PDEVICE_EXTENSION
)IrpContext
->DeviceObject
->DeviceExtension
)->DirResource
,
421 (BOOLEAN
)(IrpContext
->Flags
& IRPCONTEXT_CANWAIT
)))
423 return VfatQueueRequest(IrpContext
);
426 FsInformationClass
= Stack
->Parameters
.SetVolume
.FsInformationClass
;
427 BufferLength
= Stack
->Parameters
.SetVolume
.Length
;
428 SystemBuffer
= IrpContext
->Irp
->AssociatedIrp
.SystemBuffer
;
430 DPRINT("FsInformationClass %d\n", FsInformationClass
);
431 DPRINT("BufferLength %u\n", BufferLength
);
432 DPRINT("SystemBuffer %p\n", SystemBuffer
);
434 switch (FsInformationClass
)
436 case FileFsLabelInformation
:
437 Status
= FsdSetFsLabelInformation(IrpContext
->DeviceObject
,
442 Status
= STATUS_NOT_SUPPORTED
;
445 ExReleaseResourceLite(&((PDEVICE_EXTENSION
)IrpContext
->DeviceObject
->DeviceExtension
)->DirResource
);
446 IrpContext
->Irp
->IoStatus
.Status
= Status
;
447 IrpContext
->Irp
->IoStatus
.Information
= 0;
448 IoCompleteRequest(IrpContext
->Irp
, IO_NO_INCREMENT
);
449 VfatFreeIrpContext(IrpContext
);