From cf21d4d7ca7184dfb42583a39a830f96037b1e6b Mon Sep 17 00:00:00 2001
From: Vitaliy Margolen <wine-patch@kievinfo.com>
Date: Mon, 5 Dec 2005 13:30:26 +0100
Subject: [PATCH] Move mailslot devices into directory name space.

---
 dlls/ntdll/file.c              |  22 ++---
 include/wine/server_protocol.h |   4 +-
 server/directory.c             |   3 +
 server/mailslot.c              | 148 +++++++++++++++++++++++++--------
 server/object.h                |   1 +
 server/protocol.def            |   2 +
 server/trace.c                 |   2 +
 7 files changed, 136 insertions(+), 46 deletions(-)

diff --git a/dlls/ntdll/file.c b/dlls/ntdll/file.c
index 606b39f9c55..660ba1bd1c3 100644
--- a/dlls/ntdll/file.c
+++ b/dlls/ntdll/file.c
@@ -173,12 +173,6 @@ 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) &&
@@ -188,9 +182,10 @@ NTSTATUS WINAPI NtCreateFile( PHANDLE handle, ACCESS_MASK access, POBJECT_ATTRIB
         {
             req->access = access & GENERIC_WRITE;
             req->attributes = (attr) ? attr->Attributes : 0;
+            req->rootdir = attr ? attr->RootDirectory : 0;
             req->sharing = sharing;
-            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;
         }
@@ -198,6 +193,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;
+    }
+
     io->u.Status = wine_nt_to_unix_file_name( attr->ObjectName, &unix_name, disposition,
                                               !(attr->Attributes & OBJ_CASE_INSENSITIVE) );
 
@@ -2065,10 +2066,11 @@ NTSTATUS WINAPI NtCreateMailslotFile(PHANDLE pHandle, ULONG DesiredAccess,
     {
         req->access = DesiredAccess;
         req->attributes = (attr) ? attr->Attributes : 0;
+        req->rootdir = attr ? attr->RootDirectory : 0;
         req->max_msgsize = MaxMessageSize;
         req->read_timeout = (TimeOut->QuadPart <= 0) ? TimeOut->QuadPart / -10000 : -1;
-        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 );
         ret = wine_server_call( req );
         if( ret == STATUS_SUCCESS )
             *pHandle = reply->handle;
diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h
index 429fcdf1ab4..b81cc6cc6df 100644
--- a/include/wine/server_protocol.h
+++ b/include/wine/server_protocol.h
@@ -3543,6 +3543,7 @@ struct create_mailslot_request
     struct request_header __header;
     unsigned int   access;
     unsigned int   attributes;
+    obj_handle_t   rootdir;
     unsigned int   max_msgsize;
     int            read_timeout;
     /* VARARG(name,unicode_str); */
@@ -3560,6 +3561,7 @@ struct open_mailslot_request
     struct request_header __header;
     unsigned int   access;
     unsigned int   attributes;
+    obj_handle_t   rootdir;
     unsigned int   sharing;
     /* VARARG(name,unicode_str); */
 };
@@ -4314,6 +4316,6 @@ union generic_reply
     struct query_symlink_reply query_symlink_reply;
 };
 
-#define SERVER_PROTOCOL_VERSION 206
+#define SERVER_PROTOCOL_VERSION 207
 
 #endif /* __WINE_WINE_SERVER_PROTOCOL_H */
