ntdll/kernel32: #36

Eric Pouech pouech-eric at wanadoo.fr
Sat Sep 20 13:39:36 CDT 2003


Changelog:
- created pathgate objects in server
- enhanced current device server object to mimic a bit more NT objects
- implemented ntdll.NtCreateFile (and ntdll.NtOpenFile) using the 
pathgate and device server objects
- copied most of the drive init to ntdll, and converted it in terms of 
pathgates and device server objects

for the time being, we'll be living with two sets of data for device 
configuration. At the end, of course, only the newly introduced shall 
subsist.

A+
-- 
Eric Pouech
-------------- next part --------------
diff -u -N -r -x '*~' -x '.#*' -x CVS dlls/kernel35/process.c dlls/kernel/process.c
--- dlls/kernel35/process.c	2003-09-19 19:02:37.000000000 +0200
+++ dlls/kernel/process.c	2003-09-20 17:59:07.000000000 +0200
@@ -127,9 +127,10 @@
 extern WINE_MODREF *MODULE_AllocModRef( HMODULE hModule, LPCSTR filename );  /* FIXME */
 
 extern void RELAY_InitDebugLists(void);
-extern void SHELL_LoadRegistry(void);
+extern BOOL SHELL_LoadRegistry(void);
+extern void FILE_InitPathNameSpace(BOOL);
 extern void VERSION_Init( const char *appname );
 
 /***********************************************************************
  *           get_basename
  */
@@ -430,7 +434,15 @@
     if (!DIR_Init()) return FALSE;
 
     /* registry initialisation */
-    SHELL_LoadRegistry();
+    if (SHELL_LoadRegistry())
+    {
+        /* let's do all configuration related handling */
+        FILE_InitPathNameSpace(TRUE);
+    }
+    else
+    {
+        FILE_InitPathNameSpace(FALSE);
+    }
 
     /* global boot finished, the rest is process-local */
     SERVER_START_REQ( boot_done )
