Alexandre Julliard : server: Add support for opening files from a specified root directory.

Alexandre Julliard julliard at winehq.org
Wed Dec 2 10:22:10 CST 2009


Module: wine
Branch: master
Commit: 42806f32e933cf1e6f6513ca95a0ec7cbb7c2bd9
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=42806f32e933cf1e6f6513ca95a0ec7cbb7c2bd9

Author: Alexandre Julliard <julliard at winehq.org>
Date:   Tue Dec  1 17:38:24 2009 +0100

server: Add support for opening files from a specified root directory.

---

 server/change.c |    3 +--
 server/fd.c     |   37 ++++++++++++++++++++++++++++++++++---
 server/file.c   |   31 ++++++++++++++++++++++++-------
 server/file.h   |    5 +++--
 4 files changed, 62 insertions(+), 14 deletions(-)

diff --git a/server/change.c b/server/change.c
index 06d9e37..7ef456f 100644
--- a/server/change.c
+++ b/server/change.c
@@ -419,8 +419,7 @@ static void dir_destroy( struct object *obj )
     }
 }
 
-static struct dir *
-get_dir_obj( struct process *process, obj_handle_t handle, unsigned int access )
+struct dir *get_dir_obj( struct process *process, obj_handle_t handle, unsigned int access )
 {
     return (struct dir *)get_handle_obj( process, handle, access, &dir_ops );
 }
diff --git a/server/fd.c b/server/fd.c
index 9d8a06f..8f35812 100644
--- a/server/fd.c
+++ b/server/fd.c
@@ -1702,14 +1702,34 @@ void set_fd_user( struct fd *fd, const struct fd_ops *user_ops, struct object *u
     fd->user   = user;
 }
 
+static char *dup_fd_name( struct fd *root, const char *name )
+{
+    char *ret;
+
+    if (!root) return strdup( name );
+    if (!root->unix_name) return NULL;
+
+    /* skip . prefix */
+    if (name[0] == '.' && (!name[1] || name[1] == '/')) name++;
+
+    if ((ret = malloc( strlen(root->unix_name) + strlen(name) + 2 )))
+    {
+        strcpy( ret, root->unix_name );
+        if (name[0] && name[0] != '/') strcat( ret, "/" );
+        strcat( ret, name );
+    }
+    return ret;
+}
+
 /* open() wrapper that returns a struct fd with no fd user set */