diff --git a/server/directory.c b/server/directory.c
index e8088a42454..14ed4ccf859 100644
--- a/server/directory.c
+++ b/server/directory.c
@@ -286,6 +286,7 @@ void *open_object_dir( struct directory *root, const struct unicode_str *name,
 static struct directory *dir_driver;
 static struct symlink *link_dosdev, *link_global1, *link_global2, *link_local;
 static struct named_pipe_device *dev_named_pipe;
+static struct mailslot_device *dev_mailslot;
 
 void init_directories(void)
 {
@@ -325,6 +326,7 @@ void init_directories(void)
 
     /* devices */
     dev_named_pipe = create_named_pipe_device();
+    dev_mailslot   = create_mailslot_device();
 
     /* the symlinks or devices hold references so we can release these */
     release_object( dir_device );
@@ -335,6 +337,7 @@ void init_directories(void)
 void close_directories(void)
 {
     release_object( dev_named_pipe );
+    release_object( dev_mailslot );
 
     release_object( link_dosdev );
     release_object( link_global1 );
diff --git a/server/mailslot.c b/server/mailslot.c
index 2c04fe2b895..7d2d0b00d56 100644
--- a/server/mailslot.c
+++ b/server/mailslot.c
@@ -62,6 +62,12 @@ struct mailslot
     struct list         writers;
 };
 
+struct mailslot_device
+{
+    struct object       obj;         /* object header */
+    struct namespace   *mailslots;   /* mailslot namespace */
+};
+
 /* mailslot functions */
 static void mailslot_dump( struct object*, int );
 static struct fd *mailslot_get_fd( struct object * );
@@ -135,6 +141,26 @@ static const struct fd_ops mail_writer_fd_ops =
     NULL                         /* cancel_async */
 };
 
+static void mailslot_device_dump( struct object *obj, int verbose );
+static struct object *mailslot_device_lookup_name( struct object *obj, struct unicode_str *name,
+                                                   unsigned int attr );
+static void mailslot_device_destroy( struct object *obj );
+
+static const struct object_ops mailslot_device_ops =
+{
+    sizeof(struct mailslot_device), /* size */
+    mailslot_device_dump,         /* dump */
+    no_add_queue,                 /* add_queue */
+    NULL,                         /* remove_queue */
+    NULL,                         /* signaled */
+    no_satisfied,                 /* satisfied */
+    no_signal,                    /* signal */
+    no_get_fd,                    /* get_fd */
+    mailslot_device_lookup_name,  /* lookup_name */
+    no_close_handle,              /* close_handle */
+    mailslot_device_destroy       /* destroy */
+};
+
 static void mailslot_destroy( struct object *obj)
 {
     struct mailslot *mailslot = (struct mailslot *) obj;
@@ -216,30 +242,91 @@ static void mailslot_queue_async( struct fd *fd, void *apc, void *user,
     fd_queue_async_timeout( fd, apc, user, iosb, type, count, timeout );
 }
 
-static struct mailslot *create_mailslot( const struct unicode_str *name, unsigned int attr,
+static void mailslot_device_dump( struct object *obj, int verbose )
+{
+    assert( obj->ops == &mailslot_device_ops );
+    fprintf( stderr, "Mail slot device\n" );
+}
+
+static struct object *mailslot_device_lookup_name( struct object *obj, struct unicode_str *name,
+                                                   unsigned int attr )
+{
+    struct mailslot_device *device = (struct mailslot_device*)obj;
+    struct object *found;
+
+    assert( obj->ops == &mailslot_device_ops );
+
+    if ((found = find_object( device->mailslots, name, attr | OBJ_CASE_INSENSITIVE )))
+        name->len = 0;
+
+    return found;
+}
+
+static void mailslot_device_destroy( struct object *obj )
+{
+    struct mailslot_device *device = (struct mailslot_device*)obj;
+    assert( obj->ops == &mailslot_device_ops );
+    free( device->mailslots );
+}
+
+struct mailslot_device *create_mailslot_device( void )
+{
+    static const WCHAR mailslotW[] = {'\\','?','?','\\','M','A','I','L','S','L','O','T'};
+    static struct unicode_str mailslot = {mailslotW, sizeof(mailslotW)};
+    struct mailslot_device *dev;
+
+    if ((dev = create_named_object_dir( NULL, &mailslot, 0, &mailslot_device_ops )) &&
+        get_error() != STATUS_OBJECT_NAME_EXISTS)
+    {
+        if (!(dev->mailslots = create_namespace( 7 )))
+        {
+            release_object( dev );
+            dev = NULL;
+        }
+    }
+    return dev;
+}
+
+static struct mailslot *create_mailslot( struct directory *root,
+                                         const struct unicode_str *name, unsigned int attr,
                                          int max_msgsize, int read_timeout )
 {
+    struct object *obj;
+    struct unicode_str new_name;
+    struct mailslot_device *dev;
     struct mailslot *mailslot;
     int fds[2];
-    static const WCHAR slot[] = {'m','a','i','l','s','l','o','t','\\'};
 
-    if ((name->len <= sizeof(slot)) || strncmpiW( slot, name->str, sizeof(slot)/sizeof(WCHAR) ))
+    if (!name || !name->len) return alloc_object( &mailslot_ops );
+
+    if (!(obj = find_object_dir( root, name, attr, &new_name ))) return NULL;
+
+    if (!new_name.len)
     {
-        set_error( STATUS_OBJECT_NAME_INVALID );
+        if (attr & OBJ_OPENIF && obj->ops == &mailslot_ops)
+            /* it already exists - there can only be one mailslot to read from */
+            set_error( STATUS_OBJECT_NAME_EXISTS );
+        else if (attr & OBJ_OPENIF)
+            set_error( STATUS_OBJECT_TYPE_MISMATCH );
+        else
+            set_error( STATUS_OBJECT_NAME_COLLISION );
+        release_object( obj );
         return NULL;
     }
 
-    mailslot = create_named_object( sync_namespace, &mailslot_ops, name, attr );
-    if (!mailslot)
-        return NULL;
-
-    /* it already exists - there can only be one mailslot to read from */
-    if (get_error() == STATUS_OBJECT_NAME_EXISTS)
+    if (obj->ops != &mailslot_device_ops)
     {
-        release_object( mailslot );
+        set_error( STATUS_OBJECT_TYPE_MISMATCH );
+        release_object( obj );
         return NULL;
     }
 
+    dev = (struct mailslot_device *)obj;
+    mailslot = create_object( dev->mailslots, &mailslot_ops, &new_name, NULL );
+    release_object( dev );
+
+    if (!mailslot) return NULL;
+
     mailslot->fd = NULL;
     mailslot->write_fd = NULL;
     mailslot->max_msgsize = max_msgsize;
@@ -262,24 +349,6 @@ static struct mailslot *create_mailslot( const struct unicode_str *name, unsigne
     return NULL;
 }
 
-static struct mailslot *open_mailslot( const struct unicode_str *name, unsigned int attr )
-{
-    struct object *obj;
-
-    obj = find_object( sync_namespace, name, attr );
-    if (obj)
-    {
-        if (obj->ops == &mailslot_ops)
-            return (struct mailslot *)obj;
-        release_object( obj );
-        set_error( STATUS_OBJECT_TYPE_MISMATCH );
-    }
-    else
-        set_error( STATUS_OBJECT_NAME_NOT_FOUND );
-
-    return NULL;
-}
-
 static void mail_writer_dump( struct object *obj, int verbose )
 {
     fprintf( stderr, "Mailslot writer\n" );
@@ -343,9 +412,7 @@ static struct mail_writer *create_mail_writer( struct mailslot *mailslot, unsign
 static struct mailslot *get_mailslot_obj( struct process *process, obj_handle_t handle,
                                           unsigned int access )
 {
-    struct object *obj;
-    obj = get_handle_obj( process, handle, access, &mailslot_ops );
-    return (struct mailslot *) obj;
+    return (struct mailslot *)get_handle_obj( process, handle, access, &mailslot_ops );
 }
 
 
@@ -354,16 +421,22 @@ DECL_HANDLER(create_mailslot)
 {
     struct mailslot *mailslot;
     struct unicode_str name;
+    struct directory *root = NULL;
 
     reply->handle = 0;
     get_req_unicode_str( &name );
-    mailslot = create_mailslot( &name, req->attributes, req->max_msgsize, req->read_timeout );
-    if (mailslot)
+    if (req->rootdir && !(root = get_directory_obj( current->process, req->rootdir, 0 )))
+        return;
+
+    if ((mailslot = create_mailslot( root, &name, req->attributes, req->max_msgsize,
+                                     req->read_timeout )))
     {
         reply->handle = alloc_handle( current->process, mailslot,
                                       req->access, req->attributes & OBJ_INHERIT );
         release_object( mailslot );
     }
+
+    if (root) release_object( root );
 }
 
 
@@ -372,6 +445,7 @@ DECL_HANDLER(open_mailslot)
 {
     struct mailslot *mailslot;
     struct unicode_str name;
+    struct directory *root = NULL;
 
     reply->handle = 0;
     get_req_unicode_str( &name );
@@ -382,7 +456,11 @@ DECL_HANDLER(open_mailslot)
         return;
     }
 
-    mailslot = open_mailslot( &name, req->attributes );
+    if (req->rootdir && !(root = get_directory_obj( current->process, req->rootdir, 0 )))
+        return;
+    mailslot = open_object_dir( root, &name, req->attributes, &mailslot_ops );
+    if (root) release_object( root );
+
     if (mailslot)
     {
         struct mail_writer *writer;
diff --git a/server/object.h b/server/object.h
index 66cd357f57c..06ce443eb06 100644
--- a/server/object.h
+++ b/server/object.h
@@ -199,6 +199,7 @@ extern struct symlink *create_symlink( struct directory *root, const struct unic
 
 /* devices */
 extern struct named_pipe_device *create_named_pipe_device( void );
+extern struct mailslot_device *create_mailslot_device( void );
 
 /* global variables */
 
diff --git a/server/protocol.def b/server/protocol.def
index 905e0ff82ec..dc302b03ffa 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -2486,6 +2486,7 @@ enum message_type
 @REQ(create_mailslot)
     unsigned int   access;        /* wanted access rights */
     unsigned int   attributes;    /* object attributes */
+    obj_handle_t   rootdir;       /* root directory */
     unsigned int   max_msgsize;
     int            read_timeout;
     VARARG(name,unicode_str);     /* mailslot name */
@@ -2498,6 +2499,7 @@ enum message_type
 @REQ(open_mailslot)
     unsigned int   access;
     unsigned int   attributes;    /* object attributes */
+    obj_handle_t   rootdir;       /* root directory */
     unsigned int   sharing;       /* sharing mode */
     VARARG(name,unicode_str);     /* mailslot name */
 @REPLY
diff --git a/server/trace.c b/server/trace.c
index 3618f6ed7dc..53199122619 100644
--- a/server/trace.c
+++ b/server/trace.c
@@ -3065,6 +3065,7 @@ static void dump_create_mailslot_request( const struct create_mailslot_request *
 {
     fprintf( stderr, " access=%08x,", req->access );
     fprintf( stderr, " attributes=%08x,", req->attributes );
+    fprintf( stderr, " rootdir=%p,", req->rootdir );
     fprintf( stderr, " max_msgsize=%08x,", req->max_msgsize );
     fprintf( stderr, " read_timeout=%d,", req->read_timeout );
     fprintf( stderr, " name=" );
@@ -3080,6 +3081,7 @@ static void dump_open_mailslot_request( const struct open_mailslot_request *req
 {
     fprintf( stderr, " access=%08x,", req->access );
     fprintf( stderr, " attributes=%08x,", req->attributes );
+    fprintf( stderr, " rootdir=%p,", req->rootdir );
     fprintf( stderr, " sharing=%08x,", req->sharing );
     fprintf( stderr, " name=" );
     dump_varargs_unicode_str( cur_size );
-- 
GitLab