diff -u -N -r -x '*~' -x '.#*' -x CVS dlls/ntdll35/dos_fs.c dlls/ntdll/dos_fs.c
--- dlls/ntdll35/dos_fs.c	1970-01-01 01:00:00.000000000 +0100
+++ dlls/ntdll/dos_fs.c	2003-09-20 17:04:51.000000000 +0200
@@ -0,0 +1,743 @@
+/*
+ * DOS file system functions
+ *
+ * Copyright 1993 Erik Bos
+ * Copyright 1996 Alexandre Julliard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "config.h"
+#include "wine/port.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <assert.h>
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+#ifdef HAVE_SYS_ERRNO_H
+#include <sys/errno.h>
+#endif
+
+#include <dirent.h>
+#ifdef HAVE_SYS_IOCTL_H 
+#include <sys/ioctl.h>
+#endif
+
+#define NONAMELESSUNION
+#define NONAMELESSSTRUCT
+#include "wine/unicode.h"
+#include "wine/debug.h"
+#include "wine/server.h"
+#include "async.h"
+#include "ntdll_misc.h"
+#include "../files/smb.h"
+
+#include "winternl.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(dos_fs);
+
+/* Chars we don't want to see in DOS file names */
+#define INVALID_DOS_CHARS  "*?<>|\"+=,;[] \345"
+
+#define IS_END_OF_NAME(ch)  (!(ch) || ((ch) == '/') || ((ch) == '\\'))
+
+/***********************************************************************
+ *           DOSFS_ValidDOSName
+ *
+ * Return 1 if Unix file 'name' is also a valid MS-DOS name
+ * (i.e. contains only valid DOS chars, lower-case only, fits in 8.3 format).
+ * File name can be terminated by '\0', '\\' or '/'.
+ */
+static int DOSFS_ValidDOSName(LPCWSTR name, int ignore_case)
+{
+    static const char invalid_chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" INVALID_DOS_CHARS;
+    const WCHAR *p = name;
+    const char *invalid = ignore_case ? (invalid_chars + 26) : invalid_chars;
+    int len = 0;
+
+    if (*p == '.')
+    {
+        /* Check for "." and ".." */
+        p++;
+        if (*p == '.') p++;
+        /* All other names beginning with '.' are invalid */
+        return (IS_END_OF_NAME(*p));
+    }
+    while (!IS_END_OF_NAME(*p))
+    {
+        if (*p < 256 && strchr(invalid, (char)*p)) return 0;  /* Invalid char */
+        if (*p == '.') break;  /* Start of the extension */
+        if (++len > 8) return 0;  /* Name too long */
+        p++;
+    }
+    if (*p != '.') return 1;  /* End of name */
+    p++;
+    if (IS_END_OF_NAME(*p)) return 0;  /* Empty extension not allowed */
+    len = 0;
+    while (!IS_END_OF_NAME(*p))
+    {
+        if (*p < 256 && strchr(invalid, (char)*p)) return 0;  /* Invalid char */
+        if (*p == '.') return 0;  /* Second extension not allowed */
+        if (++len > 3) return 0;  /* Extension too long */
+        p++;
+    }
+    return 1;
+}
+
+/***********************************************************************
+ *           DOSFS_ToDosFCBFormat
+ *
+ * Convert a file name to DOS FCB format (8+3 chars, padded with blanks),
+ * expanding wild cards and converting to upper-case in the process.
+ * File name can be terminated by '\0', '\\' or '/'.
+ * Return FALSE if the name is not a valid DOS name.
+ * 'buffer' must be at least 12 characters long.
+ */
+static BOOL DOSFS_ToDosFCBFormat(LPCWSTR name, LPWSTR buffer)
+{
+    static const char invalid_chars[] = INVALID_DOS_CHARS;
+    LPCWSTR p = name;
+    int i;
+
+    /* Check for "." and ".." */
+    if (*p == '.')
+    {
+        p++;
+        buffer[0] = '.';
+        for(i = 1; i < 11; i++) buffer[i] = ' ';
+        buffer[11] = 0;
+        if (*p == '.')
+        {
+            buffer[1] = '.';
+            p++;
+        }
+        return IS_END_OF_NAME(*p);
+    }
+
+    for (i = 0; i < 8; i++)
+    {
+        switch (*p)
+        {
+        case '\0':
+        case '\\':
+        case '/':
+        case '.':
+            buffer[i] = ' ';
+            break;
+        case '?':
+            p++;
+            /* fall through */
+        case '*':
+            buffer[i] = '?';
+            break;
+        default:
+            if (*p < 256 && strchr(invalid_chars, (char)*p)) return FALSE;
+            buffer[i] = toupperW(*p);
+            p++;
+            break;
+        }
+    }
+
+    if (*p == '*')
+    {
+        /* Skip all chars after wildcard up to first dot */
+        while (*p && (*p != '/') && (*p != '\\') && (*p != '.')) p++;
+    }
+    else
+    {
+        /* Check if name too long */
+        if (*p && (*p != '/') && (*p != '\\') && (*p != '.')) return FALSE;
+    }
+    if (*p == '.') p++;  /* Skip dot */
+
+    for (i = 8; i < 11; i++)
+    {
+        switch(*p)
+        {
+        case '\0':
+        case '\\':
+        case '/':
+            buffer[i] = ' ';
+            break;
+        case '.':
+            return FALSE;  /* Second extension not allowed */
+        case '?':
+            p++;
+            /* fall through */
+        case '*':
+            buffer[i] = '?';
+            break;
+        default:
+            if (*p < 256 && strchr(invalid_chars, (char)*p)) return FALSE;
+            buffer[i] = toupperW(*p);
+            p++;
+            break;
+        }
+    }
+    buffer[11] = '\0';
+
+    /* at most 3 character of the extension are processed
+     * is something behind this ?
+     */
+    while (*p == '*' || *p == ' ') p++; /* skip wildcards and spaces */
+    return IS_END_OF_NAME(*p);
+}
+
+/***********************************************************************
+ *           DOSFS_ToDosDTAFormat
+ *
+ * Convert a file name from FCB to DTA format (name.ext, null-terminated)
+ * converting to upper-case in the process.
+ * File name can be terminated by '\0', '\\' or '/'.
+ * 'buffer' must be at least 13 characters long.
+ */
+static void DOSFS_ToDosDTAFormat(LPCWSTR name, UNICODE_STRING* dst)
+{
+    LPWSTR p, d;
+    
+    /* FIXME: check that we can store at least (8+1+3+1) * sizeof(WCHAR) in dst */
+    d = dst->Buffer + dst->Length / sizeof(WCHAR);
+    memcpy(d, name, 8 * sizeof(WCHAR));
+    p = d + 8;
+    while ((p > d) && (p[-1] == ' ')) p--;
+    *p++ = '.';
+    memcpy(p, name + 8, 3 * sizeof(WCHAR));
+    p += 3;
+    while (p[-1] == ' ') p--;
+    if (p[-1] == '.') p--;
+    *p = '\0';
+    dst->Length += (p - d) * sizeof(WCHAR);
+}
+
+/***********************************************************************
+ *           DOSFS_Hash
+ *
+ * Transform a Unix file name into a hashed DOS name. If the name is a valid
+ * DOS name, it is converted to upper-case; otherwise it is replaced by a
+ * hashed version that fits in 8.3 format.
+ * File name can be terminated by '\0', '\\' or '/'.
+ * 'buffer' must be at least 13 characters long.
+ */
+static void DOSFS_Hash(LPCWSTR name, LPWSTR buffer, BOOL dir_format,
+                        BOOL ignore_case)
+{
+    static const char invalid_chars[] = INVALID_DOS_CHARS "~.";
+    static const char hash_chars[32] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ012345";
+
+    LPCWSTR p, ext;
+    LPWSTR dst;
+    unsigned short hash;
+    int i;
+
+    if (dir_format)
+    {
+        for(i = 0; i < 11; i++) buffer[i] = ' ';
+        buffer[11] = 0;
+    }
+
+    if (DOSFS_ValidDOSName(name, ignore_case))
+    {
+        /* Check for '.' and '..' */
+        if (*name == '.')
+        {
+            buffer[0] = '.';
+            if (!dir_format) buffer[1] = buffer[2] = '\0';
+            if (name[1] == '.') buffer[1] = '.';
+            return;
+        }
+
+        /* Simply copy the name, converting to uppercase */
+
+        for (dst = buffer; !IS_END_OF_NAME(*name) && (*name != '.'); name++)
+            *dst++ = toupperW(*name);
+        if (*name == '.')
+        {
+            if (dir_format) dst = buffer + 8;
+            else *dst++ = '.';
+            for (name++; !IS_END_OF_NAME(*name); name++)
+                *dst++ = toupperW(*name);
+        }
+        if (!dir_format) *dst = '\0';
+        return;
+    }
+
+    /* Compute the hash code of the file name */
+    /* If you know something about hash functions, feel free to */
+    /* insert a better algorithm here... */
+    if (ignore_case)
+    {
+        for (p = name, hash = 0xbeef; !IS_END_OF_NAME(p[1]); p++)
+            hash = (hash<<3) ^ (hash>>5) ^ tolowerW(*p) ^ (tolowerW(p[1]) << 8);
+        hash = (hash<<3) ^ (hash>>5) ^ tolowerW(*p); /* Last character */
+    }
+    else
+    {
+        for (p = name, hash = 0xbeef; !IS_END_OF_NAME(p[1]); p++)
+            hash = (hash << 3) ^ (hash >> 5) ^ *p ^ (p[1] << 8);
+        hash = (hash << 3) ^ (hash >> 5) ^ *p;  /* Last character */
+    }
+
+    /* Find last dot for start of the extension */
+    for (p = name+1, ext = NULL; !IS_END_OF_NAME(*p); p++)
+        if (*p == '.') ext = p;
+    if (ext && IS_END_OF_NAME(ext[1]))
+        ext = NULL;  /* Empty extension ignored */
+
+    /* Copy first 4 chars, replacing invalid chars with '_' */
+    for (i = 4, p = name, dst = buffer; i > 0; i--, p++)
+    {
+        if (IS_END_OF_NAME(*p) || (p == ext)) break;
+        *dst++ = (*p < 256 && strchr(invalid_chars, (char)*p)) ? '_' : toupperW(*p);
+    }
+    /* Pad to 5 chars with '~' */
+    while (i-- >= 0) *dst++ = '~';
+
+    /* Insert hash code converted to 3 ASCII chars */
+    *dst++ = hash_chars[(hash >> 10) & 0x1f];
+    *dst++ = hash_chars[(hash >> 5) & 0x1f];
+    *dst++ = hash_chars[hash & 0x1f];
+
+    /* Copy the first 3 chars of the extension (if any) */
+    if (ext)
+    {
+        if (!dir_format) *dst++ = '.';
+        for (i = 3, ext++; (i > 0) && !IS_END_OF_NAME(*ext); i--, ext++)
+            *dst++ = (*ext < 256 && strchr(invalid_chars, (char)*ext)) ? '_' : toupperW(*ext);
+    }
+    if (!dir_format) *dst = '\0';
+}
+
+/* Define the VFAT ioctl to get both short and long file names */
+/* FIXME: is it possible to get this to work on other systems? */
+#ifdef linux
+/* We want the real kernel dirent structure, not the libc one */
+typedef struct
+{
+    long d_ino;
+    long d_off;
+    unsigned short d_reclen;
+    char d_name[256];
+} KERNEL_DIRENT;
+
+#define VFAT_IOCTL_READDIR_BOTH  _IOR('r', 1, KERNEL_DIRENT [2])
+
+/* To avoid blocking on non-directories in DOSFS_OpenDir_VFAT*/
+#ifndef O_DIRECTORY
+# define O_DIRECTORY    0200000	/* must be directory */
+#endif
+
+#else   /* linux */
+#undef VFAT_IOCTL_READDIR_BOTH  /* just in case... */
+#endif  /* linux */
+
+#define IS_OPTION_TRUE(ch) ((ch) == 'y' || (ch) == 'Y' || (ch) == 't' || (ch) == 'T' || (ch) == '1')
+
+/*
+ * Directory info for DOSFS_ReadDir
+ * contains the names of *all* the files in the directory
+ */
+typedef struct
+{
+    int         used;
+    int         size;
+    WCHAR       names[1];
+} DOS_DIR;
+
+/***********************************************************************
+ *           DOSFS_AddDirEntry
+ *
+ *  Used to construct an array of filenames in DOSFS_OpenDir
+ */
+static NTSTATUS DOSFS_AddDirEntry(DOS_DIR **dir, LPCWSTR name, LPCWSTR dosname)
+{
+    int extra1 = strlenW(name) + 1;
+    int extra2 = strlenW(dosname) + 1;
+
+    /* if we need more, at minimum double the size */
+    if ((extra1 + extra2 + (*dir)->used) > (*dir)->size)
+    {
+        int more = (*dir)->size;
+        DOS_DIR *t;
+
+        if (more < (extra1 + extra2)) more = extra1 + extra2;
+
+        t = RtlReAllocateHeap(ntdll_get_process_heap(), 0, *dir, 
+                              sizeof(**dir) + ((*dir)->size + more) * sizeof(WCHAR));
+        if (!t)
+        {
+            ERR("Out of memory caching directory structure %d %d %d\n",
+                 (*dir)->size, more, (*dir)->used);
+            return STATUS_NO_MEMORY;
+        }
+        (*dir) = t;
+        (*dir)->size += more;
+    }
+
+    /* at this point, the dir structure is big enough to hold these names */
+    strcpyW(&(*dir)->names[(*dir)->used], name);
+    (*dir)->used += extra1;
+    strcpyW(&(*dir)->names[(*dir)->used], dosname);
+    (*dir)->used += extra2;
+
+    return STATUS_SUCCESS;
+}
+
+
+/***********************************************************************
+ *           DOSFS_OpenDir_VFAT
+ */
+static NTSTATUS DOSFS_OpenDir_VFAT(const union cptable *table, const char *unix_path, DOS_DIR **dir)
+{
+#ifdef VFAT_IOCTL_READDIR_BOTH
+    KERNEL_DIRENT       de[2];
+    int                 fd = open(unix_path, O_RDONLY|O_DIRECTORY);
+    NTSTATUS            status = STATUS_SUCCESS;
+
+    /* Check if the VFAT ioctl is supported on this directory */
+    if (fd < 0) return STATUS_OBJECT_PATH_NOT_FOUND;
+
+    do
+    {
+        WCHAR long_name[MAX_PATH];
+        WCHAR short_name[12];
+
+        if (ioctl(fd, VFAT_IOCTL_READDIR_BOTH, (long)de) == -1)
+        {
+            status = STATUS_NOT_SUPPORTED;
+            break;
+        }
+        if (!de[0].d_reclen)
+        {       
+            static const WCHAR empty_strW[] = { 0 };
+            DOSFS_AddDirEntry(dir, empty_strW, empty_strW);
+            break;
+        }
+        wine_cp_mbstowcs(table, 0, de[0].d_name, strlen(de[0].d_name) + 1,
+                         long_name, MAX_PATH);
+        if (!DOSFS_ToDosFCBFormat(long_name, short_name))
+            short_name[0] = '\0';
+        if (de[1].d_name[0])
+            wine_cp_mbstowcs(table, 0, de[1].d_name, strlen(de[1].d_name) + 1,
+                             long_name, MAX_PATH);
+        else
+            wine_cp_mbstowcs(table, 0, de[0].d_name, strlen(de[0].d_name) + 1,
+                             long_name, MAX_PATH);
+        status = DOSFS_AddDirEntry(dir, long_name, short_name);
+    } while (status == STATUS_SUCCESS);
+    close(fd);
+    return status;
+#else
+    return STATUS_NOT_SUPPORTED;
+#endif  /* VFAT_IOCTL_READDIR_BOTH */
+}
+
+
+/***********************************************************************
+ *           DOSFS_OpenDir_Normal
+ *
+ * Now use the standard opendir/readdir interface
+ */
+static NTSTATUS DOSFS_OpenDir_Normal(const union cptable *table, const char *unix_path, DOS_DIR **dir)
+{
+    DIR *unixdir = opendir(unix_path);
+    NTSTATUS status = STATUS_SUCCESS;
+    static const WCHAR empty_strW[] = { 0 };
+
+    if (!unixdir) return FILE_GetNtStatus();
+    do
+    {
+        WCHAR long_name[MAX_PATH];
+        struct dirent *de = readdir(unixdir);
+
+        if (!de) 
+        {
+            DOSFS_AddDirEntry(dir, empty_strW, empty_strW);
+            break;
+        }
+        wine_cp_mbstowcs(table, 0, de->d_name, strlen(de->d_name) + 1,
+                         long_name, MAX_PATH);
+        status = DOSFS_AddDirEntry(dir, long_name, empty_strW);
+    } while (status == STATUS_SUCCESS);
+    closedir(unixdir);
+    return status;
+}
+
+/***********************************************************************
+ *           DOSFS_OpenDir
+ */
+static NTSTATUS DOSFS_OpenDir(const union cptable *table, const char *unix_path, DOS_DIR** dir)
+{
+    const int init_size = 0x100;
+    NTSTATUS status;
+
+    TRACE("%s\n", debugstr_a(unix_path));
+
+    *dir = RtlAllocateHeap(ntdll_get_process_heap(), 0, 
+                            sizeof(**dir) + init_size * sizeof(WCHAR));
+    if (!*dir) return STATUS_NO_MEMORY;
+    (*dir)->used = 0;
+    (*dir)->size = init_size;
+
+    status = DOSFS_OpenDir_VFAT(table, unix_path, dir);
+
+    if (status != STATUS_SUCCESS)
+        status = DOSFS_OpenDir_Normal(table, unix_path, dir);
+
+    if (status != STATUS_SUCCESS)
+    {
+        RtlFreeHeap(ntdll_get_process_heap(), 0, *dir);
+        *dir = NULL;
+    }
+    else (*dir)->used = 0;
+
+    return status;
+}
+
+
+/***********************************************************************
+ *           DOSFS_CloseDir
+ */
+static void DOSFS_CloseDir(DOS_DIR *dir)
+{
+    RtlFreeHeap(ntdll_get_process_heap(), 0, dir);
+}
+
+
+/***********************************************************************
+ *           DOSFS_ReadDir
+ */
+static NTSTATUS DOSFS_ReadDir(DOS_DIR *dir, LPCWSTR *long_name,
+                              LPCWSTR *short_name)
+{
+    LPCWSTR sn, ln;
+
+    /* the long pathname is first */
+    ln = &dir->names[dir->used];
+    if (!ln[0]) return STATUS_NO_MORE_ENTRIES;
+    *long_name  = ln;
+    dir->used += (strlenW(ln) + 1);
+
+    /* followed by the short path name */
+    sn = &dir->names[dir->used];
+    if (sn[0])
+        *short_name = sn;
+    else
+        *short_name = NULL;
+    dir->used += (strlenW(sn) + 1);
+
+    return STATUS_SUCCESS;
+}
+
+
+/******************************************************************
+ *		append
+ *
+ *
+ */
+static  NTSTATUS append(struct nt_to_unix_path* paths, 
+                        const union cptable* cptable,
+                        LPCWSTR element, unsigned len,  
+                        BOOL last, BOOL ignore_case, BOOL check)
+{
+    static WCHAR sepW[] = {'\\', '\0'};
+
+    WCHAR       dos_name[12], tmp_buf[13];
+    LPCWSTR     long_name, short_name;
+    DOS_DIR*    dir;
+    NTSTATUS    status = STATUS_SUCCESS;
+
+    TRACE("(%s + %s@%d last%c nocase%c check%c)\n", debugstr_an(paths->unix_str.Buffer, paths->unix_str.Length),
+          debugstr_wn(element, len), len, last ? '+':'-', ignore_case?'+':'-',check?'+':'-');
+
+    if (check)
+    {
+        if (!DOSFS_ToDosFCBFormat(element, dos_name)) dos_name[0] = '\0';
+
+        if ((status = DOSFS_OpenDir(cptable, paths->unix_str.Buffer, &dir)) != STATUS_SUCCESS)
+        {
+            WARN("(%s,%s): can't open dir: %s\n",
+                 paths->unix_str.Buffer, debugstr_w(element), strerror(errno));
+            return status;
+        }
+
+        while ((status = DOSFS_ReadDir(dir, &long_name, &short_name)) == STATUS_SUCCESS)
+        {
+            /* Check against Unix name */
+            if (len == strlenW(long_name))
+            {
+                if (!ignore_case)
+                {
+                    if (!strncmpW(long_name, element, len)) break;
+                }
+                else
+                {
+                    if (!strncmpiW(long_name, element, len)) break;
+                }
+            }
+            if (dos_name[0])
+            {
+                /* Check against hashed DOS name */
+                if (!short_name)
+                {
+                    DOSFS_Hash(long_name, tmp_buf, TRUE, ignore_case);
+                    short_name = tmp_buf;
+                }
+                if (!strcmpW(dos_name, short_name)) break;
+            }
+        }
+    }
+    else
+    {
+        long_name = element;
+        short_name = NULL;
+    }
+    if (status == STATUS_SUCCESS)
+    {
+        INT len;
+
+        len = wine_cp_wcstombs(cptable, 0, long_name, 
+                               strlenW(long_name) + 1, 
+                               &paths->unix_str.Buffer[paths->unix_str.Length], 
+                               paths->unix_str.MaximumLength - paths->unix_str.Length, 
+                               NULL, NULL);
+        if (len > 0) paths->unix_str.Length += len - 1;
+        else status = STATUS_BUFFER_TOO_SMALL;
+
+        if (status == STATUS_SUCCESS && !last)
+        {
+            paths->unix_str.Buffer[paths->unix_str.Length++] = '/';
+            paths->unix_str.Buffer[paths->unix_str.Length] = '\0';
+        }
+        if (status == STATUS_SUCCESS && paths->long_ustr.Buffer)
+        {
+            status = RtlAppendUnicodeToString(&paths->long_ustr, long_name);
+            if (!last) status = RtlAppendUnicodeToString(&paths->long_ustr, sepW);
+        }
+        if (status == STATUS_SUCCESS && paths->short_ustr.Buffer)
+        {
+            if (short_name)
+                DOSFS_ToDosDTAFormat(short_name, &paths->short_ustr);
+            else
+            {
+                DOSFS_Hash(long_name, tmp_buf, FALSE, ignore_case);
+                status = RtlAppendUnicodeToString(&paths->short_ustr, tmp_buf);
+            }
+            if (!last) status = RtlAppendUnicodeToString(&paths->short_ustr, sepW);
+        }
+        TRACE("-> %s,%s,%s (%lx)\n", 
+              paths->unix_str.Buffer, debugstr_w(long_name), 
+              paths->short_ustr.Buffer ? debugstr_w(paths->short_ustr.Buffer) : "***", status);
+    }
+    else
+        WARN("%s not found in '%s'\n", debugstr_wn(element, len), paths->unix_str.Buffer);
+    if (check) DOSFS_CloseDir(dir);
+    return status;
+}
+
+/******************************************************************
+ *		FILE_GetUnixName
+ *
+ *
+ */
+NTSTATUS FILE_GetUnixName(const UNICODE_STRING* win_ustr, BOOL check_last,
+                          struct nt_to_unix_path* paths)
+{
+    WCHAR       b[2048]; /* FIXME: make it a growable string */
+    unsigned    len = 0, dir_len = 0, name_ofs = 0, i, lasti;
+    NTSTATUS    status;
+    const union cptable* cptable;
+    unsigned    codepage;
+
+    TRACE("Lookup %s\n",
+          debugstr_wn(win_ustr->Buffer, win_ustr->Length / sizeof(WCHAR)));
+
+    SERVER_START_REQ(get_file_name)
+    {
+        wine_server_add_data(req, win_ustr->Buffer, win_ustr->Length);
+        wine_server_set_reply(req, b, sizeof(b));
+        status = wine_server_call(req);
+        if (status == STATUS_SUCCESS)
+        {
+            len = wine_server_reply_size(reply) / sizeof(WCHAR);
+            dir_len = reply->dir_len / sizeof(WCHAR);
+            name_ofs = reply->name_offset;
+            codepage = reply->codepage;
+            paths->flags = reply->flags;
+        }
+    }
+    SERVER_END_REQ;
+    if (status != STATUS_SUCCESS) return status;
+    
+    /* FIXME: should we return an error here ?? */
+    if (!(cptable = wine_cp_get_table(codepage)))
+        cptable = wine_cp_get_table(1252); /* ansi */
+
+    TRACE("\t\t=> %s extra=%s name=%s\n",
+          debugstr_wn(b, dir_len),
+          debugstr_wn(&b[dir_len], len - dir_len),
+          debugstr_wn(&win_ustr->Buffer[name_ofs], 
+                      win_ustr->Length / sizeof(WCHAR) - name_ofs));
+    if (len > dir_len)
+    {
+        int     i;
+        paths->unix_str.Length = len - dir_len;
+        /* FIXME (extra data should be ASCII, not Unicode) */
+        for (i = 0; i < len - dir_len; i++)
+            paths->unix_str.Buffer[i] = b[dir_len + i];
+        paths->unix_str.Buffer[paths->unix_str.Length++] = '/';
+    }
+    else paths->unix_str.Length = 0; /* FIXME: case of error ??? */
+    paths->unix_str.Buffer[paths->unix_str.Length] = '\0';
+
+    if (paths->short_ustr.Buffer)
+    {
+        paths->short_ustr.Length = 0;
+        paths->short_ustr.Buffer[0] = '\0';
+    }
+    if (paths->long_ustr.Buffer)
+    {
+        paths->long_ustr.Length = 0;
+        paths->long_ustr.Buffer[0] = '\0';
+    }
+    for (i = lasti = 0; i < win_ustr->Length / sizeof(WCHAR) - name_ofs; i++)
+    {
+        switch (win_ustr->Buffer[name_ofs + i])
+        {
+        case '\\':
+        case '/':
+            append(paths, cptable, &win_ustr->Buffer[name_ofs + lasti], 
+                   i - lasti, FALSE, !(paths->flags & PATHGATE_CASE_SENSITIVE), TRUE);
+            lasti = i + 1;
+            break;
+        }
+    }
+    if (i != lasti)
+        status = append(paths, cptable, &win_ustr->Buffer[name_ofs + lasti], 
+                        i - lasti, TRUE, !(paths->flags & PATHGATE_CASE_SENSITIVE), 
+                        check_last);
+
+    TRACE("\tunix=%s\n", debugstr_an(paths->unix_str.Buffer, paths->unix_str.Length));
+    if (paths->short_ustr.Buffer)
+        TRACE("\tshort=%s\n", debugstr_wn(paths->short_ustr.Buffer, paths->short_ustr.Length / sizeof(WCHAR)));
+    if (paths->long_ustr.Buffer)
+        TRACE("\tlong=%s\n", debugstr_wn(paths->long_ustr.Buffer, paths->long_ustr.Length / sizeof(WCHAR)));
+
+    return status;
+}
+
diff -u -N -r -x '*~' -x '.#*' -x CVS dlls/ntdll35/file.c dlls/ntdll/file.c
--- dlls/ntdll35/file.c	2003-08-24 10:15:12.000000000 +0200
+++ dlls/ntdll/file.c	2003-09-20 20:17:48.000000000 +0200
@@ -1,5 +1,6 @@
 /*
  * Copyright 1999, 2000 Juergen Schmied
+ *           2003, Eric Pouech
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -38,13 +39,14 @@
 #include "wine/server.h"
 #include "async.h"
 #include "ntdll_misc.h"
-#include "file.h" /* FIXME */
 #include "../files/smb.h"
 
 #include "winternl.h"
 #include "winioctl.h"
 
