Patch to make server understand NT path names

Mike McCormack mikem at codeweavers.com
Sun Jun 16 20:15:10 CDT 2002


Hi All,

This patch is the start of my work to make the wineserver understand NT 
path names. It's still quite raw, but works for simple read-only cases.

The end goal is to have all file access go through the NT native 
interface, thus dll-seperate the kernel32 file API from our ntdll.

I've made the following changes:

* the create_file server call is modified so that it takes a unicode path.
* if the above path starts with a backslash, it is interpretted as a 
WinNT style path name.
* created two new server objects, directory and virtual directory.
* created the NT root directory is a virtual directory containing 
another virtual directory named \DosDevices
* created the virtual directory DosDevices containing each drive as a 
subdirectory.

With these changes, directories will become server objects, and we can 
procede to modify the client side code to use the new directory objects.

Anyway, with all this, my test program can open (NtOpenFile) and 
dump(NtReadFile) a file with names like this, as it does on WinNT.

\DosDevices\C:\test.txt
\DosDevices\C:\Tmp\asdf

There's still lots of work to do on this:

* create a hash of currently open directory objects
* use [Drive] entry to convert between unicode and ascii
* implement NtQueryDirectoryFile so we can read directories
* rewrite the client side code to use it
* debug and test it all

Anyway I've put this out early so you can all compla^H^H^H comment on it 
   and don't have to totally rewrite it after completing it to my own 
satisfaction ;-) Give me a yell is there's stuff missing or you want my 
test program... remember to run tools/make_requests

Mike


License: LGPL
ChangeLog:
* add NT style path handling to wineserver

-------------- next part --------------
? server/dir.c
? server/drive.c
? server/ntroot.c
? server/registry.h
? server/x
Index: dlls/ntdll/file.c
===================================================================
RCS file: /home/wine/wine/dlls/ntdll/file.c,v
retrieving revision 1.14
diff -u -r1.14 file.c
--- dlls/ntdll/file.c	14 Jun 2002 00:36:20 -0000	1.14
+++ dlls/ntdll/file.c	16 Jun 2002 16:14:30 -0000
@@ -58,12 +58,15 @@
 	ULONG ShareAccess,
 	ULONG OpenOptions)
 {
+#if 0
 	ULONG len = 0;
 	PSTR filename;
 	CHAR szDosDevices[] = "\\DosDevices\\";
 	DOS_FULL_NAME full_name;
+	UNICODE_STRING unix_name;
+#endif
 	NTSTATUS r;
-
+	
 	FIXME("(%p,0x%08lx,%p,%p,0x%08lx,0x%08lx) partial stub\n",
 		FileHandle, DesiredAccess, ObjectAttributes,
 		IoStatusBlock, ShareAccess, OpenOptions);
@@ -77,8 +80,9 @@
 		return STATUS_OBJECT_NAME_NOT_FOUND;
 	}
 
+#if 0
 	/* create an ascii string from the unicode filename */
-	RtlUnicodeToMultiByteSize( &len, ObjectAttributes->ObjectName->Buffer,
+	RtlUnicodeToMultiByteSize( &len, ObjectAttributes->ObjectName->Buffer, 
 				ObjectAttributes->ObjectName->Length );
 	filename = RtlAllocateHeap( GetProcessHeap(), 0, len + 1);
 	RtlUnicodeToMultiByteN(filename, len, NULL, ObjectAttributes->ObjectName->Buffer,
@@ -94,7 +98,10 @@
 				&full_name))
 		return STATUS_OBJECT_NAME_NOT_FOUND;
 
-	/* FIXME: modify server protocol so
+	RtlCreateUnicodeStringFromAsciiz(&unix_name, full_name.long_name);
+#endif
+
+	/* FIXME: modify server protocol so 
                   create file takes an OBJECT_ATTRIBUTES structure */
         SERVER_START_REQ( create_file )
         {
@@ -103,13 +110,20 @@
             req->sharing    = ShareAccess;
             req->create     = OPEN_EXISTING;
             req->attrs      = 0;
-            req->drive_type = GetDriveTypeA( full_name.short_name );
-            wine_server_add_data( req, full_name.long_name, strlen(full_name.long_name) );
-            SetLastError(0);
+            req->drive_type = -1;
+#if 0
+            wine_server_add_data( req, unix_name.Buffer, unix_name.Length );
+#else
+            wine_server_add_data( req, ObjectAttributes->ObjectName->Buffer, ObjectAttributes->ObjectName->Length );
+#endif
             r = wine_server_call( req );
             *FileHandle = reply->handle;
         }
         SERVER_END_REQ;
+
+#if 0
+	RtlFreeUnicodeString(&unix_name);
+#endif
 
 	return r;
 }
Index: dlls/ntdll/ntdll.spec
===================================================================
RCS file: /home/wine/wine/dlls/ntdll/ntdll.spec,v
retrieving revision 1.68
diff -u -r1.68 ntdll.spec
--- dlls/ntdll/ntdll.spec	10 Jun 2002 02:28:00 -0000	1.68
+++ dlls/ntdll/ntdll.spec	16 Jun 2002 16:14:31 -0000
@@ -252,7 +252,7 @@
 @ stdcall NtWaitForSingleObject(long long long) NtWaitForSingleObject
 @ stub NtWaitHighEventPair
 @ stub NtWaitLowEventPair
-@ stub NtWriteFile
+@ stdcall NtWriteFile(long long long long long long long long long) NtWriteFile
 @ stub NtWriteRequestData
 @ stub NtWriteVirtualMemory
 @ stub PfxFindPrefix
@@ -757,7 +757,7 @@
 @ stdcall ZwWaitForSingleObject(long long long) NtWaitForSingleObject
 @ stub ZwWaitHighEventPair
 @ stub ZwWaitLowEventPair
-@ stub ZwWriteFile
+@ stdcall ZwWriteFile(long long long long long long long long long) NtWriteFile
 @ stub ZwWriteRequestData
 @ stub ZwWriteVirtualMemory
 @ cdecl _CIpow() NTDLL__CIpow
Index: files/file.c
===================================================================
RCS file: /home/wine/wine/files/file.c,v
retrieving revision 1.149
diff -u -r1.149 file.c
--- files/file.c	5 Jun 2002 00:47:38 -0000	1.149
+++ files/file.c	16 Jun 2002 16:14:33 -0000
@@ -378,6 +378,8 @@
 {
     unsigned int err;
     HANDLE ret;
+    WCHAR name[MAX_PATH];
+    int len = MultiByteToWideChar(CP_ACP,0,filename,-1,name,MAX_PATH);
 
     for (;;)
     {
@@ -389,7 +391,7 @@
             req->create     = creation;
             req->attrs      = attributes;
             req->drive_type = drive_type;
-            wine_server_add_data( req, filename, strlen(filename) );
+            wine_server_add_data( req, name, len*sizeof(WCHAR) );
             SetLastError(0);
             err = wine_server_call( req );
             ret = reply->handle;
@@ -403,7 +405,7 @@
             if ((err == STATUS_MEDIA_WRITE_PROTECTED) || (err == STATUS_ACCESS_DENIED))
             {
                 TRACE("Write access failed for file '%s', trying without "
-                      "write access\n", filename);
+                      "write access\n", debugstr_w(name));
                 access &= ~GENERIC_WRITE;
                 continue;
             }
@@ -411,7 +413,7 @@
 
         if (err) SetLastError( RtlNtStatusToDosError(err) );
 
-        if (!ret) WARN("Unable to create file '%s' (GLE %ld)\n", filename, GetLastError());
+        if (!ret) WARN("Unable to create file '%s' (GLE %ld)\n", debugstr_wn(name,len), GetLastError());
         return ret;
     }
 }
