9d90dc7d72af616138e1790ceb1ead455d33cae3
[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 CDROM_TOC Toc;
204
205 DPRINT("CdfsGetVolumeData\n");
206
207 Buffer = ExAllocatePoolWithTag(NonPagedPool, CDFS_BASIC_SECTOR, CDFS_TAG);
208 if (Buffer == NULL)
209 return STATUS_INSUFFICIENT_RESOURCES;
210
211 Size = sizeof(Toc);
212 Status = CdfsDeviceIoControl(DeviceObject,
213 IOCTL_CDROM_READ_TOC,
214 NULL,
215 0,
216 &Toc,
217 &Size,
218 TRUE);
219 if (!NT_SUCCESS(Status))
220 {
221 ExFreePoolWithTag(Buffer, CDFS_TAG);
222 return Status;
223 }
224
225 DPRINT("FirstTrack %u, LastTrack %u, TrackNumber %u\n",
226 Toc.FirstTrack, Toc.LastTrack, Toc.TrackData[0].TrackNumber);
227
228 Offset = Toc.TrackData[0].Address[1] * 60 * 75;
229 Offset += Toc.TrackData[0].Address[2] * 75;
230 Offset += Toc.TrackData[0].Address[3];
231 if (Offset >= 150)
232 {
233 /* Remove MSF numbering offset of first frame */
234 /* FIXME: should be done only for real cdroms? */
235 Offset -= 150;
236 }
237 CdInfo->VolumeOffset = Offset;
238
239 DPRINT("Offset of first track in last session %u\n", Offset);
240
241 CdInfo->JolietLevel = 0;
242 VdHeader = (PVD_HEADER)Buffer;
243 Buffer[0] = 0;
244
245 for (Sector = CDFS_PRIMARY_DESCRIPTOR_LOCATION; Sector < 100 && Buffer[0] != 255; Sector++)
246 {
247 /* Read the Primary Volume Descriptor (PVD) */
248 Status = CdfsReadSectors (DeviceObject,
249 Sector + Offset,
250 1,
251 Buffer,
252 TRUE);
253 if (!NT_SUCCESS(Status))
254 {
255 ExFreePoolWithTag(Buffer, CDFS_TAG);
256 return Status;
257 }
258
259 if (Sector == CDFS_PRIMARY_DESCRIPTOR_LOCATION)
260 {
261 DPRINT("CD-identifier: [%.5s]\n", Buffer + 1);
262
263 if (Buffer[0] != 1 || Buffer[1] != 'C' || Buffer[2] != 'D' ||
264 Buffer[3] != '0' || Buffer[4] != '0' || Buffer[5] != '1')
265 {
266 ExFreePoolWithTag(Buffer, CDFS_TAG);
267 return STATUS_UNRECOGNIZED_VOLUME;
268 }
269 }
270
271 switch (VdHeader->VdType)
272 {
273 case 0:
274 DPRINT("BootVolumeDescriptor found!\n");
275 break;
276
277 case 1:
278 DPRINT("PrimaryVolumeDescriptor found!\n");
279 CdfsGetPVDData(Buffer, CdInfo);
280 break;
281
282 case 2:
283 DPRINT("SupplementaryVolumeDescriptor found!\n");
284 CdfsGetSVDData(Buffer, CdInfo);
285 break;
286
287 case 3:
288 DPRINT("VolumePartitionDescriptor found!\n");
289 break;
290
291 case 255:
292 DPRINT("VolumeDescriptorSetTerminator found!\n");
293 break;
294
295 default:
296 DPRINT1("Unknown volume descriptor type %u found!\n", VdHeader->VdType);
297 break;
298 }
299 }
300
301 ExFreePoolWithTag(Buffer, CDFS_TAG);
302
303 return(STATUS_SUCCESS);
304 }
305
306
307 static NTSTATUS
308 CdfsMountVolume(PDEVICE_OBJECT DeviceObject,
309 PIRP Irp)
310 {
311 PDEVICE_EXTENSION DeviceExt = NULL;
312 PDEVICE_OBJECT NewDeviceObject = NULL;
313 PDEVICE_OBJECT DeviceToMount;
314 PIO_STACK_LOCATION Stack;
315 PFCB Fcb = NULL;
316 PCCB Ccb = NULL;
317 PVPB Vpb;
318 NTSTATUS Status;
319 CDINFO CdInfo;
320
321 DPRINT("CdfsMountVolume() called\n");
322
323 if (DeviceObject != CdfsGlobalData->DeviceObject)
324 {
325 Status = STATUS_INVALID_DEVICE_REQUEST;
326 goto ByeBye;
327 }
328
329 Stack = IoGetCurrentIrpStackLocation(Irp);
330 DeviceToMount = Stack->Parameters.MountVolume.DeviceObject;
331 Vpb = Stack->Parameters.MountVolume.Vpb;
332
333 Status = CdfsGetVolumeData(DeviceToMount, &CdInfo);
334 if (!NT_SUCCESS(Status))
335 {
336 goto ByeBye;
337 }
338
339 Status = IoCreateDevice(CdfsGlobalData->DriverObject,
340 sizeof(DEVICE_EXTENSION),
341 NULL,
342 FILE_DEVICE_CD_ROM_FILE_SYSTEM,
343 DeviceToMount->Characteristics,
344 FALSE,
345 &NewDeviceObject);
346 if (!NT_SUCCESS(Status))
347 goto ByeBye;
348
349 NewDeviceObject->Flags = NewDeviceObject->Flags | DO_DIRECT_IO;
350 NewDeviceObject->Flags &= ~DO_VERIFY_VOLUME;
351 DeviceExt = (PVOID)NewDeviceObject->DeviceExtension;
352 RtlZeroMemory(DeviceExt,
353 sizeof(DEVICE_EXTENSION));
354
355 Vpb->SerialNumber = CdInfo.SerialNumber;
356 Vpb->VolumeLabelLength = CdInfo.VolumeLabelLength;
357 RtlCopyMemory(Vpb->VolumeLabel, CdInfo.VolumeLabel, CdInfo.VolumeLabelLength);
358 RtlCopyMemory(&DeviceExt->CdInfo, &CdInfo, sizeof(CDINFO));
359
360 NewDeviceObject->Vpb = DeviceToMount->Vpb;
361
362 DeviceExt->VolumeDevice = NewDeviceObject;
363 DeviceExt->StorageDevice = DeviceToMount;
364 DeviceExt->StorageDevice->Vpb->DeviceObject = NewDeviceObject;
365 DeviceExt->StorageDevice->Vpb->RealDevice = DeviceExt->StorageDevice;
366 DeviceExt->StorageDevice->Vpb->Flags |= VPB_MOUNTED;
367 NewDeviceObject->StackSize = DeviceExt->StorageDevice->StackSize + 1;
368 NewDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
369
370 /* Close (and cleanup) might be called from IoCreateStreamFileObject
371 * but we use this resource from CdfsCleanup, therefore it should be
372 * initialized no later than this. */
373 ExInitializeResourceLite(&DeviceExt->DirResource);
374
375 DeviceExt->StreamFileObject = IoCreateStreamFileObject(NULL,
376 DeviceExt->StorageDevice);
377
378 Fcb = CdfsCreateFCB(NULL);
379 if (Fcb == NULL)
380 {
381 Status = STATUS_INSUFFICIENT_RESOURCES;
382 goto ByeBye;
383 }
384
385 Ccb = ExAllocatePoolWithTag(NonPagedPool, sizeof(CCB), CDFS_CCB_TAG);
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 _SEH2_TRY
415 {
416 CcInitializeCacheMap(DeviceExt->StreamFileObject,
417 (PCC_FILE_SIZES)(&Fcb->RFCB.AllocationSize),
418 TRUE,
419 &(CdfsGlobalData->CacheMgrCallbacks),
420 Fcb);
421 }
422 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
423 {
424 Status = _SEH2_GetExceptionCode();
425 goto ByeBye;
426 }
427 _SEH2_END;
428
429 ExInitializeResourceLite(&DeviceExt->VcbResource);
430
431 KeInitializeSpinLock(&DeviceExt->FcbListLock);
432 InitializeListHead(&DeviceExt->FcbListHead);
433
434 FsRtlNotifyInitializeSync(&DeviceExt->NotifySync);
435 InitializeListHead(&DeviceExt->NotifyList);
436
437 Status = STATUS_SUCCESS;
438
439 ByeBye:
440 if (!NT_SUCCESS(Status))
441 {
442 /* Cleanup */
443 if (DeviceExt && DeviceExt->StreamFileObject)
444 ObDereferenceObject(DeviceExt->StreamFileObject);
445 if (Fcb)
446 ExFreePoolWithTag(Fcb, CDFS_NONPAGED_FCB_TAG);
447 if (NewDeviceObject)
448 IoDeleteDevice(NewDeviceObject);
449 }
450
451 DPRINT("CdfsMountVolume() done (Status: %lx)\n", Status);
452
453 return(Status);
454 }
455
456
457 static NTSTATUS
458 CdfsVerifyVolume(PDEVICE_OBJECT DeviceObject,
459 PIRP Irp)
460 {
461 PDEVICE_EXTENSION DeviceExt;
462 PIO_STACK_LOCATION Stack;
463 NTSTATUS Status;
464 CDINFO CdInfo;
465 PLIST_ENTRY Entry;
466 PFCB Fcb;
467 PVPB VpbToVerify;
468
469 DPRINT1 ("CdfsVerifyVolume() called\n");
470
471 DeviceExt = DeviceObject->DeviceExtension;
472
473 Stack = IoGetCurrentIrpStackLocation (Irp);
474 VpbToVerify = Stack->Parameters.VerifyVolume.Vpb;
475
476 FsRtlEnterFileSystem();
477 ExAcquireResourceExclusiveLite (&DeviceExt->VcbResource,
478 TRUE);
479
480 if (!(VpbToVerify->RealDevice->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, VpbToVerify->RealDevice);
489
490 Status = CdfsGetVolumeData(VpbToVerify->RealDevice,
491 &CdInfo);
492 if (NT_SUCCESS(Status) &&
493 CdInfo.SerialNumber == VpbToVerify->SerialNumber &&
494 CdInfo.VolumeLabelLength == VpbToVerify->VolumeLabelLength &&
495 !wcsncmp(CdInfo.VolumeLabel, VpbToVerify->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 VpbToVerify->RealDevice->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(
554 PCDFS_IRP_CONTEXT IrpContext)
555 {
556 PIRP Irp;
557 PDEVICE_OBJECT DeviceObject;
558 PIO_STACK_LOCATION Stack;
559 NTSTATUS Status;
560
561 DPRINT("CdfsFileSystemControl() called\n");
562
563 ASSERT(IrpContext);
564
565 DeviceObject = IrpContext->DeviceObject;
566 Irp = IrpContext->Irp;
567 Stack = IrpContext->Stack;
568
569 Irp->IoStatus.Information = 0;
570
571 switch (IrpContext->MinorFunction)
572 {
573 case IRP_MN_KERNEL_CALL:
574 case IRP_MN_USER_FS_REQUEST:
575 switch (Stack->Parameters.DeviceIoControl.IoControlCode)
576 {
577 case FSCTL_SET_COMPRESSION:
578 DPRINT("CDFS: IRP_MN_USER_FS_REQUEST / FSCTL_SET_COMPRESSION\n");
579 Status = CdfsSetCompression(DeviceObject, Irp);
580 break;
581
582 default:
583 DPRINT1("CDFS: IRP_MN_USER_FS_REQUEST / Unknown IoControlCode 0x%x\n",
584 Stack->Parameters.DeviceIoControl.IoControlCode);
585 Status = STATUS_INVALID_DEVICE_REQUEST;
586 }
587 break;
588
589 case IRP_MN_MOUNT_VOLUME:
590 DPRINT("CDFS: IRP_MN_MOUNT_VOLUME\n");
591 Status = CdfsMountVolume(DeviceObject, Irp);
592 break;
593
594 case IRP_MN_VERIFY_VOLUME:
595 DPRINT1("CDFS: IRP_MN_VERIFY_VOLUME\n");
596 Status = CdfsVerifyVolume(DeviceObject, Irp);
597 break;
598
599 default:
600 DPRINT1("CDFS FSC: MinorFunction %u\n", Stack->MinorFunction);
601 Status = STATUS_INVALID_DEVICE_REQUEST;
602 break;
603 }
604
605 return(Status);
606 }
607
608 /* EOF */