In the Corel Wine tree there is now the facility to dynamically map DOS
drives. That is, instead of having to manually define DOS drives in the
winerc, Wine will attempt to map mount points it finds on the system to
DOS drives. eg. if a floppy drive is mounted on /mnt/floppy, then Wine
will map DOS Drive A to /mnt/floppy.

I thought I would present the idea here to see if there is any interest
to make this a part of the winehq tree. Although the patch is rough in
some spots, the main idea is there. It allows dynamic drive mapping to
be turned on/off by adding a section to the winerc:

[DynamicDrives]
Enabled=y

If the section is not present, or if Enabled=n, then drives will be
mapped in the same manner as they are currently. When dynamic mapping is
enabled, the entries in the winerc will still be considered
authoritative. For now, we aren't concerned about unmounted devices, but
an option "UseFSTAB=y" can also be added to the winerc, which will cause
wine to also map any removable media it finds in fstab. This would
really only be useful on a system with an automounter, though.

-- 
Patrick Dubroy
x5361
[EMAIL PROTECTED]
Index: include/drive.h
===================================================================
RCS file: /home/wine/wine/include/drive.h,v
retrieving revision 1.6
diff -u -r1.6 drive.h
--- include/drive.h     2000/04/04 20:35:46     1.6
+++ include/drive.h     2000/08/01 16:45:11
@@ -28,6 +28,13 @@
 #define DRIVE_CASE_PRESERVING 0x0008  /* Drive fs is case preserving */
 #define DRIVE_FAIL_READ_ONLY  0x0010  /* Fail opening read-only files for writing */
 #define DRIVE_READ_VOL_INFO   0x0020  /* Try to read volume info from the device? */
+#define DRIVE_DYNAMIC         0x0040  /* Drive was mapped dynamically */
+
+/* flags for DRIVE_NextMntEnt function (dynamic drive mapping) */
+#define DRIVE_MNTENT_VIRTUAL   0x0001
+#define DRIVE_MNTENT_REMOVABLE 0x0002
+#define DRIVE_MNTENT_HD        0x0004
+#define DRIVE_MNTENT_NETWORK   0x0008
 
 extern int DRIVE_Init(void);
 extern int DRIVE_IsValid( int drive );
Index: files/drive.c
===================================================================
RCS file: /home/wine/wine/files/drive.c,v
retrieving revision 1.39
diff -u -r1.39 drive.c
--- files/drive.c       2000/07/25 20:59:59     1.39
+++ files/drive.c       2000/08/01 16:45:11
@@ -22,6 +22,11 @@
 #include <errno.h>
 #include <unistd.h>
 
+#include <stdio.h>
+#include <mntent.h>
+#include <regex.h>
+#include <time.h>
+
 #ifdef HAVE_SYS_PARAM_H
 # include <sys/param.h>
 #endif
@@ -104,6 +109,7 @@
 
 static HTASK16 DRIVE_LastTask = 0;
 