Index: server/Makefile.in
===================================================================
RCS file: /home/wine/wine/server/Makefile.in,v
retrieving revision 1.33
diff -u -r1.33 Makefile.in
--- server/Makefile.in	9 May 2002 04:31:40 -0000	1.33
+++ server/Makefile.in	16 Jun 2002 16:14:33 -0000
@@ -14,6 +14,7 @@
 	context_sparc.c \
 	debugger.c \
 	device.c \
+	dir.c \
 	event.c \
 	file.c \
 	handle.c \
@@ -21,6 +22,7 @@
 	mapping.c \
 	mutex.c \
 	named_pipe.c \
+	ntroot.c \
 	object.c \
 	pipe.c \
 	process.c \
Index: server/atom.c
===================================================================
RCS file: /home/wine/wine/server/atom.c,v
retrieving revision 1.14
diff -u -r1.14 atom.c
--- server/atom.c	26 Apr 2002 19:05:17 -0000	1.14
+++ server/atom.c	16 Jun 2002 16:14:33 -0000
@@ -77,6 +77,8 @@
     no_flush,                     /* flush */
     no_get_file_info,             /* get_file_info */
     NULL,                         /* queue_async */
+    NULL,                         /* enumerate */
+    NULL,                         /* get_child_handle */
     atom_table_destroy            /* destroy */
 };
 
Index: server/change.c
===================================================================
RCS file: /home/wine/wine/server/change.c,v
retrieving revision 1.12
diff -u -r1.12 change.c
--- server/change.c	10 Mar 2002 00:18:36 -0000	1.12
+++ server/change.c	16 Jun 2002 16:14:33 -0000
@@ -52,6 +52,8 @@
     no_flush,                 /* flush */
     no_get_file_info,         /* get_file_info */
     NULL,                     /* queue_async */
+    NULL,                         /* enumerate */
+    NULL,                         /* get_child_handle */
     no_destroy                /* destroy */
 };
 
Index: server/console.c
===================================================================
RCS file: /home/wine/wine/server/console.c,v
retrieving revision 1.40
diff -u -r1.40 console.c
--- server/console.c	2 Jun 2002 21:22:22 -0000	1.40
+++ server/console.c	16 Jun 2002 16:14:34 -0000
@@ -57,6 +57,8 @@
     no_flush,                         /* flush */
     console_get_file_info,            /* get_file_info */
     NULL,                             /* queue_async */
+    NULL,                         /* enumerate */
+    NULL,                         /* get_child_handle */
     console_input_destroy             /* destroy */
 };
 
@@ -86,6 +88,8 @@
     no_flush,                         /* flush */
     no_get_file_info,                 /* get_file_info */
     NULL,                             /* queue_async */
+    NULL,                         /* enumerate */
+    NULL,                         /* get_child_handle */
     console_input_events_destroy      /* destroy */
 };
 
@@ -127,6 +131,8 @@
     no_flush,                         /* flush */
     console_get_file_info,            /* get_file_info */
     NULL,                             /* queue_async */
+    NULL,                         /* enumerate */
+    NULL,                         /* get_child_handle */
     screen_buffer_destroy             /* destroy */
 };
 
Index: server/debugger.c
===================================================================
RCS file: /home/wine/wine/server/debugger.c,v
retrieving revision 1.42
diff -u -r1.42 debugger.c
--- server/debugger.c	30 May 2002 20:12:58 -0000	1.42
+++ server/debugger.c	16 Jun 2002 16:14:34 -0000
@@ -78,6 +78,8 @@
     no_flush,                      /* flush */
     no_get_file_info,              /* get_file_info */
     NULL,                          /* queue_async */
+    NULL,                         /* enumerate */
+    NULL,                         /* get_child_handle */
     debug_event_destroy            /* destroy */
 };
 
@@ -99,6 +101,8 @@
     no_flush,                      /* flush */
     no_get_file_info,              /* get_file_info */
     NULL,                          /* queue_async */
+    NULL,                         /* enumerate */
+    NULL,                         /* get_child_handle */
     debug_ctx_destroy              /* destroy */
 };
 
Index: server/device.c
===================================================================
RCS file: /home/wine/wine/server/device.c,v
retrieving revision 1.14
diff -u -r1.14 device.c
--- server/device.c	10 Mar 2002 00:18:36 -0000	1.14
+++ server/device.c	16 Jun 2002 16:14:35 -0000
@@ -59,6 +59,8 @@
     no_flush,                 /* flush */
     device_get_info,          /* get_file_info */
     NULL,                     /* queue_async */
+    NULL,                         /* enumerate */
+    NULL,                         /* get_child_handle */
     no_destroy                /* destroy */
 };
 
Index: server/event.c
===================================================================
RCS file: /home/wine/wine/server/event.c,v
retrieving revision 1.24
diff -u -r1.24 event.c
--- server/event.c	30 May 2002 20:12:58 -0000	1.24
+++ server/event.c	16 Jun 2002 16:14:35 -0000
@@ -56,6 +56,8 @@
     no_flush,                  /* flush */
     no_get_file_info,          /* get_file_info */
     NULL,                      /* queue_async */
+    NULL,                         /* enumerate */
+    NULL,                         /* get_child_handle */
     no_destroy                 /* destroy */
 };
 
Index: server/file.c
===================================================================
RCS file: /home/wine/wine/server/file.c,v
retrieving revision 1.58
diff -u -r1.58 file.c
--- server/file.c	30 May 2002 20:12:58 -0000	1.58
+++ server/file.c	16 Jun 2002 16:14:35 -0000
@@ -44,12 +44,17 @@
 #include "thread.h"
 #include "request.h"
 #include "async.h"
+#include "unicode.h"
+
+#include "winnt.h"
+#include "winreg.h"
+#include "registry.h"
 
 struct file
 {
     struct object       obj;        /* object header */
     struct file        *next;       /* next file in hashing list */
-    char               *name;       /* file name */
+    WCHAR              *name;       /* file name */
     unsigned int        access;     /* file access (GENERIC_READ/WRITE) */
     unsigned int        flags;      /* flags (FILE_FLAG_*) */
     unsigned int        sharing;    /* file sharing mode */
@@ -85,20 +90,22 @@
     file_flush,                   /* flush */
     file_get_info,                /* get_file_info */
     file_queue_async,             /* queue_async */
+    NULL,                         /* enumerate */
+    NULL,                         /* get_child_handle */
     file_destroy                  /* destroy */
 };
 
 
-static int get_name_hash( const char *name )
+static int get_name_hash( const WCHAR *name )
 {
     int hash = 0;
-    while (*name) hash ^= (unsigned char)*name++;
+    while (*name) hash ^= (unsigned short)*name++;
     return hash % NAME_HASH_SIZE;
 }
 
 /* check if the desired access is possible without violating */
 /* the sharing mode of other opens of the same file */
