diff --git a/dlls/ntdll/om.c b/dlls/ntdll/om.c
index 41d8bef41eaac5fb8d676d2fae7246b97556abbf..bd314a397e8d4547af4c578f9e2cdc971dcf89ee 100644
--- a/dlls/ntdll/om.c
+++ b/dlls/ntdll/om.c
@@ -362,30 +362,77 @@ NTSTATUS WINAPI NtClose( HANDLE Handle )
  *  Success: ERROR_SUCCESS.
  *  Failure: An NTSTATUS error code.
  */
-NTSTATUS WINAPI NtOpenDirectoryObject(
-	PHANDLE DirectoryHandle,
-	ACCESS_MASK DesiredAccess,
-	POBJECT_ATTRIBUTES ObjectAttributes)
+NTSTATUS WINAPI NtOpenDirectoryObject(PHANDLE DirectoryHandle, ACCESS_MASK DesiredAccess,
+                                      POBJECT_ATTRIBUTES ObjectAttributes)
 {
-	FIXME("(%p,0x%08lx,%p): stub\n",
-	DirectoryHandle, DesiredAccess, ObjectAttributes);
-	dump_ObjectAttributes(ObjectAttributes);
-	return 0;
+    NTSTATUS ret;
+    TRACE("(%p,0x%08lx)\n", DirectoryHandle, DesiredAccess);
+    dump_ObjectAttributes(ObjectAttributes);
+
+    if (!DirectoryHandle) return STATUS_ACCESS_VIOLATION;
+    if (!ObjectAttributes) return STATUS_INVALID_PARAMETER;
+    /* Have to test it here because server won't know difference between
+     * ObjectName == NULL and ObjectName == "" */
+    if (!ObjectAttributes->ObjectName)
+    {
+        if (ObjectAttributes->RootDirectory)
+            return STATUS_OBJECT_NAME_INVALID;
+        else
+            return STATUS_OBJECT_PATH_SYNTAX_BAD;
+    }
+
+    SERVER_START_REQ(open_directory)
+    {
+        req->access = DesiredAccess;
+        req->attributes = ObjectAttributes->Attributes;
+        req->rootdir = ObjectAttributes->RootDirectory;
+        if (ObjectAttributes->ObjectName)
+            wine_server_add_data(req, ObjectAttributes->ObjectName->Buffer,
+                                 ObjectAttributes->ObjectName->Length);
+        ret = wine_server_call( req );
+        *DirectoryHandle = reply->handle;
+    }
+    SERVER_END_REQ;
+    return ret;
 }
 
 /******************************************************************************
  *  NtCreateDirectoryObject	[NTDLL.@]
  *  ZwCreateDirectoryObject	[NTDLL.@]
+ *
+ * Create a namespace directory object.
+ * 
+ * PARAMS
+ *  DirectoryHandle  [O] Destination for the new directory handle
+ *  DesiredAccess    [I] Desired access to the directory
+ *  ObjectAttributes [I] Structure describing the directory
+ *
+ * RETURNS
+ *  Success: ERROR_SUCCESS.
+ *  Failure: An NTSTATUS error code.
  */
-NTSTATUS WINAPI NtCreateDirectoryObject(
-	PHANDLE DirectoryHandle,
-	ACCESS_MASK DesiredAccess,
-	POBJECT_ATTRIBUTES ObjectAttributes)
+NTSTATUS WINAPI NtCreateDirectoryObject(PHANDLE DirectoryHandle, ACCESS_MASK DesiredAccess,
+                                        POBJECT_ATTRIBUTES ObjectAttributes)
 {
-	FIXME("(%p,0x%08lx,%p),stub!\n",
-	DirectoryHandle,DesiredAccess,ObjectAttributes);
-	dump_ObjectAttributes(ObjectAttributes);
-	return 0;
+    NTSTATUS ret;
+    TRACE("(%p,0x%08lx)\n", DirectoryHandle, DesiredAccess);
+    dump_ObjectAttributes(ObjectAttributes);
+
+    if (!DirectoryHandle) return STATUS_ACCESS_VIOLATION;
+
+    SERVER_START_REQ(create_directory)
+    {
+        req->access = DesiredAccess;
+        req->attributes = ObjectAttributes ? ObjectAttributes->Attributes : 0;
+        req->rootdir = ObjectAttributes ? ObjectAttributes->RootDirectory : 0;
+        if (ObjectAttributes && ObjectAttributes->ObjectName)
+            wine_server_add_data(req, ObjectAttributes->ObjectName->Buffer,
+                                 ObjectAttributes->ObjectName->Length);
+        ret = wine_server_call( req );
+        *DirectoryHandle = reply->handle;
+    }
+    SERVER_END_REQ;
+    return ret;
 }
 
 /******************************************************************************
diff --git a/dlls/ntdll/tests/om.c b/dlls/ntdll/tests/om.c
index c0a4921f163f7c5ba82239d220ae24667f314ff9..747c47777438e25e384f304b435bf0e4b562df37 100644
--- a/dlls/ntdll/tests/om.c
+++ b/dlls/ntdll/tests/om.c
@@ -186,11 +186,11 @@ static void test_name_collisions(void)
     InitializeObjectAttributes(&attr, &str, 0, 0, NULL);
     pRtlCreateUnicodeStringFromAsciiz(&str, "\\");
     h = 0;
-    todo_wine{ DIR_TEST_CREATE_FAILURE(&h, STATUS_OBJECT_NAME_COLLISION) }
+    DIR_TEST_CREATE_FAILURE(&h, STATUS_OBJECT_NAME_COLLISION)
     ok(h == 0, "Failed create returned valid handle! (%p)\n", h);
     InitializeObjectAttributes(&attr, &str, OBJ_OPENIF, 0, NULL);
 
-    todo_wine{ DIR_TEST_CREATE_FAILURE(&h, STATUS_OBJECT_NAME_EXISTS) }
+    DIR_TEST_CREATE_FAILURE(&h, STATUS_OBJECT_NAME_EXISTS)
     pNtClose(h);
     status = pNtCreateMutant(&h, GENERIC_ALL, &attr, FALSE);
     todo_wine ok(status == STATUS_OBJECT_TYPE_MISMATCH,
@@ -199,7 +199,7 @@ static void test_name_collisions(void)
 
     pRtlCreateUnicodeStringFromAsciiz(&str, "\\??\\PIPE\\om.c-mutant");
     status = pNtCreateMutant(&h, GENERIC_ALL, &attr, FALSE);
-    todo_wine ok(status == STATUS_OBJECT_TYPE_MISMATCH,
+    todo_wine ok(status == STATUS_OBJECT_TYPE_MISMATCH || status == STATUS_OBJECT_PATH_NOT_FOUND,
         "NtCreateMutant should have failed with STATUS_OBJECT_TYPE_MISMATCH got(%08lx)\n", status);
     pRtlFreeUnicodeString(&str);
 
@@ -289,22 +289,22 @@ void test_directory(void)
 
     /* No name and/or no attributes */
     status = pNtCreateDirectoryObject(NULL, DIRECTORY_QUERY, &attr);
