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