-WINE_DEFAULT_DEBUG_CHANNEL(ntdll);
+WINE_DEFAULT_DEBUG_CHANNEL(ntfile);
+
+static  BOOL    init_done;
 
 /**************************************************************************
  *                 NtOpenFile				[NTDLL.@]
@@ -64,61 +66,11 @@
  *  Success: 0. FileHandle and IoStatusBlock are updated.
  *  Failure: An NTSTATUS error code describing the error.
  */
-NTSTATUS WINAPI NtOpenFile(
-	OUT PHANDLE FileHandle,
-	ACCESS_MASK DesiredAccess,
-	POBJECT_ATTRIBUTES ObjectAttributes,
-	OUT PIO_STATUS_BLOCK IoStatusBlock,
-	ULONG ShareAccess,
-	ULONG OpenOptions)
+NTSTATUS WINAPI NtOpenFile(PHANDLE phndl, ACCESS_MASK access, POBJECT_ATTRIBUTES oa,
+                           PIO_STATUS_BLOCK iosb, ULONG share, ULONG options)
 {
-	LPWSTR filename;
-	static const WCHAR szDosDevices[] = {'\\','D','o','s','D','e','v','i','c','e','s','\\',0};
-	DOS_FULL_NAME full_name;
-	NTSTATUS r;
-
-	FIXME("(%p,0x%08lx,%p,%p,0x%08lx,0x%08lx) partial stub\n",
-		FileHandle, DesiredAccess, ObjectAttributes,
-		IoStatusBlock, ShareAccess, OpenOptions);
-
-	dump_ObjectAttributes (ObjectAttributes);
-
-	if(ObjectAttributes->RootDirectory)
-	{
-		FIXME("Object root directory unknown %p\n",
-			ObjectAttributes->RootDirectory);
-		return STATUS_OBJECT_NAME_NOT_FOUND;
-	}
-
-	filename = ObjectAttributes->ObjectName->Buffer;
-
-	/* FIXME: DOSFS stuff should call here, not vice-versa */
-	if(strncmpW(filename, szDosDevices, strlenW(szDosDevices)))
-		return STATUS_OBJECT_NAME_NOT_FOUND;
-
-	/* FIXME: this calls SetLastError() -> bad */
-	if(!DOSFS_GetFullName(&filename[strlenW(szDosDevices)], TRUE,
-				&full_name))
-		return STATUS_OBJECT_NAME_NOT_FOUND;
-
-	/* FIXME: modify server protocol so
-                  create file takes an OBJECT_ATTRIBUTES structure */
-        SERVER_START_REQ( create_file )
-        {
-            req->access     = DesiredAccess;
-            req->inherit    = 0;
-            req->sharing    = ShareAccess;
-            req->create     = OPEN_EXISTING;
-            req->attrs      = 0;
-            req->drive_type = GetDriveTypeW( full_name.short_name );
-            wine_server_add_data( req, full_name.long_name, strlen(full_name.long_name) );
-            SetLastError(0);
-            r = wine_server_call( req );
-            *FileHandle = reply->handle;
-        }
-        SERVER_END_REQ;
-
-	return r;
+    return NtCreateFile(phndl, access, oa, iosb, NULL, 0, 
+                        share, FILE_OPEN, options, NULL, 0);
 }
 
 /**************************************************************************
@@ -145,25 +97,156 @@
  *  Success: 0. FileHandle and IoStatusBlock are updated.
  *  Failure: An NTSTATUS error code describing the error.
  */
