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