Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- Perhaps it would also make sense to move this definition to ddk/ntifs.h?
dlls/ntdll/file.c | 4 +-- dlls/ntdll/tests/file.c | 68 ++++++++++++++++++++--------------------- include/winternl.h | 4 +-- 3 files changed, 38 insertions(+), 38 deletions(-)
diff --git a/dlls/ntdll/file.c b/dlls/ntdll/file.c index 5dda468d74b..5ecf293820e 100644 --- a/dlls/ntdll/file.c +++ b/dlls/ntdll/file.c @@ -2771,14 +2771,14 @@ NTSTATUS WINAPI NtSetInformationFile(HANDLE handle, PIO_STATUS_BLOCK io,
attr.Length = sizeof(attr); attr.ObjectName = &name_str; - attr.RootDirectory = info->RootDir; + attr.RootDirectory = info->RootDirectory; attr.Attributes = OBJ_CASE_INSENSITIVE;
io->u.Status = nt_to_unix_file_name_attr( &attr, &unix_name, FILE_OPEN_IF ); if (io->u.Status != STATUS_SUCCESS && io->u.Status != STATUS_NO_SUCH_FILE) break;
- if (!info->Replace && io->u.Status == STATUS_SUCCESS) + if (!info->ReplaceIfExists && io->u.Status == STATUS_SUCCESS) { RtlFreeAnsiString( &unix_name ); io->u.Status = STATUS_OBJECT_NAME_COLLISION; diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c index dd188fd9132..561cf800433 100644 --- a/dlls/ntdll/tests/file.c +++ b/dlls/ntdll/tests/file.c @@ -1502,8 +1502,8 @@ static void test_file_rename_information(void) pRtlDosPathNameToNtPathName_U( newpath, &name_str, NULL, NULL ); DeleteFileW( newpath ); fri = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_RENAME_INFORMATION) + name_str.Length ); - fri->Replace = FALSE; - fri->RootDir = NULL; + fri->ReplaceIfExists = FALSE; + fri->RootDirectory = NULL; fri->FileNameLength = name_str.Length; memcpy( fri->FileName, name_str.Buffer, name_str.Length ); pRtlFreeUnicodeString( &name_str ); @@ -1540,8 +1540,8 @@ static void test_file_rename_information(void) ok( res != 0, "failed to create temp file\n" ); pRtlDosPathNameToNtPathName_U( newpath, &name_str, NULL, NULL ); fri = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_RENAME_INFORMATION) + name_str.Length ); - fri->Replace = FALSE; - fri->RootDir = NULL; + fri->ReplaceIfExists = FALSE; + fri->RootDirectory = NULL; fri->FileNameLength = name_str.Length; memcpy( fri->FileName, name_str.Buffer, name_str.Length ); pRtlFreeUnicodeString( &name_str ); @@ -1570,8 +1570,8 @@ static void test_file_rename_information(void) ok( res != 0, "failed to create temp file\n" ); pRtlDosPathNameToNtPathName_U( newpath, &name_str, NULL, NULL ); fri = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_RENAME_INFORMATION) + name_str.Length ); - fri->Replace = TRUE; - fri->RootDir = NULL; + fri->ReplaceIfExists = TRUE; + fri->RootDirectory = NULL; fri->FileNameLength = name_str.Length; memcpy( fri->FileName, name_str.Buffer, name_str.Length ); pRtlFreeUnicodeString( &name_str ); @@ -1603,8 +1603,8 @@ static void test_file_rename_information(void)
pRtlDosPathNameToNtPathName_U( newpath, &name_str, NULL, NULL ); fri = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_RENAME_INFORMATION) + name_str.Length ); - fri->Replace = FALSE; - fri->RootDir = NULL; + fri->ReplaceIfExists = FALSE; + fri->RootDirectory = NULL; fri->FileNameLength = name_str.Length; memcpy( fri->FileName, name_str.Buffer, name_str.Length ); pRtlFreeUnicodeString( &name_str ); @@ -1637,8 +1637,8 @@ static void test_file_rename_information(void)
pRtlDosPathNameToNtPathName_U( newpath, &name_str, NULL, NULL ); fri = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_RENAME_INFORMATION) + name_str.Length ); - fri->Replace = TRUE; - fri->RootDir = NULL; + fri->ReplaceIfExists = TRUE; + fri->RootDirectory = NULL; fri->FileNameLength = name_str.Length; memcpy( fri->FileName, name_str.Buffer, name_str.Length ); pRtlFreeUnicodeString( &name_str ); @@ -1672,8 +1672,8 @@ static void test_file_rename_information(void) pRtlDosPathNameToNtPathName_U( newpath, &name_str, NULL, NULL ); DeleteFileW( newpath ); fri = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_RENAME_INFORMATION) + name_str.Length ); - fri->Replace = FALSE; - fri->RootDir = NULL; + fri->ReplaceIfExists = FALSE; + fri->RootDirectory = NULL; fri->FileNameLength = name_str.Length; memcpy( fri->FileName, name_str.Buffer, name_str.Length ); pRtlFreeUnicodeString( &name_str ); @@ -1719,8 +1719,8 @@ static void test_file_rename_information(void) pRtlDosPathNameToNtPathName_U( newpath, &name_str, NULL, NULL ); DeleteFileW( newpath ); fri = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_RENAME_INFORMATION) + name_str.Length ); - fri->Replace = FALSE; - fri->RootDir = NULL; + fri->ReplaceIfExists = FALSE; + fri->RootDirectory = NULL; fri->FileNameLength = name_str.Length; memcpy( fri->FileName, name_str.Buffer, name_str.Length ); pRtlFreeUnicodeString( &name_str ); @@ -1759,8 +1759,8 @@ static void test_file_rename_information(void) ok( res != 0, "failed to create temp file\n" ); pRtlDosPathNameToNtPathName_U( newpath, &name_str, NULL, NULL ); fri = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_RENAME_INFORMATION) + name_str.Length ); - fri->Replace = FALSE; - fri->RootDir = NULL; + fri->ReplaceIfExists = FALSE; + fri->RootDirectory = NULL; fri->FileNameLength = name_str.Length; memcpy( fri->FileName, name_str.Buffer, name_str.Length ); pRtlFreeUnicodeString( &name_str ); @@ -1795,8 +1795,8 @@ static void test_file_rename_information(void)
pRtlDosPathNameToNtPathName_U( newpath, &name_str, NULL, NULL ); fri = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_RENAME_INFORMATION) + name_str.Length ); - fri->Replace = FALSE; - fri->RootDir = NULL; + fri->ReplaceIfExists = FALSE; + fri->RootDirectory = NULL; fri->FileNameLength = name_str.Length; memcpy( fri->FileName, name_str.Buffer, name_str.Length ); pRtlFreeUnicodeString( &name_str ); @@ -1829,8 +1829,8 @@ static void test_file_rename_information(void) ok( res != 0, "failed to create temp file\n" ); pRtlDosPathNameToNtPathName_U( newpath, &name_str, NULL, NULL ); fri = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_RENAME_INFORMATION) + name_str.Length ); - fri->Replace = TRUE; - fri->RootDir = NULL; + fri->ReplaceIfExists = TRUE; + fri->RootDirectory = NULL; fri->FileNameLength = name_str.Length; memcpy( fri->FileName, name_str.Buffer, name_str.Length ); pRtlFreeUnicodeString( &name_str ); @@ -1865,8 +1865,8 @@ static void test_file_rename_information(void)
pRtlDosPathNameToNtPathName_U( newpath, &name_str, NULL, NULL ); fri = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_RENAME_INFORMATION) + name_str.Length ); - fri->Replace = TRUE; - fri->RootDir = NULL; + fri->ReplaceIfExists = TRUE; + fri->RootDirectory = NULL; fri->FileNameLength = name_str.Length; memcpy( fri->FileName, name_str.Buffer, name_str.Length ); pRtlFreeUnicodeString( &name_str ); @@ -1902,8 +1902,8 @@ static void test_file_rename_information(void) 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->Replace = FALSE; - fri->RootDir = NULL; + fri->ReplaceIfExists = FALSE; + fri->RootDirectory = NULL; fri->FileNameLength = name_str.Length; memcpy( fri->FileName, name_str.Buffer, name_str.Length ); pRtlFreeUnicodeString( &name_str ); @@ -1938,8 +1938,8 @@ static void test_file_rename_information(void) 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->Replace = TRUE; - fri->RootDir = NULL; + fri->ReplaceIfExists = TRUE; + fri->RootDirectory = NULL; fri->FileNameLength = name_str.Length; memcpy( fri->FileName, name_str.Buffer, name_str.Length ); pRtlFreeUnicodeString( &name_str ); @@ -1977,8 +1977,8 @@ static void test_file_rename_information(void)
pRtlDosPathNameToNtPathName_U( newpath, &name_str, NULL, NULL ); fri = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_RENAME_INFORMATION) + name_str.Length ); - fri->Replace = TRUE; - fri->RootDir = NULL; + fri->ReplaceIfExists = TRUE; + fri->RootDirectory = NULL; fri->FileNameLength = name_str.Length; memcpy( fri->FileName, name_str.Buffer, name_str.Length ); pRtlFreeUnicodeString( &name_str ); @@ -2011,8 +2011,8 @@ static void test_file_rename_information(void) 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->Replace = FALSE; - fri->RootDir = NULL; + fri->ReplaceIfExists = FALSE; + fri->RootDirectory = NULL; fri->FileNameLength = name_str.Length; memcpy( fri->FileName, name_str.Buffer, name_str.Length ); pRtlFreeUnicodeString( &name_str ); @@ -2044,8 +2044,8 @@ static void test_file_rename_information(void) 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->Replace = TRUE; - fri->RootDir = NULL; + fri->ReplaceIfExists = TRUE; + fri->RootDirectory = NULL; fri->FileNameLength = name_str.Length; memcpy( fri->FileName, name_str.Buffer, name_str.Length ); pRtlFreeUnicodeString( &name_str ); @@ -2079,8 +2079,8 @@ static void test_file_rename_information(void) ok( handle2 != INVALID_HANDLE_VALUE, "CreateFileW failed\n" );
fri = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_RENAME_INFORMATION) + lstrlenW(filename) * sizeof(WCHAR) ); - fri->Replace = FALSE; - fri->RootDir = handle2; + fri->ReplaceIfExists = FALSE; + fri->RootDirectory = handle2; fri->FileNameLength = lstrlenW(filename) * sizeof(WCHAR); memcpy( fri->FileName, filename, fri->FileNameLength );
diff --git a/include/winternl.h b/include/winternl.h index f55d275320a..d9809c7ad31 100644 --- a/include/winternl.h +++ b/include/winternl.h @@ -632,8 +632,8 @@ typedef struct _FILE_NAME_INFORMATION { } FILE_NAME_INFORMATION, *PFILE_NAME_INFORMATION;
typedef struct _FILE_RENAME_INFORMATION { - BOOLEAN Replace; - HANDLE RootDir; + BOOLEAN ReplaceIfExists; + HANDLE RootDirectory; ULONG FileNameLength; WCHAR FileName[1]; } FILE_RENAME_INFORMATION, *PFILE_RENAME_INFORMATION;
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/kernel32/tests/file.c | 94 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+)
diff --git a/dlls/kernel32/tests/file.c b/dlls/kernel32/tests/file.c index 1f704337877..ad0c694f410 100644 --- a/dlls/kernel32/tests/file.c +++ b/dlls/kernel32/tests/file.c @@ -5591,6 +5591,99 @@ static void test_hard_link(void) SetCurrentDirectoryA( cwd ); }
+static void test_move_file(void) +{ + char cwd[MAX_PATH], temp_dir[MAX_PATH]; + HANDLE file; + BOOL ret; + + GetCurrentDirectoryA( sizeof(cwd), cwd ); + GetTempPathA( sizeof(temp_dir), temp_dir ); + SetCurrentDirectoryA( temp_dir ); + + ret = CreateDirectoryA( "winetest_dir1", NULL ); + ok(ret, "failed to create directory, error %u\n", GetLastError()); + ret = CreateDirectoryA( "winetest_dir2", NULL ); + ok(ret, "failed to create directory, error %u\n", GetLastError()); + create_file( "winetest_file1" ); + create_file( "winetest_file2" ); + + ret = MoveFileA( "winetest_file1", "winetest_file3" ); + ok(ret, "failed to move file, error %u\n", GetLastError()); + ret = GetFileAttributesA( "winetest_file1" ); + ok(ret == INVALID_FILE_ATTRIBUTES, "got %#x\n", ret); + ret = GetFileAttributesA( "winetest_file3" ); + ok(ret != INVALID_FILE_ATTRIBUTES, "got %#x\n", ret); + + SetLastError(0xdeadbeef); + ret = MoveFileA( "winetest_file3", "winetest_file2" ); + ok(!ret, "expected failure\n"); + ok(GetLastError() == ERROR_ALREADY_EXISTS, "got error %u\n", GetLastError()); + + SetLastError(0xdeadbeef); + ret = MoveFileA( "winetest_file1", "winetest_file4" ); + ok(!ret, "expected failure\n"); + ok(GetLastError() == ERROR_FILE_NOT_FOUND, "got error %u\n", GetLastError()); + + ret = MoveFileA( "winetest_dir1", "winetest_dir3" ); + ok(ret, "failed to move file, error %u\n", GetLastError()); + + SetLastError(0xdeadbeef); + ret = MoveFileA( "winetest_dir3", "winetest_dir2" ); + ok(!ret, "expected failure\n"); + todo_wine ok(GetLastError() == ERROR_ALREADY_EXISTS, "got error %u\n", GetLastError()); + + file = CreateFileA( "winetest_file3", DELETE, 0, NULL, OPEN_EXISTING, 0, 0 ); + ok(file != INVALID_HANDLE_VALUE, "failed to open file, error %u\n", GetLastError()); + ret = MoveFileA( "winetest_file3", "winetest_file1" ); + ok(!ret, "expected failure\n"); + ok(GetLastError() == ERROR_SHARING_VIOLATION, "got error %u\n", GetLastError()); + CloseHandle( file ); + + file = CreateFileA( "winetest_file3", 0, 0, NULL, OPEN_EXISTING, 0, 0 ); + ok(file != INVALID_HANDLE_VALUE, "failed to open file, error %u\n", GetLastError()); + ret = MoveFileA( "winetest_file3", "winetest_file1" ); + ok(ret, "failed to move file, error %u\n", GetLastError()); + ret = GetFileAttributesA( "winetest_file1" ); + ok(ret != INVALID_FILE_ATTRIBUTES, "got %#x\n", ret); + ret = GetFileAttributesA( "winetest_file3" ); + ok(ret == INVALID_FILE_ATTRIBUTES, "got %#x\n", ret); + CloseHandle( file ); + + ret = MoveFileExA( "winetest_file1", "winetest_file2", MOVEFILE_REPLACE_EXISTING ); + ok(ret, "failed to move file, error %u\n", GetLastError()); + + file = CreateFileA( "winetest_file1", GENERIC_ALL, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, CREATE_NEW, 0, 0 ); + ok(file != INVALID_HANDLE_VALUE, "failed to open file, error %u\n", GetLastError()); + SetLastError(0xdeadbeef); + ret = MoveFileExA( "winetest_file2", "winetest_file1", MOVEFILE_REPLACE_EXISTING ); + todo_wine ok(!ret, "expected failure\n"); + todo_wine ok(GetLastError() == ERROR_ACCESS_DENIED, "got error %u\n", GetLastError()); + CloseHandle( file ); + + SetLastError(0xdeadbeef); + ret = MoveFileExA( "winetest_file2", "winetest_dir2", MOVEFILE_REPLACE_EXISTING ); + ok(!ret, "expected failure\n"); + todo_wine ok(GetLastError() == ERROR_ACCESS_DENIED, "got error %u\n", GetLastError()); + + SetLastError(0xdeadbeef); + ret = MoveFileExA( "winetest_dir3", "winetest_dir2", MOVEFILE_REPLACE_EXISTING ); + ok(!ret, "expected failure\n"); + ok(GetLastError() == ERROR_ACCESS_DENIED, "got error %u\n", GetLastError()); + + ret = MoveFileExA( "winetest_dir2", "winetest_file2", MOVEFILE_REPLACE_EXISTING ); + ok(ret, "failed to move file, error %u\n", GetLastError()); + + ret = RemoveDirectoryA( "winetest_dir3" ); + ok(ret, "failed to remove directory, error %u\n", GetLastError()); + ret = RemoveDirectoryA( "winetest_file2" ); + ok(ret, "failed to remove directory, error %u\n", GetLastError()); + ret = DeleteFileA( "winetest_file1" ); + ok(ret, "failed to delete file, error %u\n", GetLastError()); + SetCurrentDirectoryA( cwd ); +} + START_TEST(file) { char temp_path[MAX_PATH]; @@ -5666,4 +5759,5 @@ START_TEST(file) test_SetFileTime(); test_ReOpenFile(); test_hard_link(); + test_move_file(); }
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/ntdll/tests/file.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+)
diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c index 561cf800433..e0d4580ae04 100644 --- a/dlls/ntdll/tests/file.c +++ b/dlls/ntdll/tests/file.c @@ -2106,6 +2106,30 @@ static void test_file_rename_information(void) HeapFree( GetProcessHeap(), 0, fri ); delete_object( oldpath ); delete_object( newpath ); + + /* oldpath == newpath */ + 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" ); + + pRtlDosPathNameToNtPathName_U( oldpath, &name_str, NULL, NULL ); + fri = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_RENAME_INFORMATION) + name_str.Length ); + fri->ReplaceIfExists = FALSE; + fri->RootDirectory = NULL; + fri->FileNameLength = name_str.Length; + memcpy( fri->FileName, name_str.Buffer, name_str.Length ); + pRtlFreeUnicodeString( &name_str ); + + U(io).Status = 0xdeadbeef; + res = pNtSetInformationFile( handle, &io, fri, sizeof(FILE_RENAME_INFORMATION) + fri->FileNameLength, FileRenameInformation ); + todo_wine ok( U(io).Status == STATUS_SUCCESS, "got io status %#x\n", U(io).Status ); + todo_wine ok( res == STATUS_SUCCESS, "got status %x\n", res ); + ok( GetFileAttributesW( oldpath ) != INVALID_FILE_ATTRIBUTES, "file should exist\n" ); + + CloseHandle( handle ); + HeapFree( GetProcessHeap(), 0, fri ); + delete_object( oldpath ); }
static void test_file_link_information(void)
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/ntdll/file.c | 23 ++++++++++++++++++++++- dlls/ntdll/tests/file.c | 4 ++-- 2 files changed, 24 insertions(+), 3 deletions(-)
diff --git a/dlls/ntdll/file.c b/dlls/ntdll/file.c index 5ecf293820e..86b552dd1fc 100644 --- a/dlls/ntdll/file.c +++ b/dlls/ntdll/file.c @@ -2780,8 +2780,29 @@ NTSTATUS WINAPI NtSetInformationFile(HANDLE handle, PIO_STATUS_BLOCK io,
if (!info->ReplaceIfExists && io->u.Status == STATUS_SUCCESS) { + struct stat st, st2; + int fd; + + if ((io->u.Status = server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL ))) + { + RtlFreeAnsiString( &unix_name ); + break; + } + + if (fstat( fd, &st ) < 0 || stat( unix_name.Buffer, &st2 ) < 0) + { + RtlFreeAnsiString( &unix_name ); + io->u.Status = FILE_GetNtStatus(); + break; + } + + if (st.st_dev == st2.st_dev && st.st_ino == st2.st_ino) + io->u.Status = STATUS_SUCCESS; + else + io->u.Status = STATUS_OBJECT_NAME_COLLISION; + RtlFreeAnsiString( &unix_name ); - io->u.Status = STATUS_OBJECT_NAME_COLLISION; + if (needs_close) close( fd ); break; }
diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c index e0d4580ae04..bb4bf9df8ad 100644 --- a/dlls/ntdll/tests/file.c +++ b/dlls/ntdll/tests/file.c @@ -2123,8 +2123,8 @@ static void test_file_rename_information(void)
U(io).Status = 0xdeadbeef; res = pNtSetInformationFile( handle, &io, fri, sizeof(FILE_RENAME_INFORMATION) + fri->FileNameLength, FileRenameInformation ); - todo_wine ok( U(io).Status == STATUS_SUCCESS, "got io status %#x\n", U(io).Status ); - todo_wine ok( res == STATUS_SUCCESS, "got status %x\n", res ); + ok( U(io).Status == STATUS_SUCCESS, "got io status %#x\n", U(io).Status ); + ok( res == STATUS_SUCCESS, "got status %x\n", res ); ok( GetFileAttributesW( oldpath ) != INVALID_FILE_ATTRIBUTES, "file should exist\n" );
CloseHandle( handle );
Zebediah Figura z.figura12@gmail.com writes:
@@ -2780,8 +2780,29 @@ NTSTATUS WINAPI NtSetInformationFile(HANDLE handle, PIO_STATUS_BLOCK io,
if (!info->ReplaceIfExists && io->u.Status == STATUS_SUCCESS) {
struct stat st, st2;
int fd;
if ((io->u.Status = server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL )))
{
RtlFreeAnsiString( &unix_name );
break;
}
if (fstat( fd, &st ) < 0 || stat( unix_name.Buffer, &st2 ) < 0)
{
RtlFreeAnsiString( &unix_name );
io->u.Status = FILE_GetNtStatus();
break;
}
if (st.st_dev == st2.st_dev && st.st_ino == st2.st_ino)
io->u.Status = STATUS_SUCCESS;
else
io->u.Status = STATUS_OBJECT_NAME_COLLISION;
RtlFreeAnsiString( &unix_name );
io->u.Status = STATUS_OBJECT_NAME_COLLISION;
if (needs_close) close( fd );
I feel it would be cleaner to do that on the server side.
On 3/9/20 5:01 AM, Alexandre Julliard wrote:
Zebediah Figura z.figura12@gmail.com writes:
@@ -2780,8 +2780,29 @@ NTSTATUS WINAPI NtSetInformationFile(HANDLE handle, PIO_STATUS_BLOCK io,
if (!info->ReplaceIfExists && io->u.Status == STATUS_SUCCESS) {
struct stat st, st2;
int fd;
if ((io->u.Status = server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL )))
{
RtlFreeAnsiString( &unix_name );
break;
}
if (fstat( fd, &st ) < 0 || stat( unix_name.Buffer, &st2 ) < 0)
{
RtlFreeAnsiString( &unix_name );
io->u.Status = FILE_GetNtStatus();
break;
}
if (st.st_dev == st2.st_dev && st.st_ino == st2.st_ino)
io->u.Status = STATUS_SUCCESS;
else
io->u.Status = STATUS_OBJECT_NAME_COLLISION;
RtlFreeAnsiString( &unix_name );
io->u.Status = STATUS_OBJECT_NAME_COLLISION;
if (needs_close) close( fd );
I feel it would be cleaner to do that on the server side.
Sure, will do.
I guess that's necessary anyway, to fix bug 45935...
Same as MoveFileWithProgressW().
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- v2: Fix apply failures...
server/fd.c | 10 ++++++++++ server/file.c | 9 +++++++-- server/file.h | 1 + 3 files changed, 18 insertions(+), 2 deletions(-)
diff --git a/server/fd.c b/server/fd.c index 5d80e218b97..0be5cf0f7c6 100644 --- a/server/fd.c +++ b/server/fd.c @@ -2413,6 +2413,16 @@ static void set_fd_name( struct fd *fd, struct fd *root, const char *nameptr, goto failed; }
+ if (is_file_executable( fd->unix_name ) != is_file_executable( name ) && !fstat( fd->unix_fd, &st )) + { + if (is_file_executable( fd->unix_name )) + /* set executable bit where read bit is set */ + st.st_mode |= (st.st_mode & 0444) >> 2; + else + st.st_mode &= ~0111; + fchmod( fd->unix_fd, st.st_mode ); + } + free( fd->unix_name ); fd->unix_name = name; fd->closed->unix_name = name; diff --git a/server/file.c b/server/file.c index 71b84486b0f..bce202138e0 100644 --- a/server/file.c +++ b/server/file.c @@ -191,6 +191,12 @@ static struct object *create_file_obj( struct fd *fd, unsigned int access, mode_ return &file->obj; }
+int is_file_executable( const char *name ) +{ + int len = strlen( name ); + return len >= 4 && (!strcasecmp( name + len - 4, ".exe") || !strcasecmp( name + len - 4, ".com" )); +} + static struct object *create_file( struct fd *root, const char *nameptr, data_size_t len, unsigned int access, unsigned int sharing, int create, unsigned int options, unsigned int attrs, @@ -236,8 +242,7 @@ static struct object *create_file( struct fd *root, const char *nameptr, data_si else mode = (attrs & FILE_ATTRIBUTE_READONLY) ? 0444 : 0666;
- if (len >= 4 && - (!strcasecmp( name + len - 4, ".exe" ) || !strcasecmp( name + len - 4, ".com" ))) + if (is_file_executable( name )) { if (mode & S_IRUSR) mode |= S_IXUSR; diff --git a/server/file.h b/server/file.h index 4341ad3b040..0df4c177162 100644 --- a/server/file.h +++ b/server/file.h @@ -149,6 +149,7 @@ extern void file_set_error(void); extern struct object_type *file_get_type( struct object *obj ); extern struct security_descriptor *mode_to_sd( mode_t mode, const SID *user, const SID *group ); extern mode_t sd_to_mode( const struct security_descriptor *sd, const SID *owner ); +extern int is_file_executable( const char *name );
/* file mapping functions */
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/kernel32/path.c | 104 +++++++------------------------------ dlls/kernel32/tests/file.c | 8 +-- 2 files changed, 22 insertions(+), 90 deletions(-)
diff --git a/dlls/kernel32/path.c b/dlls/kernel32/path.c index 617b14a7178..31652d3164b 100644 --- a/dlls/kernel32/path.c +++ b/dlls/kernel32/path.c @@ -448,14 +448,14 @@ BOOL WINAPI MoveFileWithProgressW( LPCWSTR source, LPCWSTR dest, LPPROGRESS_ROUTINE fnProgress, LPVOID param, DWORD flag ) { + FILE_RENAME_INFORMATION *rename_info; FILE_BASIC_INFORMATION info; UNICODE_STRING nt_name; OBJECT_ATTRIBUTES attr; IO_STATUS_BLOCK io; NTSTATUS status; - HANDLE source_handle = 0, dest_handle = 0; - ANSI_STRING source_unix, dest_unix; - DWORD options; + HANDLE source_handle = 0; + ULONG size;
TRACE("(%s,%s,%p,%p,%04x)\n", debugstr_w(source), debugstr_w(dest), fnProgress, param, flag ); @@ -473,8 +473,6 @@ BOOL WINAPI MoveFileWithProgressW( LPCWSTR source, LPCWSTR dest, SetLastError( ERROR_PATH_NOT_FOUND ); return FALSE; } - source_unix.Buffer = NULL; - dest_unix.Buffer = NULL; attr.Length = sizeof(attr); attr.RootDirectory = 0; attr.Attributes = OBJ_CASE_INSENSITIVE; @@ -484,8 +482,6 @@ BOOL WINAPI MoveFileWithProgressW( LPCWSTR source, LPCWSTR dest,
status = NtOpenFile( &source_handle, DELETE | SYNCHRONIZE, &attr, &io, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_SYNCHRONOUS_IO_NONALERT ); - if (status == STATUS_SUCCESS) - status = wine_nt_to_unix_file_name( &nt_name, &source_unix, FILE_OPEN, FALSE ); RtlFreeUnicodeString( &nt_name ); if (status != STATUS_SUCCESS) { @@ -499,101 +495,37 @@ BOOL WINAPI MoveFileWithProgressW( LPCWSTR source, LPCWSTR dest, goto error; }
- /* we must have write access to the destination, and it must */ - /* not exist except if MOVEFILE_REPLACE_EXISTING is set */ - if (!RtlDosPathNameToNtPathName_U( dest, &nt_name, NULL, NULL )) { SetLastError( ERROR_PATH_NOT_FOUND ); goto error; } - options = FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT; - if (flag & MOVEFILE_WRITE_THROUGH) - options |= FILE_WRITE_THROUGH; - status = NtOpenFile( &dest_handle, GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE, &attr, &io, - FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, options ); - if (status == STATUS_SUCCESS) /* destination exists */ - { - if (!(flag & MOVEFILE_REPLACE_EXISTING)) - { - if (!is_same_file( source_handle, dest_handle )) - { - SetLastError( ERROR_ALREADY_EXISTS ); - RtlFreeUnicodeString( &nt_name ); - goto error; - } - } - else if (info.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) /* cannot replace directory */ - { - SetLastError( ERROR_ACCESS_DENIED ); - goto error; - }
- NtClose( dest_handle ); - dest_handle = NULL; - } - else if (status != STATUS_OBJECT_NAME_NOT_FOUND) - { - SetLastError( RtlNtStatusToDosError(status) ); - RtlFreeUnicodeString( &nt_name ); + size = offsetof( FILE_RENAME_INFORMATION, FileName ) + nt_name.Length; + if (!(rename_info = HeapAlloc( GetProcessHeap(), 0, size ))) goto error; - }
- status = wine_nt_to_unix_file_name( &nt_name, &dest_unix, FILE_OPEN_IF, FALSE ); + rename_info->ReplaceIfExists = !!(flag & MOVEFILE_REPLACE_EXISTING); + rename_info->RootDirectory = NULL; + rename_info->FileNameLength = nt_name.Length; + memcpy( rename_info->FileName, nt_name.Buffer, nt_name.Length ); RtlFreeUnicodeString( &nt_name ); - if (status != STATUS_SUCCESS && status != STATUS_NO_SUCH_FILE) - { - SetLastError( RtlNtStatusToDosError(status) ); - goto error; - } - - /* now perform the rename */ - - if (rename( source_unix.Buffer, dest_unix.Buffer ) == -1) + status = NtSetInformationFile( source_handle, &io, rename_info, size, FileRenameInformation ); + if (status == STATUS_NOT_SAME_DEVICE && (flag & MOVEFILE_COPY_ALLOWED)) { - if (errno == EXDEV && (flag & MOVEFILE_COPY_ALLOWED)) - { - NtClose( source_handle ); - RtlFreeAnsiString( &source_unix ); - RtlFreeAnsiString( &dest_unix ); - if (!CopyFileExW( source, dest, fnProgress, param, NULL, - flag & MOVEFILE_REPLACE_EXISTING ? - 0 : COPY_FILE_FAIL_IF_EXISTS )) - return FALSE; - return DeleteFileW( source ); - } - FILE_SetDosError(); - /* if we created the destination, remove it */ - if (io.Information == FILE_CREATED) unlink( dest_unix.Buffer ); - goto error; - } - - /* fixup executable permissions */ - - if (is_executable( source ) != is_executable( dest )) - { - struct stat fstat; - if (stat( dest_unix.Buffer, &fstat ) != -1) - { - if (is_executable( dest )) - /* set executable bit where read bit is set */ - fstat.st_mode |= (fstat.st_mode & 0444) >> 2; - else - fstat.st_mode &= ~0111; - chmod( dest_unix.Buffer, fstat.st_mode ); - } + NtClose( source_handle ); + if (!CopyFileExW( source, dest, fnProgress, param, NULL, + flag & MOVEFILE_REPLACE_EXISTING ? + 0 : COPY_FILE_FAIL_IF_EXISTS )) + return FALSE; + return DeleteFileW( source ); }
NtClose( source_handle ); - RtlFreeAnsiString( &source_unix ); - RtlFreeAnsiString( &dest_unix ); - return TRUE; + return set_ntstatus( status );
error: if (source_handle) NtClose( source_handle ); - if (dest_handle) NtClose( dest_handle ); - RtlFreeAnsiString( &source_unix ); - RtlFreeAnsiString( &dest_unix ); return FALSE; }
diff --git a/dlls/kernel32/tests/file.c b/dlls/kernel32/tests/file.c index ad0c694f410..785bd60c237 100644 --- a/dlls/kernel32/tests/file.c +++ b/dlls/kernel32/tests/file.c @@ -5631,7 +5631,7 @@ static void test_move_file(void) SetLastError(0xdeadbeef); ret = MoveFileA( "winetest_dir3", "winetest_dir2" ); ok(!ret, "expected failure\n"); - todo_wine ok(GetLastError() == ERROR_ALREADY_EXISTS, "got error %u\n", GetLastError()); + ok(GetLastError() == ERROR_ALREADY_EXISTS, "got error %u\n", GetLastError());
file = CreateFileA( "winetest_file3", DELETE, 0, NULL, OPEN_EXISTING, 0, 0 ); ok(file != INVALID_HANDLE_VALUE, "failed to open file, error %u\n", GetLastError()); @@ -5658,14 +5658,14 @@ static void test_move_file(void) ok(file != INVALID_HANDLE_VALUE, "failed to open file, error %u\n", GetLastError()); SetLastError(0xdeadbeef); ret = MoveFileExA( "winetest_file2", "winetest_file1", MOVEFILE_REPLACE_EXISTING ); - todo_wine ok(!ret, "expected failure\n"); - todo_wine ok(GetLastError() == ERROR_ACCESS_DENIED, "got error %u\n", GetLastError()); + ok(!ret, "expected failure\n"); + ok(GetLastError() == ERROR_ACCESS_DENIED, "got error %u\n", GetLastError()); CloseHandle( file );
SetLastError(0xdeadbeef); ret = MoveFileExA( "winetest_file2", "winetest_dir2", MOVEFILE_REPLACE_EXISTING ); ok(!ret, "expected failure\n"); - todo_wine ok(GetLastError() == ERROR_ACCESS_DENIED, "got error %u\n", GetLastError()); + ok(GetLastError() == ERROR_ACCESS_DENIED, "got error %u\n", GetLastError());
SetLastError(0xdeadbeef); ret = MoveFileExA( "winetest_dir3", "winetest_dir2", MOVEFILE_REPLACE_EXISTING );