-static int check_sharing( const char *name, int hash, unsigned int access,
+static int check_sharing( const WCHAR *name, int hash, unsigned int access,
                           unsigned int sharing )
 {
     struct file *file;
@@ -107,7 +114,7 @@
 
     for (file = file_hash[hash]; file; file = file->next)
     {
-        if (strcmp( file->name, name )) continue;
+        if (strcmpW( file->name, name )) continue;
         existing_sharing &= file->sharing;
         existing_access |= file->access;
     }
@@ -144,20 +151,21 @@
     return file;
 }
 
-
-static struct file *create_file( const char *nameptr, size_t len, unsigned int access,
+struct object *create_file( const WCHAR *nameptr, size_t len, unsigned int access,
                                  unsigned int sharing, int create, unsigned int attrs,
                                  int drive_type )
 {
     struct file *file;
     int hash, flags;
     struct stat st;
-    char *name;
+    WCHAR *name, szwCom[] = {'.','c','o','m',0 }, szwExe[] = {'.','e','x','e',0 };
     int fd = -1;
     mode_t mode;
 
-    if (!(name = mem_alloc( len + 1 ))) return NULL;
-    memcpy( name, nameptr, len );
+    /* fprintf(stderr,"opening: "); dump_strW(name,len,stderr,"[]"); fprintf(stderr,"\n"); */
+
+    if (!(name = mem_alloc( (len+1)*sizeof (WCHAR) ))) return NULL;
+    memcpy( name, nameptr, len*sizeof (WCHAR) );
     name[len] = 0;
 
     /* check sharing mode */
@@ -183,11 +191,11 @@
     mode = (attrs & FILE_ATTRIBUTE_READONLY) ? 0444 : 0666;
 
     if (len >= 4 &&
-        (!strcasecmp( name + len - 4, ".exe" ) || !strcasecmp( name + len - 4, ".com" )))
+        (!strcmpiW( name + len - 4, szwExe ) || !strcmpiW( name + len - 4, szwCom )))
         mode |= 0111;
 
     /* FIXME: should set error to STATUS_OBJECT_NAME_COLLISION if file existed before */
-    if ((fd = open( name, flags | O_NONBLOCK | O_LARGEFILE, mode )) == -1 )
+    if ((fd = openw( name, flags | O_NONBLOCK | O_LARGEFILE, mode )) == -1 )
         goto file_error;
     /* refuse to open a directory */
     if (fstat( fd, &st ) == -1) goto file_error;
@@ -205,7 +213,7 @@
     file->name = name;
     file->next = file_hash[hash];
     file_hash[hash] = file;
-    return file;
+    return &file->obj;
 
  file_error:
     file_set_error();
@@ -218,7 +226,7 @@
 /* check if two file objects point to the same file */
 int is_same_file( struct file *file1, struct file *file2 )
 {
-    return !strcmp( file1->name, file2->name );
+    return !strcmpW( file1->name, file2->name );
 }
 
 /* get the type of drive the file is on */
@@ -264,7 +272,9 @@
 {
     struct file *file = (struct file *)obj;
     assert( obj->ops == &file_ops );
-    fprintf( stderr, "File fd=%d flags=%08x name='%s'\n", file->obj.fd, file->flags, file->name );
+    fprintf( stderr, "File fd=%d flags=%08x name=", file->obj.fd, file->flags );
+    dump_strW(file->name,strlenW(file->name),stderr,"[]");
+    fprintf( stderr, "\n" );
 }
 
 static int file_get_poll_events( struct object *obj )
@@ -427,7 +437,7 @@
         while (*pptr && *pptr != file) pptr = &(*pptr)->next;
         assert( *pptr );
         *pptr = (*pptr)->next;
-        if (file->flags & FILE_FLAG_DELETE_ON_CLOSE) unlink( file->name );
+        if (file->flags & FILE_FLAG_DELETE_ON_CLOSE) unlinkw( file->name );
         free( file->name );
     }
     if (file->flags & FILE_FLAG_OVERLAPPED)
@@ -564,13 +574,13 @@
     if (!access_time || !write_time)
     {
         struct stat st;
-        if (stat( file->name, &st ) == -1) goto error;
+        if (statw( file->name, &st ) == -1) goto error;
         if (!access_time) access_time = st.st_atime;
         if (!write_time) write_time = st.st_mtime;
     }
     utimbuf.actime  = access_time;
     utimbuf.modtime = write_time;
-    if (utime( file->name, &utimbuf ) == -1) goto error;
+    if (utimew( file->name, &utimbuf ) == -1) goto error;
     release_object( file );
     return 1;
  error:
@@ -596,11 +606,29 @@
 /* create a file */
 DECL_HANDLER(create_file)
 {
-    struct file *file;
+    struct object *file = NULL;
+    const WCHAR *name = get_req_data();
+    int len = get_req_data_size()/sizeof (WCHAR);
 
     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 )))
+
+    if(len && (name[0]=='\\')) /* nt path name */
+    {
+        if(root)
+        {
+            root->ops->open_child(root, name+1, len-1, req->access, 
+                                  req->sharing, req->create, req->attrs, &file );
+        }
+        else
+            set_error(STATUS_ACCESS_DENIED);
+    }
+    else
+    {
+        file = create_file( name, len, req->access,
+                            req->sharing, req->create, req->attrs, req->drive_type );
+    }
+
+    if (file)
     {
         reply->handle = alloc_handle( current->process, file, req->access, req->inherit );
         release_object( file );
Index: server/handle.c
===================================================================
RCS file: /home/wine/wine/server/handle.c,v
retrieving revision 1.21
diff -u -r1.21 handle.c
--- server/handle.c	30 May 2002 20:12:58 -0000	1.21
+++ server/handle.c	16 Jun 2002 16:14:35 -0000
@@ -110,6 +110,8 @@
     no_flush,                        /* flush */
     no_get_file_info,                /* get_file_info */
     NULL,                            /* queue_async */
+    NULL,                         /* enumerate */
+    NULL,                         /* get_child_handle */
     handle_table_destroy             /* destroy */
 };
 
Index: server/main.c
===================================================================
RCS file: /home/wine/wine/server/main.c,v
retrieving revision 1.24
diff -u -r1.24 main.c
--- server/main.c	3 Apr 2002 22:51:18 -0000	1.24
+++ server/main.c	16 Jun 2002 16:14:35 -0000
@@ -34,6 +34,7 @@
 /* command-line options */
 int debug_level = 0;
 int master_socket_timeout = 3;  /* master socket timeout in seconds, default is 3 s */
+struct object *root; /* root of the NT filesystem */
 
 /* parse-line args */
 /* FIXME: should probably use getopt, and add a (more complete?) help option */
@@ -109,8 +110,10 @@
 
     if (debug_level) fprintf( stderr, "Server: starting (pid=%ld)\n", (long) getpid() );
     init_registry();
+    root = get_ntroot();
     select_loop();
     close_registry();
+    release_object(root);
     if (debug_level) fprintf( stderr, "Server: exiting (pid=%ld)\n", (long) getpid() );
 
 #ifdef DEBUG_OBJECTS
Index: server/mapping.c
===================================================================
RCS file: /home/wine/wine/server/mapping.c,v
retrieving revision 1.33
diff -u -r1.33 mapping.c
--- server/mapping.c	30 May 2002 20:12:58 -0000	1.33
+++ server/mapping.c	16 Jun 2002 16:14:36 -0000
@@ -67,6 +67,8 @@
     no_flush,                    /* flush */
     mapping_get_info,            /* get_file_info */
     NULL,                        /* queue_async */
+    NULL,                         /* enumerate */
+    NULL,                         /* get_child_handle */
     mapping_destroy              /* destroy */
 };
 