-struct fd *open_fd( const char *name, int flags, mode_t *mode, unsigned int access,
+struct fd *open_fd( struct fd *root, const char *name, int flags, mode_t *mode, unsigned int access,
                     unsigned int sharing, unsigned int options )
 {
     struct stat st;
     struct closed_fd *closed_fd;
     struct fd *fd;
     const char *unlink_name = "";
+    int root_fd = -1;
     int rw_mode;
 
     if ((options & FILE_DELETE_ON_CLOSE) && !(access & DELETE))
@@ -1728,6 +1748,17 @@ struct fd *open_fd( const char *name, int flags, mode_t *mode, unsigned int acce
         return NULL;
     }
 
+    if (root)
+    {
+        if ((root_fd = get_unix_fd( root )) == -1) goto error;
+        if (fchdir( root_fd ) == -1)
+        {
+            file_set_error();
+            root_fd = -1;
+            goto error;
+        }
+    }
+
     /* create the directory if needed */
     if ((options & FILE_DIRECTORY_FILE) && (flags & O_CREAT))
     {
@@ -1749,8 +1780,7 @@ struct fd *open_fd( const char *name, int flags, mode_t *mode, unsigned int acce
     }
     else rw_mode = O_RDONLY;
 
-    if (!(fd->unix_name = mem_alloc( strlen(name) + 1 ))) goto error;
-    strcpy( fd->unix_name, name );
+    fd->unix_name = dup_fd_name( root, name );
 
     if ((fd->unix_fd = open( name, rw_mode | (flags & ~O_TRUNC), *mode )) == -1)
     {
@@ -1827,6 +1857,7 @@ struct fd *open_fd( const char *name, int flags, mode_t *mode, unsigned int acce
 error:
     release_object( fd );
     free( closed_fd );
+    if (root_fd != -1) fchdir( server_dir_fd ); /* go back to the server dir */
     return NULL;
 }
 
diff --git a/server/file.c b/server/file.c
index c09ddc5..3e09ddd 100644
--- a/server/file.c
+++ b/server/file.c
@@ -154,9 +154,10 @@ static struct object *create_file_obj( struct fd *fd, unsigned int access, mode_
     return &file->obj;
 }
 
-static struct object *create_file( const char *nameptr, data_size_t len, unsigned int access,
-                                   unsigned int sharing, int create, unsigned int options,
-                                   unsigned int attrs, const struct security_descriptor *sd )
+static struct object *create_file( struct fd *root, const char *nameptr, data_size_t len,
+                                   unsigned int access, unsigned int sharing, int create,
+                                   unsigned int options, unsigned int attrs,
+                                   const struct security_descriptor *sd )
 {
     struct object *obj = NULL;
     struct fd *fd;
@@ -164,6 +165,11 @@ static struct object *create_file( const char *nameptr, data_size_t len, unsigne
     char *name;
     mode_t mode;
 
+    if (!len || ((nameptr[0] == '/') ^ !root))
+    {
+        set_error( STATUS_OBJECT_PATH_SYNTAX_BAD );
+        return NULL;
+    }
     if (!(name = mem_alloc( len + 1 ))) return NULL;
     memcpy( name, nameptr, len );
     name[len] = 0;
@@ -203,7 +209,7 @@ static struct object *create_file( const char *nameptr, data_size_t len, unsigne
     access = generic_file_map_access( access );
 
     /* FIXME: should set error to STATUS_OBJECT_NAME_COLLISION if file existed before */
-    fd = open_fd( name, flags | O_NONBLOCK | O_LARGEFILE, &mode, access, sharing, options );
+    fd = open_fd( root, name, flags | O_NONBLOCK | O_LARGEFILE, &mode, access, sharing, options );
     if (!fd) goto done;
 
     if (S_ISDIR(mode))
@@ -628,6 +634,7 @@ struct file *grab_file_unless_removable( struct file *file )
 DECL_HANDLER(create_file)
 {
     struct object *file;
+    struct fd *root_fd = NULL;
     const struct object_attributes *objattr = get_req_data();
     const struct security_descriptor *sd;
     const char *name;
@@ -644,19 +651,29 @@ DECL_HANDLER(create_file)
         return;
     }
 
+    if (objattr->rootdir)
+    {
+        struct dir *root;
+
+        if (!(root = get_dir_obj( current->process, objattr->rootdir, 0 ))) return;
+        root_fd = get_obj_fd( (struct object *)root );
+        release_object( root );
+        if (!root_fd) return;
+    }
+
     sd = objattr->sd_len ? (const struct security_descriptor *)(objattr + 1) : NULL;
 
     name = (const char *)get_req_data() + sizeof(*objattr) + objattr->sd_len;
     name_len = get_req_data_size() - sizeof(*objattr) - objattr->sd_len;
 
     reply->handle = 0;
-    if ((file = create_file( name, name_len, req->access,
-                             req->sharing, req->create, req->options,
-                             req->attrs, sd )))
+    if ((file = create_file( root_fd, name, name_len, req->access, req->sharing,
+                             req->create, req->options, req->attrs, sd )))
     {
         reply->handle = alloc_handle( current->process, file, req->access, req->attributes );
         release_object( file );
     }
+    if (root_fd) release_object( root_fd );
 }
 
 /* allocate a file handle for a Unix fd */
diff --git a/server/file.h b/server/file.h
index a49fc4d..03cea89 100644
--- a/server/file.h
+++ b/server/file.h
@@ -54,8 +54,8 @@ struct fd_ops
 extern struct fd *alloc_pseudo_fd( const struct fd_ops *fd_user_ops, struct object *user,
                                    unsigned int options );
 extern void set_no_fd_status( struct fd *fd, unsigned int status );
-extern struct fd *open_fd( const char *name, int flags, mode_t *mode, unsigned int access,
-                           unsigned int sharing, unsigned int options );
+extern struct fd *open_fd( struct fd *root, const char *name, int flags, mode_t *mode,
+                           unsigned int access, unsigned int sharing, unsigned int options );
 extern struct fd *create_anonymous_fd( const struct fd_ops *fd_user_ops,
                                        int unix_fd, struct object *user, unsigned int options );
 extern struct fd *dup_fd_object( struct fd *orig, unsigned int access, unsigned int sharing,
@@ -125,6 +125,7 @@ extern mode_t sd_to_mode( const struct security_descriptor *sd, const SID *owner
 extern void do_change_notify( int unix_fd );
 extern void sigio_callback(void);
 extern struct object *create_dir_obj( struct fd *fd, unsigned int access, mode_t mode );
+extern struct dir *get_dir_obj( struct process *process, obj_handle_t handle, unsigned int access );
 
 /* completion */
 




More information about the wine-cvs mailing list