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 ; 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 To: patches@winehq.com Subject: Read ISO 9660 label from /dev/cdrom Status: RO ChangeLog entry: * files/drive.c: Petter Reinholdtsen 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