winecfg: implement drive detection

Mike Hearn mike at navi.cx
Sat Sep 25 11:47:03 CDT 2004


Not quite finished yet, it needs to be startable from the command line.
But that's like a 5 line patch, anybody can do it. I'm gone for the next
week or so while I settle back into university life - if you're reading
this and have five minutes of hacking time why not add it in? Should be
obvious from the code.

thanks -mike

ChangeLog:
Implement drive detection


-------------- next part --------------
--- programs/winecfg.working/drive.c	2004-09-23 23:10:46.000000000 +0100
+++ programs/winecfg/drive.c	2004-09-24 18:19:18.000000000 +0100
@@ -50,6 +50,40 @@
     return (toupper(letter) - 'A');
 }
 
+/* This function produces a mask for each drive letter that isn't
+ * currently used. Each bit of the long result represents a letter,
+ * with A being the least significant bit, and Z being the most
+ * significant.
+ *
+ * To calculate this, we loop over each letter, and see if we can get
+ * a drive entry for it. If so, we set the appropriate bit. At the
+ * end, we flip each bit, to give the desired result.
+ *
+ * The letter parameter is always marked as being available. This is
+ * so the edit dialog can display the currently used drive letter
+ * alongside the available ones.
+ */
+long drive_available_mask(char letter)
+{
+  long result = 0;
+  int i;
+
+  WINE_TRACE("\n");
+
+
+  for(i = 0; i < 26; i++)
+  {
+      if (!drives[i].in_use) continue;
+      result |= (1 << (toupper(drives[i].letter) - 'A'));
+  }
+
+  result = ~result;
+  if (letter) result |= DRIVE_MASK_BIT(letter);
+
+  WINE_TRACE("finished drive letter loop with %lx\n", result);
+  return result;
+}
+
 BOOL add_drive(char letter, char *targetpath, char *label, char *serial, uint type)
 {
     int driveIndex = letter_to_index(letter);
--- programs/winecfg.working/drivedetect.c	2004-09-23 23:10:46.000000000 +0100
+++ programs/winecfg/drivedetect.c	2004-09-24 19:44:19.000000000 +0100
@@ -20,13 +20,233 @@
  */
 
 #include <wine/debug.h>
+#include <wine/library.h>
+
 #include "winecfg.h"
 
+#include <stdio.h>
+#include <mntent.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include <sys/stat.h>
+
 #include <winbase.h>
 
 WINE_DEFAULT_DEBUG_CHANNEL(winecfg);
 
+BOOL gui_mode = TRUE;
+static long working_mask = 0;
+
+static char *ignored_fstypes[] = {
+    "devpts",
+    "tmpfs",
+    "proc",
+    "sysfs",
+    "swap",
+    "usbdevfs",
+    "rpc_pipefs",
+    NULL
+};
+
+static BOOL should_ignore_fstype(char *type)
+{
+    char **s;
+    
+    for (s = ignored_fstypes; *s; s++)
+        if (!strcmp(*s, type)) return TRUE;
+
+    return FALSE;
+}
+
+static BOOL is_drive_defined(char *path)
+{
+    int i;
+    
+    for (i = 0; i < 26; i++)
+        if (drives[i].in_use && !strcmp(drives[i].unixpath, path)) return TRUE;
+
+    return FALSE;
+}
+
+/* returns Z + 1 if there are no more available letters */
+static char allocate_letter()
+{
+    char letter;
+
+    for (letter = 'C'; letter <= 'Z'; letter++)
+        if ((DRIVE_MASK_BIT(letter) & working_mask) != 0) break;
+
+    return letter;
+}
+
+#define FSTAB_OPEN 1
+#define NO_MORE_LETTERS 2
+#define NO_ROOT 3
+#define NO_DRIVE_C 4
+
+static void report_error(int code)
+{
+    char *buffer;
+    int len;
+    
+    switch (code)
+    {
+        case FSTAB_OPEN:
+            if (gui_mode)
+            {
+                static const char *s = "Could not open your mountpoint description table.\n\nOpening of /etc/fstab failed: %s";
+                len = snprintf(NULL, 0, s, strerror(errno));
+                buffer = HeapAlloc(GetProcessHeap(), 0, len + 1);
+                snprintf(buffer, len, s, strerror(errno));
+                MessageBox(NULL, s, "", MB_OK | MB_ICONEXCLAMATION);
+                HeapFree(GetProcessHeap(), 0, buffer);
+            }
+            else
+            {
+                fprintf(stderr, "winecfg: could not open fstab: %s", strerror(errno));
+            }
+            break;
+
+        case NO_MORE_LETTERS:
+            if (gui_mode) MessageBox(NULL, "No more letters are available to auto-detect available drives with.", "", MB_OK | MB_ICONEXCLAMATION);
+            fprintf(stderr, "winecfg: no more available letters while scanning /etc/fstab");
+            break;
+
+        case NO_ROOT:
+            if (gui_mode) MessageBox(NULL, "Could not ensure that the root directory was mapped.\n\n"
+                                     "This can happen if you run out of drive letters. "
+                                     "It's important to have the root directory mapped, otherwise Wine"
+                                     "will not be able to always find the programs you want to run. "
+                                     "Try unmapping a drive letter then trying again.", "",
+                                     MB_OK | MB_ICONEXCLAMATION);
+            else fprintf(stderr, "winecfg: unable to map root drive\n");
+            break;
+
+        case NO_DRIVE_C:
+            if (gui_mode)
+                MessageBox(NULL, "No virtual drive C mapped\n\nTry running wineprefixcreate", "", MB_OK | MB_ICONEXCLAMATION);
+            else
+                fprintf(stderr, "winecfg: no drive_c directory\n");
+    }
+    
+}
+
+static void ensure_root_is_mapped()
+{
+    int i;
+    BOOL mapped = FALSE;
+
+    for (i = 0; i < 26; i++)
+        if (drives[i].in_use && !strcmp(drives[i].unixpath, "/")) mapped = TRUE;
+
+    if (!mapped)
+    {
+        /* work backwards from Z, trying to map it */
+        char letter;
+
+        for (letter = 'Z'; letter >= 'A'; letter--)
+        {
+            if (drives[letter - 'A'].in_use) continue;
+            add_drive(letter, "/", "System", 0, DRIVE_FIXED);
+            WINE_TRACE("allocated drive %c as the root drive\n", letter);
+        }
+
+        if (letter == ('A' - 1)) report_error(NO_ROOT);
+    }
+}
+
+static void ensure_drive_c_is_mapped()
+{
+    struct stat buf;
+    char *configdir = wine_get_config_dir();
+    int len;
+    char *drive_c_dir;
+    
+    if (drives[2].in_use) return;
+
+    len = snprintf(NULL, 0, "%s/../drive_c", configdir);
+    drive_c_dir = HeapAlloc(GetProcessHeap(), 0, len);
+    snprintf(drive_c_dir, len, "%s/../drive_c", configdir);
+    HeapFree(GetProcessHeap(), 0, drive_c_dir);
+
+    if (stat(drive_c_dir, &buf) == 0)
+    {
+        add_drive('C', "../drive_c", "Virtual Windows Drive", "0", DRIVE_FIXED);
+    }
+    else
+    {
+        report_error(NO_DRIVE_C);
+    }
+}
+
 int autodetect_drives()
 {
-    MessageBox(NULL, "Write me!", "", MB_OK | MB_ICONEXCLAMATION);
+    struct mntent *ent;
+    FILE *fstab;
+
+    /* we want to build a list of autodetected drives, then ensure each entry
+       exists in the users setup. so, we superimpose the autodetected drives
+       onto whatever is pre-existing.
+
+       for now let's just rummage around inside the fstab.
+     */
+
+    load_drives();
+
+    working_mask = drive_available_mask('\0');
+
+    fstab = fopen("/etc/fstab", "r");
+    if (!fstab)
+    {
+        report_error(FSTAB_OPEN);
+        return FALSE;
+    }
+
+    while ((ent = getmntent(fstab)))
+    {
+        char letter;
+        char label[256];
+        int type;
+        
+        WINE_TRACE("ent->mnt_dir=%s\n", ent->mnt_dir);
+
+        if (should_ignore_fstype(ent->mnt_type)) continue;
+        if (is_drive_defined(ent->mnt_dir)) continue;
+
+        /* allocate a drive for it */
+        letter = allocate_letter();
+        if (letter == ']')
+        {
+            report_error(NO_MORE_LETTERS);
+            fclose(fstab);
+            return FALSE;
+        }
+            
+        WINE_TRACE("adding drive %c for %s, type %s\n", letter, ent->mnt_dir, ent->mnt_type);
+        
+        strncpy(label, "Drive X", 8);
+        label[6] = letter;
+
+        if (!strcmp(ent->mnt_type, "nfs")) type = DRIVE_REMOTE;
+        else if (!strcmp(ent->mnt_type, "nfs4")) type = DRIVE_REMOTE;
+        else if (!strcmp(ent->mnt_type, "smbfs")) type = DRIVE_REMOTE;
+        else if (!strcmp(ent->mnt_type, "cifs")) type = DRIVE_REMOTE;
+        else if (!strcmp(ent->mnt_type, "coda")) type = DRIVE_REMOTE;
+        else if (!strcmp(ent->mnt_type, "iso9660")) type = DRIVE_CDROM;
+        else if (!strcmp(ent->mnt_type, "ramfs")) type = DRIVE_RAMDISK;
+        else type = DRIVE_FIXED;
+        
+        add_drive(letter, ent->mnt_dir, label, "0", type);
+        
+        working_mask |= DRIVE_MASK_BIT(letter);
+    }
+
+    fclose(fstab);
+
+    ensure_root_is_mapped();
+
+    ensure_drive_c_is_mapped();
+
+    return TRUE;
 }
--- programs/winecfg.working/driveui.c	2004-09-23 23:10:46.000000000 +0100
+++ programs/winecfg/driveui.c	2004-09-24 19:35:13.000000000 +0100
@@ -41,8 +41,6 @@
 
 WINE_DEFAULT_DEBUG_CHANNEL(winecfg);
 
-#define DRIVE_MASK_BIT(B) 1 << (toupper(B) - 'A')
-
 #define BOX_MODE_CD_ASSIGN 1
 #define BOX_MODE_CD_AUTODETECT 2
 #define BOX_MODE_NONE 3
@@ -194,40 +192,6 @@
     }
 }
 
