ntdll / kernel32: #41

Eric Pouech pouech-eric at wanadoo.fr
Wed Feb 4 14:55:00 CST 2004


let's start submitting the new fs code...

basically, you will need to have run this new tool on your configuration 
directory before we can go any further (otherwise, wine will give you 
some nice warning messages, and breakages could appear)
winefs --config--assign

see the previous winedevel post for some more details.

ChangeLog:
- winefs, a tool for creating the files needed for the new fs infrastructure
-------------- next part --------------
diff -u -N -r -x '*~' -x '.#*' -x CVS files40/drive.c files/drive.c
--- files40/drive.c	2004-01-23 22:15:33.000000000 +0100
+++ files/drive.c	2004-02-04 21:28:50.000000000 +0100
@@ -400,6 +400,42 @@
         if (toupperW(path[0]) != drive_env[1] || path[1] != ':') continue;
         DRIVE_Chdir( i, path + 2 );
     }
+
+    /* temporary check to warn about
+     * 1/ absence of device/drive directories
+     * 2/ modification of config without possible device/drive directories update
+     */
+    do 
+    {
+        const char*     pfx = wine_get_config_dir();
+        char            tmp[MAX_PATH];
+        struct stat     dev, ddev, cfg;
+
+        sprintf(tmp, "%s/config", pfx);
+        if (stat(tmp, &cfg) == -1) break;
+        sprintf(tmp, "%s/device", pfx);
+        if (stat(tmp, &dev) != -1 &&
+            sprintf(tmp, "%s/dosdevices", pfx) &&
+            stat(tmp, &ddev) != -1)
+        {
+            if (dev.st_ctime < cfg.st_mtime ||
+                ddev.st_ctime < cfg.st_mtime)
+            {
+                MESSAGE("Your configuration file (%s/config) seems newer than\n"
+                        "the device/drive directories (%s/device and %s/dosdevices).\n"
+                        "You should perhaps run 'tools/winefs --config-assign %s' in order to update the later.\n",
+                        pfx, pfx, pfx, pfx);
+            }
+        }
+        else
+        {
+            MESSAGE("No device/drive directories files (%s/device and %s/dosdevices) found.\n"
+                    "You should run 'tools/winefs  --config-assign %s' in order to create them\n",
+                    pfx, pfx, pfx);
+            exit(0);
+        }
+    } while (0);
+
     return 1;
 }
 
Index: tools/Makefile.in
===================================================================
RCS file: /home/cvs/cvsroot/wine/wine/tools/Makefile.in,v
retrieving revision 1.37
diff -u -r1.37 Makefile.in
--- tools/Makefile.in	20 Nov 2003 22:02:15 -0000	1.37
+++ tools/Makefile.in	3 Jan 2004 16:07:33 -0000
@@ -8,12 +8,14 @@
 PROGRAMS = \
 	bin2res \
 	fnt2bdf \
-	makedep
+	makedep \
+	winefs
 
 C_SRCS = \
 	bin2res.c \
 	fnt2bdf.c \
-	makedep.c
+	makedep.c \
+	winefs.c
 
 SUBDIRS = \
 	widl \
@@ -37,6 +39,9 @@
 fnt2bdf: fnt2bdf.o
 	$(CC) $(CFLAGS) -o fnt2bdf fnt2bdf.o $(LIBPORT)
 
+winefs: winefs.o
+	$(CC) $(CFLAGS) -o winefs winefs.o $(LIBPORT)
+
 bin2res: bin2res.o
 	$(CC) $(CFLAGS) -o bin2res bin2res.o $(LIBPORT)
 
