[CDFS]
[reactos.git] / reactos / drivers / filesystems / cdfs / fsctl.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 2002, 2003 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19 /*
20 * COPYRIGHT: See COPYING in the top level directory
21 * PROJECT: ReactOS kernel
22 * FILE: drivers/filesystems/cdfs/fsctl.c
23 * PURPOSE: CDROM (ISO 9660) filesystem driver
24 * PROGRAMMER: Art Yerkes
25 * Eric Kohl
26 */
27
28 /* INCLUDES *****************************************************************/
29
30 #include "cdfs.h"
31
32 #define NDEBUG
33 #include <debug.h>
34
35 /* FUNCTIONS ****************************************************************/
36
37 static __inline
38 int msf_to_lba (UCHAR m, UCHAR s, UCHAR f)
39 {
40 return (((m * 60) + s) * 75 + f) - 150;
41 }
42
43
44 static
45 VOID
46 CdfsGetPVDData(
47 PUCHAR Buffer,
48 PCDINFO CdInfo)
49 {
50 PPVD Pvd;
51 USHORT i;
52 PUCHAR pc;
53 PWCHAR pw;
54
55 union
56 {
57 ULONG Value;
58 UCHAR Part[4];
59 } Serial;
60
61 Pvd = (PPVD)Buffer;
62
63 /* Calculate the volume serial number */
64 Serial.Value = 0;
65 for (i = 0; i < 2048; i += 4)
66 {
67 /* DON'T optimize this to ULONG!!! (breaks overflow) */
68 Serial.Part[3] += Buffer[i+0];
69 Serial.Part[2] += Buffer[i+1];
70 Serial.Part[1] += Buffer[i+2];
71 Serial.Part[0] += Buffer[i+3];
72 }
73 CdInfo->SerialNumber = Serial.Value;
74
75 /* Extract the volume label */
76 pc = Pvd->VolumeId;
77 pw = CdInfo->VolumeLabel;
78 for (i = 0; i < (MAXIMUM_VOLUME_LABEL_LENGTH / sizeof(WCHAR)) - 1; i++)
79 {
80 *pw++ = (WCHAR)*pc++;
81 }
82 *pw = 0;
83
84 /* Trim trailing spaces */
85 while (pw > CdInfo->VolumeLabel)
86 {
87 if (*--pw != ' ') break;
88
89 /* Remove the space */
90 *pw = '\0';
91
92 /* Decrease size */
93 i--;
94 }
95
96 CdInfo->VolumeLabelLength = i * sizeof(WCHAR);
97
98 CdInfo->VolumeSpaceSize = Pvd->VolumeSpaceSizeL;
99 CdInfo->RootStart = Pvd->RootDirRecord.ExtentLocationL;
100 CdInfo->RootSize = Pvd->RootDirRecord.DataLengthL;
101
102 DPRINT("VolumeSerial: %08lx\n", CdInfo->SerialNumber);
103 DPRINT("VolumeLabel: '%S'\n", CdInfo->VolumeLabel);
104 DPRINT("VolumeLabelLength: %lu\n", CdInfo->VolumeLabelLength);
105 DPRINT("VolumeSize: %lu\n", Pvd->VolumeSpaceSizeL);
106 DPRINT("RootStart: %lu\n", Pvd->RootDirRecord.ExtentLocationL);
107 DPRINT("RootSize: %lu\n", Pvd->RootDirRecord.DataLengthL);
108 DPRINT("PathTableSize: %lu\n", Pvd->PathTableSizeL);
109 DPRINT("PathTablePos: %lu\n", Pvd->LPathTablePos);
110 DPRINT("OptPathTablePos: %lu\n", Pvd->LOptPathTablePos);
111
112 #if 0
113 DbgPrint("******** PVD **********\n");
114 DbgPrint("VdType: %d\n", Pvd->VdType);
115 DbgPrint("StandardId: '%.*s'\n", 5, Pvd->StandardId);
116 DbgPrint("VdVersion: %d\n", Pvd->VdVersion);
117 DbgPrint("SystemId: '%.*s'\n", 32, Pvd->SystemId);
118 DbgPrint("VolumeId: '%.*s'\n", 32, Pvd->VolumeId);
119 DbgPrint("VolumeSpaceSizeL: %d (%x)\n", Pvd->VolumeSpaceSizeL, Pvd->VolumeSpaceSizeL);
120 DbgPrint("VolumeSpaceSizeM: %d (%x)\n", Pvd->VolumeSpaceSizeM, Pvd->VolumeSpaceSizeM);
121 DbgPrint("VolumeSetSize: %d (%x)\n", Pvd->VolumeSequenceNumber, Pvd->VolumeSequenceNumber);
122 DbgPrint("VolumeSequenceNumber: %d (%x)\n", Pvd->VolumeSequenceNumber, Pvd->VolumeSequenceNumber);
123 DbgPrint("LogicalBlockSize: %d (%x)\n", Pvd->LogicalBlockSize, Pvd->LogicalBlockSize);
124 DbgPrint("PathTableSizeL: %d (%x)\n", Pvd->PathTableSizeL, Pvd->PathTableSizeL);
125 DbgPrint("PathTableSizeM: %d (%x)\n", Pvd->PathTableSizeM, Pvd->PathTableSizeM);
126 DbgPrint("LPathTablePos: %d (%x)\n", Pvd->LPathTablePos, Pvd->LPathTablePos);
127 DbgPrint("LOptPathTablePos: %d (%x)\n", Pvd->LOptPathTablePos, Pvd->LOptPathTablePos);
128 DbgPrint("MPathTablePos: %d (%x)\n", Pvd->MPathTablePos, Pvd->MPathTablePos);
129 DbgPrint("MOptPathTablePos: %d (%x)\n", Pvd->MOptPathTablePos, Pvd->MOptPathTablePos);
130 DbgPrint("VolumeSetIdentifier: '%.*s'\n", 128, Pvd->VolumeSetIdentifier);
131 DbgPrint("PublisherIdentifier: '%.*s'\n", 128, Pvd->PublisherIdentifier);
132 DbgPrint("******** Root *********\n");
133 DbgPrint("RecordLength: %d\n", Pvd->RootDirRecord.RecordLength);
134 DbgPrint("ExtAttrRecordLength: %d\n", Pvd->RootDirRecord.ExtAttrRecordLength);
135 DbgPrint("ExtentLocationL: %d\n", Pvd->RootDirRecord.ExtentLocationL);
136 DbgPrint("DataLengthL: %d\n", Pvd->RootDirRecord.DataLengthL);
137 DbgPrint("Year: %d\n", Pvd->RootDirRecord.Year);
138 DbgPrint("Month: %d\n", Pvd->RootDirRecord.Month);
139 DbgPrint("Day: %d\n", Pvd->RootDirRecord.Day);
140 DbgPrint("Hour: %d\n", Pvd->RootDirRecord.Hour);
141 DbgPrint("Minute: %d\n", Pvd->RootDirRecord.Minute);
142 DbgPrint("Second: %d\n", Pvd->RootDirRecord.Second);
143 DbgPrint("TimeZone: %d\n", Pvd->RootDirRecord.TimeZone);
144 DbgPrint("FileFlags: %d\n", Pvd->RootDirRecord.FileFlags);
145 DbgPrint("FileUnitSize: %d\n", Pvd->RootDirRecord.FileUnitSize);
146 DbgPrint("InterleaveGapSize: %d\n", Pvd->RootDirRecord.InterleaveGapSize);
147 DbgPrint("VolumeSequenceNumber: %d\n", Pvd->RootDirRecord.VolumeSequenceNumber);
148 DbgPrint("FileIdLength: %d\n", Pvd->RootDirRecord.FileIdLength);
149 DbgPrint("FileId: '%.*s'\n", Pvd->RootDirRecord.FileId);
150 DbgPrint("***********************\n");
151 #endif
152 }
153
154
155 static
156 VOID
157 CdfsGetSVDData(
158 PUCHAR Buffer,
159 PCDINFO CdInfo)
160 {
161 PSVD Svd;
162 ULONG JolietLevel = 0;
163
164 Svd = (PSVD)Buffer;
165
166 DPRINT("EscapeSequences: '%.32s'\n", Svd->EscapeSequences);
167
168 if (strncmp((PCHAR)Svd->EscapeSequences, "%/@", 3) == 0)
169 {
170 DPRINT("Joliet extension found (UCS-2 Level 1)\n");
171 JolietLevel = 1;
172 }
173 else if (strncmp((PCHAR)Svd->EscapeSequences, "%/C", 3) == 0)
174 {
175 DPRINT("Joliet extension found (UCS-2 Level 2)\n");
176 JolietLevel = 2;
177 }
178 else if (strncmp((PCHAR)Svd->EscapeSequences, "%/E", 3) == 0)
179 {
180 DPRINT("Joliet extension found (UCS-2 Level 3)\n");
181 JolietLevel = 3;
182 }
183
184 CdInfo->JolietLevel = JolietLevel;
185
186 if (JolietLevel != 0)
187 {
188 CdInfo->RootStart = Svd->RootDirRecord.ExtentLocationL;
189 CdInfo->RootSize = Svd->RootDirRecord.DataLengthL;
190
191 DPRINT("RootStart: %lu\n", Svd->RootDirRecord.ExtentLocationL);
192 DPRINT("RootSize: %lu\n", Svd->RootDirRecord.DataLengthL);
193 }
194 }
195
196
197 static
198 NTSTATUS
199 CdfsGetVolumeData(
200 PDEVICE_OBJECT DeviceObject,
201 PCDINFO CdInfo)
202 {
203 PUCHAR Buffer;
204 NTSTATUS Status;
205 ULONG Sector;
206 PVD_HEADER VdHeader;
207 ULONG Size;
208 ULONG Offset;
209 CDROM_TOC Toc;
210
211 DPRINT("CdfsGetVolumeData\n");
212
213 Buffer = ExAllocatePoolWithTag(NonPagedPool, CDFS_BASIC_SECTOR, CDFS_TAG);
214 if (Buffer == NULL)
215 return STATUS_INSUFFICIENT_RESOURCES;
216
217 Size = sizeof(Toc);
218 Status = CdfsDeviceIoControl(DeviceObject,
219 IOCTL_CDROM_READ_TOC,
220 NULL,
221 0,
222 &Toc,
223 &Size,
224 TRUE);
225 if (!NT_SUCCESS(Status))
226 {
227 ExFreePoolWithTag(Buffer, CDFS_TAG);
228 return Status;
229 }
230
231 DPRINT("FirstTrack %u, LastTrack %u, TrackNumber %u\n",
232 Toc.FirstTrack, Toc.LastTrack, Toc.TrackData[0].TrackNumber);
233
234 Offset = Toc.TrackData[0].Address[1] * 60 * 75;
235 Offset += Toc.TrackData[0].Address[2] * 75;
236 Offset += Toc.TrackData[0].Address[3];
237 if (Offset >= 150)
238 {
239 /* Remove MSF numbering offset of first frame */
240 /* FIXME: should be done only for real cdroms? */
241 Offset -= 150;
242 }
243 CdInfo->VolumeOffset = Offset;
244
245 DPRINT("Offset of first track in last session %u\n", Offset);
246
247 CdInfo->JolietLevel = 0;
248 VdHeader = (PVD_HEADER)Buffer;
249 Buffer[0] = 0;
250
251 for (Sector = CDFS_PRIMARY_DESCRIPTOR_LOCATION; Sector < 100 && Buffer[0] != 255; Sector++)
252 {
253 /* Read the Primary Volume Descriptor (PVD) */
254 Status = CdfsReadSectors(DeviceObject,
255 Sector + Offset,
256 1,
257 Buffer,
258 TRUE);
259 if (!NT_SUCCESS(Status))
260 {
261 ExFreePoolWithTag(Buffer, CDFS_TAG);
262 return Status;
263 }
264
265 if (Sector == CDFS_PRIMARY_DESCRIPTOR_LOCATION)
266 {
267 DPRINT("CD-identifier: [%.5s]\n", Buffer + 1);
268
269 if (Buffer[0] != 1 || Buffer[1] != 'C' || Buffer[2] != 'D' ||
270 Buffer[3] != '0' || Buffer[4] != '0' || Buffer[5] != '1')
271 {
272 ExFreePoolWithTag(Buffer, CDFS_TAG);
273 return STATUS_UNRECOGNIZED_VOLUME;
274 }
275 }
276
277 switch (VdHeader->VdType)
278 {
279 case 0:
280 DPRINT("BootVolumeDescriptor found!\n");
281 break;
282
283 case 1:
284 DPRINT("PrimaryVolumeDescriptor found!\n");
285 CdfsGetPVDData(Buffer, CdInfo);
286 break;
287
288 case 2:
289 DPRINT("SupplementaryVolumeDescriptor found!\n");
290 CdfsGetSVDData(Buffer, CdInfo);
291 break;
292
293 case 3:
294 DPRINT("VolumePartitionDescriptor found!\n");
295 break;
296
297 case 255:
298 DPRINT("VolumeDescriptorSetTerminator found!\n");
299 break;
300
301 default:
302 DPRINT1("Unknown volume descriptor type %u found!\n", VdHeader->VdType);
303 break;
304 }
305 }
306
307 ExFreePoolWithTag(Buffer, CDFS_TAG);
308
309 return STATUS_SUCCESS;
310 }
311
312
313 static
314 NTSTATUS
315 CdfsMountVolume(
316 PDEVICE_OBJECT DeviceObject,
317 PIRP Irp)
318 {
319 PDEVICE_EXTENSION DeviceExt = NULL;
320 PDEVICE_OBJECT NewDeviceObject = NULL;
321 PDEVICE_OBJECT DeviceToMount;
322 PIO_STACK_LOCATION Stack;
323 PFCB Fcb = NULL;
324 PCCB Ccb = NULL;
325 PVPB Vpb;
326 NTSTATUS Status;
327 CDINFO CdInfo;
328
329 DPRINT("CdfsMountVolume() called\n");
330
331 if (DeviceObject != CdfsGlobalData->DeviceObject)
332 {
333 Status = STATUS_INVALID_DEVICE_REQUEST;
334 goto ByeBye;
335 }
336
337 Stack = IoGetCurrentIrpStackLocation(Irp);
338 DeviceToMount = Stack->Parameters.MountVolume.DeviceObject;
339 Vpb = Stack->Parameters.MountVolume.Vpb;
340
341 Status = CdfsGetVolumeData(DeviceToMount, &CdInfo);
342 if (!NT_SUCCESS(Status))
343 {
344 goto ByeBye;
345 }
346
347 Status = IoCreateDevice(CdfsGlobalData->DriverObject,
348 sizeof(DEVICE_EXTENSION),
349 NULL,
350 FILE_DEVICE_CD_ROM_FILE_SYSTEM,
351 DeviceToMount->Characteristics,
352 FALSE,
353 &NewDeviceObject);
354 if (!NT_SUCCESS(Status))
355 goto ByeBye;
356
357 NewDeviceObject->Flags = NewDeviceObject->Flags | DO_DIRECT_IO;
358 NewDeviceObject->Flags &= ~DO_VERIFY_VOLUME;
359 DeviceExt = (PVOID)NewDeviceObject->DeviceExtension;
360 RtlZeroMemory(DeviceExt,
361 sizeof(DEVICE_EXTENSION));
362
363 Vpb->SerialNumber = CdInfo.SerialNumber;
364 Vpb->VolumeLabelLength = CdInfo.VolumeLabelLength;
365 RtlCopyMemory(Vpb->VolumeLabel, CdInfo.VolumeLabel, CdInfo.VolumeLabelLength);
366 RtlCopyMemory(&DeviceExt->CdInfo, &CdInfo, sizeof(CDINFO));
367
368 NewDeviceObject->Vpb = DeviceToMount->Vpb;
369
370 DeviceExt->VolumeDevice = NewDeviceObject;
371 DeviceExt->StorageDevice = DeviceToMount;
372 DeviceExt->StorageDevice->Vpb->DeviceObject = NewDeviceObject;
373 DeviceExt->StorageDevice->Vpb->RealDevice = DeviceExt->StorageDevice;
374 DeviceExt->StorageDevice->Vpb->Flags |= VPB_MOUNTED;
375 NewDeviceObject->StackSize = DeviceExt->StorageDevice->StackSize + 1;
376 NewDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
377
378 /* Close (and cleanup) might be called from IoCreateStreamFileObject
379 * but we use this resource from CdfsCleanup, therefore it should be
380 * initialized no later than this. */
381 ExInitializeResourceLite(&DeviceExt->DirResource);
382
383 DeviceExt->StreamFileObject = IoCreateStreamFileObject(NULL,
384 DeviceExt->StorageDevice);
385
386 Fcb = CdfsCreateFCB(NULL);
387 if (Fcb == NULL)
388 {
389 Status = STATUS_INSUFFICIENT_RESOURCES;
390 goto ByeBye;
391 }
392
393 Ccb = ExAllocatePoolWithTag(NonPagedPool, sizeof(CCB), CDFS_CCB_TAG);
394 if (Ccb == NULL)
395 {
396 Status = STATUS_INSUFFICIENT_RESOURCES;
397 goto ByeBye;
398 }
399
400 RtlZeroMemory(Ccb,
401 sizeof(CCB));
402
403 DeviceExt->StreamFileObject->ReadAccess = TRUE;
404 DeviceExt->StreamFileObject->WriteAccess = FALSE;
405 DeviceExt->StreamFileObject->DeleteAccess = FALSE;
406 DeviceExt->StreamFileObject->FsContext = Fcb;
407 DeviceExt->StreamFileObject->FsContext2 = Ccb;
408 DeviceExt->StreamFileObject->SectionObjectPointer = &Fcb->SectionObjectPointers;
409 DeviceExt->StreamFileObject->PrivateCacheMap = NULL;
410 DeviceExt->StreamFileObject->Vpb = DeviceExt->Vpb;
411 Ccb->PtrFileObject = DeviceExt->StreamFileObject;
412 Fcb->FileObject = DeviceExt->StreamFileObject;
413 Fcb->DevExt = (PDEVICE_EXTENSION)DeviceExt->StorageDevice;
414
415 Fcb->Flags = FCB_IS_VOLUME_STREAM;
416
417 Fcb->RFCB.FileSize.QuadPart = (DeviceExt->CdInfo.VolumeSpaceSize + DeviceExt->CdInfo.VolumeOffset) * BLOCKSIZE;
418 Fcb->RFCB.ValidDataLength = Fcb->RFCB.AllocationSize = Fcb->RFCB.FileSize;
419
420 Fcb->Entry.ExtentLocationL = 0;
421 Fcb->Entry.DataLengthL = (DeviceExt->CdInfo.VolumeSpaceSize + DeviceExt->CdInfo.VolumeOffset) * BLOCKSIZE;
422
423 _SEH2_TRY
424 {
425 CcInitializeCacheMap(DeviceExt->StreamFileObject,
426 (PCC_FILE_SIZES)(&Fcb->RFCB.AllocationSize),
427 TRUE,
428 &(CdfsGlobalData->CacheMgrCallbacks),
429 Fcb);
430 }
431 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
432 {
433 Status = _SEH2_GetExceptionCode();
434 goto ByeBye;
435 }
436 _SEH2_END;
437
438 ExInitializeResourceLite(&DeviceExt->VcbResource);
439
440 KeInitializeSpinLock(&DeviceExt->FcbListLock);
441 InitializeListHead(&DeviceExt->FcbListHead);
442
443 FsRtlNotifyInitializeSync(&DeviceExt->NotifySync);
444 InitializeListHead(&DeviceExt->NotifyList);
445
446 Status = STATUS_SUCCESS;
447
448 ByeBye:
449 if (!NT_SUCCESS(Status))
450 {
451 /* Cleanup */
452 if (DeviceExt && DeviceExt->StreamFileObject)
453 ObDereferenceObject(DeviceExt->StreamFileObject);
454 if (Fcb)
455 ExFreePoolWithTag(Fcb, CDFS_NONPAGED_FCB_TAG);
456 if (NewDeviceObject)
457 IoDeleteDevice(NewDeviceObject);
458 }
459
460 DPRINT("CdfsMountVolume() done (Status: %lx)\n", Status);
461
462 return Status;
463 }
464
465
466 static
467 NTSTATUS
468 CdfsVerifyVolume(
469 PDEVICE_OBJECT DeviceObject,
470 PIRP Irp)
471 {
472 PDEVICE_EXTENSION DeviceExt;
473 PIO_STACK_LOCATION Stack;
474 NTSTATUS Status;
475 CDINFO CdInfo;
476 PLIST_ENTRY Entry;
477 PFCB Fcb;
478 PVPB VpbToVerify;
479
480 DPRINT("CdfsVerifyVolume() called\n");
481
482 DeviceExt = DeviceObject->DeviceExtension;
483
484 Stack = IoGetCurrentIrpStackLocation (Irp);
485 VpbToVerify = Stack->Parameters.VerifyVolume.Vpb;
486
487 FsRtlEnterFileSystem();
488 ExAcquireResourceExclusiveLite(&DeviceExt->VcbResource,
489 TRUE);
490
491 if (!(VpbToVerify->RealDevice->Flags & DO_VERIFY_VOLUME))
492 {
493 DPRINT1("Volume has been verified!\n");
494 ExReleaseResourceLite (&DeviceExt->VcbResource);
495 FsRtlExitFileSystem();
496 return STATUS_SUCCESS;
497 }
498
499 DPRINT1("Device object %p Device to verify %p\n", DeviceObject, VpbToVerify->RealDevice);
500
501 Status = CdfsGetVolumeData(VpbToVerify->RealDevice,
502 &CdInfo);
503 if (NT_SUCCESS(Status) &&
504 CdInfo.SerialNumber == VpbToVerify->SerialNumber &&
505 CdInfo.VolumeLabelLength == VpbToVerify->VolumeLabelLength &&
506 !wcsncmp(CdInfo.VolumeLabel, VpbToVerify->VolumeLabel, CdInfo.VolumeLabelLength))
507 {
508 DPRINT1("Same volume!\n");
509
510 /* FIXME: Flush and purge metadata */
511
512 Status = STATUS_SUCCESS;
513 }
514 else
515 {
516 DPRINT1("Different volume!\n");
517
518 /* FIXME: force volume dismount */
519 Entry = DeviceExt->FcbListHead.Flink;
520 while (Entry != &DeviceExt->FcbListHead)
521 {
522 Fcb = (PFCB)CONTAINING_RECORD(Entry, FCB, FcbListEntry);
523 DPRINT1("OpenFile %wZ RefCount %ld\n", &Fcb->PathName, Fcb->RefCount);
524
525 Entry = Entry->Flink;
526 }
527
528 Status = STATUS_WRONG_VOLUME;
529 }
530
531 VpbToVerify->RealDevice->Flags &= ~DO_VERIFY_VOLUME;
532
533 ExReleaseResourceLite(&DeviceExt->VcbResource);
534 FsRtlExitFileSystem();
535
536 return Status;
537 }
538
539
540 NTSTATUS
541 NTAPI
542 CdfsSetCompression(
543 IN PDEVICE_OBJECT DeviceObject,
544 IN PIRP Irp)
545 {
546 PIO_STACK_LOCATION Stack;
547 USHORT CompressionState;
548
549 UNREFERENCED_PARAMETER(DeviceObject);
550
551 Stack = IoGetCurrentIrpStackLocation(Irp);
552
553 if (Stack->Parameters.DeviceIoControl.InputBufferLength != sizeof(CompressionState))
554 return STATUS_INVALID_DEVICE_REQUEST;
555
556 CompressionState = *(USHORT *)Irp->AssociatedIrp.SystemBuffer;
557 if (CompressionState != COMPRESSION_FORMAT_NONE)
558 return STATUS_INVALID_PARAMETER;
559
560 return STATUS_SUCCESS;
561 }
562
563
564 NTSTATUS
565 NTAPI
566 CdfsFileSystemControl(
567 PCDFS_IRP_CONTEXT IrpContext)
568 {
569 PIRP Irp;
570 PDEVICE_OBJECT DeviceObject;
571 PIO_STACK_LOCATION Stack;
572 NTSTATUS Status;
573
574 DPRINT("CdfsFileSystemControl() called\n");
575
576 ASSERT(IrpContext);
577
578 DeviceObject = IrpContext->DeviceObject;
579 Irp = IrpContext->Irp;
580 Stack = IrpContext->Stack;
581
582 Irp->IoStatus.Information = 0;
583
584 switch (IrpContext->MinorFunction)
585 {
586 case IRP_MN_KERNEL_CALL:
587 case IRP_MN_USER_FS_REQUEST:
588 switch (Stack->Parameters.DeviceIoControl.IoControlCode)
589 {
590 case FSCTL_SET_COMPRESSION:
591 DPRINT("CDFS: IRP_MN_USER_FS_REQUEST / FSCTL_SET_COMPRESSION\n");
592 Status = CdfsSetCompression(DeviceObject, Irp);
593 break;
594
595 default:
596 DPRINT1("CDFS: IRP_MN_USER_FS_REQUEST / Unknown IoControlCode 0x%x\n",
597 Stack->Parameters.DeviceIoControl.IoControlCode);
598 Status = STATUS_INVALID_DEVICE_REQUEST;
599 }
600 break;
601
602 case IRP_MN_MOUNT_VOLUME:
603 DPRINT("CDFS: IRP_MN_MOUNT_VOLUME\n");
604 Status = CdfsMountVolume(DeviceObject, Irp);
605 break;
606
607 case IRP_MN_VERIFY_VOLUME:
608 DPRINT1("CDFS: IRP_MN_VERIFY_VOLUME\n");
609 Status = CdfsVerifyVolume(DeviceObject, Irp);
610 break;
611
612 default:
613 DPRINT1("CDFS FSC: MinorFunction %u\n", Stack->MinorFunction);
614 Status = STATUS_INVALID_DEVICE_REQUEST;
615 break;
616 }
617
618 return Status;
619 }
620
621 /* EOF */