[PATCH v3 0/11] MR3907: ntdll: Initial implementation of File{Rename,Link}InformationEx
-- v3: ntdll: Add support for FILE_{RENAME,LINK}_POSIX_SEMANTICS. ntdll: Factored out get_inode_open_sharing. ntdll/test: Add tests for FILE_LINK_POSIX_SEMANTICS. ntdll/test: Add tests for FILE_RENAME_POSIX_SEMANTICS. ntdll: Add support for FILE_{RENAME,LINK}_IGNORE_READONLY_ATTRIBUTE. server: Don't allow read-only files to be replaced by File{Rename,Link}Information{,Ex}. ntdll/test: Add tests for FILE_LINK_IGNORE_READONLY_ATTRIBUTE. ntdll/test: Add tests for FILE_RENAME_IGNORE_READONLY_ATTRIBUTE. ntdll/test: Use FileDispositionInformationEx to delete files and directories. ntdll: Initial implementation of FileLinkInformationEx. ntdll: Initial implementation of FileRenameInformationEx. https://gitlab.winehq.org/wine/wine/-/merge_requests/3907
From: Joel Holdsworth <joel(a)airwebreathe.org.uk> Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=54997 Signed-off-by: Joel Holdsworth <joel(a)airwebreathe.org.uk> --- dlls/ntdll/tests/file.c | 48 +++------------------------------- dlls/ntdll/unix/file.c | 14 ++++++++-- include/wine/server_protocol.h | 4 +-- server/fd.c | 5 ++-- server/protocol.def | 2 +- server/request.h | 2 +- server/trace.c | 2 +- 7 files changed, 23 insertions(+), 54 deletions(-) diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c index 1fcffe36a35..da4f817b1da 100644 --- a/dlls/ntdll/tests/file.c +++ b/dlls/ntdll/tests/file.c @@ -1549,29 +1549,24 @@ static void test_file_rename_information(FILE_INFORMATION_CLASS class) if (class == FileRenameInformationEx && (res == STATUS_NOT_IMPLEMENTED || res == STATUS_INVALID_INFO_CLASS)) { - todo_wine win_skip( "FileRenameInformationEx not supported\n" ); + win_skip( "FileRenameInformationEx not supported\n" ); CloseHandle( handle ); HeapFree( GetProcessHeap(), 0, fri ); delete_object( oldpath ); return; } - todo_wine_if( class == FileRenameInformationEx ) ok( io.Status == STATUS_SUCCESS, "io.Status expected STATUS_SUCCESS, got %lx\n", io.Status ); - todo_wine_if( class == FileRenameInformationEx ) ok( res == STATUS_SUCCESS, "res expected STATUS_SUCCESS, got %lx\n", res ); fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; - todo_wine_if( class == FileRenameInformationEx ) ok( fileDeleted, "file should not exist\n" ); fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; - todo_wine_if( class == FileRenameInformationEx ) ok( !fileDeleted, "file should exist\n" ); fni = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_NAME_INFORMATION) + MAX_PATH * sizeof(WCHAR) ); res = pNtQueryInformationFile( handle, &io, fni, sizeof(FILE_NAME_INFORMATION) + MAX_PATH * sizeof(WCHAR), FileNameInformation ); ok( res == STATUS_SUCCESS, "res expected STATUS_SUCCESS, got %lx\n", res ); fni->FileName[ fni->FileNameLength / sizeof(WCHAR) ] = 0; - todo_wine_if( class == FileRenameInformationEx ) ok( !lstrcmpiW(fni->FileName, newpath + 2), "FileName expected %s, got %s\n", wine_dbgstr_w(newpath + 2), wine_dbgstr_w(fni->FileName) ); HeapFree( GetProcessHeap(), 0, fni ); @@ -1600,7 +1595,6 @@ static void test_file_rename_information(FILE_INFORMATION_CLASS class) io.Status = 0xdeadbeef; res = pNtSetInformationFile( handle, &io, fri, sizeof(FILE_RENAME_INFORMATION) + fri->FileNameLength, class ); todo_wine ok( io.Status == 0xdeadbeef, "io.Status expected 0xdeadbeef, got %lx\n", io.Status ); - todo_wine_if( class == FileRenameInformationEx ) ok( res == STATUS_OBJECT_NAME_COLLISION, "res expected STATUS_OBJECT_NAME_COLLISION, got %lx\n", res ); fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; ok( !fileDeleted, "file should exist\n" ); @@ -1630,12 +1624,9 @@ static void test_file_rename_information(FILE_INFORMATION_CLASS class) io.Status = 0xdeadbeef; res = pNtSetInformationFile( handle, &io, fri, sizeof(FILE_RENAME_INFORMATION) + fri->FileNameLength, class ); - todo_wine_if( class == FileRenameInformationEx ) ok( io.Status == STATUS_SUCCESS, "io.Status expected STATUS_SUCCESS, got %lx\n", io.Status ); - todo_wine_if( class == FileRenameInformationEx ) ok( res == STATUS_SUCCESS, "res expected STATUS_SUCCESS, got %lx\n", res ); fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; - todo_wine_if( class == FileRenameInformationEx ) ok( fileDeleted, "file should not exist\n" ); fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; ok( !fileDeleted, "file should exist\n" ); @@ -1667,7 +1658,6 @@ static void test_file_rename_information(FILE_INFORMATION_CLASS class) io.Status = 0xdeadbeef; res = pNtSetInformationFile( handle, &io, fri, sizeof(FILE_RENAME_INFORMATION) + fri->FileNameLength, class ); todo_wine ok( io.Status == 0xdeadbeef, "io.Status expected 0xdeadbeef, got %lx\n", io.Status ); - todo_wine_if( class == FileRenameInformationEx ) ok( res == STATUS_OBJECT_NAME_COLLISION, "res expected STATUS_OBJECT_NAME_COLLISION, got %lx\n", res ); fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; ok( !fileDeleted, "file should exist\n" ); @@ -1702,7 +1692,6 @@ static void test_file_rename_information(FILE_INFORMATION_CLASS class) io.Status = 0xdeadbeef; res = pNtSetInformationFile( handle, &io, fri, sizeof(FILE_RENAME_INFORMATION) + fri->FileNameLength, class ); todo_wine ok( io.Status == 0xdeadbeef, "io.Status expected 0xdeadbeef, got %lx\n", io.Status ); - todo_wine_if( class == FileRenameInformationEx ) ok( res == STATUS_ACCESS_DENIED, "res expected STATUS_ACCESS_DENIED, got %lx\n", res ); fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; ok( !fileDeleted, "file should exist\n" ); @@ -1737,22 +1726,17 @@ static void test_file_rename_information(FILE_INFORMATION_CLASS class) io.Status = 0xdeadbeef; res = pNtSetInformationFile( handle, &io, fri, sizeof(FILE_RENAME_INFORMATION) + fri->FileNameLength, class ); - todo_wine_if( class == FileRenameInformationEx ) ok( io.Status == STATUS_SUCCESS, "io.Status expected STATUS_SUCCESS, got %lx\n", io.Status ); - todo_wine_if( class == FileRenameInformationEx ) ok( res == STATUS_SUCCESS, "res expected STATUS_SUCCESS, got %lx\n", res ); fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; - todo_wine_if( class == FileRenameInformationEx ) ok( fileDeleted, "file should not exist\n" ); fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; - todo_wine_if( class == FileRenameInformationEx ) ok( !fileDeleted, "file should exist\n" ); fni = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_NAME_INFORMATION) + MAX_PATH * sizeof(WCHAR) ); res = pNtQueryInformationFile( handle, &io, fni, sizeof(FILE_NAME_INFORMATION) + MAX_PATH * sizeof(WCHAR), FileNameInformation ); ok( res == STATUS_SUCCESS, "res expected STATUS_SUCCESS, got %lx\n", res ); fni->FileName[ fni->FileNameLength / sizeof(WCHAR) ] = 0; - todo_wine_if( class == FileRenameInformationEx ) ok( !lstrcmpiW(fni->FileName, newpath + 2), "FileName expected %s, got %s\n", wine_dbgstr_w(newpath + 2), wine_dbgstr_w(fni->FileName) ); HeapFree( GetProcessHeap(), 0, fni ); @@ -1792,11 +1776,9 @@ static void test_file_rename_information(FILE_INFORMATION_CLASS class) todo_wine ok( io.Status == 0xdeadbeef || io.Status == STATUS_ACCESS_DENIED, "io.Status got %lx\n", io.Status ); todo_wine ok( res == STATUS_ACCESS_DENIED, "res expected STATUS_ACCESS_DENIED, got %lx\n", res ); fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; - todo_wine_if( class != FileRenameInformationEx ) - ok( !fileDeleted, "file should exist\n" ); + todo_wine ok( !fileDeleted, "file should exist\n" ); fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; - todo_wine_if( class != FileRenameInformationEx ) - ok( fileDeleted, "file should not exist\n" ); + todo_wine ok( fileDeleted, "file should not exist\n" ); CloseHandle( handle ); CloseHandle( handle2 ); @@ -1831,9 +1813,7 @@ static void test_file_rename_information(FILE_INFORMATION_CLASS class) io.Status = 0xdeadbeef; res = pNtSetInformationFile( handle, &io, fri, sizeof(FILE_RENAME_INFORMATION) + fri->FileNameLength, class ); - todo_wine_if( class == FileRenameInformationEx ) ok( io.Status == 0xdeadbeef || io.Status == STATUS_OBJECT_NAME_COLLISION, "io.Status got %lx\n", io.Status ); - todo_wine_if( class == FileRenameInformationEx ) ok( res == STATUS_OBJECT_NAME_COLLISION, "res expected STATUS_OBJECT_NAME_COLLISION, got %lx\n", res ); fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; ok( !fileDeleted, "file should exist\n" ); @@ -1869,9 +1849,7 @@ static void test_file_rename_information(FILE_INFORMATION_CLASS class) io.Status = 0xdeadbeef; res = pNtSetInformationFile( handle, &io, fri, sizeof(FILE_RENAME_INFORMATION) + fri->FileNameLength, class ); - todo_wine_if( class == FileRenameInformationEx ) ok( io.Status == 0xdeadbeef || io.Status == STATUS_OBJECT_NAME_COLLISION, "io.Status got %lx\n", io.Status ); - todo_wine_if( class == FileRenameInformationEx ) ok( res == STATUS_OBJECT_NAME_COLLISION, "res expected STATUS_OBJECT_NAME_COLLISION, got %lx\n", res ); fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; ok( !fileDeleted, "file should exist\n" ); @@ -1905,12 +1883,9 @@ static void test_file_rename_information(FILE_INFORMATION_CLASS class) io.Status = 0xdeadbeef; res = pNtSetInformationFile( handle, &io, fri, sizeof(FILE_RENAME_INFORMATION) + fri->FileNameLength, class ); - todo_wine_if( class == FileRenameInformationEx ) ok( io.Status == STATUS_SUCCESS, "io.Status expected STATUS_SUCCESS, got %lx\n", io.Status ); - todo_wine_if( class == FileRenameInformationEx ) ok( res == STATUS_SUCCESS, "res expected STATUS_SUCCESS, got %lx\n", res ); fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; - todo_wine_if( class == FileRenameInformationEx ) ok( fileDeleted, "file should not exist\n" ); fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; ok( !fileDeleted, "file should exist\n" ); @@ -1944,9 +1919,7 @@ static void test_file_rename_information(FILE_INFORMATION_CLASS class) io.Status = 0xdeadbeef; res = pNtSetInformationFile( handle, &io, fri, sizeof(FILE_RENAME_INFORMATION) + fri->FileNameLength, class ); - todo_wine_if( class == FileRenameInformationEx ) ok( io.Status == 0xdeadbeef || io.Status == STATUS_ACCESS_DENIED, "io.Status got %lx\n", io.Status ); - todo_wine_if( class == FileRenameInformationEx ) ok( res == STATUS_ACCESS_DENIED, "res expected STATUS_ACCESS_DENIED, got %lx\n", res ); fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; ok( !fileDeleted, "file should exist\n" ); @@ -1983,9 +1956,7 @@ static void test_file_rename_information(FILE_INFORMATION_CLASS class) io.Status = 0xdeadbeef; res = pNtSetInformationFile( handle, &io, fri, sizeof(FILE_RENAME_INFORMATION) + fri->FileNameLength, class ); - todo_wine_if( class == FileRenameInformationEx ) ok( io.Status == 0xdeadbeef || io.Status == STATUS_OBJECT_NAME_COLLISION, "io.Status got %lx\n", io.Status ); - todo_wine_if( class == FileRenameInformationEx ) ok( res == STATUS_OBJECT_NAME_COLLISION, "res expected STATUS_OBJECT_NAME_COLLISION, got %lx\n", res ); fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; ok( !fileDeleted, "file should exist\n" ); @@ -2021,9 +1992,7 @@ static void test_file_rename_information(FILE_INFORMATION_CLASS class) io.Status = 0xdeadbeef; res = pNtSetInformationFile( handle, &io, fri, sizeof(FILE_RENAME_INFORMATION) + fri->FileNameLength, class ); - todo_wine_if( class == FileRenameInformationEx ) ok( io.Status == 0xdeadbeef || io.Status == STATUS_ACCESS_DENIED, "io.Status got %lx\n", io.Status ); - todo_wine_if( class == FileRenameInformationEx ) ok( res == STATUS_ACCESS_DENIED, "res expected STATUS_ACCESS_DENIED, got %lx\n", res ); fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; ok( !fileDeleted, "file should exist\n" ); @@ -2062,9 +2031,7 @@ static void test_file_rename_information(FILE_INFORMATION_CLASS class) io.Status = 0xdeadbeef; res = pNtSetInformationFile( handle, &io, fri, sizeof(FILE_RENAME_INFORMATION) + fri->FileNameLength, class ); - todo_wine_if( class == FileRenameInformationEx ) ok( io.Status == 0xdeadbeef || io.Status == STATUS_ACCESS_DENIED, "io.Status got %lx\n", io.Status ); - todo_wine_if( class == FileRenameInformationEx ) ok( res == STATUS_ACCESS_DENIED, "res expected STATUS_ACCESS_DENIED, got %lx\n", res ); fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; ok( !fileDeleted, "file should exist\n" ); @@ -2099,7 +2066,6 @@ static void test_file_rename_information(FILE_INFORMATION_CLASS class) io.Status = 0xdeadbeef; res = pNtSetInformationFile( handle, &io, fri, sizeof(FILE_RENAME_INFORMATION) + fri->FileNameLength, class ); todo_wine ok( io.Status == 0xdeadbeef, "io.Status expected 0xdeadbeef, got %lx\n", io.Status ); - todo_wine_if( class == FileRenameInformationEx ) ok( res == STATUS_OBJECT_NAME_COLLISION, "res expected STATUS_OBJECT_NAME_COLLISION, got %lx\n", res ); fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; ok( !fileDeleted, "file should exist\n" ); @@ -2133,7 +2099,6 @@ static void test_file_rename_information(FILE_INFORMATION_CLASS class) io.Status = 0xdeadbeef; res = pNtSetInformationFile( handle, &io, fri, sizeof(FILE_RENAME_INFORMATION) + fri->FileNameLength, class ); todo_wine ok( io.Status == 0xdeadbeef, "io.Status expected 0xdeadbeef, got %lx\n", io.Status ); - todo_wine_if( class == FileRenameInformationEx ) ok( res == STATUS_ACCESS_DENIED, "res expected STATUS_ACCESS_DENIED, got %lx\n", res ); fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; ok( !fileDeleted, "file should exist\n" ); @@ -2167,22 +2132,17 @@ static void test_file_rename_information(FILE_INFORMATION_CLASS class) io.Status = 0xdeadbeef; res = pNtSetInformationFile( handle, &io, fri, sizeof(FILE_RENAME_INFORMATION) + fri->FileNameLength, class ); - todo_wine_if( class == FileRenameInformationEx ) ok( io.Status == STATUS_SUCCESS, "io.Status expected STATUS_SUCCESS, got %lx\n", io.Status ); - todo_wine_if( class == FileRenameInformationEx ) ok( res == STATUS_SUCCESS, "res expected STATUS_SUCCESS, got %lx\n", res ); fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; - todo_wine_if( class == FileRenameInformationEx ) ok( fileDeleted, "file should not exist\n" ); fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; - todo_wine_if( class == FileRenameInformationEx ) ok( !fileDeleted, "file should exist\n" ); fni = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_NAME_INFORMATION) + MAX_PATH * sizeof(WCHAR) ); res = pNtQueryInformationFile( handle, &io, fni, sizeof(FILE_NAME_INFORMATION) + MAX_PATH * sizeof(WCHAR), FileNameInformation ); ok( res == STATUS_SUCCESS, "res expected STATUS_SUCCESS, got %lx\n", res ); fni->FileName[ fni->FileNameLength / sizeof(WCHAR) ] = 0; - todo_wine_if( class == FileRenameInformationEx ) ok( !lstrcmpiW(fni->FileName, newpath + 2), "FileName expected %s, got %s\n", wine_dbgstr_w(newpath + 2), wine_dbgstr_w(fni->FileName) ); HeapFree( GetProcessHeap(), 0, fni ); @@ -2209,9 +2169,7 @@ static void test_file_rename_information(FILE_INFORMATION_CLASS class) io.Status = 0xdeadbeef; res = pNtSetInformationFile( handle, &io, fri, sizeof(FILE_RENAME_INFORMATION) + fri->FileNameLength, class ); - todo_wine_if( class == FileRenameInformationEx ) ok( io.Status == STATUS_SUCCESS, "got io status %#lx\n", io.Status ); - todo_wine_if( class == FileRenameInformationEx ) ok( res == STATUS_SUCCESS, "got status %lx\n", res ); ok( GetFileAttributesW( oldpath ) != INVALID_FILE_ATTRIBUTES, "file should exist\n" ); diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c index 43bde14e5d8..38ba1f0e883 100644 --- a/dlls/ntdll/unix/file.c +++ b/dlls/ntdll/unix/file.c @@ -4783,13 +4783,23 @@ NTSTATUS WINAPI NtSetInformationFile( HANDLE handle, IO_STATUS_BLOCK *io, break; case FileRenameInformation: + case FileRenameInformationEx: if (len >= sizeof(FILE_RENAME_INFORMATION)) { FILE_RENAME_INFORMATION *info = ptr; + ULONG flags; UNICODE_STRING name_str, redir; OBJECT_ATTRIBUTES attr; char *unix_name; + if (class == FileRenameInformation) + flags = info->ReplaceIfExists ? FILE_RENAME_REPLACE_IF_EXISTS : 0; + else + flags = info->Flags; + + if (flags & ~FILE_RENAME_REPLACE_IF_EXISTS) + FIXME( "unsupported flags: %#x\n", (unsigned int)flags ); + name_str.Buffer = info->FileName; name_str.Length = info->FileNameLength; name_str.MaximumLength = info->FileNameLength + sizeof(WCHAR); @@ -4805,7 +4815,7 @@ NTSTATUS WINAPI NtSetInformationFile( HANDLE handle, IO_STATUS_BLOCK *io, req->rootdir = wine_server_obj_handle( attr.RootDirectory ); req->namelen = attr.ObjectName->Length; req->link = FALSE; - req->replace = info->ReplaceIfExists; + req->flags = flags; wine_server_add_data( req, attr.ObjectName->Buffer, attr.ObjectName->Length ); wine_server_add_data( req, unix_name, strlen(unix_name) ); status = wine_server_call( req ); @@ -4842,7 +4852,7 @@ NTSTATUS WINAPI NtSetInformationFile( HANDLE handle, IO_STATUS_BLOCK *io, req->rootdir = wine_server_obj_handle( attr.RootDirectory ); req->namelen = attr.ObjectName->Length; req->link = TRUE; - req->replace = info->ReplaceIfExists; + req->flags = info->ReplaceIfExists ? FILE_LINK_REPLACE_IF_EXISTS : 0; wine_server_add_data( req, attr.ObjectName->Buffer, attr.ObjectName->Length ); wine_server_add_data( req, unix_name, strlen(unix_name) ); status = wine_server_call( req ); diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index 6d9f8550647..9ad2bf9c3f9 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -5307,7 +5307,7 @@ struct set_fd_name_info_request obj_handle_t rootdir; data_size_t namelen; int link; - int replace; + unsigned int flags; /* VARARG(name,unicode_str,namelen); */ /* VARARG(filename,string); */ }; @@ -6487,7 +6487,7 @@ union generic_reply /* ### protocol_version begin ### */ -#define SERVER_PROTOCOL_VERSION 782 +#define SERVER_PROTOCOL_VERSION 783 /* ### protocol_version end ### */ diff --git a/server/fd.c b/server/fd.c index 7cdd329bcbb..5947dee3ae1 100644 --- a/server/fd.c +++ b/server/fd.c @@ -2511,11 +2511,12 @@ static void set_fd_disposition( struct fd *fd, unsigned int flags ) /* set new name for the fd */ static void set_fd_name( struct fd *fd, struct fd *root, const char *nameptr, data_size_t len, - struct unicode_str nt_name, int create_link, int replace ) + struct unicode_str nt_name, int create_link, unsigned int flags ) { struct inode *inode; struct stat st, st2; char *name; + const unsigned int replace = flags & FILE_RENAME_REPLACE_IF_EXISTS; if (!fd->inode || !fd->unix_name) { @@ -2967,7 +2968,7 @@ DECL_HANDLER(set_fd_name_info) if ((fd = get_handle_fd_obj( current->process, req->handle, 0 ))) { set_fd_name( fd, root_fd, (const char *)get_req_data() + req->namelen, - get_req_data_size() - req->namelen, nt_name, req->link, req->replace ); + get_req_data_size() - req->namelen, nt_name, req->link, req->flags ); release_object( fd ); } if (root_fd) release_object( root_fd ); diff --git a/server/protocol.def b/server/protocol.def index 1699dd37473..4d2a95d6324 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -3692,7 +3692,7 @@ struct handle_info obj_handle_t rootdir; /* root directory */ data_size_t namelen; /* length of NT name in bytes */ int link; /* link instead of renaming */ - int replace; /* replace an existing file? */ + unsigned int flags; /* FILE_RENAME_* flags */ VARARG(name,unicode_str,namelen); /* NT name */ VARARG(filename,string); /* new file name */ @END diff --git a/server/request.h b/server/request.h index fe148f84f35..41d38e4347f 100644 --- a/server/request.h +++ b/server/request.h @@ -2241,7 +2241,7 @@ C_ASSERT( FIELD_OFFSET(struct set_fd_name_info_request, handle) == 12 ); C_ASSERT( FIELD_OFFSET(struct set_fd_name_info_request, rootdir) == 16 ); C_ASSERT( FIELD_OFFSET(struct set_fd_name_info_request, namelen) == 20 ); C_ASSERT( FIELD_OFFSET(struct set_fd_name_info_request, link) == 24 ); -C_ASSERT( FIELD_OFFSET(struct set_fd_name_info_request, replace) == 28 ); +C_ASSERT( FIELD_OFFSET(struct set_fd_name_info_request, flags) == 28 ); C_ASSERT( sizeof(struct set_fd_name_info_request) == 32 ); C_ASSERT( FIELD_OFFSET(struct set_fd_eof_info_request, handle) == 12 ); C_ASSERT( FIELD_OFFSET(struct set_fd_eof_info_request, eof) == 16 ); diff --git a/server/trace.c b/server/trace.c index f9cb2207b79..b968b74034d 100644 --- a/server/trace.c +++ b/server/trace.c @@ -4411,7 +4411,7 @@ static void dump_set_fd_name_info_request( const struct set_fd_name_info_request fprintf( stderr, ", rootdir=%04x", req->rootdir ); fprintf( stderr, ", namelen=%u", req->namelen ); fprintf( stderr, ", link=%d", req->link ); - fprintf( stderr, ", replace=%d", req->replace ); + fprintf( stderr, ", flags=%08x", req->flags ); dump_varargs_unicode_str( ", name=", min(cur_size,req->namelen) ); dump_varargs_string( ", filename=", cur_size ); } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/3907
From: Joel Holdsworth <joel(a)airwebreathe.org.uk> Signed-off-by: Joel Holdsworth <joel(a)airwebreathe.org.uk> --- dlls/ntdll/tests/file.c | 41 +---------------------------------------- dlls/ntdll/unix/file.c | 12 +++++++++++- 2 files changed, 12 insertions(+), 41 deletions(-) diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c index da4f817b1da..cf04ccc1264 100644 --- a/dlls/ntdll/tests/file.c +++ b/dlls/ntdll/tests/file.c @@ -2216,21 +2216,18 @@ static void test_file_link_information(FILE_INFORMATION_CLASS class) if (class == FileLinkInformationEx && (res == STATUS_NOT_IMPLEMENTED || res == STATUS_INVALID_INFO_CLASS)) { - todo_wine win_skip( "FileLinkInformationEx not supported\n" ); + win_skip( "FileLinkInformationEx not supported\n" ); CloseHandle( handle ); HeapFree( GetProcessHeap(), 0, fli ); delete_object( oldpath ); return; } - todo_wine_if( class == FileLinkInformationEx ) ok( io.Status == STATUS_SUCCESS, "io.Status expected STATUS_SUCCESS, got %lx\n", io.Status ); - todo_wine_if( class == FileLinkInformationEx ) ok( res == STATUS_SUCCESS, "res expected STATUS_SUCCESS, got %lx\n", res ); fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; ok( !fileDeleted, "file should exist\n" ); fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; - todo_wine_if( class == FileLinkInformationEx ) ok( !fileDeleted, "file should exist\n" ); fni = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_NAME_INFORMATION) + MAX_PATH * sizeof(WCHAR) ); @@ -2265,7 +2262,6 @@ static void test_file_link_information(FILE_INFORMATION_CLASS class) io.Status = 0xdeadbeef; res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, class ); todo_wine ok( io.Status == 0xdeadbeef, "io.Status expected 0xdeadbeef, got %lx\n", io.Status ); - todo_wine_if( class == FileLinkInformationEx ) ok( res == STATUS_OBJECT_NAME_COLLISION, "res expected STATUS_OBJECT_NAME_COLLISION, got %lx\n", res ); fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; ok( !fileDeleted, "file should exist\n" ); @@ -2295,9 +2291,7 @@ static void test_file_link_information(FILE_INFORMATION_CLASS class) io.Status = 0xdeadbeef; res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, class ); - todo_wine_if( class == FileLinkInformationEx ) ok( io.Status == STATUS_SUCCESS, "io.Status expected STATUS_SUCCESS, got %lx\n", io.Status ); - todo_wine_if( class == FileLinkInformationEx ) ok( res == STATUS_SUCCESS, "res expected STATUS_SUCCESS, got %lx\n", res ); fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; ok( !fileDeleted, "file should exist\n" ); @@ -2328,9 +2322,7 @@ static void test_file_link_information(FILE_INFORMATION_CLASS class) io.Status = 0xdeadbeef; res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, class ); - todo_wine_if( class == FileLinkInformationEx ) ok( io.Status == STATUS_SUCCESS, "io.Status expected STATUS_SUCCESS, got %lx\n", io.Status ); - todo_wine_if( class == FileLinkInformationEx ) ok( res == STATUS_SUCCESS, "res expected STATUS_SUCCESS, got %lx\n", res ); fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; ok( !fileDeleted, "file should exist\n" ); @@ -2373,7 +2365,6 @@ static void test_file_link_information(FILE_INFORMATION_CLASS class) io.Status = 0xdeadbeef; res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, class ); todo_wine ok( io.Status == 0xdeadbeef, "io.Status expected 0xdeadbeef, got %lx\n", io.Status ); - todo_wine_if( class == FileLinkInformationEx ) ok( res == STATUS_OBJECT_NAME_COLLISION, "res expected STATUS_OBJECT_NAME_COLLISION, got %lx\n", res ); fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; ok( !fileDeleted, "file should exist\n" ); @@ -2408,7 +2399,6 @@ static void test_file_link_information(FILE_INFORMATION_CLASS class) io.Status = 0xdeadbeef; res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, class ); todo_wine ok( io.Status == 0xdeadbeef, "io.Status expected 0xdeadbeef, got %lx\n", io.Status ); - todo_wine_if( class == FileLinkInformationEx ) ok( res == STATUS_ACCESS_DENIED, "res expected STATUS_ACCESS_DENIED, got %lx\n", res ); fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; ok( !fileDeleted, "file should exist\n" ); @@ -2443,10 +2433,8 @@ static void test_file_link_information(FILE_INFORMATION_CLASS class) io.Status = 0xdeadbeef; res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, class ); - todo_wine_if( class == FileLinkInformationEx ) ok( io.Status == 0xdeadbeef || io.Status == STATUS_FILE_IS_A_DIRECTORY , "io.Status expected 0xdeadbeef or STATUS_FILE_IS_A_DIRECTORY, got %lx\n", io.Status ); - todo_wine_if( class == FileLinkInformationEx ) ok( res == STATUS_FILE_IS_A_DIRECTORY, "res expected STATUS_FILE_IS_A_DIRECTORY, got %lx\n", res ); fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; ok( !fileDeleted, "file should exist\n" ); @@ -2493,10 +2481,8 @@ static void test_file_link_information(FILE_INFORMATION_CLASS class) io.Status = 0xdeadbeef; res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, class ); - todo_wine_if( class == FileLinkInformationEx ) ok( io.Status == 0xdeadbeef || io.Status == STATUS_FILE_IS_A_DIRECTORY, "io.Status expected 0xdeadbeef or STATUS_FILE_IS_A_DIRECTORY, got %lx\n", io.Status ); - todo_wine_if( class == FileLinkInformationEx ) ok( res == STATUS_FILE_IS_A_DIRECTORY, "res expected STATUS_FILE_IS_A_DIRECTORY, got %lx\n", res ); fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; ok( !fileDeleted, "file should exist\n" ); @@ -2530,10 +2516,8 @@ static void test_file_link_information(FILE_INFORMATION_CLASS class) io.Status = 0xdeadbeef; res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, class ); - todo_wine_if( class == FileLinkInformationEx ) ok( io.Status == 0xdeadbeef || io.Status == STATUS_FILE_IS_A_DIRECTORY, "io.Status expected 0xdeadbeef or STATUS_FILE_IS_A_DIRECTORY, got %lx\n", io.Status ); - todo_wine_if( class == FileLinkInformationEx ) ok( res == STATUS_OBJECT_NAME_COLLISION || res == STATUS_FILE_IS_A_DIRECTORY /* > Win XP */, "res expected STATUS_OBJECT_NAME_COLLISION or STATUS_FILE_IS_A_DIRECTORY, got %lx\n", res ); fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; @@ -2570,10 +2554,8 @@ static void test_file_link_information(FILE_INFORMATION_CLASS class) io.Status = 0xdeadbeef; res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, class ); - todo_wine_if( class == FileLinkInformationEx ) ok( io.Status == 0xdeadbeef || io.Status == STATUS_FILE_IS_A_DIRECTORY, "io.Status expected 0xdeadbeef or STATUS_FILE_IS_A_DIRECTORY, got %lx\n", io.Status ); - todo_wine_if( class == FileLinkInformationEx ) ok( res == STATUS_OBJECT_NAME_COLLISION || res == STATUS_FILE_IS_A_DIRECTORY /* > Win XP */, "res expected STATUS_OBJECT_NAME_COLLISION or STATUS_FILE_IS_A_DIRECTORY, got %lx\n", res ); fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; @@ -2608,10 +2590,8 @@ static void test_file_link_information(FILE_INFORMATION_CLASS class) io.Status = 0xdeadbeef; res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, class ); - todo_wine_if( class == FileLinkInformationEx ) ok( io.Status == 0xdeadbeef || io.Status == STATUS_FILE_IS_A_DIRECTORY, "io.Status expected 0xdeadbeef or STATUS_FILE_IS_A_DIRECTORY, got %lx\n", io.Status ); - todo_wine_if( class == FileLinkInformationEx ) ok( res == STATUS_FILE_IS_A_DIRECTORY, "res expected STATUS_FILE_IS_A_DIRECTORY, got %lx\n", res ); fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; ok( !fileDeleted, "file should exist\n" ); @@ -2647,10 +2627,8 @@ static void test_file_link_information(FILE_INFORMATION_CLASS class) io.Status = 0xdeadbeef; res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, class ); - todo_wine_if( class == FileLinkInformationEx ) ok( io.Status == 0xdeadbeef || io.Status == STATUS_FILE_IS_A_DIRECTORY, "io.Status expected 0xdeadbeef or STATUS_FILE_IS_A_DIRECTORY, got %lx\n", io.Status ); - todo_wine_if( class == FileLinkInformationEx ) ok( res == STATUS_FILE_IS_A_DIRECTORY, "res expected STATUS_FILE_IS_A_DIRECTORY, got %lx\n", res ); fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; ok( !fileDeleted, "file should exist\n" ); @@ -2687,10 +2665,8 @@ static void test_file_link_information(FILE_INFORMATION_CLASS class) io.Status = 0xdeadbeef; res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, class ); - todo_wine_if( class == FileLinkInformationEx ) ok( io.Status == 0xdeadbeef || io.Status == STATUS_FILE_IS_A_DIRECTORY, "io.Status expected 0xdeadbeef or STATUS_FILE_IS_A_DIRECTORY, got %lx\n", io.Status ); - todo_wine_if( class == FileLinkInformationEx ) ok( res == STATUS_OBJECT_NAME_COLLISION || res == STATUS_FILE_IS_A_DIRECTORY /* > Win XP */, "res expected STATUS_OBJECT_NAME_COLLISION or STATUS_FILE_IS_A_DIRECTORY, got %lx\n", res ); fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; @@ -2727,10 +2703,8 @@ static void test_file_link_information(FILE_INFORMATION_CLASS class) io.Status = 0xdeadbeef; res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, class ); - todo_wine_if( class == FileLinkInformationEx ) ok( io.Status == 0xdeadbeef || io.Status == STATUS_FILE_IS_A_DIRECTORY, "io.Status expected 0xdeadbeef or STATUS_FILE_IS_A_DIRECTORY, got %lx\n", io.Status ); - todo_wine_if( class == FileLinkInformationEx ) ok( res == STATUS_FILE_IS_A_DIRECTORY, "res expected STATUS_FILE_IS_A_DIRECTORY, got %lx\n", res ); fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; ok( !fileDeleted, "file should exist\n" ); @@ -2769,10 +2743,8 @@ static void test_file_link_information(FILE_INFORMATION_CLASS class) io.Status = 0xdeadbeef; res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, class ); - todo_wine_if( class == FileLinkInformationEx ) ok( io.Status == 0xdeadbeef || io.Status == STATUS_FILE_IS_A_DIRECTORY, "io.Status expected 0xdeadbeef or STATUS_FILE_IS_A_DIRECTORY, got %lx\n", io.Status ); - todo_wine_if( class == FileLinkInformationEx ) ok( res == STATUS_FILE_IS_A_DIRECTORY, "res expected STATUS_FILE_IS_A_DIRECTORY, got %lx\n", res ); fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; ok( !fileDeleted, "file should exist\n" ); @@ -2807,7 +2779,6 @@ static void test_file_link_information(FILE_INFORMATION_CLASS class) io.Status = 0xdeadbeef; res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, class ); todo_wine ok( io.Status == 0xdeadbeef, "io.Status expected 0xdeadbeef, got %lx\n", io.Status ); - todo_wine_if( class == FileLinkInformationEx ) ok( res == STATUS_OBJECT_NAME_COLLISION, "res expected STATUS_OBJECT_NAME_COLLISION, got %lx\n", res ); fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; ok( !fileDeleted, "file should exist\n" ); @@ -2841,7 +2812,6 @@ static void test_file_link_information(FILE_INFORMATION_CLASS class) io.Status = 0xdeadbeef; res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, class ); todo_wine ok( io.Status == 0xdeadbeef, "io.Status expected 0xdeadbeef, got %lx\n", io.Status ); - todo_wine_if( class == FileLinkInformationEx ) ok( res == STATUS_ACCESS_DENIED, "res expected STATUS_ACCESS_DENIED, got %lx\n", res ); fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; ok( !fileDeleted, "file should exist\n" ); @@ -2875,14 +2845,11 @@ static void test_file_link_information(FILE_INFORMATION_CLASS class) io.Status = 0xdeadbeef; res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, class ); - todo_wine_if( class == FileLinkInformationEx ) ok( io.Status == STATUS_SUCCESS, "io.Status expected STATUS_SUCCESS, got %lx\n", io.Status ); - todo_wine_if( class == FileLinkInformationEx ) ok( res == STATUS_SUCCESS, "res expected STATUS_SUCCESS, got %lx\n", res ); fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; ok( !fileDeleted, "file should exist\n" ); fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; - todo_wine_if( class == FileLinkInformationEx ) ok( !fileDeleted, "file should exist\n" ); fni = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_NAME_INFORMATION) + MAX_PATH * sizeof(WCHAR) ); @@ -2916,15 +2883,12 @@ static void test_file_link_information(FILE_INFORMATION_CLASS class) io.Status = 0xdeadbeef; res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, class ); todo_wine ok( io.Status == 0xdeadbeef, "got io status %#lx\n", io.Status ); - todo_wine_if( class == FileLinkInformationEx ) ok( res == STATUS_OBJECT_NAME_COLLISION, "got status %lx\n", res ); fli->Flags = FILE_LINK_REPLACE_IF_EXISTS; io.Status = 0xdeadbeef; res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, class ); - todo_wine_if( class == FileLinkInformationEx ) ok( io.Status == STATUS_SUCCESS, "got io status %#lx\n", io.Status ); - todo_wine_if( class == FileLinkInformationEx ) ok( res == STATUS_SUCCESS, "got status %lx\n", res ); ok( GetFileAttributesW( oldpath ) != INVALID_FILE_ATTRIBUTES, "file should exist\n" ); @@ -2950,15 +2914,12 @@ static void test_file_link_information(FILE_INFORMATION_CLASS class) io.Status = 0xdeadbeef; res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, class ); todo_wine ok( io.Status == 0xdeadbeef, "got io status %#lx\n", io.Status ); - todo_wine_if( class == FileLinkInformationEx ) ok( res == STATUS_OBJECT_NAME_COLLISION, "got status %lx\n", res ); fli->Flags = FILE_LINK_REPLACE_IF_EXISTS; io.Status = 0xdeadbeef; res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, class ); - todo_wine_if( class == FileLinkInformationEx ) ok( io.Status == STATUS_SUCCESS, "got io status %#lx\n", io.Status ); - todo_wine_if( class == FileLinkInformationEx ) ok( res == STATUS_SUCCESS, "got status %lx\n", res ); ok( GetFileAttributesW( oldpath ) != INVALID_FILE_ATTRIBUTES, "file should exist\n" ); diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c index 38ba1f0e883..90a689c1759 100644 --- a/dlls/ntdll/unix/file.c +++ b/dlls/ntdll/unix/file.c @@ -4830,13 +4830,23 @@ NTSTATUS WINAPI NtSetInformationFile( HANDLE handle, IO_STATUS_BLOCK *io, break; case FileLinkInformation: + case FileLinkInformationEx: if (len >= sizeof(FILE_LINK_INFORMATION)) { FILE_LINK_INFORMATION *info = ptr; + ULONG flags; UNICODE_STRING name_str, redir; OBJECT_ATTRIBUTES attr; char *unix_name; + if (class == FileLinkInformation) + flags = info->ReplaceIfExists ? FILE_LINK_REPLACE_IF_EXISTS : 0; + else + flags = info->Flags; + + if (flags & ~FILE_LINK_REPLACE_IF_EXISTS) + FIXME( "unsupported flags: %#x\n", (unsigned int)flags ); + name_str.Buffer = info->FileName; name_str.Length = info->FileNameLength; name_str.MaximumLength = info->FileNameLength + sizeof(WCHAR); @@ -4852,7 +4862,7 @@ NTSTATUS WINAPI NtSetInformationFile( HANDLE handle, IO_STATUS_BLOCK *io, req->rootdir = wine_server_obj_handle( attr.RootDirectory ); req->namelen = attr.ObjectName->Length; req->link = TRUE; - req->flags = info->ReplaceIfExists ? FILE_LINK_REPLACE_IF_EXISTS : 0; + req->flags = flags; wine_server_add_data( req, attr.ObjectName->Buffer, attr.ObjectName->Length ); wine_server_add_data( req, unix_name, strlen(unix_name) ); status = wine_server_call( req ); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/3907
From: Joel Holdsworth <joel(a)airwebreathe.org.uk> This change has the benefit that a file or directory can be deleted using a single combined operation. It can also be later adapted to include FILE_DISPOSITION_IGNORE_READONLY_ATTRIBUTE for deletion of read-only test files. Signed-off-by: Joel Holdsworth <joel(a)airwebreathe.org.uk> --- dlls/ntdll/tests/file.c | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c index cf04ccc1264..a1841c5936c 100644 --- a/dlls/ntdll/tests/file.c +++ b/dlls/ntdll/tests/file.c @@ -1502,13 +1502,27 @@ static void test_file_all_information(void) static void delete_object( WCHAR *path ) { - BOOL ret = DeleteFileW( path ); - ok( ret || GetLastError() == ERROR_FILE_NOT_FOUND || GetLastError() == ERROR_ACCESS_DENIED, - "DeleteFileW failed with %lu\n", GetLastError() ); - if (!ret && GetLastError() == ERROR_ACCESS_DENIED) - { - ret = RemoveDirectoryW( path ); - ok( ret, "RemoveDirectoryW failed with %lu\n", GetLastError() ); + UNICODE_STRING str; + OBJECT_ATTRIBUTES attr; + HANDLE handle; + FILE_DISPOSITION_INFORMATION_EX fdie; + IO_STATUS_BLOCK io; + NTSTATUS status; + + pRtlDosPathNameToNtPathName_U( path, &str, NULL, NULL ); + InitializeObjectAttributes( &attr, &str, 0, 0, NULL ); + io.Status = 0xdeadbeef; + status = pNtCreateFile( &handle, DELETE, &attr, &io, NULL, 0, 0, FILE_OPEN, 0, NULL, 0 ); + pRtlFreeUnicodeString( &str ); + ok(status == STATUS_SUCCESS || status == STATUS_OBJECT_NAME_NOT_FOUND, + "expected STATUS_SUCESS or STATUS_OBJECT_NAME_NOT_FOUND, got: %lx\n", io.Status); + if (status == STATUS_SUCCESS) { + fdie.Flags = FILE_DISPOSITION_DELETE; + io.Status = 0xdeadbeef; + status = pNtSetInformationFile( handle, &io, &fdie, sizeof fdie, FileDispositionInformationEx ); + ok ( status == STATUS_SUCCESS, "can't set file disposition, status: %lx\n", status ); + ok ( io.Status == STATUS_SUCCESS, "can't set file disposition, io.Status: %lx\n", io.Status ); + CloseHandle( handle ); } } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/3907
From: Joel Holdsworth <joel(a)airwebreathe.org.uk> Signed-off-by: Joel Holdsworth <joel(a)airwebreathe.org.uk> --- dlls/ntdll/tests/file.c | 85 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 84 insertions(+), 1 deletion(-) diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c index a1841c5936c..e19d8bd29b5 100644 --- a/dlls/ntdll/tests/file.c +++ b/dlls/ntdll/tests/file.c @@ -1517,7 +1517,7 @@ static void delete_object( WCHAR *path ) ok(status == STATUS_SUCCESS || status == STATUS_OBJECT_NAME_NOT_FOUND, "expected STATUS_SUCESS or STATUS_OBJECT_NAME_NOT_FOUND, got: %lx\n", io.Status); if (status == STATUS_SUCCESS) { - fdie.Flags = FILE_DISPOSITION_DELETE; + fdie.Flags = FILE_DISPOSITION_DELETE | FILE_DISPOSITION_IGNORE_READONLY_ATTRIBUTE; io.Status = 0xdeadbeef; status = pNtSetInformationFile( handle, &io, &fdie, sizeof fdie, FileDispositionInformationEx ); ok ( status == STATUS_SUCCESS, "can't set file disposition, status: %lx\n", status ); @@ -2192,6 +2192,88 @@ static void test_file_rename_information(FILE_INFORMATION_CLASS class) delete_object( oldpath ); } +static void test_file_rename_information_ex(void) +{ + static const WCHAR fooW[] = {'f','o','o',0}; + WCHAR tmp_path[MAX_PATH], oldpath[MAX_PATH + 16], newpath[MAX_PATH + 16]; + FILE_RENAME_INFORMATION *fri; + BOOL fileDeleted; + UNICODE_STRING name_str; + HANDLE handle, handle2; + IO_STATUS_BLOCK io; + NTSTATUS res; + + GetTempPathW( MAX_PATH, tmp_path ); + + /* oldpath is a file, newpath is a read-only file, with FILE_RENAME_REPLACE_IF_EXISTS */ + res = GetTempFileNameW( tmp_path, fooW, 0, oldpath ); + ok( res != 0, "failed to create temp file\n" ); + handle = CreateFileW( oldpath, GENERIC_WRITE | DELETE, 0, NULL, CREATE_ALWAYS, 0, 0 ); + ok( handle != INVALID_HANDLE_VALUE, "CreateFileW failed\n" ); + + res = GetTempFileNameW( tmp_path, fooW, 0, newpath ); + ok( res != 0, "failed to create temp file\n" ); + DeleteFileW( newpath ); + handle2 = CreateFileW( newpath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_READONLY, 0 ); + ok( handle2 != INVALID_HANDLE_VALUE, "CreateFileW failed\n" ); + CloseHandle( handle2 ); + pRtlDosPathNameToNtPathName_U( newpath, &name_str, NULL, NULL ); + fri = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_RENAME_INFORMATION) + name_str.Length ); + fri->Flags = FILE_RENAME_REPLACE_IF_EXISTS; + fri->RootDirectory = NULL; + fri->FileNameLength = name_str.Length; + memcpy( fri->FileName, name_str.Buffer, name_str.Length ); + pRtlFreeUnicodeString( &name_str ); + + io.Status = 0xdeadbeef; + res = pNtSetInformationFile( handle, &io, fri, sizeof(FILE_RENAME_INFORMATION) + fri->FileNameLength, FileRenameInformationEx ); + todo_wine ok( io.Status == 0xdeadbeef, "io.Status expected 0xdeadbeef, got %lx\n", io.Status ); + todo_wine ok( res == STATUS_ACCESS_DENIED, "res expected STATUS_ACCESS_DENIED, got %lx\n", res ); + fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; + todo_wine ok( !fileDeleted, "file should exist\n" ); + fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; + ok( !fileDeleted, "file should exist\n" ); + + CloseHandle( handle ); + HeapFree( GetProcessHeap(), 0, fri ); + delete_object( oldpath ); + delete_object( newpath ); + + /* oldpath is a file, newpath is a read-only file, with FILE_RENAME_REPLACE_IF_EXISTS and FILE_RENAME_IGNORE_READONLY_ATTRIBUTE */ + res = GetTempFileNameW( tmp_path, fooW, 0, oldpath ); + ok( res != 0, "failed to create temp file\n" ); + handle = CreateFileW( oldpath, GENERIC_WRITE | DELETE, 0, NULL, CREATE_ALWAYS, 0, 0 ); + ok( handle != INVALID_HANDLE_VALUE, "CreateFileW failed\n" ); + + res = GetTempFileNameW( tmp_path, fooW, 0, newpath ); + ok( res != 0, "failed to create temp file\n" ); + DeleteFileW( newpath ); + handle2 = CreateFileW( newpath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_READONLY, 0 ); + ok( handle2 != INVALID_HANDLE_VALUE, "CreateFileW failed\n" ); + CloseHandle( handle2 ); + pRtlDosPathNameToNtPathName_U( newpath, &name_str, NULL, NULL ); + fri = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_RENAME_INFORMATION) + name_str.Length ); + fri->Flags = FILE_RENAME_REPLACE_IF_EXISTS | FILE_RENAME_IGNORE_READONLY_ATTRIBUTE; + fri->RootDirectory = NULL; + fri->FileNameLength = name_str.Length; + memcpy( fri->FileName, name_str.Buffer, name_str.Length ); + pRtlFreeUnicodeString( &name_str ); + + io.Status = 0xdeadbeef; + res = pNtSetInformationFile( handle, &io, fri, sizeof(FILE_RENAME_INFORMATION) + fri->FileNameLength, FileRenameInformationEx ); + ok( io.Status == STATUS_SUCCESS, "io.Status expected STATUS_SUCCESS, got %lx\n", io.Status ); + ok( res == STATUS_SUCCESS, "res expected STATUS_SUCCESS, got %lx\n", res ); + fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; + ok( fileDeleted, "file should not exist\n" ); + fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; + ok( !fileDeleted, "file should exist\n" ); + + CloseHandle( handle ); + HeapFree( GetProcessHeap(), 0, fri ); + delete_object( oldpath ); + delete_object( newpath ); +} + static void test_file_link_information(FILE_INFORMATION_CLASS class) { static const WCHAR foo_txtW[] = {'\\','f','o','o','.','t','x','t',0}; @@ -5713,6 +5795,7 @@ START_TEST(file) test_file_all_name_information(); test_file_rename_information(FileRenameInformation); test_file_rename_information(FileRenameInformationEx); + test_file_rename_information_ex(); test_file_link_information(FileLinkInformation); test_file_link_information(FileLinkInformationEx); test_file_disposition_information(); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/3907
From: Joel Holdsworth <joel(a)airwebreathe.org.uk> Signed-off-by: Joel Holdsworth <joel(a)airwebreathe.org.uk> --- dlls/ntdll/tests/file.c | 83 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c index e19d8bd29b5..6990ef39b42 100644 --- a/dlls/ntdll/tests/file.c +++ b/dlls/ntdll/tests/file.c @@ -3033,6 +3033,88 @@ static void test_file_link_information(FILE_INFORMATION_CLASS class) delete_object( oldpath ); } +static void test_file_link_information_ex(void) +{ + static const WCHAR fooW[] = {'f','o','o',0}; + WCHAR tmp_path[MAX_PATH], oldpath[MAX_PATH + 16], newpath[MAX_PATH + 16]; + FILE_LINK_INFORMATION *fli; + BOOL fileDeleted; + UNICODE_STRING name_str; + HANDLE handle, handle2; + IO_STATUS_BLOCK io; + NTSTATUS res; + + GetTempPathW( MAX_PATH, tmp_path ); + + /* oldpath is a file, newpath is a read-only file, with FILE_LINK_REPLACE_IF_EXISTS */ + res = GetTempFileNameW( tmp_path, fooW, 0, oldpath ); + ok( res != 0, "failed to create temp file\n" ); + handle = CreateFileW( oldpath, GENERIC_WRITE | DELETE, 0, NULL, CREATE_ALWAYS, 0, 0 ); + ok( handle != INVALID_HANDLE_VALUE, "CreateFileW failed\n" ); + + res = GetTempFileNameW( tmp_path, fooW, 0, newpath ); + ok( res != 0, "failed to create temp file\n" ); + DeleteFileW( newpath ); + handle2 = CreateFileW( newpath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_READONLY, 0 ); + ok( handle2 != INVALID_HANDLE_VALUE, "CreateFileW failed\n" ); + CloseHandle( handle2 ); + pRtlDosPathNameToNtPathName_U( newpath, &name_str, NULL, NULL ); + fli = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_LINK_INFORMATION) + name_str.Length ); + fli->Flags = FILE_LINK_REPLACE_IF_EXISTS; + fli->RootDirectory = NULL; + fli->FileNameLength = name_str.Length; + memcpy( fli->FileName, name_str.Buffer, name_str.Length ); + pRtlFreeUnicodeString( &name_str ); + + io.Status = 0xdeadbeef; + res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, FileLinkInformationEx ); + todo_wine ok( io.Status == 0xdeadbeef, "io.Status expected 0xdeadbeef, got %lx\n", io.Status ); + todo_wine ok( res == STATUS_ACCESS_DENIED, "res expected STATUS_ACCESS_DENIED, got %lx\n", res ); + fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; + ok( !fileDeleted, "file should exist\n" ); + fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; + ok( !fileDeleted, "file should exist\n" ); + + CloseHandle( handle ); + HeapFree( GetProcessHeap(), 0, fli ); + delete_object( oldpath ); + delete_object( newpath ); + + /* oldpath is a file, newpath is a read-only file, with FILE_LINK_REPLACE_IF_EXISTS and FILE_LINK_IGNORE_READONLY_ATTRIBUTE */ + res = GetTempFileNameW( tmp_path, fooW, 0, oldpath ); + ok( res != 0, "failed to create temp file\n" ); + handle = CreateFileW( oldpath, GENERIC_WRITE | DELETE, 0, NULL, CREATE_ALWAYS, 0, 0 ); + ok( handle != INVALID_HANDLE_VALUE, "CreateFileW failed\n" ); + + res = GetTempFileNameW( tmp_path, fooW, 0, newpath ); + ok( res != 0, "failed to create temp file\n" ); + DeleteFileW( newpath ); + handle2 = CreateFileW( newpath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_READONLY, 0 ); + ok( handle2 != INVALID_HANDLE_VALUE, "CreateFileW failed\n" ); + CloseHandle( handle2 ); + pRtlDosPathNameToNtPathName_U( newpath, &name_str, NULL, NULL ); + fli = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_LINK_INFORMATION) + name_str.Length ); + fli->Flags = FILE_LINK_REPLACE_IF_EXISTS | FILE_LINK_IGNORE_READONLY_ATTRIBUTE; + fli->RootDirectory = NULL; + fli->FileNameLength = name_str.Length; + memcpy( fli->FileName, name_str.Buffer, name_str.Length ); + pRtlFreeUnicodeString( &name_str ); + + io.Status = 0xdeadbeef; + res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, FileLinkInformationEx ); + ok( io.Status == STATUS_SUCCESS, "io.Status expected STATUS_SUCCESS, got %lx\n", io.Status ); + ok( res == STATUS_SUCCESS, "res expected STATUS_SUCCESS, got %lx\n", res ); + fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; + ok( !fileDeleted, "file should exist\n" ); + fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; + ok( !fileDeleted, "file should exist\n" ); + + CloseHandle( handle ); + HeapFree( GetProcessHeap(), 0, fli ); + delete_object( oldpath ); + delete_object( newpath ); +} + static void test_file_both_information(void) { IO_STATUS_BLOCK io; @@ -5798,6 +5880,7 @@ START_TEST(file) test_file_rename_information_ex(); test_file_link_information(FileLinkInformation); test_file_link_information(FileLinkInformationEx); + test_file_link_information_ex(); test_file_disposition_information(); test_file_completion_information(); test_file_id_information(); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/3907
From: Joel Holdsworth <joel(a)airwebreathe.org.uk> Signed-off-by: Joel Holdsworth <joel(a)airwebreathe.org.uk> --- dlls/ntdll/tests/file.c | 16 ++++++++-------- server/fd.c | 7 +++++++ 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c index 6990ef39b42..45ee937ca02 100644 --- a/dlls/ntdll/tests/file.c +++ b/dlls/ntdll/tests/file.c @@ -2228,9 +2228,9 @@ static void test_file_rename_information_ex(void) io.Status = 0xdeadbeef; res = pNtSetInformationFile( handle, &io, fri, sizeof(FILE_RENAME_INFORMATION) + fri->FileNameLength, FileRenameInformationEx ); todo_wine ok( io.Status == 0xdeadbeef, "io.Status expected 0xdeadbeef, got %lx\n", io.Status ); - todo_wine ok( res == STATUS_ACCESS_DENIED, "res expected STATUS_ACCESS_DENIED, got %lx\n", res ); + ok( res == STATUS_ACCESS_DENIED, "res expected STATUS_ACCESS_DENIED, got %lx\n", res ); fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; - todo_wine ok( !fileDeleted, "file should exist\n" ); + ok( !fileDeleted, "file should exist\n" ); fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; ok( !fileDeleted, "file should exist\n" ); @@ -2261,10 +2261,10 @@ static void test_file_rename_information_ex(void) io.Status = 0xdeadbeef; res = pNtSetInformationFile( handle, &io, fri, sizeof(FILE_RENAME_INFORMATION) + fri->FileNameLength, FileRenameInformationEx ); - ok( io.Status == STATUS_SUCCESS, "io.Status expected STATUS_SUCCESS, got %lx\n", io.Status ); - ok( res == STATUS_SUCCESS, "res expected STATUS_SUCCESS, got %lx\n", res ); + todo_wine ok( io.Status == STATUS_SUCCESS, "io.Status expected STATUS_SUCCESS, got %lx\n", io.Status ); + todo_wine ok( res == STATUS_SUCCESS, "res expected STATUS_SUCCESS, got %lx\n", res ); fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; - ok( fileDeleted, "file should not exist\n" ); + todo_wine ok( fileDeleted, "file should not exist\n" ); fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; ok( !fileDeleted, "file should exist\n" ); @@ -3068,7 +3068,7 @@ static void test_file_link_information_ex(void) io.Status = 0xdeadbeef; res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, FileLinkInformationEx ); - todo_wine ok( io.Status == 0xdeadbeef, "io.Status expected 0xdeadbeef, got %lx\n", io.Status ); + ok( io.Status == 0xdeadbeef, "io.Status expected 0xdeadbeef, got %lx\n", io.Status ); todo_wine ok( res == STATUS_ACCESS_DENIED, "res expected STATUS_ACCESS_DENIED, got %lx\n", res ); fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; ok( !fileDeleted, "file should exist\n" ); @@ -3102,8 +3102,8 @@ static void test_file_link_information_ex(void) io.Status = 0xdeadbeef; res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, FileLinkInformationEx ); - ok( io.Status == STATUS_SUCCESS, "io.Status expected STATUS_SUCCESS, got %lx\n", io.Status ); - ok( res == STATUS_SUCCESS, "res expected STATUS_SUCCESS, got %lx\n", res ); + todo_wine ok( io.Status == STATUS_SUCCESS, "io.Status expected STATUS_SUCCESS, got %lx\n", io.Status ); + todo_wine ok( res == STATUS_SUCCESS, "res expected STATUS_SUCCESS, got %lx\n", res ); fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; ok( !fileDeleted, "file should exist\n" ); fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; diff --git a/server/fd.c b/server/fd.c index 5947dee3ae1..3426a39682a 100644 --- a/server/fd.c +++ b/server/fd.c @@ -2579,6 +2579,13 @@ static void set_fd_name( struct fd *fd, struct fd *root, const char *nameptr, da goto failed; } + /* read-only files cannot be replaced */ + if (!(st.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH))) + { + set_error( STATUS_ACCESS_DENIED ); + goto failed; + } + /* can't replace an opened file */ if ((inode = get_inode( st.st_dev, st.st_ino, -1 ))) { -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/3907
From: Joel Holdsworth <joel(a)airwebreathe.org.uk> Signed-off-by: Joel Holdsworth <joel(a)airwebreathe.org.uk> --- dlls/ntdll/tests/file.c | 14 +++++++------- dlls/ntdll/unix/file.c | 4 ++-- server/fd.c | 3 ++- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c index 45ee937ca02..7ff05dbb937 100644 --- a/dlls/ntdll/tests/file.c +++ b/dlls/ntdll/tests/file.c @@ -2261,10 +2261,10 @@ static void test_file_rename_information_ex(void) io.Status = 0xdeadbeef; res = pNtSetInformationFile( handle, &io, fri, sizeof(FILE_RENAME_INFORMATION) + fri->FileNameLength, FileRenameInformationEx ); - todo_wine ok( io.Status == STATUS_SUCCESS, "io.Status expected STATUS_SUCCESS, got %lx\n", io.Status ); - todo_wine ok( res == STATUS_SUCCESS, "res expected STATUS_SUCCESS, got %lx\n", res ); + ok( io.Status == STATUS_SUCCESS, "io.Status expected STATUS_SUCCESS, got %lx\n", io.Status ); + ok( res == STATUS_SUCCESS, "res expected STATUS_SUCCESS, got %lx\n", res ); fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; - todo_wine ok( fileDeleted, "file should not exist\n" ); + ok( fileDeleted, "file should not exist\n" ); fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; ok( !fileDeleted, "file should exist\n" ); @@ -3068,8 +3068,8 @@ static void test_file_link_information_ex(void) io.Status = 0xdeadbeef; res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, FileLinkInformationEx ); - ok( io.Status == 0xdeadbeef, "io.Status expected 0xdeadbeef, got %lx\n", io.Status ); - todo_wine ok( res == STATUS_ACCESS_DENIED, "res expected STATUS_ACCESS_DENIED, got %lx\n", res ); + todo_wine ok( io.Status == 0xdeadbeef, "io.Status expected 0xdeadbeef, got %lx\n", io.Status ); + ok( res == STATUS_ACCESS_DENIED, "res expected STATUS_ACCESS_DENIED, got %lx\n", res ); fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; ok( !fileDeleted, "file should exist\n" ); fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; @@ -3102,8 +3102,8 @@ static void test_file_link_information_ex(void) io.Status = 0xdeadbeef; res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, FileLinkInformationEx ); - todo_wine ok( io.Status == STATUS_SUCCESS, "io.Status expected STATUS_SUCCESS, got %lx\n", io.Status ); - todo_wine ok( res == STATUS_SUCCESS, "res expected STATUS_SUCCESS, got %lx\n", res ); + ok( io.Status == STATUS_SUCCESS, "io.Status expected STATUS_SUCCESS, got %lx\n", io.Status ); + ok( res == STATUS_SUCCESS, "res expected STATUS_SUCCESS, got %lx\n", res ); fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; ok( !fileDeleted, "file should exist\n" ); fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c index 90a689c1759..db91f9930ed 100644 --- a/dlls/ntdll/unix/file.c +++ b/dlls/ntdll/unix/file.c @@ -4797,7 +4797,7 @@ NTSTATUS WINAPI NtSetInformationFile( HANDLE handle, IO_STATUS_BLOCK *io, else flags = info->Flags; - if (flags & ~FILE_RENAME_REPLACE_IF_EXISTS) + if (flags & ~(FILE_RENAME_REPLACE_IF_EXISTS | FILE_RENAME_IGNORE_READONLY_ATTRIBUTE)) FIXME( "unsupported flags: %#x\n", (unsigned int)flags ); name_str.Buffer = info->FileName; @@ -4844,7 +4844,7 @@ NTSTATUS WINAPI NtSetInformationFile( HANDLE handle, IO_STATUS_BLOCK *io, else flags = info->Flags; - if (flags & ~FILE_LINK_REPLACE_IF_EXISTS) + if (flags & ~(FILE_LINK_REPLACE_IF_EXISTS | FILE_LINK_IGNORE_READONLY_ATTRIBUTE)) FIXME( "unsupported flags: %#x\n", (unsigned int)flags ); name_str.Buffer = info->FileName; diff --git a/server/fd.c b/server/fd.c index 3426a39682a..06793c3f281 100644 --- a/server/fd.c +++ b/server/fd.c @@ -2580,7 +2580,8 @@ static void set_fd_name( struct fd *fd, struct fd *root, const char *nameptr, da } /* read-only files cannot be replaced */ - if (!(st.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH))) + if (!(st.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)) && + !(flags & FILE_RENAME_IGNORE_READONLY_ATTRIBUTE)) { set_error( STATUS_ACCESS_DENIED ); goto failed; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/3907
From: Joel Holdsworth <joel(a)airwebreathe.org.uk> Signed-off-by: Joel Holdsworth <joel(a)airwebreathe.org.uk> --- dlls/ntdll/tests/file.c | 189 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 188 insertions(+), 1 deletion(-) diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c index 7ff05dbb937..8c7eaa670e6 100644 --- a/dlls/ntdll/tests/file.c +++ b/dlls/ntdll/tests/file.c @@ -2197,7 +2197,7 @@ static void test_file_rename_information_ex(void) static const WCHAR fooW[] = {'f','o','o',0}; WCHAR tmp_path[MAX_PATH], oldpath[MAX_PATH + 16], newpath[MAX_PATH + 16]; FILE_RENAME_INFORMATION *fri; - BOOL fileDeleted; + BOOL success, fileDeleted; UNICODE_STRING name_str; HANDLE handle, handle2; IO_STATUS_BLOCK io; @@ -2272,6 +2272,193 @@ static void test_file_rename_information_ex(void) HeapFree( GetProcessHeap(), 0, fri ); delete_object( oldpath ); delete_object( newpath ); + + /* oldpath is a file, newpath is a file, with FILE_RENAME_REPLACE_IF_EXISTS, with + * FILE_RENAME_POSIX_SEMANTICS, target file opened without sharing mode */ + res = GetTempFileNameW( tmp_path, fooW, 0, oldpath ); + ok( res != 0, "failed to create temp file\n" ); + handle = CreateFileW( oldpath, GENERIC_WRITE | DELETE, 0, NULL, CREATE_ALWAYS, 0, 0 ); + ok( handle != INVALID_HANDLE_VALUE, "CreateFileW failed\n" ); + + res = GetTempFileNameW( tmp_path, fooW, 0, newpath ); + ok( res != 0, "failed to create temp file\n" ); + handle2 = CreateFileW( newpath, GENERIC_WRITE | DELETE, 0, NULL, CREATE_ALWAYS, 0, 0 ); + ok( handle2 != INVALID_HANDLE_VALUE, "CreateFileW failed\n" ); + + pRtlDosPathNameToNtPathName_U( newpath, &name_str, NULL, NULL ); + fri = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_RENAME_INFORMATION) + name_str.Length ); + fri->Flags = FILE_RENAME_REPLACE_IF_EXISTS | FILE_RENAME_POSIX_SEMANTICS; + fri->RootDirectory = NULL; + fri->FileNameLength = name_str.Length; + memcpy( fri->FileName, name_str.Buffer, name_str.Length ); + pRtlFreeUnicodeString( &name_str ); + + io.Status = 0xdeadbeef; + res = pNtSetInformationFile( handle, &io, fri, sizeof(FILE_RENAME_INFORMATION) + fri->FileNameLength, FileRenameInformationEx ); + todo_wine ok( io.Status == 0xdeadbeef, "io.Status expected 0xdeadbeef, got %lx\n", io.Status ); + todo_wine ok( res == STATUS_SHARING_VIOLATION, "res expected STATUS_SHARING_VIOLATION, got %lx\n", res ); + fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; + ok( !fileDeleted, "file should exist\n" ); + fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; + ok( !fileDeleted, "file should exist\n" ); + + CloseHandle( handle ); + CloseHandle( handle2 ); + HeapFree( GetProcessHeap(), 0, fri ); + delete_object( oldpath ); + delete_object( newpath ); + + /* oldpath is a file, newpath is a file, with FILE_RENAME_REPLACE_IF_EXISTS, with + * FILE_RENAME_POSIX_SEMANTICS, target file opened with sharing mode */ + res = GetTempFileNameW( tmp_path, fooW, 0, oldpath ); + ok( res != 0, "failed to create temp file\n" ); + handle = CreateFileW( oldpath, GENERIC_WRITE | DELETE, 0, NULL, CREATE_ALWAYS, 0, 0 ); + ok( handle != INVALID_HANDLE_VALUE, "CreateFileW failed\n" ); + + res = GetTempFileNameW( tmp_path, fooW, 0, newpath ); + ok( res != 0, "failed to create temp file\n" ); + handle2 = CreateFileW( newpath, GENERIC_WRITE | DELETE, FILE_SHARE_DELETE, + NULL, CREATE_ALWAYS, 0, 0 ); + ok( handle2 != INVALID_HANDLE_VALUE, "CreateFileW failed\n" ); + + pRtlDosPathNameToNtPathName_U( newpath, &name_str, NULL, NULL ); + fri = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_RENAME_INFORMATION) + name_str.Length ); + fri->Flags = FILE_RENAME_REPLACE_IF_EXISTS | FILE_RENAME_POSIX_SEMANTICS; + fri->RootDirectory = NULL; + fri->FileNameLength = name_str.Length; + memcpy( fri->FileName, name_str.Buffer, name_str.Length ); + pRtlFreeUnicodeString( &name_str ); + + io.Status = 0xdeadbeef; + res = pNtSetInformationFile( handle, &io, fri, sizeof(FILE_RENAME_INFORMATION) + fri->FileNameLength, FileRenameInformationEx ); + todo_wine ok( io.Status == STATUS_SUCCESS, "io.Status expected STATUS_SUCCESS, got %lx\n", io.Status ); + todo_wine ok( res == STATUS_SUCCESS, "res expected STATUS_SUCCESS, got %lx\n", res ); + fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; + todo_wine ok( fileDeleted, "file should not exist\n" ); + fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; + ok( !fileDeleted, "file should exist\n" ); + + CloseHandle( handle ); + CloseHandle( handle2 ); + HeapFree( GetProcessHeap(), 0, fri ); + delete_object( oldpath ); + delete_object( newpath ); + + /* oldpath is a directory, newpath is a file, with FILE_RENAME_REPLACE_IF_EXISTS, with + * FILE_RENAME_POSIX_SEMANTICS, target file opened */ + res = GetTempFileNameW( tmp_path, fooW, 0, oldpath ); + ok( res != 0, "failed to create temp file\n" ); + DeleteFileW( oldpath ); + success = CreateDirectoryW( oldpath, NULL ); + ok( success != 0, "failed to create temp directory\n" ); + handle = CreateFileW( oldpath, GENERIC_WRITE | DELETE, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0 ); + ok( handle != INVALID_HANDLE_VALUE, "CreateFileW failed\n" ); + + res = GetTempFileNameW( tmp_path, fooW, 0, newpath ); + ok( res != 0, "failed to create temp file\n" ); + handle2 = CreateFileW( newpath, GENERIC_WRITE | DELETE, FILE_SHARE_DELETE, + NULL, CREATE_ALWAYS, 0, 0 ); + ok( handle2 != INVALID_HANDLE_VALUE, "CreateFileW failed\n" ); + + pRtlDosPathNameToNtPathName_U( newpath, &name_str, NULL, NULL ); + fri = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_RENAME_INFORMATION) + name_str.Length ); + fri->Flags = FILE_RENAME_REPLACE_IF_EXISTS | FILE_RENAME_POSIX_SEMANTICS; + fri->RootDirectory = NULL; + fri->FileNameLength = name_str.Length; + memcpy( fri->FileName, name_str.Buffer, name_str.Length ); + pRtlFreeUnicodeString( &name_str ); + + io.Status = 0xdeadbeef; + res = pNtSetInformationFile( handle, &io, fri, sizeof(FILE_RENAME_INFORMATION) + fri->FileNameLength, FileRenameInformationEx ); + todo_wine ok( io.Status == 0xdeadbeef, "io.Status expected 0xdeadbeef, got %lx\n", io.Status ); + todo_wine ok( res == STATUS_NOT_A_DIRECTORY, "res expected STATUS_NOT_A_DIRECTORY, got %lx\n", res ); + fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; + ok( !fileDeleted, "file should exist\n" ); + fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; + ok( !fileDeleted, "file should exist\n" ); + + CloseHandle( handle ); + CloseHandle( handle2 ); + HeapFree( GetProcessHeap(), 0, fri ); + delete_object( oldpath ); + delete_object( newpath ); + + /* oldpath is a directory, newpath is a directory, with FILE_RENAME_REPLACE_IF_EXISTS, with + * FILE_RENAME_POSIX_SEMANTICS, target file opened */ + res = GetTempFileNameW( tmp_path, fooW, 0, oldpath ); + ok( res != 0, "failed to create temp file\n" ); + DeleteFileW( oldpath ); + success = CreateDirectoryW( oldpath, NULL ); + ok( success != 0, "failed to create temp directory\n" ); + handle = CreateFileW( oldpath, GENERIC_WRITE | DELETE, 0, + NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0 ); + ok( handle != INVALID_HANDLE_VALUE, "CreateFileW failed\n" ); + + res = GetTempFileNameW( tmp_path, fooW, 0, newpath ); + ok( res != 0, "failed to create temp file\n" ); + DeleteFileW( newpath ); + success = CreateDirectoryW( newpath, NULL ); + ok( success != 0, "failed to create temp directory\n" ); + handle2 = CreateFileW( newpath, GENERIC_WRITE | DELETE, FILE_SHARE_DELETE, + NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0 ); + ok( handle2 != INVALID_HANDLE_VALUE, "CreateFileW failed\n" ); + + pRtlDosPathNameToNtPathName_U( newpath, &name_str, NULL, NULL ); + fri = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_RENAME_INFORMATION) + name_str.Length ); + fri->Flags = FILE_RENAME_REPLACE_IF_EXISTS | FILE_RENAME_POSIX_SEMANTICS; + fri->RootDirectory = NULL; + fri->FileNameLength = name_str.Length; + memcpy( fri->FileName, name_str.Buffer, name_str.Length ); + pRtlFreeUnicodeString( &name_str ); + + io.Status = 0xdeadbeef; + res = pNtSetInformationFile( handle, &io, fri, sizeof(FILE_RENAME_INFORMATION) + fri->FileNameLength, FileRenameInformationEx ); + todo_wine ok( io.Status == STATUS_SUCCESS, "io.Status expected STATUS_SUCCESS, got %lx\n", io.Status ); + todo_wine ok( res == STATUS_SUCCESS, "res expected STATUS_SUCCESS, got %lx\n", res ); + fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; + todo_wine ok( fileDeleted, "file should not exist\n" ); + fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; + ok( !fileDeleted, "file should exist\n" ); + + CloseHandle( handle ); + CloseHandle( handle2 ); + HeapFree( GetProcessHeap(), 0, fri ); + delete_object( oldpath ); + delete_object( newpath ); + + /* oldpath is a file, newpath is a directory, with FILE_RENAME_REPLACE_IF_EXISTS, with + * FILE_RENAME_POSIX_SEMANTICS */ + res = GetTempFileNameW( tmp_path, fooW, 0, oldpath ); + ok( res != 0, "failed to create temp file\n" ); + handle = CreateFileW( oldpath, GENERIC_WRITE | DELETE, 0, NULL, CREATE_ALWAYS, 0, 0 ); + ok( handle != INVALID_HANDLE_VALUE, "CreateFileW failed\n" ); + + res = GetTempFileNameW( tmp_path, fooW, 0, newpath ); + ok( res != 0, "failed to create temp file\n" ); + DeleteFileW( newpath ); + success = CreateDirectoryW( newpath, NULL ); + ok( success != 0, "failed to create temp directory\n" ); + pRtlDosPathNameToNtPathName_U( newpath, &name_str, NULL, NULL ); + fri = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_RENAME_INFORMATION) + name_str.Length ); + fri->Flags = FILE_RENAME_REPLACE_IF_EXISTS | FILE_RENAME_POSIX_SEMANTICS; + fri->RootDirectory = NULL; + fri->FileNameLength = name_str.Length; + memcpy( fri->FileName, name_str.Buffer, name_str.Length ); + pRtlFreeUnicodeString( &name_str ); + + io.Status = 0xdeadbeef; + res = pNtSetInformationFile( handle, &io, fri, sizeof(FILE_RENAME_INFORMATION) + fri->FileNameLength, FileRenameInformationEx ); + todo_wine ok( io.Status == 0xdeadbeef, "io.Status expected 0xdeadbeef, got %lx\n", io.Status ); + todo_wine ok( res == STATUS_FILE_IS_A_DIRECTORY, "res expected STATUS_FILE_IS_A_DIRECTORY, got %lx\n", res ); + fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; + ok( !fileDeleted, "file should exist\n" ); + fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; + ok( !fileDeleted, "file should exist\n" ); + + CloseHandle( handle ); + HeapFree( GetProcessHeap(), 0, fri ); + delete_object( oldpath ); + delete_object( newpath ); } static void test_file_link_information(FILE_INFORMATION_CLASS class) -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/3907
From: Joel Holdsworth <joel(a)airwebreathe.org.uk> Signed-off-by: Joel Holdsworth <joel(a)airwebreathe.org.uk> --- dlls/ntdll/tests/file.c | 195 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 194 insertions(+), 1 deletion(-) diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c index 8c7eaa670e6..f7dbf97e11c 100644 --- a/dlls/ntdll/tests/file.c +++ b/dlls/ntdll/tests/file.c @@ -3225,7 +3225,7 @@ static void test_file_link_information_ex(void) static const WCHAR fooW[] = {'f','o','o',0}; WCHAR tmp_path[MAX_PATH], oldpath[MAX_PATH + 16], newpath[MAX_PATH + 16]; FILE_LINK_INFORMATION *fli; - BOOL fileDeleted; + BOOL success, fileDeleted; UNICODE_STRING name_str; HANDLE handle, handle2; IO_STATUS_BLOCK io; @@ -3300,6 +3300,199 @@ static void test_file_link_information_ex(void) HeapFree( GetProcessHeap(), 0, fli ); delete_object( oldpath ); delete_object( newpath ); + + /* oldpath is a file, newpath is a file, with FILE_LINK_REPLACE_IF_EXISTS, with + * FILE_LINK_POSIX_SEMANTICS, target file opened without sharing mode */ + res = GetTempFileNameW( tmp_path, fooW, 0, oldpath ); + ok( res != 0, "failed to create temp file\n" ); + handle = CreateFileW( oldpath, GENERIC_WRITE | DELETE, 0, + NULL, CREATE_ALWAYS, 0, 0 ); + ok( handle != INVALID_HANDLE_VALUE, "CreateFileW failed\n" ); + + res = GetTempFileNameW( tmp_path, fooW, 0, newpath ); + ok( res != 0, "failed to create temp file\n" ); + handle2 = CreateFileW( newpath, GENERIC_WRITE | DELETE, 0, + NULL, CREATE_ALWAYS, 0, 0 ); + ok( handle2 != INVALID_HANDLE_VALUE, "CreateFileW failed\n" ); + + pRtlDosPathNameToNtPathName_U( newpath, &name_str, NULL, NULL ); + fli = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_LINK_INFORMATION) + name_str.Length ); + fli->Flags = FILE_LINK_REPLACE_IF_EXISTS | FILE_LINK_POSIX_SEMANTICS; + fli->RootDirectory = NULL; + fli->FileNameLength = name_str.Length; + memcpy( fli->FileName, name_str.Buffer, name_str.Length ); + pRtlFreeUnicodeString( &name_str ); + + io.Status = 0xdeadbeef; + res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, FileLinkInformationEx ); + todo_wine ok( io.Status == 0xdeadbeef, "io.Status expected 0xdeadbeef, got %lx\n", io.Status ); + todo_wine ok( res == STATUS_SHARING_VIOLATION, "res expected STATUS_SHARING_VIOLATION, got %lx\n", res ); + fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; + ok( !fileDeleted, "file should exist\n" ); + fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; + ok( !fileDeleted, "file should exist\n" ); + + CloseHandle( handle ); + CloseHandle( handle2 ); + HeapFree( GetProcessHeap(), 0, fli ); + delete_object( oldpath ); + delete_object( newpath ); + + /* oldpath is a file, newpath is a file, with FILE_LINK_REPLACE_IF_EXISTS, with + * FILE_LINK_POSIX_SEMANTICS, target file opened with sharing mode */ + res = GetTempFileNameW( tmp_path, fooW, 0, oldpath ); + ok( res != 0, "failed to create temp file\n" ); + handle = CreateFileW( oldpath, GENERIC_WRITE | DELETE, 0, + NULL, CREATE_ALWAYS, 0, 0 ); + ok( handle != INVALID_HANDLE_VALUE, "CreateFileW failed\n" ); + + res = GetTempFileNameW( tmp_path, fooW, 0, newpath ); + ok( res != 0, "failed to create temp file\n" ); + handle2 = CreateFileW( newpath, GENERIC_WRITE | DELETE, FILE_SHARE_DELETE, + NULL, CREATE_ALWAYS, 0, 0 ); + ok( handle2 != INVALID_HANDLE_VALUE, "CreateFileW failed\n" ); + + pRtlDosPathNameToNtPathName_U( newpath, &name_str, NULL, NULL ); + fli = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_LINK_INFORMATION) + name_str.Length ); + fli->Flags = FILE_LINK_REPLACE_IF_EXISTS | FILE_LINK_POSIX_SEMANTICS; + fli->RootDirectory = NULL; + fli->FileNameLength = name_str.Length; + memcpy( fli->FileName, name_str.Buffer, name_str.Length ); + pRtlFreeUnicodeString( &name_str ); + + io.Status = 0xdeadbeef; + res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, FileLinkInformationEx ); + todo_wine ok( io.Status == STATUS_SUCCESS, "io.Status expected STATUS_SUCCESS, got %lx\n", io.Status ); + todo_wine ok( res == STATUS_SUCCESS, "res expected STATUS_ACCESS_DENIED, got %lx\n", res ); + fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; + ok( !fileDeleted, "file should exist\n" ); + fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; + ok( !fileDeleted, "file should exist\n" ); + + CloseHandle( handle ); + CloseHandle( handle2 ); + HeapFree( GetProcessHeap(), 0, fli ); + delete_object( oldpath ); + delete_object( newpath ); + + /* oldpath is a directory, newpath is a file, with FILE_LINK_REPLACE_IF_EXISTS, with + * FILE_LINK_POSIX_SEMANTICS, target file opened */ + res = GetTempFileNameW( tmp_path, fooW, 0, oldpath ); + ok( res != 0, "failed to create temp file\n" ); + DeleteFileW( oldpath ); + success = CreateDirectoryW( oldpath, NULL ); + ok( success != 0, "failed to create temp directory\n" ); + handle = CreateFileW( oldpath, GENERIC_WRITE | DELETE, 0, + NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0 ); + ok( handle != INVALID_HANDLE_VALUE, "CreateFileW failed\n" ); + + res = GetTempFileNameW( tmp_path, fooW, 0, newpath ); + ok( res != 0, "failed to create temp file\n" ); + handle2 = CreateFileW( newpath, GENERIC_WRITE | DELETE, FILE_SHARE_DELETE, + NULL, CREATE_ALWAYS, 0, 0 ); + ok( handle2 != INVALID_HANDLE_VALUE, "CreateFileW failed\n" ); + + pRtlDosPathNameToNtPathName_U( newpath, &name_str, NULL, NULL ); + fli = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_LINK_INFORMATION) + name_str.Length ); + fli->Flags = FILE_LINK_REPLACE_IF_EXISTS | FILE_LINK_POSIX_SEMANTICS; + fli->RootDirectory = NULL; + fli->FileNameLength = name_str.Length; + memcpy( fli->FileName, name_str.Buffer, name_str.Length ); + pRtlFreeUnicodeString( &name_str ); + + io.Status = 0xdeadbeef; + res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, FileLinkInformationEx ); + ok( io.Status == STATUS_FILE_IS_A_DIRECTORY, + "io.Status expected STATUS_FILE_IS_A_DIRECTORY, got %lx\n", io.Status ); + ok( res == STATUS_FILE_IS_A_DIRECTORY, "res expected STATUS_FILE_IS_A_DIRECTORY, got %lx\n", res ); + fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; + ok( !fileDeleted, "file should exist\n" ); + fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; + ok( !fileDeleted, "file should exist\n" ); + + CloseHandle( handle ); + CloseHandle( handle2 ); + HeapFree( GetProcessHeap(), 0, fli ); + delete_object( oldpath ); + delete_object( newpath ); + + /* oldpath is a directory, newpath is a directory, with FILE_LINK_REPLACE_IF_EXISTS, with + * FILE_LINK_POSIX_SEMANTICS, target file opened */ + res = GetTempFileNameW( tmp_path, fooW, 0, oldpath ); + ok( res != 0, "failed to create temp file\n" ); + DeleteFileW( oldpath ); + success = CreateDirectoryW( oldpath, NULL ); + ok( success != 0, "failed to create temp directory\n" ); + handle = CreateFileW( oldpath, GENERIC_WRITE | DELETE, 0, + NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0 ); + ok( handle != INVALID_HANDLE_VALUE, "CreateFileW failed\n" ); + + res = GetTempFileNameW( tmp_path, fooW, 0, newpath ); + ok( res != 0, "failed to create temp file\n" ); + DeleteFileW( newpath ); + success = CreateDirectoryW( newpath, NULL ); + ok( success != 0, "failed to create temp directory\n" ); + handle2 = CreateFileW( newpath, GENERIC_WRITE | DELETE, FILE_SHARE_DELETE, + NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0 ); + ok( handle2 != INVALID_HANDLE_VALUE, "CreateFileW failed\n" ); + + pRtlDosPathNameToNtPathName_U( newpath, &name_str, NULL, NULL ); + fli = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_LINK_INFORMATION) + name_str.Length ); + fli->Flags = FILE_LINK_REPLACE_IF_EXISTS | FILE_LINK_POSIX_SEMANTICS; + fli->RootDirectory = NULL; + fli->FileNameLength = name_str.Length; + memcpy( fli->FileName, name_str.Buffer, name_str.Length ); + pRtlFreeUnicodeString( &name_str ); + + io.Status = 0xdeadbeef; + res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, FileLinkInformationEx ); + ok( io.Status == STATUS_FILE_IS_A_DIRECTORY, + "io.Status expected STATUS_FILE_IS_A_DIRECTORY, got %lx\n", io.Status ); + ok( res == STATUS_FILE_IS_A_DIRECTORY, "res expected STATUS_FILE_IS_A_DIRECTORY, got %lx\n", res ); + fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; + ok( !fileDeleted, "file should exist\n" ); + fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; + ok( !fileDeleted, "file should exist\n" ); + + CloseHandle( handle ); + CloseHandle( handle2 ); + HeapFree( GetProcessHeap(), 0, fli ); + delete_object( oldpath ); + delete_object( newpath ); + + /* oldpath is a file, newpath is a directory, with FILE_LINK_REPLACE_IF_EXISTS, with + * FILE_LINK_POSIX_SEMANTICS */ + res = GetTempFileNameW( tmp_path, fooW, 0, oldpath ); + ok( res != 0, "failed to create temp file\n" ); + handle = CreateFileW( oldpath, GENERIC_WRITE | DELETE, 0, NULL, CREATE_ALWAYS, 0, 0 ); + ok( handle != INVALID_HANDLE_VALUE, "CreateFileW failed\n" ); + + res = GetTempFileNameW( tmp_path, fooW, 0, newpath ); + ok( res != 0, "failed to create temp file\n" ); + DeleteFileW( newpath ); + success = CreateDirectoryW( newpath, NULL ); + ok( success != 0, "failed to create temp directory\n" ); + pRtlDosPathNameToNtPathName_U( newpath, &name_str, NULL, NULL ); + fli = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_LINK_INFORMATION) + name_str.Length ); + fli->Flags = FILE_LINK_REPLACE_IF_EXISTS | FILE_LINK_POSIX_SEMANTICS; + fli->RootDirectory = NULL; + fli->FileNameLength = name_str.Length; + memcpy( fli->FileName, name_str.Buffer, name_str.Length ); + pRtlFreeUnicodeString( &name_str ); + + io.Status = 0xdeadbeef; + res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, FileLinkInformationEx ); + todo_wine ok( io.Status == 0xdeadbeef, "io.Status expected 0xdeadbeef, got %lx\n", io.Status ); + todo_wine ok( res == STATUS_FILE_IS_A_DIRECTORY, "res expected STATUS_FILE_IS_A_DIRECTORY, got %lx\n", res ); + fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; + ok( !fileDeleted, "file should exist\n" ); + fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; + ok( !fileDeleted, "file should exist\n" ); + + CloseHandle( handle ); + HeapFree( GetProcessHeap(), 0, fli ); + delete_object( oldpath ); + delete_object( newpath ); } static void test_file_both_information(void) -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/3907
From: Joel Holdsworth <joel(a)airwebreathe.org.uk> Signed-off-by: Joel Holdsworth <joel(a)airwebreathe.org.uk> --- server/fd.c | 40 +++++++++++++++++++++++++++------------- 1 file changed, 27 insertions(+), 13 deletions(-) diff --git a/server/fd.c b/server/fd.c index 06793c3f281..f945738cdd3 100644 --- a/server/fd.c +++ b/server/fd.c @@ -1564,6 +1564,31 @@ static void fd_destroy( struct object *obj ) } } +static void get_inode_open_sharing(struct fd *fd, struct inode *inode, + unsigned int *sharing, unsigned int *access ) +{ + static const unsigned int all_access = FILE_READ_DATA | FILE_EXECUTE | FILE_WRITE_DATA | FILE_APPEND_DATA | DELETE; + + struct list *ptr; + + *sharing = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE; + *access = 0; + + if (!inode) + inode = fd->inode; + + LIST_FOR_EACH( ptr, &inode->open ) + { + struct fd *fd_ptr = LIST_ENTRY( ptr, struct fd, inode_entry ); + if (fd_ptr != fd) + { + /* if access mode is 0, sharing mode is ignored */ + if (fd_ptr->access & all_access) *sharing &= fd_ptr->sharing; + *access |= fd_ptr->access; + } + } +} + /* 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, @@ -1574,23 +1599,12 @@ static unsigned int check_sharing( struct fd *fd, unsigned int access, unsigned const unsigned int write_access = FILE_WRITE_DATA | FILE_APPEND_DATA; const unsigned int all_access = read_access | write_access | DELETE; - unsigned int existing_sharing = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE; - unsigned int existing_access = 0; - struct list *ptr; + unsigned int existing_sharing, existing_access; fd->access = access; fd->sharing = sharing; - LIST_FOR_EACH( ptr, &fd->inode->open ) - { - struct fd *fd_ptr = LIST_ENTRY( ptr, struct fd, inode_entry ); - if (fd_ptr != fd) - { - /* if access mode is 0, sharing mode is ignored */ - if (fd_ptr->access & all_access) existing_sharing &= fd_ptr->sharing; - existing_access |= fd_ptr->access; - } - } + get_inode_open_sharing(fd, NULL, &existing_sharing, &existing_access); if (((access & read_access) && !(existing_sharing & FILE_SHARE_READ)) || ((access & write_access) && !(existing_sharing & FILE_SHARE_WRITE)) || -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/3907
From: Joel Holdsworth <joel(a)airwebreathe.org.uk> Signed-off-by: Joel Holdsworth <joel(a)airwebreathe.org.uk> --- dlls/ntdll/tests/file.c | 20 +++++++-------- dlls/ntdll/unix/file.c | 8 ++++-- server/fd.c | 56 ++++++++++++++++++++++++++++++++--------- 3 files changed, 60 insertions(+), 24 deletions(-) diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c index f7dbf97e11c..140faa33577 100644 --- a/dlls/ntdll/tests/file.c +++ b/dlls/ntdll/tests/file.c @@ -2296,7 +2296,7 @@ static void test_file_rename_information_ex(void) io.Status = 0xdeadbeef; res = pNtSetInformationFile( handle, &io, fri, sizeof(FILE_RENAME_INFORMATION) + fri->FileNameLength, FileRenameInformationEx ); todo_wine ok( io.Status == 0xdeadbeef, "io.Status expected 0xdeadbeef, got %lx\n", io.Status ); - todo_wine ok( res == STATUS_SHARING_VIOLATION, "res expected STATUS_SHARING_VIOLATION, got %lx\n", res ); + ok( res == STATUS_SHARING_VIOLATION, "res expected STATUS_SHARING_VIOLATION, got %lx\n", res ); fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; ok( !fileDeleted, "file should exist\n" ); fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; @@ -2331,10 +2331,10 @@ static void test_file_rename_information_ex(void) io.Status = 0xdeadbeef; res = pNtSetInformationFile( handle, &io, fri, sizeof(FILE_RENAME_INFORMATION) + fri->FileNameLength, FileRenameInformationEx ); - todo_wine ok( io.Status == STATUS_SUCCESS, "io.Status expected STATUS_SUCCESS, got %lx\n", io.Status ); - todo_wine ok( res == STATUS_SUCCESS, "res expected STATUS_SUCCESS, got %lx\n", res ); + ok( io.Status == STATUS_SUCCESS, "io.Status expected STATUS_SUCCESS, got %lx\n", io.Status ); + ok( res == STATUS_SUCCESS, "res expected STATUS_SUCCESS, got %lx\n", res ); fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; - todo_wine ok( fileDeleted, "file should not exist\n" ); + ok( fileDeleted, "file should not exist\n" ); fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; ok( !fileDeleted, "file should exist\n" ); @@ -2371,7 +2371,7 @@ static void test_file_rename_information_ex(void) io.Status = 0xdeadbeef; res = pNtSetInformationFile( handle, &io, fri, sizeof(FILE_RENAME_INFORMATION) + fri->FileNameLength, FileRenameInformationEx ); todo_wine ok( io.Status == 0xdeadbeef, "io.Status expected 0xdeadbeef, got %lx\n", io.Status ); - todo_wine ok( res == STATUS_NOT_A_DIRECTORY, "res expected STATUS_NOT_A_DIRECTORY, got %lx\n", res ); + ok( res == STATUS_NOT_A_DIRECTORY, "res expected STATUS_NOT_A_DIRECTORY, got %lx\n", res ); fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; ok( !fileDeleted, "file should exist\n" ); fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; @@ -2449,7 +2449,7 @@ static void test_file_rename_information_ex(void) io.Status = 0xdeadbeef; res = pNtSetInformationFile( handle, &io, fri, sizeof(FILE_RENAME_INFORMATION) + fri->FileNameLength, FileRenameInformationEx ); todo_wine ok( io.Status == 0xdeadbeef, "io.Status expected 0xdeadbeef, got %lx\n", io.Status ); - todo_wine ok( res == STATUS_FILE_IS_A_DIRECTORY, "res expected STATUS_FILE_IS_A_DIRECTORY, got %lx\n", res ); + ok( res == STATUS_FILE_IS_A_DIRECTORY, "res expected STATUS_FILE_IS_A_DIRECTORY, got %lx\n", res ); fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; ok( !fileDeleted, "file should exist\n" ); fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; @@ -3326,7 +3326,7 @@ static void test_file_link_information_ex(void) io.Status = 0xdeadbeef; res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, FileLinkInformationEx ); todo_wine ok( io.Status == 0xdeadbeef, "io.Status expected 0xdeadbeef, got %lx\n", io.Status ); - todo_wine ok( res == STATUS_SHARING_VIOLATION, "res expected STATUS_SHARING_VIOLATION, got %lx\n", res ); + ok( res == STATUS_SHARING_VIOLATION, "res expected STATUS_SHARING_VIOLATION, got %lx\n", res ); fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; ok( !fileDeleted, "file should exist\n" ); fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; @@ -3362,8 +3362,8 @@ static void test_file_link_information_ex(void) io.Status = 0xdeadbeef; res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, FileLinkInformationEx ); - todo_wine ok( io.Status == STATUS_SUCCESS, "io.Status expected STATUS_SUCCESS, got %lx\n", io.Status ); - todo_wine ok( res == STATUS_SUCCESS, "res expected STATUS_ACCESS_DENIED, got %lx\n", res ); + ok( io.Status == STATUS_SUCCESS, "io.Status expected STATUS_SUCCESS, got %lx\n", io.Status ); + ok( res == STATUS_SUCCESS, "res expected STATUS_ACCESS_DENIED, got %lx\n", res ); fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; ok( !fileDeleted, "file should exist\n" ); fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; @@ -3483,7 +3483,7 @@ static void test_file_link_information_ex(void) io.Status = 0xdeadbeef; res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, FileLinkInformationEx ); todo_wine ok( io.Status == 0xdeadbeef, "io.Status expected 0xdeadbeef, got %lx\n", io.Status ); - todo_wine ok( res == STATUS_FILE_IS_A_DIRECTORY, "res expected STATUS_FILE_IS_A_DIRECTORY, got %lx\n", res ); + ok( res == STATUS_FILE_IS_A_DIRECTORY, "res expected STATUS_FILE_IS_A_DIRECTORY, got %lx\n", res ); fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; ok( !fileDeleted, "file should exist\n" ); fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c index db91f9930ed..a31e421c3ff 100644 --- a/dlls/ntdll/unix/file.c +++ b/dlls/ntdll/unix/file.c @@ -4797,7 +4797,9 @@ NTSTATUS WINAPI NtSetInformationFile( HANDLE handle, IO_STATUS_BLOCK *io, else flags = info->Flags; - if (flags & ~(FILE_RENAME_REPLACE_IF_EXISTS | FILE_RENAME_IGNORE_READONLY_ATTRIBUTE)) + if (flags & ~(FILE_RENAME_REPLACE_IF_EXISTS | + FILE_RENAME_IGNORE_READONLY_ATTRIBUTE | + FILE_RENAME_POSIX_SEMANTICS)) FIXME( "unsupported flags: %#x\n", (unsigned int)flags ); name_str.Buffer = info->FileName; @@ -4844,7 +4846,9 @@ NTSTATUS WINAPI NtSetInformationFile( HANDLE handle, IO_STATUS_BLOCK *io, else flags = info->Flags; - if (flags & ~(FILE_LINK_REPLACE_IF_EXISTS | FILE_LINK_IGNORE_READONLY_ATTRIBUTE)) + if (flags & ~(FILE_LINK_REPLACE_IF_EXISTS | + FILE_LINK_IGNORE_READONLY_ATTRIBUTE | + FILE_LINK_POSIX_SEMANTICS)) FIXME( "unsupported flags: %#x\n", (unsigned int)flags ); name_str.Buffer = info->FileName; diff --git a/server/fd.c b/server/fd.c index f945738cdd3..96be10d7d7a 100644 --- a/server/fd.c +++ b/server/fd.c @@ -2586,13 +2586,6 @@ static void set_fd_name( struct fd *fd, struct fd *root, const char *nameptr, da goto failed; } - /* can't replace directories or special files */ - if (!S_ISREG( st.st_mode )) - { - set_error( STATUS_ACCESS_DENIED ); - goto failed; - } - /* read-only files cannot be replaced */ if (!(st.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)) && !(flags & FILE_RENAME_IGNORE_READONLY_ATTRIBUTE)) @@ -2601,16 +2594,55 @@ static void set_fd_name( struct fd *fd, struct fd *root, const char *nameptr, da goto failed; } - /* can't replace an opened file */ - if ((inode = get_inode( st.st_dev, st.st_ino, -1 ))) + if (flags & FILE_RENAME_POSIX_SEMANTICS) { - int is_empty = list_empty( &inode->open ); - release_object( inode ); - if (!is_empty) + /* can't replace a file with a directory with FILE_RENAME_POSIX_SEMANTICS */ + if (S_ISDIR( st2.st_mode ) && !S_ISDIR( st.st_mode )) + { + set_error( STATUS_NOT_A_DIRECTORY ); + goto failed; + } + + /* can't replace a directory with a file with FILE_RENAME_POSIX_SEMANTICS */ + if (!S_ISDIR( st2.st_mode ) && S_ISDIR( st.st_mode )) + { + set_error( STATUS_FILE_IS_A_DIRECTORY ); + goto failed; + } + + /* can't replace an open file that was not opened with FILE_SHARE_DELETE */ + if ((inode = get_inode( st.st_dev, st.st_ino, -1 ))) + { + unsigned int sharing, access; + get_inode_open_sharing( NULL, inode, &sharing, &access ); + release_object( inode ); + + if (!(sharing & FILE_SHARE_DELETE)) { + set_error( STATUS_SHARING_VIOLATION ); + goto failed; + } + } + } + else + { + /* can't replace directories or special files */ + if (!S_ISREG( st.st_mode )) { set_error( STATUS_ACCESS_DENIED ); goto failed; } + + /* can't replace an opened file without FILE_RENAME_POSIX_SEMANTICS */ + if ((inode = get_inode( st.st_dev, st.st_ino, -1 ))) + { + int is_empty = list_empty( &inode->open ); + release_object( inode ); + if (!is_empty) + { + set_error( STATUS_ACCESS_DENIED ); + goto failed; + } + } } /* link() expects that the target doesn't exist */ -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/3907
Hi, It looks like your patch introduced the new failures shown below. Please investigate and fix them before resubmitting your patch. If they are not new, fixing them anyway would help a lot. Otherwise please ask for the known failures list to be updated. The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=137991 Your paranoid android. === build (build log) === error: patch failed: dlls/ntdll/tests/file.c:1549 error: patch failed: dlls/ntdll/tests/file.c:2216 Task: Patch failed to apply === debian11 (build log) === error: patch failed: dlls/ntdll/tests/file.c:1549 error: patch failed: dlls/ntdll/tests/file.c:2216 Task: Patch failed to apply === debian11b (build log) === error: patch failed: dlls/ntdll/tests/file.c:1549 error: patch failed: dlls/ntdll/tests/file.c:2216 Task: Patch failed to apply
On Wed Sep 27 21:14:36 2023 +0000, Joel Holdsworth wrote:
changed this line in [version 2 of the diff](/wine/wine/-/merge_requests/3907/diffs?diff_id=72428&start_sha=50ba1fb9dbf7f808e7dde3382b36f98266eb66ff#51bc191c8a1fc172f9ad299dd009ef2d24dfa043_4807_4800) Now fixed!
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/3907#note_47222
On Wed Sep 27 21:14:37 2023 +0000, Joel Holdsworth wrote:
changed this line in [version 2 of the diff](/wine/wine/-/merge_requests/3907/diffs?diff_id=72428&start_sha=50ba1fb9dbf7f808e7dde3382b36f98266eb66ff#51bc191c8a1fc172f9ad299dd009ef2d24dfa043_4862_4849) Done!
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/3907#note_47223
On Wed Sep 27 21:14:38 2023 +0000, Joel Holdsworth wrote:
changed this line in [version 2 of the diff](/wine/wine/-/merge_requests/3907/diffs?diff_id=72428&start_sha=50ba1fb9dbf7f808e7dde3382b36f98266eb66ff#21721cceaf2ea82f93539de2c6e01cc016bbac65_2599_2614) Fixed!
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/3907#note_47224
On Fri Sep 29 17:37:33 2023 +0000, Jinoh Kang wrote:
This open-codes part of the access sharing check logic (which is normally doned by `check_sharing()`). This stretches the scope of `set_fd_name` (as evidenced by the indent). We should factor out actual sharing validation logic out of `check_sharing()` and use that. This will make `set_fd_name()` shorter, hopefully improving readability. Fair enough. I moved this out to a helper: `get_inode_open_sharing`.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/3907#note_47225
This is still too much for a single MR. It looks like you could have at least 3 separate MRs here. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/3907#note_47233
This merge request was closed by Joel Holdsworth. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/3907
On Sun Oct 1 16:13:36 2023 +0000, Alexandre Julliard wrote:
This is still too much for a single MR. It looks like you could have at least 3 separate MRs here. Ok. Part 1 MR is !3992
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/3907#note_47304
participants (4)
-
Alexandre Julliard (@julliard) -
Joel Holdsworth -
Joel Holdsworth (@jhol) -
Marvin