Alexandre Julliard : server: Implement the special file sharing rules for memory mappings.

Alexandre Julliard julliard at winehq.org
Tue Nov 24 12:40:20 CST 2009


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

Author: Alexandre Julliard <julliard at winehq.org>
Date:   Mon Nov 23 17:09:08 2009 +0100

server: Implement the special file sharing rules for memory mappings.

---

 dlls/kernel32/tests/file.c |   22 ++++++++++++++--------
 server/fd.c                |   16 +++++++++-------
 server/file.h              |    7 ++++++-
 server/mapping.c           |   10 +++++++++-
 4 files changed, 38 insertions(+), 17 deletions(-)

diff --git a/dlls/kernel32/tests/file.c b/dlls/kernel32/tests/file.c
index 63e6e78..dc95f63 100644
--- a/dlls/kernel32/tests/file.c
+++ b/dlls/kernel32/tests/file.c
@@ -1827,16 +1827,16 @@ static void test_file_sharing(void)
                 if (h2 == INVALID_HANDLE_VALUE)
                 {
                     if (is_sharing_map_compatible(mapping_modes[a1], access_modes[a2], sharing_modes[s2]))
-                        todo_wine ok( is_win9x, /* there's no sharing at all with a mapping on win9x */
-                                      "open failed for modes map %x/%x/%x\n",
-                                      mapping_modes[a1], access_modes[a2], sharing_modes[s2] );
+                        ok( is_win9x, /* there's no sharing at all with a mapping on win9x */
+                            "open failed for modes map %x/%x/%x\n",
+                            mapping_modes[a1], access_modes[a2], sharing_modes[s2] );
                     ok( ret == ERROR_SHARING_VIOLATION,
                         "wrong error code %d\n", ret );
                 }
                 else
                 {
                     if (!is_sharing_map_compatible(mapping_modes[a1], access_modes[a2], sharing_modes[s2]))
-                        todo_wine ok( broken(1),  /* no checking on nt4 */
+                        ok( broken(1),  /* no checking on nt4 */
                             "open succeeded for modes map %x/%x/%x\n",
                             mapping_modes[a1], access_modes[a2], sharing_modes[s2] );
                     ok( ret == 0xdeadbeef /* Win9x */ ||
@@ -1852,11 +1852,17 @@ static void test_file_sharing(void)
         h2 = CreateFileA( filename, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
                           NULL, CREATE_ALWAYS, 0, 0 );
         ret = GetLastError();
-        ok( h2 == INVALID_HANDLE_VALUE, "create succeeded for map %x\n", mapping_modes[a1] );
         if ((mapping_modes[a1] & SEC_IMAGE) || is_win9x)
+        {
+            ok( h2 == INVALID_HANDLE_VALUE, "create succeeded for map %x\n", mapping_modes[a1] );
             ok( ret == ERROR_SHARING_VIOLATION, "wrong error code %d for %x\n", ret, mapping_modes[a1] );
+        }
         else todo_wine
+        {
+            ok( h2 == INVALID_HANDLE_VALUE, "create succeeded for map %x\n", mapping_modes[a1] );
             ok( ret == ERROR_USER_MAPPED_FILE, "wrong error code %d for %x\n", ret, mapping_modes[a1] );
+        }
+        if (h2 != INVALID_HANDLE_VALUE) CloseHandle( h2 );
 
         /* try DELETE_ON_CLOSE over an existing mapping */
         SetLastError(0xdeadbeef);
@@ -1868,12 +1874,12 @@ static void test_file_sharing(void)
             ok( h2 == INVALID_HANDLE_VALUE, "create succeeded for map %x\n", mapping_modes[a1] );
             ok( ret == ERROR_SHARING_VIOLATION, "wrong error code %d for %x\n", ret, mapping_modes[a1] );
         }
-        else if (mapping_modes[a1] & SEC_IMAGE)
+        else if (mapping_modes[a1] & SEC_IMAGE) todo_wine
         {
             ok( h2 == INVALID_HANDLE_VALUE, "create succeeded for map %x\n", mapping_modes[a1] );
-            todo_wine ok( ret == ERROR_ACCESS_DENIED, "wrong error code %d for %x\n", ret, mapping_modes[a1] );
+            ok( ret == ERROR_ACCESS_DENIED, "wrong error code %d for %x\n", ret, mapping_modes[a1] );
         }
-        else todo_wine
+        else
         {
             ok( h2 != INVALID_HANDLE_VALUE, "open failed for map %x err %u\n", mapping_modes[a1], ret );
         }
diff --git a/server/fd.c b/server/fd.c
index a4018ee..7d15138 100644
--- a/server/fd.c
+++ b/server/fd.c
@@ -1489,7 +1489,7 @@ struct fd *alloc_pseudo_fd( const struct fd_ops *fd_user_ops, struct object *use
 }
 
 /* duplicate an fd object for a different user */
-struct fd *dup_fd_object( struct fd *orig )
+struct fd *dup_fd_object( struct fd *orig, unsigned int access, unsigned int sharing, unsigned int options )
 {
     struct fd *fd = alloc_object( &fd_ops );
 
@@ -1499,9 +1499,9 @@ struct fd *dup_fd_object( struct fd *orig )
     fd->user       = NULL;
     fd->inode      = NULL;
     fd->closed     = NULL;
-    fd->access     = orig->access;
-    fd->options    = orig->options;
-    fd->sharing    = orig->sharing;
+    fd->access     = access;
+    fd->options    = options;
+    fd->sharing    = sharing;
     fd->unix_fd    = -1;
     fd->signaled   = 0;
     fd->fs_locks   = 0;
@@ -1555,8 +1555,6 @@ static int check_sharing( struct fd *fd, unsigned int access, unsigned int shari
     unsigned int existing_access = 0;
     struct list *ptr;
 
-    /* if access mode is 0, sharing mode is ignored */
-    if (!access) sharing = existing_sharing;
     fd->access = access;
     fd->sharing = sharing;
 
@@ -1565,7 +1563,8 @@ static int check_sharing( struct fd *fd, unsigned int access, unsigned int shari
         struct fd *fd_ptr = LIST_ENTRY( ptr, struct fd, inode_entry );
         if (fd_ptr != fd)
         {
-            existing_sharing &= fd_ptr->sharing;
+            /* if access mode is 0, sharing mode is ignored */
+            if (fd_ptr->access) existing_sharing &= fd_ptr->sharing;
             existing_access  |= fd_ptr->access;
         }
     }
@@ -1573,6 +1572,9 @@ static int check_sharing( struct fd *fd, unsigned int access, unsigned int shari
     if ((access & FILE_UNIX_READ_ACCESS) && !(existing_sharing & FILE_SHARE_READ)) return 0;
     if ((access & FILE_UNIX_WRITE_ACCESS) && !(existing_sharing & FILE_SHARE_WRITE)) return 0;
     if ((access & DELETE) && !(existing_sharing & FILE_SHARE_DELETE)) return 0;
+    if ((existing_access & FILE_MAPPING_WRITE) && !(sharing & FILE_SHARE_WRITE)) return 0;
+    if ((existing_access & FILE_MAPPING_IMAGE) && (access & FILE_SHARE_WRITE)) return 0;
+    if (!access) return 1;  /* if access mode is 0, sharing mode is ignored (except for mappings) */
     if ((existing_access & FILE_UNIX_READ_ACCESS) && !(sharing & FILE_SHARE_READ)) return 0;
     if ((existing_access & FILE_UNIX_WRITE_ACCESS) && !(sharing & FILE_SHARE_WRITE)) return 0;
     if ((existing_access & DELETE) && !(sharing & FILE_SHARE_DELETE)) return 0;
diff --git a/server/file.h b/server/file.h
index 1ace6f7..91dd034 100644
--- a/server/file.h
+++ b/server/file.h
@@ -58,7 +58,8 @@ extern struct fd *open_fd( const char *name, int flags, mode_t *mode, unsigned i
                            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 );
+extern struct fd *dup_fd_object( struct fd *orig, unsigned int access, unsigned int sharing,
+                                 unsigned int options );
 extern void *get_fd_user( struct fd *fd );
 extern void set_fd_user( struct fd *fd, const struct fd_ops *ops, struct object *user );
 extern unsigned int get_fd_options( struct fd *fd );
@@ -158,4 +159,8 @@ extern void fd_copy_completion( struct fd *src, struct fd *dst );
 /* access rights that require Unix write permission */
 #define FILE_UNIX_WRITE_ACCESS (FILE_WRITE_DATA|FILE_WRITE_ATTRIBUTES|FILE_WRITE_EA)
 
+/* magic file access rights for mappings */
+#define FILE_MAPPING_IMAGE  0x80000000
+#define FILE_MAPPING_WRITE  0x40000000
+
 #endif  /* __WINE_SERVER_FILE_H */
diff --git a/server/mapping.c b/server/mapping.c
index 1f60e88..d8bc527 100644
--- a/server/mapping.c
+++ b/server/mapping.c
@@ -457,6 +457,8 @@ static struct object *create_mapping( struct directory *root, const struct unico
 
     if (handle)
     {
+        unsigned int mapping_access = 0;
+
         if (!(protect & VPROT_COMMITTED))
         {
             set_error( STATUS_INVALID_PARAMETER );
@@ -464,7 +466,13 @@ static struct object *create_mapping( struct directory *root, const struct unico
         }
         if (!(file = get_file_obj( current->process, handle, access ))) goto error;
         fd = get_obj_fd( (struct object *)file );
-        mapping->fd = dup_fd_object( fd );
+
+        /* file sharing rules for mappings are different so we use magic the access rights */
+        if (protect & VPROT_IMAGE) mapping_access |= FILE_MAPPING_IMAGE;
+        else if (protect & VPROT_WRITE) mapping_access |= FILE_MAPPING_WRITE;
+        mapping->fd = dup_fd_object( fd, mapping_access,
+                                     FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+                                     FILE_SYNCHRONOUS_IO_NONALERT );
         release_object( file );
         release_object( fd );
         if (!mapping->fd) goto error;




More information about the wine-cvs mailing list