--- /dev/null	1970-01-01 01:00:00.000000000 +0100
+++ tools/winefs.c	2004-02-04 21:21:58.000000000 +0100
@@ -0,0 +1,761 @@
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <mntent.h>
+#include <fcntl.h>
+#include <errno.h>
+
+/* TODO:
+ * - surely a bit too much Linux centric
+ * - erases all existing content when rerun
+ */
+
+#define DEV_NAME_LEN    32
+#define MAX_PATH_LEN    1024
+
+static const char* subdirs[] = {"device", "dosdevices"};
+static char        tmp1[MAX_PATH_LEN];
+static char        tmp2[MAX_PATH_LEN];
+static int         verbose = 0;
+static const char* pfx;
+
+static const char* VxDs[] = {
+    "vmm", "debug", "vpicd", "vdmad", "vtd", "v86mmgr", "pageswap", "parity",
+    "reboot", "vdd", "vsd", "vmd", "vkd20", "vcd", "vpd", "blockdev", "vmcpd", "ebios",
+    "biosxlat", "vnetbios", "dosmgr", "winload", "shell", "vmpoll", "vprod", 
+    "dosnet", "vfd", "vdd2", "windebug", "tsrload", "bioshook", "int13", "pagefile",
+    "scsi", "mca_pos", "scsifd", "vpend", "vpowerd", "vxdldr", "ndis", "bios_ext", 
+    "vwin32", "vcomm", "spooler", "win32s", "debugcmd", "vnb", "server", "configmg",
+    "dwcfgmg", "scsiport", "vfbackup", "enable", "vcond", "efax", "dsvxd", "isapnp",
+    "bios", "winsock", "wsock", "wsipx", "ifsmgr", "vcdfsd", "mrci2", "pci", 
+    "peloader", "eisa", "dragcli", "dragsrv", "perf", "awredir", "eten", "chbios",
+    "vmsgd", "vppid", "vime", "vhbiosd", "vtdapi", "mmdevldr", "vnetsup", "vredir",
+    "vbrowse", "vshare", "ifsmgr", "memprobe", "vfat", "nwlink", "vnwlink", "nwsup",
+    "vtdi", "vip", "vtcp", "vcache", "vudp", "vasync", "nwredir", "stat80", 
+    "scsiport", "filesec", "nwserver", "secprov", "nscl", "wstcp", "ndis2sup", 
+    "msodisup", "splitter", "ppp", "vdhcp", "vnbt", "logger", "efilter", "ffilter",
+    "tfilter", "afilter", "irlamp", "pccard", "hasp95", "monodebg.vxd"
+};
+
+static const char* TSRs[] = {
+    "scsimgr$", "hpscan", "emmxxxx0", NULL
+};
+
+static void cleanup_dir(void)
+{
+    int i;
+
+    for (i = 0; i < sizeof(subdirs) / sizeof(subdirs[0]); i++)
+    {
+        sprintf(tmp1, "rm -rf %s/%s", pfx, subdirs[i]);
+        system(tmp1);
+    }
+}
+
+static void create_dir(void)
+{
+    int         i;
+
+    for (i = 0; i < sizeof(subdirs) / sizeof(subdirs[0]); i++)
+    {
+        sprintf(tmp1, "%s/%s", pfx, subdirs[i]);
+        if (mkdir(tmp1, 0777) == -1)
+            perror("mkdir");
+    }
+}
+
+static unsigned is_ro(const struct mntent* me)
+{
+    return hasmntopt(me, MNTOPT_RO) ? 1 : 0;
+}
+
+static unsigned is_remote(const struct mntent* me)
+{
+    return !strcmp(me->mnt_type, "nfs") || !strcmp(me->mnt_type, "smbfs");
+}
+
+static unsigned is_floppy(const char* dev_name)
+{
+    return dev_name[0] == 'f' && dev_name[1] == 'd' && isdigit(dev_name[2]);
+}
+
+static unsigned is_harddisk(const char* dev_name)
+{
+    return (dev_name[0] == 'h' || dev_name[0] == 's') && dev_name[1] == 'd' && 
+        (dev_name[2] >= 'a' && dev_name[2] <= 'z') && isdigit(dev_name[3]);
+}
+
+/******************************************************************
+ *		build_dev_name
+ * builds a device name for a full path to the unix device (/dev/hda)
+ */
+static unsigned   build_dev_name(char* dev_name, const struct mntent* me)
+{
+    char*       ptr;
+
+    ptr = strrchr(me->mnt_fsname, '/');
+    if (!ptr++) return 0;
+
+    strcpy(dev_name, ptr);
+    for (ptr = dev_name; *ptr; ptr++) *ptr = tolower(*ptr);
+    return 1;
+}
+
+/******************************************************************
+ *		mntent_loop
+ * loops across all known mount entities
+ *      called with *f = NULL resets the loop
+ *      takes care of most of the issues (entries to be ignored, supermount quirks)
+ */
+static unsigned mntent_loop(FILE** f, char* dev_name, struct mntent* res)
+{
+    struct mntent*      me;
+
+    if (!*f && !(*f = setmntent(_PATH_MNTTAB, "r"))) return 0;
+    
+    while ((me = getmntent(*f)))
+    {
+
+        if (verbose > 1) printf("%s %s %s %s\n", me->mnt_fsname, me->mnt_dir, me->mnt_type, me->mnt_opts);
+        if (!strcmp(me->mnt_fsname, "none") && strcmp(me->mnt_type, "supermount")) continue;
+        if (!strcmp(me->mnt_type, MNTTYPE_IGNORE) || !strcmp(me->mnt_type, MNTTYPE_SWAP)) continue;
+        memcpy(res, me, sizeof(*me));
+        /* fixme: some supermount configuration define device in the options...
+         * let's grab it
+         */
+        if (!strcmp(me->mnt_fsname, "none") && !strcmp(me->mnt_type, "supermount"))
+        {
+            char* ldev = hasmntopt(me, "dev"), *ptr;
+            if (ldev)
+            {
+                ldev += 4;
+                if (verbose > 1) printf("overriding %s with", me->mnt_fsname);
+                if (!(ptr = strchr(ldev, ','))) ptr = ldev + strlen(ldev);
+                res->mnt_fsname = malloc(ptr - ldev + 1);
+                strncpy(res->mnt_fsname, ldev, ptr - ldev);
+                res->mnt_fsname[ptr - ldev] = '\0';
+            }
+        }
+        if (!build_dev_name(dev_name, res)) continue;
+        return 1;
+    }
+    endmntent(*f);
+    *f = NULL;
+    return 0;
+}
+
+/******************************************************************
+ *		normalize
+ * removes double / and trailing / in path names
+ */
+static void normalize(char* ptr)
+{
+    char*       dst = ptr;
+
+    while (*ptr)
+        if (ptr[0] == '/' && ptr[1] == '/') ptr++; else *dst++ = *ptr++;
+    if (dst[-1] == '/') dst--;
+    *dst = '\0';
+}
+
+/******************************************************************
+ *		create_volumes
+ * for each known partition:
+ *      - create ${WINEPREFIX}/device/volume{<dev>}
+ *      - link ${WINEPREFIX}/device/volume{<dev>}/device to the unix device
+ *      - link ${WINEPREFIX}/device/volume{<dev>}/mount to the unix mount point
+ * for each known physical drive:
+ *      - create ${WINEPREFIX}/device/harddisk<NN>
+ *      - link ${WINEPREFIX}/device/harddisk<NN>/device to the unix device
+ *      - link ${WINEPREFIX}/dosdevices/physicaldrive<NN> to 
+ *        ${WINEPREFIX}/device/harddisk<NN>/device
+ */
+static void create_volumes(void)
+{
+    char* p;
+    unsigned map = 0, bit;
+    char dev_name[DEV_NAME_LEN];
+    FILE* f = NULL;
+    struct mntent me;
+
+    while (mntent_loop(&f, dev_name, &me))
+    {
+        sprintf(tmp1, "%s/device/volume{%s}", pfx, dev_name);
+        mkdir(tmp1, 0777);
+        p = tmp1 + strlen(tmp1);
+        strcpy(p, "/device");
+        if (verbose) printf("\t%s => %s\n", tmp1, me.mnt_fsname);
+        symlink(me.mnt_fsname, tmp1);
+        strcpy(p, "/mount");
+        if (verbose) printf("\t%s => %s\n", tmp1, me.mnt_dir);
+        symlink(me.mnt_dir, tmp1);
+        bit = 1 << (dev_name[2] - 'a');
+        if (is_harddisk(dev_name) && !(map & bit))
+        {
+            map |= bit;
+            sprintf(tmp1, "/dev/hd%c", dev_name[2]);
+            sprintf(tmp2, "%s/device/harddisk%d", pfx, dev_name[2] - 'a');
+            mkdir(tmp2, 0777);
+            strcat(tmp2, "/device");
+            if (verbose) printf("\t%s => %s\n", tmp2, tmp1);
+            symlink(tmp1, tmp2);
+
+            sprintf(tmp1, "%s/device/harddisk%d/device", pfx, dev_name[2] - 'a');
+            sprintf(tmp2, "%s/dosdevices/physicaldrive%d", pfx, dev_name[2] - 'a');
+            normalize(tmp1); normalize(tmp2);
+            if (verbose) printf("\t%s => %s\n", tmp2, tmp1);
+            symlink(tmp1, tmp2);
+        }
+    }
+}
+
+/******************************************************************
+ *		create_vxd
+ * populates ${WINEPREFIX}/dosdevices/ with all known & supported VxDs
+ */
+static void create_vxd(void)
+{
+    int i, fd;
+    for (i = 0; i < sizeof(VxDs) / sizeof(VxDs[0]); i++)
+    {
+        sprintf(tmp1, "%s/dosdevices/%s", pfx, VxDs[i]);
+        fd = creat(tmp1, 0777);
+        if (fd == -1) perror("create VxD"); else close(fd);
+    }
+}
+
+/******************************************************************
+ *		create_tsr
+ * populates ${WINEPREFIX}/dosdevices/ with all known & supported TSRs
+ */
+static void create_tsr(void)
+{
+    int i, fd;
+    for (i = 0; i < sizeof(TSRs) / sizeof(TSRs[0]); i++)
+    {
+        sprintf(tmp1, "%s/dosdevices/%s", pfx, TSRs[i]);
+        fd = creat(tmp1, 0777);
+        if (fd == -1) perror("create TSR"); else close(fd);
+    }
+}
+
+/******************************************************************
+ *		create_nul
+ * creation of the null device (${WINEPREFIX}/device/null) and link to
+ * the DOS counterpart (${WINEPREFIX}/dosdevices/NUL)
+ */
+static void create_nul(void)
+{
+    sprintf(tmp2, "%s/device/null", pfx);
+    mkdir(tmp2, 0777);
+    strcat(tmp2, "/device");
+    symlink("/dev/null", tmp2);
+    sprintf(tmp1, "%s/dosdevices/nul", pfx);
+    symlink(tmp2, tmp1);
+}
+
+/******************************************************************
+ *		create_comm
+ * for each known unix serial device (/dev/ttyS<NN>):
+ *      - create ${WINEPREFIX}/device/serial<NN>
+ *      - link ${WINEPREFIX}/device/serial<NN>/device to /dev/ttyS<NN>
+ *      - link ${WINEPREFIX}/dosdevices/com<NN+1> to 
+ *        ${WINEPREFIX}/device/serial<NN>/device
+ *      - link ${WINEPREFIX}/dosdevices/aux to
+ *        ${WINEPREFIX}/dosdevices/com1
+ * for each known unix parallel device (/dev/lp<NN>):
+ *      - create ${WINEPREFIX}/device/parallel<NN>
+ *      - link ${WINEPREFIX}/device/parallel<NN>/device to /dev/lp<NN>
+ *      - link ${WINEPREFIX}/dosdevices/lpt<NN+1> to 
+ *        ${WINEPREFIX}/device/parallel<NN>/device
+ */
+static void create_comm(void)
+{
+    int i, jc, jp;
+    struct stat st;
+
+    for (i = jc = jp = 0; i < 4; i++)
+    {
+        sprintf(tmp1, "/dev/ttyS%d", i);
+        if (stat(tmp1, &st) == 0)
+        {
+            sprintf(tmp2, "%s/device/serial%d", pfx, i);
+            mkdir(tmp2, 0777);
+            strcat(tmp2, "/device");
+            symlink(tmp1, tmp2);
+            sprintf(tmp1, "%s/dosdevices/com%d", pfx, ++jc);
+            symlink(tmp2, tmp1);
+            if (i == 0)
+            {
+                sprintf(tmp2, "%s/dosdevices/aux", pfx);
+                symlink(tmp1, tmp2);
+            }
+        }
+        sprintf(tmp1, "/dev/lp%d", i);
+        if (stat(tmp1, &st) == 0)
+        {
+            sprintf(tmp2, "%s/device/parallel%d", pfx, i);
+            mkdir(tmp2, 0777);
+            strcat(tmp2, "/device");
+            symlink(tmp1, tmp2);
+            sprintf(tmp1, "%s/dosdevices/lpt%d", pfx, ++jp);
+            symlink(tmp2, tmp1);
+        }
+    }
+}
+
+/******************************************************************
+ *		win_mount
+ * short implementation for DOS device mounting (drive) on volume <dev_name>,
+ * starting at path <rem> in the volume
+ */
+static void win_mount(char drive, const char* dev_name, const char* rem)
+{
+    sprintf(tmp1, "%s/device/volume{%s}/mount/%s", pfx, dev_name, rem);
+    sprintf(tmp2, "%s/dosdevices/%c:", pfx, drive);
+    normalize(tmp1); normalize(tmp2);
+    if (verbose) printf("\t%s => %s\n", tmp2, tmp1);
+    symlink(tmp1, tmp2);
+    sprintf(tmp1, "%s/device/volume{%s}", pfx, dev_name);
+    sprintf(tmp2, "%s/device/%c:", pfx, drive);
+    normalize(tmp1); normalize(tmp2);
+    if (verbose) printf("\t%s => %s\n", tmp2, tmp1);
+    symlink(tmp1, tmp2);
+}
+
+/******************************************************************
+ *		assign_as_bios
+ * defines & mounts the disks as the BIOS would do:
+ * - floppies (if any) as A:, then B:
+ * - looping in known physical disks, then in all partitions and start
+ *   assigning at C: until Z:
+ */
+static void assign_as_bios(void)
+{
+    unsigned            drive;
+    unsigned            map = 0;
+    char                dev_name[DEV_NAME_LEN];
+    FILE*               f = NULL;
+    struct mntent       me;
+
+    /* assign floppies */
+    drive = 'A';
+    while (mntent_loop(&f, dev_name, &me))
+    {
+        if (is_floppy(dev_name))
+        {
+            if (drive == 'C')
+            {
+                printf("Too many floppies, skipping %s\n", dev_name); 
+                continue; 
+            }
+            win_mount(drive++, dev_name, "");
+        }
+    }
+    /* assign hard disks */
+    drive = 'C';
+    while (mntent_loop(&f, dev_name, &me))
+    {
+        if (is_harddisk(dev_name))
+        {
+            if (drive > 'Z')
+            {
+                printf("Too many harddisks, skipping %s\n", dev_name); 
+                continue; 
+            }
+            win_mount(drive++, dev_name, "");
+            if (!(map & (1 << (dev_name[2] - 'a'))))
+            {
+                map |= 1 << (dev_name[2] - 'a');
+                sprintf(tmp1, "%s/device/harddisk%d/device", pfx, dev_name[2] - 'a');
+                sprintf(tmp2, "%s/dosdevices/physicaldrive%d", pfx, dev_name[2] - 'a');
+                normalize(tmp1); normalize(tmp2);
+                if (verbose) printf("\t%s => %s\n", tmp2, tmp1);
+                symlink(tmp1, tmp2);
+            }
+        }
+    }
+    /* assign the rest */
+    while (mntent_loop(&f, dev_name, &me))
+    {
+        if (!is_floppy(dev_name) && !is_harddisk(dev_name))
+        {
+            if (drive > 'Z')
+            {
+                printf("Too many drives, skipping %s\n", dev_name); 
+                continue; 
+            }
+            win_mount(drive++, dev_name, "");
+        }
+    }
+}
+
+/******************************************************************
+ *		get_word
+ * helper for assign_from_config (parses a word, handling quotes, and 
+ * potentially expanding the environment variables)
+ */
+static int get_word(char** ptr, char* xdst, int expand)
+{
+    char        *dst = xdst, *p1, *p2;
+
+    if (*(*ptr)++ != '\"') return 0;
+    while (**ptr != '\"') *dst++ = *(*ptr)++;
+    *dst = '\0'; (*ptr)++;
+    while ((p1 = strchr(xdst, '%')) && (p2 = strchr(p1 + 1, '%')))
+    {
+        char    exp[MAX_PATH_LEN], *env;
+        size_t  len = p2 - p1 - 1;
+        strncpy(exp, p1 + 1, len); exp[len] = '\0';
+        env = getenv(exp);
+        memmove(p2 + 1 + strlen(env) - len - 2, p2 + 1, strlen(p2) + 1);
+        memcpy(p1, env, strlen(env));
+    }
+    return 1;
+}
+
+/******************************************************************
+ *		set_value
+ * helper for assign_from_config. Creates a file and writes into it
+ * some content (also reports detailed error, like when the files has already
+ * been written by this very tool).
+ * return values:
+ *      0: success (content written)
+ *      otherwise => errno
+ */
+static int set_value(const char* file, const char* value, unsigned msg_for_failure)
+{
+    int         fd, ret;
+    char        cont[MAX_PATH_LEN];
+    unsigned    r;
+    
+    if ((fd = open(file, O_CREAT|O_EXCL|O_WRONLY, 0666)) != -1)
+    {
+        write(fd, value, strlen(value));
+        close(fd);
+        return 0;
+    }
+    switch (ret = errno)
+    {
+    case EEXIST:
+        if ((fd = open(file, O_RDONLY)) != -1 && 
+            (r = read(fd, cont, sizeof(cont))) && r != -1)
+        {
+            cont[r] = '\0';
+            if (memcmp(value, cont, strlen(value)))
+                printf("\tFile %s already exists and contains '%s',\n"
+                       "\t\ttherefore couldn't write '%s' into it\n", file, cont, value);
+        }
+        break;
+    case EROFS:
+        break;
+    default:
+        if (msg_for_failure)
+            printf("\tCouldn't write '%s' to %s (%s)\n", value, file, strerror(errno));
+        break;
+    }
+    return ret;
+}
+
+/******************************************************************
+ *		get_device_flags
+ *
+ * compute flags value for a given device
+ */
+static unsigned get_device_type(const char* volume, const char* type, 
+                                size_t remote, char* rtype)
+{
+    if (!strcasecmp(type, "floppy"))            strcpy(rtype, "floppy-disk");
+    else if (!strcasecmp(type, "hd"))           strcpy(rtype, "hard-disk");
+    else if (!strcasecmp(type, "network"))      strcpy(rtype, "remote-disk");
+    else if (!strcasecmp(type, "cdrom"))        strcpy(rtype, "cdrom");
+    else if (!strcasecmp(type, "ramdisk"))      strcpy(rtype, "ram-disk");
+    else
+    {
+        printf("Unknown type '%s', no type set\n", type);
+        return 0;
+    }
+    /* ok, some wild guesses */
+    if (remote && strcmp(rtype, "remote-disk"))
+    {
+        printf("\t/etc/mtab says volume is remote\n\t\tforcing its type to remote-disk (was %s)\n", rtype);
+        strcpy(rtype, "remote-disk");
+    }
+    if (is_floppy(volume) && strcmp(rtype, "floppy-disk"))
+    {
+        printf("\t/etc/mtab says volume is a floppy\n\t\tforcing its type to floppy-disk (was %s)\n", rtype);
+        strcpy(rtype, "floppy-disk");
+    }
+    if (is_harddisk(volume) && strcmp(rtype, "hard-disk"))
+    {
+        printf("\t/etc/mtab says volume is a hard disk\n\t\tforcing its type to hard-disk (was %s)\n", rtype);
+        strcpy(rtype, "hard-disk");
+    }
+    return 1;
+}
+
+/******************************************************************
+ *		is_mounted
+ *
+ * helper for assign_from_config
+ * Checks whether a volume is actually mounted - in unix terms -
+ * (the volume must be mounted in win32 terms)
+ * this shall forbid (for example) writting to /mnt/cdrom when 
+ * the cdrom not mounted
+ */
+static unsigned is_mounted(const char* volume)
+{
+    struct stat root, dev;
+    char        tmp[MAX_PATH_LEN];
+
+    sprintf(tmp, "/dev/%s", volume);
+    if (stat(tmp, &dev) == -1) return 0;
+    sprintf(tmp, "%s/device/volume{%s}/mount", pfx, volume);
+    if (stat(tmp, &root) == -1) return 0;
+    return root.st_dev == dev.st_rdev;
+}
+
+/******************************************************************
+ *		configure_drive
+ * helper for assign_from_config (actually configures a drive with a set of
+ * options gotten from config file)
+ */
+static int configure_drive(char drive, const char* path, const char* device, const char* type, 
+                           const char* filesystem, const char* label, const char* serial)
+{
+    char                value[MAX_PATH_LEN], volume[MAX_PATH_LEN], mntdev[MAX_PATH_LEN];
+    char                dev_name[DEV_NAME_LEN];
+    size_t              len, ro, remote;
+    FILE*               f = NULL;
+    struct mntent       me;
+
+    printf("Configuring drive %c:\n", drive);
+    value[0] = '\0'; ro = remote = 0;
+    while (mntent_loop(&f, dev_name, &me))
+    {
+        len = strlen(me.mnt_dir);
+        if (!strncmp(me.mnt_dir, path, len) && len > strlen(value))
+        {
+            strcpy(value, me.mnt_dir);
+            strcpy(volume, dev_name);
+            strcpy(mntdev, me.mnt_fsname);
+            ro = is_ro(&me); remote = is_remote(&me);
+        }
+    }
+    if (!value[0])
+    {
+        printf("Couldn't find volume for %s\n", path);
+        return 0;
+    }
+
+    len = strlen(value);
+    if (path[len] == '/') len++;
+
+    if (verbose)
+        printf("\tGot device: %s => %s %s\n", path, value, volume);
+    win_mount(tolower(drive), volume, path + len);
+                
+    if (!value[len])
+    {
+        if (*label)
+        {
+            sprintf(tmp1, "%s/device/volume{%s}/mount/.windows-label", pfx, volume);
+            if (ro || !is_mounted(volume) || set_value(tmp1, label, 0) == EROFS)
+            {
+                sprintf(tmp1, "%s/device/volume{%s}/label", pfx, volume);
+                set_value(tmp1, label, 1);
+            }
+        }
+        if (*serial)
+        {
+            sprintf(tmp1, "%s/device/volume{%s}/mount/.windows-serial", pfx, volume);
+            if (ro || !is_mounted(volume) || set_value(tmp1, label, 0) == EROFS)
+            {
+                sprintf(tmp1, "%s/device/volume{%s}/serial", pfx, volume);
+                set_value(tmp1, serial, 1);
+            }
+        }
+        if (*device && strcmp(device, mntdev))
+            printf("\tDevice mismatch: config=%s %s=%s, using the later\n", 
+                   device, _PATH_MNTTAB, mntdev);
+        if (*type)
+        {
+            if (get_device_type(volume, type, remote, tmp2))
+            {
+                sprintf(tmp1, "%s/device/volume{%s}/type", pfx, volume);
+                set_value(tmp1, tmp2, 1);
+            }
+        }
+    }
+    else 
+    {
+        if (*label) 
+            printf("\tSkipping label '%s': (not a physical volume)\n", label);
+        if (*serial) 
+            printf("\tSkipping serial number '%s': (not a physical volume)\n", serial);
+        if (*device)
+            printf("\tSkipping device '%s': (not a physical volume)\n", device);
+        if (*type && strcmp(type, "hd")) /* hd is the default */
+            printf("\tSkipping type '%s': (not a physical volume)\n", type);
+    }
+    return 1;
+}
+
+/******************************************************************
+ *		assign_from_config
+ * parse wine config file, and read for each defined drive its path,
+ * device name, label name, serial number.
+ * then define the DOS drives accordingly.
+ */
+static void assign_from_config(void)
+{
+    FILE*               cf;
+    char                line[MAX_PATH_LEN], drive = -1, option[MAX_PATH_LEN];
+    char                value[MAX_PATH_LEN];
+    char                path[MAX_PATH_LEN], device[MAX_PATH_LEN], type[MAX_PATH_LEN];
+    char                label[MAX_PATH_LEN], serial[MAX_PATH_LEN], fs[MAX_PATH_LEN];
+    char*               ptr;
+
+    sprintf(tmp1, "%s/config", pfx);
+    cf = fopen(tmp1, "r");
+    if (cf == NULL)
+    {
+        printf("Couldn't open config file: %s\n", tmp1);
+        exit(0);
+    }
+    while (fgets(line, sizeof(line), cf))
+    {
+        for (ptr = line; isspace(*ptr); ptr++);
+        if (ptr[0] == '[')  /* we enter another section */
+        {
+            if (drive != -1) /* configure drive if previous was a drive */
+            {
+                configure_drive(drive, path, device, type, fs, label, serial);
+                drive = -1;
+            }
+            /* check whether we start a new one */
+            if (strncmp(ptr, "[Drive ", 6) == 0 && ptr[8] == ']')
+            {
+                drive = ptr[7]; 
+                path[0] = device[0] = type[0] = label[0] = serial[0] = fs[0] = '\0';
+            }
+        }
+        else if (drive != -1)
+        {
+            if (get_word(&ptr, option, 0))
+            {
+                while (isspace(*ptr)) ptr++;
+                if (*ptr++ == '=')
+                {
+                    while (isspace(*ptr)) ptr++;
+                    if (get_word(&ptr, value, 1))
+                    {
+                        if (verbose) printf("\t%s => %s\n", option, value);
+                        if (!strcasecmp(option, "path"))        strcpy(path,   value);
+                        else if (!strcasecmp(option, "device")) strcpy(device, value);
+                        else if (!strcasecmp(option, "type"))   strcpy(type,   value);
+                        else if (!strcasecmp(option, "label"))  strcpy(label,  value);
+                        else if (!strcasecmp(option, "serial")) strcpy(serial, value);
+                        else if (!strcasecmp(option, "filesystem")) strcpy(fs, value);
+                        else printf("Unknown config drive option %s\n", option);
+                    }
+                }
+            }
+        }
+    }
+    fclose(cf);
+}
+
+static void assign_none(void) {}
+
+static void usage(void)
+{
+    printf("winefs (--no-assign|--config-assign|--bios-assign) <wineprefix>\n"
+           "  --no-assign means not to do any drive assignment\n"
+           "  --config-assign means to do drive assignment based on <wineprefix>/config\n"
+           "  --bios-assign means to do drive assignment as BIOS would\n"
+           "  by default: <wineprefix> is ~/.wine\n");
+    exit(-1);
+}
+
+static int check_options(const char* arg, void (**fassign)(void))
+{
+    if (!strcmp(arg, "--no-assign"))            *fassign = assign_none;
+    else if (!strcmp(arg, "--config-assign"))   *fassign = assign_from_config;
+    else if (!strcmp(arg, "--bios-assign"))     *fassign = assign_as_bios;
+    else if (!strcmp(arg, "--verbose"))         verbose++;
+    else return 0;
+    return 1;
+}
+
+/******************************************************************
+ *		set_prefix
+ * sets the prefix
+ *
+ */
+static void set_prefix(const char* str)
+{
+    unsigned    len;
+    struct stat st;
+
+    if (!str)
+    {
+        const char*     e = getenv("HOME");
+        char*           apfx;
+        if (!e)
+        {
+            printf("Cannot detect your $HOME directory\n");
+            exit(-1);
+        }
+        apfx = malloc(strlen(e) + 6 + 1);
+        strcpy(apfx, e); strcat(apfx, "/.wine");
+        pfx = apfx;
+    }
+    else if (str[(len = strlen(str)) - 1] == '/') /* remove trailing '/' if any */
+    {
+        char*   apfx = malloc(len);
+        memcpy(apfx, str, len - 1);
+        apfx[len - 1] = '\0';
+        pfx = apfx;
+    }
+    else pfx = str;
+
+    /* check that pfx is actually a directory */
+    if (stat(pfx, &st) == -1 || !S_ISDIR(st.st_mode))
+    {
+        fprintf(stderr, "%s is not a directory\n", pfx);
+        usage();
+    }
+}
+
+int main(int argc, char* argv[])
+{
+    void  (*fassign)(void) = NULL;
+    const char* pfx = NULL;
+    int i;
+    
+    for (i = 1; i < argc; i++)
+    {
+        if (!check_options(argv[i], &fassign))
+        {
+            if (pfx != NULL) usage(); else pfx = argv[i];
+        }
+    }
+    if (!fassign) usage();
+    set_prefix(pfx);
+
+    cleanup_dir();
+    create_dir();
+    create_nul();
+    create_comm();
+    create_volumes();
+    create_vxd();
+    create_tsr();
+
+    if (fassign) fassign();
+    return 0;
+}


More information about the wine-patches mailing list