Implement directory object in wineserver.
Vitaliy Margolen
wine-patch at kievinfo.com
Mon Nov 28 21:42:58 CST 2005
ChangeLog:
Implement directory object in wineserver.
Implement Nt[Create|Open]DirectoryObject.
Change tests accordingly.
dlls/ntdll/om.c | 79 +++++++++---
dlls/ntdll/tests/om.c | 44 +++----
server/Makefile.in | 1
server/directory.c | 327 +++++++++++++++++++++++++++++++++++++++++++++++++
server/main.c | 1
server/object.c | 95 ++++++++++++--
server/object.h | 26 ++++
server/protocol.def | 21 +++
server/request.c | 1
server/unicode.h | 13 ++
10 files changed, 556 insertions(+), 52 deletions(-)
create mode 100644 server/directory.c
-------------- next part --------------
58ffb6de5adfefaa2097fa7137ee5f241719a772
diff --git a/dlls/ntdll/om.c b/dlls/ntdll/om.c
index 41d8bef..cbeb305 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 differentce 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 c0a4921..747c477 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/server/Makefile.in b/server/Makefile.in
index 47687c0..50a5049 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 0000000..f9c43df
--- /dev/null
+++ b/server/directory.c
@@ -0,0 +1,327 @@
+/*
+ * 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 <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 "unicode.h"
+#include "object.h"
+
+#define HASH_SIZE 37
+
+/* Global name space */
+struct directory *root_directory;
+
+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 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 object *found;
+ struct unicode_str tmp;
+ 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( ((struct directory *)obj)->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 )
+{
+ assert( obj->ops == &directory_ops );
+ free( ((struct directory *)obj)->entries );
+}
+
+/******************************************************************************/
+
+/* Create root directory - it's a special case when no namespace exists yet.*/
+struct directory *create_root( void )
+{
+ static const WCHAR rootW[]={'\\'};
+ static const struct unicode_str root = {rootW, sizeof(rootW)};
+ struct directory *dir;
+
+ if ((dir = create_object( NULL, &directory_ops, &root )))
+ dir->entries = create_namespace( HASH_SIZE );
+ return dir;
+}
+
+struct directory *create_directory( struct directory *root, const struct unicode_str *name,
+ unsigned int attr )
+{
+ struct directory *dir;
+
+ if ((dir = create_named_object_dir( root, name, attr, &directory_ops )) &&
+ get_error() != STATUS_OBJECT_NAME_EXISTS)
+ {
+ dir->entries = create_namespace( HASH_SIZE );
+ }
+ return dir;
+}
+
+static void insert_into_dir( struct directory* dir, struct object *obj )
+{
+ set_object_parent( obj, grab_object( 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 it's 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( const 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 = {NULL, 0};
+
+ if (name) name_tmp = *name;
+
+ /* Arguments check:
+ * - Either rootdir or name have to be specified
+ * - If root is specified path shouldn't start with backslash */
+ if (!(root || (name_tmp.str && name_tmp.len)) ||
+ (name_tmp.len && ((*name_tmp.str == '\\' && root) ||
+ (*name_tmp.str != '\\' && !root))))
+ {
+ set_error( STATUS_OBJECT_PATH_SYNTAX_BAD );
+ return NULL;
+ }
+
+ parent = grab_object( root ? (struct object *)root : &root_directory->obj );
+ if (!parent) return NULL;
+
+ /* Skip leading backslash */
+ if (name_tmp.len && *name_tmp.str == '\\')
+ {
+ 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) dup_unicode_str(&name_tmp, name_left);
+ return parent;
+}
+
+/* oreate 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 if ((new_obj = create_object( ((struct directory *)obj)->entries, ops, &new_name )))
+ {
+ insert_into_dir( (struct directory *)obj, new_obj );
+ clear_error();
+ }
+
+ release_object( obj );
+ free_unicode_str( &new_name );
+ return new_obj;
+}
+
+/* open a new handle to an existing object */
+obj_handle_t open_object_dir( const 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 );
+ free_unicode_str( &name_left );
+ }
+ return handle;
+}
+
+/******************************************************************************/
+
+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 )))
+ {
+ reply->handle = alloc_handle( current->process, dir, req->access,
+ req->attributes & OBJ_INHERIT );
+ release_object( dir );
+ }
+
+ if (root) release_object( root );
+}
+
+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 6609a3a..063f1fb 100644
--- a/server/main.c
+++ b/server/main.c
@@ -131,6 +131,7 @@ int main( int argc, char *argv[] )
sock_init();
open_master_socket();
sync_namespace = create_namespace( 37 );
+ init_namespace();
setvbuf( stderr, NULL, _IOLBF, 0 );
if (debug_level) fprintf( stderr, "wineserver: starting (pid=%ld)\n", (long) getpid() );
diff --git a/server/object.c b/server/object.c
index 2235c60..4fb97fa 100644
--- a/server/object.c
+++ b/server/object.c
@@ -32,6 +32,7 @@
#include "ntstatus.h"
#define WIN32_NO_STATUS
#include "winternl.h"
+#include "ddk/wdm.h"
#include "file.h"
#include "thread.h"
@@ -40,9 +41,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; /* pointer to an object */
+ struct object *parent; /* parent object */
+ size_t len; /* name lengh in bytes */
WCHAR name[1];
};
@@ -109,6 +111,7 @@ static struct object_name *alloc_name( c
{
ptr->len = name->len;
memcpy( ptr->name, name->str, name->len );
+ ptr->parent = NULL;
}
return ptr;
}
@@ -121,15 +124,30 @@ static void free_name( struct object *ob
free( ptr );
}
+/* set object's parent */
+void set_object_parent( struct object *obj, struct object *parent )
+{
+ if (obj->name) obj->name->parent = parent;
+}
+
/* set the name of an existing object */
static void set_object_name( struct namespace *namespace,
struct object *obj, struct object_name *ptr )
{
- int hash = get_name_hash( namespace, ptr->name, ptr->len );
+ int hash;
- list_add_head( &namespace->names[hash], &ptr->entry );
ptr->obj = obj;
obj->name = ptr;
+
+ /* Special case for root directory */
+ if (!namespace)
+ {
+ list_init( &ptr->entry );
+ return;
+ }
+
+ hash = get_name_hash( namespace, ptr->name, ptr->len );
+ list_add_head( &namespace->names[hash], &ptr->entry );
}
/* get the name of an existing object */
@@ -159,11 +177,24 @@ void *alloc_object( const struct object_
return NULL;
}
+void *create_object( struct namespace *namespace, const struct object_ops *ops,
+ const struct unicode_str *name )
+{
+ 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 );
+ 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 +213,7 @@ void *create_named_object( struct namesp
}
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 ))) clear_error();
return obj;
}
@@ -223,7 +248,12 @@ void release_object( void *ptr )
/* if the refcount is 0, nobody can be in the wait queue */
assert( list_empty( &obj->wait_queue ));
obj->ops->destroy( obj );
- if (obj->name) free_name( obj );
+ if (obj->name)
+ {
+ if (obj->name->parent)
+ release_object( obj->name->parent );
+ free_name( obj );
+ }
#ifdef DEBUG_OBJECTS
list_remove( &obj->obj_list );
memset( obj, 0xaa, obj->ops->size );
@@ -313,3 +343,40 @@ int no_close_handle( struct object *obj,
void no_destroy( struct object *obj )
{
}
+
+/* Name space initialization */
+
+struct directory *dir1_perm, *dir2_perm, *dir3_perm, *dir4_perm;
+
+static void init_namespace_dirs(void)
+{
+ /* Directories */
+ static const WCHAR dir1W[]={'\\','?','?'};
+ static const WCHAR dir2W[]={'\\','B','a','s','e','N','a','m','e','d','O','b','j','e','c','t','s'};
+ static const WCHAR dir3W[]={'\\','D','r','i','v','e','r'};
+ static const WCHAR dir4W[]={'\\','D','e','v','i','c','e'};
+ static const struct unicode_str dir1={dir1W, sizeof(dir1W)};
+ static const struct unicode_str dir2={dir2W, sizeof(dir2W)};
+ static const struct unicode_str dir3={dir3W, sizeof(dir3W)};
+ static const struct unicode_str dir4={dir4W, sizeof(dir4W)};
+
+ root_directory = create_root();
+ dir1_perm = create_directory( NULL, &dir1, DIRECTORY_ALL_ACCESS );
+ dir2_perm = create_directory( NULL, &dir2, DIRECTORY_ALL_ACCESS );
+ dir3_perm = create_directory( NULL, &dir3, DIRECTORY_ALL_ACCESS );
+ dir4_perm = create_directory( NULL, &dir4, DIRECTORY_ALL_ACCESS );
+}
+
+void init_namespace( void )
+{
+ init_namespace_dirs();
+}
+
+void close_namespace( void )
+{
+ release_object( root_directory );
+ release_object( dir1_perm );
+ release_object( dir2_perm );
+ release_object( dir3_perm );
+ release_object( dir4_perm );
+}
diff --git a/server/object.h b/server/object.h
index f73d8a1..a62e751 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,9 @@ extern void *memdup( const void *data, s
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 set_object_parent( struct object *obj, struct object *parent );
+extern void *create_object( struct namespace *namespace, const struct object_ops *ops,
+ const struct unicode_str *name );
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 +181,27 @@ extern atom_t find_global_atom( struct w
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 *create_root( void );
+extern struct directory *create_directory( struct directory *root, const struct unicode_str *name,
+ unsigned int attr );
+extern struct directory *get_directory_obj( struct process *process, obj_handle_t handle, unsigned int access );
+
+
+/* object management functions */
+
+extern void init_namespace( void );
+extern void close_namespace( void );
+
+extern struct object *find_object_dir( const 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( const struct directory *root, const struct unicode_str *name,
+ unsigned int attr, const struct object_ops *ops,
+ unsigned int access );
+
/* global variables */
/* command-line options */
@@ -190,5 +215,6 @@ extern time_t server_start_time;
/* name space for synchronization objects */
extern struct namespace *sync_namespace;
+extern struct directory *root_directory;
#endif /* __WINE_SERVER_OBJECT_H */
diff --git a/server/protocol.def b/server/protocol.def
index 95ec43b..be16246 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -2505,3 +2505,24 @@ enum message_type
unsigned int next_msgsize;
@END
#define MAILSLOT_SET_READ_TIMEOUT 1
+
+
+/* Create directory object */
+ at 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 */
+ at REPLY
+ obj_handle_t handle; /* handle to the directory */
+ at END
+
+/* Open directory object */
+ at 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 */
+ at REPLY
+ obj_handle_t handle; /* handle to the directory */
+ at END
diff --git a/server/request.c b/server/request.c
index f7fb0b3..d85e28a 100644
--- a/server/request.c
+++ b/server/request.c
@@ -801,6 +801,7 @@ static void close_socket_timeout( void *
close_signals();
close_global_handles();
close_registry();
+ close_namespace();
dump_objects(); /* dump any remaining objects */
#else
exit(0);
diff --git a/server/unicode.h b/server/unicode.h
index f745705..5b39c66 100644
--- a/server/unicode.h
+++ b/server/unicode.h
@@ -33,6 +33,19 @@ static inline WCHAR *strdupW( const WCHA
return memdup( str, len );
}
+static inline void free_unicode_str( struct unicode_str *str )
+{
+ if (str->str) free( (WCHAR*)str->str );
+ str->str = NULL;
+ str->len = 0;
+}
+
+static inline void dup_unicode_str( const struct unicode_str *src, struct unicode_str *dst )
+{
+ dst->str = memdup( src->str, src->len );
+ dst->len = src->len;
+}
+
extern int dump_strW( const WCHAR *str, size_t len, FILE *f, const char escape[2] );
#endif /* __WINE_SERVER_UNICODE_H */
More information about the wine-patches
mailing list