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 ****************************************************************/
18 FsdGetFsVolumeInformation(PDEVICE_OBJECT DeviceObject
,
19 PFILE_FS_VOLUME_INFORMATION FsVolumeInfo
,
22 DPRINT("FsdGetFsVolumeInformation()\n");
23 DPRINT("FsVolumeInfo = %p\n", FsVolumeInfo
);
24 DPRINT("BufferLength %lu\n", *BufferLength
);
26 DPRINT("Required length %lu\n", (sizeof(FILE_FS_VOLUME_INFORMATION
) + DeviceObject
->Vpb
->VolumeLabelLength
));
27 DPRINT("LabelLength %hu\n", DeviceObject
->Vpb
->VolumeLabelLength
);
28 DPRINT("Label %*.S\n", DeviceObject
->Vpb
->VolumeLabelLength
/ sizeof(WCHAR
), DeviceObject
->Vpb
->VolumeLabel
);
30 if (*BufferLength
< sizeof(FILE_FS_VOLUME_INFORMATION
))
31 return STATUS_INFO_LENGTH_MISMATCH
;
33 if (*BufferLength
< (sizeof(FILE_FS_VOLUME_INFORMATION
) + DeviceObject
->Vpb
->VolumeLabelLength
))
34 return STATUS_BUFFER_OVERFLOW
;
37 FsVolumeInfo
->VolumeSerialNumber
= DeviceObject
->Vpb
->SerialNumber
;
38 FsVolumeInfo
->VolumeLabelLength
= DeviceObject
->Vpb
->VolumeLabelLength
;
39 RtlCopyMemory(FsVolumeInfo
->VolumeLabel
, DeviceObject
->Vpb
->VolumeLabel
, FsVolumeInfo
->VolumeLabelLength
);
42 FsVolumeInfo
->VolumeCreationTime
.QuadPart
= 0;
43 FsVolumeInfo
->SupportsObjects
= FALSE
;
45 DPRINT("Finished FsdGetFsVolumeInformation()\n");
47 *BufferLength
-= (sizeof(FILE_FS_VOLUME_INFORMATION
) + DeviceObject
->Vpb
->VolumeLabelLength
);
49 DPRINT("BufferLength %lu\n", *BufferLength
);
51 return(STATUS_SUCCESS
);
56 FsdGetFsAttributeInformation(PDEVICE_EXTENSION DeviceExt
,
57 PFILE_FS_ATTRIBUTE_INFORMATION FsAttributeInfo
,
60 PCWSTR pName
; ULONG Length
;
61 DPRINT("FsdGetFsAttributeInformation()\n");
62 DPRINT("FsAttributeInfo = %p\n", FsAttributeInfo
);
63 DPRINT("BufferLength %lu\n", *BufferLength
);
65 if (*BufferLength
< sizeof (FILE_FS_ATTRIBUTE_INFORMATION
))
66 return STATUS_INFO_LENGTH_MISMATCH
;
68 if (DeviceExt
->FatInfo
.FatType
== FAT32
)
79 DPRINT("Required length %lu\n", (sizeof(FILE_FS_ATTRIBUTE_INFORMATION
) + Length
));
81 if (*BufferLength
< (sizeof(FILE_FS_ATTRIBUTE_INFORMATION
) + Length
))
82 return STATUS_BUFFER_OVERFLOW
;
84 FsAttributeInfo
->FileSystemAttributes
=
85 FILE_CASE_PRESERVED_NAMES
| FILE_UNICODE_ON_DISK
;
87 FsAttributeInfo
->MaximumComponentNameLength
= 255;
89 FsAttributeInfo
->FileSystemNameLength
= Length
;
91 RtlCopyMemory(FsAttributeInfo
->FileSystemName
, pName
, Length
);
93 DPRINT("Finished FsdGetFsAttributeInformation()\n");
95 *BufferLength
-= (sizeof(FILE_FS_ATTRIBUTE_INFORMATION
) + Length
);
96 DPRINT("BufferLength %lu\n", *BufferLength
);
98 return(STATUS_SUCCESS
);
103 FsdGetFsSizeInformation(PDEVICE_OBJECT DeviceObject
,
104 PFILE_FS_SIZE_INFORMATION FsSizeInfo
,
107 PDEVICE_EXTENSION DeviceExt
;
110 DPRINT("FsdGetFsSizeInformation()\n");
111 DPRINT("FsSizeInfo = %p\n", FsSizeInfo
);
113 if (*BufferLength
< sizeof(FILE_FS_SIZE_INFORMATION
))
114 return(STATUS_BUFFER_OVERFLOW
);
116 DeviceExt
= DeviceObject
->DeviceExtension
;
117 Status
= CountAvailableClusters(DeviceExt
, &FsSizeInfo
->AvailableAllocationUnits
);
119 FsSizeInfo
->TotalAllocationUnits
.QuadPart
= DeviceExt
->FatInfo
.NumberOfClusters
;
120 FsSizeInfo
->SectorsPerAllocationUnit
= DeviceExt
->FatInfo
.SectorsPerCluster
;
121 FsSizeInfo
->BytesPerSector
= DeviceExt
->FatInfo
.BytesPerSector
;
123 DPRINT("Finished FsdGetFsSizeInformation()\n");
124 if (NT_SUCCESS(Status
))
125 *BufferLength
-= sizeof(FILE_FS_SIZE_INFORMATION
);
132 FsdGetFsDeviceInformation
134 PDEVICE_OBJECT DeviceObject
,
135 PFILE_FS_DEVICE_INFORMATION FsDeviceInfo
,
139 DPRINT("FsdGetFsDeviceInformation()\n");
140 DPRINT("FsDeviceInfo = %p\n", FsDeviceInfo
);
141 DPRINT("BufferLength %lu\n", *BufferLength
);
142 DPRINT("Required length %lu\n", sizeof(FILE_FS_DEVICE_INFORMATION
));
144 if (*BufferLength
< sizeof(FILE_FS_DEVICE_INFORMATION
))
145 return(STATUS_BUFFER_OVERFLOW
);
147 FsDeviceInfo
->DeviceType
= FILE_DEVICE_DISK
;
148 FsDeviceInfo
->Characteristics
= DeviceObject
->Characteristics
;
150 DPRINT("FsdGetFsDeviceInformation() finished.\n");
152 *BufferLength
-= sizeof(FILE_FS_DEVICE_INFORMATION
);
153 DPRINT("BufferLength %lu\n", *BufferLength
);
155 return(STATUS_SUCCESS
);
160 FsdSetFsLabelInformation(PDEVICE_OBJECT DeviceObject
,
161 PFILE_FS_LABEL_INFORMATION FsLabelInfo
)
163 PDEVICE_EXTENSION DeviceExt
;
164 PVOID Context
= NULL
;
168 LARGE_INTEGER FileOffset
;
169 BOOLEAN LabelFound
= FALSE
;
170 DIR_ENTRY VolumeLabelDirEntry
;
171 ULONG VolumeLabelDirIndex
;
173 NTSTATUS Status
= STATUS_UNSUCCESSFUL
;
175 UNICODE_STRING StringW
;
178 ULONG EntriesPerPage
;
180 DPRINT("FsdSetFsLabelInformation()\n");
182 DeviceExt
= (PDEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
184 if (sizeof(DeviceObject
->Vpb
->VolumeLabel
) < FsLabelInfo
->VolumeLabelLength
)
186 return STATUS_NAME_TOO_LONG
;
189 if (DeviceExt
->Flags
& VCB_IS_FATX
)
191 if (FsLabelInfo
->VolumeLabelLength
/ sizeof(WCHAR
) > 42)
192 return STATUS_NAME_TOO_LONG
;
193 SizeDirEntry
= sizeof(FATX_DIR_ENTRY
);
194 EntriesPerPage
= FATX_ENTRIES_PER_PAGE
;
198 if (FsLabelInfo
->VolumeLabelLength
/ sizeof(WCHAR
) > 11)
199 return STATUS_NAME_TOO_LONG
;
200 SizeDirEntry
= sizeof(FAT_DIR_ENTRY
);
201 EntriesPerPage
= FAT_ENTRIES_PER_PAGE
;
204 /* Create Volume label dir entry */
205 LabelLen
= FsLabelInfo
->VolumeLabelLength
/ sizeof(WCHAR
);
206 RtlZeroMemory(&VolumeLabelDirEntry
, SizeDirEntry
);
207 StringW
.Buffer
= FsLabelInfo
->VolumeLabel
;
208 StringW
.Length
= StringW
.MaximumLength
= (USHORT
)FsLabelInfo
->VolumeLabelLength
;
209 StringO
.Buffer
= cString
;
211 StringO
.MaximumLength
= 42;
212 Status
= RtlUnicodeStringToOemString(&StringO
, &StringW
, FALSE
);
213 if (!NT_SUCCESS(Status
))
215 if (DeviceExt
->Flags
& VCB_IS_FATX
)
217 RtlCopyMemory(VolumeLabelDirEntry
.FatX
.Filename
, cString
, LabelLen
);
218 memset(&VolumeLabelDirEntry
.FatX
.Filename
[LabelLen
], ' ', 42 - LabelLen
);
219 VolumeLabelDirEntry
.FatX
.Attrib
= 0x08;
223 RtlCopyMemory(VolumeLabelDirEntry
.Fat
.Filename
, cString
, LabelLen
);
224 memset(&VolumeLabelDirEntry
.Fat
.Filename
[LabelLen
], ' ', 11 - LabelLen
);
225 VolumeLabelDirEntry
.Fat
.Attrib
= 0x08;
228 pRootFcb
= vfatOpenRootFCB(DeviceExt
);
230 /* Search existing volume entry on disk */
231 FileOffset
.QuadPart
= 0;
232 if (CcPinRead(pRootFcb
->FileObject
, &FileOffset
, PAGE_SIZE
, TRUE
, &Context
, (PVOID
*)&Entry
))
236 if (ENTRY_VOLUME(DeviceExt
, Entry
))
240 RtlCopyMemory(Entry
, &VolumeLabelDirEntry
, SizeDirEntry
);
241 CcSetDirtyPinnedData(Context
, NULL
);
242 Status
= STATUS_SUCCESS
;
245 if (ENTRY_END(DeviceExt
, Entry
))
250 Entry
= (PDIR_ENTRY
)((ULONG_PTR
)Entry
+ SizeDirEntry
);
251 if ((DirIndex
% EntriesPerPage
) == 0)
253 CcUnpinData(Context
);
254 FileOffset
.u
.LowPart
+= PAGE_SIZE
;
255 if (!CcPinRead(pRootFcb
->FileObject
, &FileOffset
, PAGE_SIZE
, TRUE
, &Context
, (PVOID
*)&Entry
))
264 CcUnpinData(Context
);
269 /* Add new entry for label */
270 if (!vfatFindDirSpace(DeviceExt
, pRootFcb
, 1, &VolumeLabelDirIndex
))
271 Status
= STATUS_DISK_FULL
;
274 FileOffset
.u
.HighPart
= 0;
275 FileOffset
.u
.LowPart
= VolumeLabelDirIndex
* SizeDirEntry
;
276 CcPinRead(pRootFcb
->FileObject
, &FileOffset
, SizeDirEntry
,
277 TRUE
, &Context
, (PVOID
*)&Entry
);
278 RtlCopyMemory(Entry
, &VolumeLabelDirEntry
, SizeDirEntry
);
279 CcSetDirtyPinnedData(Context
, NULL
);
280 CcUnpinData(Context
);
281 Status
= STATUS_SUCCESS
;
285 vfatReleaseFCB(DeviceExt
, pRootFcb
);
286 if (!NT_SUCCESS(Status
))
291 /* Update volume label in memory */
292 DeviceObject
->Vpb
->VolumeLabelLength
= (USHORT
)FsLabelInfo
->VolumeLabelLength
;
293 RtlCopyMemory(DeviceObject
->Vpb
->VolumeLabel
, FsLabelInfo
->VolumeLabel
, DeviceObject
->Vpb
->VolumeLabelLength
);
299 NTSTATUS
VfatQueryVolumeInformation(PVFAT_IRP_CONTEXT IrpContext
)
301 * FUNCTION: Retrieve the specified volume information
304 FS_INFORMATION_CLASS FsInformationClass
;
305 NTSTATUS RC
= STATUS_SUCCESS
;
312 DPRINT("VfatQueryVolumeInformation(IrpContext %p)\n", IrpContext
);
314 if (!ExAcquireResourceSharedLite(&((PDEVICE_EXTENSION
)IrpContext
->DeviceObject
->DeviceExtension
)->DirResource
,
315 (BOOLEAN
)(IrpContext
->Flags
& IRPCONTEXT_CANWAIT
)))
317 return VfatQueueRequest (IrpContext
);
321 FsInformationClass
= IrpContext
->Stack
->Parameters
.QueryVolume
.FsInformationClass
;
322 BufferLength
= IrpContext
->Stack
->Parameters
.QueryVolume
.Length
;
323 SystemBuffer
= IrpContext
->Irp
->AssociatedIrp
.SystemBuffer
;
326 DPRINT ("FsInformationClass %d\n", FsInformationClass
);
327 DPRINT ("SystemBuffer %p\n", SystemBuffer
);
329 switch (FsInformationClass
)
331 case FileFsVolumeInformation
:
332 RC
= FsdGetFsVolumeInformation(IrpContext
->DeviceObject
,
337 case FileFsAttributeInformation
:
338 RC
= FsdGetFsAttributeInformation(IrpContext
->DeviceObject
->DeviceExtension
,
343 case FileFsSizeInformation
:
344 RC
= FsdGetFsSizeInformation(IrpContext
->DeviceObject
,
349 case FileFsDeviceInformation
:
350 RC
= FsdGetFsDeviceInformation(IrpContext
->DeviceObject
,
356 RC
= STATUS_NOT_SUPPORTED
;
359 ExReleaseResourceLite(&((PDEVICE_EXTENSION
)IrpContext
->DeviceObject
->DeviceExtension
)->DirResource
);
360 IrpContext
->Irp
->IoStatus
.Status
= RC
;
362 IrpContext
->Irp
->IoStatus
.Information
=
363 IrpContext
->Stack
->Parameters
.QueryVolume
.Length
- BufferLength
;
365 IrpContext
->Irp
->IoStatus
.Information
= 0;
366 IoCompleteRequest(IrpContext
->Irp
, IO_NO_INCREMENT
);
367 VfatFreeIrpContext(IrpContext
);
373 NTSTATUS
VfatSetVolumeInformation(PVFAT_IRP_CONTEXT IrpContext
)
375 * FUNCTION: Set the specified volume information
378 FS_INFORMATION_CLASS FsInformationClass
;
379 NTSTATUS Status
= STATUS_SUCCESS
;
382 PIO_STACK_LOCATION Stack
= IrpContext
->Stack
;
387 DPRINT ("VfatSetVolumeInformation(IrpContext %p)\n", IrpContext
);
389 if (!ExAcquireResourceExclusiveLite(&((PDEVICE_EXTENSION
)IrpContext
->DeviceObject
->DeviceExtension
)->DirResource
,
390 (BOOLEAN
)(IrpContext
->Flags
& IRPCONTEXT_CANWAIT
)))
392 return VfatQueueRequest (IrpContext
);
395 FsInformationClass
= Stack
->Parameters
.SetVolume
.FsInformationClass
;
396 BufferLength
= Stack
->Parameters
.SetVolume
.Length
;
397 SystemBuffer
= IrpContext
->Irp
->AssociatedIrp
.SystemBuffer
;
399 DPRINT ("FsInformationClass %d\n", FsInformationClass
);
400 DPRINT ("BufferLength %d\n", BufferLength
);
401 DPRINT ("SystemBuffer %p\n", SystemBuffer
);
403 switch(FsInformationClass
)
405 case FileFsLabelInformation
:
406 Status
= FsdSetFsLabelInformation(IrpContext
->DeviceObject
,
411 Status
= STATUS_NOT_SUPPORTED
;
414 ExReleaseResourceLite(&((PDEVICE_EXTENSION
)IrpContext
->DeviceObject
->DeviceExtension
)->DirResource
);
415 IrpContext
->Irp
->IoStatus
.Status
= Status
;
416 IrpContext
->Irp
->IoStatus
.Information
= 0;
417 IoCompleteRequest(IrpContext
->Irp
, IO_NO_INCREMENT
);
418 VfatFreeIrpContext(IrpContext
);