-/* This function produces a mask for each drive letter that isn't
- * currently used. Each bit of the long result represents a letter,
- * with A being the least significant bit, and Z being the most
- * significant.
- *
- * To calculate this, we loop over each letter, and see if we can get
- * a drive entry for it. If so, we set the appropriate bit. At the
- * end, we flip each bit, to give the desired result.
- *
- * The letter parameter is always marked as being available. This is
- * so the edit dialog can display the currently used drive letter
- * alongside the available ones.
- */
-long drive_available_mask(char letter)
-{
-  long result = 0;
-  int i;
-
-  WINE_TRACE("\n");
-
-
-  for(i = 0; i < 26; i++)
-  {
-      if (!drives[i].in_use) continue;
-      result |= (1 << (toupper(drives[i].letter) - 'A'));
-  }
-
-  result = ~result;
-  if (letter) result |= DRIVE_MASK_BIT(letter);
-
-  WINE_TRACE("finished drive letter loop with %lx\n", result);
-  return result;
-}
-
 int fill_drives_list(HWND dialog)
 {
     int count = 0;
@@ -607,6 +571,7 @@
 
                 case IDC_BUTTON_AUTODETECT:
                     autodetect_drives();
+                    fill_drives_list(dialog);
                     break;
 
                 case IDC_BUTTON_SHOW_HIDE_ADVANCED:
-- programs/winecfg.working/winecfg.h	2004-09-23 23:10:46.000000000 +0100
+++ programs/winecfg/winecfg.h	2004-09-24 19:18:36.000000000 +0100
@@ -77,7 +77,7 @@
 
 /* Drive management  */
 void load_drives();
-void autodetect_drives();
+int autodetect_drives();
 
 struct drive
 {
@@ -85,16 +85,21 @@
     char *unixpath;
     char *label;
     char *serial;
-    DWORD type;
+    DWORD type; /* one of the DRIVE_ constants from winbase.h  */
 
     BOOL in_use;
 };
 
-BOOL add_drive(char letter, char *targetpath, char *label, char *serial, uint type);
+#define DRIVE_MASK_BIT(B) 1 << (toupper(B) - 'A')
+
+long drive_available_mask(char letter);
+BOOL add_drive(char letter, char *targetpath, char *label, char *serial, unsigned int type);
 void delete_drive(struct drive *pDrive);
 void apply_drive_changes();
 extern struct drive drives[26]; /* one for each drive letter */
 
+BOOL gui_mode;
+
 /* Some basic utilities to make win32 suck less */
 #define disable(id) EnableWindow(GetDlgItem(dialog, id), 0);
 #define enable(id) EnableWindow(GetDlgItem(dialog, id), 1);


More information about the wine-patches mailing list