-    todo_wine ok(status == STATUS_ACCESS_VIOLATION,
+    ok(status == STATUS_ACCESS_VIOLATION,
         "NtCreateDirectoryObject should have failed with STATUS_ACCESS_VIOLATION got(%08lx)\n", status);
     status = pNtOpenDirectoryObject(NULL, DIRECTORY_QUERY, &attr);
-    todo_wine ok(status == STATUS_ACCESS_VIOLATION,
+    ok(status == STATUS_ACCESS_VIOLATION,
         "NtOpenDirectoryObject should have failed with STATUS_ACCESS_VIOLATION got(%08lx)\n", status);
 
     status = pNtCreateDirectoryObject(&h, DIRECTORY_QUERY, NULL);
     ok(status == STATUS_SUCCESS, "Failed to create Directory without attributes(%08lx)\n", status);
     pNtClose(h);
     status = pNtOpenDirectoryObject(&h, DIRECTORY_QUERY, NULL);
-    todo_wine ok(status == STATUS_INVALID_PARAMETER,
+    ok(status == STATUS_INVALID_PARAMETER,
         "NtOpenDirectoryObject should have failed with STATUS_INVALID_PARAMETER got(%08lx)\n", status);
 
     InitializeObjectAttributes(&attr, NULL, 0, 0, NULL);
     DIR_TEST_CREATE_SUCCESS(&dir)
-    todo_wine{ DIR_TEST_OPEN_FAILURE(&h, STATUS_OBJECT_PATH_SYNTAX_BAD) }
+    DIR_TEST_OPEN_FAILURE(&h, STATUS_OBJECT_PATH_SYNTAX_BAD)
 
     /* Bad name */
     InitializeObjectAttributes(&attr, &str, 0, 0, NULL);
@@ -312,15 +312,15 @@ void test_directory(void)
     pRtlCreateUnicodeStringFromAsciiz(&str, "");
     DIR_TEST_CREATE_SUCCESS(&h)
     pNtClose(h);
-    todo_wine{ DIR_TEST_OPEN_FAILURE(&h, STATUS_OBJECT_PATH_SYNTAX_BAD) }
+    DIR_TEST_OPEN_FAILURE(&h, STATUS_OBJECT_PATH_SYNTAX_BAD)
     pRtlFreeUnicodeString(&str);
     pNtClose(dir);
 
-    todo_wine{ DIR_TEST_CREATE_OPEN_FAILURE(&h, "BaseNamedObjects", STATUS_OBJECT_PATH_SYNTAX_BAD) }
-    todo_wine{ DIR_TEST_CREATE_OPEN_FAILURE(&h, "\\BaseNamedObjects\\", STATUS_OBJECT_NAME_INVALID) }
-    todo_wine{ DIR_TEST_CREATE_OPEN_FAILURE(&h, "\\\\BaseNamedObjects", STATUS_OBJECT_NAME_INVALID) }
-    todo_wine{ DIR_TEST_CREATE_OPEN_FAILURE(&h, "\\BaseNamedObjects\\\\om.c-test", STATUS_OBJECT_NAME_INVALID) }
-    todo_wine{ DIR_TEST_CREATE_OPEN_FAILURE(&h, "\\BaseNamedObjects\\om.c-test\\", STATUS_OBJECT_PATH_NOT_FOUND) }
+    DIR_TEST_CREATE_OPEN_FAILURE(&h, "BaseNamedObjects", STATUS_OBJECT_PATH_SYNTAX_BAD)
+    DIR_TEST_CREATE_OPEN_FAILURE(&h, "\\BaseNamedObjects\\", STATUS_OBJECT_NAME_INVALID)
+    DIR_TEST_CREATE_OPEN_FAILURE(&h, "\\\\BaseNamedObjects", STATUS_OBJECT_NAME_INVALID)
+    DIR_TEST_CREATE_OPEN_FAILURE(&h, "\\BaseNamedObjects\\\\om.c-test", STATUS_OBJECT_NAME_INVALID)
+    DIR_TEST_CREATE_OPEN_FAILURE(&h, "\\BaseNamedObjects\\om.c-test\\", STATUS_OBJECT_PATH_NOT_FOUND)
 
     pRtlCreateUnicodeStringFromAsciiz(&str, "\\BaseNamedObjects\\om.c-test");
     DIR_TEST_CREATE_SUCCESS(&h)
@@ -351,14 +351,14 @@ void test_directory(void)
     pRtlFreeUnicodeString(&str);
 
     InitializeObjectAttributes(&attr, NULL, 0, dir, NULL);
-    todo_wine{ DIR_TEST_OPEN_FAILURE(&h, STATUS_OBJECT_NAME_INVALID) }
+    DIR_TEST_OPEN_FAILURE(&h, STATUS_OBJECT_NAME_INVALID)
 
     InitializeObjectAttributes(&attr, &str, 0, dir, NULL);
     DIR_TEST_CREATE_OPEN_SUCCESS(&h, "")
-    todo_wine{ DIR_TEST_CREATE_OPEN_FAILURE(&h, "\\", STATUS_OBJECT_PATH_SYNTAX_BAD) }
-    todo_wine{ DIR_TEST_CREATE_OPEN_FAILURE(&h, "\\om.c-test", STATUS_OBJECT_PATH_SYNTAX_BAD) }
-    todo_wine{ DIR_TEST_CREATE_OPEN_FAILURE(&h, "\\om.c-test\\", STATUS_OBJECT_PATH_SYNTAX_BAD) }
-    todo_wine{ DIR_TEST_CREATE_OPEN_FAILURE(&h, "om.c-test\\", STATUS_OBJECT_PATH_NOT_FOUND) }
+    DIR_TEST_CREATE_OPEN_FAILURE(&h, "\\", STATUS_OBJECT_PATH_SYNTAX_BAD)
+    DIR_TEST_CREATE_OPEN_FAILURE(&h, "\\om.c-test", STATUS_OBJECT_PATH_SYNTAX_BAD)
+    DIR_TEST_CREATE_OPEN_FAILURE(&h, "\\om.c-test\\", STATUS_OBJECT_PATH_SYNTAX_BAD)
+    DIR_TEST_CREATE_OPEN_FAILURE(&h, "om.c-test\\", STATUS_OBJECT_PATH_NOT_FOUND)
 
     pRtlCreateUnicodeStringFromAsciiz(&str, "om.c-test");
     DIR_TEST_CREATE_SUCCESS(&dir1)
@@ -374,7 +374,7 @@ void test_directory(void)
     InitializeObjectAttributes(&attr, &str, 0, 0, NULL);
     DIR_TEST_OPEN_SUCCESS(&dir)
     InitializeObjectAttributes(&attr, &str, 0, dir, NULL);
-    todo_wine{ DIR_TEST_OPEN_FAILURE(&h, STATUS_OBJECT_PATH_SYNTAX_BAD) }
+    DIR_TEST_OPEN_FAILURE(&h, STATUS_OBJECT_PATH_SYNTAX_BAD)
     pRtlFreeUnicodeString(&str);
     pNtClose(dir);
 
@@ -396,15 +396,15 @@ void test_directory(void)
 
     InitializeObjectAttributes(&attr, &str, 0, 0, NULL);
     pRtlCreateUnicodeStringFromAsciiz(&str, "\\BaseNamedObjects\\Global\\om.c-test");
-    DIR_TEST_CREATE_SUCCESS(&dir)
+    todo_wine{ DIR_TEST_CREATE_SUCCESS(&dir) }
     pRtlFreeUnicodeString(&str);
     pRtlCreateUnicodeStringFromAsciiz(&str, "\\BaseNamedObjects\\Local\\om.c-test\\one more level");
-    DIR_TEST_CREATE_SUCCESS(&h)
+    todo_wine{ DIR_TEST_CREATE_SUCCESS(&h) }
     pRtlFreeUnicodeString(&str);
     pNtClose(h);
     InitializeObjectAttributes(&attr, &str, 0, dir, NULL);
     pRtlCreateUnicodeStringFromAsciiz(&str, "one more level");
-    DIR_TEST_CREATE_SUCCESS(&dir)
+    todo_wine{ DIR_TEST_CREATE_SUCCESS(&dir) }
     pRtlFreeUnicodeString(&str);
     pNtClose(h);
 
diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h
index 168e9316727def8f5b0ef78e4222227b23b427fc..213e3be55f14e5da61c4da6ae760b325c5c19ea4 100644
--- a/include/wine/server_protocol.h
+++ b/include/wine/server_protocol.h
@@ -3577,6 +3577,38 @@ struct set_mailslot_info_reply
 #define MAILSLOT_SET_READ_TIMEOUT  1
 
 
+
+struct create_directory_request
+{
+    struct request_header __header;
+    unsigned int   access;
+    unsigned int   attributes;
+    obj_handle_t   rootdir;
+    /* VARARG(directory_name,unicode_str); */
+};
+struct create_directory_reply
+{
+    struct reply_header __header;
+    obj_handle_t   handle;
+};
+
+
+
+struct open_directory_request
+{
+    struct request_header __header;
+    unsigned int   access;
+    unsigned int   attributes;
+    obj_handle_t   rootdir;
+    /* VARARG(directory_name,unicode_str); */
+};
+struct open_directory_reply
+{
+    struct reply_header __header;
+    obj_handle_t   handle;
+};
+
+
 enum request
 {
     REQ_new_process,
@@ -3784,6 +3816,8 @@ enum request
     REQ_create_mailslot,
     REQ_open_mailslot,
     REQ_set_mailslot_info,
+    REQ_create_directory,
+    REQ_open_directory,
     REQ_NB_REQUESTS
 };
 
@@ -3996,6 +4030,8 @@ union generic_request
     struct create_mailslot_request create_mailslot_request;
     struct open_mailslot_request open_mailslot_request;
     struct set_mailslot_info_request set_mailslot_info_request;
+    struct create_directory_request create_directory_request;
+    struct open_directory_request open_directory_request;
 };
 union generic_reply
 {
@@ -4206,8 +4242,10 @@ union generic_reply
     struct create_mailslot_reply create_mailslot_reply;
     struct open_mailslot_reply open_mailslot_reply;
     struct set_mailslot_info_reply set_mailslot_info_reply;
+    struct create_directory_reply create_directory_reply;
+    struct open_directory_reply open_directory_reply;
 };
 
-#define SERVER_PROTOCOL_VERSION 199
+#define SERVER_PROTOCOL_VERSION 200
 
 #endif /* __WINE_WINE_SERVER_PROTOCOL_H */
diff --git a/server/Makefile.in b/server/Makefile.in
index 47687c035f649fa885879d2ca0208d7bd3a28a4d..50a504965802fe3b38e3ce22d6864a9e4fbdf413 100644
--- a/server/Makefile.in
+++ b/server/Makefile.in
@@ -17,6 +17,7 @@ C_SRCS = \
 	context_sparc.c \
 	context_x86_64.c \
 	debugger.c \
+	directory.c \
 	event.c \
 	fd.c \
 	file.c \
diff --git a/server/directory.c b/server/directory.c
new file mode 100644
index 0000000000000000000000000000000000000000..716ad66ed5fa8b7ad434d2de3f6817d805798712
--- /dev/null
+++ b/server/directory.c
@@ -0,0 +1,354 @@
+/*
+ * Server-side directory object management
+ *
+ * Copyright (C) 2005 Vitaliy Margolen
+ *
+ * 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 <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/types.h>
+
+#include "ntstatus.h"
+#define WIN32_NO_STATUS
+#include "winternl.h"
+#include "ddk/wdm.h"
+
+#include "handle.h"
+#include "request.h"
+#include "process.h"
+#include "object.h"
+#include "unicode.h"
+
+#define HASH_SIZE 7  /* default hash size */
+
+struct directory
+{
+    struct object     obj;        /* object header */
+    struct namespace *entries;    /* directory's name space */
+};
+
+static void directory_dump( struct object *obj, int verbose );
+static struct object *directory_lookup_name( struct object *obj, struct unicode_str *name,
+                                             unsigned int attr );
+static void directory_destroy( struct object *obj );
+
+static const struct object_ops directory_ops =
+{
+    sizeof(struct directory),     /* size */
+    directory_dump,               /* dump */
+    no_add_queue,                 /* add_queue */
+    NULL,                         /* remove_queue */
+    NULL,                         /* signaled */
+    NULL,                         /* satisfied */
+    no_signal,                    /* signal */
+    no_get_fd,                    /* get_fd */
+    directory_lookup_name,        /* lookup_name */
+    no_close_handle,              /* close_handle */
+    directory_destroy             /* destroy */
+};
+
+static struct directory *root_directory;
+
+
+static void directory_dump( struct object *obj, int verbose )
+{
+    assert( obj->ops == &directory_ops );
+
+    fputs( "Directory ", stderr );
+    dump_object_name( obj );
+    fputc( '\n', stderr );
+}
+
+static struct object *directory_lookup_name( struct object *obj, struct unicode_str *name,
+                                             unsigned int attr )
+{
+    struct directory *dir = (struct directory *)obj;
+    struct object *found;
+    struct unicode_str tmp;
+    const WCHAR *p;
+
+    assert( obj->ops == &directory_ops );
+
+    if (!(p = memchrW( name->str, '\\', name->len / sizeof(WCHAR) )))
+        /* Last element in the path name */
+        tmp.len = name->len;
+    else
+        tmp.len = (p - name->str) * sizeof(WCHAR);
+
+    tmp.str = name->str;
+    if ((found = find_object( dir->entries, &tmp, attr )))
+    {
+        /* Skip trailing \\ */
+        if (p)
+        {
+            p++;
+            tmp.len += sizeof(WCHAR);
+        }
+        /* Move to the next element*/
+        name->str = p;
+        name->len -= tmp.len;
+        return found;
+    }
+
+    if (name->str)
+    {
+        if (tmp.len == 0) /* Double backslash */
+            set_error( STATUS_OBJECT_NAME_INVALID );
+        else if (p)  /* Path still has backslashes */
+            set_error( STATUS_OBJECT_PATH_NOT_FOUND );
+    }
+    return NULL;
+}
+
+static void directory_destroy( struct object *obj )
+{
+    struct directory *dir = (struct directory *)obj;
+    assert( obj->ops == &directory_ops );
+    free( dir->entries );
+}
+
+static struct directory *create_directory( struct directory *root, const struct unicode_str *name,
+                                           unsigned int attr, unsigned int hash_size )
+{
+    struct directory *dir;
+
+    if ((dir = create_named_object_dir( root, name, attr, &directory_ops )) &&
+        get_error() != STATUS_OBJECT_NAME_EXISTS)
+    {
+        if (!(dir->entries = create_namespace( hash_size )))
+        {
+            release_object( dir );
+            dir = NULL;
+        }
+    }
+    return dir;
+}
+
+struct directory *get_directory_obj( struct process *process, obj_handle_t handle, unsigned int access )
+{
+    return (struct directory *)get_handle_obj( process, handle, access, &directory_ops );
+}
+
+/******************************************************************************
+ * Find an object by its name in a given root object
+ *
+ * PARAMS
+ *  root      [I] directory to start search from or NULL to start from \\
+ *  name      [I] object name to search for
+ *  attr      [I] OBJECT_ATTRIBUTES.Attributes
+ *  name_left [O] [optional] leftover name if object is not found
+ *
+ * RETURNS
+ *  NULL:      If params are invalid
+ *  Found:     If object with exact name is found returns that object
+ *             (name_left->len == 0). Object's refcount is incremented
+ *  Not found: The last matched parent. (name_left->len > 0)
+ *             Parent's refcount is incremented.
+ */
+struct object *find_object_dir( struct directory *root, const struct unicode_str *name,
+                                unsigned int attr, struct unicode_str *name_left )
+{
+    struct object *obj, *parent;
+    struct unicode_str name_tmp;
+
+    if (name) name_tmp = *name;
+    else name_tmp.len = 0;
+
+    /* Arguments check:
+     * - Either rootdir or name have to be specified
+     * - If root is specified path shouldn't start with backslash */
+    if (root)
+    {
+        if (name_tmp.len && name_tmp.str[0] == '\\')
+        {
+            set_error( STATUS_OBJECT_PATH_SYNTAX_BAD );
+            return NULL;
+        }
+        parent = grab_object( root );
+    }
+    else
+    {
+        if (!name_tmp.len || name_tmp.str[0] != '\\')
+        {
+            set_error( STATUS_OBJECT_PATH_SYNTAX_BAD );
+            return NULL;
+        }
+        parent = grab_object( &root_directory->obj );
+        /* skip leading backslash */
+        name_tmp.str++;
+        name_tmp.len -= sizeof(WCHAR);
+    }
+
+    /* Special case for opening RootDirectory */
+    if (!name_tmp.len) goto done;
+
+    while ((obj = parent->ops->lookup_name( parent, &name_tmp, attr )))
+    {
+        /* move to the next element */
+        release_object ( parent );
+        parent = obj;
+    }
+    if (get_error())
+    {
+        release_object( parent );
+        return NULL;
+    }
+
+    done:
+    if (name_left) *name_left = name_tmp;
+    return parent;
+}
+
+/* create a named (if name is present) or unnamed object. */
+void *create_named_object_dir( struct directory *root, const struct unicode_str *name,
+                               unsigned int attributes, const struct object_ops *ops )
+{
+    struct object *obj, *new_obj = NULL;
+    struct unicode_str new_name;
+
+    if (!name || !name->len) return alloc_object( ops );
+
+    if (!(obj = find_object_dir( root, name, attributes, &new_name ))) return NULL;
+    if (!new_name.len)
+    {
+        if (attributes & OBJ_OPENIF && obj->ops == ops)
+            set_error( STATUS_OBJECT_NAME_EXISTS );
+        else
+        {
+            release_object( obj );
+            obj = NULL;
+            if (attributes & OBJ_OPENIF)
+                set_error( STATUS_OBJECT_TYPE_MISMATCH );
+            else
+                set_error( STATUS_OBJECT_NAME_COLLISION );
+        }
+        return obj;
+    }
+
+    /* ATM we can't insert objects into anything else but directories */
+    if (obj->ops != &directory_ops)
+        set_error( STATUS_OBJECT_TYPE_MISMATCH );
+    else
+    {
+        struct directory *dir = (struct directory *)obj;
+        if ((new_obj = create_object( dir->entries, ops, &new_name, &dir->obj )))
+            clear_error();
+    }
+
+    release_object( obj );
+    return new_obj;
+}
+
+/* open a new handle to an existing object */
+obj_handle_t open_object_dir( struct directory *root, const struct unicode_str *name,
+                              unsigned int attr, const struct object_ops *ops,
+                              unsigned int access )
+{
+    obj_handle_t handle = 0;
+    struct unicode_str name_left;
+    struct object *obj;
+
+    if ((obj = find_object_dir( root, name, attr, &name_left )))
+    {
+        if (name_left.len) /* not fully parsed */
+            set_error( STATUS_OBJECT_NAME_NOT_FOUND );
+        else if (ops && obj->ops != ops)
+            set_error( STATUS_OBJECT_TYPE_MISMATCH );
+        else
+            handle = alloc_handle( current->process, obj, access, attr & OBJ_INHERIT );
+
+        release_object( obj );
+    }
+    return handle;
+}
+
+
+/* Global initialization */
+
+static struct directory *dir_global, *dir_driver, *dir_device, *dir_basenamed;
+
+void init_directories(void)
+{
+    /* Directories */
+    static const WCHAR dir_globalW[] = {'?','?'};
+    static const WCHAR dir_driverW[] = {'D','r','i','v','e','r'};
+    static const WCHAR dir_deviceW[] = {'D','e','v','i','c','e'};
+    static const WCHAR dir_basenamedW[] = {'B','a','s','e','N','a','m','e','d','O','b','j','e','c','t','s'};
+    static const struct unicode_str dir_global_str = {dir_globalW, sizeof(dir_globalW)};
+    static const struct unicode_str dir_driver_str = {dir_driverW, sizeof(dir_driverW)};
+    static const struct unicode_str dir_device_str = {dir_deviceW, sizeof(dir_deviceW)};
+    static const struct unicode_str dir_basenamed_str = {dir_basenamedW, sizeof(dir_basenamedW)};
+
+    root_directory = create_directory( NULL, NULL, 0, HASH_SIZE );
+    dir_global     = create_directory( root_directory, &dir_global_str, 0, HASH_SIZE );
+    dir_driver     = create_directory( root_directory, &dir_driver_str, 0, HASH_SIZE );
+    dir_device     = create_directory( root_directory, &dir_device_str, 0, HASH_SIZE );
+    /* use a larger hash table for this one since it can contain a lot of objects */
+    dir_basenamed  = create_directory( root_directory, &dir_basenamed_str, 0, 37 );
+}
+
+void close_directories(void)
+{
+    release_object( dir_global );
+    release_object( dir_driver );
+    release_object( dir_device );
+    release_object( dir_basenamed );
+    release_object( root_directory );
+}
+
+
+/* create a directory object */
+DECL_HANDLER(create_directory)
+{
+    struct unicode_str name;
+    struct directory *dir, *root = NULL;
+
+    reply->handle = 0;
+    get_req_unicode_str( &name );
+    if (req->rootdir && !(root = get_directory_obj( current->process, req->rootdir, 0 )))
+        return;
+
+    if ((dir = create_directory( root, &name, req->attributes, HASH_SIZE )))
+    {
+        reply->handle = alloc_handle( current->process, dir, req->access,
+                                      req->attributes & OBJ_INHERIT );
+        release_object( dir );
+    }
+
+    if (root) release_object( root );
+}
+
+/* open a directory object */
+DECL_HANDLER(open_directory)
+{
+    struct unicode_str name;
+    struct directory *root = NULL;
+
+    get_req_unicode_str( &name );
+    if (req->rootdir && !(root = get_directory_obj( current->process, req->rootdir, 0 )))
+        return;
+
+    reply->handle = open_object_dir( root, &name, req->attributes, &directory_ops, req->access );
+
+    if (root) release_object( root );
+}
diff --git a/server/main.c b/server/main.c
index 6609a3aae0010bc305a99ae117a9df153684c9ee..7f07aacefa1f2a2151bb0d8576a72c69cdcb967d 100644
--- a/server/main.c
+++ b/server/main.c
@@ -135,6 +135,7 @@ int main( int argc, char *argv[] )
 
     if (debug_level) fprintf( stderr, "wineserver: starting (pid=%ld)\n", (long) getpid() );
     init_signals();
+    init_directories();
     init_registry();
     main_loop();
     return 0;
diff --git a/server/object.c b/server/object.c
index 2235c60f412b6a65555b97e26c284f428f0f70a4..e1330f23a6e39c90971cb26f11811bcf9ffbb786 100644
--- a/server/object.c
+++ b/server/object.c
@@ -40,9 +40,10 @@
 
 struct object_name
 {
-    struct list         entry;    /* entry in the hash list */
-    struct object      *obj;
-    size_t              len;
+    struct list         entry;           /* entry in the hash list */
+    struct object      *obj;             /* object owning this name */
+    struct object      *parent;          /* parent object */
+    size_t              len;             /* name length in bytes */
     WCHAR               name[1];
 };
 
@@ -108,6 +109,7 @@ static struct object_name *alloc_name( const struct unicode_str *name )
     if ((ptr = mem_alloc( sizeof(*ptr) + name->len - sizeof(ptr->name) )))
     {
         ptr->len = name->len;
+        ptr->parent = NULL;
         memcpy( ptr->name, name->str, name->len );
     }
     return ptr;
@@ -118,6 +120,7 @@ static void free_name( struct object *obj )
 {
     struct object_name *ptr = obj->name;
     list_remove( &ptr->entry );
+    if (ptr->parent) release_object( ptr->parent );
     free( ptr );
 }
 
@@ -159,11 +162,27 @@ void *alloc_object( const struct object_ops *ops )
     return NULL;
 }
 
+void *create_object( struct namespace *namespace, const struct object_ops *ops,
+                     const struct unicode_str *name, struct object *parent )
+{
+    struct object *obj;
+    struct object_name *name_ptr;
+
+    if (!(name_ptr = alloc_name( name ))) return NULL;
+    if ((obj = alloc_object( ops )))
+    {
+        set_object_name( namespace, obj, name_ptr );
+        if (parent) name_ptr->parent = grab_object( parent );
+    }
+    else
+        free( name_ptr );
+    return obj;
+}
+
 void *create_named_object( struct namespace *namespace, const struct object_ops *ops,
                            const struct unicode_str *name, unsigned int attributes )
 {
     struct object *obj;
-    struct object_name *name_ptr;
 
     if (!name || !name->len) return alloc_object( ops );
 
@@ -182,13 +201,7 @@ void *create_named_object( struct namespace *namespace, const struct object_ops
         }
         return obj;
     }
-    if (!(name_ptr = alloc_name( name ))) return NULL;
-    if ((obj = alloc_object( ops )))
-    {
-        set_object_name( namespace, obj, name_ptr );
-        clear_error();
-    }
-    else free( name_ptr );
+    if ((obj = create_object( namespace, ops, name, NULL ))) clear_error();
     return obj;
 }
 