-NTSTATUS WINAPI NtCreateFile(
-	OUT PHANDLE FileHandle,
-	ACCESS_MASK DesiredAccess,
-	POBJECT_ATTRIBUTES ObjectAttributes,
-	OUT PIO_STATUS_BLOCK IoStatusBlock,
-	PLARGE_INTEGER AllocateSize,
-	ULONG FileAttributes,
-	ULONG ShareAccess,
-	ULONG CreateDisposition,
-	ULONG CreateOptions,
-	PVOID EaBuffer,
-	ULONG EaLength)
-{
-	FIXME("(%p,0x%08lx,%p,%p,%p,0x%08lx,0x%08lx,0x%08lx,0x%08lx,%p,0x%08lx) stub\n",
-	FileHandle,DesiredAccess,ObjectAttributes,
-	IoStatusBlock,AllocateSize,FileAttributes,
-	ShareAccess,CreateDisposition,CreateOptions,EaBuffer,EaLength);
-	dump_ObjectAttributes (ObjectAttributes);
-	return 0;
+NTSTATUS WINAPI NtCreateFile(OUT PHANDLE FileHandle,
+                             ACCESS_MASK DesiredAccess,
+                             POBJECT_ATTRIBUTES ObjectAttributes,
+                             OUT PIO_STATUS_BLOCK IoStatusBlock,
+                             PLARGE_INTEGER AllocateSize,
+                             ULONG FileAttributes,
+                             ULONG ShareAccess,
+                             ULONG CreateDisposition,
+                             ULONG CreateOptions,
+                             PVOID EaBuffer,
+                             ULONG EaLength)
+{
+    char                buffer[2048]; /* FIXME */
+    UNICODE_STRING      ntstr;
+    struct nt_to_unix_path      paths;
+    BOOL                check_last, unix_path = FALSE;
+
+    TRACE("(%p,0x%08lx,%p,%p,%p,0x%08lx,0x%08lx,0x%08lx,0x%08lx,%p,0x%08lx)\n",
+          FileHandle,DesiredAccess,ObjectAttributes,
+          IoStatusBlock,AllocateSize,FileAttributes,
+          ShareAccess,CreateDisposition,CreateOptions,EaBuffer,EaLength);
+    dump_ObjectAttributes (ObjectAttributes);
+
+    if (AllocateSize || CreateOptions || EaBuffer || EaLength)
+    {
+        FIXME("Unsupported parameter\n");
+        return IoStatusBlock->u.Status = STATUS_NOT_IMPLEMENTED;
+    }
+    if (DesiredAccess & (FILE_LIST_DIRECTORY|FILE_TRAVERSE))
+    {
+        FIXME("Cannot handle directories yet\n");
+        return IoStatusBlock->u.Status = STATUS_NOT_IMPLEMENTED;
+    }
+    if (ObjectAttributes->RootDirectory)
+    {
+        FIXME("Cannot handle non-absolute file names yet\n");
+        return IoStatusBlock->u.Status = STATUS_NOT_IMPLEMENTED;
+    }
+    /* FIXME, the string is perhaps not null terminated */
+    if (ObjectAttributes->ObjectName->Buffer[ObjectAttributes->ObjectName->Length / sizeof(WCHAR)] != '\0')
+        FIXME("Non terminated object attribute string\n");
+
+    paths.unix_str.Buffer = buffer;
+    paths.unix_str.Length = 0;
+    paths.unix_str.MaximumLength = sizeof(buffer);
+
+    paths.short_ustr.Buffer = NULL;
+    paths.short_ustr.Length = 0;
+    paths.short_ustr.MaximumLength = 0;
+
+    paths.long_ustr.Buffer = NULL;
+    paths.long_ustr.Length = 0;
+    paths.long_ustr.MaximumLength = 0;
+
+    if (!init_done) unix_path = TRUE;
+    else if (ObjectAttributes->ObjectName->Buffer[0] == '/')
+    {
+        /* may this is a fully qualified UNIX path... try to map it to a windows pathgate
+         */
+        WCHAR   tmp[] = {'\\','?','?','\\','A',':','\\',0};
+
+        ntstr.Buffer = tmp;
+        ntstr.Length = 7 * sizeof(WCHAR);
+        ntstr.MaximumLength = 8 * sizeof(WCHAR);
+        for (tmp[4] = 'A'; tmp[4] <= 'Z'; tmp[4]++)
+        {
+            if (!FILE_GetUnixName(&ntstr, TRUE, &paths))
+            {
+                int i;
+
+                /* FIXME: use proper conversion here... (and path gate codepage) */
+                for (i = 0; i < paths.unix_str.Length; i++)
+                    if (ObjectAttributes->ObjectName->Buffer[i] != paths.unix_str.Buffer[i]) break;
+                if (i == paths.unix_str.Length)
+                {
+                    TRACE("Got mapping %s => %s\n", debugstr_w(tmp), paths.unix_str.Buffer);
+                    unix_path = TRUE;
+                    break;
+                }
+            }
+        }
+    }
+
+    if (unix_path)
+    {
+        IoStatusBlock->u.Status = RtlUnicodeStringToAnsiString(&paths.unix_str, ObjectAttributes->ObjectName, FALSE);
+    }
+    else
+    {
+        if (!RtlDosPathNameToNtPathName_U(ObjectAttributes->ObjectName->Buffer,
+                                          &ntstr, NULL, NULL))
+            return IoStatusBlock->u.Status = STATUS_OBJECT_NAME_INVALID;
+        switch (CreateDisposition)
+        {
+        case FILE_SUPERSEDE:
+        case FILE_CREATE:
+        case FILE_OPEN_IF:
+        case FILE_OVERWRITE_IF:
+            check_last = FALSE;
+            break;
+        case FILE_OPEN:
+        case FILE_OVERWRITE:
+            check_last = TRUE;
+            break;
+        default:
+            return STATUS_INVALID_PARAMETER;
+        }
+
+        IoStatusBlock->u.Status = FILE_GetUnixName(&ntstr, check_last, &paths);
+    }
+
+    if (IoStatusBlock->u.Status == STATUS_SUCCESS)
+    {
+        if (paths.unix_str.Buffer[0] == '/')
+        {
+        again:
+            SERVER_START_REQ( create_file )
+            {
+                req->access     = DesiredAccess;
+                req->inherit    = ObjectAttributes->Attributes & OBJ_INHERIT;
+                req->sharing    = ShareAccess;
+                req->create     = CreateDisposition;
+                req->attrs      = FileAttributes;
+                wine_server_add_data( req, paths.unix_str.Buffer, paths.unix_str.Length );
+                IoStatusBlock->u.Status = wine_server_call( req );
+                *FileHandle = reply->handle;
+            }
+            SERVER_END_REQ;
+
+            if (((IoStatusBlock->u.Status == STATUS_MEDIA_WRITE_PROTECTED) || 
+                 (IoStatusBlock->u.Status == STATUS_ACCESS_DENIED)) &&
+                !(paths.flags & PATHGATE_FAIL_READ_ONLY) && 
+                !(FileAttributes & FILE_ATTRIBUTE_READONLY) &&
+                (DesiredAccess & GENERIC_WRITE))
+            {
+                TRACE("Write access failed for file '%s', "
+                      "trying without write access\n", 
+                      debugstr_an(paths.unix_str.Buffer, paths.unix_str.Length));
+                DesiredAccess &= ~GENERIC_WRITE;
+                goto again;
+            }
+        }
+        else IoStatusBlock->u.Status = STATUS_NOT_IMPLEMENTED; /* device */
+    }
+
+    if (!unix_path) RtlFreeUnicodeString(&ntstr);
+
+    /* FIXME: IoStatusBlock.Information hadn't been set */
+
+    return IoStatusBlock->u.Status;
 }
 
 /***********************************************************************
@@ -250,12 +333,12 @@
  * Retrieve the Nt Status code from errno.
  * Try to be consistent with FILE_SetDosError().
  */
-static DWORD FILE_GetNtStatus(void)
+DWORD FILE_GetNtStatus(void)
 {
     int err = errno;
     DWORD nt;
 
-    TRACE( "errno = %d\n", errno );
+    TRACE( "errno = %d\n", err );
     switch (err)
     {
     case EAGAIN:       nt = STATUS_SHARING_VIOLATION;       break;
@@ -271,6 +354,7 @@
     case EINVAL:
     case ENOTEMPTY:    nt = STATUS_DIRECTORY_NOT_EMPTY;     break;
     case EPIPE:        nt = STATUS_PIPE_BROKEN;             break;
+    case ENOTDIR:      nt = STATUS_NOT_A_DIRECTORY;         break;
     case ENOEXEC:      /* ?? */
     case ESPIPE:       /* ?? */
     case EEXIST:       /* ?? */
@@ -328,6 +412,7 @@
     }
 
     io_status->Information += result;
+
     if (io_status->Information >= fileio->count || fileio->fd_type == FD_TYPE_SOCKET )
         io_status->u.Status = STATUS_SUCCESS;
     else
@@ -434,7 +519,6 @@
     switch (type)
     {
     case FD_TYPE_SMB:
-        FIXME("NIY-SMB\n");
         close(unix_handle);
         return SMB_ReadFile(hFile, buffer, length, io_status);
 
@@ -553,9 +637,6 @@
     TRACE("(%p,%p,%p,%p,%p,%p,0x%08lx,%p,%p)!\n",
           hFile,hEvent,apc,apc_user,io_status,buffer,length,offset,key);
 
-    TRACE("(%p,%p,%p,%p,%p,%p,0x%08lx,%p,%p),partial stub!\n",
-          hFile,hEvent,apc,apc_user,io_status,buffer,length,offset,key);
-
     io_status->Information = 0;
 
     io_status->u.Status = FILE_GetUnixHandleType( hFile, GENERIC_WRITE, &type, &flags, &unix_handle );
@@ -691,7 +772,7 @@
           InputBuffer, InputBufferSize, OutputBuffer, OutputBufferSize);
 
     /* FIXME: clientID hack should disappear */
-    SERVER_START_REQ( get_device_id )
+    SERVER_START_REQ( get_device_info )
     {
         req->handle = DeviceHandle;
         if (!wine_server_call( req )) clientID = reply->id;
@@ -945,7 +1026,6 @@
                 status = wine_server_call( req );
             }
             SERVER_END_REQ;
-            status = STATUS_SUCCESS;
         }
         break;
     default:
@@ -1220,3 +1300,340 @@
     SERVER_END_REQ;
     return status;
 }
