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