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
= _A_VOLID
;
223 RtlCopyMemory(VolumeLabelDirEntry
.Fat
.Filename
, cString
, max(sizeof(VolumeLabelDirEntry
.Fat
.Filename
), LabelLen
));
224 if (LabelLen
> sizeof(VolumeLabelDirEntry
.Fat
.Filename
))
226 memset(VolumeLabelDirEntry
.Fat
.Ext
, ' ', sizeof(VolumeLabelDirEntry
.Fat
.Ext
));
227 RtlCopyMemory(VolumeLabelDirEntry
.Fat
.Ext
, cString
+ sizeof(VolumeLabelDirEntry
.Fat
.Filename
), LabelLen
- sizeof(VolumeLabelDirEntry
.Fat
.Filename
));
231 memset(&VolumeLabelDirEntry
.Fat
.Filename
[LabelLen
], ' ', sizeof(VolumeLabelDirEntry
.Fat
.Filename
) - LabelLen
);
233 VolumeLabelDirEntry
.Fat
.Attrib
= _A_VOLID
;
236 pRootFcb
= vfatOpenRootFCB(DeviceExt
);
238 /* Search existing volume entry on disk */
239 FileOffset
.QuadPart
= 0;
240 if (CcPinRead(pRootFcb
->FileObject
, &FileOffset
, SizeDirEntry
, TRUE
, &Context
, (PVOID
*)&Entry
))
244 if (ENTRY_VOLUME(DeviceExt
, Entry
))
248 RtlCopyMemory(Entry
, &VolumeLabelDirEntry
, SizeDirEntry
);
249 CcSetDirtyPinnedData(Context
, NULL
);
250 Status
= STATUS_SUCCESS
;
253 if (ENTRY_END(DeviceExt
, Entry
))
258 Entry
= (PDIR_ENTRY
)((ULONG_PTR
)Entry
+ SizeDirEntry
);
259 if ((DirIndex
% EntriesPerPage
) == 0)
261 CcUnpinData(Context
);
262 FileOffset
.u
.LowPart
+= PAGE_SIZE
;
263 if (!CcPinRead(pRootFcb
->FileObject
, &FileOffset
, SizeDirEntry
, TRUE
, &Context
, (PVOID
*)&Entry
))
272 CcUnpinData(Context
);
277 /* Add new entry for label */
278 if (!vfatFindDirSpace(DeviceExt
, pRootFcb
, 1, &VolumeLabelDirIndex
))
279 Status
= STATUS_DISK_FULL
;
282 FileOffset
.u
.HighPart
= 0;
283 FileOffset
.u
.LowPart
= VolumeLabelDirIndex
* SizeDirEntry
;
284 CcPinRead(pRootFcb
->FileObject
, &FileOffset
, SizeDirEntry
,
285 TRUE
, &Context
, (PVOID
*)&Entry
);
286 RtlCopyMemory(Entry
, &VolumeLabelDirEntry
, SizeDirEntry
);
287 CcSetDirtyPinnedData(Context
, NULL
);
288 CcUnpinData(Context
);
289 Status
= STATUS_SUCCESS
;
293 vfatReleaseFCB(DeviceExt
, pRootFcb
);
294 if (!NT_SUCCESS(Status
))
299 /* Update volume label in memory */
300 DeviceObject
->Vpb
->VolumeLabelLength
= (USHORT
)FsLabelInfo
->VolumeLabelLength
;
301 RtlCopyMemory(DeviceObject
->Vpb
->VolumeLabel
, FsLabelInfo
->VolumeLabel
, DeviceObject
->Vpb
->VolumeLabelLength
);
307 NTSTATUS
VfatQueryVolumeInformation(PVFAT_IRP_CONTEXT IrpContext
)
309 * FUNCTION: Retrieve the specified volume information
312 FS_INFORMATION_CLASS FsInformationClass
;
313 NTSTATUS RC
= STATUS_SUCCESS
;
320 DPRINT("VfatQueryVolumeInformation(IrpContext %p)\n", IrpContext
);
322 if (!ExAcquireResourceSharedLite(&((PDEVICE_EXTENSION
)IrpContext
->DeviceObject
->DeviceExtension
)->DirResource
,
323 (BOOLEAN
)(IrpContext
->Flags
& IRPCONTEXT_CANWAIT
)))
325 return VfatQueueRequest (IrpContext
);
329 FsInformationClass
= IrpContext
->Stack
->Parameters
.QueryVolume
.FsInformationClass
;
330 BufferLength
= IrpContext
->Stack
->Parameters
.QueryVolume
.Length
;
331 SystemBuffer
= IrpContext
->Irp
->AssociatedIrp
.SystemBuffer
;
334 DPRINT ("FsInformationClass %d\n", FsInformationClass
);
335 DPRINT ("SystemBuffer %p\n", SystemBuffer
);
337 switch (FsInformationClass
)
339 case FileFsVolumeInformation
:
340 RC
= FsdGetFsVolumeInformation(IrpContext
->DeviceObject
,
345 case FileFsAttributeInformation
:
346 RC
= FsdGetFsAttributeInformation(IrpContext
->DeviceObject
->DeviceExtension
,
351 case FileFsSizeInformation
:
352 RC
= FsdGetFsSizeInformation(IrpContext
->DeviceObject
,
357 case FileFsDeviceInformation
:
358 RC
= FsdGetFsDeviceInformation(IrpContext
->DeviceObject
,
364 RC
= STATUS_NOT_SUPPORTED
;
367 ExReleaseResourceLite(&((PDEVICE_EXTENSION
)IrpContext
->DeviceObject
->DeviceExtension
)->DirResource
);
368 IrpContext
->Irp
->IoStatus
.Status
= RC
;
370 IrpContext
->Irp
->IoStatus
.Information
=
371 IrpContext
->Stack
->Parameters
.QueryVolume
.Length
- BufferLength
;
373 IrpContext
->Irp
->IoStatus
.Information
= 0;
374 IoCompleteRequest(IrpContext
->Irp
, IO_NO_INCREMENT
);
375 VfatFreeIrpContext(IrpContext
);
381 NTSTATUS
VfatSetVolumeInformation(PVFAT_IRP_CONTEXT IrpContext
)
383 * FUNCTION: Set the specified volume information
386 FS_INFORMATION_CLASS FsInformationClass
;
387 NTSTATUS Status
= STATUS_SUCCESS
;
390 PIO_STACK_LOCATION Stack
= IrpContext
->Stack
;
395 DPRINT ("VfatSetVolumeInformation(IrpContext %p)\n", IrpContext
);
397 if (!ExAcquireResourceExclusiveLite(&((PDEVICE_EXTENSION
)IrpContext
->DeviceObject
->DeviceExtension
)->DirResource
,
398 (BOOLEAN
)(IrpContext
->Flags
& IRPCONTEXT_CANWAIT
)))
400 return VfatQueueRequest (IrpContext
);
403 FsInformationClass
= Stack
->Parameters
.SetVolume
.FsInformationClass
;
404 BufferLength
= Stack
->Parameters
.SetVolume
.Length
;
405 SystemBuffer
= IrpContext
->Irp
->AssociatedIrp
.SystemBuffer
;
407 DPRINT ("FsInformationClass %d\n", FsInformationClass
);
408 DPRINT ("BufferLength %d\n", BufferLength
);
409 DPRINT ("SystemBuffer %p\n", SystemBuffer
);
411 switch(FsInformationClass
)
413 case FileFsLabelInformation
:
414 Status
= FsdSetFsLabelInformation(IrpContext
->DeviceObject
,
419 Status
= STATUS_NOT_SUPPORTED
;
422 ExReleaseResourceLite(&((PDEVICE_EXTENSION
)IrpContext
->DeviceObject
->DeviceExtension
)->DirResource
);
423 IrpContext
->Irp
->IoStatus
.Status
= Status
;
424 IrpContext
->Irp
->IoStatus
.Information
= 0;
425 IoCompleteRequest(IrpContext
->Irp
, IO_NO_INCREMENT
);
426 VfatFreeIrpContext(IrpContext
);