3 * Copyright (C) 2002 ReactOS Team
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.
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.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 * COPYRIGHT: See COPYING in the top level directory
22 * PROJECT: ReactOS kernel
23 * FILE: services/fs/cdfs/fsctl.c
24 * PURPOSE: CDROM (ISO 9660) filesystem driver
25 * PROGRAMMER: Art Yerkes
29 /* INCLUDES *****************************************************************/
31 #include <ddk/ntddk.h>
32 #include <ntos/minmax.h>
39 /* FUNCTIONS ****************************************************************/
42 int msf_to_lba (BYTE m, BYTE s, BYTE f)
44 return (((m * 60) + s) * 75 + f) - 150;
48 CdfsGetPVDData(PUCHAR Buffer,
64 /* Calculate the volume serial number */
66 for (i = 0; i < 2048; i += 4)
68 /* DON'T optimize this to ULONG!!! (breaks overflow) */
69 Serial.Part[0] += Buffer[i+3];
70 Serial.Part[1] += Buffer[i+2];
71 Serial.Part[2] += Buffer[i+1];
72 Serial.Part[3] += Buffer[i+0];
74 CdInfo->SerialNumber = Serial.Value;
76 /* Extract the volume label */
78 pw = CdInfo->VolumeLabel;
79 for (i = 0; i < MAXIMUM_VOLUME_LABEL_LENGTH && *pc != ' '; i++)
84 CdInfo->VolumeLabelLength = i;
86 CdInfo->VolumeSpaceSize = Pvd->VolumeSpaceSizeL;
87 CdInfo->RootStart = Pvd->RootDirRecord.ExtentLocationL;
88 CdInfo->RootSize = Pvd->RootDirRecord.DataLengthL;
90 DPRINT("VolumeSerial: %08lx\n", CdInfo->SerialNumber);
91 DPRINT("VolumeLabel: '%S'\n", CdInfo->VolumeLabel);
92 DPRINT("VolumeLabelLength: %lu\n", CdInfo->VolumeLabelLength);
93 DPRINT("VolumeSize: %lu\n", Pvd->VolumeSpaceSizeL);
94 DPRINT("RootStart: %lu\n", Pvd->RootDirRecord.ExtentLocationL);
95 DPRINT("RootSize: %lu\n", Pvd->RootDirRecord.DataLengthL);
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");
141 CdfsGetSVDData(PUCHAR Buffer,
145 ULONG JolietLevel = 0;
149 DPRINT("EscapeSequences: '%.32s'\n", Svd->EscapeSequences);
151 if (strncmp(Svd->EscapeSequences, "%/@", 3) == 0)
153 DPRINT("Joliet extension found (UCS-2 Level 1)\n");
156 else if (strncmp(Svd->EscapeSequences, "%/C", 3) == 0)
158 DPRINT("Joliet extension found (UCS-2 Level 2)\n");
161 else if (strncmp(Svd->EscapeSequences, "%/E", 3) == 0)
163 DPRINT("Joliet extension found (UCS-2 Level 3)\n");
167 CdInfo->JolietLevel = JolietLevel;
169 if (JolietLevel != 0)
171 CdInfo->RootStart = Svd->RootDirRecord.ExtentLocationL;
172 CdInfo->RootSize = Svd->RootDirRecord.DataLengthL;
174 DPRINT("RootStart: %lu\n", Svd->RootDirRecord.ExtentLocationL);
175 DPRINT("RootSize: %lu\n", Svd->RootDirRecord.DataLengthL);
181 CdfsGetVolumeData(PDEVICE_OBJECT DeviceObject,
196 TRACK_DATA TrackData;
200 DPRINT("CdfsGetVolumeData\n");
202 Buffer = ExAllocatePool(NonPagedPool,
206 return(STATUS_INSUFFICIENT_RESOURCES);
209 Status = CdfsDeviceIoControl(DeviceObject,
210 IOCTL_CDROM_GET_LAST_SESSION,
215 if (!NT_SUCCESS(Status))
221 DPRINT("FirstSession %d, LastSession %d, FirstTrack %d\n",
222 Toc.FirstSession, Toc.LastSession, Toc.TrackData.TrackNumber);
225 for (i = 0; i < 4; i++)
227 Offset = (Offset << 8) + Toc.TrackData.Address[i];
229 CdInfo->VolumeOffset = Offset;
231 DPRINT("Offset of first track in last session %d\n", Offset);
233 CdInfo->JolietLevel = 0;
234 VdHeader = (PVD_HEADER)Buffer;
237 for (Sector = CDFS_PRIMARY_DESCRIPTOR_LOCATION; Sector < 100 && Buffer[0] != 255; Sector++)
239 /* Read the Primary Volume Descriptor (PVD) */
240 Status = CdfsReadRawSectors(DeviceObject,
244 if (!NT_SUCCESS(Status))
250 if (Sector == CDFS_PRIMARY_DESCRIPTOR_LOCATION)
252 DPRINT("CD-identifier: [%.5s]\n", Buffer + 1);
254 if (Buffer[0] != 1 || Buffer[1] != 'C' || Buffer[2] != 'D' ||
255 Buffer[3] != '0' || Buffer[4] != '0' || Buffer[5] != '1')
258 return STATUS_UNRECOGNIZED_VOLUME;
262 switch (VdHeader->VdType)
265 DPRINT("BootVolumeDescriptor found!\n");
269 DPRINT("PrimaryVolumeDescriptor found!\n");
270 CdfsGetPVDData(Buffer, CdInfo);
274 DPRINT("SupplementaryVolumeDescriptor found!\n");
275 CdfsGetSVDData(Buffer, CdInfo);
279 DPRINT("VolumePartitionDescriptor found!\n");
283 DPRINT("VolumeDescriptorSetTerminator found!\n");
287 DPRINT1("Unknown volume descriptor type %u found!\n", VdHeader->VdType);
295 return(STATUS_SUCCESS);
299 CdfsMountVolume(PDEVICE_OBJECT DeviceObject,
302 PDEVICE_EXTENSION DeviceExt = NULL;
303 PDEVICE_OBJECT NewDeviceObject = NULL;
304 PDEVICE_OBJECT DeviceToMount;
305 PIO_STACK_LOCATION Stack;
312 DPRINT("CdfsMountVolume() called\n");
314 if (DeviceObject != CdfsGlobalData->DeviceObject)
316 Status = STATUS_INVALID_DEVICE_REQUEST;
320 Stack = IoGetCurrentIrpStackLocation(Irp);
321 DeviceToMount = Stack->Parameters.MountVolume.DeviceObject;
322 Vpb = Stack->Parameters.MountVolume.Vpb;
324 Status = CdfsGetVolumeData(DeviceToMount, &CdInfo);
325 if (!NT_SUCCESS(Status))
330 Status = IoCreateDevice(CdfsGlobalData->DriverObject,
331 sizeof(DEVICE_EXTENSION),
333 FILE_DEVICE_FILE_SYSTEM,
334 // FILE_DEVICE_DISK_FILE_SYSTEM,
338 if (!NT_SUCCESS(Status))
341 NewDeviceObject->Flags = NewDeviceObject->Flags | DO_DIRECT_IO;
342 DeviceExt = (PVOID)NewDeviceObject->DeviceExtension;
343 RtlZeroMemory(DeviceExt,
344 sizeof(DEVICE_EXTENSION));
346 Vpb->SerialNumber = CdInfo.SerialNumber;
347 Vpb->VolumeLabelLength = CdInfo.VolumeLabelLength;
348 RtlCopyMemory(Vpb->VolumeLabel, CdInfo.VolumeLabel, CdInfo.VolumeLabelLength * sizeof(WCHAR));
349 RtlCopyMemory(&DeviceExt->CdInfo, &CdInfo, sizeof(CDINFO));
351 NewDeviceObject->Vpb = DeviceToMount->Vpb;
353 DeviceExt->StorageDevice = DeviceToMount;
354 DeviceExt->StorageDevice->Vpb->DeviceObject = NewDeviceObject;
355 DeviceExt->StorageDevice->Vpb->RealDevice = DeviceExt->StorageDevice;
356 DeviceExt->StorageDevice->Vpb->Flags |= VPB_MOUNTED;
357 DeviceObject->StackSize = DeviceExt->StorageDevice->StackSize + 1;
358 DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
360 DeviceExt->StreamFileObject = IoCreateStreamFileObject(NULL,
361 DeviceExt->StorageDevice);
363 Fcb = CdfsCreateFCB(NULL);
366 Status = STATUS_INSUFFICIENT_RESOURCES;
370 Ccb = ExAllocatePoolWithTag(NonPagedPool,
375 Status = STATUS_INSUFFICIENT_RESOURCES;
381 DeviceExt->StreamFileObject->Flags = DeviceExt->StreamFileObject->Flags | FO_FCB_IS_VALID | FO_DIRECT_CACHE_PAGING_READ;
382 DeviceExt->StreamFileObject->FsContext = Fcb;
383 DeviceExt->StreamFileObject->FsContext2 = Ccb;
384 DeviceExt->StreamFileObject->SectionObjectPointers = &Fcb->SectionObjectPointers;
385 DeviceExt->StreamFileObject->PrivateCacheMap = NULL;
386 DeviceExt->StreamFileObject->Vpb = DeviceExt->Vpb;
387 Ccb->PtrFileObject = DeviceExt->StreamFileObject;
388 Fcb->FileObject = DeviceExt->StreamFileObject;
389 Fcb->DevExt = (PDEVICE_EXTENSION)DeviceExt->StorageDevice;
391 Fcb->Flags = FCB_IS_VOLUME_STREAM;
393 Fcb->RFCB.FileSize.QuadPart = (DeviceExt->CdInfo.VolumeSpaceSize + DeviceExt->CdInfo.VolumeOffset) * BLOCKSIZE;
394 Fcb->RFCB.ValidDataLength = Fcb->RFCB.AllocationSize = Fcb->RFCB.FileSize;
396 Fcb->Entry.ExtentLocationL = 0;
397 Fcb->Entry.DataLengthL = (DeviceExt->CdInfo.VolumeSpaceSize + DeviceExt->CdInfo.VolumeOffset) * BLOCKSIZE;
399 Status = CcRosInitializeFileCache(DeviceExt->StreamFileObject,
401 if (!NT_SUCCESS (Status))
403 DbgPrint("CcRosInitializeFileCache failed\n");
407 ExInitializeResourceLite(&DeviceExt->DirResource);
408 // ExInitializeResourceLite(&DeviceExt->FatResource);
410 KeInitializeSpinLock(&DeviceExt->FcbListLock);
411 InitializeListHead(&DeviceExt->FcbListHead);
413 Status = STATUS_SUCCESS;
416 if (!NT_SUCCESS(Status))
419 if (DeviceExt && DeviceExt->StreamFileObject)
420 ObDereferenceObject(DeviceExt->StreamFileObject);
426 IoDeleteDevice(NewDeviceObject);
429 DPRINT("CdfsMountVolume() done (Status: %lx)\n", Status);
436 CdfsVerifyVolume(PDEVICE_OBJECT DeviceObject,
439 PDEVICE_OBJECT DeviceToVerify;
440 PIO_STACK_LOCATION Stack;
444 DPRINT1("CdfsVerifyVolume() called\n");
447 if (DeviceObject != CdfsGlobalData->DeviceObject)
449 DPRINT1("DeviceObject != CdfsGlobalData->DeviceObject\n");
450 return(STATUS_INVALID_DEVICE_REQUEST);
454 Stack = IoGetCurrentIrpStackLocation(Irp);
455 DeviceToVerify = Stack->Parameters.VerifyVolume.DeviceObject;
457 DPRINT("Device object %p Device to verify %p\n", DeviceObject, DeviceToVerify);
459 CdInfo.SerialNumber = ~DeviceToVerify->Vpb->SerialNumber;
461 Status = CdfsGetVolumeData(DeviceToVerify, &CdInfo);
463 if (NT_SUCCESS(Status))
465 DPRINT("Current serial number %08lx Vpb serial number %08lx\n",
466 CdInfo.SerialNumber, DeviceToVerify->Vpb->SerialNumber);
468 if (CdInfo.SerialNumber != DeviceToVerify->Vpb->SerialNumber)
469 Status = STATUS_WRONG_VOLUME;
477 CdfsFileSystemControl(PDEVICE_OBJECT DeviceObject,
480 PIO_STACK_LOCATION Stack;
483 DPRINT("CdfsFileSystemControl() called\n");
485 Stack = IoGetCurrentIrpStackLocation(Irp);
487 switch (Stack->MinorFunction)
489 case IRP_MN_USER_FS_REQUEST:
490 DPRINT("CDFS: IRP_MN_USER_FS_REQUEST\n");
491 Status = STATUS_INVALID_DEVICE_REQUEST;
494 case IRP_MN_MOUNT_VOLUME:
495 DPRINT("CDFS: IRP_MN_MOUNT_VOLUME\n");
496 Status = CdfsMountVolume(DeviceObject, Irp);
499 case IRP_MN_VERIFY_VOLUME:
500 DPRINT1("CDFS: IRP_MN_VERIFY_VOLUME\n");
501 Status = CdfsVerifyVolume(DeviceObject, Irp);
505 DPRINT("CDFS FSC: MinorFunction %d\n", Stack->MinorFunction);
506 Status = STATUS_INVALID_DEVICE_REQUEST;
510 Irp->IoStatus.Status = Status;
511 Irp->IoStatus.Information = 0;
513 IoCompleteRequest(Irp, IO_NO_INCREMENT);