update on ntdll/kernel32 separation

Eric Pouech pouech-eric at wanadoo.fr
Thu Sep 18 14:17:27 CDT 2003


I've been quite quiet recently on ntdll/separation.
I was working on the NtCreateFile implementation.

Even, if it's not ready for prime time, I've been running lots of apps 
since once week without issues (which doesn't mean that none are left).
You'll find attached the patch for review.
(Since Alexandre has been busy lately, better to share some info)

However, it's not ready for prime time yet. Among things that remain to 
be done:
- review some internal namings (that's easy) and file naming
- get Alexandre review (that's harder... I mean to get a positive review)
- cleanup the initialisation code

There are some parts I don't like. The current server scheme doesn't fit 
well with the device manipulation we need.

Currently, I set, at a given point in NT pathnames (say \??\C:) a link 
to a Unix pathname (say /opt/windows).
This fits well with path conversions. It doesn't work for real device 
configuration, in particular CDROMs, where we need both the unix path 
for data access (/mnt/cdrom) and the unix path of the associated unix 
device (/dev/cdrom).

I'm still thinking of either:
- stick to current device structures, and store every bit of information 
(server-side) in the 'pathgate' object.
- beef up the device server object to store this information (unix 
device name, fake label, fake serial number).

The later is in fact more suited for an evolution of the current server 
device object.

My final question is more on which order we go on:
Solution 1:
1/ get the NtCreateFile ready and include it in the tree
2.a/ fix the introduces bugs
2.b/ convert the file/paths related functions
3/ finish the server side objects (devices...)

Solution 1:
3/
1/
2.a/
2.b/

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-18 20:48:27.000000000 +0200
+++ dlls/kernel/process.c	2003-09-18 20:37:57.000000000 +0200
@@ -385,6 +388,8 @@
     /* registry initialisation */
     SHELL_LoadRegistry();
 
+    FILE_InitPathNameSpace();
+
     /* global boot finished, the rest is process-local */
     CLIENT_BootDone( TRACE_ON(server) );
     if (TRACE_ON(relay) || TRACE_ON(snoop)) RELAY_InitDebugLists();
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-18 20:52:40.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-18 20:57:15.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,157 @@
  *  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 */
+    WCHAR               bs[2048], bl[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 = bs;
+    paths.short_ustr.Length = 0;
+    paths.short_ustr.MaximumLength = sizeof(bs);
+
+    paths.long_ustr.Buffer = bl;
+    paths.long_ustr.Length = 0;
+    paths.long_ustr.MaximumLength = sizeof(bl);
+
+    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 +334,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 +355,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:       /* ?? */
@@ -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 );
@@ -945,7 +1026,6 @@
                 status = wine_server_call( req );
             }
             SERVER_END_REQ;
-            status = STATUS_SUCCESS;
         }
         break;
     default:
@@ -1220,3 +1300,325 @@
     SERVER_END_REQ;
     return status;
 }
