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)
8 * Herve Poussineau (reactos@poussine.freesurf.fr)
11 /* INCLUDES *****************************************************************/
16 /* FUNCTIONS ****************************************************************/
19 FsdGetFsVolumeInformation(PDEVICE_OBJECT DeviceObject
,
20 PFILE_FS_VOLUME_INFORMATION FsVolumeInfo
,
23 DPRINT("FsdGetFsVolumeInformation()\n");
24 DPRINT("FsVolumeInfo = %p\n", FsVolumeInfo
);
25 DPRINT("BufferLength %lu\n", *BufferLength
);
27 DPRINT("Required length %lu\n", (sizeof(FILE_FS_VOLUME_INFORMATION
) + DeviceObject
->Vpb
->VolumeLabelLength
));
28 DPRINT("LabelLength %hu\n", DeviceObject
->Vpb
->VolumeLabelLength
);
29 DPRINT("Label %*.S\n", DeviceObject
->Vpb
->VolumeLabelLength
/ sizeof(WCHAR
), DeviceObject
->Vpb
->VolumeLabel
);
31 if (*BufferLength
< sizeof(FILE_FS_VOLUME_INFORMATION
))
32 return STATUS_INFO_LENGTH_MISMATCH
;
34 if (*BufferLength
< (sizeof(FILE_FS_VOLUME_INFORMATION
) + DeviceObject
->Vpb
->VolumeLabelLength
))
35 return STATUS_BUFFER_OVERFLOW
;
38 FsVolumeInfo
->VolumeSerialNumber
= DeviceObject
->Vpb
->SerialNumber
;
39 FsVolumeInfo
->VolumeLabelLength
= DeviceObject
->Vpb
->VolumeLabelLength
;
40 RtlCopyMemory(FsVolumeInfo
->VolumeLabel
, DeviceObject
->Vpb
->VolumeLabel
, FsVolumeInfo
->VolumeLabelLength
);
43 FsVolumeInfo
->VolumeCreationTime
.QuadPart
= 0;
44 FsVolumeInfo
->SupportsObjects
= FALSE
;
46 DPRINT("Finished FsdGetFsVolumeInformation()\n");
48 *BufferLength
-= (sizeof(FILE_FS_VOLUME_INFORMATION
) + DeviceObject
->Vpb
->VolumeLabelLength
);
50 DPRINT("BufferLength %lu\n", *BufferLength
);
52 return(STATUS_SUCCESS
);
57 FsdGetFsAttributeInformation(PDEVICE_EXTENSION DeviceExt
,
58 PFILE_FS_ATTRIBUTE_INFORMATION FsAttributeInfo
,
61 WCHAR
* pName
; ULONG Length
;
62 DPRINT("FsdGetFsAttributeInformation()\n");
63 DPRINT("FsAttributeInfo = %p\n", FsAttributeInfo
);
64 DPRINT("BufferLength %lu\n", *BufferLength
);
66 if (*BufferLength
< sizeof (FILE_FS_ATTRIBUTE_INFORMATION
))
67 return STATUS_INFO_LENGTH_MISMATCH
;
69 if (DeviceExt
->FatInfo
.FatType
== FAT32
)
80 DPRINT("Required length %lu\n", (sizeof(FILE_FS_ATTRIBUTE_INFORMATION
) + Length
));
82 if (*BufferLength
< (sizeof(FILE_FS_ATTRIBUTE_INFORMATION
) + Length
))
83 return STATUS_BUFFER_OVERFLOW
;
85 FsAttributeInfo
->FileSystemAttributes
=
86 FILE_CASE_PRESERVED_NAMES
| FILE_UNICODE_ON_DISK
;
88 FsAttributeInfo
->MaximumComponentNameLength
= 255;
90 FsAttributeInfo
->FileSystemNameLength
= Length
;
92 RtlCopyMemory(FsAttributeInfo
->FileSystemName
, pName
, Length
);
94 DPRINT("Finished FsdGetFsAttributeInformation()\n");
96 *BufferLength
-= (sizeof(FILE_FS_ATTRIBUTE_INFORMATION
) + Length
);
97 DPRINT("BufferLength %lu\n", *BufferLength
);
99 return(STATUS_SUCCESS
);
104 FsdGetFsSizeInformation(PDEVICE_OBJECT DeviceObject
,
105 PFILE_FS_SIZE_INFORMATION FsSizeInfo
,
108 PDEVICE_EXTENSION DeviceExt
;
111 DPRINT("FsdGetFsSizeInformation()\n");
112 DPRINT("FsSizeInfo = %p\n", FsSizeInfo
);
114 if (*BufferLength
< sizeof(FILE_FS_SIZE_INFORMATION
))
115 return(STATUS_BUFFER_OVERFLOW
);
117 DeviceExt
= DeviceObject
->DeviceExtension
;
118 Status
= CountAvailableClusters(DeviceExt
, &FsSizeInfo
->AvailableAllocationUnits
);
120 FsSizeInfo
->TotalAllocationUnits
.QuadPart
= DeviceExt
->FatInfo
.NumberOfClusters
;
121 FsSizeInfo
->SectorsPerAllocationUnit
= DeviceExt
->FatInfo
.SectorsPerCluster
;
122 FsSizeInfo
->BytesPerSector
= DeviceExt
->FatInfo
.BytesPerSector
;
124 DPRINT("Finished FsdGetFsSizeInformation()\n");
125 if (NT_SUCCESS(Status
))
126 *BufferLength
-= sizeof(FILE_FS_SIZE_INFORMATION
);
133 FsdGetFsDeviceInformation(PFILE_FS_DEVICE_INFORMATION FsDeviceInfo
,
136 DPRINT("FsdGetFsDeviceInformation()\n");
137 DPRINT("FsDeviceInfo = %p\n", FsDeviceInfo
);
138 DPRINT("BufferLength %lu\n", *BufferLength
);
139 DPRINT("Required length %lu\n", sizeof(FILE_FS_DEVICE_INFORMATION
));
141 if (*BufferLength
< sizeof(FILE_FS_DEVICE_INFORMATION
))
142 return(STATUS_BUFFER_OVERFLOW
);
144 FsDeviceInfo
->DeviceType
= FILE_DEVICE_DISK
;
145 FsDeviceInfo
->Characteristics
= 0; /* FIXME: fix this !! */
147 DPRINT("FsdGetFsDeviceInformation() finished.\n");
149 *BufferLength
-= sizeof(FILE_FS_DEVICE_INFORMATION
);
150 DPRINT("BufferLength %lu\n", *BufferLength
);
152 return(STATUS_SUCCESS
);
157 FsdSetFsLabelInformation(PDEVICE_OBJECT DeviceObject
,
158 PFILE_FS_LABEL_INFORMATION FsLabelInfo
)
160 PDEVICE_EXTENSION DeviceExt
;
161 PVOID Context
= NULL
;
165 LARGE_INTEGER FileOffset
;
166 BOOLEAN LabelFound
= FALSE
;
167 DIR_ENTRY VolumeLabelDirEntry
;
168 ULONG VolumeLabelDirIndex
;
170 NTSTATUS Status
= STATUS_UNSUCCESSFUL
;
172 UNICODE_STRING StringW
;
175 ULONG EntriesPerPage
;
177 DPRINT("FsdSetFsLabelInformation()\n");
179 DeviceExt
= (PDEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
181 if (sizeof(DeviceObject
->Vpb
->VolumeLabel
) < FsLabelInfo
->VolumeLabelLength
)
184 return STATUS_NAME_TOO_LONG
;
187 if (DeviceExt
->Flags
& VCB_IS_FATX
)
189 if (FsLabelInfo
->VolumeLabelLength
/ sizeof(WCHAR
) > 42)
190 return STATUS_NAME_TOO_LONG
;
191 SizeDirEntry
= sizeof(FATX_DIR_ENTRY
);
192 EntriesPerPage
= FATX_ENTRIES_PER_PAGE
;
196 if (FsLabelInfo
->VolumeLabelLength
/ sizeof(WCHAR
) > 11)
197 return STATUS_NAME_TOO_LONG
;
198 SizeDirEntry
= sizeof(FAT_DIR_ENTRY
);
199 EntriesPerPage
= FAT_ENTRIES_PER_PAGE
;
202 /* Create Volume label dir entry */
203 LabelLen
= FsLabelInfo
->VolumeLabelLength
/ sizeof(WCHAR
);
204 RtlZeroMemory(&VolumeLabelDirEntry
, SizeDirEntry
);
205 StringW
.Buffer
= FsLabelInfo
->VolumeLabel
;
206 StringW
.Length
= StringW
.MaximumLength
= (USHORT
)FsLabelInfo
->VolumeLabelLength
;
207 StringO
.Buffer
= cString
;
209 StringO
.MaximumLength
= 42;
210 Status
= RtlUnicodeStringToOemString(&StringO
, &StringW
, FALSE
);
211 if (!NT_SUCCESS(Status
))
213 if (DeviceExt
->Flags
& VCB_IS_FATX
)
215 RtlCopyMemory(VolumeLabelDirEntry
.FatX
.Filename
, cString
, LabelLen
);
216 memset(&VolumeLabelDirEntry
.FatX
.Filename
[LabelLen
], ' ', 42 - LabelLen
);
217 VolumeLabelDirEntry
.FatX
.Attrib
= 0x08;
221 RtlCopyMemory(VolumeLabelDirEntry
.Fat
.Filename
, cString
, LabelLen
);
222 memset(&VolumeLabelDirEntry
.Fat
.Filename
[LabelLen
], ' ', 11 - LabelLen
);
223 VolumeLabelDirEntry
.Fat
.Attrib
= 0x08;
226 pRootFcb
= vfatOpenRootFCB(DeviceExt
);
228 /* Search existing volume entry on disk */
229 FileOffset
.QuadPart
= 0;
230 if (CcPinRead(pRootFcb
->FileObject
, &FileOffset
, PAGE_SIZE
, TRUE
, &Context
, (PVOID
*)&Entry
))
234 if (ENTRY_VOLUME(DeviceExt
, Entry
))
238 RtlCopyMemory(Entry
, &VolumeLabelDirEntry
, SizeDirEntry
);
239 CcSetDirtyPinnedData(Context
, NULL
);
240 Status
= STATUS_SUCCESS
;
243 if (ENTRY_END(DeviceExt
, Entry
))
248 Entry
= (PDIR_ENTRY
)((ULONG_PTR
)Entry
+ SizeDirEntry
);
249 if ((DirIndex
% EntriesPerPage
) == 0)
251 CcUnpinData(Context
);
252 FileOffset
.u
.LowPart
+= PAGE_SIZE
;
253 if (!CcPinRead(pRootFcb
->FileObject
, &FileOffset
, PAGE_SIZE
, TRUE
, &Context
, (PVOID
*)&Entry
))
262 CcUnpinData(Context
);
267 /* Add new entry for label */
268 if (!vfatFindDirSpace(DeviceExt
, pRootFcb
, 1, &VolumeLabelDirIndex
))
269 Status
= STATUS_DISK_FULL
;
272 FileOffset
.u
.HighPart
= 0;
273 FileOffset
.u
.LowPart
= VolumeLabelDirIndex
* SizeDirEntry
;
274 CcPinRead(pRootFcb
->FileObject
, &FileOffset
, SizeDirEntry
,
275 TRUE
, &Context
, (PVOID
*)&Entry
);
276 RtlCopyMemory(Entry
, &VolumeLabelDirEntry
, SizeDirEntry
);
277 CcSetDirtyPinnedData(Context
, NULL
);
278 CcUnpinData(Context
);
279 Status
= STATUS_SUCCESS
;
283 vfatReleaseFCB(DeviceExt
, pRootFcb
);
284 if (!NT_SUCCESS(Status
))
289 /* Update volume label in memory */
290 DeviceObject
->Vpb
->VolumeLabelLength
= (USHORT
)FsLabelInfo
->VolumeLabelLength
;
291 RtlCopyMemory(DeviceObject
->Vpb
->VolumeLabel
, FsLabelInfo
->VolumeLabel
, DeviceObject
->Vpb
->VolumeLabelLength
);
297 NTSTATUS
VfatQueryVolumeInformation(PVFAT_IRP_CONTEXT IrpContext
)
299 * FUNCTION: Retrieve the specified volume information
302 FS_INFORMATION_CLASS FsInformationClass
;
303 NTSTATUS RC
= STATUS_SUCCESS
;
310 DPRINT("VfatQueryVolumeInformation(IrpContext %x)\n", IrpContext
);
312 if (!ExAcquireResourceSharedLite(&((PDEVICE_EXTENSION
)IrpContext
->DeviceObject
->DeviceExtension
)->DirResource
,
313 (BOOLEAN
)(IrpContext
->Flags
& IRPCONTEXT_CANWAIT
)))
315 return VfatQueueRequest (IrpContext
);
319 FsInformationClass
= IrpContext
->Stack
->Parameters
.QueryVolume
.FsInformationClass
;
320 BufferLength
= IrpContext
->Stack
->Parameters
.QueryVolume
.Length
;
321 SystemBuffer
= IrpContext
->Irp
->AssociatedIrp
.SystemBuffer
;
324 DPRINT ("FsInformationClass %d\n", FsInformationClass
);
325 DPRINT ("SystemBuffer %x\n", SystemBuffer
);
327 switch (FsInformationClass
)
329 case FileFsVolumeInformation
:
330 RC
= FsdGetFsVolumeInformation(IrpContext
->DeviceObject
,
335 case FileFsAttributeInformation
:
336 RC
= FsdGetFsAttributeInformation(IrpContext
->DeviceObject
->DeviceExtension
,
341 case FileFsSizeInformation
:
342 RC
= FsdGetFsSizeInformation(IrpContext
->DeviceObject
,
347 case FileFsDeviceInformation
:
348 RC
= FsdGetFsDeviceInformation(SystemBuffer
,
353 RC
= STATUS_NOT_SUPPORTED
;
356 ExReleaseResourceLite(&((PDEVICE_EXTENSION
)IrpContext
->DeviceObject
->DeviceExtension
)->DirResource
);
357 IrpContext
->Irp
->IoStatus
.Status
= RC
;
359 IrpContext
->Irp
->IoStatus
.Information
=
360 IrpContext
->Stack
->Parameters
.QueryVolume
.Length
- BufferLength
;
362 IrpContext
->Irp
->IoStatus
.Information
= 0;
363 IoCompleteRequest(IrpContext
->Irp
, IO_NO_INCREMENT
);
364 VfatFreeIrpContext(IrpContext
);
370 NTSTATUS
VfatSetVolumeInformation(PVFAT_IRP_CONTEXT IrpContext
)
372 * FUNCTION: Set the specified volume information
375 FS_INFORMATION_CLASS FsInformationClass
;
376 NTSTATUS Status
= STATUS_SUCCESS
;
379 PIO_STACK_LOCATION Stack
= IrpContext
->Stack
;
384 DPRINT ("VfatSetVolumeInformation(IrpContext %x)\n", IrpContext
);
386 if (!ExAcquireResourceExclusiveLite(&((PDEVICE_EXTENSION
)IrpContext
->DeviceObject
->DeviceExtension
)->DirResource
,
387 (BOOLEAN
)(IrpContext
->Flags
& IRPCONTEXT_CANWAIT
)))
389 return VfatQueueRequest (IrpContext
);
392 FsInformationClass
= Stack
->Parameters
.SetVolume
.FsInformationClass
;
393 BufferLength
= Stack
->Parameters
.SetVolume
.Length
;
394 SystemBuffer
= IrpContext
->Irp
->AssociatedIrp
.SystemBuffer
;
396 DPRINT ("FsInformationClass %d\n", FsInformationClass
);
397 DPRINT ("BufferLength %d\n", BufferLength
);
398 DPRINT ("SystemBuffer %x\n", SystemBuffer
);
400 switch(FsInformationClass
)
402 case FileFsLabelInformation
:
403 Status
= FsdSetFsLabelInformation(IrpContext
->DeviceObject
,
408 Status
= STATUS_NOT_SUPPORTED
;
411 ExReleaseResourceLite(&((PDEVICE_EXTENSION
)IrpContext
->DeviceObject
->DeviceExtension
)->DirResource
);
412 IrpContext
->Irp
->IoStatus
.Status
= Status
;
413 IrpContext
->Irp
->IoStatus
.Information
= 0;
414 IoCompleteRequest(IrpContext
->Irp
, IO_NO_INCREMENT
);
415 VfatFreeIrpContext(IrpContext
);