Fix merge r65567.
[reactos.git] / 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 CDROM_TOC Toc;
204
205 DPRINT("CdfsGetVolumeData\n");
206
207 Buffer = ExAllocatePool(NonPagedPool,
208 CDFS_BASIC_SECTOR);
209 if (Buffer == NULL)
210 return STATUS_INSUFFICIENT_RESOURCES;
211
212 Size = sizeof(Toc);
213 Status = CdfsDeviceIoControl(DeviceObject,
214 IOCTL_CDROM_READ_TOC,
215 NULL,
216 0,
217 &Toc,
218 &Size,
219 TRUE);
220 if (!NT_SUCCESS(Status))
221 {
222 ExFreePool(Buffer);
223 return Status;
224 }
225
226 DPRINT("FirstTrack %u, LastTrack %u, TrackNumber %u\n",
227 Toc.FirstTrack, Toc.LastTrack, Toc.TrackData[0].TrackNumber);
228
229 Offset = Toc.TrackData[0].Address[1] * 60 * 75;
230 Offset += Toc.TrackData[0].Address[2] * 75;
231 Offset += Toc.TrackData[0].Address[3];
232 if (Offset >= 150)
233 {
234 /* Remove MSF numbering offset of first frame */
235 /* FIXME: should be done only for real cdroms? */
236 Offset -= 150;
237 }
238 CdInfo->VolumeOffset = Offset;
239
240 DPRINT("Offset of first track in last session %u\n", Offset);
241
242 CdInfo->JolietLevel = 0;
243 VdHeader = (PVD_HEADER)Buffer;
244 Buffer[0] = 0;
245
246 for (Sector = CDFS_PRIMARY_DESCRIPTOR_LOCATION; Sector < 100 && Buffer[0] != 255; Sector++)
247 {
248 /* Read the Primary Volume Descriptor (PVD) */
249 Status = CdfsReadSectors (DeviceObject,
250 Sector + Offset,
251 1,
252 Buffer,
253 TRUE);
254 if (!NT_SUCCESS(Status))
255 {
256 ExFreePool(Buffer);
257 return Status;
258 }
259
260 if (Sector == CDFS_PRIMARY_DESCRIPTOR_LOCATION)
261 {
262 DPRINT("CD-identifier: [%.5s]\n", Buffer + 1);
263
264 if (Buffer[0] != 1 || Buffer[1] != 'C' || Buffer[2] != 'D' ||
265 Buffer[3] != '0' || Buffer[4] != '0' || Buffer[5] != '1')
266 {
267 ExFreePool(Buffer);
268 return STATUS_UNRECOGNIZED_VOLUME;
269 }
270 }
271
272 switch (VdHeader->VdType)
273 {
274 case 0:
275 DPRINT("BootVolumeDescriptor found!\n");
276 break;
277
278 case 1:
279 DPRINT("PrimaryVolumeDescriptor found!\n");
280 CdfsGetPVDData(Buffer, CdInfo);
281 break;
282
283 case 2:
284 DPRINT("SupplementaryVolumeDescriptor found!\n");
285 CdfsGetSVDData(Buffer, CdInfo);
286 break;
287
288 case 3:
289 DPRINT("VolumePartitionDescriptor found!\n");
290 break;
291
292 case 255:
293 DPRINT("VolumeDescriptorSetTerminator found!\n");
294 break;
295
296 default:
297 DPRINT1("Unknown volume descriptor type %u found!\n", VdHeader->VdType);
298 break;
299 }
300 }
301
302 ExFreePool(Buffer);
303
304 return(STATUS_SUCCESS);
305 }
306
307
308 static NTSTATUS
309 CdfsMountVolume(PDEVICE_OBJECT DeviceObject,
310 PIRP Irp)
311 {
312 PDEVICE_EXTENSION DeviceExt = NULL;
313 PDEVICE_OBJECT NewDeviceObject = NULL;
314 PDEVICE_OBJECT DeviceToMount;
315 PIO_STACK_LOCATION Stack;
316 PFCB Fcb = NULL;
317 PCCB Ccb = NULL;
318 PVPB Vpb;
319 NTSTATUS Status;
320 CDINFO CdInfo;
321
322 DPRINT("CdfsMountVolume() called\n");
323
324 if (DeviceObject != CdfsGlobalData->DeviceObject)
325 {
326 Status = STATUS_INVALID_DEVICE_REQUEST;
327 goto ByeBye;
328 }
329
330 Stack = IoGetCurrentIrpStackLocation(Irp);
331 DeviceToMount = Stack->Parameters.MountVolume.DeviceObject;
332 Vpb = Stack->Parameters.MountVolume.Vpb;
333
334 Status = CdfsGetVolumeData(DeviceToMount, &CdInfo);
335 if (!NT_SUCCESS(Status))
336 {
337 goto ByeBye;
338 }
339
340 Status = IoCreateDevice(CdfsGlobalData->DriverObject,
341 sizeof(DEVICE_EXTENSION),
342 NULL,
343 FILE_DEVICE_CD_ROM_FILE_SYSTEM,
344 DeviceToMount->Characteristics,
345 FALSE,
346 &NewDeviceObject);
347 if (!NT_SUCCESS(Status))
348 goto ByeBye;
349
350 NewDeviceObject->Flags = NewDeviceObject->Flags | DO_DIRECT_IO;
351 NewDeviceObject->Flags &= ~DO_VERIFY_VOLUME;
352 DeviceExt = (PVOID)NewDeviceObject->DeviceExtension;
353 RtlZeroMemory(DeviceExt,
354 sizeof(DEVICE_EXTENSION));
355
356 Vpb->SerialNumber = CdInfo.SerialNumber;
357 Vpb->VolumeLabelLength = CdInfo.VolumeLabelLength;
358 RtlCopyMemory(Vpb->VolumeLabel, CdInfo.VolumeLabel, CdInfo.VolumeLabelLength);
359 RtlCopyMemory(&DeviceExt->CdInfo, &CdInfo, sizeof(CDINFO));
360
361 NewDeviceObject->Vpb = DeviceToMount->Vpb;
362
363 DeviceExt->VolumeDevice = NewDeviceObject;
364 DeviceExt->StorageDevice = DeviceToMount;
365 DeviceExt->StorageDevice->Vpb->DeviceObject = NewDeviceObject;
366 DeviceExt->StorageDevice->Vpb->RealDevice = DeviceExt->StorageDevice;
367 DeviceExt->StorageDevice->Vpb->Flags |= VPB_MOUNTED;
368 NewDeviceObject->StackSize = DeviceExt->StorageDevice->StackSize + 1;
369 NewDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
370
371 /* Close (and cleanup) might be called from IoCreateStreamFileObject
372 * but we use this resource from CdfsCleanup, therefore it should be
373 * initialized no later than this. */
374 ExInitializeResourceLite(&DeviceExt->DirResource);
375
376 DeviceExt->StreamFileObject = IoCreateStreamFileObject(NULL,
377 DeviceExt->StorageDevice);
378
379 Fcb = CdfsCreateFCB(NULL);
380 if (Fcb == NULL)
381 {
382 Status = STATUS_INSUFFICIENT_RESOURCES;
383 goto ByeBye;
384 }
385
386 Ccb = ExAllocatePoolWithTag(NonPagedPool,
387 sizeof(CCB),
388 TAG_CCB);
389 if (Ccb == NULL)
390 {
391 Status = STATUS_INSUFFICIENT_RESOURCES;
392 goto ByeBye;
393 }
394 RtlZeroMemory(Ccb,
395 sizeof(CCB));
396
397 DeviceExt->StreamFileObject->ReadAccess = TRUE;
398 DeviceExt->StreamFileObject->WriteAccess = FALSE;
399 DeviceExt->StreamFileObject->DeleteAccess = FALSE;
400 DeviceExt->StreamFileObject->FsContext = Fcb;
401 DeviceExt->StreamFileObject->FsContext2 = Ccb;
402 DeviceExt->StreamFileObject->SectionObjectPointer = &Fcb->SectionObjectPointers;
403 DeviceExt->StreamFileObject->PrivateCacheMap = NULL;
404 DeviceExt->StreamFileObject->Vpb = DeviceExt->Vpb;
405 Ccb->PtrFileObject = DeviceExt->StreamFileObject;
406 Fcb->FileObject = DeviceExt->StreamFileObject;
407 Fcb->DevExt = (PDEVICE_EXTENSION)DeviceExt->StorageDevice;
408
409 Fcb->Flags = FCB_IS_VOLUME_STREAM;
410
411 Fcb->RFCB.FileSize.QuadPart = (DeviceExt->CdInfo.VolumeSpaceSize + DeviceExt->CdInfo.VolumeOffset) * BLOCKSIZE;
412 Fcb->RFCB.ValidDataLength = Fcb->RFCB.AllocationSize = Fcb->RFCB.FileSize;
413
414 Fcb->Entry.ExtentLocationL = 0;
415 Fcb->Entry.DataLengthL = (DeviceExt->CdInfo.VolumeSpaceSize + DeviceExt->CdInfo.VolumeOffset) * BLOCKSIZE;
416
417 CcInitializeCacheMap(DeviceExt->StreamFileObject,
418 (PCC_FILE_SIZES)(&Fcb->RFCB.AllocationSize),
419 TRUE,
420 &(CdfsGlobalData->CacheMgrCallbacks),
421 Fcb);
422
423 ExInitializeResourceLite(&DeviceExt->VcbResource);
424
425 KeInitializeSpinLock(&DeviceExt->FcbListLock);
426 InitializeListHead(&DeviceExt->FcbListHead);
427
428 FsRtlNotifyInitializeSync(&DeviceExt->NotifySync);
429 InitializeListHead(&DeviceExt->NotifyList);
430
431 Status = STATUS_SUCCESS;
432
433 ByeBye:
434 if (!NT_SUCCESS(Status))
435 {
436 /* Cleanup */
437 if (DeviceExt && DeviceExt->StreamFileObject)
438 ObDereferenceObject(DeviceExt->StreamFileObject);
439 if (Fcb)
440 ExFreePool(Fcb);
441 if (NewDeviceObject)
442 IoDeleteDevice(NewDeviceObject);
443 }
444
445 DPRINT("CdfsMountVolume() done (Status: %lx)\n", Status);
446
447 return(Status);
448 }
449
450
451 static NTSTATUS
452 CdfsVerifyVolume(PDEVICE_OBJECT DeviceObject,
453 PIRP Irp)
454 {
455 PDEVICE_EXTENSION DeviceExt;
456 PDEVICE_OBJECT DeviceToVerify;
457 PIO_STACK_LOCATION Stack;
458 NTSTATUS Status;
459 CDINFO CdInfo;
460
461 PLIST_ENTRY Entry;
462 PFCB Fcb;
463
464 DPRINT1 ("CdfsVerifyVolume() called\n");
465
466 #if 0
467 if (DeviceObject != CdfsGlobalData->DeviceObject)
468 {
469 DPRINT1("DeviceObject != CdfsGlobalData->DeviceObject\n");
470 return(STATUS_INVALID_DEVICE_REQUEST);
471 }
472 #endif
473
474 DeviceExt = DeviceObject->DeviceExtension;
475
476 Stack = IoGetCurrentIrpStackLocation (Irp);
477 DeviceToVerify = Stack->Parameters.VerifyVolume.DeviceObject;
478
479 FsRtlEnterFileSystem();
480 ExAcquireResourceExclusiveLite (&DeviceExt->VcbResource,
481 TRUE);
482
483 if (!(DeviceToVerify->Flags & DO_VERIFY_VOLUME))
484 {
485 DPRINT1 ("Volume has been verified!\n");
486 ExReleaseResourceLite (&DeviceExt->VcbResource);
487 FsRtlExitFileSystem();
488 return STATUS_SUCCESS;
489 }
490
491 DPRINT1 ("Device object %p Device to verify %p\n", DeviceObject, DeviceToVerify);
492
493 Status = CdfsGetVolumeData (DeviceToVerify,
494 &CdInfo);
495 if (NT_SUCCESS(Status) &&
496 CdInfo.SerialNumber == DeviceToVerify->Vpb->SerialNumber &&
497 CdInfo.VolumeLabelLength == DeviceToVerify->Vpb->VolumeLabelLength &&
498 !wcsncmp (CdInfo.VolumeLabel, DeviceToVerify->Vpb->VolumeLabel, CdInfo.VolumeLabelLength))
499 {
500 DPRINT1 ("Same volume!\n");
501
502 /* FIXME: Flush and purge metadata */
503
504 Status = STATUS_SUCCESS;
505 }
506 else
507 {
508 DPRINT1 ("Different volume!\n");
509
510 /* FIXME: force volume dismount */
511 Entry = DeviceExt->FcbListHead.Flink;
512 while (Entry != &DeviceExt->FcbListHead)
513 {
514 Fcb = (PFCB)CONTAINING_RECORD(Entry, FCB, FcbListEntry);
515 DPRINT1("OpenFile %wZ RefCount %ld\n", &Fcb->PathName, Fcb->RefCount);
516
517 Entry = Entry->Flink;
518 }
519
520 Status = STATUS_WRONG_VOLUME;
521 }
522
523 DeviceToVerify->Flags &= ~DO_VERIFY_VOLUME;
524
525 ExReleaseResourceLite (&DeviceExt->VcbResource);
526 FsRtlExitFileSystem();
527
528 return Status;
529 }
530
531
532 NTSTATUS NTAPI
533 CdfsSetCompression(
534 IN PDEVICE_OBJECT DeviceObject,
535 IN PIRP Irp)
536 {
537 PIO_STACK_LOCATION Stack;
538 USHORT CompressionState;
539
540 UNREFERENCED_PARAMETER(DeviceObject);
541
542 Stack = IoGetCurrentIrpStackLocation(Irp);
543
544 if (Stack->Parameters.DeviceIoControl.InputBufferLength != sizeof(CompressionState))
545 return STATUS_INVALID_DEVICE_REQUEST;
546
547 CompressionState = *(USHORT *)Irp->AssociatedIrp.SystemBuffer;
548 if (CompressionState != COMPRESSION_FORMAT_NONE)
549 return STATUS_INVALID_PARAMETER;
550
551 return STATUS_SUCCESS;
552 }
553
554
555 NTSTATUS NTAPI
556 CdfsFileSystemControl(PDEVICE_OBJECT DeviceObject,
557 PIRP Irp)
558 {
559 PIO_STACK_LOCATION Stack;
560 NTSTATUS Status;
561
562 DPRINT("CdfsFileSystemControl() called\n");
563
564 Stack = IoGetCurrentIrpStackLocation(Irp);
565
566 switch (Stack->MinorFunction)
567 {
568 case IRP_MN_KERNEL_CALL:
569 case IRP_MN_USER_FS_REQUEST:
570 switch (Stack->Parameters.DeviceIoControl.IoControlCode)
571 {
572 case FSCTL_SET_COMPRESSION:
573 DPRINT("CDFS: IRP_MN_USER_FS_REQUEST / FSCTL_SET_COMPRESSION\n");
574 Status = CdfsSetCompression(DeviceObject, Irp);
575 break;
576
577 default:
578 DPRINT1("CDFS: IRP_MN_USER_FS_REQUEST / Unknown IoControlCode 0x%x\n",
579 Stack->Parameters.DeviceIoControl.IoControlCode);
580 Status = STATUS_INVALID_DEVICE_REQUEST;
581 }
582 break;
583
584 case IRP_MN_MOUNT_VOLUME:
585 DPRINT("CDFS: IRP_MN_MOUNT_VOLUME\n");
586 Status = CdfsMountVolume(DeviceObject, Irp);
587 break;
588
589 case IRP_MN_VERIFY_VOLUME:
590 DPRINT1("CDFS: IRP_MN_VERIFY_VOLUME\n");
591 Status = CdfsVerifyVolume(DeviceObject, Irp);
592 break;
593
594 default:
595 DPRINT1("CDFS FSC: MinorFunction %u\n", Stack->MinorFunction);
596 Status = STATUS_INVALID_DEVICE_REQUEST;
597 break;
598 }
599
600 Irp->IoStatus.Status = Status;
601 Irp->IoStatus.Information = 0;
602
603 IoCompleteRequest(Irp, IO_NO_INCREMENT);
604
605 return(Status);
606 }
607
608 /* EOF */