Index: server/mutex.c
===================================================================
RCS file: /home/wine/wine/server/mutex.c,v
retrieving revision 1.21
diff -u -r1.21 mutex.c
--- server/mutex.c	26 Apr 2002 19:05:18 -0000	1.21
+++ server/mutex.c	16 Jun 2002 16:14:36 -0000
@@ -60,6 +60,8 @@
     no_flush,                  /* flush */
     no_get_file_info,          /* get_file_info */
     NULL,                      /* queue_async */
+    NULL,                         /* enumerate */
+    NULL,                         /* get_child_handle */
     mutex_destroy              /* destroy */
 };
 
Index: server/named_pipe.c
===================================================================
RCS file: /home/wine/wine/server/named_pipe.c,v
retrieving revision 1.14
diff -u -r1.14 named_pipe.c
--- server/named_pipe.c	31 May 2002 23:06:53 -0000	1.14
+++ server/named_pipe.c	16 Jun 2002 16:14:36 -0000
@@ -96,6 +96,8 @@
     no_flush,                     /* flush */
     no_get_file_info,             /* get_file_info */
     NULL,                         /* queue_async */
+    NULL,                         /* enumerate */
+    NULL,                         /* get_child_handle */
     named_pipe_destroy            /* destroy */
 };
 
@@ -118,6 +120,8 @@
     no_flush,                     /* flush */
     pipe_user_get_info,           /* get_file_info */
     NULL,                         /* queue_async */
+    NULL,                         /* enumerate */
+    NULL,                         /* get_child_handle */
     pipe_user_destroy             /* destroy */
 };
 
Index: server/object.h
===================================================================
RCS file: /home/wine/wine/server/object.h,v
retrieving revision 1.43
diff -u -r1.43 object.h
--- server/object.h	30 May 2002 20:12:58 -0000	1.43
+++ server/object.h	16 Jun 2002 16:14:36 -0000
@@ -65,6 +65,11 @@
     int  (*get_file_info)(struct object *,struct get_file_info_reply *, int *flags);
     /* queue an async operation - see register_async handler in async.c*/
     void (*queue_async)(struct object *, void* ptr, unsigned int status, int type, int count);
+    /* enumerate child objects (directory listing) */
+    int (*enumerate)(struct object *, unsigned int index, WCHAR **name, int *len);
+    /* get child handle */
+    int (*open_child)(struct object *, const WCHAR *nameptr, size_t len, unsigned int access,
+                      unsigned int sharing, int create, unsigned int attrs, struct object **);
     /* destroy on refcount == 0 */
     void (*destroy)(struct object *);
 };
@@ -167,6 +172,9 @@
 extern int create_anonymous_file(void);
 extern struct file *create_temp_file( int access );
 extern void file_set_error(void);
+extern struct object *create_file( const WCHAR *nameptr, size_t len, unsigned int access,
+                                 unsigned int sharing, int create, unsigned int attrs,
+                                 int drive_type );
 
 /* serial functions */
 
@@ -194,7 +202,14 @@
 extern int grab_global_atom( atom_t atom );
 extern void release_global_atom( atom_t atom );
 
+/* NT filesystem root */
+extern struct object* get_ntroot(void);
+extern struct object* get_dir(WCHAR *name, int len);
+
 /* global variables */
+
+  /* root of the NT filesystem */
+extern struct object *root;
 
   /* command-line options */
 extern int debug_level;
Index: server/pipe.c
===================================================================
RCS file: /home/wine/wine/server/pipe.c,v
retrieving revision 1.24
diff -u -r1.24 pipe.c
--- server/pipe.c	30 May 2002 20:12:58 -0000	1.24
+++ server/pipe.c	16 Jun 2002 16:14:36 -0000
@@ -68,6 +68,8 @@
     no_flush,                     /* flush */
     pipe_get_info,                /* get_file_info */
     NULL,                         /* queue_async */
+    NULL,                         /* enumerate */
+    NULL,                         /* get_child_handle */
     pipe_destroy                  /* destroy */
 };
 
Index: server/process.c
===================================================================
RCS file: /home/wine/wine/server/process.c,v
retrieving revision 1.87
diff -u -r1.87 process.c
--- server/process.c	2 Jun 2002 21:22:22 -0000	1.87
+++ server/process.c	16 Jun 2002 16:14:37 -0000
@@ -69,6 +69,8 @@
     no_flush,                    /* flush */
     no_get_file_info,            /* get_file_info */
     NULL,                        /* queue_async */
+    NULL,                         /* enumerate */
+    NULL,                         /* get_child_handle */
     process_destroy              /* destroy */
 };
 
@@ -109,6 +111,8 @@
     no_flush,                      /* flush */
     no_get_file_info,              /* get_file_info */
     NULL,                        /* queue_async */
+    NULL,                         /* enumerate */
+    NULL,                         /* get_child_handle */
     startup_info_destroy           /* destroy */
 };
 
Index: server/protocol.def
===================================================================
RCS file: /home/wine/wine/server/protocol.def,v
retrieving revision 1.39
diff -u -r1.39 protocol.def
--- server/protocol.def	2 Jun 2002 21:22:22 -0000	1.39
+++ server/protocol.def	16 Jun 2002 16:14:38 -0000
@@ -572,7 +572,7 @@
     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 */
+    VARARG(filename,unicode_str); /* file name */
 @REPLY
     obj_handle_t handle;        /* handle to the file */
 @END
Index: server/queue.c
===================================================================
RCS file: /home/wine/wine/server/queue.c,v
retrieving revision 1.25
diff -u -r1.25 queue.c
--- server/queue.c	26 Apr 2002 19:05:18 -0000	1.25
+++ server/queue.c	16 Jun 2002 16:14:39 -0000
@@ -130,6 +130,8 @@
     no_flush,                  /* flush */
     no_get_file_info,          /* get_file_info */
     NULL,                      /* queue_async */
+    NULL,
+    NULL,
     msg_queue_destroy          /* destroy */
 };
 
Index: server/registry.c
===================================================================
RCS file: /home/wine/wine/server/registry.c,v
retrieving revision 1.39
diff -u -r1.39 registry.c
--- server/registry.c	31 May 2002 23:06:53 -0000	1.39
+++ server/registry.c	16 Jun 2002 16:14:39 -0000
@@ -47,7 +47,9 @@
 #include "winreg.h"
 #include "winnt.h" /* registry definitions */
 #include "ntddk.h"
+#include "registry.h"
 
+#if 0
 /* a registry key */
 struct key
 {
@@ -91,6 +93,8 @@
 #define IS_SPECIAL_ROOT_HKEY(h)   (((unsigned int)(h) >= HKEY_SPECIAL_ROOT_FIRST) && \
                                    ((unsigned int)(h) <= HKEY_SPECIAL_ROOT_LAST))
 
+#endif
+
 static struct key *special_root_keys[NB_SPECIAL_ROOT_KEYS];
 
 /* the real root key */
@@ -160,6 +164,8 @@
     no_flush,                /* flush */
     no_get_file_info,        /* get_file_info */
     NULL,                    /* queue_async */
+    NULL,                    /* enumerate */
+    NULL,                    /* get_child_handle */
     key_destroy              /* destroy */
 };
 
@@ -503,7 +509,7 @@
 
 /* open a subkey */
 /* warning: the key name must be writeable (use copy_path) */
-static struct key *open_key( struct key *key, WCHAR *name )
+struct key *open_key( struct key *key, WCHAR *name )
 {
     int index;
     WCHAR *path;
@@ -722,7 +728,7 @@
 }
 
 /* find the named value of a given key and return its index in the array */
