Module: wine Branch: master Commit: fd504b62899bb8d5d01a2f064ccd368fe7aa6297 URL: http://source.winehq.org/git/wine.git/?a=commit;h=fd504b62899bb8d5d01a2f064c...
Author: Alexandre Julliard julliard@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;