+
+/***************************************************************************
+ *                       Device initialization
+ ***************************************************************************/
+
+static const WCHAR known_types[][8] =
+{
+    { 0 }, /* DRIVE_UNKNOWN */
+    { 0 }, /* DRIVE_NO_ROOT_DIR */
+    {'f','l','o','p','p','y',0}, /* DRIVE_REMOVABLE */
+    {'h','d',0}, /* DRIVE_FIXED */
+    {'n','e','t','w','o','r','k',0}, /* DRIVE_REMOTE */
+    {'c','d','r','o','m',0}, /* DRIVE_CDROM */
+    {'r','a','m','d','i','s','k',0} /* DRIVE_RAMDISK */
+};
+
+/***********************************************************************
+ *           get_device_type
+ */
+static inline UINT get_device_type(int drive, LPCWSTR value)
+{
+    int i;
+
+    for (i = 0; i < sizeof(known_types)/sizeof(known_types[0]); i++)
+    {
+        if (!strcmpiW( value, known_types[i] )) return i;
+    }
+    MESSAGE("Drive %c: unknown drive type %s, defaulting to 'hd'.\n",
+            drive, debugstr_w(value) );
+    return DRIVE_FIXED;
+}
+
+/* Known filesystem types */
+
+typedef struct
+{
+    const WCHAR name[6];
+    UINT        flags;
+} FS_DESCR;
+
+static const FS_DESCR known_filesystems[] =
+{
+    { {'u','n','i','x',0}, PATHGATE_CASE_SENSITIVE | PATHGATE_CASE_PRESERVING },
+    { {'m','s','d','o','s',0}, PATHGATE_SHORT_NAMES },
+    { {'d','o','s',0}, PATHGATE_SHORT_NAMES },
+    { {'f','a','t',0}, PATHGATE_SHORT_NAMES },
+    { {'v','f','a','t',0}, PATHGATE_CASE_PRESERVING },
+    { {'w','i','n','9','5',0}, PATHGATE_CASE_PRESERVING },
+    { { 0 }, 0 }
+};
+
+/***********************************************************************
+ *           get_fs_flags
+ */
+static UINT get_fs_flags(int drive, LPCWSTR value)
+{
+    const FS_DESCR *descr;
+
+    for (descr = known_filesystems; *descr->name; descr++)
+        if (!strcmpiW( value, descr->name )) return descr->flags;
+    MESSAGE("Drive %c: unknown filesystem type %s, defaulting to 'win95'.\n",
+            drive, debugstr_w(value) );
+    return PATHGATE_CASE_PRESERVING;
+}
+
+static NTSTATUS  create_device(DWORD type, LPCSTR device, LPCWSTR label, DWORD serial,
+                               HANDLE *hDevice)
+{
+    NTSTATUS    status;
+
+    TRACE("=> %s %s\n", debugstr_a(device), debugstr_w(label));
+    SERVER_START_REQ( create_device )
+    {
+        req->type               = type;
+        req->serial_number      = serial;
+        req->id                 = 0;
+        req->name_len           = 0;
+        req->unix_path_len      = (device) ? strlen(device) : 0;
+        req->access             = GENERIC_READ;
+        req->inherit            = FALSE;
+        if (device) wine_server_add_data( req, device, strlen(device) );
+        if (label) wine_server_add_data( req, label, strlenW(label) * sizeof(WCHAR) );
+        if (!(status = wine_server_call( req ))) *hDevice = reply->handle;
+    }
+    SERVER_END_REQ;
+    return status;
+}
+
+static void     add_node(HANDLE hDevice, 
+                         const WCHAR* root, size_t root_len, 
+                         const WCHAR* name, size_t name_len, 
+                         const WCHAR* extra, size_t extra_len, 
+                         unsigned codepage, unsigned flags)
+{
+    SERVER_START_REQ( create_pathgate )
+    {
+        req->device   = hDevice;
+        req->codepage = codepage;
+        req->flags    = flags;
+        req->root_len = root_len * sizeof(WCHAR);
+        req->name_len = name_len * sizeof(WCHAR);
+        wine_server_add_data( req, root, root_len * sizeof(WCHAR) );
+        wine_server_add_data( req, name, name_len * sizeof(WCHAR) );
+        if (extra) wine_server_add_data( req, extra, extra_len * sizeof(WCHAR));
+        wine_server_call( req );
+    }
+    SERVER_END_REQ;
+}
+
+#define IS_OPTION_TRUE(ch) ((ch) == 'y' || (ch) == 'Y' || (ch) == 't' || (ch) == 'T' || (ch) == '1')
+/* FIXME */
+extern void CDROM_InitRegistry(int);
+
+void    FILE_InitPathNameSpace(BOOL need_to_load)
+{
+    static const WCHAR       ntroot[] =  {'\\','\0'};
+    static const WCHAR       unc[] = {'U','N','C','\0'};
+    static const WCHAR       dos[] = {'?','?','\0'};
+    static const WCHAR       rdos[] = {'\\','?','?','\0'};
+
+    int         drv, len, count = 0;
+    WCHAR       driveW[] = {'M','a','c','h','i','n','e','\\','S','o','f','t','w','a','r','e','\\',
+                            'W','i','n','e','\\','W','i','n','e','\\',
+                            'C','o','n','f','i','g','\\','D','r','i','v','e',' ','A',0};
+    WCHAR       drive_env[] = {'=','A',':',0};
+#define MAX_PATHNAME_LEN        1024 /* FIXME */
+    WCHAR       path[MAX_PATHNAME_LEN];
+    char        tmp[MAX_PATHNAME_LEN*sizeof(WCHAR) + sizeof(KEY_VALUE_PARTIAL_INFORMATION)];
+    struct stat drive_stat_buffer;
+    LPWSTR      p;
+    WCHAR       label[256];
+    LPSTR       root, device;
+    HKEY        hkey;
+    HANDLE      hDevice;
+    DWORD       dummy, serial;
+    OBJECT_ATTRIBUTES attr;
+    UNICODE_STRING nameW;
+    unsigned    codepage, drivetype, driveflags;
+
+    static const WCHAR PathW[] = {'P','a','t','h',0};
+    static const WCHAR CodepageW[] = {'C','o','d','e','p','a','g','e',0};
+    static const WCHAR LabelW[] = {'L','a','b','e','l',0};
+    static const WCHAR SerialW[] = {'S','e','r','i','a','l',0};
+    static const WCHAR TypeW[] = {'T','y','p','e',0};
+    static const WCHAR FilesystemW[] = {'F','i','l','e','s','y','s','t','e','m',0};
+    static const WCHAR DeviceW[] = {'D','e','v','i','c','e',0};
+    static const WCHAR ReadVolInfoW[] = {'R','e','a','d','V','o','l','I','n','f','o',0};
+    static const WCHAR FailReadOnlyW[] = {'F','a','i','l','R','e','a','d','O','n','l','y',0};
+    static const WCHAR driveC_labelW[] = {'D','r','i','v','e',' ','C',' ',' ',' ',' ',0};
+    static const WCHAR RootW[] = {'/','\0'};
+
+    if (!need_to_load)
+    {
+        init_done = TRUE;
+        return;
+    }
+
+    /* system */
+    add_node(NULL, ntroot, strlenW(ntroot), dos, strlenW(dos), NULL, 0, 1242, 0);
+    add_node(NULL, rdos, strlenW(rdos), unc, strlenW(unc), NULL, 0, 1242, 0);
+
+    attr.Length = sizeof(attr);
+    attr.RootDirectory = 0;
+    attr.ObjectName = &nameW;
+    attr.Attributes = 0;
+    attr.SecurityDescriptor = NULL;
+    attr.SecurityQualityOfService = NULL;
+
+    /* now get the drives from configuration */
+    for (drv = 'A'; drv <= 'Z'; drv++)
+    {
+        RtlInitUnicodeString( &nameW, driveW );
+        nameW.Buffer[(nameW.Length / sizeof(WCHAR)) - 1] = drv;
+        if (NtOpenKey( &hkey, KEY_ALL_ACCESS, &attr ) != STATUS_SUCCESS) continue;
+
+        /* Get the code page number */
+        RtlInitUnicodeString( &nameW, CodepageW );
+        if (!NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &dummy ))
+        {
+            WCHAR *data = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
+            codepage = strtolW( data, NULL, 10 );
+        } else codepage = 1252; /* ansi */
+
+        /* Get the root path */
+        RtlInitUnicodeString( &nameW, PathW );
+        if (!NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &dummy ))
+        {
+            WCHAR *data = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
+            ExpandEnvironmentStringsW( data, path, sizeof(path)/sizeof(WCHAR) );
+
+            p = path + strlenW(path) - 1;
+            while ((p > path) && (*p == '/')) *p-- = '\0';
+
+            if (path[0] == '/')
+            {
+                len = WideCharToMultiByte(codepage, 0, path, -1, NULL, 0, NULL, NULL);
+                root = RtlAllocateHeap(ntdll_get_process_heap(), 0, len);
+                WideCharToMultiByte(codepage, 0, path, -1, root, len, NULL, NULL);
+            }
+            else
+            {
+                /* relative paths are relative to config dir */
+                const char *config = wine_get_config_dir();
+                len = strlen(config);
+                len += WideCharToMultiByte(codepage, 0, path, -1, NULL, 0, NULL, NULL) + 2;
+                root = RtlAllocateHeap( ntdll_get_process_heap(), 0, len );
+                len -= sprintf( root, "%s/", config );
+                WideCharToMultiByte(codepage, 0, path, -1,
+                                    root + strlen(root), len, NULL, NULL);
+                FIXME("path isn't yet converted to a full unix path... won't work!!!\n");
+            }
+
+            if (stat( root, &drive_stat_buffer ))
+            {
+                MESSAGE("Could not stat %s (%s), ignoring drive %c:\n",
+                        root, strerror(errno), drv);
+                RtlFreeHeap( ntdll_get_process_heap(), 0, root );
+                root = NULL;
+                goto next;
+            }
+            if (!S_ISDIR(drive_stat_buffer.st_mode))
+            {
+                MESSAGE("%s is not a directory, ignoring drive %c:\n", root, drv );
+                RtlFreeHeap( ntdll_get_process_heap(), 0, root );
+                root = NULL;
+                goto next;
+            }
+
+            /* Get the drive type */
+            RtlInitUnicodeString( &nameW, TypeW );
+            if (!NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &dummy ))
+            {
+                WCHAR *data = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
+                drivetype = get_device_type( drv, data );
+            }
+            else drivetype = DRIVE_FIXED;
+
+            /* Get the drive label */
+            RtlInitUnicodeString( &nameW, LabelW );
+            if (!NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &dummy ))
+            {
+                WCHAR*  data = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
+                strncpyW(label, data, sizeof(label) / sizeof(WCHAR));
+            } else label[0] = '\0';
+            if ((len = strlenW(label)) < 11)
+            {
+                /* Pad label with spaces */
+                while (len < 11) label[len++] = ' ';
+                label[11] = '\0';
+            }
+
+            /* Get the serial number */
+            RtlInitUnicodeString( &nameW, SerialW );
+            if (!NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &dummy ))
+            {
+                WCHAR *data = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
+                serial = strtoulW( data, NULL, 16 );
+            }
+            else serial = 12345678;
+
+            /* Get the filesystem type */
+            RtlInitUnicodeString( &nameW, FilesystemW );
+            if (!NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &dummy ))
+            {
+                WCHAR *data = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
+                driveflags = get_fs_flags( drv,  data );
+            }
+            else driveflags = PATHGATE_CASE_PRESERVING;
+
+            /* Get the device */
+            RtlInitUnicodeString( &nameW, DeviceW );
+            if (!NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &dummy ))
+            {
+                WCHAR *data = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
+                len = WideCharToMultiByte(CP_ACP, 0, data, -1, NULL, 0, NULL, NULL);
+                device = RtlAllocateHeap(ntdll_get_process_heap(), 0, len);
+                WideCharToMultiByte(codepage, 0, data, -1, device, len, NULL, NULL);
+
+                RtlInitUnicodeString( &nameW, ReadVolInfoW );
+                if (!NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &dummy ))
+                {
+                    WCHAR *data = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
+                    /* FIXME: this shouldn't be a pathgate option but a device option !!!! */
+                    if (IS_OPTION_TRUE(data[0])) driveflags |= PATHGATE_READ_VOL_INFO;
+                }
+                else driveflags |= PATHGATE_READ_VOL_INFO;
+
+                if (drivetype == DRIVE_CDROM)
+                {
+                    int cd_fd;
+                    if ((cd_fd = open(device, O_RDONLY|O_NONBLOCK)) != -1)
+                    {
+                        CDROM_InitRegistry(cd_fd);
+                        close(cd_fd);
+                    }
+                }
+            } else device = NULL;
+
+            /* Get the FailReadOnly flag */
+            RtlInitUnicodeString( &nameW, FailReadOnlyW );
+            if (!NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &dummy ))
+            {
+                WCHAR *data = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
+                if (IS_OPTION_TRUE(data[0])) driveflags |= PATHGATE_FAIL_READ_ONLY;
+            }
+
+            TRACE("Drive %c: path=%s type=%d label=%s serial=%08lx "
+                  "flags=%08x codepage=%u\n",
+                  drv, root, drivetype, debugstr_w(label), serial, driveflags, codepage);
+            if (!create_device(drivetype, device, label, serial, &hDevice))
+            {
+                count++;
+                drive_env[1] = drv;
+                TRACE("Adding drive %c => %s/%s\n", drv, root, debugstr_w(path));
+                add_node(hDevice, rdos, strlenW(rdos), drive_env + 1, strlenW(drive_env + 1), 
+                         path, strlenW(path), codepage, 0);
+                NtClose(hDevice);
+            } else ERR("Failed to init drive %c\n", drv);
+        }
+
+    next:
+        NtClose( hkey );
+    }
+    if (!count)
+    {
+        MESSAGE("Warning: no valid DOS drive found, check your configuration file.\n" );
+        /* Create a C drive pointing to Unix root dir */
+        if (!create_device(DRIVE_FIXED, NULL, driveC_labelW, 12345678, &hDevice))
+        {
+            drive_env[1] = 'C';
+            add_node(hDevice, rdos, strlenW(rdos), drive_env + 1, strlenW(drive_env + 1), 
+                     RootW, 1, 1252, 0);
+            NtClose(hDevice);
+        } else ERR("Failed to fall back to minimum settings\n");
+    }
+    init_done = TRUE;
+}
diff -u -N -r -x '*~' -x '.#*' -x CVS dlls/ntdll35/Makefile.in dlls/ntdll/Makefile.in
--- dlls/ntdll35/Makefile.in	2003-09-19 19:02:40.000000000 +0200
+++ dlls/ntdll/Makefile.in	2003-09-19 18:55:46.000000000 +0200
@@ -36,6 +36,7 @@
 	cdrom.c \
 	critsection.c \
 	debugtools.c \
