From babfa79436e1d745886ead360bee402bfd46074a Mon Sep 17 00:00:00 2001 From: Vitaliy Margolen Date: Mon, 5 Dec 2005 13:09:35 +0100 Subject: [PATCH] Move named pipe objects into directory name space. Change tests accordingly. Add small test for WaitNamedPipe. --- dlls/kernel/sync.c | 3 +- dlls/kernel/tests/pipe.c | 4 +- dlls/ntdll/file.c | 21 +++-- dlls/ntdll/tests/om.c | 4 +- include/wine/server_protocol.h | 4 +- server/directory.c | 14 ++- server/named_pipe.c | 159 +++++++++++++++++++++++++++------ server/object.h | 2 + server/protocol.def | 2 + server/trace.c | 2 + 10 files changed, 169 insertions(+), 46 deletions(-) diff --git a/dlls/kernel/sync.c b/dlls/kernel/sync.c index 0c340984b4d..6158a990084 100644 --- a/dlls/kernel/sync.c +++ b/dlls/kernel/sync.c @@ -1340,7 +1340,8 @@ BOOL WINAPI WaitNamedPipeW (LPCWSTR name, DWORD nTimeOut) req->timeout = nTimeOut; req->overlapped = &ov; req->func = PIPE_CompletionWait; - wine_server_add_data( req, nt_name.Buffer + 4, nt_name.Length - 4*sizeof(WCHAR) ); + wine_server_add_data( req, nt_name.Buffer + sizeof(leadin)/sizeof(WCHAR), + nt_name.Length - sizeof(leadin) ); ret = !wine_server_call_err( req ); } SERVER_END_REQ; diff --git a/dlls/kernel/tests/pipe.c b/dlls/kernel/tests/pipe.c index aaad8d6781a..a4c15fe192e 100644 --- a/dlls/kernel/tests/pipe.c +++ b/dlls/kernel/tests/pipe.c @@ -91,8 +91,10 @@ static void test_CreateNamedPipe(int pipemode) /* lpSecurityAttrib */ NULL); ok(hnp != INVALID_HANDLE_VALUE, "CreateNamedPipe failed\n"); + todo_wine ok(WaitNamedPipeA(PIPENAME, 2000), "WaitNamedPipe failed (%08lx)\n", GetLastError()); + hFile = CreateFileA(PIPENAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0); - ok(hFile != INVALID_HANDLE_VALUE, "CreateFile failed\n"); + ok(hFile != INVALID_HANDLE_VALUE, "CreateFile failed (%08lx)\n", GetLastError()); /* don't try to do i/o if one side couldn't be opened, as it hangs */ if (hFile != INVALID_HANDLE_VALUE) { diff --git a/dlls/ntdll/file.c b/dlls/ntdll/file.c index c52e16b3b08..606b39f9c55 100644 --- a/dlls/ntdll/file.c +++ b/dlls/ntdll/file.c @@ -151,11 +151,6 @@ NTSTATUS WINAPI NtCreateFile( PHANDLE handle, ACCESS_MASK access, POBJECT_ATTRIB if (!attr || !attr->ObjectName) return STATUS_INVALID_PARAMETER; - if (attr->RootDirectory) - { - FIXME( "RootDirectory %p not supported\n", attr->RootDirectory ); - return STATUS_OBJECT_NAME_NOT_FOUND; - } if (alloc_size) FIXME( "alloc_size not supported\n" ); /* check for named pipe */ @@ -167,9 +162,10 @@ NTSTATUS WINAPI NtCreateFile( PHANDLE handle, ACCESS_MASK access, POBJECT_ATTRIB { req->access = access; req->attributes = (attr) ? attr->Attributes : 0; + req->rootdir = attr ? attr->RootDirectory : 0; req->flags = options; - wine_server_add_data( req, attr->ObjectName->Buffer + 4, - attr->ObjectName->Length - 4*sizeof(WCHAR) ); + wine_server_add_data( req, attr->ObjectName->Buffer, + attr->ObjectName->Length ); io->u.Status = wine_server_call( req ); *handle = reply->handle; } @@ -177,6 +173,12 @@ NTSTATUS WINAPI NtCreateFile( PHANDLE handle, ACCESS_MASK access, POBJECT_ATTRIB return io->u.Status; } + if (attr->RootDirectory) + { + FIXME( "RootDirectory %p not supported\n", attr->RootDirectory ); + return STATUS_OBJECT_NAME_NOT_FOUND; + } + /* check for mailslot */ if (attr->ObjectName->Length > sizeof(mailslotW) && @@ -1957,6 +1959,7 @@ NTSTATUS WINAPI NtCreateNamedPipeFile( PHANDLE handle, ULONG access, { req->access = access; req->attributes = (attr) ? attr->Attributes : 0; + req->rootdir = attr ? attr->RootDirectory : 0; req->options = options; req->flags = (pipe_type) ? NAMED_PIPE_MESSAGE_STREAM_WRITE : 0 | @@ -1966,8 +1969,8 @@ NTSTATUS WINAPI NtCreateNamedPipeFile( PHANDLE handle, ULONG access, req->outsize = outbound_quota; req->insize = inbound_quota; req->timeout = timeout->QuadPart / -10000; - wine_server_add_data( req, attr->ObjectName->Buffer + 4, - attr->ObjectName->Length - 4 * sizeof(WCHAR) ); + wine_server_add_data( req, attr->ObjectName->Buffer, + attr->ObjectName->Length ); status = wine_server_call( req ); if (!status) *handle = reply->handle; } diff --git a/dlls/ntdll/tests/om.c b/dlls/ntdll/tests/om.c index 492033d31c0..96a68a51d1d 100644 --- a/dlls/ntdll/tests/om.c +++ b/dlls/ntdll/tests/om.c @@ -126,7 +126,7 @@ void test_namespace_pipe(void) InitializeObjectAttributes(&attr, &str, 0, 0, NULL); status = pNtCreateNamedPipeFile(&pipe, GENERIC_READ|GENERIC_WRITE, &attr, &iosb, FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_CREATE, FILE_PIPE_FULL_DUPLEX, FALSE, FALSE, FALSE, 1, 256, 256, &timeout); - todo_wine ok(status == STATUS_INSTANCE_NOT_AVAILABLE, + ok(status == STATUS_INSTANCE_NOT_AVAILABLE, "NtCreateNamedPipeFile should have failed with STATUS_INSTANCE_NOT_AVAILABLE got(%08lx)\n", status); attr.Attributes = OBJ_CASE_INSENSITIVE; @@ -137,7 +137,7 @@ void test_namespace_pipe(void) pRtlInitUnicodeString(&str, buffer3); InitializeObjectAttributes(&attr, &str, 0, 0, NULL); status = pNtOpenFile(&h, GENERIC_READ, &attr, &iosb, FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_OPEN); - todo_wine ok(status == STATUS_OBJECT_PATH_NOT_FOUND || status == STATUS_PIPE_NOT_AVAILABLE, + ok(status == STATUS_OBJECT_PATH_NOT_FOUND || status == STATUS_PIPE_NOT_AVAILABLE, "pNtOpenFile should have failed with STATUS_OBJECT_PATH_NOT_FOUND got(%08lx)\n", status); pRtlInitUnicodeString(&str, buffer4); diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index 4ab0136c824..429fcdf1ab4 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -2378,6 +2378,7 @@ struct create_named_pipe_request struct request_header __header; unsigned int access; unsigned int attributes; + obj_handle_t rootdir; unsigned int options; unsigned int flags; unsigned int maxinstances; @@ -2404,6 +2405,7 @@ struct open_named_pipe_request struct request_header __header; unsigned int access; unsigned int attributes; + obj_handle_t rootdir; unsigned int flags; /* VARARG(name,unicode_str); */ }; @@ -4312,6 +4314,6 @@ union generic_reply struct query_symlink_reply query_symlink_reply; }; -#define SERVER_PROTOCOL_VERSION 205 +#define SERVER_PROTOCOL_VERSION 206 #endif /* __WINE_WINE_SERVER_PROTOCOL_H */ diff --git a/server/directory.c b/server/directory.c index c5de9863ea1..e8088a42454 100644 --- a/server/directory.c +++ b/server/directory.c @@ -283,8 +283,9 @@ void *open_object_dir( struct directory *root, const struct unicode_str *name, /* Global initialization */ -static struct directory *dir_driver, *dir_device; +static struct directory *dir_driver; static struct symlink *link_dosdev, *link_global1, *link_global2, *link_local; +static struct named_pipe_device *dev_named_pipe; void init_directories(void) { @@ -306,7 +307,7 @@ void init_directories(void) static const struct unicode_str link_global_str = {link_globalW, sizeof(link_globalW)}; static const struct unicode_str link_local_str = {link_localW, sizeof(link_localW)}; - struct directory *dir_global, *dir_basenamed; + struct directory *dir_global, *dir_basenamed, *dir_device; root_directory = create_directory( NULL, NULL, 0, HASH_SIZE ); dir_driver = create_directory( root_directory, &dir_driver_str, 0, HASH_SIZE ); @@ -322,20 +323,25 @@ void init_directories(void) link_global2 = create_symlink( dir_basenamed, &link_global_str, 0, &dir_basenamed_str ); link_local = create_symlink( dir_basenamed, &link_local_str, 0, &dir_basenamed_str ); - /* the symlinks hold references so we can release these */ + /* devices */ + dev_named_pipe = create_named_pipe_device(); + + /* the symlinks or devices hold references so we can release these */ + release_object( dir_device ); release_object( dir_global ); release_object( dir_basenamed ); } void close_directories(void) { + release_object( dev_named_pipe ); + release_object( link_dosdev ); release_object( link_global1 ); release_object( link_global2 ); release_object( link_local ); release_object( dir_driver ); - release_object( dir_device ); release_object( root_directory ); } diff --git a/server/named_pipe.c b/server/named_pipe.c index 0aa57336c3f..ac6aaabf9d2 100644 --- a/server/named_pipe.c +++ b/server/named_pipe.c @@ -99,6 +99,12 @@ struct named_pipe struct list waiters; /* list of clients waiting to connect */ }; +struct named_pipe_device +{ + struct object obj; /* object header */ + struct namespace *pipes; /* named pipe namespace */ +}; + static void named_pipe_dump( struct object *obj, int verbose ); static void named_pipe_destroy( struct object *obj ); @@ -181,6 +187,26 @@ static const struct fd_ops pipe_client_fd_ops = default_fd_cancel_async /* cancel_async */ }; +static void named_pipe_device_dump( struct object *obj, int verbose ); +static struct object *named_pipe_device_lookup_name( struct object *obj, + struct unicode_str *name, unsigned int attr ); +static void named_pipe_device_destroy( struct object *obj ); + +static const struct object_ops named_pipe_device_ops = +{ + sizeof(struct named_pipe_device), /* size */ + named_pipe_device_dump, /* dump */ + no_add_queue, /* add_queue */ + NULL, /* remove_queue */ + NULL, /* signaled */ + no_satisfied, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ + named_pipe_device_lookup_name, /* lookup_name */ + no_close_handle, /* close_handle */ + named_pipe_device_destroy /* destroy */ +}; + static void named_pipe_dump( struct object *obj, int verbose ) { struct named_pipe *pipe = (struct named_pipe *) obj; @@ -338,6 +364,58 @@ static void pipe_client_destroy( struct object *obj) assert( !client->fd ); } +static void named_pipe_device_dump( struct object *obj, int verbose ) +{ + assert( obj->ops == &named_pipe_device_ops ); + fprintf( stderr, "Named pipe device\n" ); +} + +static struct object *named_pipe_device_lookup_name( struct object *obj, struct unicode_str *name, + unsigned int attr ) +{ + struct named_pipe_device *device = (struct named_pipe_device*)obj; + struct object *found; + + assert( obj->ops == &named_pipe_device_ops ); + assert( device->pipes ); + + if (!name->len) return NULL; + + if ((found = find_object( device->pipes, name, attr | OBJ_CASE_INSENSITIVE ))) + name->len = 0; + + return found; +} + +static void named_pipe_device_destroy( struct object *obj ) +{ + struct named_pipe_device *device = (struct named_pipe_device*)obj; + assert( obj->ops == &named_pipe_device_ops ); + free( device->pipes ); +} + +/* this will be deleted as soon an we fix wait_named_pipe */ +static struct named_pipe_device *named_pipe_device; + +struct named_pipe_device *create_named_pipe_device( void ) +{ + static const WCHAR pipeW[] = {'\\','?','?','\\','P','I','P','E'}; + static struct unicode_str pipe = {pipeW, sizeof(pipeW)}; + struct named_pipe_device *dev; + + if ((dev = create_named_object_dir( NULL, &pipe, 0, &named_pipe_device_ops )) && + get_error() != STATUS_OBJECT_NAME_EXISTS) + { + if (!(dev->pipes = create_namespace( 7 ))) + { + release_object( dev ); + dev = NULL; + } + } + named_pipe_device = dev; + return dev; +} + static int pipe_data_remaining( struct pipe_server *server ) { struct pollfd pfd; @@ -445,37 +523,43 @@ static int pipe_client_get_info( struct fd *fd ) return flags; } -static struct named_pipe *create_named_pipe( const struct unicode_str *name, unsigned int attr ) -{ - struct named_pipe *pipe; - - pipe = create_named_object( sync_namespace, &named_pipe_ops, name, attr | OBJ_OPENIF ); - if (pipe) - { - if (get_error() != STATUS_OBJECT_NAME_EXISTS) - { - /* initialize it if it didn't already exist */ - pipe->instances = 0; - list_init( &pipe->servers ); - list_init( &pipe->waiters ); - } - } - return pipe; -} - -static struct named_pipe *open_named_pipe( const struct unicode_str *name, unsigned int attr ) +static struct named_pipe *create_named_pipe( struct directory *root, const struct unicode_str *name, + unsigned int attr ) { struct object *obj; + struct named_pipe *pipe = NULL; + struct unicode_str new_name; - if ((obj = find_object( sync_namespace, name, attr ))) + if (!name || !name->len) return alloc_object( &named_pipe_ops ); + + if (!(obj = find_object_dir( root, name, attr, &new_name ))) return NULL; + if (!new_name.len) { - if (obj->ops == &named_pipe_ops) return (struct named_pipe *)obj; - release_object( obj ); - set_error( STATUS_OBJECT_TYPE_MISMATCH ); + if (attr & OBJ_OPENIF && obj->ops == &named_pipe_ops) + set_error( STATUS_OBJECT_NAME_EXISTS ); + else + { + release_object( obj ); + obj = NULL; + if (attr & OBJ_OPENIF) + set_error( STATUS_OBJECT_TYPE_MISMATCH ); + else + set_error( STATUS_OBJECT_NAME_COLLISION ); + } + return (struct named_pipe *)obj; } - else set_error( STATUS_OBJECT_NAME_NOT_FOUND ); - return NULL; + if (obj->ops != &named_pipe_device_ops) + set_error( STATUS_OBJECT_TYPE_MISMATCH ); + else + { + struct named_pipe_device *dev = (struct named_pipe_device *)obj; + if ((pipe = create_object( dev->pipes, &named_pipe_ops, &new_name, NULL ))) + clear_error(); + } + + release_object( obj ); + return pipe; } static struct pipe_server *get_pipe_server_obj( struct process *process, @@ -552,13 +636,24 @@ DECL_HANDLER(create_named_pipe) struct named_pipe *pipe; struct pipe_server *server; struct unicode_str name; + struct directory *root = NULL; reply->handle = 0; get_req_unicode_str( &name ); - if (!(pipe = create_named_pipe( &name, req->attributes ))) return; + if (req->rootdir && !(root = get_directory_obj( current->process, req->rootdir, 0 ))) + return; + + pipe = create_named_pipe( root, &name, req->attributes | OBJ_OPENIF ); + + if (root) release_object( root ); + if (!pipe) return; if (get_error() != STATUS_OBJECT_NAME_EXISTS) { + /* initialize it if it didn't already exist */ + pipe->instances = 0; + list_init( &pipe->servers ); + list_init( &pipe->waiters ); pipe->insize = req->insize; pipe->outsize = req->outsize; pipe->maxinstances = req->maxinstances; @@ -601,11 +696,18 @@ DECL_HANDLER(open_named_pipe) struct pipe_server *server; struct pipe_client *client; struct unicode_str name; + struct directory *root = NULL; struct named_pipe *pipe; int fds[2]; get_req_unicode_str( &name ); - if (!(pipe = open_named_pipe( &name, req->attributes ))) return; + if (req->rootdir && !(root = get_directory_obj( current->process, req->rootdir, 0 ))) + return; + + pipe = open_object_dir( root, &name, req->attributes, &named_pipe_ops ); + + if (root) release_object( root ); + if (!pipe) return; server = find_server2( pipe, ps_idle_server, ps_wait_open ); release_object( pipe ); @@ -701,7 +803,8 @@ DECL_HANDLER(wait_named_pipe) struct unicode_str name; get_req_unicode_str( &name ); - if (!(pipe = open_named_pipe( &name, OBJ_CASE_INSENSITIVE ))) + pipe = (struct named_pipe *)find_object( named_pipe_device->pipes, &name, OBJ_CASE_INSENSITIVE ); + if (!pipe) { set_error( STATUS_PIPE_NOT_AVAILABLE ); return; diff --git a/server/object.h b/server/object.h index 2beb148f257..66cd357f57c 100644 --- a/server/object.h +++ b/server/object.h @@ -197,6 +197,8 @@ extern void close_directories(void); extern struct symlink *create_symlink( struct directory *root, const struct unicode_str *name, unsigned int attr, const struct unicode_str *target ); +/* devices */ +extern struct named_pipe_device *create_named_pipe_device( void ); /* global variables */ diff --git a/server/protocol.def b/server/protocol.def index 297313c92fe..905e0ff82ec 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -1692,6 +1692,7 @@ enum message_type @REQ(create_named_pipe) unsigned int access; unsigned int attributes; /* object attributes */ + obj_handle_t rootdir; /* root directory */ unsigned int options; unsigned int flags; unsigned int maxinstances; @@ -1713,6 +1714,7 @@ enum message_type @REQ(open_named_pipe) unsigned int access; unsigned int attributes; /* object attributes */ + obj_handle_t rootdir; /* root directory */ unsigned int flags; /* file flags */ VARARG(name,unicode_str); /* pipe name */ @REPLY diff --git a/server/trace.c b/server/trace.c index 5d5159ab133..3618f6ed7dc 100644 --- a/server/trace.c +++ b/server/trace.c @@ -2154,6 +2154,7 @@ static void dump_create_named_pipe_request( const struct create_named_pipe_reque { fprintf( stderr, " access=%08x,", req->access ); fprintf( stderr, " attributes=%08x,", req->attributes ); + fprintf( stderr, " rootdir=%p,", req->rootdir ); fprintf( stderr, " options=%08x,", req->options ); fprintf( stderr, " flags=%08x,", req->flags ); fprintf( stderr, " maxinstances=%08x,", req->maxinstances ); @@ -2173,6 +2174,7 @@ static void dump_open_named_pipe_request( const struct open_named_pipe_request * { fprintf( stderr, " access=%08x,", req->access ); fprintf( stderr, " attributes=%08x,", req->attributes ); + fprintf( stderr, " rootdir=%p,", req->rootdir ); fprintf( stderr, " flags=%08x,", req->flags ); fprintf( stderr, " name=" ); dump_varargs_unicode_str( cur_size );