Signed-off-by: Daniel Lehman dlehman25@gmail.com --- dlls/kernel32/tests/file.c | 58 +++++++++++++++++++++++++++++++++++++- 1 file changed, 57 insertions(+), 1 deletion(-)
diff --git a/dlls/kernel32/tests/file.c b/dlls/kernel32/tests/file.c index 9327d0319dd..cc7a518b9c3 100644 --- a/dlls/kernel32/tests/file.c +++ b/dlls/kernel32/tests/file.c @@ -3978,10 +3978,40 @@ static void test_CreateFile(void) /* 25*/ { TRUNCATE_EXISTING, GENERIC_READ|GENERIC_WRITE, 0, 0 }, /* 26*/ { TRUNCATE_EXISTING, FILE_WRITE_DATA, ERROR_INVALID_PARAMETER, 0 } }; + static const struct test_data2 + { + DWORD disposition, access, share, share2, error; + } td2[] = + { + /* roughly matches dlls/ntdll/tests/file.c minus FILE_SUPERSEDE */ + /* 0 */ { CREATE_ALWAYS, GENERIC_READ, 0, FILE_SHARE_READ, ERROR_SHARING_VIOLATION }, + /* 1 */ { CREATE_ALWAYS, GENERIC_READ, FILE_SHARE_READ, 0, ERROR_SHARING_VIOLATION }, + /* 2 */ { CREATE_ALWAYS, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_SHARE_READ, ERROR_ALREADY_EXISTS }, + /* 3 */ { CREATE_ALWAYS, GENERIC_WRITE, 0, FILE_SHARE_WRITE, ERROR_SHARING_VIOLATION }, + /* 4 */ { CREATE_ALWAYS, GENERIC_WRITE, FILE_SHARE_WRITE, 0, ERROR_ALREADY_EXISTS }, + /* 5 */ { CREATE_NEW, GENERIC_READ, 0, FILE_SHARE_READ, ERROR_FILE_EXISTS }, + /* 6 */ { CREATE_NEW, GENERIC_READ, FILE_SHARE_READ, 0, ERROR_FILE_EXISTS }, + /* 7 */ { CREATE_NEW, GENERIC_WRITE, 0, FILE_SHARE_WRITE, ERROR_FILE_EXISTS }, + /* 8 */ { CREATE_NEW, GENERIC_WRITE, FILE_SHARE_WRITE, 0, ERROR_FILE_EXISTS }, + /* 9 */ { OPEN_ALWAYS, GENERIC_READ, 0, FILE_SHARE_READ, ERROR_SHARING_VIOLATION }, + /* 10 */ { OPEN_ALWAYS, GENERIC_READ, FILE_SHARE_READ, 0, ERROR_ALREADY_EXISTS }, + /* 11 */ { OPEN_ALWAYS, GENERIC_WRITE, 0, FILE_SHARE_WRITE, ERROR_SHARING_VIOLATION }, + /* 12 */ { OPEN_ALWAYS, GENERIC_WRITE, FILE_SHARE_WRITE, 0, ERROR_ALREADY_EXISTS }, + /* 13 */ { OPEN_EXISTING, GENERIC_READ, 0, FILE_SHARE_READ, ERROR_SHARING_VIOLATION }, + /* 14 */ { OPEN_EXISTING, GENERIC_READ, FILE_SHARE_READ, 0, 0 }, + /* 15 */ { OPEN_EXISTING, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_SHARE_READ, ERROR_SHARING_VIOLATION }, + /* 16 */ { OPEN_EXISTING, GENERIC_WRITE, 0, FILE_SHARE_WRITE, ERROR_SHARING_VIOLATION }, + /* 17 */ { OPEN_EXISTING, GENERIC_WRITE, FILE_SHARE_WRITE, 0, 0 }, + /* 18 */ { TRUNCATE_EXISTING, GENERIC_READ, 0, FILE_SHARE_READ, ERROR_INVALID_PARAMETER }, + /* 19 */ { TRUNCATE_EXISTING, GENERIC_READ, FILE_SHARE_READ, 0, ERROR_INVALID_PARAMETER }, + /* 20 */ { TRUNCATE_EXISTING, GENERIC_WRITE, FILE_SHARE_READ, FILE_SHARE_WRITE, ERROR_SHARING_VIOLATION }, + /* 21 */ { TRUNCATE_EXISTING, GENERIC_WRITE, 0, FILE_SHARE_WRITE, ERROR_SHARING_VIOLATION }, + /* 22 */ { TRUNCATE_EXISTING, GENERIC_WRITE, FILE_SHARE_WRITE, 0, 0 }, + }; char temp_path[MAX_PATH]; char file_name[MAX_PATH]; DWORD i, ret, written; - HANDLE hfile; + HANDLE hfile, hfile2;
GetTempPathA(MAX_PATH, temp_path); GetTempFileNameA(temp_path, "tmp", 0, file_name); @@ -4074,6 +4104,32 @@ todo_wine_if (i == 1) }
DeleteFileA(file_name); + + /* test consecutive calls to CreateFile */ + for (i = 0; i < ARRAY_SIZE(td2); i++) + { + SetLastError(0xdeadbeef); + hfile = CreateFileA(file_name, td2[i].access, td2[i].share, NULL, CREATE_NEW, 0, 0); + ok(GetLastError() == ERROR_SUCCESS, "%d: expected 0, got %d\n", i, GetLastError()); + ok(hfile != INVALID_HANDLE_VALUE, "%d: CreateFile error %d\n", i, GetLastError()); + + SetLastError(0xdeadbeef); + hfile2 = CreateFileA(file_name, td2[i].access, td2[i].share2 ? td2[i].share2 : td2[i].share, + NULL, td2[i].disposition, 0, 0); +todo_wine_if(i == 1 || i == 18 || i == 19) + ok(GetLastError() == td2[i].error, "%d: expected %d, got %d\n", i, td2[i].error, GetLastError()); +todo_wine_if(i == 1 || i == 19) +{ + if (td2[i].error && (td2[i].error != ERROR_ALREADY_EXISTS)) + ok(hfile2 == INVALID_HANDLE_VALUE, "%d: CreateFile should fail\n", i); + else + ok(hfile2 != INVALID_HANDLE_VALUE, "%d: CreateFile error %d\n", i, GetLastError()); +} + if (hfile2 != INVALID_HANDLE_VALUE) + CloseHandle(hfile2); + CloseHandle(hfile); + DeleteFileA(file_name); + } }
static void test_GetFileInformationByHandleEx(void)
Signed-off-by: Daniel Lehman dlehman25@gmail.com --- dlls/ntdll/tests/file.c | 66 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 64 insertions(+), 2 deletions(-)
diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c index 8b9ec4f624d..5e956d8a66c 100644 --- a/dlls/ntdll/tests/file.c +++ b/dlls/ntdll/tests/file.c @@ -4012,9 +4012,44 @@ static void test_NtCreateFile(void) /*17*/{ FILE_SUPERSEDE, FILE_ATTRIBUTE_READONLY, 0, FILE_SUPERSEDED, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY, TRUE }, /*18*/{ FILE_SUPERSEDE, 0, 0, FILE_CREATED, FILE_ATTRIBUTE_ARCHIVE, TRUE } }; + static const struct test_data2 + { + DWORD disposition, access, share, share2, status, result; + } td2[] = + { + /* roughly matches dlls/kernel32/tests/file.c plus FILE_SUPERSEDE */ + /* 0*/{ FILE_OVERWRITE_IF, GENERIC_READ, 0, FILE_SHARE_READ, STATUS_SHARING_VIOLATION }, + /* 1*/{ FILE_OVERWRITE_IF, GENERIC_READ, FILE_SHARE_READ, 0, STATUS_SHARING_VIOLATION }, + /* 2*/{ FILE_OVERWRITE_IF, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_SHARE_READ, 0, FILE_OVERWRITTEN }, + /* 3*/{ FILE_OVERWRITE_IF, GENERIC_WRITE, 0, FILE_SHARE_WRITE, STATUS_SHARING_VIOLATION, }, + /* 4*/{ FILE_OVERWRITE_IF, GENERIC_WRITE, FILE_SHARE_WRITE, 0, 0, FILE_OVERWRITTEN }, + /* 5*/{ FILE_CREATE, GENERIC_READ, 0, FILE_SHARE_READ, STATUS_OBJECT_NAME_COLLISION }, + /* 6*/{ FILE_CREATE, GENERIC_READ, FILE_SHARE_READ, 0, STATUS_OBJECT_NAME_COLLISION }, + /* 7*/{ FILE_CREATE, GENERIC_WRITE, 0, FILE_SHARE_WRITE, STATUS_OBJECT_NAME_COLLISION }, + /* 8*/{ FILE_CREATE, GENERIC_WRITE, FILE_SHARE_WRITE, 0, STATUS_OBJECT_NAME_COLLISION }, + /* 9*/{ FILE_OPEN_IF, GENERIC_READ, 0, FILE_SHARE_READ, STATUS_SHARING_VIOLATION }, + /* 10*/{ FILE_OPEN_IF, GENERIC_READ, FILE_SHARE_READ, 0, 0, FILE_OPENED }, + /* 11*/{ FILE_OPEN_IF, GENERIC_WRITE, 0, FILE_SHARE_WRITE, STATUS_SHARING_VIOLATION }, + /* 12*/{ FILE_OPEN_IF, GENERIC_WRITE, FILE_SHARE_WRITE, 0, 0, FILE_OPENED }, + /* 13*/{ FILE_OPEN, GENERIC_READ, 0, FILE_SHARE_READ, STATUS_SHARING_VIOLATION }, + /* 14*/{ FILE_OPEN, GENERIC_READ, FILE_SHARE_READ, 0, 0, FILE_OPENED }, + /* 15*/{ FILE_OPEN, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_SHARE_READ, STATUS_SHARING_VIOLATION }, + /* 16*/{ FILE_OPEN, GENERIC_WRITE, 0, FILE_SHARE_WRITE, STATUS_SHARING_VIOLATION }, + /* 17*/{ FILE_OPEN, GENERIC_WRITE, FILE_SHARE_WRITE, 0, 0, FILE_OPENED }, + /* 18*/{ FILE_OVERWRITE, GENERIC_READ, 0, FILE_SHARE_READ, STATUS_SHARING_VIOLATION }, + /* 19*/{ FILE_OVERWRITE, GENERIC_READ, FILE_SHARE_READ, 0, STATUS_SHARING_VIOLATION }, + /* 20*/{ FILE_OVERWRITE, GENERIC_WRITE, FILE_SHARE_READ, FILE_SHARE_WRITE, STATUS_SHARING_VIOLATION }, + /* 21*/{ FILE_OVERWRITE, GENERIC_WRITE, 0, FILE_SHARE_WRITE, STATUS_SHARING_VIOLATION }, + /* 22*/{ FILE_OVERWRITE, GENERIC_WRITE, FILE_SHARE_WRITE, 0, 0, FILE_OVERWRITTEN }, + /* 23*/{ FILE_SUPERSEDE, GENERIC_READ, 0, FILE_SHARE_READ, STATUS_SHARING_VIOLATION }, + /* 24*/{ FILE_SUPERSEDE, GENERIC_READ, FILE_SHARE_READ, 0, STATUS_SHARING_VIOLATION }, + /* 25*/{ FILE_SUPERSEDE, GENERIC_WRITE, 0, FILE_SHARE_WRITE, STATUS_SHARING_VIOLATION }, + /* 26*/{ FILE_SUPERSEDE, GENERIC_WRITE, FILE_SHARE_WRITE, 0, STATUS_SHARING_VIOLATION }, + /* 27*/{ FILE_SUPERSEDE, GENERIC_WRITE, FILE_SHARE_WRITE|FILE_SHARE_DELETE, 0, FILE_SUPERSEDED }, + }; static const WCHAR fooW[] = {'f','o','o',0}; NTSTATUS status; - HANDLE handle; + HANDLE handle, handle2; WCHAR path[MAX_PATH]; OBJECT_ATTRIBUTES attr; IO_STATUS_BLOCK io; @@ -4067,9 +4102,36 @@ static void test_NtCreateFile(void) } }
- pRtlFreeUnicodeString( &nameW ); SetFileAttributesW(path, FILE_ATTRIBUTE_ARCHIVE); DeleteFileW( path ); + + /* test consecutive calls to NtCreateFile */ + for (i = 0; i < ARRAY_SIZE(td2); i++) + { + status = pNtCreateFile(&handle, td2[i].access, &attr, &io, NULL, + FILE_ATTRIBUTE_NORMAL, td2[i].share, + FILE_CREATE, 0, NULL, 0); + ok(status == STATUS_SUCCESS, "%d: expected 0 got %#x\n", i, status); + + status = pNtCreateFile(&handle2, td2[i].access, &attr, &io, NULL, + FILE_ATTRIBUTE_NORMAL, td2[i].share2 ? td2[i].share2 : td2[i].share, + td2[i].disposition, 0, NULL, 0); + + todo_wine_if(i == 1 || i == 19 || i == 24 || i == 26) + ok(status == td2[i].status, "%d: expected %#x got %#x\n", i, td2[i].status, status); + if (!status) + { + todo_wine_if(i == 1 || i == 19) + ok(io.Information == td2[i].result,"%d: expected %#x got %#lx\n", i, td2[i].result, io.Information); + CloseHandle(handle2); + } + + CloseHandle(handle); + DeleteFileW(path); + } + + DeleteFileW( path ); + pRtlFreeUnicodeString( &nameW ); }
static void test_read_write(void)
Signed-off-by: Daniel Lehman dlehman25@gmail.com --- dlls/kernel32/tests/file.c | 5 +---- dlls/ntdll/tests/file.c | 3 +-- server/fd.c | 19 ++++++++++++++----- server/file.c | 2 +- server/file.h | 2 ++ 5 files changed, 19 insertions(+), 12 deletions(-)
diff --git a/dlls/kernel32/tests/file.c b/dlls/kernel32/tests/file.c index cc7a518b9c3..ffa1d3e2e32 100644 --- a/dlls/kernel32/tests/file.c +++ b/dlls/kernel32/tests/file.c @@ -4116,15 +4116,12 @@ todo_wine_if (i == 1) SetLastError(0xdeadbeef); hfile2 = CreateFileA(file_name, td2[i].access, td2[i].share2 ? td2[i].share2 : td2[i].share, NULL, td2[i].disposition, 0, 0); -todo_wine_if(i == 1 || i == 18 || i == 19) +todo_wine_if(i == 18 || i == 19) ok(GetLastError() == td2[i].error, "%d: expected %d, got %d\n", i, td2[i].error, GetLastError()); -todo_wine_if(i == 1 || i == 19) -{ if (td2[i].error && (td2[i].error != ERROR_ALREADY_EXISTS)) ok(hfile2 == INVALID_HANDLE_VALUE, "%d: CreateFile should fail\n", i); else ok(hfile2 != INVALID_HANDLE_VALUE, "%d: CreateFile error %d\n", i, GetLastError()); -} if (hfile2 != INVALID_HANDLE_VALUE) CloseHandle(hfile2); CloseHandle(hfile); diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c index 5e956d8a66c..bc369ee9354 100644 --- a/dlls/ntdll/tests/file.c +++ b/dlls/ntdll/tests/file.c @@ -4117,11 +4117,10 @@ static void test_NtCreateFile(void) FILE_ATTRIBUTE_NORMAL, td2[i].share2 ? td2[i].share2 : td2[i].share, td2[i].disposition, 0, NULL, 0);
- todo_wine_if(i == 1 || i == 19 || i == 24 || i == 26) + todo_wine_if(i == 24 || i == 26) ok(status == td2[i].status, "%d: expected %#x got %#x\n", i, td2[i].status, status); if (!status) { - todo_wine_if(i == 1 || i == 19) ok(io.Information == td2[i].result,"%d: expected %#x got %#lx\n", i, td2[i].result, io.Information); CloseHandle(handle2); } diff --git a/server/fd.c b/server/fd.c index edb59b0d540..a4cd633ae04 100644 --- a/server/fd.c +++ b/server/fd.c @@ -1585,7 +1585,7 @@ static void fd_destroy( struct object *obj ) /* check if the desired access is possible without violating */ /* the sharing mode of other opens of the same file */ static unsigned int check_sharing( struct fd *fd, unsigned int access, unsigned int sharing, - unsigned int open_flags, unsigned int options ) + unsigned int open_flags, unsigned int options, int create ) { /* only a few access bits are meaningful wrt sharing */ const unsigned int read_access = FILE_READ_DATA | FILE_EXECUTE; @@ -1627,6 +1627,9 @@ static unsigned int check_sharing( struct fd *fd, unsigned int access, unsigned ((existing_access & write_access) && !(sharing & FILE_SHARE_WRITE)) || ((existing_access & DELETE) && !(sharing & FILE_SHARE_DELETE))) return STATUS_SHARING_VIOLATION; + if ((create == FILE_OVERWRITE_IF || create == FILE_OVERWRITE) && + !(existing_sharing & FILE_SHARE_WRITE)) + return STATUS_SHARING_VIOLATION; return 0; }
@@ -1772,7 +1775,7 @@ struct fd *dup_fd_object( struct fd *orig, unsigned int access, unsigned int sha fd->closed = closed; fd->inode = (struct inode *)grab_object( orig->inode ); list_add_head( &fd->inode->open, &fd->inode_entry ); - if ((err = check_sharing( fd, access, sharing, 0, options ))) + if ((err = check_sharing( fd, access, sharing, 0, options, -1 ))) { set_error( err ); goto failed; @@ -1831,9 +1834,15 @@ char *dup_fd_name( struct fd *root, const char *name ) return ret; }
+struct fd *open_fd( struct fd *root, const char *name, int flags, mode_t *mode, + unsigned int access, unsigned int sharing, unsigned int options ) +{ + return open_fd2( root, name, flags, mode, access, sharing, options, -1 ); +} + /* open() wrapper that returns a struct fd with no fd user set */ -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 fd *open_fd2( struct fd *root, const char *name, int flags, mode_t *mode, unsigned int access, + unsigned int sharing, unsigned int options, int create ) { struct stat st; struct closed_fd *closed_fd; @@ -1949,7 +1958,7 @@ struct fd *open_fd( struct fd *root, const char *name, int flags, mode_t *mode, set_error( STATUS_FILE_IS_A_DIRECTORY ); goto error; } - if ((err = check_sharing( fd, access, sharing, flags, options ))) + if ((err = check_sharing( fd, access, sharing, flags, options, create ))) { set_error( err ); goto error; diff --git a/server/file.c b/server/file.c index 4690af2424e..9cdc8f31a85 100644 --- a/server/file.c +++ b/server/file.c @@ -255,7 +255,7 @@ static struct object *create_file( struct fd *root, const char *nameptr, data_si access = generic_file_map_access( access );
/* FIXME: should set error to STATUS_OBJECT_NAME_COLLISION if file existed before */ - fd = open_fd( root, name, flags | O_NONBLOCK | O_LARGEFILE, &mode, access, sharing, options ); + fd = open_fd2( root, name, flags | O_NONBLOCK | O_LARGEFILE, &mode, access, sharing, options, create ); if (!fd) goto done;
if (S_ISDIR(mode)) diff --git a/server/file.h b/server/file.h index 2fb634fad8d..48fea7de816 100644 --- a/server/file.h +++ b/server/file.h @@ -80,6 +80,8 @@ extern struct fd *alloc_pseudo_fd( const struct fd_ops *fd_user_ops, struct obje 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 *open_fd2( struct fd *root, const char *name, int flags, mode_t *mode, + unsigned int access, unsigned int sharing, unsigned int options, int create ); 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,