From 923d582f0769af65dc79bf6cad884e96989c8915 Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Mon, 23 Nov 2009 17:24:09 +0100 Subject: [PATCH] server: Implement the file sharing check when truncating a file that has an existing mapping. --- dlls/kernel32/tests/file.c | 12 +++++------- server/fd.c | 33 ++++++++++++++++++++------------- server/file.h | 5 +++-- server/mapping.c | 2 +- server/trace.c | 1 + 5 files changed, 30 insertions(+), 23 deletions(-) diff --git a/dlls/kernel32/tests/file.c b/dlls/kernel32/tests/file.c index dc95f63c565..35ca3c6822e 100644 --- a/dlls/kernel32/tests/file.c +++ b/dlls/kernel32/tests/file.c @@ -649,12 +649,10 @@ static void test_CopyFileA(void) ok(hmapfile != NULL, "CreateFileMapping: error %d\n", GetLastError()); ret = CopyFileA(source, dest, FALSE); - todo_wine { - ok(!ret, "CopyFileA: expected failure\n"); - ok(GetLastError() == ERROR_USER_MAPPED_FILE || - broken(GetLastError() == ERROR_SHARING_VIOLATION), /* Win9x and WinMe */ - "CopyFileA with mapped dest file: expected ERROR_USER_MAPPED_FILE, got %d\n", GetLastError()); - } + ok(!ret, "CopyFileA: expected failure\n"); + ok(GetLastError() == ERROR_USER_MAPPED_FILE || + broken(GetLastError() == ERROR_SHARING_VIOLATION), /* Win9x */ + "CopyFileA with mapped dest file: expected ERROR_USER_MAPPED_FILE, got %d\n", GetLastError()); CloseHandle(hmapfile); CloseHandle(hfile); @@ -1857,7 +1855,7 @@ 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 todo_wine + else { 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] ); diff --git a/server/fd.c b/server/fd.c index 7d151388458..ee1a9d3936b 100644 --- a/server/fd.c +++ b/server/fd.c @@ -1549,7 +1549,8 @@ void set_no_fd_status( struct fd *fd, unsigned int status ) /* check if the desired access is possible without violating */ /* the sharing mode of other opens of the same file */ -static int check_sharing( struct fd *fd, unsigned int access, unsigned int sharing ) +static unsigned int check_sharing( struct fd *fd, unsigned int access, unsigned int sharing, + unsigned int open_flags, unsigned int options ) { unsigned int existing_sharing = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE; unsigned int existing_access = 0; @@ -1569,16 +1570,21 @@ 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; - return 1; + if (((access & FILE_UNIX_READ_ACCESS) && !(existing_sharing & FILE_SHARE_READ)) || + ((access & FILE_UNIX_WRITE_ACCESS) && !(existing_sharing & FILE_SHARE_WRITE)) || + ((access & DELETE) && !(existing_sharing & FILE_SHARE_DELETE))) + return STATUS_SHARING_VIOLATION; + if (((existing_access & FILE_MAPPING_WRITE) && !(sharing & FILE_SHARE_WRITE)) || + ((existing_access & FILE_MAPPING_IMAGE) && (access & FILE_SHARE_WRITE))) + return STATUS_SHARING_VIOLATION; + if ((existing_access & FILE_MAPPING_ACCESS) && (open_flags & O_TRUNC)) + return STATUS_USER_MAPPED_FILE; + if (!access) return 0; /* if access mode is 0, sharing mode is ignored (except for mappings) */ + if (((existing_access & FILE_UNIX_READ_ACCESS) && !(sharing & FILE_SHARE_READ)) || + ((existing_access & FILE_UNIX_WRITE_ACCESS) && !(sharing & FILE_SHARE_WRITE)) || + ((existing_access & DELETE) && !(sharing & FILE_SHARE_DELETE))) + return STATUS_SHARING_VIOLATION; + return 0; } /* sets the user of an fd that previously had no user */ @@ -1659,6 +1665,7 @@ struct fd *open_fd( const char *name, int flags, mode_t *mode, unsigned int acce /* only bother with an inode for normal files and directories */ if (S_ISREG(st.st_mode) || S_ISDIR(st.st_mode)) { + unsigned int err; struct inode *inode = get_inode( st.st_dev, st.st_ino, fd->unix_fd ); if (!inode) @@ -1685,10 +1692,10 @@ struct fd *open_fd( const char *name, int flags, mode_t *mode, unsigned int acce set_error( STATUS_FILE_IS_A_DIRECTORY ); return NULL; } - if (!check_sharing( fd, access, sharing )) + if ((err = check_sharing( fd, access, sharing, flags, options ))) { release_object( fd ); - set_error( STATUS_SHARING_VIOLATION ); + set_error( err ); return NULL; } strcpy( closed_fd->unlink, unlink_name ); diff --git a/server/file.h b/server/file.h index 91dd034249d..a49fc4dca2d 100644 --- a/server/file.h +++ b/server/file.h @@ -160,7 +160,8 @@ extern void fd_copy_completion( struct fd *src, struct fd *dst ); #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 +#define FILE_MAPPING_IMAGE 0x80000000 /* set for SEC_IMAGE mappings */ +#define FILE_MAPPING_WRITE 0x40000000 /* set for writable shared mappings */ +#define FILE_MAPPING_ACCESS 0x20000000 /* set for all mappings */ #endif /* __WINE_SERVER_FILE_H */ diff --git a/server/mapping.c b/server/mapping.c index d8bc527a0cd..1cf53b9fe99 100644 --- a/server/mapping.c +++ b/server/mapping.c @@ -457,7 +457,7 @@ static struct object *create_mapping( struct directory *root, const struct unico if (handle) { - unsigned int mapping_access = 0; + unsigned int mapping_access = FILE_MAPPING_ACCESS; if (!(protect & VPROT_COMMITTED)) { diff --git a/server/trace.c b/server/trace.c index a4b1faac917..6c503f99064 100644 --- a/server/trace.c +++ b/server/trace.c @@ -4629,6 +4629,7 @@ static const struct { "TOO_MANY_OPENED_FILES", STATUS_TOO_MANY_OPENED_FILES }, { "UNSUCCESSFUL", STATUS_UNSUCCESSFUL }, { "USER_APC", STATUS_USER_APC }, + { "USER_MAPPED_FILE", STATUS_USER_MAPPED_FILE }, { "VOLUME_DISMOUNTED", STATUS_VOLUME_DISMOUNTED }, { "WAS_LOCKED", STATUS_WAS_LOCKED }, { NULL, 0 }