+	dos_fs.c \
 	env.c \
 	error.c \
 	exception.c \
diff -u -N -r -x '*~' -x '.#*' -x CVS dlls/ntdll35/ntdll_misc.h dlls/ntdll/ntdll_misc.h
--- dlls/ntdll35/ntdll_misc.h	2003-09-19 19:02:40.000000000 +0200
+++ dlls/ntdll/ntdll_misc.h	2003-09-19 18:55:47.000000000 +0200
@@ -57,6 +57,25 @@
     return NtCurrentTeb()->Peb->ProcessParameters;
 }
 
+/* File IO */
+/* path gates options */
+#define PATHGATE_SHORT_NAMES     0x0002  /* Drive fs has 8.3 file names */
+#define PATHGATE_CASE_SENSITIVE  0x0004  /* Drive fs is case sensitive */
+#define PATHGATE_CASE_PRESERVING 0x0008  /* Drive fs is case preserving */
+#define PATHGATE_FAIL_READ_ONLY  0x0010  /* Fail opening read-only files for writing */
+#define PATHGATE_READ_VOL_INFO   0x0020  /* Try to read volume info from the device? */
+
+struct nt_to_unix_path {
+    ANSI_STRING         unix_str;
+    UNICODE_STRING      short_ustr;
+    UNICODE_STRING      long_ustr;
+    unsigned            flags;
+};
+extern NTSTATUS FILE_GetUnixName(const UNICODE_STRING* win_ustr, BOOL check_last,
+                                 struct nt_to_unix_path* n2up);
+
+extern DWORD FILE_GetNtStatus(void);
+
 /* Device IO */
 /* ntdll/cdrom.c.c */
 extern NTSTATUS CDROM_DeviceIoControl(DWORD clientID, HANDLE hDevice, 
diff -u -N -r -x '*~' -x '.#*' -x CVS files35/dos_fs.c files/dos_fs.c
--- files35/dos_fs.c	2003-09-18 20:48:44.000000000 +0200
+++ files/dos_fs.c	2003-09-20 18:31:27.000000000 +0200
@@ -854,7 +854,7 @@
 const DOS_DEVICE *DOSFS_GetDeviceByHandle( HANDLE hFile )
 {
     const DOS_DEVICE *ret = NULL;
-    SERVER_START_REQ( get_device_id )
+    SERVER_START_REQ( get_device_info )
     {
         req->handle = hFile;
         if (!wine_server_call( req ))
diff -u -N -r -x '*~' -x '.#*' -x CVS files35/file.c files/file.c
--- files35/file.c	2003-09-18 20:48:44.000000000 +0200
+++ files/file.c	2003-09-20 20:31:01.000000000 +0200
@@ -404,55 +404,52 @@
                         DWORD attributes, HANDLE template, BOOL fail_read_only,
                         UINT drive_type )
 {
-    unsigned int err;
-    HANDLE ret;
-
-    for (;;)
-    {
-        SERVER_START_REQ( create_file )
-        {
-            req->access     = access;
-            req->inherit    = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
-            req->sharing    = sharing;
-            req->create     = creation;
-            req->attrs      = attributes;
-            req->drive_type = drive_type;
-            wine_server_add_data( req, filename, strlen(filename) );
-            SetLastError(0);
-            err = wine_server_call( req );
-            ret = reply->handle;
-        }
-        SERVER_END_REQ;
-
-        /* If write access failed, retry without GENERIC_WRITE */
-
-        if (!ret && !fail_read_only && (access & GENERIC_WRITE))
-        {
-            if ((err == STATUS_MEDIA_WRITE_PROTECTED) || (err == STATUS_ACCESS_DENIED))
-            {
-                TRACE("Write access failed for file '%s', trying without "
-                      "write access\n", filename);
-                access &= ~GENERIC_WRITE;
-                continue;
-            }
-        }
-
-        if (err)
-        {
-            /* In the case file creation was rejected due to CREATE_NEW flag
-             * was specified and file with that name already exists, correct
-             * last error is ERROR_FILE_EXISTS and not ERROR_ALREADY_EXISTS.
-             * Note: RtlNtStatusToDosError is not the subject to blame here.
-             */
-            if (err == STATUS_OBJECT_NAME_COLLISION)
-                SetLastError( ERROR_FILE_EXISTS );
-            else
-                SetLastError( RtlNtStatusToDosError(err) );
-        }
+    HANDLE              hFile;
+    UNICODE_STRING      ustr;
+    OBJECT_ATTRIBUTES   oa;
+    IO_STATUS_BLOCK     iosb;
+    ULONG               disp;
 
-        if (!ret) WARN("Unable to create file '%s' (GLE %ld)\n", filename, GetLastError());
-        return ret;
+    oa.Length = sizeof(oa);
+    oa.ObjectName = &ustr;
+    oa.RootDirectory = 0;
+    oa.SecurityDescriptor = NULL;
+    oa.SecurityQualityOfService = NULL;
+    oa.Attributes = 0;
+    if (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle) 
+        oa.Attributes |= OBJ_INHERIT;
+
+    RtlCreateUnicodeStringFromAsciiz(&ustr, filename);
+
+    switch (creation)
+    {
+    case CREATE_ALWAYS:     disp = FILE_SUPERSEDE; break;
+    case CREATE_NEW:        disp = FILE_CREATE; break;
+    case OPEN_ALWAYS:       disp = FILE_OPEN_IF; break;
+    case OPEN_EXISTING:     disp = FILE_OPEN; break;
+    case TRUNCATE_EXISTING: disp = FILE_OVERWRITE; break;
+    default: FIXME("Unknown creation flag\n"); disp = FILE_OPEN;
+    }
+    NtCreateFile(&hFile, access, &oa, &iosb, NULL, attributes, 
+                 sharing, disp, 0, NULL, 0);
+    RtlFreeUnicodeString(&ustr);
+
+    if (iosb.u.Status)
+    {
+        /* In the case file creation was rejected due to CREATE_NEW flag
+         * was specified and file with that name already exists, correct
+         * last error is ERROR_FILE_EXISTS and not ERROR_ALREADY_EXISTS.
+         * Note: RtlNtStatusToDosError is not the subject to blame here.
+         */
+        if (iosb.u.Status == STATUS_OBJECT_NAME_COLLISION)
+            SetLastError( ERROR_FILE_EXISTS );
+        else
+            SetLastError( RtlNtStatusToDosError(iosb.u.Status) );
+        hFile = 0;
     }
+
+    if (!hFile) WARN("Unable to create file '%s' (GLE %ld)\n", filename, GetLastError());
+    return hFile;
 }
 
 
@@ -465,11 +462,16 @@
 HANDLE FILE_CreateDevice( int client_id, DWORD access, LPSECURITY_ATTRIBUTES sa )
 {
     HANDLE ret;
+
     SERVER_START_REQ( create_device )
     {
-        req->access  = access;
-        req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
-        req->id      = client_id;
+        req->type               = DRIVE_UNKNOWN;
+        req->serial_number      = 0;
+        req->id                 = client_id;
+        req->name_len           = 0;
+        req->unix_path_len      = 0;
+        req->access             = access;
+        req->inherit            = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
         SetLastError(0);
         wine_server_call_err( req );
         ret = reply->handle;
@@ -1702,7 +1704,7 @@
 
     /* check if we are allowed to delete the source */
     hFile = FILE_CreateFile( full_name.long_name, GENERIC_READ|GENERIC_WRITE, 0,
-                             NULL, OPEN_EXISTING, 0, 0, TRUE,
+                             NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, 0, TRUE,
                              GetDriveTypeW( full_name.short_name ) );
     if (!hFile) return FALSE;
 
@@ -1985,7 +1987,7 @@
 
         /* check if we are allowed to rename the source */
         hFile = FILE_CreateFile( full_name1.long_name, 0, 0,
-                                 NULL, OPEN_EXISTING, 0, 0, TRUE,
+                                 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, 0, TRUE,
                                  GetDriveTypeW( full_name1.short_name ) );
         if (!hFile)
         {
@@ -1998,7 +2000,7 @@
         /* check, if we are allowed to delete the destination,
         **     (but the file not being there is fine) */
         hFile = FILE_CreateFile( full_name2.long_name, GENERIC_READ|GENERIC_WRITE, 0,
-                                 NULL, OPEN_EXISTING, 0, 0, TRUE,
+                                 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, 0, TRUE,
                                  GetDriveTypeW( full_name2.short_name ) );
         if(!hFile && GetLastError() != ERROR_FILE_NOT_FOUND) return FALSE;
         CloseHandle(hFile);
diff -u -N -r -x '*~' -x '.#*' -x CVS include35/winternl.h include/winternl.h
--- include35/winternl.h	2003-09-18 20:48:47.000000000 +0200
+++ include/winternl.h	2003-09-16 21:25:05.000000000 +0200
@@ -912,6 +912,15 @@
 #define FILE_EXISTS      0x00000004
 #define FILE_DOES_NOT_EXIST 0x00000005
 
+/* disposition for NtCreateFile */
+#define FILE_SUPERSEDE                  0x0000
+#define FILE_OPEN                       0x0001
+#define FILE_CREATE                     0x0002
+#define FILE_OPEN_IF                    0x0003
+#define FILE_OVERWRITE                  0x0004
+#define FILE_OVERWRITE_IF               0x0005
+#define FILE_MAXIMUM_DISPOSITION        0x0005
+
 #if (_WIN32_WINNT >= 0x0501)
 #define INTERNAL_TS_ACTIVE_CONSOLE_ID ( *((volatile ULONG*)(0x7ffe02d8)) )
 #endif /* (_WIN32_WINNT >= 0x0501) */
diff -u -N -r -x '*~' -x '.#*' -x CVS misc35/registry.c misc/registry.c
--- misc35/registry.c	2003-09-19 19:02:46.000000000 +0200
+++ misc/registry.c	2003-09-20 17:59:16.000000000 +0200
@@ -1648,7 +1648,7 @@
 
 
 /* load all registry (native and global and home) */
-void SHELL_LoadRegistry( void )
+BOOL SHELL_LoadRegistry( void )
 {
     HKEY hkey_local_machine, hkey_users, hkey_users_default, hkey_current_user, hkey_config;
     OBJECT_ATTRIBUTES attr;
@@ -1691,7 +1691,7 @@
     {
         /* someone else already loaded the registry */
         NtClose( hkey_users );
-        return;
+        return FALSE;
     }
 
     RtlInitUnicodeString( &nameW, MachineW );
@@ -1817,4 +1817,6 @@
     NtClose(hkey_users);
     NtClose(hkey_local_machine);
     NtClose(hkey_config);
+
+    return TRUE;
 }
diff -u -N -r -x '*~' -x '.#*' -x CVS server35/device.c server/device.c
--- server35/device.c	2003-09-13 21:07:01.000000000 +0200
+++ server/device.c	2003-09-20 18:28:42.000000000 +0200
@@ -34,6 +34,7 @@
 #include "windef.h"
 #include "winbase.h"
 
+#include "unicode.h"
 #include "handle.h"
 #include "thread.h"
 #include "request.h"
@@ -41,7 +42,11 @@
 struct device
 {
     struct object  obj;             /* object header */
+    int            type;            /* device type */
+    int            serial_number;   /* device serial number */
     int            id;              /* client identifier */
+    char*          device_name;     /* unix path to device */
+    WCHAR*         label;           /* label of device */
 };
 
 static void device_dump( struct object *obj, int verbose );
@@ -58,45 +63,104 @@
     no_destroy                /* destroy */
 };
 
-static struct device *create_device( int id )
+static struct device *create_device(int type, LPCSTR unix_path, size_t unix_path_len,
+                                    LPCWSTR label, size_t label_len,
+                                    int serial,  int id)
 {
     struct device *dev;
+    size_t      len = 0;
+    char*       ptr = NULL;
+
+    if (unix_path) len += unix_path_len + 1;
+    if (label)     len += label_len + sizeof(WCHAR);
+    if (len && !(ptr = malloc(len)))
+    {
+        set_error(STATUS_NO_MEMORY);
+        return NULL;
+    }
+
     if ((dev = alloc_object( &device_ops )))
     {
-        dev->id = id;
+        dev->type           = type;
+        dev->serial_number  = serial;
+        dev->id             = id;
+        if (label)
+        {
+            dev->label = (WCHAR*)ptr;
+            memcpy(dev->label, label, label_len);
+            dev->label[label_len / sizeof(WCHAR)] = '\0';
+            ptr += label_len + sizeof(WCHAR);
+        } else dev->label = NULL;
+        if (unix_path)
+        {
+            dev->device_name = ptr;
+            memcpy(dev->device_name, unix_path, unix_path_len);
+            dev->device_name[unix_path_len] = '\0';
+        } else dev->device_name = NULL;
     }
     return dev;
+    
 }
 
 static void device_dump( struct object *obj, int verbose )
 {
     struct device *dev = (struct device *)obj;
     assert( obj->ops == &device_ops );
-    fprintf( stderr, "Device id=%08x\n", dev->id );
+    fprintf( stderr, "Device type=%d id=%08x serial=%08x unix=%s label=", 
+             dev->type, dev->id, dev->serial_number, dev->device_name ? dev->device_name : "[None]");
+    dump_strW(dev->label, dev->label ? strlenW(dev->label) : 0, stderr, "[None]");
+    fprintf( stderr, "\n" );
+}
+
+struct device *get_device_obj( struct process *process, obj_handle_t handle, unsigned int access )
+{
+    return (struct device *)get_handle_obj( process, handle, access, &device_ops );
 }
 
-/* create a device */
+/* creates (installs) a new device */
 DECL_HANDLER(create_device)
 {
-    struct device *dev;
+    LPWSTR              name = NULL, label = NULL;
+    LPSTR               unix_path = NULL;
+    size_t              len = get_req_data_size();
+    struct device*      dev;
+
+    if (req->name_len) name = (WCHAR*)get_req_data();
+    if (req->unix_path_len) unix_path = ((char*)get_req_data() + req->name_len);
+    if (req->name_len + req->unix_path_len < len)
+        label = (WCHAR*)((char*)get_req_data() + req->name_len + req->unix_path_len);
 
+    /* FIXME: for now, don't take care of name */
     reply->handle = 0;
-    if ((dev = create_device( req->id )))
+    dev = create_device(req->type, unix_path, req->unix_path_len, 
+                        label, label ? (len - (req->name_len + req->unix_path_len)) : 0,
+                        req->serial_number, req->id);
+    if (dev)
     {
         reply->handle = alloc_handle( current->process, dev, req->access, req->inherit );
         release_object( dev );
     }
 }
 
-
-/* Retrieve the client private id for a device */
-DECL_HANDLER(get_device_id)
+/* get information on an installed device */
+DECL_HANDLER(get_device_info)
 {
     struct device *dev;
 
-    if ((dev = (struct device *)get_handle_obj( current->process, req->handle, 0, &device_ops )))
+    if ((dev = (struct device *)get_handle_obj( current->process, req->handle, GENERIC_READ, &device_ops )))
     {
-        reply->id = dev->id;
+        reply->type             = dev->type;
+        reply->serial_number    = dev->serial_number;
+        reply->id               = dev->id;      
+        if (dev->label) set_reply_data(dev->label, strlenW(dev->label) * sizeof(WCHAR));
+
         release_object( dev );
     }
 }
+
+/* open an existing device */
+DECL_HANDLER(open_device)
+{
+    set_error(STATUS_NOT_IMPLEMENTED);
+}
+
diff -u -N -r -x '*~' -x '.#*' -x CVS server35/file.c server/file.c
--- server35/file.c	2003-09-13 21:07:01.000000000 +0200
+++ server/file.c	2003-09-14 14:24:27.000000000 +0200
@@ -43,6 +43,8 @@
 #include "winerror.h"
 #include "windef.h"
 #include "winbase.h"
+#include "winreg.h"
+#include "winternl.h"
 
 #include "file.h"
 #include "handle.h"
@@ -162,8 +164,7 @@
 
 
 static struct file *create_file( const char *nameptr, size_t len, unsigned int access,
-                                 unsigned int sharing, int create, unsigned int attrs,
-                                 int drive_type )
+                                 unsigned int sharing, int create, unsigned int attrs)
 {
     struct file *file;
     int hash, flags;
@@ -180,11 +181,12 @@
 
     switch(create)
     {
-    case CREATE_NEW:        flags = O_CREAT | O_EXCL; break;
-    case CREATE_ALWAYS:     flags = O_CREAT | O_TRUNC; break;
-    case OPEN_ALWAYS:       flags = O_CREAT; break;
-    case TRUNCATE_EXISTING: flags = O_TRUNC; break;
-    case OPEN_EXISTING:     flags = 0; break;
+    case FILE_CREATE:       flags = O_CREAT | O_EXCL; break;
+    case FILE_OVERWRITE_IF: /* FIXME: the difference is whether we trash existing attr or not */
+    case FILE_SUPERSEDE:    flags = O_CREAT | O_TRUNC; break;
+    case FILE_OPEN:         flags = 0; break;
+    case FILE_OPEN_IF:      flags = O_CREAT; break;
+    case FILE_OVERWRITE:    flags = O_TRUNC; break;
     default:                set_error( STATUS_INVALID_PARAMETER ); goto error;
     }
     switch(access & (GENERIC_READ | GENERIC_WRITE))
@@ -205,7 +207,7 @@
     file->access     = access;
     file->flags      = attrs;
     file->sharing    = sharing;
-    file->drive_type = drive_type;
+    file->drive_type = 0; /* FIXME: this shall go away anyway */
     file->name       = name;
     file->next       = file_hash[hash];
     file_hash[hash]  = file;
@@ -598,7 +600,7 @@
 
     reply->handle = 0;
     if ((file = create_file( get_req_data(), get_req_data_size(), req->access,
-                             req->sharing, req->create, req->attrs, req->drive_type )))
+                             req->sharing, req->create, req->attrs )))
     {
         reply->handle = alloc_handle( current->process, file, req->access, req->inherit );
         release_object( file );
diff -u -N -r -x '*~' -x '.#*' -x CVS server35/Makefile.in server/Makefile.in
--- server35/Makefile.in	2003-08-24 10:18:16.000000000 +0200
+++ server/Makefile.in	2003-09-20 10:37:26.000000000 +0200
@@ -26,6 +26,7 @@
 	mutex.c \
 	named_pipe.c \
 	object.c \
+	pathgate.c \
 	process.c \
 	ptrace.c \
 	queue.c \
diff -u -N -r -x '*~' -x '.#*' -x CVS server35/object.h server/object.h
--- server35/object.h	2003-09-13 21:07:01.000000000 +0200
+++ server/object.h	2003-09-20 12:33:55.000000000 +0200
@@ -161,6 +161,13 @@
 extern int grab_global_atom( atom_t atom );
 extern void release_global_atom( atom_t atom );
 
+/* pathgates functions */
+extern void close_pathgates(void);
+
+/* device functions */
+extern struct device *get_device_obj( struct process *process, obj_handle_t handle,
+                                      unsigned int access );
+
 /* global variables */
 
   /* command-line options */
diff -u -N -r -x '*~' -x '.#*' -x CVS server35/pathgate.c server/pathgate.c
--- server35/pathgate.c	1970-01-01 01:00:00.000000000 +0100
+++ server/pathgate.c	2003-09-20 17:13:13.000000000 +0200
@@ -0,0 +1,250 @@
+/*
+ * Server-side file name space management
+ *
+ * Copyright (C) 2003 Eric Pouech
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "config.h"
+#include "wine/port.h"
+
+#include <assert.h>
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <signal.h>
+
+#include "handle.h"
+#include "process.h"
+#include "request.h"
+#include "unicode.h"
+
+struct dir_node
+{
+    enum dir_node_type {regular, dlink} type;
+    struct dir_node*    children;       /* linked list of children */
+    struct dir_node*    next;           /* link to sibling */
+    struct device*      device;         /* pointer to device (if any) */
+    unsigned            codepage;
+    unsigned            flags;
+    WCHAR*              extra;          /* extra information (mount point) */
+    size_t              extra_len;      /* sizeof of extra information */
+    struct dir_node*    parent;         /* parent node */
+    WCHAR               name[1];        /* name of current node */
+};
+
+static  struct dir_node all_root = {regular, NULL, NULL, NULL, 1242, 0, NULL, 0, NULL, {'\0'}};
+
+static struct dir_node* create_node(struct device* dev, 
+                                    const WCHAR* name, size_t name_len, 
+                                    enum dir_node_type type, 
+                                    const WCHAR* extra, size_t extra_len,
+                                    unsigned codepage, unsigned flags)
+{
+    struct dir_node*    node;
+
+    if ((node = malloc(sizeof(struct dir_node) + name_len + sizeof(WCHAR) + extra_len)))
+    {
+        node->device = dev;
+        node->type = type;
+        node->children = NULL;
+        node->codepage = codepage;
+        node->flags = flags;
+        if (extra)
+        {
+            node->extra = (WCHAR*)((char*)node + sizeof(struct dir_node) + name_len);
+            memcpy(node->extra, extra, extra_len);
+        }
+        else node->extra = NULL;
+        node->extra_len = extra_len;
+        node->next = NULL;
+        memcpy(node->name, name, name_len);
+        node->name[name_len / sizeof(WCHAR)] = '\0';
+    }
+    else set_error(STATUS_NO_MEMORY);
+    return node;
+}
+
+static void     delete_node(struct dir_node* node)
+{
+    struct dir_node*    child;
+    struct dir_node*    next;
+
+    for (child = node->children; child; child = next)
+    {
+        next = child->next;
+        delete_node(child);
+    }
+    if (node->device) release_object(node->device);
+    if (node != &all_root) free(node);
+}
+
+void close_pathgates(void)
+{
+    delete_node(&all_root);
+}
+
+static void     add_child(struct dir_node* parent, struct dir_node* new)
+{
+    new->parent = parent;
+    new->next = parent->children;
+    parent->children = new;
+}
+
+static struct dir_node* lookup(const WCHAR* name, size_t len, const WCHAR** ret)
+{
+    struct dir_node* node;
+    struct dir_node* child;
+    size_t elen;
+
+    len /= sizeof(WCHAR);
+
+    name++; /* skip first '\\' */
+    len--;
+
+    node = &all_root;
+    if (!*name) return node;
+
+    while (node->children)
+    {
+        for (elen = 0; elen < len; elen++)
+            if (name[elen] == '\\') break;
+
+        for (child = node->children; child; child = child->next)
+        {
+            if (elen == strlenW(child->name) && strncmpiW(child->name, name, elen) == 0)
+                break;
+        }
+        if (!child) return NULL;
+        switch (child->type)
+        {
+        case dlink:
+            if (elen == len)
+            {
+                return lookup(child->extra, child->extra_len, ret);
+            }
+            else
+            {
+                WCHAR*  target;
+                size_t  xlen;
+                
+                xlen = child->extra_len / sizeof(WCHAR);
+                target = malloc((xlen + len - elen + 1) * sizeof(WCHAR));
+                memcpy(target, child->extra, xlen * sizeof(WCHAR));
+                target[xlen] = '\\';
+                memcpy(target + xlen + 1, name + elen + 1, (len - elen) * sizeof(WCHAR));
+                node = lookup(target, (xlen + len - elen) * sizeof(WCHAR), ret);
+                if (*ret) *ret = name + (xlen + len - elen) - (*ret - target + xlen - 1);
+                free(target);
+                return node;
+            }
+            break;
+        case regular:
+            node = child;
+            break;
+        }
+        
+        if (elen == len) break;
+        len -= elen + 1;
+        name += elen + 1;
+    }
+    if (node) *ret = name;
+    return node;
+}
+
+static void add_node(struct device* dev, 
+                     const WCHAR* root, size_t root_len, 
+                     const WCHAR* name, size_t name_len, 
+                     enum dir_node_type type, 
+                     const WCHAR* extra, size_t extra_len,
+                     unsigned codepage, unsigned flags)
+{
+    struct dir_node* parent;
+    struct dir_node* child;
+    const WCHAR* left;
+
+    if ((parent = lookup(root, root_len, &left)))
+    {
+        child = create_node(dev, name, name_len, type, extra, extra_len, codepage, flags);
+        add_child(parent, child);
+    }
+    else set_error(STATUS_OBJECT_PATH_NOT_FOUND);
+}
+
+DECL_HANDLER(create_pathgate)
+{
+    size_t              len = get_req_data_size();
+    size_t              extra_len;
+    const WCHAR*        data = get_req_data();
+    struct device*      dev = NULL;
+
+    if (!req->device ||
+        (dev = get_device_obj(current->process, req->device, GENERIC_READ)))
+    {
+        extra_len = len - (req->root_len + req->name_len);
+
+        add_node(dev, data, req->root_len, 
+                 data + req->root_len / sizeof(WCHAR), req->name_len, 
+                 regular, 
+                 extra_len ? data + (req->root_len + req->name_len) / sizeof(WCHAR) : NULL, 
+                 extra_len, req->codepage, req->flags);
+    }
+}
+
+DECL_HANDLER(get_file_name)
+{
+    const WCHAR*        p;
+    struct dir_node*    node;
+    const WCHAR*        dirname = get_req_data();
+    struct dir_node*    pp;
+    size_t              rlen, pos, elen;
+    WCHAR*              ptr;
+
+    node = lookup(dirname, get_req_data_size(), &p);
+    if (!node)
+    {
+        set_error(STATUS_OBJECT_NAME_NOT_FOUND);
+        return;
+    }
+
+    reply->dir_len = 0;
+    for (pp = node; pp; pp = pp->parent)
+    {
+        reply->dir_len += strlenW(pp->name) + 1;
+    }
+    reply->dir_len--;
+    reply->name_offset = p - dirname;
+    ptr = malloc(rlen = reply->dir_len * sizeof(WCHAR) + node->extra_len);
+    if (ptr)
+    {
+        pos = reply->dir_len;
+        for (pp = node; pp; pp = pp->parent)
+        {
+            elen = strlenW(pp->name);
+            pos -= elen;
+            memcpy(ptr + pos, pp->name, elen * sizeof(WCHAR));
+            if (pos > 0) ptr[--pos] = '/';
+        }
+        if (node->extra)
+            memcpy(ptr + reply->dir_len, node->extra, node->extra_len);
+        reply->dir_len *= sizeof(WCHAR);
+        reply->codepage = node->codepage;
+        reply->flags = node->flags;
+        set_reply_data_ptr(ptr, rlen);
+    }
+    else set_error(STATUS_NO_MEMORY);
+}
diff -u -N -r -x '*~' -x '.#*' -x CVS server35/protocol.def server/protocol.def
--- server35/protocol.def	2003-09-18 20:48:55.000000000 +0200
+++ server/protocol.def	2003-09-20 18:27:46.000000000 +0200
@@ -594,6 +596,33 @@
 @END
 
 
+/* Create a path gate */
+ at REQ(create_pathgate)
+    obj_handle_t    device;             /* handle to associated device */
+    unsigned int    codepage;           /* pathgate's codepage */
+    unsigned int    flags;              /* flags */
+    size_t          root_len;           /* length of pathgate root directory */
+    size_t          name_len;           /* length of pathgate name */
+    VARARG(root,unicode_str,root_len);  /* root directory */
+    VARARG(name,unicode_str,name_len);  /* pathgate's name */
+    VARARG(extra,unicode_str);          /* extra information for pathgate (Unix path) */
+ at REPLY
+ at END
+
+
+/* Lookup filename in pathgates */
+ at REQ(get_file_name)
+    VARARG(name,unicode_str);           /* name of file to lookup */
+ at REPLY
+    unsigned int    codepage;           /* code page of path gate */
+    unsigned int    flags;              /* flags */
+    size_t          name_offset;        /* offset, in name, of the file name */
+    size_t          dir_len;            /* length of directory name */
+    VARARG(dirname,unicode_str,dir_len);/* actually dirname of name */
+    VARARG(extra,unicode_str);          /* extra information on dirname (Unix path) */
+ at END
+
+
 /* Create a file */
 @REQ(create_file)
     unsigned int access;        /* wanted access rights */
@@ -601,7 +630,6 @@
     unsigned int sharing;       /* sharing flags */
     int          create;        /* file create action */
     unsigned int attrs;         /* file attributes for creation */
-    int          drive_type;    /* type of drive the file is on */
     VARARG(filename,string);    /* file name */
 @REPLY
     obj_handle_t handle;        /* handle to the file */
@@ -1131,21 +1159,41 @@
 @END
 
 
-/* Create a device */
+/* install a device in NT pathname space */
 @REQ(create_device)
+    unsigned int type;          /* type of device */
+    unsigned int serial_number; /* device serial number */
+    unsigned int id;            /* device ID */
+    unsigned int name_len;      /* length of device name */
+    unsigned int unix_path_len; /* length of associated unix device path */
     unsigned int access;        /* wanted access rights */
     int          inherit;       /* inherit flag */
-    int          id;            /* client private id */
+    VARARG(name,unicode_str);   /* name of the device */
+    VARARG(unix_path,string);   /* associated unix device */
+    VARARG(label,unicode_str);  /* device label */
 @REPLY
     obj_handle_t handle;        /* handle to the device */
 @END
 
 
-/* Retrieve the client private id for a device */
- at REQ(get_device_id)
+/* open an existing device */
+ at REQ(open_device)
+    unsigned int access;        /* wanted access rights */
+    int          inherit;       /* inherit flag */
+    VARARG(name,unicode_str);   /* name of the device */
+ at REPLY
+    obj_handle_t handle;        /* handle to the device */
+ at END
+
+
+/* get information on a device */
+ at REQ(get_device_info)
     obj_handle_t handle;        /* handle to the device */
 @REPLY
-    int          id;            /* client private id */
+    unsigned int type;          /* type of device */
+    unsigned int serial_number; /* device serial number */
+    unsigned int id;            /* device ID */
+    VARARG(label,unicode_str);  /* device label */
 @END
 
 
diff -u -N -r -x '*~' -x '.#*' -x CVS server35/request.c server/request.c
--- server35/request.c	2003-06-21 14:31:02.000000000 +0200
+++ server/request.c	2003-09-20 12:33:00.000000000 +0200
@@ -787,6 +787,7 @@
     close_signals();
     close_global_hooks();
     close_global_handles();
+    close_pathgates();
     close_registry();
     close_atom_table();
 #else
diff -u -N -r -x '*~' -x '.#*' -x CVS win3235/device.c win32/device.c
--- win3235/device.c	2003-09-18 20:48:57.000000000 +0200
+++ win32/device.c	2003-09-20 18:27:37.000000000 +0200
@@ -267,7 +267,8 @@
 static DWORD DEVICE_GetClientID( HANDLE handle )
 {
     DWORD       ret = 0;
-    SERVER_START_REQ( get_device_id )
+
+    SERVER_START_REQ( get_device_info )
     {
         req->handle = handle;
         if (!wine_server_call( req )) ret = reply->id;


More information about the wine-patches mailing list