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