+
+/* 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",
+            'A' + drive, debugstr_w(value) );
+    return PATHGATE_CASE_PRESERVING;
+}
+
+static void     add_node(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->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(void)
+{
+    static const WCHAR       ntroot[] =  {'\\','\0'};
+    static const WCHAR       unc[] = {'U','N','C','\0'};
+    static const WCHAR       dos[] = {'?','?','\0'};
+    static const WCHAR       rdos[] = {'\\','?','?','\0'};
+
+    if (!CLIENT_IsBootThread()) return;  /* already loaded */
+
+    int         i, 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;
+    LPSTR       root, device;
+    HKEY        hkey;
+    DWORD       dummy;
+    OBJECT_ATTRIBUTES attr;
+    UNICODE_STRING nameW;
+    unsigned    codepage, drivetype, driveflags = 0;
+
+    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};
+/* EPP     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};
+/* EPP     static const WCHAR driveC_labelW[] = {'D','r','i','v','e',' ','C',' ',' ',' ',' ',0}; */
+
+    /* system */
+    add_node(ntroot, strlenW(ntroot), dos,  strlenW(dos),  NULL,  0, 1242, 0);
+    add_node(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;
+
+    for (i = 0; i < 26 /* FIXME MAX_DOS_DRIVES */; i++)
+    {
+        RtlInitUnicodeString( &nameW, driveW );
+        nameW.Buffer[(nameW.Length / sizeof(WCHAR)) - 1] = 'A' + i;
+        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);
+            }
+
+            if (stat( root, &drive_stat_buffer ))
+            {
+                MESSAGE("Could not stat %s (%s), ignoring drive %c:\n",
+                        root, strerror(errno), 'A' + i);
+                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, 'A' + i );
+                RtlFreeHeap( ntdll_get_process_heap(), 0, root );
+                root = NULL;
+                goto next;
+            }
+
+#if 0
+            drive->dos_cwd  = HeapAlloc(ntdll_get_process_heap(), HEAP_ZERO_MEMORY, sizeof(drive->dos_cwd[0]));
+            drive->unix_cwd = heap_strdup( "" );
+            drive->device   = NULL;
+            drive->flags    = 0;
+            drive->dev      = drive_stat_buffer.st_dev;
+            drive->ino      = drive_stat_buffer.st_ino;
+#endif
+
+            /* 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;
+                TRACE("Got type %s\n", debugstr_w(data));
+                drivetype = DRIVE_FIXED; //DRIVE_GetDriveType( i, 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;
+                TRACE("Got label %s\n", debugstr_w(data));
+                // lstrcpynW( drive->label_conf, data, 12 );
+            }
+#if 0
+            if ((len = strlenW(drive->label_conf)) < 11)
+            {
+                /* Pad label with spaces */
+                while(len < 11) drive->label_conf[len++] = ' ';
+                drive->label_conf[11] = '\0';
+            }
+#endif
+
+#if 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;
+                drive->serial_conf = strtoulW( data, NULL, 16 );
+            }
+            else drive->serial_conf = 12345678;
+#endif
+
+            /* 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( i, 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;
+                    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);
+                    }
+                }
+            }
+
+            /* 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;
+            }
+
+#if 0
+            /* Make the first hard disk the current drive */
+            if ((DRIVE_CurDrive == -1) && (drive->type == DRIVE_FIXED))
+                DRIVE_CurDrive = i;
+#endif
+            count++;
+#if 0
+            TRACE("Drive %c: path=%s type=%s label=%s serial=%08lx "
+                  "flags=%08x codepage=%u dev=%x ino=%x\n",
+                  'A' + i, root, debugstr_w(DRIVE_Types[drive->type]),
+                  debugstr_w(drive->label_conf), drive->serial_conf, drive->flags,
+                  drive->codepage, (int)drive->dev, (int)drive->ino );
+#else
+            TRACE("Drive %c: path=%s type=%d label=-<>- serial=-<>- "
+                  "flags=%08x codepage=%u\n",
+                  'A' + i, root, drivetype, driveflags, codepage);
+#endif
+            drive_env[1] = 'A' + i;
+            TRACE("Adding drive %c => %s/%s\n", 'A' + i, root, debugstr_w(path));
+            add_node(rdos, strlenW(rdos), drive_env + 1, strlenW(drive_env + 1), path, strlenW(path),
+                     codepage, 0);
+        }
+
+    next:
+        NtClose( hkey );
+    }
+    init_done = TRUE;
+#if 0
+    if (!count)
+    {
+        MESSAGE("Warning: no valid DOS drive found, check your configuration file.\n" );
+        /* Create a C drive pointing to Unix root dir */
+        DOSDrives[2].root     = heap_strdup( "/" );
+        DOSDrives[2].dos_cwd  = RtlAllocateHeap(ntdll_get_process_heap(), HEAP_ZERO_MEMORY, sizeof(DOSDrives[2].dos_cwd[0]));
+        DOSDrives[2].unix_cwd = heap_strdup( "" );
+        strcpyW( DOSDrives[2].label_conf, driveC_labelW );
+        DOSDrives[2].serial_conf   = 12345678;
+        DOSDrives[2].type     = DRIVE_FIXED;
+        DOSDrives[2].device   = NULL;
+        DOSDrives[2].flags    = 0;
+        DRIVE_CurDrive = 2;
+    }
+
+    /* Make sure the current drive is valid */
+    if (DRIVE_CurDrive == -1)
+    {
+        for (i = 0, drive = DOSDrives; i < MAX_DOS_DRIVES; i++, drive++)
+        {
+            if (drive->root && !(drive->flags & DRIVE_DISABLED))
+            {
+                DRIVE_CurDrive = i;
+                break;
+            }
+        }
+    }
+
+    /* get current working directory info for all drives */
+    for (i = 0; i < MAX_DOS_DRIVES; i++, drive_env[1]++)
+    {
+        if (!GetEnvironmentVariableW(drive_env, path, MAX_PATHNAME_LEN)) continue;
+        /* sanity check */
+        if (toupperW(path[0]) != drive_env[1] || path[1] != ':') continue;
+        DRIVE_Chdir( i, path + 2 );
+    }
+#endif
+}
diff -u -N -r -x '*~' -x '.#*' -x CVS dlls/ntdll35/Makefile.in dlls/ntdll/Makefile.in
--- dlls/ntdll35/Makefile.in	2003-09-18 20:48:32.000000000 +0200
+++ dlls/ntdll/Makefile.in	2003-09-18 19:37:13.000000000 +0200
@@ -43,6 +43,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-13 21:06:36.000000000 +0200
+++ dlls/ntdll/ntdll_misc.h	2003-09-16 22:27:37.000000000 +0200
@@ -58,6 +58,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/file.c files/file.c
--- files35/file.c	2003-09-18 20:48:44.000000000 +0200
+++ files/file.c	2003-09-18 20:54:37.000000000 +0200
@@ -404,6 +404,7 @@
                         DWORD attributes, HANDLE template, BOOL fail_read_only,
                         UINT drive_type )
 {
+#if 0
     unsigned int err;
     HANDLE ret;
 
@@ -453,6 +454,54 @@
         if (!ret) WARN("Unable to create file '%s' (GLE %ld)\n", filename, GetLastError());
         return ret;
     }
