From: Joel Holdsworth joel@airwebreathe.org.uk
Signed-off-by: Joel Holdsworth joel@airwebreathe.org.uk --- dlls/ntdll/tests/file.c | 20 ++++++------- dlls/ntdll/unix/file.c | 4 --- server/fd.c | 65 +++++++++++++++++++++++++++++++++-------- 3 files changed, 63 insertions(+), 26 deletions(-)
diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c index d2e93afb859..42bf8f638b8 100644 --- a/dlls/ntdll/tests/file.c +++ b/dlls/ntdll/tests/file.c @@ -2455,7 +2455,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; @@ -2490,10 +2490,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" );
@@ -2758,7 +2758,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; @@ -3014,7 +3014,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; @@ -4158,7 +4158,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; @@ -4194,8 +4194,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; @@ -4727,7 +4727,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 b4eb172f501..866677ea8ce 100644 --- a/dlls/ntdll/unix/file.c +++ b/dlls/ntdll/unix/file.c @@ -4797,8 +4797,6 @@ NTSTATUS WINAPI NtSetInformationFile( HANDLE handle, IO_STATUS_BLOCK *io, else flags = info->Flags;
- if (flags & FILE_RENAME_POSIX_SEMANTICS) - FIXME( "FILE_RENAME_POSIX_SEMANTICS not supported\n" ); if (flags & FILE_RENAME_SUPPRESS_PIN_STATE_INHERITANCE) FIXME( "FILE_RENAME_SUPPRESS_PIN_STATE_INHERITANCE not supported\n" ); if (flags & FILE_RENAME_SUPPRESS_STORAGE_RESERVE_INHERITANCE) @@ -4852,8 +4850,6 @@ NTSTATUS WINAPI NtSetInformationFile( HANDLE handle, IO_STATUS_BLOCK *io, else flags = info->Flags;
- if (flags & FILE_LINK_POSIX_SEMANTICS) - FIXME( "FILE_LINK_POSIX_SEMANTICS not supported\n" ); if (flags & FILE_LINK_SUPPRESS_STORAGE_RESERVE_INHERITANCE) FIXME( "FILE_LINK_SUPPRESS_STORAGE_RESERVE_INHERITANCE not supported\n" ); if (flags & FILE_LINK_NO_INCREASE_AVAILABLE_SPACE) diff --git a/server/fd.c b/server/fd.c index 2b705bfe8e1..61b1943a0a9 100644 --- a/server/fd.c +++ b/server/fd.c @@ -2611,13 +2611,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)) @@ -2626,16 +2619,64 @@ 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) + { + /* 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 no opened with FILE_SHARE_DELETE */ + if ((inode = get_inode( st.st_dev, st.st_ino, -1 ))) + { + int have_delete_sharing = 1; + struct list *ptr; + LIST_FOR_EACH( ptr, &inode->open ) + { + struct fd *fd_ptr = LIST_ENTRY( ptr, struct fd, inode_entry ); + if (!(fd_ptr->sharing & FILE_SHARE_DELETE)) { + have_delete_sharing = 0; + break; + } + } + + release_object( inode ); + + if (!have_delete_sharing) { + set_error( STATUS_SHARING_VIOLATION ); + goto failed; + } + } + } + else { - int is_empty = list_empty( &inode->open ); - release_object( inode ); - if (!is_empty) + /* 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 */