Sync with trunk (48237)
[reactos.git] / 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 FatUserFsCtrl(PFAT_IRP_CONTEXT IrpContext, PIRP Irp)
19 {
20 DPRINT1("FatUserFsCtrl()\n");
21 FatCompleteRequest(IrpContext, Irp, STATUS_INVALID_DEVICE_REQUEST);
22 return STATUS_INVALID_DEVICE_REQUEST;
23 }
24
25 NTSTATUS
26 NTAPI
27 FatVerifyVolume(PFAT_IRP_CONTEXT IrpContext, PIRP Irp)
28 {
29 DPRINT1("FatVerifyVolume()\n");
30 FatCompleteRequest(IrpContext, Irp, STATUS_INVALID_DEVICE_REQUEST);
31 return STATUS_INVALID_DEVICE_REQUEST;
32 }
33
34 VOID
35 NTAPI
36 FatiCleanVcbs(PFAT_IRP_CONTEXT IrpContext)
37 {
38 /* Make sure this IRP is waitable */
39 ASSERT(IrpContext->Flags & IRPCONTEXT_CANWAIT);
40
41 /* Acquire global resource */
42 ExAcquireResourceExclusiveLite(&FatGlobalData.Resource, TRUE);
43
44 /* TODO: Go through all VCBs and delete unmounted ones */
45
46 /* Release global resource */
47 ExReleaseResourceLite(&FatGlobalData.Resource);
48 }
49
50 VOID
51 NTAPI
52 FatiUnpackBpb(PBIOS_PARAMETER_BLOCK Bpb, PPACKED_BIOS_PARAMETER_BLOCK PackedBpb)
53 {
54 CopyUchar2(&Bpb->BytesPerSector, &PackedBpb->BytesPerSector[0]);
55 CopyUchar1(&Bpb->SectorsPerCluster, &PackedBpb->SectorsPerCluster[0]);
56 CopyUchar2(&Bpb->ReservedSectors, &PackedBpb->ReservedSectors[0]);
57 CopyUchar1(&Bpb->Fats, &PackedBpb->Fats[0]);
58 CopyUchar2(&Bpb->RootEntries, &PackedBpb->RootEntries[0]);
59 CopyUchar2(&Bpb->Sectors, &PackedBpb->Sectors[0]);
60 CopyUchar1(&Bpb->Media, &PackedBpb->Media[0]);
61 CopyUchar2(&Bpb->SectorsPerFat, &PackedBpb->SectorsPerFat[0]);
62 CopyUchar2(&Bpb->SectorsPerTrack, &PackedBpb->SectorsPerTrack[0]);
63 CopyUchar2(&Bpb->Heads, &PackedBpb->Heads[0]);
64 CopyUchar4(&Bpb->HiddenSectors, &PackedBpb->HiddenSectors[0]);
65 CopyUchar4(&Bpb->LargeSectors, &PackedBpb->LargeSectors[0]);
66 CopyUchar4(&Bpb->LargeSectorsPerFat, &((PPACKED_BIOS_PARAMETER_BLOCK_EX)PackedBpb)->LargeSectorsPerFat[0]);
67 CopyUchar2(&Bpb->ExtendedFlags, &((PPACKED_BIOS_PARAMETER_BLOCK_EX)PackedBpb)->ExtendedFlags[0]);
68 CopyUchar2(&Bpb->FsVersion, &((PPACKED_BIOS_PARAMETER_BLOCK_EX)PackedBpb)->FsVersion[0]);
69 CopyUchar4(&Bpb->RootDirFirstCluster,&((PPACKED_BIOS_PARAMETER_BLOCK_EX)PackedBpb)->RootDirFirstCluster[0]);
70 CopyUchar2(&Bpb->FsInfoSector, &((PPACKED_BIOS_PARAMETER_BLOCK_EX)PackedBpb)->FsInfoSector[0]);
71 CopyUchar2(&Bpb->BackupBootSector, &((PPACKED_BIOS_PARAMETER_BLOCK_EX)PackedBpb)->BackupBootSector[0]);
72 }
73
74 BOOLEAN
75 NTAPI
76 FatiBpbFat32(PPACKED_BIOS_PARAMETER_BLOCK PackedBpb)
77 {
78 return (*(USHORT *)(&PackedBpb->SectorsPerFat) == 0);
79 }
80
81 NTSTATUS
82 NTAPI
83 FatMountVolume(PFAT_IRP_CONTEXT IrpContext,
84 PDEVICE_OBJECT TargetDeviceObject,
85 PVPB Vpb,
86 PDEVICE_OBJECT FsDeviceObject)
87 {
88 NTSTATUS Status;
89 DISK_GEOMETRY DiskGeometry;
90 ULONG MediaChangeCount = 0;
91 PVOLUME_DEVICE_OBJECT VolumeDevice;
92 VCB *Vcb;
93 FF_ERROR Error;
94 PBCB BootBcb;
95 PPACKED_BOOT_SECTOR BootSector;
96
97 DPRINT1("FatMountVolume()\n");
98
99 /* Make sure this IRP is waitable */
100 ASSERT(IrpContext->Flags & IRPCONTEXT_CANWAIT);
101
102 /* Request media changes count, mostly useful for removable devices */
103 Status = FatPerformDevIoCtrl(TargetDeviceObject,
104 IOCTL_STORAGE_CHECK_VERIFY,
105 NULL,
106 0,
107 &MediaChangeCount,
108 sizeof(ULONG),
109 TRUE);
110
111 if (!NT_SUCCESS(Status)) return Status;
112
113 /* TODO: Check if data-track present in case of a CD drive */
114 /* TODO: IOCTL_DISK_GET_PARTITION_INFO_EX */
115
116 /* Remove unmounted VCBs */
117 FatiCleanVcbs(IrpContext);
118
119 /* Acquire the global exclusive lock */
120 FatAcquireExclusiveGlobal(IrpContext);
121
122 /* Create a new volume device object */
123 Status = IoCreateDevice(FatGlobalData.DriverObject,
124 sizeof(VOLUME_DEVICE_OBJECT) - sizeof(DEVICE_OBJECT),
125 NULL,
126 FILE_DEVICE_DISK_FILE_SYSTEM,
127 0,
128 FALSE,
129 (PDEVICE_OBJECT *)&VolumeDevice);
130
131 if (!NT_SUCCESS(Status))
132 {
133 /* Release the global lock */
134 FatReleaseGlobal(IrpContext);
135
136 return Status;
137 }
138
139 /* Match alignment requirements */
140 if (TargetDeviceObject->AlignmentRequirement > VolumeDevice->DeviceObject.AlignmentRequirement)
141 {
142 VolumeDevice->DeviceObject.AlignmentRequirement = TargetDeviceObject->AlignmentRequirement;
143 }
144
145 /* Init stack size */
146 VolumeDevice->DeviceObject.StackSize = TargetDeviceObject->StackSize + 1;
147
148 /* Get sector size */
149 Status = FatPerformDevIoCtrl(TargetDeviceObject,
150 IOCTL_DISK_GET_DRIVE_GEOMETRY,
151 NULL,
152 0,
153 &DiskGeometry,
154 sizeof(DISK_GEOMETRY),
155 TRUE);
156
157 if (!NT_SUCCESS(Status)) goto FatMountVolumeCleanup;
158
159 VolumeDevice->DeviceObject.SectorSize = (USHORT) DiskGeometry.BytesPerSector;
160
161 /* Signal we're done with initializing */
162 VolumeDevice->DeviceObject.Flags &= ~DO_DEVICE_INITIALIZING;
163
164 /* Save device object in a VPB */
165 Vpb->DeviceObject = (PDEVICE_OBJECT)VolumeDevice;
166
167 /* Initialize VCB for this volume */
168 Status = FatInitializeVcb(IrpContext, &VolumeDevice->Vcb, TargetDeviceObject, Vpb);
169 if (!NT_SUCCESS(Status)) goto FatMountVolumeCleanup;
170
171 Vcb = &VolumeDevice->Vcb;
172
173 /* Initialize FullFAT library */
174 Vcb->Ioman = FF_CreateIOMAN(NULL,
175 8192,
176 VolumeDevice->DeviceObject.SectorSize,
177 &Error);
178
179 ASSERT(Vcb->Ioman);
180
181 /* Register block device read/write functions */
182 Error = FF_RegisterBlkDevice(Vcb->Ioman,
183 VolumeDevice->DeviceObject.SectorSize,
184 (FF_WRITE_BLOCKS)FatWriteBlocks,
185 (FF_READ_BLOCKS)FatReadBlocks,
186 Vcb);
187
188 if (Error)
189 {
190 DPRINT1("Registering block device with FullFAT failed with error %d\n", Error);
191 FF_DestroyIOMAN(Vcb->Ioman);
192 goto FatMountVolumeCleanup;
193 }
194
195 /* Mount the volume using FullFAT */
196 if(FF_MountPartition(Vcb->Ioman, 0))
197 {
198 DPRINT1("Partition mounting failed\n");
199 FF_DestroyIOMAN(Vcb->Ioman);
200 goto FatMountVolumeCleanup;
201 }
202
203 /* Read the boot sector */
204 FatReadStreamFile(Vcb, 0, sizeof(PACKED_BOOT_SECTOR), &BootBcb, (PVOID)&BootSector);
205
206 /* Check if it's successful */
207 if (!BootBcb)
208 {
209 Status = STATUS_UNRECOGNIZED_VOLUME;
210 goto FatMountVolumeCleanup;
211 }
212
213 /* Unpack data */
214 FatiUnpackBpb(&Vcb->Bpb, &BootSector->PackedBpb);
215
216 /* Verify if sector size matches */
217 if (DiskGeometry.BytesPerSector != Vcb->Bpb.BytesPerSector)
218 {
219 DPRINT1("Disk geometry BPS %d and bios BPS %d don't match!\n",
220 DiskGeometry.BytesPerSector, Vcb->Bpb.BytesPerSector);
221
222 /* Fail */
223 Status = STATUS_UNRECOGNIZED_VOLUME;
224 goto FatMountVolumeCleanup;
225 }
226
227 /* If Sectors value is set, discard the LargeSectors value */
228 if (Vcb->Bpb.Sectors) Vcb->Bpb.LargeSectors = 0;
229
230 /* Copy serial number */
231 if (FatiBpbFat32(&BootSector->PackedBpb))
232 {
233 CopyUchar4(&Vpb->SerialNumber, ((PPACKED_BOOT_SECTOR_EX)BootSector)->Id);
234 }
235 else
236 {
237 /* This is FAT12/16 */
238 CopyUchar4(&Vpb->SerialNumber, BootSector->Id);
239 }
240
241 /* Unpin the BCB */
242 CcUnpinData(BootBcb);
243
244 /* Create root DCB for it */
245 FatCreateRootDcb(IrpContext, &VolumeDevice->Vcb);
246
247 /* Keep trace of media changes */
248 VolumeDevice->Vcb.MediaChangeCount = MediaChangeCount;
249
250 //ObDereferenceObject(TargetDeviceObject);
251
252 /* Release the global lock */
253 FatReleaseGlobal(IrpContext);
254
255 /* Notify about volume mount */
256 //FsRtlNotifyVolumeEvent(VolumeDevice->Vcb.StreamFileObject, FSRTL_VOLUME_MOUNT);
257
258 /* Return success */
259 return STATUS_SUCCESS;
260
261
262 FatMountVolumeCleanup:
263
264 /* Unwind the routine actions */
265 IoDeleteDevice((PDEVICE_OBJECT)VolumeDevice);
266
267 /* Release the global lock */
268 FatReleaseGlobal(IrpContext);
269
270 return Status;
271 }
272
273
274
275 NTSTATUS
276 NTAPI
277 FatiFileSystemControl(PFAT_IRP_CONTEXT IrpContext, PIRP Irp)
278 {
279 PIO_STACK_LOCATION IrpSp;
280 NTSTATUS Status;
281
282 /* Get current IRP stack location */
283 IrpSp = IoGetCurrentIrpStackLocation(Irp);
284
285 /* Dispatch depending on the minor function */
286 switch (IrpSp->MinorFunction)
287 {
288 case IRP_MN_USER_FS_REQUEST:
289 Status = FatUserFsCtrl(IrpContext, Irp);
290 break;
291
292 case IRP_MN_MOUNT_VOLUME:
293 Status = FatMountVolume(IrpContext,
294 IrpSp->Parameters.MountVolume.DeviceObject,
295 IrpSp->Parameters.MountVolume.Vpb,
296 IrpSp->DeviceObject);
297
298 FatCompleteRequest(IrpContext, Irp, Status);
299
300 break;
301
302 case IRP_MN_VERIFY_VOLUME:
303 Status = FatVerifyVolume(IrpContext, Irp);
304 break;
305
306 default:
307 DPRINT1("Unhandled FSCTL minor 0x%x\n", IrpSp->MinorFunction);
308 FatCompleteRequest(IrpContext, Irp, STATUS_INVALID_DEVICE_REQUEST);
309 Status = STATUS_INVALID_DEVICE_REQUEST;
310 }
311
312 return Status;
313 }
314
315
316 NTSTATUS
317 NTAPI
318 FatFileSystemControl(PDEVICE_OBJECT DeviceObject, PIRP Irp)
319 {
320 NTSTATUS Status = STATUS_SUCCESS;
321 PFAT_IRP_CONTEXT IrpContext;
322 BOOLEAN CanWait = TRUE;
323
324 DPRINT("FatFileSystemControl(DeviceObject %p, Irp %p)\n", DeviceObject, Irp);
325
326 /* Get CanWait flag */
327 if (IoGetCurrentIrpStackLocation(Irp)->FileObject)
328 {
329 CanWait = IoIsOperationSynchronous(Irp);
330 }
331
332 /* Enter FsRtl critical region */
333 FsRtlEnterFileSystem();
334
335 /* Build an irp context */
336 IrpContext = FatBuildIrpContext(Irp, CanWait);
337
338 /* Call internal function */
339 Status = FatiFileSystemControl(IrpContext, Irp);
340
341 /* Leave FsRtl critical region */
342 FsRtlExitFileSystem();
343
344 return Status;
345 }