#include "config.h"
#include "captive/storage.h" /* self */
-#include "reactos/ddk/iotypes.h" /* for DRIVER_OBJECT */
+#include "media.h"
#include <glib/gmessages.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include "reactos/ddk/ntddscsi.h" /* for IO_SCSI_CAPABILITIES */
-#include "reactos/ddk/class2.h" /* for PDEVICE_EXTENSION */
-#include "reactos/ddk/status.h" /* for STATUS_INVALID_PARAMETER */
-#include "reactos/ddk/iofuncs.h" /* for IoCreateDevice() */
#include "captive/unicode.h"
-#include "captive/macros.h"
-#include "reactos/ddk/mmfuncs.h" /* for MmGetSystemAddressForMdl() */
+#include "reactos/ddk/status.h" /* for NT_SUCCESS() */
+#include "captive/options.h"
-static DRIVER_OBJECT cdrom_DriverObject;
-static DISK_GEOMETRY cdrom_DiskGeometry;
-static DISK_GEOMETRY cdrom_DiskGeometry_check; /* for g_assert() checking against foreign modifications */
-static IO_SCSI_CAPABILITIES cdrom_PortCapabilities;
-static IO_SCSI_CAPABILITIES cdrom_PortCapabilities_check; /* for g_assert() checking against foreign modifications */
-static GIOChannel *Image_iochannel=NULL;
-static guint64 Image_size; /* FIXME: lseek64() */
-
-
-static gboolean validate_DeviceObject(DEVICE_OBJECT *DeviceObject)
-{
-DEVICE_EXTENSION *DeviceExtension;
-DISK_GEOMETRY *DiskGeometry;
-IO_SCSI_CAPABILITIES *PortCapabilities;
-
- g_return_val_if_fail(DeviceObject!=NULL,FALSE);
- g_return_val_if_fail(DeviceObject->DriverObject==&cdrom_DriverObject,FALSE);
-
- DeviceExtension=DeviceObject->DeviceExtension;
-
- DiskGeometry=DeviceExtension->DiskGeometry;
- g_return_val_if_fail(DiskGeometry==&cdrom_DiskGeometry,FALSE);
- g_return_val_if_fail(DiskGeometry->MediaType==cdrom_DiskGeometry_check.MediaType,FALSE);
- g_return_val_if_fail(DiskGeometry->TracksPerCylinder==cdrom_DiskGeometry_check.TracksPerCylinder,FALSE);
- g_return_val_if_fail(DiskGeometry->SectorsPerTrack==cdrom_DiskGeometry_check.SectorsPerTrack,FALSE);
- g_return_val_if_fail(DiskGeometry->BytesPerSector==cdrom_DiskGeometry_check.BytesPerSector,FALSE);
- g_return_val_if_fail(DiskGeometry->Cylinders.QuadPart==cdrom_DiskGeometry_check.Cylinders.QuadPart,FALSE);
- g_return_val_if_fail(DeviceExtension->PartitionLength.QuadPart==(gint64)Image_size,FALSE);
-
- PortCapabilities=DeviceExtension->PortCapabilities;
- g_return_val_if_fail(PortCapabilities==&cdrom_PortCapabilities,FALSE);
- g_return_val_if_fail(PortCapabilities->Length==cdrom_PortCapabilities_check.Length,FALSE);
- g_return_val_if_fail(PortCapabilities->MaximumTransferLength==cdrom_PortCapabilities_check.MaximumTransferLength,FALSE);
- g_return_val_if_fail(PortCapabilities->MaximumPhysicalPages==cdrom_PortCapabilities_check.MaximumPhysicalPages,FALSE);
- g_return_val_if_fail(PortCapabilities->SupportedAsynchronousEvents==cdrom_PortCapabilities_check.SupportedAsynchronousEvents,FALSE);
- g_return_val_if_fail(PortCapabilities->AlignmentMask==cdrom_PortCapabilities_check.AlignmentMask,FALSE);
- g_return_val_if_fail(PortCapabilities->TaggedQueuing==cdrom_PortCapabilities_check.TaggedQueuing,FALSE);
- g_return_val_if_fail(PortCapabilities->AdapterScansDown==cdrom_PortCapabilities_check.AdapterScansDown,FALSE);
- g_return_val_if_fail(PortCapabilities->AdapterUsesPio==cdrom_PortCapabilities_check.AdapterUsesPio,FALSE);
-
- return TRUE;
-}
-
-
-static NTSTATUS MajorFunction_Irp_finish(DEVICE_OBJECT *DeviceObject,IRP *Irp)
-{
-NTSTATUS r;
-
- g_return_val_if_fail(TRUE==validate_DeviceObject(DeviceObject),STATUS_INVALID_PARAMETER);
- g_return_val_if_fail(Irp!=NULL,STATUS_INVALID_PARAMETER);
-
- /* required for removable media only */
- if (!NT_SUCCESS(Irp->IoStatus.Status) && IoIsErrorUserInduced(Irp->IoStatus.Status)) {
- g_assert(Irp->Tail.Overlay.Thread!=NULL); /* FIXME: Error should be postponed to first !=NULL Irp later */
- IoSetHardErrorOrVerifyDevice(Irp,DeviceObject);
- Irp->IoStatus.Information=0; /* may got set during some processing before error occured */
- }
-
- /* IoCompleteRequest() will do 'IoFreeIrp(Irp);'!
- * 'IoStatus.Status' must be saved before its invocation!
- */
- r=Irp->IoStatus.Status;
- IoCompleteRequest(Irp,IO_NO_INCREMENT);
- return r;
-}
-
-
-/* FIXME: We should comply with PDRIVER_DISPATCH prototype but unfortunately
- * CAPTIVE_STDCALL prevents us to do so at least in RedHat gcc-3.2-4 (gcc bug?).
- */
-#define MajorFunction_DEVICE_CONTROL ((PDRIVER_DISPATCH)MajorFunction_DEVICE_CONTROL_func)
-static NTSTATUS CAPTIVE_STDCALL MajorFunction_DEVICE_CONTROL_func(IN DEVICE_OBJECT *DeviceObject,IN IRP *Irp)
-{
-IO_STACK_LOCATION *IrpStack;
-
- g_return_val_if_fail(TRUE==validate_DeviceObject(DeviceObject),STATUS_INVALID_PARAMETER);
- g_return_val_if_fail(Irp!=NULL,STATUS_INVALID_PARAMETER);
-
- Irp->IoStatus.Information=0; /* request-specific, may get overriden later */
- IrpStack=IoGetCurrentIrpStackLocation(Irp);
- g_assert(IrpStack->MajorFunction==IRP_MJ_DEVICE_CONTROL);
- g_assert(IrpStack->MinorFunction==0);
-
- switch (IrpStack->Parameters.DeviceIoControl.IoControlCode) {
-
- case IOCTL_CDROM_GET_LAST_SESSION:
- /* Nothing interesting to see, move along.
- * FIXME: This call is somehow multisession related - must we care?
- */
- /* PASSTHRU */
-
- case IOCTL_CDROM_READ_TOC: {
-CDROM_TOC *CdromToc;
-
- if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength<sizeof(CDROM_TOC)) {
- Irp->IoStatus.Status=STATUS_BUFFER_TOO_SMALL;
- Irp->IoStatus.Information=sizeof(CDROM_TOC);
- g_assert_not_reached();
- goto done;
- }
- CdromToc=(CDROM_TOC *)Irp->AssociatedIrp.SystemBuffer;
- CAPTIVE_MEMZERO(CdromToc);
- CdromToc->Length[0]=((sizeof(*CdromToc)-2)>>0U)&0xFFU; /* little-endian */
- CdromToc->Length[1]=((sizeof(*CdromToc)-2)>>8U)&0xFFU;
- CdromToc->FirstTrack=0; /* one track; TOC_LAST_TRACK does not count */
- CdromToc->LastTrack =0; /* one track; TOC_LAST_TRACK does not count */
- CdromToc->TrackData[0].Control=TOC_DATA_TRACK;
- CdromToc->TrackData[0].Adr=0; /* Q-subchannel subinfo */
- CdromToc->TrackData[0].TrackNumber=0;
- CdromToc->TrackData[0].Address[0]=0>>24U; /* LBA offset; big-endian */
- CdromToc->TrackData[0].Address[1]=0>>16U;
- CdromToc->TrackData[0].Address[2]=0>> 8U;
- CdromToc->TrackData[0].Address[3]=0>> 0U;
- CdromToc->TrackData[1].Control=0;
- CdromToc->TrackData[1].Adr=0; /* Q-subchannel subinfo */
- CdromToc->TrackData[1].TrackNumber=TOC_LAST_TRACK;
- /* FIXME: should we put the Image_size to TOC_LAST_TRACK? */
- CdromToc->TrackData[1].Address[0]=(Image_size/512)>>24U; /* LBA offset; big-endian */
- CdromToc->TrackData[1].Address[1]=(Image_size/512)>>16U;
- CdromToc->TrackData[1].Address[2]=(Image_size/512)>> 8U;
- CdromToc->TrackData[1].Address[3]=(Image_size/512)>> 0U;
-
- Irp->IoStatus.Information=sizeof(DISK_GEOMETRY);
- Irp->IoStatus.Status=STATUS_SUCCESS;
- } break;
-
- case IOCTL_CDROM_GET_DRIVE_GEOMETRY:
- if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength<sizeof(DISK_GEOMETRY)) {
- Irp->IoStatus.Status=STATUS_BUFFER_TOO_SMALL;
- Irp->IoStatus.Information=sizeof(DISK_GEOMETRY);
- g_assert_not_reached();
- goto done;
- }
- *(DISK_GEOMETRY *)Irp->AssociatedIrp.SystemBuffer=cdrom_DiskGeometry;
- Irp->IoStatus.Information=sizeof(DISK_GEOMETRY);
- Irp->IoStatus.Status=STATUS_SUCCESS;
- break;
-
- case IOCTL_CDROM_CHECK_VERIFY:
- if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength) {
- if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength<sizeof(ULONG)) {
- Irp->IoStatus.Status=STATUS_BUFFER_TOO_SMALL;
- Irp->IoStatus.Information=sizeof(ULONG);
- g_assert_not_reached();
- goto done;
- }
- *(ULONG *)Irp->AssociatedIrp.SystemBuffer=0; /* MediaChangeCount */
- Irp->IoStatus.Information=sizeof(ULONG);
- }
- else {
- Irp->IoStatus.Information=0;
- }
- Irp->IoStatus.Status=STATUS_SUCCESS;
- break;
-
- case IOCTL_SCSI_GET_CAPABILITIES:
- if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength<sizeof(IO_SCSI_CAPABILITIES)) {
- Irp->IoStatus.Status=STATUS_BUFFER_TOO_SMALL;
- Irp->IoStatus.Information=sizeof(IO_SCSI_CAPABILITIES);
- g_assert_not_reached();
- goto done;
- }
- *(IO_SCSI_CAPABILITIES *)Irp->AssociatedIrp.SystemBuffer=cdrom_PortCapabilities;
- Irp->IoStatus.Information=sizeof(IO_SCSI_CAPABILITIES);
- Irp->IoStatus.Status=STATUS_SUCCESS;
- break;
-
- default:
- Irp->IoStatus.Status=STATUS_INVALID_DEVICE_REQUEST;
- g_assert_not_reached();
- goto done;
- }
- /* PASSTHRU */
-
-done: /* 'err:' but we flow here even during success */
- return MajorFunction_Irp_finish(DeviceObject,Irp);
-}
-
-
-/* FIXME: We should comply with PDRIVER_DISPATCH prototype but unfortunately
- * CAPTIVE_STDCALL prevents us to do so at least in RedHat gcc-3.2-4 (gcc bug?).
- */
-#define MajorFunction_READ ((PDRIVER_DISPATCH)MajorFunction_READ_func)
-static NTSTATUS CAPTIVE_STDCALL MajorFunction_READ_func(IN DEVICE_OBJECT *DeviceObject,IN IRP *Irp)
-{
-IO_STACK_LOCATION *IrpStack;
-gsize bytesread;
-gpointer buffer=NULL;
-GIOStatus erriostatus;
-
- g_return_val_if_fail(TRUE==validate_DeviceObject(DeviceObject),STATUS_INVALID_PARAMETER);
- g_return_val_if_fail(Irp!=NULL,STATUS_INVALID_PARAMETER);
-
- Irp->IoStatus.Information=0; /* request-specific, may get overriden later */
- IrpStack=IoGetCurrentIrpStackLocation(Irp);
- g_assert(IrpStack->MajorFunction==IRP_MJ_READ);
- g_assert(IrpStack->MinorFunction==0);
-
- /* What is 'IrpStack->Parameters.Read.Key'? */
- g_assert(0==(IrpStack->Parameters.Read.Length%2048));
- g_assert(0==(IrpStack->Parameters.Read.ByteOffset.QuadPart%2048));
- g_assert(IrpStack->Parameters.Read.ByteOffset.QuadPart>=0);
-
- /* Autodetect 'buffer' as we are !DO_BUFFERED_IO && !DO_DIRECT_IO hybrid */
- if (Irp->UserBuffer) {
- g_assert(buffer==NULL);
- buffer=Irp->UserBuffer;
- }
- if (Irp->AssociatedIrp.SystemBuffer) {
- g_assert(buffer==NULL);
- buffer=Irp->AssociatedIrp.SystemBuffer;
- }
- if (Irp->MdlAddress) {
- g_assert(buffer==NULL);
- g_assert(IrpStack->Parameters.Read.Length<=MmGetMdlByteCount(Irp->MdlAddress));
- buffer=MmGetSystemAddressForMdl(Irp->MdlAddress);
- }
- g_assert(buffer!=NULL);
-
- erriostatus=g_io_channel_seek_position(Image_iochannel,
- IrpStack->Parameters.Read.ByteOffset.QuadPart, /* offset */
- G_SEEK_SET, /* type */
- NULL); /* error */
- g_assert(erriostatus==G_IO_STATUS_NORMAL);
-
- erriostatus=g_io_channel_read_chars(Image_iochannel,
- buffer, /* buf */
- IrpStack->Parameters.Read.Length, /* count */
- &bytesread, /* bytesread */
- NULL); /* error */
- g_assert(erriostatus==G_IO_STATUS_NORMAL);
- g_assert(bytesread==IrpStack->Parameters.Read.Length);
-
- Irp->IoStatus.Information=IrpStack->Parameters.Read.Length;
- Irp->IoStatus.Status=STATUS_SUCCESS;
-
- /* PASSTHRU */
-/* done: */ /* 'err:' but we flow here even during success */
- return MajorFunction_Irp_finish(DeviceObject,Irp);
-}
-
-
-/* similiar to drivers/storage/cdrom/cdrom.c/DriverEntry()->...
- * ...->CdromClassCreateDeviceObject()->
- * ->reactos/drivers/storage/class2/class2.c/ScsiClassCreateDeviceObject()
- * We should be driving a lower layer PortDevice but currently we
- * do not provide it, I hope W32 filesystems don't touch it.
- */
-static NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject,IN PUNICODE_STRING RegistryPath)
-{
-PDEVICE_OBJECT DeviceObject;
-PDEVICE_EXTENSION DeviceExtension;
-NTSTATUS err;
-
- g_return_val_if_fail(DriverObject!=NULL,STATUS_INVALID_PARAMETER);
- g_return_val_if_fail(RegistryPath!=NULL,STATUS_INVALID_PARAMETER);
-
- err=IoCreateDevice(
- DriverObject, /* DriverObject */
- sizeof(DEVICE_EXTENSION), /* DeviceExtensionSize; additional storage not used */
- captive_utf8_to_UnicodeString_alloca("\\Device\\CdRom0"), /* DeviceName */
- FILE_DEVICE_CD_ROM, /* DeviceType */
- FILE_REMOVABLE_MEDIA|FILE_READ_ONLY_DEVICE, /* DeviceCharacteristics */
- FALSE, /* Exclusive */
- &DeviceObject); /* DeviceObject */
- g_return_val_if_fail(NT_SUCCESS(err),FALSE);
-
- /* Currently we are !DO_BUFFERED_IO && !DO_DIRECT_IO and we must solve
- * being called with 'Irp->UserBuffer', 'Irp->AssociatedIrp.SystemBuffer' or 'Irp->MdlAddress'.
- */
- /* should be left from IoCreateDevice(DeviceCharacteristics) above: */
- g_assert(DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA);
- /* ignored: DeviceObject->StackSize */
- /* ignored: DeviceObject->AlignmentRequirement */
-
- /* from reactos/drivers/storage/scsiport/scsiport.c/ScsiPortCreatePortDevice() */
- cdrom_PortCapabilities.Length=sizeof(cdrom_PortCapabilities);
- cdrom_PortCapabilities.MaximumTransferLength=0x10000; /* 64KB */
- g_assert((cdrom_PortCapabilities.MaximumTransferLength%PAGE_SIZE)==0);
- cdrom_PortCapabilities.MaximumPhysicalPages=cdrom_PortCapabilities.MaximumTransferLength/PAGE_SIZE;
- cdrom_PortCapabilities.SupportedAsynchronousEvents=0;
- cdrom_PortCapabilities.AlignmentMask=1; /* no alignment required by us; speced as "integer multiple" */
- cdrom_PortCapabilities.TaggedQueuing=FALSE;
- cdrom_PortCapabilities.AdapterScansDown=FALSE;
- cdrom_PortCapabilities.AdapterUsesPio=TRUE;
- cdrom_PortCapabilities_check=cdrom_PortCapabilities; /* for g_assert() checking against foreign modifications */
-
- DeviceExtension=DeviceObject->DeviceExtension;
- DeviceExtension->MediaChangeCount=0;
- DeviceExtension->PhysicalDevice=DeviceObject; /* no real PhysicalDeviceObject */
- DeviceExtension->LockCount=0;
- DeviceExtension->DeviceNumber=0; /* corresponds to the # in "\\Device\\CdRom0" */
- /* ignored DeviceExtension->PortDeviceObject
- * as we are the final driver and we don't have any PortDeviceObject
- */
- DeviceExtension->PortCapabilities=&cdrom_PortCapabilities;
- DeviceExtension->StartingOffset.QuadPart=0;
- DeviceExtension->PartitionLength.QuadPart=Image_size;
- DeviceExtension->PortNumber=0;
- DeviceExtension->PathId=0;
- DeviceExtension->TargetId=0;
- DeviceExtension->Lun=0;
-
- cdrom_DiskGeometry.MediaType=RemovableMedia;
- cdrom_DiskGeometry.TracksPerCylinder=64;
- cdrom_DiskGeometry.SectorsPerTrack=32;
- cdrom_DiskGeometry.BytesPerSector=2048;
- cdrom_DiskGeometry.Cylinders.QuadPart=Image_size
- /cdrom_DiskGeometry.BytesPerSector
- /cdrom_DiskGeometry.SectorsPerTrack
- /cdrom_DiskGeometry.TracksPerCylinder;
- /* 'DeviceExtension->DiskGeometry' is NULL! */
- cdrom_DiskGeometry_check=cdrom_DiskGeometry; /* for g_assert() checking against foreign modifications */
- DeviceExtension->DiskGeometry=&cdrom_DiskGeometry;
-
- DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL]=MajorFunction_DEVICE_CONTROL;
- DriverObject->MajorFunction[IRP_MJ_READ ]=MajorFunction_READ;
-
- return STATUS_SUCCESS;
-}
-
/**
* captive_cdrom_init:
- * @image_channel: Host OS file of the disk image to provide.
- * %NULL value is forbidden.
*
* Creates system device "\Device\CdRom%d" providing readonly access
- * to the given @image_pathname as emulation of CD-ROM driver.
+ * to the given #captive_image_iochannel as emulation of CD-ROM driver.
*
- * captive currently supports just one drive and thus "\Device\CdRom0"
+ * libcaptive currently supports just one drive and thus "\Device\CdRom0"
* is always created. It is forbidden to call this function twice.
*
* Returns: %TRUE if the initialization was successful.
*/
-gboolean captive_cdrom_init(GIOChannel *image_iochannel)
+gboolean captive_cdrom_init(void)
{
+static struct captive_DriverObject cdrom_captive_DriverObject;
NTSTATUS err;
- g_return_val_if_fail(image_iochannel!=NULL,FALSE);
+ g_return_val_if_fail(captive_image_iochannel!=NULL,FALSE);
- Image_iochannel=image_iochannel;
- Image_size=captive_giochannel_size(Image_iochannel);
-
- err=DriverEntry(
- &cdrom_DriverObject, /* DriverEntry_DriverObject */
+ cdrom_captive_DriverObject.DiskGeometry.BytesPerSector=2048;
+ cdrom_captive_DriverObject.DiskGeometry.MediaType=RemovableMedia;
+ cdrom_captive_DriverObject.DeviceName_utf8="\\Device\\CdRom0";
+ cdrom_captive_DriverObject.DeviceType=FILE_DEVICE_CD_ROM;
+ cdrom_captive_DriverObject.DeviceCharacteristics=FILE_REMOVABLE_MEDIA|FILE_READ_ONLY_DEVICE;
+ err=captive_media_DriverEntry(
+ &cdrom_captive_DriverObject, /* DriverEntry_DriverObject */
captive_utf8_to_UnicodeString_alloca("\\captive\\storage\\cdrom")); /* DriverEntry_RegistryPath; ignored */
g_return_val_if_fail(NT_SUCCESS(err),FALSE);
return TRUE;
-
-/* err_close: */
- g_io_channel_close(Image_iochannel);
- Image_iochannel=NULL;
-/* err: */
- g_return_val_if_reached(FALSE);
}