+#else
+    HANDLE              h;
+    UNICODE_STRING      u;
+    OBJECT_ATTRIBUTES   oa;
+    IO_STATUS_BLOCK     iosb;
+    ULONG               disp;
+
+    oa.Length = sizeof(oa);
+    oa.ObjectName = &u;
+    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(&u, 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(&h, access, &oa, &iosb, NULL, attributes, 
+                 sharing, disp, 0, NULL, 0);
+    RtlFreeUnicodeString(&u);
+
+    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) );
+        h = 0;
+    }
+
+    if (!h) WARN("Unable to create file '%s' (GLE %ld)\n", filename, GetLastError());
+    return h;
+#endif
 }
 
 
@@ -1702,7 +1751,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 +2034,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 +2047,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 server35/directory.c server/directory.c
--- server35/directory.c	1970-01-01 01:00:00.000000000 +0100
+++ server/directory.c	2003-09-14 14:23:13.000000000 +0200
@@ -0,0 +1,248 @@
+/*
+ * 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"
+#include "console.h"
+
+static int verbose = 0;
+
+#define fprintf         if (verbose) fprintf
+#define dump_strW       if (verbose) dump_strW
+
+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 */
+    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, 1252, 0, NULL, 0, NULL, {'\0'}};
+
+static struct dir_node* create_node(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;
+
+    node = malloc(sizeof(struct dir_node) + name_len);
+    node->type = type;
+    node->children = NULL;
+    node->codepage = codepage;
+    node->flags = flags;
+    if (extra)
+    {
+        node->extra = malloc(extra_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';
+    return node;
+}
+
+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);
+
+    fprintf(stderr,"##");
+    dump_strW(name, len, stderr, "[]");
+    fprintf(stderr, "\n");
+    
+    name++; /* skip first '\\' */
+    len--;
+
+    node = &all_root;
+    if (!*name) return node;
+
+    while (node->children)
+    {
+        fprintf(stderr,"  --");
+        dump_strW(name, len, stderr, "[]");
+        fprintf(stderr, "\n");
+
+        for (elen = 0; elen < len; elen++)
+            if (name[elen] == '\\') break;
+
+        for (child = node->children; child; child = child->next)
+        {
+            fprintf(stderr,"    <<");
+            dump_strW(child->name, strlenW(child->name), stderr, "[]");
+            fprintf(stderr, ">> %d\n", elen);
+
+            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*  n;
+                size_t  xlen;
+                
+                xlen = child->extra_len / sizeof(WCHAR);
+                n = malloc((xlen + len - elen + 1) * sizeof(WCHAR));
+                memcpy(n, child->extra, xlen * sizeof(WCHAR));
+                n[xlen] = '\\';
+                memcpy(n + xlen + 1, name + elen + 1, (len - elen) * sizeof(WCHAR));
+                node = lookup(n, (xlen + len - elen) * sizeof(WCHAR), ret);
+                if (*ret) *ret = name + (xlen + len - elen) - (*ret - n + xlen - 1);
+                free(n);
+                return node;
+            }
+            break;
+        case regular:
+            node = child;
+            break;
+        }
+        
+        fprintf(stderr, "=> %d %d\n", elen, len);
+        if (elen == len) break;
+        len -= elen + 1;
+        name += elen + 1;
+    }
+    if (node) *ret = name;
+    return node;
+}
+
+static void add_node(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;
+
+    parent = lookup(root, root_len, &left);
+
+    if (!parent)
+    {
+        fprintf(stderr, "issue: ");
+        dump_strW(root, root_len, stderr, "[]");
+        fprintf(stderr, "\n");
+        set_error(STATUS_OBJECT_PATH_NOT_FOUND);
+    }
+    child = create_node(name, name_len, type, extra, extra_len, codepage, flags);
+    add_child(parent, child);
+}
+
+DECL_HANDLER(create_pathgate)
+{
+    size_t              len = get_req_data_size();
+    size_t              extra_len;
+    const WCHAR*        data = get_req_data();
+
+    extra_len = len - (req->root_len + req->name_len);
+
+    add_node(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;
+
+    fprintf(stderr, "imh1\n");
+    node = lookup(dirname, get_req_data_size(), &p);
+    if (!node)
+    {
+        set_error(STATUS_OBJECT_NAME_NOT_FOUND);
+        return;
+    }
+
+    fprintf(stderr, "imh2\n");
+    reply->dir_len = 0;
+    fprintf(stderr, "imh3\n");
+    for (pp = node; pp; pp = pp->parent)
+    {
+        reply->dir_len += strlenW(pp->name) + 1;
+    }
+    fprintf(stderr, "imh4\n");
+    reply->dir_len--;
+    reply->name_offset = p - dirname;
+    ptr = malloc(rlen = reply->dir_len * sizeof(WCHAR) + node->extra_len);
+    fprintf(stderr, "imh5\n");
+
+    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);
+}
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-08-12 20:55:23.000000000 +0200
@@ -16,6 +16,7 @@
 	context_sparc.c \
 	debugger.c \
 	device.c \
+	directory.c \
 	event.c \
 	fd.c \
 	file.c \
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-16 21:25:14.000000000 +0200
@@ -594,6 +596,32 @@
 @END
 
 
+/* Create a path gate */
+ at REQ(create_pathgate)
+    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 +629,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 */
@@ -2196,3 +2223,4 @@
 #define OPEN_TOKEN_THREAD   1
 #define OPEN_TOKEN_AS_SELF  2
 
+


More information about the wine-devel mailing list