-static struct key_value *find_value( const struct key *key, const WCHAR *name, int *index )
+struct key_value *find_value( const struct key *key, const WCHAR *name, int *index )
 {
     int i, min, max, res;
 
@@ -927,7 +933,7 @@
 }
 
 /* get the registry key corresponding to an hkey handle */
-static struct key *get_hkey_obj( obj_handle_t hkey, unsigned int access )
+struct key *get_hkey_obj( obj_handle_t hkey, unsigned int access )
 {
     struct key *key;
 
Index: server/request.c
===================================================================
RCS file: /home/wine/wine/server/request.c,v
retrieving revision 1.64
diff -u -r1.64 request.c
--- server/request.c	30 May 2002 20:12:58 -0000	1.64
+++ server/request.c	16 Jun 2002 16:14:40 -0000
@@ -81,6 +81,8 @@
     no_flush,                      /* flush */
     no_get_file_info,              /* get_file_info */
     NULL,                          /* queue_async */
+    NULL,                         /* enumerate */
+    NULL,                         /* get_child_handle */
     no_destroy                     /* destroy */
 };
 
Index: server/semaphore.c
===================================================================
RCS file: /home/wine/wine/server/semaphore.c,v
retrieving revision 1.21
diff -u -r1.21 semaphore.c
--- server/semaphore.c	30 May 2002 20:12:58 -0000	1.21
+++ server/semaphore.c	16 Jun 2002 16:14:40 -0000
@@ -56,6 +56,8 @@
     no_flush,                      /* flush */
     no_get_file_info,              /* get_file_info */
     NULL,                          /* queue_async */
+    NULL,                         /* enumerate */
+    NULL,                         /* get_child_handle */
     no_destroy                     /* destroy */
 };
 
Index: server/serial.c
===================================================================
RCS file: /home/wine/wine/server/serial.c,v
retrieving revision 1.22
diff -u -r1.22 serial.c
--- server/serial.c	30 May 2002 20:12:58 -0000	1.22
+++ server/serial.c	16 Jun 2002 16:14:40 -0000
@@ -95,6 +95,8 @@
     no_flush,                     /* flush */
     serial_get_info,              /* get_file_info */
     serial_queue_async,           /* queue_async */
+    NULL,                         /* enumerate */
+    NULL,                         /* get_child_handle */
     destroy_serial                /* destroy */
 };
 
Index: server/smb.c
===================================================================
RCS file: /home/wine/wine/server/smb.c,v
retrieving revision 1.3
diff -u -r1.3 smb.c
--- server/smb.c	31 May 2002 23:06:53 -0000	1.3
+++ server/smb.c	16 Jun 2002 16:14:40 -0000
@@ -78,6 +78,8 @@
     no_flush,                  /* flush */
     smb_get_info,              /* get_file_info */
     NULL,                      /* queue_async */
+    NULL,                         /* enumerate */
+    NULL,                         /* get_child_handle */
     destroy_smb                /* destroy */
 };
 
Index: server/snapshot.c
===================================================================
RCS file: /home/wine/wine/server/snapshot.c,v
retrieving revision 1.15
diff -u -r1.15 snapshot.c
--- server/snapshot.c	26 Apr 2002 19:05:18 -0000	1.15
+++ server/snapshot.c	16 Jun 2002 16:14:40 -0000
@@ -68,6 +68,8 @@
     no_flush,                     /* flush */
     no_get_file_info,             /* get_file_info */
     NULL,                         /* queue_async */
+    NULL,                         /* enumerate */
+    NULL,                         /* get_child_handle */
     snapshot_destroy              /* destroy */
 };
 
Index: server/sock.c
===================================================================
RCS file: /home/wine/wine/server/sock.c,v
retrieving revision 1.35
diff -u -r1.35 sock.c
--- server/sock.c	31 May 2002 23:06:53 -0000	1.35
+++ server/sock.c	16 Jun 2002 16:14:41 -0000
@@ -102,6 +102,8 @@
     no_flush,                     /* flush */
     sock_get_info,                /* get_file_info */
     sock_queue_async,             /* queue_async */
+    NULL,                         /* enumerate */
+    NULL,                         /* get_child_handle */
     sock_destroy                  /* destroy */
 };
 
Index: server/thread.c
===================================================================
RCS file: /home/wine/wine/server/thread.c,v
retrieving revision 1.80
diff -u -r1.80 thread.c
--- server/thread.c	30 May 2002 20:12:58 -0000	1.80
+++ server/thread.c	16 Jun 2002 16:14:41 -0000
@@ -92,6 +92,8 @@
     no_flush,                   /* flush */
     no_get_file_info,           /* get_file_info */
     NULL,                       /* queue_async */
+    NULL,                         /* enumerate */
+    NULL,                         /* get_child_handle */
     destroy_thread              /* destroy */
 };
 
Index: server/timer.c
===================================================================
RCS file: /home/wine/wine/server/timer.c,v
retrieving revision 1.15
diff -u -r1.15 timer.c
--- server/timer.c	26 Apr 2002 19:05:18 -0000	1.15
+++ server/timer.c	16 Jun 2002 16:14:41 -0000
@@ -63,6 +63,8 @@
     no_flush,                  /* flush */
     no_get_file_info,          /* get_file_info */
     NULL,                      /* queue_async */
+    NULL,                         /* enumerate */
+    NULL,                         /* get_child_handle */
     timer_destroy              /* destroy */
 };
 
Index: server/trace.c
===================================================================
RCS file: /home/wine/wine/server/trace.c,v
retrieving revision 1.135
diff -u -r1.135 trace.c
--- server/trace.c	2 Jun 2002 21:22:22 -0000	1.135
+++ server/trace.c	16 Jun 2002 16:14:43 -0000
@@ -769,7 +769,7 @@
     fprintf( stderr, " attrs=%08x,", req->attrs );
     fprintf( stderr, " drive_type=%d,", req->drive_type );
     fprintf( stderr, " filename=" );
-    dump_varargs_string( cur_size );
+    dump_varargs_unicode_str( cur_size );
 }
 
 static void dump_create_file_reply( const struct create_file_reply *req )
Index: server/unicode.c
===================================================================
RCS file: /home/wine/wine/server/unicode.c,v
retrieving revision 1.4
diff -u -r1.4 unicode.c
--- server/unicode.c	26 Apr 2002 19:05:18 -0000	1.4
+++ server/unicode.c	16 Jun 2002 16:14:43 -0000
@@ -24,8 +24,18 @@
 #include <ctype.h>
 #include <stdio.h>
 
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <errno.h>
+
+#include "thread.h"
 #include "unicode.h"
 
+static const union cptable *ansi_cptable;
+
+
 /* dump a Unicode string with proper escaping */
 int dump_strW( const WCHAR *str, size_t len, FILE *f, char escape[2] )
 {
@@ -68,3 +78,85 @@
     count += pos - buffer;
     return count;
 }