diff --git a/server/object.h b/server/object.h
index f73d8a1f3edfdfcc9268e536fbc32250f9c93de8..0c2ee1a6a98160676553c5f1f79b73b1b96119d5 100644
--- a/server/object.h
+++ b/server/object.h
@@ -44,6 +44,7 @@ struct wait_queue_entry;
 struct async;
 struct async_queue;
 struct winstation;
+struct directory;
 
 
 struct unicode_str
@@ -102,6 +103,8 @@ extern void *memdup( const void *data, size_t len );
 extern void *alloc_object( const struct object_ops *ops );
 extern const WCHAR *get_object_name( struct object *obj, size_t *len );
 extern void dump_object_name( struct object *obj );
+extern void *create_object( struct namespace *namespace, const struct object_ops *ops,
+                            const struct unicode_str *name, struct object *parent );
 extern void *create_named_object( struct namespace *namespace, const struct object_ops *ops,
                                   const struct unicode_str *name, unsigned int attributes );
 extern struct namespace *create_namespace( unsigned int hash_size );
@@ -177,6 +180,19 @@ extern atom_t find_global_atom( struct winstation *winstation, const WCHAR *str,
 extern int grab_global_atom( struct winstation *winstation, atom_t atom );
 extern void release_global_atom( struct winstation *winstation, atom_t atom );
 
+/* directory functions */
+
+extern struct directory *get_directory_obj( struct process *process, obj_handle_t handle, unsigned int access );
+extern struct object *find_object_dir( struct directory *root, const struct unicode_str *name,
+                                       unsigned int attr, struct unicode_str *name_left );
+extern void *create_named_object_dir( struct directory *root, const struct unicode_str *name,
+                                      unsigned int attr, const struct object_ops *ops );
+extern obj_handle_t open_object_dir( struct directory *root, const struct unicode_str *name,
+                                     unsigned int attr, const struct object_ops *ops,
+                                     unsigned int access );
+extern void init_directories(void);
+extern void close_directories(void);
+
 /* global variables */
 
   /* command-line options */
diff --git a/server/protocol.def b/server/protocol.def
index 95ec43b54335067eba3c73e06920b327862c9165..56d0bc1b70048052ca1d1eb0f212e64425dfee70 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -2505,3 +2505,25 @@ enum message_type
     unsigned int   next_msgsize;
 @END
 #define MAILSLOT_SET_READ_TIMEOUT  1
+
+
+/* Create a directory object */
+@REQ(create_directory)
+    unsigned int   access;        /* access flags */
+    unsigned int   attributes;    /* object attributes */
+    obj_handle_t   rootdir;       /* root directory */
+    VARARG(directory_name,unicode_str); /* Directory name */
+@REPLY
+    obj_handle_t   handle;        /* handle to the directory */
+@END
+
+
+/* Open a directory object */
+@REQ(open_directory)
+    unsigned int   access;        /* access flags */
+    unsigned int   attributes;    /* object attributes */
+    obj_handle_t   rootdir;       /* root directory */
+    VARARG(directory_name,unicode_str); /* Directory name */
+@REPLY
+    obj_handle_t   handle;        /* handle to the directory */
+@END
diff --git a/server/request.c b/server/request.c
index f7fb0b39884f107f652ad21c60e36b26c88c6d6d..7c3b50a77817c621eebbd39c3df526551d437fa9 100644
--- a/server/request.c
+++ b/server/request.c
@@ -801,6 +801,7 @@ static void close_socket_timeout( void *arg )
     close_signals();
     close_global_handles();
     close_registry();
+    close_directories();
     dump_objects();  /* dump any remaining objects */
 #else
     exit(0);
diff --git a/server/request.h b/server/request.h
index eb829117dd13201d321f13d497e7c9e050643d31..f656372ac5ae76af0592f0b41aa11e240985df91 100644
--- a/server/request.h
+++ b/server/request.h
@@ -315,6 +315,8 @@ DECL_HANDLER(get_token_user);
 DECL_HANDLER(create_mailslot);
 DECL_HANDLER(open_mailslot);
 DECL_HANDLER(set_mailslot_info);
+DECL_HANDLER(create_directory);
+DECL_HANDLER(open_directory);
 
 #ifdef WANT_REQUEST_HANDLERS
 
@@ -526,6 +528,8 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] =
     (req_handler)req_create_mailslot,
     (req_handler)req_open_mailslot,
     (req_handler)req_set_mailslot_info,
