3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: drivers/fs/vfat/volume.c
6 * PURPOSE: VFAT Filesystem
7 * PROGRAMMER: Jason Filby (jasonfilby@yahoo.com)
9 * Herve Poussineau (reactos@poussine.freesurf.fr)
12 /* INCLUDES *****************************************************************/
14 #include <ddk/ntddk.h>
22 /* FUNCTIONS ****************************************************************/
25 FsdGetFsVolumeInformation(PDEVICE_OBJECT DeviceObject
,
26 PFILE_FS_VOLUME_INFORMATION FsVolumeInfo
,
29 DPRINT("FsdGetFsVolumeInformation()\n");
30 DPRINT("FsVolumeInfo = %p\n", FsVolumeInfo
);
31 DPRINT("BufferLength %lu\n", *BufferLength
);
33 DPRINT("Required length %lu\n", (sizeof(FILE_FS_VOLUME_INFORMATION
) + 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 if (*BufferLength
< sizeof(FILE_FS_VOLUME_INFORMATION
))
38 return STATUS_INFO_LENGTH_MISMATCH
;
40 if (*BufferLength
< (sizeof(FILE_FS_VOLUME_INFORMATION
) + DeviceObject
->Vpb
->VolumeLabelLength
))
41 return STATUS_BUFFER_OVERFLOW
;
44 FsVolumeInfo
->VolumeSerialNumber
= DeviceObject
->Vpb
->SerialNumber
;
45 FsVolumeInfo
->VolumeLabelLength
= DeviceObject
->Vpb
->VolumeLabelLength
;
46 RtlCopyMemory(FsVolumeInfo
->VolumeLabel
, DeviceObject
->Vpb
->VolumeLabel
, FsVolumeInfo
->VolumeLabelLength
);
49 FsVolumeInfo
->VolumeCreationTime
.QuadPart
= 0;
50 FsVolumeInfo
->SupportsObjects
= FALSE
;
52 DPRINT("Finished FsdGetFsVolumeInformation()\n");
54 *BufferLength
-= (sizeof(FILE_FS_VOLUME_INFORMATION
) + DeviceObject
->Vpb
->VolumeLabelLength
);
56 DPRINT("BufferLength %lu\n", *BufferLength
);
58 return(STATUS_SUCCESS
);
63 FsdGetFsAttributeInformation(PDEVICE_EXTENSION DeviceExt
,
64 PFILE_FS_ATTRIBUTE_INFORMATION FsAttributeInfo
,
67 WCHAR
* pName
; ULONG Length
;
68 DPRINT("FsdGetFsAttributeInformation()\n");
69 DPRINT("FsAttributeInfo = %p\n", FsAttributeInfo
);
70 DPRINT("BufferLength %lu\n", *BufferLength
);
72 if (*BufferLength
< sizeof (FILE_FS_ATTRIBUTE_INFORMATION
))
73 return STATUS_INFO_LENGTH_MISMATCH
;
75 if (DeviceExt
->FatInfo
.FatType
== FAT32
)
86 DPRINT("Required length %lu\n", (sizeof(FILE_FS_ATTRIBUTE_INFORMATION
) + Length
));
88 if (*BufferLength
< (sizeof(FILE_FS_ATTRIBUTE_INFORMATION
) + Length
))
89 return STATUS_BUFFER_OVERFLOW
;
91 FsAttributeInfo
->FileSystemAttributes
=
92 FILE_CASE_PRESERVED_NAMES
| FILE_UNICODE_ON_DISK
;
94 FsAttributeInfo
->MaximumComponentNameLength
= 255;
96 FsAttributeInfo
->FileSystemNameLength
= Length
;
98 RtlCopyMemory(FsAttributeInfo
->FileSystemName
, pName
, Length
);
100 DPRINT("Finished FsdGetFsAttributeInformation()\n");
102 *BufferLength
-= (sizeof(FILE_FS_ATTRIBUTE_INFORMATION
) + Length
);
103 DPRINT("BufferLength %lu\n", *BufferLength
);
105 return(STATUS_SUCCESS
);
110 FsdGetFsSizeInformation(PDEVICE_OBJECT DeviceObject
,
111 PFILE_FS_SIZE_INFORMATION FsSizeInfo
,
114 PDEVICE_EXTENSION DeviceExt
;
117 DPRINT("FsdGetFsSizeInformation()\n");
118 DPRINT("FsSizeInfo = %p\n", FsSizeInfo
);
120 if (*BufferLength
< sizeof(FILE_FS_SIZE_INFORMATION
))
121 return(STATUS_BUFFER_OVERFLOW
);
123 DeviceExt
= DeviceObject
->DeviceExtension
;
124 Status
= CountAvailableClusters(DeviceExt
, &FsSizeInfo
->AvailableAllocationUnits
);
126 FsSizeInfo
->TotalAllocationUnits
.QuadPart
= DeviceExt
->FatInfo
.NumberOfClusters
;
127 FsSizeInfo
->SectorsPerAllocationUnit
= DeviceExt
->FatInfo
.SectorsPerCluster
;
128 FsSizeInfo
->BytesPerSector
= DeviceExt
->FatInfo
.BytesPerSector
;
130 DPRINT("Finished FsdGetFsSizeInformation()\n");
131 if (NT_SUCCESS(Status
))
132 *BufferLength
-= sizeof(FILE_FS_SIZE_INFORMATION
);
139 FsdGetFsDeviceInformation(PFILE_FS_DEVICE_INFORMATION FsDeviceInfo
,
142 DPRINT("FsdGetFsDeviceInformation()\n");
143 DPRINT("FsDeviceInfo = %p\n", FsDeviceInfo
);
144 DPRINT("BufferLength %lu\n", *BufferLength
);
145 DPRINT("Required length %lu\n", sizeof(FILE_FS_DEVICE_INFORMATION
));
147 if (*BufferLength
< sizeof(FILE_FS_DEVICE_INFORMATION
))
148 return(STATUS_BUFFER_OVERFLOW
);
150 FsDeviceInfo
->DeviceType
= FILE_DEVICE_DISK
;
151 FsDeviceInfo
->Characteristics
= 0; /* FIXME: fix this !! */
153 DPRINT("FsdGetFsDeviceInformation() finished.\n");
155 *BufferLength
-= sizeof(FILE_FS_DEVICE_INFORMATION
);
156 DPRINT("BufferLength %lu\n", *BufferLength
);
158 return(STATUS_SUCCESS
);
163 FsdSetFsLabelInformation(PDEVICE_OBJECT DeviceObject
,
164 PFILE_FS_LABEL_INFORMATION FsLabelInfo
)
166 PDEVICE_EXTENSION DeviceExt
;
167 PVOID Context
= NULL
;
171 LARGE_INTEGER FileOffset
;
172 BOOL LabelFound
= FALSE
;
173 DIR_ENTRY VolumeLabelDirEntry
;
174 ULONG VolumeLabelDirIndex
;
176 NTSTATUS Status
= STATUS_UNSUCCESSFUL
;
178 UNICODE_STRING StringW
;
181 ULONG EntriesPerPage
;
183 DPRINT("FsdSetFsLabelInformation()\n");
185 DeviceExt
= (PDEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
187 if (sizeof(DeviceObject
->Vpb
->VolumeLabel
) < FsLabelInfo
->VolumeLabelLength
)
190 return STATUS_NAME_TOO_LONG
;
193 if (DeviceExt
->Flags
& VCB_IS_FATX
)
195 if (FsLabelInfo
->VolumeLabelLength
/ sizeof(WCHAR
) > 42)
196 return STATUS_NAME_TOO_LONG
;
197 SizeDirEntry
= sizeof(FATX_DIR_ENTRY
);
198 EntriesPerPage
= FATX_ENTRIES_PER_PAGE
;
202 if (FsLabelInfo
->VolumeLabelLength
/ sizeof(WCHAR
) > 11)
203 return STATUS_NAME_TOO_LONG
;
204 SizeDirEntry
= sizeof(FAT_DIR_ENTRY
);
205 EntriesPerPage
= FAT_ENTRIES_PER_PAGE
;
208 /* Create Volume label dir entry */
209 LabelLen
= FsLabelInfo
->VolumeLabelLength
/ sizeof(WCHAR
);
210 RtlZeroMemory(&VolumeLabelDirEntry
, SizeDirEntry
);
211 StringW
.Buffer
= FsLabelInfo
->VolumeLabel
;
212 StringW
.Length
= StringW
.MaximumLength
= FsLabelInfo
->VolumeLabelLength
;
213 StringO
.Buffer
= cString
;
215 StringO
.MaximumLength
= 42;
216 Status
= RtlUnicodeStringToOemString(&StringO
, &StringW
, FALSE
);
217 if (!NT_SUCCESS(Status
))
219 if (DeviceExt
->Flags
& VCB_IS_FATX
)
221 RtlCopyMemory(VolumeLabelDirEntry
.FatX
.Filename
, cString
, LabelLen
);
222 memset(&VolumeLabelDirEntry
.FatX
.Filename
[LabelLen
], ' ', 42 - LabelLen
);
223 VolumeLabelDirEntry
.FatX
.Attrib
= 0x08;
227 RtlCopyMemory(VolumeLabelDirEntry
.Fat
.Filename
, cString
, LabelLen
);
228 memset(&VolumeLabelDirEntry
.Fat
.Filename
[LabelLen
], ' ', 11 - LabelLen
);
229 VolumeLabelDirEntry
.Fat
.Attrib
= 0x08;
232 pRootFcb
= vfatOpenRootFCB(DeviceExt
);
234 /* Search existing volume entry on disk */
235 FileOffset
.QuadPart
= 0;
236 if (CcMapData(pRootFcb
->FileObject
, &FileOffset
, PAGE_SIZE
, TRUE
, &Context
, (PVOID
*)&Entry
))
240 if (ENTRY_VOLUME(DeviceExt
, Entry
))
244 RtlCopyMemory(Entry
, &VolumeLabelDirEntry
, SizeDirEntry
);
245 CcSetDirtyPinnedData(Context
, NULL
);
246 Status
= STATUS_SUCCESS
;
249 if (ENTRY_END(DeviceExt
, Entry
))
254 Entry
= (PDIR_ENTRY
)((ULONG_PTR
)Entry
+ SizeDirEntry
);
255 if ((DirIndex
% EntriesPerPage
) == 0)
257 CcUnpinData(Context
);
258 FileOffset
.u
.LowPart
+= PAGE_SIZE
;
259 if (!CcMapData(pRootFcb
->FileObject
, &FileOffset
, PAGE_SIZE
, TRUE
, &Context
, (PVOID
*)&Entry
))
268 CcUnpinData(Context
);
273 /* Add new entry for label */
274 if (!vfatFindDirSpace(DeviceExt
, pRootFcb
, 1, &VolumeLabelDirIndex
))
275 Status
= STATUS_DISK_FULL
;
278 FileOffset
.u
.HighPart
= 0;
279 FileOffset
.u
.LowPart
= VolumeLabelDirIndex
* SizeDirEntry
;
280 CcMapData(pRootFcb
->FileObject
, &FileOffset
, SizeDirEntry
,
281 TRUE
, &Context
, (PVOID
*)&Entry
);
282 RtlCopyMemory(Entry
, &VolumeLabelDirEntry
, SizeDirEntry
);
283 CcSetDirtyPinnedData(Context
, NULL
);
284 CcUnpinData(Context
);
285 Status
= STATUS_SUCCESS
;
289 vfatReleaseFCB(DeviceExt
, pRootFcb
);
290 if (!NT_SUCCESS(Status
))
295 /* Update volume label in memory */
296 DeviceObject
->Vpb
->VolumeLabelLength
= FsLabelInfo
->VolumeLabelLength
;
297 RtlCopyMemory(DeviceObject
->Vpb
->VolumeLabel
, FsLabelInfo
->VolumeLabel
, DeviceObject
->Vpb
->VolumeLabelLength
);
303 NTSTATUS
VfatQueryVolumeInformation(PVFAT_IRP_CONTEXT IrpContext
)
305 * FUNCTION: Retrieve the specified volume information
308 FS_INFORMATION_CLASS FsInformationClass
;
309 NTSTATUS RC
= STATUS_SUCCESS
;
316 DPRINT("VfatQueryVolumeInformation(IrpContext %x)\n", IrpContext
);
318 if (!ExAcquireResourceSharedLite(&((PDEVICE_EXTENSION
)IrpContext
->DeviceObject
->DeviceExtension
)->DirResource
,
319 (BOOLEAN
)(IrpContext
->Flags
& IRPCONTEXT_CANWAIT
)))
321 return VfatQueueRequest (IrpContext
);
325 FsInformationClass
= IrpContext
->Stack
->Parameters
.QueryVolume
.FsInformationClass
;
326 BufferLength
= IrpContext
->Stack
->Parameters
.QueryVolume
.Length
;
327 SystemBuffer
= IrpContext
->Irp
->AssociatedIrp
.SystemBuffer
;
330 DPRINT ("FsInformationClass %d\n", FsInformationClass
);
331 DPRINT ("SystemBuffer %x\n", SystemBuffer
);
333 switch (FsInformationClass
)
335 case FileFsVolumeInformation
:
336 RC
= FsdGetFsVolumeInformation(IrpContext
->DeviceObject
,
341 case FileFsAttributeInformation
:
342 RC
= FsdGetFsAttributeInformation(IrpContext
->DeviceObject
->DeviceExtension
,
347 case FileFsSizeInformation
:
348 RC
= FsdGetFsSizeInformation(IrpContext
->DeviceObject
,
353 case FileFsDeviceInformation
:
354 RC
= FsdGetFsDeviceInformation(SystemBuffer
,
359 RC
= STATUS_NOT_SUPPORTED
;
362 ExReleaseResourceLite(&((PDEVICE_EXTENSION
)IrpContext
->DeviceObject
->DeviceExtension
)->DirResource
);
363 IrpContext
->Irp
->IoStatus
.Status
= RC
;
365 IrpContext
->Irp
->IoStatus
.Information
=
366 IrpContext
->Stack
->Parameters
.QueryVolume
.Length
- BufferLength
;
368 IrpContext
->Irp
->IoStatus
.Information
= 0;
369 IoCompleteRequest(IrpContext
->Irp
, IO_NO_INCREMENT
);
370 VfatFreeIrpContext(IrpContext
);
376 NTSTATUS
VfatSetVolumeInformation(PVFAT_IRP_CONTEXT IrpContext
)
378 * FUNCTION: Set the specified volume information
381 FS_INFORMATION_CLASS FsInformationClass
;
382 NTSTATUS Status
= STATUS_SUCCESS
;
385 PIO_STACK_LOCATION Stack
= IrpContext
->Stack
;
390 DPRINT ("VfatSetVolumeInformation(IrpContext %x)\n", IrpContext
);
392 if (!ExAcquireResourceExclusiveLite(&((PDEVICE_EXTENSION
)IrpContext
->DeviceObject
->DeviceExtension
)->DirResource
,
393 (BOOLEAN
)(IrpContext
->Flags
& IRPCONTEXT_CANWAIT
)))
395 return VfatQueueRequest (IrpContext
);
398 FsInformationClass
= Stack
->Parameters
.SetVolume
.FsInformationClass
;
399 BufferLength
= Stack
->Parameters
.SetVolume
.Length
;
400 SystemBuffer
= IrpContext
->Irp
->AssociatedIrp
.SystemBuffer
;
402 DPRINT ("FsInformationClass %d\n", FsInformationClass
);
403 DPRINT ("BufferLength %d\n", BufferLength
);
404 DPRINT ("SystemBuffer %x\n", SystemBuffer
);
406 switch(FsInformationClass
)
408 case FileFsLabelInformation
:
409 Status
= FsdSetFsLabelInformation(IrpContext
->DeviceObject
,
414 Status
= STATUS_NOT_SUPPORTED
;
417 ExReleaseResourceLite(&((PDEVICE_EXTENSION
)IrpContext
->DeviceObject
->DeviceExtension
)->DirResource
);
418 IrpContext
->Irp
->IoStatus
.Status
= Status
;
419 IrpContext
->Irp
->IoStatus
.Information
= 0;
420 IoCompleteRequest(IrpContext
->Irp
, IO_NO_INCREMENT
);
421 VfatFreeIrpContext(IrpContext
);