server: Implement the special file sharing rules for memory mappings.
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 @@
}
/* 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
/* 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 @@
if (handle)
{
+ unsigned int mapping_access = 0;
+
if (!(protect & VPROT_COMMITTED))
{
set_error( STATUS_INVALID_PARAMETER );
@@ -464,7 +466,13 @@
}
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;