+libcaptive/storage/cdrom.c
[captive.git] / src / libcaptive / storage / cdrom.c
diff --git a/src/libcaptive/storage/cdrom.c b/src/libcaptive/storage/cdrom.c
new file mode 100644 (file)
index 0000000..09adaa1
--- /dev/null
@@ -0,0 +1,152 @@
+/* $Id$
+ * "\Device\CdRom%d" storage emulation driver for reactos of libcaptive
+ * Copyright (C) 2002 Jan Kratochvil <project-captive@jankratochvil.net>
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; exactly version 2 of June 1991 is required
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+
+#include "config.h"
+
+#include "captive/storage.h"   /* self */
+#include "reactos/ddk/iotypes.h"       /* for DRIVER_OBJECT */
+#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"
+
+
+static DRIVER_OBJECT cdrom_DriverObject;
+static int Image_fd=-1;
+static off_t Image_size;       /* FIXME: lseek64() */
+
+
+
+/* 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)
+{
+static IO_SCSI_CAPABILITIES PortCapabilities;  /* it is const filled in DriverEntry() */
+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);
+
+       /* CdromClassCreateDeviceObject() sets:
+        *      DeviceObject->Flags|=DO_DIRECT_IO;
+        * but do we need it?
+        */
+       /* 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() */
+       PortCapabilities.Length=sizeof(PortCapabilities);
+       PortCapabilities.MaximumTransferLength=0x10000; /* 64KB */
+       g_assert((PortCapabilities.MaximumTransferLength%PAGE_SIZE)==0);
+       PortCapabilities.MaximumPhysicalPages=PortCapabilities.MaximumTransferLength/PAGE_SIZE;
+       PortCapabilities.SupportedAsynchronousEvents=0;
+       PortCapabilities.AlignmentMask=1;       /* no alignment required by us; speced as "integer multiple" */
+       PortCapabilities.TaggedQueuing=FALSE;
+       PortCapabilities.AdapterScansDown=FALSE;
+       PortCapabilities.AdapterUsesPio=TRUE;
+
+       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=&PortCapabilities;
+       DeviceExtension->StartingOffset.QuadPart=0;
+       DeviceExtension->PartitionLength.QuadPart=Image_size;
+       DeviceExtension->PortNumber=0;
+       DeviceExtension->PathId=0;
+       DeviceExtension->TargetId=0;
+       DeviceExtension->Lun=0;
+
+       /* FIXME: DriverObject->MajorFunction[IRP_MJ_CREATE] = ...; ... */
+
+       return STATUS_SUCCESS;
+}
+
+/**
+ * captive_cdrom_init:
+ * @image_pathname: Host OS file #utf8 pathname 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.
+ *
+ * captive 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(const gchar *image_pathname)
+{
+NTSTATUS err;
+
+       g_return_val_if_fail(image_pathname!=NULL,FALSE);
+
+       Image_fd=open(image_pathname,O_RDONLY
+#ifdef O_BINARY
+                       |O_BINARY
+#endif
+                       );      /* FIXME: lseek64() */
+       g_return_val_if_fail(Image_fd!=-1,FALSE);
+
+       Image_size=lseek(Image_fd,0,SEEK_END);  /* FIXME: lseek64() */
+       if (Image_size==(off_t)-1) {
+               g_assert_not_reached();
+               goto err_close;
+               }
+
+       err=DriverEntry(
+                       &cdrom_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:
+       close(Image_fd);
+       Image_fd=-1;
+/* err: */
+       g_return_val_if_reached(FALSE);
+}