From pere@minerva.cc.uit.no Mon Oct 26 18:22:40 1998
Received: from minerva.cc.uit.no (pere@nb38.stud.cs.UiT.No [129.242.13.48])
	by yuubin.games.no (8.8.7/8.8.7) with ESMTP id TAA27004
	for <pere@games.no>; Mon, 26 Oct 1998 19:22:38 +0100
Received: (from pere@localhost)
	by minerva.cc.uit.no (8.8.7/8.8.7) id TAA09696;
	Mon, 26 Oct 1998 19:22:40 +0100
Date: Mon, 26 Oct 1998 19:22:40 +0100
Message-Id: <199810261822.TAA09696@minerva.cc.uit.no>
From: Petter Reinholdtsen <pere@localhost.localdomain>
To: patches@winehq.com
Subject: Read ISO 9660 label from /dev/cdrom
Status: RO


ChangeLog entry:

  * files/drive.c: Petter Reinholdtsen <pere@td.org.uit.no>
  Changed DRIVE_GetLabel to extract ISO 9660 label from CDROMs.  It
  requires read access to /dev/cdrom and 'Device=/dev/cdrom' and
  'Type=cdrom' to be set in the [Drive X] section of .winerc.

Index: files/drive.c
===================================================================
RCS file: /home/wine/wine/files/drive.c,v
retrieving revision 1.4
diff -u -r1.4 drive.c
--- drive.c	1998/10/20 14:25:50	1.4
+++ drive.c	1998/10/26 18:18:58
@@ -41,13 +41,19 @@
 #include "task.h"
 #include "debug.h"
 
+#define ISO_9660_LABEL_LEN 32 /* 32  */
+#define FAT_LABEL_LEN      11 /* 8+3 */
+
+/* Which should we use? */
+#define LABEL_LEN          ISO_9660_LABEL_LEN
+
 typedef struct
 {
     char     *root;      /* root dir in Unix format without trailing / */
     char     *dos_cwd;   /* cwd in DOS format without leading or trailing \ */
     char     *unix_cwd;  /* cwd in Unix format without leading or trailing / */
     char     *device;    /* raw device path */
-    char      label[12]; /* drive label */
+    char      label[LABEL_LEN+1]; /* drive label + terminating 0 */
     DWORD     serial;    /* drive serial number */
     DRIVETYPE type;      /* drive type */
     UINT32    flags;     /* drive flags */
@@ -168,12 +174,13 @@
             drive->ino      = drive_stat_buffer.st_ino;
 
             /* Get the drive label */
-            PROFILE_GetWineIniString( name, "Label", name, drive->label, 12 );
-            if ((len = strlen(drive->label)) < 11)
+            PROFILE_GetWineIniString( name, "Label", name, drive->label,
+				      LABEL_LEN+1 );
+            if ((len = strlen(drive->label)) < LABEL_LEN)
             {
                 /* Pad label with spaces */
-                memset( drive->label + len, ' ', 11 - len );
-                drive->label[12] = '\0';
+                memset( drive->label + len, ' ', LABEL_LEN - len );
+                drive->label[LABEL_LEN+1] = '\0';
             }
 
             /* Get the serial number */
@@ -329,9 +336,11 @@
     *next = 0;
 
     if (rootdrive != -1)
+      {
         TRACE(dosfs, "%s -> drive %c:, root='%s', name='%s'\n",
                        buffer, 'A' + rootdrive,
                        DOSDrives[rootdrive].root, *path );
+      }
     return rootdrive;
 }
 
@@ -387,13 +396,100 @@
     return DOSDrives[drive].unix_cwd;
 }
 
+/***********************************************************************
+ *           DRIVE_iso9660label [internal]
+ *
+ * Extract the 32 bytes label from ISO 9660 CDROM filesystem.
+ *
+ * Requires read access to the raw device (/dev/cdrom).
+ *
+ * RETURNS
+ *   Current label in static char *, only valid until next call to
+ *   this method, or NULL if wrong filesystem or something else goes
+ *   wrong.
+ *
+ * BUGS
+ *   When the Unix kernel provides filesystem label using ioctl, this
+ *   method should be changed to use that instead.
+ *
+ *   I know nothing about the filesystem layout, and has just been
+ *   quessing about where to find the label based on other source
+ *   (Linux, etc).  All this should be verified by someone who knows
+ *   what they are doing.  It is tested, and seem to work.
+ */
+
+static char *
+DRIVE_iso9660label(char *device)
+{
+#define LABEL_POS 0x8028-0x8001
+#define READ_LEN LABEL_POS+ISO_9660_LABEL_LEN+1
+    const char magic[] = "CD001";
+    static char buffer[READ_LEN];
+    FILE *dev = NULL;
+
+    if (NULL == device)
+        return NULL;
+
+    /*
+     * Check if ISO 9660 magic 'CD001' is at absolute sector 16.  I hope
+     * pos 0x8001 corresponds to the correct position.  If this is
+     * correct file system, return the 32 bytes giving the label from pos
+     * 0x8028.
+     */
+    dev = fopen(device, "rb");
+    if (NULL != dev
+        && 0 == fseek(dev, 0x8001, SEEK_SET)
+        && READ_LEN == fread(buffer, 1, READ_LEN, dev)
+        && 0 == memcmp(buffer, magic, sizeof(magic)-1)
+	)
+    {
+        fclose(dev);
+        buffer[READ_LEN] = 0;
+        return buffer+LABEL_POS;
+    }
+
+    /* Something wrong, close and return. */
+    if (NULL != dev)
+        fclose(dev);
+    return NULL;
+#undef LABEL_POS
+#undef READ_LEN
+}
 
 /***********************************************************************
  *           DRIVE_GetLabel
+ * BUGS
+ *  There is no known way to extract the filesystem label using ioctl
+ *  or any other decent method.  I therefore choose this crude way, using
+ *  FS depentend code to read the label from the device file, to extract
+ *  the label and fall back to the preset one.
  */
 const char * DRIVE_GetLabel( int drive )
 {
+    char *device = NULL;
+
+    TRACE(dosfs, "(%c:)\n", 'A' + drive);
+
     if (!DRIVE_IsValid( drive )) return NULL;
+
+    device = DOSDrives[drive].device;
+
+    if (NULL != device && TYPE_CDROM == DRIVE_GetType(drive))
+    {
+        char *label = DRIVE_iso9660label(device);
+        if (NULL != label)
+        {
+            return label;
+        } else {
+	  static int first_time = 1;
+	  if (first_time) /* It is probably enough to print this once */
+            fprintf(stderr,
+                    "Unable to fetch ISO9660 label from %s.  Is it readable? (one-time-warning)\n",
+	            device);
+	  first_time = 0;
+        }
+    }
+
     return DOSDrives[drive].label;
 }
 
@@ -551,7 +647,7 @@
     new->root = HEAP_strdupA( SystemHeap, 0, old->root );
     new->dos_cwd = HEAP_strdupA( SystemHeap, 0, old->dos_cwd );
     new->unix_cwd = HEAP_strdupA( SystemHeap, 0, old->unix_cwd );
-    memcpy ( new->label, old->label, 12 );
+    memcpy ( new->label, old->label, LABEL_LEN+1 );
     new->serial = old->serial;
     new->type = old->type;
     new->flags = old->flags;
-- 
##>  Petter Reinholdtsen  <##  |  pere@td.org.uit.no