+static int DRIVE_EnableDynamic = 0;
 
 /***********************************************************************
  *           DRIVE_GetDriveType
@@ -140,6 +146,269 @@
 
 
 /***********************************************************************
+ *           DRIVE_CheckMntEnt
+ *
+ * Go through the list of DOS drives and look for a drive already
+ * mapped to the given mount point. If one is found, return the index
+ * of the drive (0 - 25) and if it is not found, return -1.
+ *
+ * FIXME: This is pretty slow and should probably be
+ * implemented with a b-search or something of the like.
+ *
+ */
+int DRIVE_CheckMntEnt(char* path)
+{
+    int i;
+    
+    for (i = 0; i < MAX_DOS_DRIVES; ++i) {
+       if (DOSDrives[i].root) {
+           if (strcmp(DOSDrives[i].root, path) == 0) {
+               TRACE("Drive %c matches mount point [%s]\n", 'A' + i, path);
+               return (i);
+           }
+       }
+    }
+
+    TRACE("Mount point [%s] is not mapped elsewhere.\n", path);
+    return (-1);
+}
+
+
+/***********************************************************************
+ *           DRIVE_NextMntEnt
+ *
+ * Return the next "useful" mount point from the file descriptor
+ * file pointed to by filep. "Useful" mount points are determined by
+ * the flags parameter, which is a logical combination of the following
+ * flags:
+ *
+ * DRIVE_MNTENT_VIRTUAL - include virtual file systems, such as /proc
+ * DRIVE_MNTENT_NETWORK - include network file systems (smbfs, nfs)
+ * DRIVE_MNTENT_HD - include hard drives
+ * DRIVE_MNTENT_REMOVABLE - include removable media
+ *
+ */
+DRIVETYPE DRIVE_NextMntEnt(FILE* filep, struct mntent* ret_entry, int flags)
+{
+    struct stat stat_buffer;
+    struct mntent* entry;
+    static regex_t pregs[3];
+
+    char* regexps[] = {
+       "^/dev/fd[0-7]",
+       "^/dev/s(cd|r)[0-9]$ | ^/dev/hd[a-z]$",
+       "^/dev/[s,h]d[a-z][0-9]$"
+    };
+
+    DRIVETYPE drive_type;
+    int i;
+
+    if (!filep) return (TYPE_INVALID);
+
+    while ((entry = getmntent(filep))) {
+       drive_type = TYPE_INVALID;
+
+       TRACE("Looking at [%s] mounted on [%s], mount type [%s]\n", 
+             entry->mnt_fsname, entry->mnt_dir, entry->mnt_type);
+
+       /* discard any entry with a fs type "ignore",
+        as well as any swap partitions */
+       if (strcmp(entry->mnt_type, "ignore") == 0 ||
+           strcmp(entry->mnt_type, "swap") == 0) continue;
+       
+       /* see if the fs type is virtual */
+       if (strcmp(entry->mnt_type, "proc") == 0 ||
+           strcmp(entry->mnt_type, "devpts") == 0) {
+
+           if (!(flags & DRIVE_MNTENT_VIRTUAL)) continue;
+           drive_type = TYPE_HD;
+       }
+
+       /* see if the fs type is network */
+       if (strcmp(entry->mnt_type, "nfs") == 0 ||
+           strcmp(entry->mnt_type, "smbfs") == 0) {
+
+           if (!(flags & DRIVE_MNTENT_NETWORK)) continue;
+           
+           drive_type = TYPE_NETWORK;
+       }
+       
+       /* make sure the mount point exists */
+       if (stat(entry->mnt_dir, &stat_buffer) != 0) {
+           TRACE("Could not stat [%s]\n", entry->mnt_dir);
+           continue;
+       }
+
+       /* if we haven't found the type yet, check the device name */
+       if (drive_type == TYPE_INVALID) {
+
+           /* FIXME: we should check here to see if the device name is
+              a symlink, eg. /dev/cdrom -> /dev/scd0. Otherwise we will
+              not properly determine its type */
+
+           for (i = 0; i <= 2; ++i) {
+               /* compile the regex if we haven't already */
+               if (!pregs[i].buffer) regcomp(&pregs[i], regexps[i], REG_EXTENDED);
+
+               /* break when we get a match */
+               if (regexec(&pregs[i], entry->mnt_fsname, 0, 0, 0) == 0) break;
+           }
+
+           /* FIXME (maybe): Right now anything that does not match will be assumed to
+              be TYPE_HD. Maybe we should assume TYPE_FLOPPY, because more than likely
+              it will be "removable" media (?) */
+           switch (i) {
+           case 0:
+               drive_type = TYPE_FLOPPY; break;
+           case 1: 
+               drive_type = TYPE_CDROM; break;
+           case 2:
+           default:
+               drive_type = TYPE_HD; break;
+           }
+           
+           if (!(flags & DRIVE_MNTENT_REMOVABLE)) {
+               /* discard any removable media */
+               if (drive_type == TYPE_FLOPPY ||
+                   drive_type == TYPE_CDROM) continue;
+           }
+
+           if (!(flags & DRIVE_MNTENT_HD)) {
+               /* discard hard drives */
+               if (drive_type == TYPE_HD) continue;
+           }
+       }
+
+       ret_entry->mnt_fsname = entry->mnt_fsname;
+       ret_entry->mnt_dir = entry->mnt_dir;
+       ret_entry->mnt_type = entry->mnt_type;
+       ret_entry->mnt_opts = entry->mnt_opts;
+       ret_entry->mnt_freq = entry->mnt_freq;
+       ret_entry->mnt_passno = entry->mnt_passno;
+
+       return (drive_type);
+    }
+    
+    return (TYPE_INVALID);
+}
+
+/***********************************************************************
+ *           DRIVE_FSDescMapDrives
+ *
+ * For a given file system descriptor file, map mount points to the
+ * master DOS drives list. The flags parameter is passed directly
+ * to DRIVE_NextMntEnt.
+ *
+ */
+void DRIVE_FSDescMapDrives(char* fs_desc_file, int flags)
+{
+    DRIVETYPE drive_type;
+    struct mntent entry;
+    int drive_index;
+    DOSDRIVE* drive;
+    int i;
+    FILE* filep = setmntent(fs_desc_file, "r");
+    struct stat stat_buffer;
+
+    while ((drive_type = DRIVE_NextMntEnt(filep, &entry, flags)) != TYPE_INVALID) {
+       drive_index = DRIVE_CheckMntEnt(entry.mnt_dir);
+
+       if (drive_index >= 0) {
+           /* the drive has been mapped somewhere already */
+
+           /* if it is disabled, enable it */
+           if (DOSDrives[drive_index].flags & DRIVE_DISABLED)
+               DOSDrives[drive_index].flags &= ~DRIVE_DISABLED;
+           continue; /* in either case, move to the next mntent */
+       }
+       else {
+           /* figure out where to map it */
+
+           /* try to map floppies to A and B first */
+           if (drive_type == TYPE_FLOPPY) {
+               if (!DOSDrives[0].root) drive_index = 0;
+               else if (!DOSDrives[1].root) drive_index = 1;
+           }
+
+           /* otherwise use the next available drive letter after C: */
+           if (drive_index < 0) {
+               for (drive_index = 2; drive_index < MAX_DOS_DRIVES; ++drive_index)
+                   if (!DOSDrives[drive_index].root) break;
+           }
+       }
+
+       TRACE("Mapping DOS Drive %c to [%s]\n", 'A' + drive_index, entry.mnt_dir);
+
+       if (stat(entry.mnt_dir, &stat_buffer) != 0) continue;
+
+       drive = &DOSDrives[drive_index];
+       
+       drive->root = HEAP_strdupA(SystemHeap, 0, entry.mnt_dir);
+       drive->dos_cwd = HEAP_strdupA(SystemHeap, 0, "");
+       drive->unix_cwd = HEAP_strdupA(SystemHeap, 0, "");
+       drive->device = HEAP_strdupA(SystemHeap, 0, "");
+
+       /* FIXME: this is a little ugly. Perhaps a DOS drive actually CAN have
+        * a label longer than 11 chars -- take network drives for instance.
+        * They can have a long label. Ideally we would do the same here.
+        */
+       strncpy(drive->label_conf, drive->root, 11);
+       /* pad the label with spaces if necessary */
+       for (i = strlen(drive->root); i < 11; ++i) {
+           drive->label_conf[i] = ' ';
+       }
+       drive->label_conf[11] = '\0';
+       
+       drive->serial_conf = (unsigned long)12345678;
+       drive->type = drive_type;
+       drive->flags = 
+           DRIVE_CASE_PRESERVING | 
+           DRIVE_DYNAMIC;
+       drive->dev = stat_buffer.st_dev;
+       drive->ino = stat_buffer.st_ino;
+
+       TRACE("Drive %c: path=%s type=%s label='%s' serial=%08lx "
+             "flags=%08x dev=%x ino=%x\n",
+             'A' + drive_index, drive->root, DRIVE_Types[drive->type],
+             drive->label_conf, drive->serial_conf, drive->flags,
+             (int)drive->dev, (int)drive->ino );
+    }
+
+    endmntent(filep);
+}
+
+/***********************************************************************
+ *           DRIVE_MapDOSDrives
+ *
+ * Parse mtab (and possibly fstab, depending on the value of the
+ * argument) and map mount points to DOS drives. By default, we will
+ * ignore virtual fs types in mtab (such as /proc and /dev/pts) and
+ * we will only look for removable media in fstab.
+ *
+ */
+int DRIVE_MapDOSDrives(int use_fstab)
+{
+    int drive_index;
+
+    /* disable all dynamic drives, they may not be mounted anymore */
+    for (drive_index = 0; drive_index < MAX_DOS_DRIVES; ++drive_index) {
+       if (DOSDrives[drive_index].flags & DRIVE_DYNAMIC)
+           DOSDrives[drive_index].flags |= DRIVE_DISABLED;
+    }
+
+    /* map mtab, excluding only virtual fs types */
+    DRIVE_FSDescMapDrives("/etc/mtab", 
+                         DRIVE_MNTENT_HD |
+                         DRIVE_MNTENT_REMOVABLE |
+                         DRIVE_MNTENT_NETWORK);
+    /* map fstab for only removable */
+    if (use_fstab) DRIVE_FSDescMapDrives("/etc/fstab", DRIVE_MNTENT_REMOVABLE);
+
+    return(1);
+}
+
+
+/***********************************************************************
  *           DRIVE_Init
  */
 int DRIVE_Init(void)