+    (req_handler)req_create_directory,
+    (req_handler)req_open_directory,
 };
 #endif  /* WANT_REQUEST_HANDLERS */
 
diff --git a/server/trace.c b/server/trace.c
index 7a3cd5d9cfa8d1cdfa27d1934d761057bf30b36f..c98633b20fc6227a7e5491c4fa5295ee0d8aaa5d 100644
--- a/server/trace.c
+++ b/server/trace.c
@@ -3093,6 +3093,34 @@ static void dump_set_mailslot_info_reply( const struct set_mailslot_info_reply *
     fprintf( stderr, " next_msgsize=%08x", req->next_msgsize );
 }
 
+static void dump_create_directory_request( const struct create_directory_request *req )
+{
+    fprintf( stderr, " access=%08x,", req->access );
+    fprintf( stderr, " attributes=%08x,", req->attributes );
+    fprintf( stderr, " rootdir=%p,", req->rootdir );
+    fprintf( stderr, " directory_name=" );
+    dump_varargs_unicode_str( cur_size );
+}
+
+static void dump_create_directory_reply( const struct create_directory_reply *req )
+{
+    fprintf( stderr, " handle=%p", req->handle );
+}
+
+static void dump_open_directory_request( const struct open_directory_request *req )
+{
+    fprintf( stderr, " access=%08x,", req->access );
+    fprintf( stderr, " attributes=%08x,", req->attributes );
+    fprintf( stderr, " rootdir=%p,", req->rootdir );
+    fprintf( stderr, " directory_name=" );
+    dump_varargs_unicode_str( cur_size );
+}
+
+static void dump_open_directory_reply( const struct open_directory_reply *req )
+{
+    fprintf( stderr, " handle=%p", req->handle );
+}
+
 static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
     (dump_func)dump_new_process_request,
     (dump_func)dump_get_new_process_info_request,
