diff --git a/dlls/ntdll/om.c b/dlls/ntdll/om.c index 41d8bef41ea..bd314a397e8 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 c0a4921f163..747c4777743 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 168e9316727..213e3be55f1 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 47687c035f6..50a50496580 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 00000000000..716ad66ed5f --- /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 +#include +#include +#include +#include + +#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 6609a3aae00..7f07aacefa1 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 2235c60f412..e1330f23a6e 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 f73d8a1f3ed..0c2ee1a6a98 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 95ec43b5433..56d0bc1b700 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 f7fb0b39884..7c3b50a7781 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 eb829117dd1..f656372ac5a 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 7a3cd5d9cfa..c98633b20fc 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 },