+
+int strcasecmpnW(const WCHAR *x, const WCHAR *y, int n)
+{
+    int i;
+    for(i=0; i<n; i++)
+    {
+        if((x[i]&~0x20)>(y[i]&~0x20))
+            return 1;
+        if((x[i]&~0x20)<(y[i]&~0x20))
+            return -1;
+    }
+    return 0;
+}
+
+/* FIXME: hardcoded to ANSI for the time being */
+
+int file_unicode_to_apath(const WCHAR *path_w, char *path_a, int len)
+{
+    if(!ansi_cptable)
+        ansi_cptable = cp_get_table( 1252 );
+    return cp_wcstombs( ansi_cptable, 0, path_w, -1, path_a, len, NULL, NULL);
+}
+
+int file_apath_to_unicode(const char *path_a, WCHAR *path_w, int len)
+{
+    if(!ansi_cptable)
+        ansi_cptable = cp_get_table( 1252 );
+    return cp_mbstowcs( ansi_cptable, 0, path_a, -1, path_w, len);
+}
+
+int openw(const WCHAR *name, int access, int mode)
+{
+    char name_a[MAX_PATH];
+    name_a[0]=0;
+    file_unicode_to_apath(name,name_a,MAX_PATH);
+    return open(name_a,access,mode);
+}
+
+int unlinkw(const WCHAR *name)
+{
+    char name_a[MAX_PATH];
+    name_a[0]=0;
+    file_unicode_to_apath(name,name_a,MAX_PATH);
+    return unlink(name_a);
+}
+
+int statw(const WCHAR *name, struct stat *st)
+{
+    char name_a[MAX_PATH];
+    name_a[0]=0;
+    file_unicode_to_apath(name,name_a,MAX_PATH);
+    return stat(name_a,st);
+}
+
+int utimew(const WCHAR *name, struct utimbuf *utimbuf)
+{
+    char name_a[MAX_PATH];
+    name_a[0]=0;
+    file_unicode_to_apath(name,name_a,MAX_PATH);
+    return utime(name_a,utimbuf);
+}
+
+DIR *opendirw(const WCHAR *name)
+{
+    char name_a[MAX_PATH];
+    name_a[0]=0;
+    file_unicode_to_apath(name,name_a,MAX_PATH);
+    return opendir(name_a);
+}
+
+static struct direntw g_de;
+
+struct direntw *readdirw(DIR *dir)
+{
+    struct dirent *de = readdir(dir);
+    if(!de)
+        return NULL;
+    g_de.d_name[0]=0;
+    file_apath_to_unicode(de->d_name, g_de.d_name, sizeof(g_de.d_name)/sizeof(WCHAR));
+    return &g_de;
+}
+
Index: server/unicode.h
===================================================================
RCS file: /home/wine/wine/server/unicode.h,v
retrieving revision 1.8
diff -u -r1.8 unicode.h
--- server/unicode.h	10 Mar 2002 00:18:36 -0000	1.8
+++ server/unicode.h	16 Jun 2002 16:14:43 -0000
@@ -22,6 +22,9 @@
 #define __WINE_SERVER_UNICODE_H
 
 #include <stdio.h>
+#include <dirent.h>
+#include <sys/time.h>
+#include <utime.h>
 
 #include "windef.h"
 #include "wine/unicode.h"
@@ -35,4 +38,20 @@
 
 extern int dump_strW( const WCHAR *str, size_t len, FILE *f, char escape[2] );
 
+extern int strcasecmpnW(const WCHAR *x, const WCHAR *y, int n);
+
+extern int openw(const WCHAR *name, int access, int mode);
+extern int unlinkw(const WCHAR *name);
+extern int statw(const WCHAR *name, struct stat *st);
+extern int utimew(const WCHAR *name, struct utimbuf *utimbuf);
+
+struct direntw 
+{
+    WCHAR d_name[NAME_MAX+1];
+};
+
+extern DIR *opendirw(const WCHAR *name);
+extern struct direntw *readdirw(DIR *dir);
+
 #endif  /* __WINE_SERVER_UNICODE_H */