@@ -3299,6 +3327,8 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
     (dump_func)dump_create_mailslot_request,
     (dump_func)dump_open_mailslot_request,
     (dump_func)dump_set_mailslot_info_request,
+    (dump_func)dump_create_directory_request,
+    (dump_func)dump_open_directory_request,
 };
 
 static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
@@ -3507,6 +3537,8 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
     (dump_func)dump_create_mailslot_reply,
     (dump_func)dump_open_mailslot_reply,
     (dump_func)dump_set_mailslot_info_reply,
+    (dump_func)dump_create_directory_reply,
+    (dump_func)dump_open_directory_reply,
 };
 
 static const char * const req_names[REQ_NB_REQUESTS] = {
@@ -3715,6 +3747,8 @@ static const char * const req_names[REQ_NB_REQUESTS] = {
     "create_mailslot",
     "open_mailslot",
     "set_mailslot_info",
+    "create_directory",
+    "open_directory",
 };
 
 static const struct
@@ -3752,6 +3786,7 @@ static const struct
     { "KEY_DELETED",                 STATUS_KEY_DELETED },
     { "MEDIA_WRITE_PROTECTED",       STATUS_MEDIA_WRITE_PROTECTED },
     { "MUTANT_NOT_OWNED",            STATUS_MUTANT_NOT_OWNED },
+    { "NAME_TOO_LONG",               STATUS_NAME_TOO_LONG },
     { "NOT_ALL_ASSIGNED",            STATUS_NOT_ALL_ASSIGNED },
     { "NOT_A_DIRECTORY",             STATUS_NOT_A_DIRECTORY },
     { "NOT_IMPLEMENTED",             STATUS_NOT_IMPLEMENTED },
@@ -3769,6 +3804,8 @@ static const struct
     { "OBJECT_NAME_INVALID",         STATUS_OBJECT_NAME_INVALID },
     { "OBJECT_NAME_NOT_FOUND",       STATUS_OBJECT_NAME_NOT_FOUND },
     { "OBJECT_PATH_INVALID",         STATUS_OBJECT_PATH_INVALID },
+    { "OBJECT_PATH_NOT_FOUND",       STATUS_OBJECT_PATH_NOT_FOUND },
+    { "OBJECT_PATH_SYNTAX_BAD",      STATUS_OBJECT_PATH_SYNTAX_BAD },
     { "OBJECT_TYPE_MISMATCH",        STATUS_OBJECT_TYPE_MISMATCH },
     { "PENDING",                     STATUS_PENDING },
     { "PIPE_BUSY",                   STATUS_PIPE_BUSY },