@@ -257,16 +526,63 @@
         }
     }
 
+    /* check to see if dynamic drive mapping is enabled */
+    PROFILE_GetWineIniString("DynamicDrives", "Enabled", "", buffer, sizeof(buffer));
+    if (buffer[0] == 'Y' || buffer[0] == 'y') {
+       TRACE("Dynamic Drive Mapping is enabled\n");
+       DRIVE_EnableDynamic = 1;
+    }
+
     return 1;
 }
 
 
 /***********************************************************************
+ *           DRIVE_FSDescChanged
+ */
+int DRIVE_FSDescChanged(char* fs_desc_file)
+{
+    static time_t last_map;
+    struct stat stat_buffer;
+    
+    stat(fs_desc_file, &stat_buffer);
+    if (stat_buffer.st_ctime > last_map) {
+       last_map = time(NULL);
+       return(1);
+    }
+    else
+       return(0);
+}
+
+
+/***********************************************************************
  *           DRIVE_IsValid
  */
 int DRIVE_IsValid( int drive )
 {
+    char buffer[80];
+    int need_remap = 0;
+    int use_fstab = 0;
+
     if ((drive < 0) || (drive >= MAX_DOS_DRIVES)) return 0;
+
+    if (DRIVE_EnableDynamic) {
+       /* see if we care about fstab */
+       PROFILE_GetWineIniString("DynamicDrives", "UseFSTAB", "", buffer, 
+sizeof(buffer));
+       if (buffer[0] == 'Y' || buffer[0] == 'y') use_fstab = 1;
+
+       /* check if mtab has been changed */
+       if (DRIVE_FSDescChanged("/etc/mtab")) {
+           need_remap = 1;
+       }
+       else if (use_fstab) {
+           /* check if fstab has been changed */
+           need_remap = DRIVE_FSDescChanged("/etc/fstab");
+       }
+       
+       if (need_remap) DRIVE_MapDOSDrives(use_fstab);
+    }
+
     return (DOSDrives[drive].root &&
             !(DOSDrives[drive].flags & DRIVE_DISABLED));
 }

Reply via email to