+
--- /dev/null	Mon Jul 18 08:46:18 1994
+++ server/ntroot.c	Mon Jun 17 09:27:22 2002
@@ -0,0 +1,302 @@
+/*
+ * Server-side NT virtual directory management
+ *
+ * Copyright (C) 1998 Alexandre Julliard
+ * Copyright (C) 2002 Mike McCormack
+ *
+ * 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 <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#ifdef HAVE_SYS_ERRNO_H
+#include <sys/errno.h>
+#endif
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <time.h>
+#include <unistd.h>
+#include <utime.h>
+
+#include "winerror.h"
+#include "winbase.h"
+
+#include "handle.h"
+#include "thread.h"
+#include "request.h"
+#include "async.h"
+#include "unicode.h"
+
+#include "winnt.h"
+#include "winreg.h"
+#include "registry.h"
+
+struct vdir
+{
+    struct object       obj;        /* object header */
+    int                 count;
+    struct object     **children;
+    WCHAR             **names;
+};
+
+static void vdir_dump( struct object *obj, int verbose );
+static int vdir_enumerate(struct object *, unsigned int index, WCHAR **name, int *len);
+static int vdir_get_child( struct object *obj, const WCHAR *nameptr, size_t len, unsigned int access,
+                           unsigned int sharing, int create, unsigned int attrs, struct object **);
+static void vdir_destroy(struct object *obj);
+
+static const struct object_ops vdir_ops =
+{
+    sizeof(struct vdir),          /* size */
+    vdir_dump,                    /* dump */
+    no_add_queue,                 /* add_queue */
+    NULL,                         /* remove_queue */
+    NULL,                         /* signaled */
+    NULL,                         /* satisfied */
+    NULL,                         /* get_poll_events */
+    NULL,                         /* poll_event */
+    no_get_fd,                    /* get_fd */
+    no_flush,                     /* flush */
+    no_get_file_info,             /* get_file_info */
+    NULL,                         /* queue_async */
+    vdir_enumerate,               /* enumerate */
+    vdir_get_child,               /* get_child_handle */
+    vdir_destroy                  /* destroy */
+};
+
+/* struct vdir *root = NULL; */
+
+static WCHAR szwDosDev[] = {'D','o','s','D','e','v','i','c','e','s', 0 };
+static WCHAR szwPath[] = {'P','a','t','h', 0 };
+static WCHAR szwKeyName[] = { 'D','r','i','v','e',' ' };
+static WCHAR szwProfile[] = { 'S','o','f','t','w','a','r','e','\\',
+                       'W','i','n','e','\\',
+                       'W','i','n','e','\\',
+                       'C','o','n','f','i','g','\\',0 };
+
+static void vdir_dump( struct object *obj, int verbose )
+{
+    struct vdir *vdir = (struct vdir *)obj;
+    int i;
+
+    assert( obj->ops == &vdir_ops );
+    fprintf( stderr, "%d nodes", vdir->count );
+    for(i=0; i<vdir->count; i++)
+    {
+        fprintf( stderr, "node %d : " , i);
+        dump_strW(vdir->names[i],strlenW(vdir->names[i]),stderr,"[]");
+        fprintf( stderr, "\n" );
+    }
+}
+
+static void vdir_destroy( struct object *obj )
+{
+    struct vdir *vdir = (struct vdir *)obj;
+    int i;
+
+    assert( obj->ops == &vdir_ops );
+    for(i=0; i<vdir->count; i++)
+    {
+        free(vdir->names[i]);
+        release_object(vdir->children[i]);
+    }
+    free(vdir->names);
+    free(vdir->children);
+}
+
+/* FIXME: detect duplicates? */
+static void add_child_node(struct vdir* dir, struct object *obj, WCHAR *name, int len)
+{
+    int count = (dir->count + 0x10) & ~0x0f;
+    WCHAR *str;
+
+    if(len<0)
+        len = strlenW(name);
+
+    /* duplicate the string */
+    str = malloc( (len+1) * sizeof (WCHAR) );
+    memcpy(str, name, len*sizeof(WCHAR));
+    str[len]=0;
+
+    /* allocate more memory if necessary */
+    dir->children = (struct object **)realloc(dir->children, sizeof (struct object*)*count);
+    dir->names = (WCHAR**)realloc(dir->names, sizeof (WCHAR*)*count);
+
+    dir->children[dir->count] = obj;
+    dir->names[dir->count] = str;
+    dir->count++;
+
+    grab_object(obj);
+}
+
+static int vdir_enumerate(struct object *obj, unsigned int index, WCHAR **name, int *len)
+{
+    struct vdir *dir = (struct vdir *)obj;
+
+    assert(obj->ops = &vdir_ops);
+
+    if (index >= dir->count)
+        return STATUS_NO_MORE_FILES;
+    strcpyW(*name, dir->names[index] );
+    *len = strlenW(dir->names[index]);
+
+    return STATUS_SUCCESS;
+}
+
+static int vdir_get_child( 
+     struct object *obj, const WCHAR *nameptr, size_t len, unsigned int access,
+     unsigned int sharing, int create, unsigned int attrs, struct object **object)
+{
+    struct vdir *dir = (struct vdir *)obj;
+    int i, x;
+
+    assert(obj->ops = &vdir_ops);
+
+    /* x is the length of the first section of the pathname */
+    for(x=0; x<len; x++)
+        if(nameptr[x]=='\\')
+            break;
+
+    for(i=0; i<dir->count; i++)
+    {
+        if(strlenW(dir->names[i]) != x)
+            continue;
+        if(memcmp(nameptr, dir->names[i], x*sizeof(WCHAR))) /* case sensitive */
+            continue;
+        if(nameptr[x]=='\\')
+            x++;
+        if(x>=len)
+        {
+            *object = dir->children[i];
+            grab_object(*object);
+            return STATUS_SUCCESS;
+        }
+
+        return dir->children[i]->ops->open_child(dir->children[i], 
+                    &nameptr[x], len - x, access, sharing, create, attrs, object);
+    }
+    return STATUS_OBJECT_NAME_NOT_FOUND;
+}
+
+/* given a pointer to a registry key [Drive X] and the DosDevices node,
+   create a directory object and add it to DosDevices as drive X: */
+static int create_drive(struct vdir *dosdev, struct key *key)
+{
+    struct object *obj;
+    struct key_value *val;
+    int index, len;
+    WCHAR szName[3];
+
+    if(!key)
+        return -1;
+
+    /* check this key is of the form [Drive X] */
+    len = strlenW(key->name);
+    if (len != (1 + sizeof szwKeyName/sizeof (WCHAR)))
+        return -1;
+    if (memcmp(key->name, szwKeyName, sizeof szwKeyName) )
+        return -1;
+
+    /* construct the name for this drive */
+    szName[0] = key->name[len-1];
+    szName[1] = ':';
+    szName[2] = 0;
+
+    /* find the Path= entry in the registry key */
+    val = find_value(key, szwPath, &index);
+    if(!val)
+        return -1;
+
+    obj = get_dir(val->data, val->len/sizeof (WCHAR));
+    if(!obj)
+        return -1;
+
+    add_child_node(dosdev, obj,  szName, 2);
+
+    release_object(obj);
+
+    return 0;
+}
+
+/* create and fill the DosDevices node */
+
+static struct object* get_dosdevs(void)
+{
+    struct vdir *dosdevs = alloc_object(&vdir_ops, -1);
+    struct key *keylm, *key;
+    int i;
+
+    if(!dosdevs)
+        return NULL;
+
+    dosdevs->children = NULL;
+    dosdevs->names = NULL;
+    dosdevs->count = 0;
+
+    keylm = get_hkey_obj(HKEY_LOCAL_MACHINE, KEY_ALL_ACCESS);
+    if(!keylm)
+        goto end;
+
+    key = open_key(keylm, szwProfile);
+    release_object(keylm);
+    if(!key)
+        goto end;
+
+    /* FIXME : we should change [Drive X] to \\Drive\\X */
+    for(i=0; i<key->last_subkey; i++)
+        create_drive(dosdevs, key->subkeys[i]);
+
+    release_object(key);
+
+    return &dosdevs->obj;
+end:
+    release_object(dosdevs);
+    return NULL;
+}
+
+/* create the root object of the NT filesystem */
+
+struct object* get_ntroot(void)
+{
+    struct vdir *root;
+    struct object *dosdevs = get_dosdevs();
+
+    if(!dosdevs)
+        return NULL;
+
+    root = alloc_object(&vdir_ops, -1);
+    if(!root)
+    {
+        release_object(dosdevs);
+        return NULL;
+    }
+    root->children = NULL;
+    root->names = NULL;
+    root->count = 0;
+
+    add_child_node(root, dosdevs, szwDosDev, -1);
+    release_object(dosdevs);
+
+    return (struct object *)root;
+}
+
--- /dev/null	Mon Jul 18 08:46:18 1994
+++ server/dir.c	Mon Jun 17 09:29:51 2002
@@ -0,0 +1,283 @@
+/*
+ * Server-side directory management
+ *
+ * Copyright (C) 1998 Alexandre Julliard
+ * Copyright (C) 2002 Mike McCormack
+ *
+ * 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 <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#ifdef HAVE_SYS_ERRNO_H
+#include <sys/errno.h>
+#endif
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <time.h>
+#include <unistd.h>
+#include <utime.h>
+
+#include "winerror.h"
+#include "winbase.h"
+
+#include "handle.h"
+#include "thread.h"
+#include "request.h"
+#include "unicode.h"
+
+#include "winnt.h"
+
+struct entry
+{
+    struct stat st;
+    int         len;
+    WCHAR       name[1];
+};
+
+struct dir
+{
+    struct object       obj;        /* object header */
+    WCHAR              *name;       /* file name */
+    int                 drive_type; /* type of drive the file is on */
+    int                 count;
+    struct entry      **children;
+};
+
+static void dir_dump( struct object *obj, int verbose );
+static void dir_destroy( struct object *obj );
+static int dir_enumerate(struct object *obj, unsigned int index, WCHAR **name, int *len);
+static int dir_get_child( struct object *obj, const WCHAR *nameptr, size_t len, unsigned int access,
+                                 unsigned int sharing, int create, unsigned int attrs, struct object **);
+
+
+static const struct object_ops dir_ops =
+{
+    sizeof(struct dir),           /* size */
+    dir_dump,                     /* dump */
+    no_add_queue,                 /* add_queue */
+    NULL,                         /* remove_queue */
+    NULL,                         /* signaled */
+    NULL,                         /* satisfied */
+    NULL,                         /* get_poll_events */
+    NULL,                         /* poll_event */
+    no_get_fd,                    /* get_fd */
+    no_flush,                     /* flush */
+    no_get_file_info,             /* get_file_info */
+    NULL,                         /* queue_async */
+    dir_enumerate,                /* enumerate */
+    dir_get_child,                /* get_child_handle */
+    dir_destroy                   /* destroy */
+};
+
+static void dir_dump( struct object *obj, int verbose )
+{
+    struct dir *dir = (struct dir *) obj;
+
+    assert(obj->ops = &dir_ops);
+    fprintf(stderr,"dump: ");
+    dump_strW(dir->name,strlenW(dir->name),stderr,"[]");
+    fprintf(stderr,", %d entries\n",dir->count);
+}
+
+static void dir_destroy( struct object *obj )
+{
+    struct dir *dir = (struct dir *) obj;
+    int i;
+
+    assert(obj->ops = &dir_ops);
+
+    for(i=0; i<dir->count; i++)
+        free(dir->children[i]);
+    free(dir->children);
+    free(dir->name);
+}
+
+static int find_entry(struct dir *dir, const WCHAR *name, int len)
+{
+    int i;
+
+    /* check for duplicate case insensitive entries */
+    for(i=0; i<dir->count; i++)
+    {
+        if( len != dir->children[i]->len)
+            continue;
+        if( strcasecmpnW(name, dir->children[i]->name, len))
+            continue;
+        return i;
+    }
+    return -1;
+}
+
+static int dir_enumerate(struct object *obj, unsigned int index, WCHAR **name, int *len)
+{
+    struct dir *dir = (struct dir *) obj;
+
+    assert(obj->ops = &dir_ops);
+
+    if(index >= dir->count)
+        return STATUS_NO_MORE_FILES;
+
+    /* FIXME: check the filesystem hasn't changed in the meantime */
+
+    *name = dir->children[index]->name;
+    *len = dir->children[index]->len;
+
+    return STATUS_SUCCESS;
+}
+
+static int dir_get_child( struct object *obj, const WCHAR *name, size_t len, unsigned int access,
+                                 unsigned int sharing, int create, unsigned int attrs, struct object **object)
+{
+    int size, x, n;
+    WCHAR full_name[MAX_PATH];
+    struct dir *dir = (struct dir*) obj;
+
+    assert(obj->ops == &dir_ops);
+
+    /* x is the length of the first section of the pathname */
+    for(x=0; x<len; x++)
+        if(name[x]=='\\')
+            break;
+
+    n = find_entry(dir, name, x);
+    if(n<0)
+        return STATUS_OBJECT_NAME_NOT_FOUND;
+
+    strcpyW(full_name, dir->name);
+    size = strlenW(full_name);
+    if(full_name[size-1]!='/')
+    {
+        full_name[size++]='/';
+        full_name[size]=0;
+    }
+
+    memcpy(&full_name[size], dir->children[n]->name, len*sizeof(WCHAR));
+    size += len;
+    full_name[size] = 0;
+
+    if(name[x]=='\\')
+        x++;
+
+    if(S_ISDIR(dir->children[n]->st.st_mode))
+    {
+        struct object *next = get_dir(full_name, size);
+        int r;
+
+        r = next->ops->open_child( next, name+x, len-x, access, 
+                                   sharing, create, attrs, object);
+        release_object(next);
+        return r;
+    }
+    else
+    {
+        *object = create_file( full_name, size, access, sharing, create, attrs, 0);
+
+        if(*object)
+            return STATUS_SUCCESS;
+    }
+
+    return STATUS_OBJECT_NAME_NOT_FOUND;
+}
+
+int add_entry(struct dir *dir, WCHAR *name, int len)
+{
+    struct entry *ent = malloc(sizeof (struct entry) + len * sizeof(WCHAR));
+    WCHAR path[MAX_PATH];
+    int sz;
+
+    if(0<=find_entry(dir, name, len))
+        goto err;
+
+    sz = strlenW(dir->name);
+    strcpyW(path, dir->name);
+    if(path[sz-1]!='/')
+    {
+        path[sz++]='/';
+        path[sz]=0;
+    }
+    memcpy(&path[sz], name, len*sizeof (WCHAR));
+    path[sz+len] = 0;
+
+    if(0>statw(path, &ent->st))
+        goto err;
+    memcpy(ent->name, name, len*sizeof (WCHAR));
+    ent->len = len;
+
+    /* reallocate the array */
+    dir->children = realloc(dir->children, (dir->count+1)*sizeof(struct entry*));
+    if(!dir->children)
+    {
+        fprintf(stderr,"empty\n");
+        goto err;
+    }
+    dir->children[dir->count++] = ent;
+
+    return 0;
+err:
+    free(ent);
+    return -1;
+}
+
+struct object* create_dir(WCHAR *path, int len)
+{
+    DIR *d = opendirw(path);
+    struct dir *dir;
+
+    if(!d)
+        return NULL;
+
+    dir = alloc_object(&dir_ops, -1);
+    if(!dir)
+        return NULL;
+
+    dir->name = (WCHAR*) malloc(len*sizeof(WCHAR));
+    memcpy(dir->name, path, len*sizeof(WCHAR));
+    dir->drive_type = 0;
+    dir->count = 0;
+    dir->children = NULL;
+
+    while(1)
+    {
+        struct direntw *de = readdirw(d);
+        if(!de)
+            break;
+        if( (de->d_name[0]=='.') && (de->d_name[1]==0) )
+            continue;
+        if( (de->d_name[0]=='.') && (de->d_name[1]=='.') && (de->d_name[2]==0) )
+            continue;
+
+        add_entry(dir, de->d_name, strlenW(de->d_name));
+    }
+    closedir(d);
+
+    return &dir->obj;
+}
+
+struct object* get_dir(WCHAR *path, int len)
+{
+    /* FIXME: need to create a hash of cached directory entries here
+              perhaps this can go in with the existing file hash? */
+
+    return create_dir(path, len);
+}
--- /dev/null	Mon Jul 18 08:46:18 1994
+++ server/registry.h	Wed Jun 12 04:48:44 2002
@@ -0,0 +1,53 @@
+
+#ifndef SERVER_REGISTRY_H
+#define SERVER_REGISTRY_H
+
+/* a registry key */
+struct key
+{
+    struct object     obj;         /* object header */
+    WCHAR            *name;        /* key name */
+    WCHAR            *class;       /* key class */
+    struct key       *parent;      /* parent key */
+    int               last_subkey; /* last in use subkey */
+    int               nb_subkeys;  /* count of allocated subkeys */
+    struct key      **subkeys;     /* subkeys array */
+    int               last_value;  /* last in use value */
+    int               nb_values;   /* count of allocated values in array */
+    struct key_value *values;      /* values array */
+    short             flags;       /* flags */
+    short             level;       /* saving level */
+    time_t            modif;       /* last modification time */
+};
+
+/* key flags */
+#define KEY_VOLATILE 0x0001  /* key is volatile (not saved to disk) */
+#define KEY_DELETED  0x0002  /* key has been deleted */
+#define KEY_ROOT     0x0004  /* key is a root key */
+
+/* a key value */
+struct key_value
+{
+    WCHAR            *name;    /* value name */
+    int               type;    /* value type */
+    size_t            len;     /* value data length in bytes */
+    void             *data;    /* pointer to value data */
+};
+
+#define MIN_SUBKEYS  8   /* min. number of allocated subkeys per key */
+#define MIN_VALUES   8   /* min. number of allocated values per key */
+
+
+/* the special root keys */
+#define HKEY_SPECIAL_ROOT_FIRST   HKEY_CLASSES_ROOT
+#define HKEY_SPECIAL_ROOT_LAST    HKEY_DYN_DATA
+#define NB_SPECIAL_ROOT_KEYS      (HKEY_SPECIAL_ROOT_LAST - HKEY_SPECIAL_ROOT_FIRST + 1)
+#define IS_SPECIAL_ROOT_HKEY(h)   (((unsigned int)(h) >= HKEY_SPECIAL_ROOT_FIRST) && \
+                                   ((unsigned int)(h) <= HKEY_SPECIAL_ROOT_LAST))
+
+struct key *get_hkey_obj( obj_handle_t hkey, unsigned int access );
+struct key_value *find_value( const struct key *key, const WCHAR *name, int *index );
+struct key *open_key( struct key *key, WCHAR *name );
+
+#endif /* SERVER_REGISTRY_H */
+


More information about the wine-devel mailing list