xbox-kernel/private/ntos/gdfx/mountvol.c

465 lines
11 KiB
C
Raw Permalink Normal View History

2001-01-01 00:00:00 +01:00
/*++
Copyright (c) 2000-2001 Microsoft Corporation
Module Name:
mountvol.c
Abstract:
This module implements routines related to the mounting of a GDF volume.
--*/
#include "gdfx.h"
//
// GDF volume descriptor signature.
//
const UCHAR GdfxVolumeDescriptorSignature[] = GDF_VOLUME_DESCRIPTOR_SIGNATURE;
NTSTATUS
GdfxCreateVolumeDevice(
IN PDEVICE_OBJECT TargetDeviceObject,
IN PDISK_GEOMETRY DiskGeometry,
OUT PDEVICE_OBJECT *ReturnedVolumeDeviceObject
)
/*++
Routine Description:
This routine creates an instance of a volume device object.
Arguments:
TargetDeviceObject - Specifies the device object that the volume object
sends I/O requests to.
DiskGeometry - Specifies the disk geometry of the target device.
ReturnedVolumeDeviceObject - Specifies the buffer to receive the created
device object.
Return Value:
Status of operation.
--*/
{
NTSTATUS status;
PDEVICE_OBJECT VolumeDeviceObject;
PGDF_VOLUME_EXTENSION VolumeExtension;
PGDF_FCB VolumeFcb;
PGDF_FCB RootDirectoryFcb;
//
// Create the volume's device object.
//
status = IoCreateDevice(&GdfxDriverObject, sizeof(GDF_VOLUME_EXTENSION),
NULL, FILE_DEVICE_CD_ROM_FILE_SYSTEM, FALSE, &VolumeDeviceObject);
if (!NT_SUCCESS(status)) {
return status;
}
//
// Increase the volume's IRP stack size for requests that we pass down to
// the target device object.
//
VolumeDeviceObject->StackSize = (UCHAR)(VolumeDeviceObject->StackSize +
TargetDeviceObject->StackSize);
//
// Ensure that the alignment for this device matches the requirements of the
// target device.
//
if (VolumeDeviceObject->AlignmentRequirement < TargetDeviceObject->AlignmentRequirement) {
VolumeDeviceObject->AlignmentRequirement = TargetDeviceObject->AlignmentRequirement;
}
//
// If the target device object supports scatter gather I/O, then indicate
// that we can as well.
//
if (GdfxIsFlagSet(TargetDeviceObject->Flags, DO_SCATTER_GATHER_IO)) {
VolumeDeviceObject->Flags |= DO_SCATTER_GATHER_IO;
}
//
// Set the size of a sector for this device.
//
VolumeDeviceObject->SectorSize = GDF_CD_SECTOR_SIZE;
//
// Increment the reference count on the target device object since we'll be
// holding a pointer to it.
//
ObReferenceObject(TargetDeviceObject);
//
// Initialize the volume's device extension data.
//
VolumeExtension = (PGDF_VOLUME_EXTENSION)VolumeDeviceObject->DeviceExtension;
VolumeExtension->TargetDeviceObject = TargetDeviceObject;
VolumeExtension->SectorSize = GDF_CD_SECTOR_SIZE;
VolumeExtension->PartitionSectorCount = DiskGeometry->Cylinders.LowPart;
VolumeExtension->PartitionLength.QuadPart =
(ULONGLONG)DiskGeometry->Cylinders.LowPart << GDF_CD_SECTOR_SHIFT;
//
// Allocate the file control block for the physical volume.
//
VolumeFcb = ExAllocatePoolWithTag(sizeof(GDF_FCB), 'cVxG');
if (VolumeFcb == NULL) {
GdfxDeleteVolumeDevice(VolumeDeviceObject);
return STATUS_INSUFFICIENT_RESOURCES;
}
VolumeExtension->VolumeFcb = VolumeFcb;
//
// Initialize the file control block for the physical volume.
//
RtlZeroMemory(VolumeFcb, sizeof(GDF_FCB));
VolumeFcb->Flags = GDF_FCB_VOLUME;
VolumeFcb->ReferenceCount = 1;
InitializeListHead(&VolumeFcb->SiblingFcbLink);
//
// Allocate the file control block for the physical volume.
//
RootDirectoryFcb = ExAllocatePoolWithTag(sizeof(GDF_FCB), 'cRxG');
if (RootDirectoryFcb == NULL) {
GdfxDeleteVolumeDevice(VolumeDeviceObject);
return STATUS_INSUFFICIENT_RESOURCES;
}
VolumeExtension->RootDirectoryFcb = RootDirectoryFcb;
//
// Initialize the file control block for the root directory;
//
RtlZeroMemory(RootDirectoryFcb, sizeof(GDF_FCB));
RootDirectoryFcb->Flags = GDF_FCB_DIRECTORY | GDF_FCB_ROOT_DIRECTORY;
RootDirectoryFcb->ReferenceCount = 1;
InitializeListHead(&RootDirectoryFcb->SiblingFcbLink);
InitializeListHead(&RootDirectoryFcb->ChildFcbList);
//
// The device has finished initializing and is ready to accept requests.
//
VolumeDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
//
// Return the device object to the caller.
//
*ReturnedVolumeDeviceObject = VolumeDeviceObject;
return STATUS_SUCCESS;
}
VOID
GdfxDeleteVolumeDevice(
IN PDEVICE_OBJECT VolumeDeviceObject
)
/*++
Routine Description:
This routine deletes an instance of a volume device object.
Arguments:
VolumeDeviceObject - Specifies the volume device object to delete.
Return Value:
Status of operation.
--*/
{
PGDF_VOLUME_EXTENSION VolumeExtension;
VolumeExtension = (PGDF_VOLUME_EXTENSION)VolumeDeviceObject->DeviceExtension;
//
// There shouldn't be any open files for this volume.
//
ASSERT(VolumeExtension->FileObjectCount == 0);
//
// Delete any file control blocks created by the volume.
//
if (VolumeExtension->VolumeFcb != NULL) {
GdfxDereferenceFcb(VolumeExtension->VolumeFcb);
}
if (VolumeExtension->RootDirectoryFcb != NULL) {
GdfxDereferenceFcb(VolumeExtension->RootDirectoryFcb);
}
//
// Invalidate any file system cache buffers for this device.
//
FscInvalidateDevice(&VolumeExtension->CacheExtension);
//
// Release the reference on the target device object.
//
if (VolumeExtension->TargetDeviceObject != NULL) {
ObDereferenceObject(VolumeExtension->TargetDeviceObject);
}
//
// Delete the device object.
//
IoDeleteDevice(VolumeDeviceObject);
}
NTSTATUS
GdfxProcessVolumeDescriptor(
IN PDEVICE_OBJECT VolumeDeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
This routine reads the volume descriptor for the supplied volume device
object, validates its structure, and caches any interesting information in
the device extension.
Arguments:
VolumeDeviceObject - Specifies the volume device object to mount.
Irp - Specifies the packet that describes the I/O request.
Return Value:
Status of operation.
--*/
{
NTSTATUS status;
PGDF_VOLUME_EXTENSION VolumeExtension;
PVOID CacheBuffer;
PGDF_VOLUME_DESCRIPTOR VolumeDescriptor;
VolumeExtension = (PGDF_VOLUME_EXTENSION)VolumeDeviceObject->DeviceExtension;
//
// If the volume is too small to hold a volume descriptor sector, then bail
// out now.
//
if (VolumeExtension->PartitionSectorCount <= GDF_VOLUME_DESCRIPTOR_SECTOR) {
return STATUS_UNRECOGNIZED_VOLUME;
}
//
// Map the volume descriptor into the cache.
//
status = FscMapBuffer(&VolumeExtension->CacheExtension, Irp,
GdfxSectorToPhysicalByteOffset(GDF_VOLUME_DESCRIPTOR_SECTOR), FALSE,
&CacheBuffer);
if (!NT_SUCCESS(status)) {
return status;
}
VolumeDescriptor = (PGDF_VOLUME_DESCRIPTOR)CacheBuffer;
//
// Validate the signature of the sector.
//
if (RtlEqualMemory(VolumeDescriptor->HeadSignature,
GdfxVolumeDescriptorSignature, GDF_VOLUME_DESCRIPTOR_SIGNATURE_LENGTH) &&
RtlEqualMemory(VolumeDescriptor->TailSignature,
GdfxVolumeDescriptorSignature, GDF_VOLUME_DESCRIPTOR_SIGNATURE_LENGTH)) {
//
// Validate that the root directory is contained within the volume.
//
if ((VolumeDescriptor->RootDirectoryFirstSector < VolumeExtension->PartitionSectorCount) &&
((VolumeExtension->PartitionSectorCount - VolumeDescriptor->RootDirectoryFirstSector) >=
(GDF_CD_SECTOR_ALIGN_UP(VolumeDescriptor->RootDirectoryFileSize) >> GDF_CD_SECTOR_SHIFT))) {
//
// Save the starting sector and size of the root directory in the
// root directory file control block.
//
VolumeExtension->RootDirectoryFcb->FirstSector =
VolumeDescriptor->RootDirectoryFirstSector;
VolumeExtension->RootDirectoryFcb->FileSize =
VolumeDescriptor->RootDirectoryFileSize;
//
// Save the global time stamp for the volume's files.
//
VolumeExtension->TimeStamp = VolumeDescriptor->TimeStamp;
status = STATUS_SUCCESS;
} else {
status = STATUS_DISK_CORRUPT_ERROR;
}
} else {
status = STATUS_UNRECOGNIZED_VOLUME;
}
//
// Unmap the cache buffer.
//
FscUnmapBuffer(CacheBuffer);
return status;
}
NTSTATUS
GdfxMountVolume(
IN PDEVICE_OBJECT TargetDeviceObject
)
/*++
Routine Description:
This routine is called by the I/O manager to attempt to mount this file
system.
Arguments:
TargetDeviceObject - Specifies the device object to attempt to mount.
Return Value:
Status of operation.
--*/
{
NTSTATUS status;
PIRP Irp;
PDEVICE_OBJECT VolumeDeviceObject;
DISK_GEOMETRY DiskGeometry;
Irp = NULL;
VolumeDeviceObject = NULL;
GdfxAcquireGlobalMutexExclusive();
//
// Attempt to perform the DVD-X2 authentication sequence in order to switch
// to the Xbox partition. If this fails, continue using the standard
// partition.
//
IoSynchronousDeviceIoControlRequest(IOCTL_CDROM_AUTHENTICATION_SEQUENCE,
TargetDeviceObject, NULL, 0, NULL, 0, NULL, FALSE);
//
// Get the drive geometry from the device.
//
status = IoSynchronousDeviceIoControlRequest(IOCTL_CDROM_GET_DRIVE_GEOMETRY,
TargetDeviceObject, NULL, 0, &DiskGeometry, sizeof(DISK_GEOMETRY), NULL,
FALSE);
if (!NT_SUCCESS(status)) {
goto CleanupAndExit;
}
ASSERT(DiskGeometry.Cylinders.HighPart == 0);
ASSERT(DiskGeometry.TracksPerCylinder == 1);
ASSERT(DiskGeometry.SectorsPerTrack == 1);
ASSERT(DiskGeometry.BytesPerSector == GDF_CD_SECTOR_SIZE);
//
// Create an I/O request packet in order to submit requests to the target
// device.
//
Irp = IoAllocateIrp(TargetDeviceObject->StackSize);
if (Irp == NULL) {
status = STATUS_INSUFFICIENT_RESOURCES;
goto CleanupAndExit;
}
//
// Create the volume's device object.
//
status = GdfxCreateVolumeDevice(TargetDeviceObject, &DiskGeometry,
&VolumeDeviceObject);
if (!NT_SUCCESS(status)) {
goto CleanupAndExit;
}
//
// Process the volume descriptor for the volume.
//
status = GdfxProcessVolumeDescriptor(VolumeDeviceObject, Irp);
if (!NT_SUCCESS(status)) {
goto CleanupAndExit;
}
//
// Connect the volume device object to the target device object and return
// success.
//
TargetDeviceObject->MountedOrSelfDevice = VolumeDeviceObject;
VolumeDeviceObject = NULL;
status = STATUS_SUCCESS;
CleanupAndExit:
if (VolumeDeviceObject != NULL) {
GdfxDeleteVolumeDevice(VolumeDeviceObject);
}
if (Irp != NULL) {
IoFreeIrp(Irp);
}
GdfxReleaseGlobalMutex();
return status;
}