2 * PROJECT: ReactOS FAT file system driver
3 * LICENSE: GNU GPLv3 as published by the Free Software Foundation
4 * FILE: drivers/filesystems/fastfat/fsctl.c
5 * PURPOSE: Filesystem control
6 * PROGRAMMERS: Aleksey Bragin (aleksey@reactos.org)
9 /* INCLUDES *****************************************************************/
14 /* FUNCTIONS ****************************************************************/
18 FatOplockRequest(IN PFAT_IRP_CONTEXT IrpContext
,
22 DPRINT1("Oplock request!\n");
24 Status
= STATUS_INVALID_DEVICE_REQUEST
;
25 FatCompleteRequest(IrpContext
, Irp
, Status
);
32 FatMarkVolumeDirty(IN PFAT_IRP_CONTEXT IrpContext
,
36 DPRINT1("Marking volume as dirty\n");
38 Status
= STATUS_SUCCESS
;
39 FatCompleteRequest(IrpContext
, Irp
, Status
);
46 FatUserFsCtrl(PFAT_IRP_CONTEXT IrpContext
, PIRP Irp
)
48 PIO_STACK_LOCATION IrpSp
;
52 /* Get current IRP stack location */
53 IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
55 Code
= IrpSp
->Parameters
.FileSystemControl
.FsControlCode
;
57 /* Set the wait flag */
58 if (Irp
->RequestorMode
!= KernelMode
&&
59 (Code
& 3) == METHOD_NEITHER
)
61 SetFlag(IrpContext
->Flags
, IRPCONTEXT_CANWAIT
);
64 /* Branch according to the code */
67 case FSCTL_REQUEST_OPLOCK_LEVEL_1
:
68 case FSCTL_REQUEST_OPLOCK_LEVEL_2
:
69 case FSCTL_REQUEST_BATCH_OPLOCK
:
70 case FSCTL_OPLOCK_BREAK_ACKNOWLEDGE
:
71 case FSCTL_OPBATCH_ACK_CLOSE_PENDING
:
72 case FSCTL_OPLOCK_BREAK_NOTIFY
:
73 case FSCTL_OPLOCK_BREAK_ACK_NO_2
:
74 case FSCTL_REQUEST_FILTER_OPLOCK
:
75 Status
= FatOplockRequest(IrpContext
, Irp
);
78 case FSCTL_LOCK_VOLUME
:
79 //Status = FatLockVolume( IrpContext, Irp );
80 DPRINT1("FSCTL_LOCK_VOLUME\n");
81 Status
= STATUS_INVALID_DEVICE_REQUEST
;
82 FatCompleteRequest(IrpContext
, Irp
, Status
);
85 case FSCTL_UNLOCK_VOLUME
:
86 //Status = FatUnlockVolume( IrpContext, Irp );
87 DPRINT1("FSCTL_UNLOCK_VOLUME\n");
88 Status
= STATUS_INVALID_DEVICE_REQUEST
;
89 FatCompleteRequest(IrpContext
, Irp
, Status
);
92 case FSCTL_DISMOUNT_VOLUME
:
93 //Status = FatDismountVolume( IrpContext, Irp );
94 DPRINT1("FSCTL_DISMOUNT_VOLUME\n");
95 Status
= STATUS_INVALID_DEVICE_REQUEST
;
96 FatCompleteRequest(IrpContext
, Irp
, Status
);
99 case FSCTL_MARK_VOLUME_DIRTY
:
100 Status
= FatMarkVolumeDirty(IrpContext
, Irp
);
103 case FSCTL_IS_VOLUME_DIRTY
:
104 //Status = FatIsVolumeDirty( IrpContext, Irp );
105 DPRINT1("FSCTL_IS_VOLUME_DIRTY\n");
106 Status
= STATUS_INVALID_DEVICE_REQUEST
;
107 FatCompleteRequest(IrpContext
, Irp
, Status
);
110 case FSCTL_IS_VOLUME_MOUNTED
:
111 //Status = FatIsVolumeMounted( IrpContext, Irp );
112 DPRINT1("FSCTL_IS_VOLUME_MOUNTED\n");
113 Status
= STATUS_INVALID_DEVICE_REQUEST
;
114 FatCompleteRequest(IrpContext
, Irp
, Status
);
117 case FSCTL_IS_PATHNAME_VALID
:
118 //Status = FatIsPathnameValid( IrpContext, Irp );
119 DPRINT1("FSCTL_IS_PATHNAME_VALID\n");
120 Status
= STATUS_INVALID_DEVICE_REQUEST
;
121 FatCompleteRequest(IrpContext
, Irp
, Status
);
124 case FSCTL_QUERY_RETRIEVAL_POINTERS
:
125 //Status = FatQueryRetrievalPointers( IrpContext, Irp );
126 DPRINT1("FSCTL_QUERY_RETRIEVAL_POINTERS\n");
127 Status
= STATUS_INVALID_DEVICE_REQUEST
;
128 FatCompleteRequest(IrpContext
, Irp
, Status
);
131 case FSCTL_QUERY_FAT_BPB
:
132 //Status = FatQueryBpb( IrpContext, Irp );
133 DPRINT1("FSCTL_QUERY_FAT_BPB\n");
134 Status
= STATUS_INVALID_DEVICE_REQUEST
;
135 FatCompleteRequest(IrpContext
, Irp
, Status
);
138 case FSCTL_FILESYSTEM_GET_STATISTICS
:
139 //Status = FatGetStatistics( IrpContext, Irp );
140 DPRINT1("FSCTL_FILESYSTEM_GET_STATISTICS\n");
141 Status
= STATUS_INVALID_DEVICE_REQUEST
;
142 FatCompleteRequest(IrpContext
, Irp
, Status
);
145 case FSCTL_GET_VOLUME_BITMAP
:
146 //Status = FatGetVolumeBitmap( IrpContext, Irp );
147 DPRINT1("FSCTL_GET_VOLUME_BITMAP\n");
148 Status
= STATUS_INVALID_DEVICE_REQUEST
;
149 FatCompleteRequest(IrpContext
, Irp
, Status
);
152 case FSCTL_GET_RETRIEVAL_POINTERS
:
153 //Status = FatGetRetrievalPointers( IrpContext, Irp );
154 DPRINT1("FSCTL_GET_RETRIEVAL_POINTERS\n");
155 Status
= STATUS_INVALID_DEVICE_REQUEST
;
156 FatCompleteRequest(IrpContext
, Irp
, Status
);
159 case FSCTL_MOVE_FILE
:
160 //Status = FatMoveFile( IrpContext, Irp );
161 DPRINT1("FSCTL_MOVE_FILE\n");
162 Status
= STATUS_INVALID_DEVICE_REQUEST
;
163 FatCompleteRequest(IrpContext
, Irp
, Status
);
166 case FSCTL_ALLOW_EXTENDED_DASD_IO
:
167 //Status = FatAllowExtendedDasdIo( IrpContext, Irp );
168 DPRINT1("FSCTL_ALLOW_EXTENDED_DASD_IO\n");
169 Status
= STATUS_INVALID_DEVICE_REQUEST
;
170 FatCompleteRequest(IrpContext
, Irp
, Status
);
174 DPRINT("FatUserFsCtrl(), unhandled fs control code 0x%x\n", Code
);
175 Status
= STATUS_INVALID_DEVICE_REQUEST
;
176 FatCompleteRequest(IrpContext
, Irp
, Status
);
179 //(((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method))
184 // 10011100000001000000
187 // Function = 10000 = 16
195 FatVerifyVolume(PFAT_IRP_CONTEXT IrpContext
, PIRP Irp
)
197 DPRINT1("FatVerifyVolume()\n");
198 FatCompleteRequest(IrpContext
, Irp
, STATUS_INVALID_DEVICE_REQUEST
);
199 return STATUS_INVALID_DEVICE_REQUEST
;
204 FatiCleanVcbs(PFAT_IRP_CONTEXT IrpContext
)
206 /* Make sure this IRP is waitable */
207 ASSERT(IrpContext
->Flags
& IRPCONTEXT_CANWAIT
);
209 /* Acquire global resource */
210 ExAcquireResourceExclusiveLite(&FatGlobalData
.Resource
, TRUE
);
212 /* TODO: Go through all VCBs and delete unmounted ones */
214 /* Release global resource */
215 ExReleaseResourceLite(&FatGlobalData
.Resource
);
220 FatiUnpackBpb(PBIOS_PARAMETER_BLOCK Bpb
, PPACKED_BIOS_PARAMETER_BLOCK PackedBpb
)
222 CopyUchar2(&Bpb
->BytesPerSector
, &PackedBpb
->BytesPerSector
[0]);
223 CopyUchar1(&Bpb
->SectorsPerCluster
, &PackedBpb
->SectorsPerCluster
[0]);
224 CopyUchar2(&Bpb
->ReservedSectors
, &PackedBpb
->ReservedSectors
[0]);
225 CopyUchar1(&Bpb
->Fats
, &PackedBpb
->Fats
[0]);
226 CopyUchar2(&Bpb
->RootEntries
, &PackedBpb
->RootEntries
[0]);
227 CopyUchar2(&Bpb
->Sectors
, &PackedBpb
->Sectors
[0]);
228 CopyUchar1(&Bpb
->Media
, &PackedBpb
->Media
[0]);
229 CopyUchar2(&Bpb
->SectorsPerFat
, &PackedBpb
->SectorsPerFat
[0]);
230 CopyUchar2(&Bpb
->SectorsPerTrack
, &PackedBpb
->SectorsPerTrack
[0]);
231 CopyUchar2(&Bpb
->Heads
, &PackedBpb
->Heads
[0]);
232 CopyUchar4(&Bpb
->HiddenSectors
, &PackedBpb
->HiddenSectors
[0]);
233 CopyUchar4(&Bpb
->LargeSectors
, &PackedBpb
->LargeSectors
[0]);
234 CopyUchar4(&Bpb
->LargeSectorsPerFat
, &((PPACKED_BIOS_PARAMETER_BLOCK_EX
)PackedBpb
)->LargeSectorsPerFat
[0]);
235 CopyUchar2(&Bpb
->ExtendedFlags
, &((PPACKED_BIOS_PARAMETER_BLOCK_EX
)PackedBpb
)->ExtendedFlags
[0]);
236 CopyUchar2(&Bpb
->FsVersion
, &((PPACKED_BIOS_PARAMETER_BLOCK_EX
)PackedBpb
)->FsVersion
[0]);
237 CopyUchar4(&Bpb
->RootDirFirstCluster
,&((PPACKED_BIOS_PARAMETER_BLOCK_EX
)PackedBpb
)->RootDirFirstCluster
[0]);
238 CopyUchar2(&Bpb
->FsInfoSector
, &((PPACKED_BIOS_PARAMETER_BLOCK_EX
)PackedBpb
)->FsInfoSector
[0]);
239 CopyUchar2(&Bpb
->BackupBootSector
, &((PPACKED_BIOS_PARAMETER_BLOCK_EX
)PackedBpb
)->BackupBootSector
[0]);
244 FatiBpbFat32(PPACKED_BIOS_PARAMETER_BLOCK PackedBpb
)
246 return (*(USHORT
*)(&PackedBpb
->SectorsPerFat
) == 0);
251 FatMountVolume(PFAT_IRP_CONTEXT IrpContext
,
252 PDEVICE_OBJECT TargetDeviceObject
,
254 PDEVICE_OBJECT FsDeviceObject
)
257 DISK_GEOMETRY DiskGeometry
;
258 ULONG MediaChangeCount
= 0;
259 PVOLUME_DEVICE_OBJECT VolumeDevice
;
263 PPACKED_BOOT_SECTOR BootSector
;
265 DPRINT1("FatMountVolume()\n");
267 /* Make sure this IRP is waitable */
268 ASSERT(IrpContext
->Flags
& IRPCONTEXT_CANWAIT
);
270 /* Request media changes count, mostly useful for removable devices */
271 Status
= FatPerformDevIoCtrl(TargetDeviceObject
,
272 IOCTL_STORAGE_CHECK_VERIFY
,
279 if (!NT_SUCCESS(Status
)) return Status
;
281 /* TODO: Check if data-track present in case of a CD drive */
282 /* TODO: IOCTL_DISK_GET_PARTITION_INFO_EX */
284 /* Remove unmounted VCBs */
285 FatiCleanVcbs(IrpContext
);
287 /* Acquire the global exclusive lock */
288 FatAcquireExclusiveGlobal(IrpContext
);
290 /* Create a new volume device object */
291 Status
= IoCreateDevice(FatGlobalData
.DriverObject
,
292 sizeof(VOLUME_DEVICE_OBJECT
) - sizeof(DEVICE_OBJECT
),
294 FILE_DEVICE_DISK_FILE_SYSTEM
,
297 (PDEVICE_OBJECT
*)&VolumeDevice
);
299 if (!NT_SUCCESS(Status
))
301 /* Release the global lock */
302 FatReleaseGlobal(IrpContext
);
307 /* Match alignment requirements */
308 if (TargetDeviceObject
->AlignmentRequirement
> VolumeDevice
->DeviceObject
.AlignmentRequirement
)
310 VolumeDevice
->DeviceObject
.AlignmentRequirement
= TargetDeviceObject
->AlignmentRequirement
;
313 /* Init stack size */
314 VolumeDevice
->DeviceObject
.StackSize
= TargetDeviceObject
->StackSize
+ 1;
316 /* Get sector size */
317 Status
= FatPerformDevIoCtrl(TargetDeviceObject
,
318 IOCTL_DISK_GET_DRIVE_GEOMETRY
,
322 sizeof(DISK_GEOMETRY
),
325 if (!NT_SUCCESS(Status
)) goto FatMountVolumeCleanup
;
327 VolumeDevice
->DeviceObject
.SectorSize
= (USHORT
) DiskGeometry
.BytesPerSector
;
329 /* Signal we're done with initializing */
330 VolumeDevice
->DeviceObject
.Flags
&= ~DO_DEVICE_INITIALIZING
;
332 /* Save device object in a VPB */
333 Vpb
->DeviceObject
= (PDEVICE_OBJECT
)VolumeDevice
;
335 /* Initialize VCB for this volume */
336 Status
= FatInitializeVcb(IrpContext
, &VolumeDevice
->Vcb
, TargetDeviceObject
, Vpb
);
337 if (!NT_SUCCESS(Status
)) goto FatMountVolumeCleanup
;
339 Vcb
= &VolumeDevice
->Vcb
;
341 /* Initialize FullFAT library */
342 Vcb
->Ioman
= FF_CreateIOMAN(NULL
,
344 VolumeDevice
->DeviceObject
.SectorSize
,
349 /* Register block device read/write functions */
350 Error
= FF_RegisterBlkDevice(Vcb
->Ioman
,
351 VolumeDevice
->DeviceObject
.SectorSize
,
352 (FF_WRITE_BLOCKS
)FatWriteBlocks
,
353 (FF_READ_BLOCKS
)FatReadBlocks
,
358 DPRINT1("Registering block device with FullFAT failed with error %d\n", Error
);
359 FF_DestroyIOMAN(Vcb
->Ioman
);
360 goto FatMountVolumeCleanup
;
363 /* Mount the volume using FullFAT */
364 if(FF_MountPartition(Vcb
->Ioman
, 0))
366 DPRINT1("Partition mounting failed\n");
367 FF_DestroyIOMAN(Vcb
->Ioman
);
368 goto FatMountVolumeCleanup
;
371 /* Read the boot sector */
372 FatReadStreamFile(Vcb
, 0, sizeof(PACKED_BOOT_SECTOR
), &BootBcb
, (PVOID
)&BootSector
);
374 /* Check if it's successful */
377 Status
= STATUS_UNRECOGNIZED_VOLUME
;
378 goto FatMountVolumeCleanup
;
382 FatiUnpackBpb(&Vcb
->Bpb
, &BootSector
->PackedBpb
);
384 /* Verify if sector size matches */
385 if (DiskGeometry
.BytesPerSector
!= Vcb
->Bpb
.BytesPerSector
)
387 DPRINT1("Disk geometry BPS %d and bios BPS %d don't match!\n",
388 DiskGeometry
.BytesPerSector
, Vcb
->Bpb
.BytesPerSector
);
391 Status
= STATUS_UNRECOGNIZED_VOLUME
;
392 goto FatMountVolumeCleanup
;
395 /* If Sectors value is set, discard the LargeSectors value */
396 if (Vcb
->Bpb
.Sectors
) Vcb
->Bpb
.LargeSectors
= 0;
398 /* Copy serial number */
399 if (FatiBpbFat32(&BootSector
->PackedBpb
))
401 CopyUchar4(&Vpb
->SerialNumber
, ((PPACKED_BOOT_SECTOR_EX
)BootSector
)->Id
);
405 /* This is FAT12/16 */
406 CopyUchar4(&Vpb
->SerialNumber
, BootSector
->Id
);
410 CcUnpinData(BootBcb
);
412 /* Create root DCB for it */
413 FatCreateRootDcb(IrpContext
, &VolumeDevice
->Vcb
);
415 /* Keep trace of media changes */
416 VolumeDevice
->Vcb
.MediaChangeCount
= MediaChangeCount
;
418 //ObDereferenceObject(TargetDeviceObject);
420 /* Release the global lock */
421 FatReleaseGlobal(IrpContext
);
423 /* Notify about volume mount */
424 //FsRtlNotifyVolumeEvent(VolumeDevice->Vcb.StreamFileObject, FSRTL_VOLUME_MOUNT);
427 return STATUS_SUCCESS
;
430 FatMountVolumeCleanup
:
432 /* Unwind the routine actions */
433 IoDeleteDevice((PDEVICE_OBJECT
)VolumeDevice
);
435 /* Release the global lock */
436 FatReleaseGlobal(IrpContext
);
445 FatiFileSystemControl(PFAT_IRP_CONTEXT IrpContext
, PIRP Irp
)
447 PIO_STACK_LOCATION IrpSp
;
450 /* Get current IRP stack location */
451 IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
453 /* Dispatch depending on the minor function */
454 switch (IrpSp
->MinorFunction
)
456 case IRP_MN_KERNEL_CALL
:
457 case IRP_MN_USER_FS_REQUEST
:
458 Status
= FatUserFsCtrl(IrpContext
, Irp
);
461 case IRP_MN_MOUNT_VOLUME
:
462 Status
= FatMountVolume(IrpContext
,
463 IrpSp
->Parameters
.MountVolume
.DeviceObject
,
464 IrpSp
->Parameters
.MountVolume
.Vpb
,
465 IrpSp
->DeviceObject
);
467 FatCompleteRequest(IrpContext
, Irp
, Status
);
471 case IRP_MN_VERIFY_VOLUME
:
472 Status
= FatVerifyVolume(IrpContext
, Irp
);
476 DPRINT1("Unhandled FSCTL minor 0x%x\n", IrpSp
->MinorFunction
);
477 FatCompleteRequest(IrpContext
, Irp
, STATUS_INVALID_DEVICE_REQUEST
);
478 Status
= STATUS_INVALID_DEVICE_REQUEST
;
487 FatFileSystemControl(PDEVICE_OBJECT DeviceObject
, PIRP Irp
)
489 NTSTATUS Status
= STATUS_SUCCESS
;
490 PFAT_IRP_CONTEXT IrpContext
;
491 BOOLEAN CanWait
= TRUE
;
493 DPRINT("FatFileSystemControl(DeviceObject %p, Irp %p)\n", DeviceObject
, Irp
);
495 /* Get CanWait flag */
496 if (IoGetCurrentIrpStackLocation(Irp
)->FileObject
)
498 CanWait
= IoIsOperationSynchronous(Irp
);
501 /* Enter FsRtl critical region */
502 FsRtlEnterFileSystem();
504 /* Build an irp context */
505 IrpContext
= FatBuildIrpContext(Irp
, CanWait
);
507 /* Call internal function */
508 Status
= FatiFileSystemControl(IrpContext
, Irp
);
510 /* Leave FsRtl critical region */
511 FsRtlExitFileSystem();