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(PFILE_FS_DEVICE_INFORMATION FsDeviceInfo
,
135 DPRINT("FsdGetFsDeviceInformation()\n");
136 DPRINT("FsDeviceInfo = %p\n", FsDeviceInfo
);
137 DPRINT("BufferLength %lu\n", *BufferLength
);
138 DPRINT("Required length %lu\n", sizeof(FILE_FS_DEVICE_INFORMATION
));
140 if (*BufferLength
< sizeof(FILE_FS_DEVICE_INFORMATION
))
141 return(STATUS_BUFFER_OVERFLOW
);
143 FsDeviceInfo
->DeviceType
= FILE_DEVICE_DISK
;
144 FsDeviceInfo
->Characteristics
= 0; /* FIXME: fix this !! */
146 DPRINT("FsdGetFsDeviceInformation() finished.\n");
148 *BufferLength
-= sizeof(FILE_FS_DEVICE_INFORMATION
);
149 DPRINT("BufferLength %lu\n", *BufferLength
);
151 return(STATUS_SUCCESS
);
156 FsdSetFsLabelInformation(PDEVICE_OBJECT DeviceObject
,
157 PFILE_FS_LABEL_INFORMATION FsLabelInfo
)
159 PDEVICE_EXTENSION DeviceExt
;
160 PVOID Context
= NULL
;
164 LARGE_INTEGER FileOffset
;
165 BOOLEAN LabelFound
= FALSE
;
166 DIR_ENTRY VolumeLabelDirEntry
;
167 ULONG VolumeLabelDirIndex
;
169 NTSTATUS Status
= STATUS_UNSUCCESSFUL
;
171 UNICODE_STRING StringW
;
174 ULONG EntriesPerPage
;
176 DPRINT("FsdSetFsLabelInformation()\n");
178 DeviceExt
= (PDEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
180 if (sizeof(DeviceObject
->Vpb
->VolumeLabel
) < FsLabelInfo
->VolumeLabelLength
)
183 return STATUS_NAME_TOO_LONG
;
186 if (DeviceExt
->Flags
& VCB_IS_FATX
)
188 if (FsLabelInfo
->VolumeLabelLength
/ sizeof(WCHAR
) > 42)
189 return STATUS_NAME_TOO_LONG
;
190 SizeDirEntry
= sizeof(FATX_DIR_ENTRY
);
191 EntriesPerPage
= FATX_ENTRIES_PER_PAGE
;
195 if (FsLabelInfo
->VolumeLabelLength
/ sizeof(WCHAR
) > 11)
196 return STATUS_NAME_TOO_LONG
;
197 SizeDirEntry
= sizeof(FAT_DIR_ENTRY
);
198 EntriesPerPage
= FAT_ENTRIES_PER_PAGE
;
201 /* Create Volume label dir entry */
202 LabelLen
= FsLabelInfo
->VolumeLabelLength
/ sizeof(WCHAR
);
203 RtlZeroMemory(&VolumeLabelDirEntry
, SizeDirEntry
);
204 StringW
.Buffer
= FsLabelInfo
->VolumeLabel
;
205 StringW
.Length
= StringW
.MaximumLength
= (USHORT
)FsLabelInfo
->VolumeLabelLength
;
206 StringO
.Buffer
= cString
;
208 StringO
.MaximumLength
= 42;
209 Status
= RtlUnicodeStringToOemString(&StringO
, &StringW
, FALSE
);
210 if (!NT_SUCCESS(Status
))
212 if (DeviceExt
->Flags
& VCB_IS_FATX
)
214 RtlCopyMemory(VolumeLabelDirEntry
.FatX
.Filename
, cString
, LabelLen
);
215 memset(&VolumeLabelDirEntry
.FatX
.Filename
[LabelLen
], ' ', 42 - LabelLen
);
216 VolumeLabelDirEntry
.FatX
.Attrib
= 0x08;
220 RtlCopyMemory(VolumeLabelDirEntry
.Fat
.Filename
, cString
, LabelLen
);
221 memset(&VolumeLabelDirEntry
.Fat
.Filename
[LabelLen
], ' ', 11 - LabelLen
);
222 VolumeLabelDirEntry
.Fat
.Attrib
= 0x08;
225 pRootFcb
= vfatOpenRootFCB(DeviceExt
);
227 /* Search existing volume entry on disk */
228 FileOffset
.QuadPart
= 0;
229 if (CcPinRead(pRootFcb
->FileObject
, &FileOffset
, PAGE_SIZE
, TRUE
, &Context
, (PVOID
*)&Entry
))
233 if (ENTRY_VOLUME(DeviceExt
, Entry
))
237 RtlCopyMemory(Entry
, &VolumeLabelDirEntry
, SizeDirEntry
);
238 CcSetDirtyPinnedData(Context
, NULL
);
239 Status
= STATUS_SUCCESS
;
242 if (ENTRY_END(DeviceExt
, Entry
))
247 Entry
= (PDIR_ENTRY
)((ULONG_PTR
)Entry
+ SizeDirEntry
);
248 if ((DirIndex
% EntriesPerPage
) == 0)
250 CcUnpinData(Context
);
251 FileOffset
.u
.LowPart
+= PAGE_SIZE
;
252 if (!CcPinRead(pRootFcb
->FileObject
, &FileOffset
, PAGE_SIZE
, TRUE
, &Context
, (PVOID
*)&Entry
))
261 CcUnpinData(Context
);
266 /* Add new entry for label */
267 if (!vfatFindDirSpace(DeviceExt
, pRootFcb
, 1, &VolumeLabelDirIndex
))
268 Status
= STATUS_DISK_FULL
;
271 FileOffset
.u
.HighPart
= 0;
272 FileOffset
.u
.LowPart
= VolumeLabelDirIndex
* SizeDirEntry
;
273 CcPinRead(pRootFcb
->FileObject
, &FileOffset
, SizeDirEntry
,
274 TRUE
, &Context
, (PVOID
*)&Entry
);
275 RtlCopyMemory(Entry
, &VolumeLabelDirEntry
, SizeDirEntry
);
276 CcSetDirtyPinnedData(Context
, NULL
);
277 CcUnpinData(Context
);
278 Status
= STATUS_SUCCESS
;
282 vfatReleaseFCB(DeviceExt
, pRootFcb
);
283 if (!NT_SUCCESS(Status
))
288 /* Update volume label in memory */
289 DeviceObject
->Vpb
->VolumeLabelLength
= (USHORT
)FsLabelInfo
->VolumeLabelLength
;
290 RtlCopyMemory(DeviceObject
->Vpb
->VolumeLabel
, FsLabelInfo
->VolumeLabel
, DeviceObject
->Vpb
->VolumeLabelLength
);
296 NTSTATUS
VfatQueryVolumeInformation(PVFAT_IRP_CONTEXT IrpContext
)
298 * FUNCTION: Retrieve the specified volume information
301 FS_INFORMATION_CLASS FsInformationClass
;
302 NTSTATUS RC
= STATUS_SUCCESS
;
309 DPRINT("VfatQueryVolumeInformation(IrpContext %p)\n", IrpContext
);
311 if (!ExAcquireResourceSharedLite(&((PDEVICE_EXTENSION
)IrpContext
->DeviceObject
->DeviceExtension
)->DirResource
,
312 (BOOLEAN
)(IrpContext
->Flags
& IRPCONTEXT_CANWAIT
)))
314 return VfatQueueRequest (IrpContext
);
318 FsInformationClass
= IrpContext
->Stack
->Parameters
.QueryVolume
.FsInformationClass
;
319 BufferLength
= IrpContext
->Stack
->Parameters
.QueryVolume
.Length
;
320 SystemBuffer
= IrpContext
->Irp
->AssociatedIrp
.SystemBuffer
;
323 DPRINT ("FsInformationClass %d\n", FsInformationClass
);
324 DPRINT ("SystemBuffer %p\n", SystemBuffer
);
326 switch (FsInformationClass
)
328 case FileFsVolumeInformation
:
329 RC
= FsdGetFsVolumeInformation(IrpContext
->DeviceObject
,
334 case FileFsAttributeInformation
:
335 RC
= FsdGetFsAttributeInformation(IrpContext
->DeviceObject
->DeviceExtension
,
340 case FileFsSizeInformation
:
341 RC
= FsdGetFsSizeInformation(IrpContext
->DeviceObject
,
346 case FileFsDeviceInformation
:
347 RC
= FsdGetFsDeviceInformation(SystemBuffer
,
352 RC
= STATUS_NOT_SUPPORTED
;
355 ExReleaseResourceLite(&((PDEVICE_EXTENSION
)IrpContext
->DeviceObject
->DeviceExtension
)->DirResource
);
356 IrpContext
->Irp
->IoStatus
.Status
= RC
;
358 IrpContext
->Irp
->IoStatus
.Information
=
359 IrpContext
->Stack
->Parameters
.QueryVolume
.Length
- BufferLength
;
361 IrpContext
->Irp
->IoStatus
.Information
= 0;
362 IoCompleteRequest(IrpContext
->Irp
, IO_NO_INCREMENT
);
363 VfatFreeIrpContext(IrpContext
);
369 NTSTATUS
VfatSetVolumeInformation(PVFAT_IRP_CONTEXT IrpContext
)
371 * FUNCTION: Set the specified volume information
374 FS_INFORMATION_CLASS FsInformationClass
;
375 NTSTATUS Status
= STATUS_SUCCESS
;
378 PIO_STACK_LOCATION Stack
= IrpContext
->Stack
;
383 DPRINT ("VfatSetVolumeInformation(IrpContext %p)\n", IrpContext
);
385 if (!ExAcquireResourceExclusiveLite(&((PDEVICE_EXTENSION
)IrpContext
->DeviceObject
->DeviceExtension
)->DirResource
,
386 (BOOLEAN
)(IrpContext
->Flags
& IRPCONTEXT_CANWAIT
)))
388 return VfatQueueRequest (IrpContext
);
391 FsInformationClass
= Stack
->Parameters
.SetVolume
.FsInformationClass
;
392 BufferLength
= Stack
->Parameters
.SetVolume
.Length
;
393 SystemBuffer
= IrpContext
->Irp
->AssociatedIrp
.SystemBuffer
;
395 DPRINT ("FsInformationClass %d\n", FsInformationClass
);
396 DPRINT ("BufferLength %d\n", BufferLength
);
397 DPRINT ("SystemBuffer %p\n", SystemBuffer
);
399 switch(FsInformationClass
)
401 case FileFsLabelInformation
:
402 Status
= FsdSetFsLabelInformation(IrpContext
->DeviceObject
,
407 Status
= STATUS_NOT_SUPPORTED
;
410 ExReleaseResourceLite(&((PDEVICE_EXTENSION
)IrpContext
->DeviceObject
->DeviceExtension
)->DirResource
);
411 IrpContext
->Irp
->IoStatus
.Status
= Status
;
412 IrpContext
->Irp
->IoStatus
.Information
= 0;
413 IoCompleteRequest(IrpContext
->Irp
, IO_NO_INCREMENT
);
414 VfatFreeIrpContext(IrpContext
);