[HEADERS] Use the new header with SPDX license identifier for host headers I've contr...
[reactos.git] / reactos / drivers / filesystems / fastfat_new / fsctl.c
1 /*
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)
7 */
8
9 /* INCLUDES *****************************************************************/
10
11 #define NDEBUG
12 #include "fastfat.h"
13
14 /* FUNCTIONS ****************************************************************/
15
16 NTSTATUS
17 NTAPI
18 FatOplockRequest(IN PFAT_IRP_CONTEXT IrpContext,
19 IN PIRP Irp)
20 {
21 NTSTATUS Status;
22 DPRINT1("Oplock request!\n");
23
24 Status = STATUS_INVALID_DEVICE_REQUEST;
25 FatCompleteRequest(IrpContext, Irp, Status);
26
27 return Status;
28 }
29
30 NTSTATUS
31 NTAPI
32 FatMarkVolumeDirty(IN PFAT_IRP_CONTEXT IrpContext,
33 IN PIRP Irp)
34 {
35 NTSTATUS Status;
36 DPRINT1("Marking volume as dirty\n");
37
38 Status = STATUS_SUCCESS;
39 FatCompleteRequest(IrpContext, Irp, Status);
40
41 return Status;
42 }
43
44 NTSTATUS
45 NTAPI
46 FatUserFsCtrl(PFAT_IRP_CONTEXT IrpContext, PIRP Irp)
47 {
48 PIO_STACK_LOCATION IrpSp;
49 NTSTATUS Status;
50 ULONG Code;
51
52 /* Get current IRP stack location */
53 IrpSp = IoGetCurrentIrpStackLocation(Irp);
54
55 Code = IrpSp->Parameters.FileSystemControl.FsControlCode;
56
57 /* Set the wait flag */
58 if (Irp->RequestorMode != KernelMode &&
59 (Code & 3) == METHOD_NEITHER)
60 {
61 SetFlag(IrpContext->Flags, IRPCONTEXT_CANWAIT);
62 }
63
64 /* Branch according to the code */
65 switch (Code)
66 {
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);
76 break;
77
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);
83 break;
84
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);
90 break;
91
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);
97 break;
98
99 case FSCTL_MARK_VOLUME_DIRTY:
100 Status = FatMarkVolumeDirty(IrpContext, Irp);
101 break;
102
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);
108 break;
109
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);
115 break;
116
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);
122 break;
123
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);
129 break;
130
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);
136 break;
137
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);
143 break;
144
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);
150 break;
151
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);
157 break;
158
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);
164 break;
165
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);
171 break;
172
173 default:
174 DPRINT("FatUserFsCtrl(), unhandled fs control code 0x%x\n", Code);
175 Status = STATUS_INVALID_DEVICE_REQUEST;
176 FatCompleteRequest(IrpContext, Irp, Status);
177 }
178
179 //(((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method))
180
181 // 9c040
182 // 1 1 0 0 0
183 // 6 4 8 4 0
184 // 10011100000001000000
185 // DT = 1001 = 9
186 // Access = 11 = 3
187 // Function = 10000 = 16
188 // Method = 0
189
190 return Status;
191 }
192
193 NTSTATUS
194 NTAPI
195 FatVerifyVolume(PFAT_IRP_CONTEXT IrpContext, PIRP Irp)
196 {
197 DPRINT1("FatVerifyVolume()\n");
198 FatCompleteRequest(IrpContext, Irp, STATUS_INVALID_DEVICE_REQUEST);
199 return STATUS_INVALID_DEVICE_REQUEST;
200 }
201
202 VOID
203 NTAPI
204 FatiCleanVcbs(PFAT_IRP_CONTEXT IrpContext)
205 {
206 /* Make sure this IRP is waitable */
207 ASSERT(IrpContext->Flags & IRPCONTEXT_CANWAIT);
208
209 /* Acquire global resource */
210 ExAcquireResourceExclusiveLite(&FatGlobalData.Resource, TRUE);
211
212 /* TODO: Go through all VCBs and delete unmounted ones */
213
214 /* Release global resource */
215 ExReleaseResourceLite(&FatGlobalData.Resource);
216 }
217
218 VOID
219 NTAPI
220 FatiUnpackBpb(PBIOS_PARAMETER_BLOCK Bpb, PPACKED_BIOS_PARAMETER_BLOCK PackedBpb)
221 {
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]);
240 }
241
242 BOOLEAN
243 NTAPI
244 FatiBpbFat32(PPACKED_BIOS_PARAMETER_BLOCK PackedBpb)
245 {
246 return (*(USHORT *)(&PackedBpb->SectorsPerFat) == 0);
247 }
248
249 NTSTATUS
250 NTAPI
251 FatMountVolume(PFAT_IRP_CONTEXT IrpContext,
252 PDEVICE_OBJECT TargetDeviceObject,
253 PVPB Vpb,
254 PDEVICE_OBJECT FsDeviceObject)
255 {
256 NTSTATUS Status;
257 DISK_GEOMETRY DiskGeometry;
258 ULONG MediaChangeCount = 0;
259 PVOLUME_DEVICE_OBJECT VolumeDevice;
260 VCB *Vcb;
261 FF_ERROR Error;
262 PBCB BootBcb;
263 PPACKED_BOOT_SECTOR BootSector;
264
265 DPRINT1("FatMountVolume()\n");
266
267 /* Make sure this IRP is waitable */
268 ASSERT(IrpContext->Flags & IRPCONTEXT_CANWAIT);
269
270 /* Request media changes count, mostly useful for removable devices */
271 Status = FatPerformDevIoCtrl(TargetDeviceObject,
272 IOCTL_STORAGE_CHECK_VERIFY,
273 NULL,
274 0,
275 &MediaChangeCount,
276 sizeof(ULONG),
277 TRUE);
278
279 if (!NT_SUCCESS(Status)) return Status;
280
281 /* TODO: Check if data-track present in case of a CD drive */
282 /* TODO: IOCTL_DISK_GET_PARTITION_INFO_EX */
283
284 /* Remove unmounted VCBs */
285 FatiCleanVcbs(IrpContext);
286
287 /* Acquire the global exclusive lock */
288 FatAcquireExclusiveGlobal(IrpContext);
289
290 /* Create a new volume device object */
291 Status = IoCreateDevice(FatGlobalData.DriverObject,
292 sizeof(VOLUME_DEVICE_OBJECT) - sizeof(DEVICE_OBJECT),
293 NULL,
294 FILE_DEVICE_DISK_FILE_SYSTEM,
295 0,
296 FALSE,
297 (PDEVICE_OBJECT *)&VolumeDevice);
298
299 if (!NT_SUCCESS(Status))
300 {
301 /* Release the global lock */
302 FatReleaseGlobal(IrpContext);
303
304 return Status;
305 }
306
307 /* Match alignment requirements */
308 if (TargetDeviceObject->AlignmentRequirement > VolumeDevice->DeviceObject.AlignmentRequirement)
309 {
310 VolumeDevice->DeviceObject.AlignmentRequirement = TargetDeviceObject->AlignmentRequirement;
311 }
312
313 /* Init stack size */
314 VolumeDevice->DeviceObject.StackSize = TargetDeviceObject->StackSize + 1;
315
316 /* Get sector size */
317 Status = FatPerformDevIoCtrl(TargetDeviceObject,
318 IOCTL_DISK_GET_DRIVE_GEOMETRY,
319 NULL,
320 0,
321 &DiskGeometry,
322 sizeof(DISK_GEOMETRY),
323 TRUE);
324
325 if (!NT_SUCCESS(Status)) goto FatMountVolumeCleanup;
326
327 VolumeDevice->DeviceObject.SectorSize = (USHORT) DiskGeometry.BytesPerSector;
328
329 /* Signal we're done with initializing */
330 VolumeDevice->DeviceObject.Flags &= ~DO_DEVICE_INITIALIZING;
331
332 /* Save device object in a VPB */
333 Vpb->DeviceObject = (PDEVICE_OBJECT)VolumeDevice;
334
335 /* Initialize VCB for this volume */
336 Status = FatInitializeVcb(IrpContext, &VolumeDevice->Vcb, TargetDeviceObject, Vpb);
337 if (!NT_SUCCESS(Status)) goto FatMountVolumeCleanup;
338
339 Vcb = &VolumeDevice->Vcb;
340
341 /* Initialize FullFAT library */
342 Vcb->Ioman = FF_CreateIOMAN(NULL,
343 8192,
344 VolumeDevice->DeviceObject.SectorSize,
345 &Error);
346
347 ASSERT(Vcb->Ioman);
348
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,
354 Vcb);
355
356 if (Error)
357 {
358 DPRINT1("Registering block device with FullFAT failed with error %d\n", Error);
359 FF_DestroyIOMAN(Vcb->Ioman);
360 goto FatMountVolumeCleanup;
361 }
362
363 /* Mount the volume using FullFAT */
364 if(FF_MountPartition(Vcb->Ioman, 0))
365 {
366 DPRINT1("Partition mounting failed\n");
367 FF_DestroyIOMAN(Vcb->Ioman);
368 goto FatMountVolumeCleanup;
369 }
370
371 /* Read the boot sector */
372 FatReadStreamFile(Vcb, 0, sizeof(PACKED_BOOT_SECTOR), &BootBcb, (PVOID)&BootSector);
373
374 /* Check if it's successful */
375 if (!BootBcb)
376 {
377 Status = STATUS_UNRECOGNIZED_VOLUME;
378 goto FatMountVolumeCleanup;
379 }
380
381 /* Unpack data */
382 FatiUnpackBpb(&Vcb->Bpb, &BootSector->PackedBpb);
383
384 /* Verify if sector size matches */
385 if (DiskGeometry.BytesPerSector != Vcb->Bpb.BytesPerSector)
386 {
387 DPRINT1("Disk geometry BPS %d and bios BPS %d don't match!\n",
388 DiskGeometry.BytesPerSector, Vcb->Bpb.BytesPerSector);
389
390 /* Fail */
391 Status = STATUS_UNRECOGNIZED_VOLUME;
392 goto FatMountVolumeCleanup;
393 }
394
395 /* If Sectors value is set, discard the LargeSectors value */
396 if (Vcb->Bpb.Sectors) Vcb->Bpb.LargeSectors = 0;
397
398 /* Copy serial number */
399 if (FatiBpbFat32(&BootSector->PackedBpb))
400 {
401 CopyUchar4(&Vpb->SerialNumber, ((PPACKED_BOOT_SECTOR_EX)BootSector)->Id);
402 }
403 else
404 {
405 /* This is FAT12/16 */
406 CopyUchar4(&Vpb->SerialNumber, BootSector->Id);
407 }
408
409 /* Unpin the BCB */
410 CcUnpinData(BootBcb);
411
412 /* Create root DCB for it */
413 FatCreateRootDcb(IrpContext, &VolumeDevice->Vcb);
414
415 /* Keep trace of media changes */
416 VolumeDevice->Vcb.MediaChangeCount = MediaChangeCount;
417
418 //ObDereferenceObject(TargetDeviceObject);
419
420 /* Release the global lock */
421 FatReleaseGlobal(IrpContext);
422
423 /* Notify about volume mount */
424 //FsRtlNotifyVolumeEvent(VolumeDevice->Vcb.StreamFileObject, FSRTL_VOLUME_MOUNT);
425
426 /* Return success */
427 return STATUS_SUCCESS;
428
429
430 FatMountVolumeCleanup:
431
432 /* Unwind the routine actions */
433 IoDeleteDevice((PDEVICE_OBJECT)VolumeDevice);
434
435 /* Release the global lock */
436 FatReleaseGlobal(IrpContext);
437
438 return Status;
439 }
440
441
442
443 NTSTATUS
444 NTAPI
445 FatiFileSystemControl(PFAT_IRP_CONTEXT IrpContext, PIRP Irp)
446 {
447 PIO_STACK_LOCATION IrpSp;
448 NTSTATUS Status;
449
450 /* Get current IRP stack location */
451 IrpSp = IoGetCurrentIrpStackLocation(Irp);
452
453 /* Dispatch depending on the minor function */
454 switch (IrpSp->MinorFunction)
455 {
456 case IRP_MN_KERNEL_CALL:
457 case IRP_MN_USER_FS_REQUEST:
458 Status = FatUserFsCtrl(IrpContext, Irp);
459 break;
460
461 case IRP_MN_MOUNT_VOLUME:
462 Status = FatMountVolume(IrpContext,
463 IrpSp->Parameters.MountVolume.DeviceObject,
464 IrpSp->Parameters.MountVolume.Vpb,
465 IrpSp->DeviceObject);
466
467 FatCompleteRequest(IrpContext, Irp, Status);
468
469 break;
470
471 case IRP_MN_VERIFY_VOLUME:
472 Status = FatVerifyVolume(IrpContext, Irp);
473 break;
474
475 default:
476 DPRINT1("Unhandled FSCTL minor 0x%x\n", IrpSp->MinorFunction);
477 FatCompleteRequest(IrpContext, Irp, STATUS_INVALID_DEVICE_REQUEST);
478 Status = STATUS_INVALID_DEVICE_REQUEST;
479 }
480
481 return Status;
482 }
483
484
485 NTSTATUS
486 NTAPI
487 FatFileSystemControl(PDEVICE_OBJECT DeviceObject, PIRP Irp)
488 {
489 NTSTATUS Status = STATUS_SUCCESS;
490 PFAT_IRP_CONTEXT IrpContext;
491 BOOLEAN CanWait = TRUE;
492
493 DPRINT("FatFileSystemControl(DeviceObject %p, Irp %p)\n", DeviceObject, Irp);
494
495 /* Get CanWait flag */
496 if (IoGetCurrentIrpStackLocation(Irp)->FileObject)
497 {
498 CanWait = IoIsOperationSynchronous(Irp);
499 }
500
501 /* Enter FsRtl critical region */
502 FsRtlEnterFileSystem();
503
504 /* Build an irp context */
505 IrpContext = FatBuildIrpContext(Irp, CanWait);
506
507 /* Call internal function */
508 Status = FatiFileSystemControl(IrpContext, Irp);
509
510 /* Leave FsRtl critical region */
511 FsRtlExitFileSystem();
512
513 return Status;
514 }