diff --git a/README.md b/README.md index a95a0363..09423ec0 100644 --- a/README.md +++ b/README.md @@ -152,7 +152,7 @@ for more details.* * Fix handling of ANSI NTLM credentials ([Wine Bug #37063](https://bugs.winehq.org/show_bug.cgi?id=37063)) * Fix handling of empty section and key name for profile files. ([Wine Bug #8036](https://bugs.winehq.org/show_bug.cgi?id=8036)) * Fix handling of invert_y in DrawTextExW ([Wine Bug #22109](https://bugs.winehq.org/show_bug.cgi?id=22109)) -* Fix handling of opening a file with RootDirectory pointing to a file handle +* ~~Fix handling of opening a file with RootDirectory pointing to a file handle~~ * Fix handling of opening read-only files for FILE_DELETE_ON_CLOSE ([Wine Bug #38417](https://bugs.winehq.org/show_bug.cgi?id=38417)) * Fix handling of window attributes for WS_EX_LAYERED | WS_EX_COMPOSITED ([Wine Bug #37876](https://bugs.winehq.org/show_bug.cgi?id=37876)) * Fix issues with dragging layers between images in Adobe Photoshop 7.0 ([Wine Bug #12007](https://bugs.winehq.org/show_bug.cgi?id=12007)) @@ -263,7 +263,7 @@ for more details.* * Support for NVIDIA video encoder library (nvencodeapi) * Support for NtQuerySection ([Wine Bug #37338](https://bugs.winehq.org/show_bug.cgi?id=37338)) * ~~Support for NtSetInformationFile class FileDispositionInformation~~ ([Wine Bug #30397](https://bugs.winehq.org/show_bug.cgi?id=30397)) -* Support for NtSetInformationFile class FileLinkInformation +* ~~Support for NtSetInformationFile class FileLinkInformation~~ * ~~Support for NtSetInformationFile class FileRenameInformation~~ ([Wine Bug #30399](https://bugs.winehq.org/show_bug.cgi?id=30399)) * Support for PulseAudio backend for audio ([Wine Bug #10495](https://bugs.winehq.org/show_bug.cgi?id=10495)) * Support for SHCreateSessionKey ([Wine Bug #35630](https://bugs.winehq.org/show_bug.cgi?id=35630)) diff --git a/patches/ntdll-FileDispositionInformation/0003-server-When-combining-root-and-name-make-sure-there-.patch b/patches/ntdll-FileDispositionInformation/0003-server-When-combining-root-and-name-make-sure-there-.patch index 9a076718..996cd963 100644 --- a/patches/ntdll-FileDispositionInformation/0003-server-When-combining-root-and-name-make-sure-there-.patch +++ b/patches/ntdll-FileDispositionInformation/0003-server-When-combining-root-and-name-make-sure-there-.patch @@ -1,4 +1,4 @@ -From 4c33b67050e2dc88ab8f1e08f4b2559132a50262 Mon Sep 17 00:00:00 2001 +From b4eabfd0a1eaca783c6a0fe35de8b1166412f078 Mon Sep 17 00:00:00 2001 From: Sebastian Lackner Date: Wed, 3 Jun 2015 01:37:34 +0200 Subject: server: When combining root and name, make sure there is only one @@ -12,10 +12,10 @@ Changes in v2: 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c -index 99aaa37..d1055e8 100644 +index 440cfaa..40c932b 100644 --- a/dlls/ntdll/tests/file.c +++ b/dlls/ntdll/tests/file.c -@@ -2068,8 +2068,8 @@ static void test_file_rename_information(void) +@@ -2111,8 +2111,8 @@ static void test_file_rename_information(void) res = pNtQueryInformationFile( handle, &io, fni, sizeof(FILE_NAME_INFORMATION) + MAX_PATH * sizeof(WCHAR), FileNameInformation ); ok( res == STATUS_SUCCESS, "res expected STATUS_SUCCESS, got %x\n", res ); fni->FileName[ fni->FileNameLength / sizeof(WCHAR) ] = 0; @@ -27,18 +27,18 @@ index 99aaa37..d1055e8 100644 CloseHandle( handle ); diff --git a/server/fd.c b/server/fd.c -index 04891e7..c0b5548 100644 +index b30ae11..07e0fc5 100644 --- a/server/fd.c +++ b/server/fd.c @@ -1720,6 +1720,7 @@ void set_fd_user( struct fd *fd, const struct fd_ops *user_ops, struct object *u - static char *dup_fd_name( struct fd *root, const char *name ) + char *dup_fd_name( struct fd *root, const char *name ) { char *ret; + int len; if (!root) return strdup( name ); if (!root->unix_name) return NULL; -@@ -1727,11 +1728,18 @@ static char *dup_fd_name( struct fd *root, const char *name ) +@@ -1727,11 +1728,18 @@ char *dup_fd_name( struct fd *root, const char *name ) /* skip . prefix */ if (name[0] == '.' && (!name[1] || name[1] == '/')) name++; diff --git a/patches/ntdll-FileDispositionInformation/0004-ntdll-tests-Add-tests-for-FileLinkInformation-class.patch b/patches/ntdll-FileDispositionInformation/0004-ntdll-tests-Add-tests-for-FileLinkInformation-class.patch deleted file mode 100644 index 4958ec42..00000000 --- a/patches/ntdll-FileDispositionInformation/0004-ntdll-tests-Add-tests-for-FileLinkInformation-class.patch +++ /dev/null @@ -1,730 +0,0 @@ -From 3a74e4ad232bb6c15925d15225c0ec039143177b Mon Sep 17 00:00:00 2001 -From: Qian Hong -Date: Wed, 3 Jun 2015 17:41:59 +0800 -Subject: ntdll/tests: Add tests for FileLinkInformation class. - -Mostly copy and paste from Sebastian Lackner's FileNameInformation class -tests, credit to Sebastian. ---- - dlls/ntdll/tests/file.c | 698 ++++++++++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 698 insertions(+) - -diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c -index d1055e8..177c2c5 100644 ---- a/dlls/ntdll/tests/file.c -+++ b/dlls/ntdll/tests/file.c -@@ -2079,6 +2079,703 @@ static void test_file_rename_information(void) - delete_object( newpath ); - } - -+static void test_file_link_information(void) -+{ -+ static const WCHAR foo_txtW[] = {'\\','f','o','o','.','t','x','t',0}; -+ static const WCHAR fooW[] = {'f','o','o',0}; -+ WCHAR tmp_path[MAX_PATH], oldpath[MAX_PATH + 16], newpath[MAX_PATH + 16], *filename, *p; -+ FILE_LINK_INFORMATION *fli; -+ FILE_NAME_INFORMATION *fni; -+ BOOL success, fileDeleted; -+ UNICODE_STRING name_str; -+ HANDLE handle, handle2; -+ IO_STATUS_BLOCK io; -+ NTSTATUS res; -+ -+ GetTempPathW( MAX_PATH, tmp_path ); -+ -+ /* oldpath is a file, newpath doesn't exist */ -+ 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" ); -+ pRtlDosPathNameToNtPathName_U( newpath, &name_str, NULL, NULL ); -+ DeleteFileW( newpath ); -+ fli = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_LINK_INFORMATION) + name_str.Length ); -+ fli->ReplaceIfExists = FALSE; -+ fli->RootDirectory = NULL; -+ fli->FileNameLength = name_str.Length; -+ memcpy( fli->FileName, name_str.Buffer, name_str.Length ); -+ pRtlFreeUnicodeString( &name_str ); -+ -+ U(io).Status = 0xdeadbeef; -+ res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, FileLinkInformation ); -+ todo_wine ok( U(io).Status == STATUS_SUCCESS, "io.Status expected STATUS_SUCCESS, got %x\n", U(io).Status ); -+ todo_wine ok( res == STATUS_SUCCESS, "res expected STATUS_SUCCESS, got %x\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 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 %x\n", res ); -+ fni->FileName[ fni->FileNameLength / sizeof(WCHAR) ] = 0; -+ ok( !lstrcmpW(fni->FileName, oldpath + 2), "FileName expected %s, got %s\n", -+ wine_dbgstr_w(oldpath + 2), wine_dbgstr_w(fni->FileName) ); -+ HeapFree( GetProcessHeap(), 0, fni ); -+ -+ CloseHandle( handle ); -+ HeapFree( GetProcessHeap(), 0, fli ); -+ delete_object( oldpath ); -+ delete_object( newpath ); -+ -+ /* oldpath is a file, newpath is a file, ReplaceIfExists = FALSE */ -+ 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" ); -+ pRtlDosPathNameToNtPathName_U( newpath, &name_str, NULL, NULL ); -+ fli = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_LINK_INFORMATION) + name_str.Length ); -+ fli->ReplaceIfExists = FALSE; -+ fli->RootDirectory = NULL; -+ fli->FileNameLength = name_str.Length; -+ memcpy( fli->FileName, name_str.Buffer, name_str.Length ); -+ pRtlFreeUnicodeString( &name_str ); -+ -+ U(io).Status = 0xdeadbeef; -+ res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, FileLinkInformation ); -+ todo_wine ok( U(io).Status == 0xdeadbeef, "io.Status expected 0xdeadbeef, got %x\n", U(io).Status ); -+ todo_wine ok( res == STATUS_OBJECT_NAME_COLLISION, "res expected STATUS_OBJECT_NAME_COLLISION, got %x\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 file, ReplaceIfExists = FALSE, target file opened */ -+ 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->ReplaceIfExists = FALSE; -+ fli->RootDirectory = NULL; -+ fli->FileNameLength = name_str.Length; -+ memcpy( fli->FileName, name_str.Buffer, name_str.Length ); -+ pRtlFreeUnicodeString( &name_str ); -+ -+ U(io).Status = 0xdeadbeef; -+ res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, FileLinkInformation ); -+ todo_wine ok( U(io).Status == 0xdeadbeef, "io.Status expected 0xdeadbeef, got %x\n", U(io).Status ); -+ todo_wine ok( res == STATUS_OBJECT_NAME_COLLISION, "res expected STATUS_OBJECT_NAME_COLLISION, got %x\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, ReplaceIfExists = TRUE */ -+ 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" ); -+ pRtlDosPathNameToNtPathName_U( newpath, &name_str, NULL, NULL ); -+ fli = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_LINK_INFORMATION) + name_str.Length ); -+ fli->ReplaceIfExists = TRUE; -+ fli->RootDirectory = NULL; -+ fli->FileNameLength = name_str.Length; -+ memcpy( fli->FileName, name_str.Buffer, name_str.Length ); -+ pRtlFreeUnicodeString( &name_str ); -+ -+ U(io).Status = 0xdeadbeef; -+ res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, FileLinkInformation ); -+ todo_wine ok( U(io).Status == STATUS_SUCCESS, "io.Status expected STATUS_SUCCESS, got %x\n", U(io).Status ); -+ todo_wine ok( res == STATUS_SUCCESS, "res expected STATUS_SUCCESS, got %x\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 file, ReplaceIfExists = TRUE, target file opened */ -+ 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->ReplaceIfExists = TRUE; -+ fli->RootDirectory = NULL; -+ fli->FileNameLength = name_str.Length; -+ memcpy( fli->FileName, name_str.Buffer, name_str.Length ); -+ pRtlFreeUnicodeString( &name_str ); -+ -+ U(io).Status = 0xdeadbeef; -+ res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, FileLinkInformation ); -+ todo_wine ok( U(io).Status == 0xdeadbeef, "io.Status expected 0xdeadbeef, got %x\n", U(io).Status ); -+ todo_wine ok( res == STATUS_ACCESS_DENIED, "res expected STATUS_ACCESS_DENIED, got %x\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, ReplaceIfExists = TRUE, target file opened with FILE_SHARE_DELETE */ -+ 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->ReplaceIfExists = TRUE; -+ fli->RootDirectory = NULL; -+ fli->FileNameLength = name_str.Length; -+ memcpy( fli->FileName, name_str.Buffer, name_str.Length ); -+ pRtlFreeUnicodeString( &name_str ); -+ -+ U(io).Status = 0xdeadbeef; -+ res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, FileLinkInformation ); -+ todo_wine ok( U(io).Status == 0xdeadbeef, "io.Status expected 0xdeadbeef, got %x\n", U(io).Status ); -+ todo_wine ok( res == STATUS_ACCESS_DENIED, "res expected STATUS_ACCESS_DENIED, got %x\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, ReplaceIfExists = TRUE, target file opened with FILE_SHARE_DELETE | FILE_SHARE_WRITE */ -+ 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 | FILE_SHARE_WRITE, 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->ReplaceIfExists = TRUE; -+ fli->RootDirectory = NULL; -+ fli->FileNameLength = name_str.Length; -+ memcpy( fli->FileName, name_str.Buffer, name_str.Length ); -+ pRtlFreeUnicodeString( &name_str ); -+ -+ U(io).Status = 0xdeadbeef; -+ res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, FileLinkInformation ); -+ todo_wine ok( U(io).Status == 0xdeadbeef, "io.Status expected 0xdeadbeef, got %x\n", U(io).Status ); -+ todo_wine ok( res == STATUS_ACCESS_DENIED, "res expected STATUS_ACCESS_DENIED, got %x\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 doesn't exist, ReplaceIfExists = FALSE */ -+ 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" ); -+ pRtlDosPathNameToNtPathName_U( newpath, &name_str, NULL, NULL ); -+ DeleteFileW( newpath ); -+ fli = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_LINK_INFORMATION) + name_str.Length ); -+ fli->ReplaceIfExists = FALSE; -+ fli->RootDirectory = NULL; -+ fli->FileNameLength = name_str.Length; -+ memcpy( fli->FileName, name_str.Buffer, name_str.Length ); -+ pRtlFreeUnicodeString( &name_str ); -+ -+ U(io).Status = 0xdeadbeef; -+ res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, FileLinkInformation ); -+ todo_wine ok( U(io).Status == 0xdeadbeef , "io.Status expected 0xdeadbeef, got %x\n", U(io).Status ); -+ todo_wine ok( res == STATUS_FILE_IS_A_DIRECTORY, "res expected STATUS_FILE_IS_A_DIRECTORY, got %x\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 not 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 %x\n", res ); -+ fni->FileName[ fni->FileNameLength / sizeof(WCHAR) ] = 0; -+ ok( !lstrcmpW(fni->FileName, oldpath + 2), "FileName expected %s, got %s\n", -+ wine_dbgstr_w(oldpath + 2), wine_dbgstr_w(fni->FileName) ); -+ HeapFree( GetProcessHeap(), 0, fni ); -+ -+ CloseHandle( handle ); -+ HeapFree( GetProcessHeap(), 0, fli ); -+ delete_object( oldpath ); -+ delete_object( newpath ); -+ -+ /* oldpath is a directory (but child object opened), newpath doesn't exist, ReplaceIfExists = FALSE */ -+ 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" ); -+ -+ lstrcpyW( newpath, oldpath ); -+ lstrcatW( newpath, foo_txtW ); -+ handle2 = CreateFileW( newpath, GENERIC_WRITE | DELETE, 0, NULL, CREATE_ALWAYS, FILE_FLAG_DELETE_ON_CLOSE, 0 ); -+ ok( handle2 != INVALID_HANDLE_VALUE, "CreateFileW failed\n" ); -+ -+ res = GetTempFileNameW( tmp_path, fooW, 0, newpath ); -+ ok( res != 0, "failed to create temp file\n" ); -+ pRtlDosPathNameToNtPathName_U( newpath, &name_str, NULL, NULL ); -+ DeleteFileW( newpath ); -+ fli = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_LINK_INFORMATION) + name_str.Length ); -+ fli->ReplaceIfExists = FALSE; -+ fli->RootDirectory = NULL; -+ fli->FileNameLength = name_str.Length; -+ memcpy( fli->FileName, name_str.Buffer, name_str.Length ); -+ pRtlFreeUnicodeString( &name_str ); -+ -+ U(io).Status = 0xdeadbeef; -+ res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, FileLinkInformation ); -+ todo_wine ok( U(io).Status == 0xdeadbeef, "io.Status expected 0xdeadbeef, got %x\n", U(io).Status ); -+ todo_wine ok( res == STATUS_FILE_IS_A_DIRECTORY, "res expected STATUS_FILE_IS_A_DIRECTORY, got %x\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 not exist\n" ); -+ -+ CloseHandle( handle ); -+ CloseHandle( handle2 ); -+ HeapFree( GetProcessHeap(), 0, fli ); -+ delete_object( oldpath ); -+ delete_object( newpath ); -+ -+ /* oldpath is a directory, newpath is a file, ReplaceIfExists = FALSE */ -+ 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" ); -+ pRtlDosPathNameToNtPathName_U( newpath, &name_str, NULL, NULL ); -+ fli = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_LINK_INFORMATION) + name_str.Length ); -+ fli->ReplaceIfExists = FALSE; -+ fli->RootDirectory = NULL; -+ fli->FileNameLength = name_str.Length; -+ memcpy( fli->FileName, name_str.Buffer, name_str.Length ); -+ pRtlFreeUnicodeString( &name_str ); -+ -+ U(io).Status = 0xdeadbeef; -+ res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, FileLinkInformation ); -+ todo_wine ok( U(io).Status == 0xdeadbeef, "io.Status expected 0xdeadbeef, got %x\n", U(io).Status ); -+ todo_wine 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 %x\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 directory, newpath is a file, ReplaceIfExists = FALSE, 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, 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->ReplaceIfExists = FALSE; -+ fli->RootDirectory = NULL; -+ fli->FileNameLength = name_str.Length; -+ memcpy( fli->FileName, name_str.Buffer, name_str.Length ); -+ pRtlFreeUnicodeString( &name_str ); -+ -+ U(io).Status = 0xdeadbeef; -+ res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, FileLinkInformation ); -+ todo_wine ok( U(io).Status == 0xdeadbeef, "io.Status expected 0xdeadbeef, got %x\n", U(io).Status ); -+ todo_wine 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 %x\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, ReplaceIfExists = TRUE */ -+ 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" ); -+ pRtlDosPathNameToNtPathName_U( newpath, &name_str, NULL, NULL ); -+ fli = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_LINK_INFORMATION) + name_str.Length ); -+ fli->ReplaceIfExists = TRUE; -+ fli->RootDirectory = NULL; -+ fli->FileNameLength = name_str.Length; -+ memcpy( fli->FileName, name_str.Buffer, name_str.Length ); -+ pRtlFreeUnicodeString( &name_str ); -+ -+ U(io).Status = 0xdeadbeef; -+ res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, FileLinkInformation ); -+ todo_wine ok( U(io).Status == 0xdeadbeef, "io.Status expected 0xdeadbeef, got %x\n", U(io).Status ); -+ todo_wine ok( res == STATUS_FILE_IS_A_DIRECTORY, "res expected STATUS_FILE_IS_A_DIRECTORY, got %x\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 directory, newpath is a file, ReplaceIfExists = TRUE, 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, 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->ReplaceIfExists = TRUE; -+ fli->RootDirectory = NULL; -+ fli->FileNameLength = name_str.Length; -+ memcpy( fli->FileName, name_str.Buffer, name_str.Length ); -+ pRtlFreeUnicodeString( &name_str ); -+ -+ U(io).Status = 0xdeadbeef; -+ res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, FileLinkInformation ); -+ todo_wine ok( U(io).Status == 0xdeadbeef, "io.Status expected 0xdeadbeef, got %x\n", U(io).Status ); -+ todo_wine ok( res == STATUS_FILE_IS_A_DIRECTORY, "res expected STATUS_FILE_IS_A_DIRECTORY, got %x\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, ReplaceIfExists = FALSE */ -+ 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" ); -+ pRtlDosPathNameToNtPathName_U( newpath, &name_str, NULL, NULL ); -+ fli = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_LINK_INFORMATION) + name_str.Length ); -+ fli->ReplaceIfExists = FALSE; -+ fli->RootDirectory = NULL; -+ fli->FileNameLength = name_str.Length; -+ memcpy( fli->FileName, name_str.Buffer, name_str.Length ); -+ pRtlFreeUnicodeString( &name_str ); -+ -+ U(io).Status = 0xdeadbeef; -+ res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, FileLinkInformation ); -+ todo_wine ok( U(io).Status == 0xdeadbeef, "io.Status expected 0xdeadbeef, got %x\n", U(io).Status ); -+ todo_wine 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 %x\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 directory, newpath is a directory, ReplaceIfExists = TRUE */ -+ 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" ); -+ pRtlDosPathNameToNtPathName_U( newpath, &name_str, NULL, NULL ); -+ fli = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_LINK_INFORMATION) + name_str.Length ); -+ fli->ReplaceIfExists = TRUE; -+ fli->RootDirectory = NULL; -+ fli->FileNameLength = name_str.Length; -+ memcpy( fli->FileName, name_str.Buffer, name_str.Length ); -+ pRtlFreeUnicodeString( &name_str ); -+ -+ U(io).Status = 0xdeadbeef; -+ res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, FileLinkInformation ); -+ todo_wine ok( U(io).Status == 0xdeadbeef, "io.Status expected 0xdeadbeef, got %x\n", U(io).Status ); -+ todo_wine ok( res == STATUS_FILE_IS_A_DIRECTORY, "res expected STATUS_FILE_IS_A_DIRECTORY, got %x\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 directory, newpath is a directory, ReplaceIfExists = TRUE, 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, 0, 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->ReplaceIfExists = TRUE; -+ fli->RootDirectory = NULL; -+ fli->FileNameLength = name_str.Length; -+ memcpy( fli->FileName, name_str.Buffer, name_str.Length ); -+ pRtlFreeUnicodeString( &name_str ); -+ -+ U(io).Status = 0xdeadbeef; -+ res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, FileLinkInformation ); -+ todo_wine ok( U(io).Status == 0xdeadbeef, "io.Status expected 0xdeadbeef, got %x\n", U(io).Status ); -+ todo_wine ok( res == STATUS_FILE_IS_A_DIRECTORY, "res expected STATUS_FILE_IS_A_DIRECTORY, got %x\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, ReplaceIfExists = FALSE */ -+ 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->ReplaceIfExists = FALSE; -+ fli->RootDirectory = NULL; -+ fli->FileNameLength = name_str.Length; -+ memcpy( fli->FileName, name_str.Buffer, name_str.Length ); -+ pRtlFreeUnicodeString( &name_str ); -+ -+ U(io).Status = 0xdeadbeef; -+ res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, FileLinkInformation ); -+ todo_wine ok( U(io).Status == 0xdeadbeef, "io.Status expected 0xdeadbeef, got %x\n", U(io).Status ); -+ todo_wine ok( res == STATUS_OBJECT_NAME_COLLISION, "res expected STATUS_OBJECT_NAME_COLLISION, got %x\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 directory, ReplaceIfExists = TRUE */ -+ 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->ReplaceIfExists = TRUE; -+ fli->RootDirectory = NULL; -+ fli->FileNameLength = name_str.Length; -+ memcpy( fli->FileName, name_str.Buffer, name_str.Length ); -+ pRtlFreeUnicodeString( &name_str ); -+ -+ U(io).Status = 0xdeadbeef; -+ res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, FileLinkInformation ); -+ todo_wine ok( U(io).Status == 0xdeadbeef, "io.Status expected 0xdeadbeef, got %x\n", U(io).Status ); -+ todo_wine ok( res == STATUS_ACCESS_DENIED, "res expected STATUS_ACCESS_DENIED, got %x\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 doesn't exist, test with RootDirectory != NULL */ -+ 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 ); -+ for (filename = newpath, p = newpath; *p; p++) -+ if (*p == '\\') filename = p + 1; -+ handle2 = CreateFileW( tmp_path, 0, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0 ); -+ ok( handle2 != INVALID_HANDLE_VALUE, "CreateFileW failed\n" ); -+ -+ fli = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_LINK_INFORMATION) + lstrlenW(filename) * sizeof(WCHAR) ); -+ fli->ReplaceIfExists = FALSE; -+ fli->RootDirectory = handle2; -+ fli->FileNameLength = lstrlenW(filename) * sizeof(WCHAR); -+ memcpy( fli->FileName, filename, fli->FileNameLength ); -+ -+ U(io).Status = 0xdeadbeef; -+ res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, FileLinkInformation ); -+ todo_wine ok( U(io).Status == STATUS_SUCCESS, "io.Status expected STATUS_SUCCESS, got %x\n", U(io).Status ); -+ todo_wine ok( res == STATUS_SUCCESS, "res expected STATUS_SUCCESS, got %x\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 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 %x\n", res ); -+ fni->FileName[ fni->FileNameLength / sizeof(WCHAR) ] = 0; -+ ok( !lstrcmpW(fni->FileName, oldpath + 2), "FileName expected %s, got %s\n", -+ wine_dbgstr_w(oldpath + 2), wine_dbgstr_w(fni->FileName) ); -+ HeapFree( GetProcessHeap(), 0, fni ); -+ -+ CloseHandle( handle ); -+ CloseHandle( handle2 ); -+ HeapFree( GetProcessHeap(), 0, fli ); -+ delete_object( oldpath ); -+ delete_object( newpath ); -+} -+ - static void test_file_both_information(void) - { - IO_STATUS_BLOCK io; -@@ -3570,6 +4267,7 @@ START_TEST(file) - test_file_full_size_information(); - test_file_all_name_information(); - test_file_rename_information(); -+ test_file_link_information(); - test_file_disposition_information(); - test_query_volume_information_file(); - test_query_attribute_information_file(); --- -2.5.0 - diff --git a/patches/ntdll-FileDispositionInformation/0005-server-Implement-support-for-FileLinkInformation-cla.patch b/patches/ntdll-FileDispositionInformation/0005-server-Implement-support-for-FileLinkInformation-cla.patch deleted file mode 100644 index 8dc28762..00000000 --- a/patches/ntdll-FileDispositionInformation/0005-server-Implement-support-for-FileLinkInformation-cla.patch +++ /dev/null @@ -1,344 +0,0 @@ -From 33b20afef41c75ec5fb2407ec226daef12039c97 Mon Sep 17 00:00:00 2001 -From: Sebastian Lackner -Date: Wed, 3 Jun 2015 17:04:23 +0200 -Subject: server: Implement support for FileLinkInformation class in - NtSetInformationFile. - ---- - dlls/ntdll/file.c | 44 ++++++++++++++++++++++++++++++++++++++++ - dlls/ntdll/tests/file.c | 54 ++++++++++++++++++++++++------------------------- - server/fd.c | 25 +++++++++++++++++++---- - server/protocol.def | 1 + - 4 files changed, 93 insertions(+), 31 deletions(-) - -diff --git a/dlls/ntdll/file.c b/dlls/ntdll/file.c -index 3cef11b..be6b591 100644 ---- a/dlls/ntdll/file.c -+++ b/dlls/ntdll/file.c -@@ -2813,6 +2813,50 @@ NTSTATUS WINAPI NtSetInformationFile(HANDLE handle, PIO_STATUS_BLOCK io, - { - req->handle = wine_server_obj_handle( handle ); - req->rootdir = wine_server_obj_handle( attr.RootDirectory ); -+ req->link = FALSE; -+ wine_server_add_data( req, unix_name.Buffer, unix_name.Length ); -+ io->u.Status = wine_server_call( req ); -+ } -+ SERVER_END_REQ; -+ -+ RtlFreeAnsiString( &unix_name ); -+ } -+ else io->u.Status = STATUS_INVALID_PARAMETER_3; -+ break; -+ -+ case FileLinkInformation: -+ if (len >= sizeof(FILE_LINK_INFORMATION)) -+ { -+ FILE_LINK_INFORMATION *info = ptr; -+ UNICODE_STRING name_str; -+ OBJECT_ATTRIBUTES attr; -+ ANSI_STRING unix_name; -+ -+ name_str.Buffer = info->FileName; -+ name_str.Length = info->FileNameLength; -+ name_str.MaximumLength = info->FileNameLength + sizeof(WCHAR); -+ -+ attr.Length = sizeof(attr); -+ attr.ObjectName = &name_str; -+ 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->ReplaceIfExists && io->u.Status == STATUS_SUCCESS) -+ { -+ RtlFreeAnsiString( &unix_name ); -+ io->u.Status = STATUS_OBJECT_NAME_COLLISION; -+ break; -+ } -+ -+ SERVER_START_REQ( set_fd_name_info ) -+ { -+ req->handle = wine_server_obj_handle( handle ); -+ req->rootdir = wine_server_obj_handle( attr.RootDirectory ); -+ req->link = TRUE; - wine_server_add_data( req, unix_name.Buffer, unix_name.Length ); - io->u.Status = wine_server_call( req ); - } -diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c -index 177c2c5..5b3db09 100644 ---- a/dlls/ntdll/tests/file.c -+++ b/dlls/ntdll/tests/file.c -@@ -2113,12 +2113,12 @@ static void test_file_link_information(void) - - U(io).Status = 0xdeadbeef; - res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, FileLinkInformation ); -- todo_wine ok( U(io).Status == STATUS_SUCCESS, "io.Status expected STATUS_SUCCESS, got %x\n", U(io).Status ); -- todo_wine ok( res == STATUS_SUCCESS, "res expected STATUS_SUCCESS, got %x\n", res ); -+ ok( U(io).Status == STATUS_SUCCESS, "io.Status expected STATUS_SUCCESS, got %x\n", U(io).Status ); -+ ok( res == STATUS_SUCCESS, "res expected STATUS_SUCCESS, got %x\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 ok( !fileDeleted, "file should exist\n" ); -+ 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 ); -@@ -2152,7 +2152,7 @@ static void test_file_link_information(void) - U(io).Status = 0xdeadbeef; - res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, FileLinkInformation ); - todo_wine ok( U(io).Status == 0xdeadbeef, "io.Status expected 0xdeadbeef, got %x\n", U(io).Status ); -- todo_wine ok( res == STATUS_OBJECT_NAME_COLLISION, "res expected STATUS_OBJECT_NAME_COLLISION, got %x\n", res ); -+ ok( res == STATUS_OBJECT_NAME_COLLISION, "res expected STATUS_OBJECT_NAME_COLLISION, got %x\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; -@@ -2185,7 +2185,7 @@ static void test_file_link_information(void) - U(io).Status = 0xdeadbeef; - res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, FileLinkInformation ); - todo_wine ok( U(io).Status == 0xdeadbeef, "io.Status expected 0xdeadbeef, got %x\n", U(io).Status ); -- todo_wine ok( res == STATUS_OBJECT_NAME_COLLISION, "res expected STATUS_OBJECT_NAME_COLLISION, got %x\n", res ); -+ ok( res == STATUS_OBJECT_NAME_COLLISION, "res expected STATUS_OBJECT_NAME_COLLISION, got %x\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; -@@ -2215,8 +2215,8 @@ static void test_file_link_information(void) - - U(io).Status = 0xdeadbeef; - res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, FileLinkInformation ); -- todo_wine ok( U(io).Status == STATUS_SUCCESS, "io.Status expected STATUS_SUCCESS, got %x\n", U(io).Status ); -- todo_wine ok( res == STATUS_SUCCESS, "res expected STATUS_SUCCESS, got %x\n", res ); -+ ok( U(io).Status == STATUS_SUCCESS, "io.Status expected STATUS_SUCCESS, got %x\n", U(io).Status ); -+ ok( res == STATUS_SUCCESS, "res expected STATUS_SUCCESS, got %x\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; -@@ -2249,7 +2249,7 @@ static void test_file_link_information(void) - U(io).Status = 0xdeadbeef; - res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, FileLinkInformation ); - todo_wine ok( U(io).Status == 0xdeadbeef, "io.Status expected 0xdeadbeef, got %x\n", U(io).Status ); -- todo_wine ok( res == STATUS_ACCESS_DENIED, "res expected STATUS_ACCESS_DENIED, got %x\n", res ); -+ ok( res == STATUS_ACCESS_DENIED, "res expected STATUS_ACCESS_DENIED, got %x\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; -@@ -2283,7 +2283,7 @@ static void test_file_link_information(void) - U(io).Status = 0xdeadbeef; - res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, FileLinkInformation ); - todo_wine ok( U(io).Status == 0xdeadbeef, "io.Status expected 0xdeadbeef, got %x\n", U(io).Status ); -- todo_wine ok( res == STATUS_ACCESS_DENIED, "res expected STATUS_ACCESS_DENIED, got %x\n", res ); -+ ok( res == STATUS_ACCESS_DENIED, "res expected STATUS_ACCESS_DENIED, got %x\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; -@@ -2317,7 +2317,7 @@ static void test_file_link_information(void) - U(io).Status = 0xdeadbeef; - res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, FileLinkInformation ); - todo_wine ok( U(io).Status == 0xdeadbeef, "io.Status expected 0xdeadbeef, got %x\n", U(io).Status ); -- todo_wine ok( res == STATUS_ACCESS_DENIED, "res expected STATUS_ACCESS_DENIED, got %x\n", res ); -+ ok( res == STATUS_ACCESS_DENIED, "res expected STATUS_ACCESS_DENIED, got %x\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; -@@ -2352,7 +2352,7 @@ static void test_file_link_information(void) - U(io).Status = 0xdeadbeef; - res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, FileLinkInformation ); - todo_wine ok( U(io).Status == 0xdeadbeef , "io.Status expected 0xdeadbeef, got %x\n", U(io).Status ); -- todo_wine ok( res == STATUS_FILE_IS_A_DIRECTORY, "res expected STATUS_FILE_IS_A_DIRECTORY, got %x\n", res ); -+ ok( res == STATUS_FILE_IS_A_DIRECTORY, "res expected STATUS_FILE_IS_A_DIRECTORY, got %x\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; -@@ -2399,7 +2399,7 @@ static void test_file_link_information(void) - U(io).Status = 0xdeadbeef; - res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, FileLinkInformation ); - todo_wine ok( U(io).Status == 0xdeadbeef, "io.Status expected 0xdeadbeef, got %x\n", U(io).Status ); -- todo_wine ok( res == STATUS_FILE_IS_A_DIRECTORY, "res expected STATUS_FILE_IS_A_DIRECTORY, got %x\n", res ); -+ ok( res == STATUS_FILE_IS_A_DIRECTORY, "res expected STATUS_FILE_IS_A_DIRECTORY, got %x\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; -@@ -2433,8 +2433,8 @@ static void test_file_link_information(void) - U(io).Status = 0xdeadbeef; - res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, FileLinkInformation ); - todo_wine ok( U(io).Status == 0xdeadbeef, "io.Status expected 0xdeadbeef, got %x\n", U(io).Status ); -- todo_wine 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 %x\n", res ); -+ 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 %x\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; -@@ -2470,8 +2470,8 @@ static void test_file_link_information(void) - U(io).Status = 0xdeadbeef; - res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, FileLinkInformation ); - todo_wine ok( U(io).Status == 0xdeadbeef, "io.Status expected 0xdeadbeef, got %x\n", U(io).Status ); -- todo_wine 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 %x\n", res ); -+ 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 %x\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; -@@ -2505,7 +2505,7 @@ static void test_file_link_information(void) - U(io).Status = 0xdeadbeef; - res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, FileLinkInformation ); - todo_wine ok( U(io).Status == 0xdeadbeef, "io.Status expected 0xdeadbeef, got %x\n", U(io).Status ); -- todo_wine ok( res == STATUS_FILE_IS_A_DIRECTORY, "res expected STATUS_FILE_IS_A_DIRECTORY, got %x\n", res ); -+ ok( res == STATUS_FILE_IS_A_DIRECTORY, "res expected STATUS_FILE_IS_A_DIRECTORY, got %x\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; -@@ -2541,7 +2541,7 @@ static void test_file_link_information(void) - U(io).Status = 0xdeadbeef; - res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, FileLinkInformation ); - todo_wine ok( U(io).Status == 0xdeadbeef, "io.Status expected 0xdeadbeef, got %x\n", U(io).Status ); -- todo_wine ok( res == STATUS_FILE_IS_A_DIRECTORY, "res expected STATUS_FILE_IS_A_DIRECTORY, got %x\n", res ); -+ ok( res == STATUS_FILE_IS_A_DIRECTORY, "res expected STATUS_FILE_IS_A_DIRECTORY, got %x\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; -@@ -2578,8 +2578,8 @@ static void test_file_link_information(void) - U(io).Status = 0xdeadbeef; - res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, FileLinkInformation ); - todo_wine ok( U(io).Status == 0xdeadbeef, "io.Status expected 0xdeadbeef, got %x\n", U(io).Status ); -- todo_wine 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 %x\n", res ); -+ 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 %x\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; -@@ -2615,7 +2615,7 @@ static void test_file_link_information(void) - U(io).Status = 0xdeadbeef; - res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, FileLinkInformation ); - todo_wine ok( U(io).Status == 0xdeadbeef, "io.Status expected 0xdeadbeef, got %x\n", U(io).Status ); -- todo_wine ok( res == STATUS_FILE_IS_A_DIRECTORY, "res expected STATUS_FILE_IS_A_DIRECTORY, got %x\n", res ); -+ ok( res == STATUS_FILE_IS_A_DIRECTORY, "res expected STATUS_FILE_IS_A_DIRECTORY, got %x\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; -@@ -2654,7 +2654,7 @@ static void test_file_link_information(void) - U(io).Status = 0xdeadbeef; - res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, FileLinkInformation ); - todo_wine ok( U(io).Status == 0xdeadbeef, "io.Status expected 0xdeadbeef, got %x\n", U(io).Status ); -- todo_wine ok( res == STATUS_FILE_IS_A_DIRECTORY, "res expected STATUS_FILE_IS_A_DIRECTORY, got %x\n", res ); -+ ok( res == STATUS_FILE_IS_A_DIRECTORY, "res expected STATUS_FILE_IS_A_DIRECTORY, got %x\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; -@@ -2688,7 +2688,7 @@ static void test_file_link_information(void) - U(io).Status = 0xdeadbeef; - res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, FileLinkInformation ); - todo_wine ok( U(io).Status == 0xdeadbeef, "io.Status expected 0xdeadbeef, got %x\n", U(io).Status ); -- todo_wine ok( res == STATUS_OBJECT_NAME_COLLISION, "res expected STATUS_OBJECT_NAME_COLLISION, got %x\n", res ); -+ ok( res == STATUS_OBJECT_NAME_COLLISION, "res expected STATUS_OBJECT_NAME_COLLISION, got %x\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; -@@ -2721,7 +2721,7 @@ static void test_file_link_information(void) - U(io).Status = 0xdeadbeef; - res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, FileLinkInformation ); - todo_wine ok( U(io).Status == 0xdeadbeef, "io.Status expected 0xdeadbeef, got %x\n", U(io).Status ); -- todo_wine ok( res == STATUS_ACCESS_DENIED, "res expected STATUS_ACCESS_DENIED, got %x\n", res ); -+ ok( res == STATUS_ACCESS_DENIED, "res expected STATUS_ACCESS_DENIED, got %x\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; -@@ -2754,12 +2754,12 @@ static void test_file_link_information(void) - - U(io).Status = 0xdeadbeef; - res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, FileLinkInformation ); -- todo_wine ok( U(io).Status == STATUS_SUCCESS, "io.Status expected STATUS_SUCCESS, got %x\n", U(io).Status ); -- todo_wine ok( res == STATUS_SUCCESS, "res expected STATUS_SUCCESS, got %x\n", res ); -+ ok( U(io).Status == STATUS_SUCCESS, "io.Status expected STATUS_SUCCESS, got %x\n", U(io).Status ); -+ ok( res == STATUS_SUCCESS, "res expected STATUS_SUCCESS, got %x\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 ok( !fileDeleted, "file should exist\n" ); -+ 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 ); -diff --git a/server/fd.c b/server/fd.c -index c0b5548..94489e7 100644 ---- a/server/fd.c -+++ b/server/fd.c -@@ -2275,7 +2275,7 @@ static void set_fd_disposition( struct fd *fd, int unlink ) - } - - /* set new name for the fd */ --static void set_fd_name( struct fd *fd, struct fd *root, const char *nameptr, data_size_t len ) -+static void set_fd_name( struct fd *fd, struct fd *root, const char *nameptr, data_size_t len, int do_link ) - { - struct inode *inode; - struct stat st; -@@ -2307,6 +2307,14 @@ static void set_fd_name( struct fd *fd, struct fd *root, const char *nameptr, da - name = combined_name; - } - -+ /* when creating a hard link, source must be a file */ -+ if (do_link && fd->unix_fd != -1 && -+ !fstat( fd->unix_fd, &st ) && S_ISDIR( st.st_mode )) -+ { -+ set_error( STATUS_FILE_IS_A_DIRECTORY ); -+ goto failed; -+ } -+ - if (!stat( name, &st )) - { - /* can't replace directories or special files */ -@@ -2328,15 +2336,24 @@ static void set_fd_name( struct fd *fd, struct fd *root, const char *nameptr, da - } - } - -+ /* link() expects that the target doesn't exist */ - /* rename() cannot replace files with directories */ -- if (fd->unix_fd != -1 && !fstat( fd->unix_fd, &st ) && -- S_ISDIR( st.st_mode ) && unlink( name )) -+ if ((do_link || (fd->unix_fd != -1 && !fstat( fd->unix_fd, &st ) && -+ S_ISDIR( st.st_mode ))) && unlink( name )) - { - file_set_error(); - goto failed; - } - } - -+ if (do_link) -+ { -+ if (link( fd->unix_name, name )) -+ file_set_error(); -+ free( name ); -+ return; -+ } -+ - if (rename( fd->unix_name, name )) - { - file_set_error(); -@@ -2576,7 +2593,7 @@ DECL_HANDLER(set_fd_name_info) - - if ((fd = get_handle_fd_obj( current->process, req->handle, 0 ))) - { -- set_fd_name( fd, root_fd, get_req_data(), get_req_data_size() ); -+ set_fd_name( fd, root_fd, get_req_data(), get_req_data_size(), req->link ); - release_object( fd ); - } - if (root_fd) release_object( root_fd ); -diff --git a/server/protocol.def b/server/protocol.def -index d3ff4b7..c313006 100644 ---- a/server/protocol.def -+++ b/server/protocol.def -@@ -3536,6 +3536,7 @@ enum coords_relative - @REQ(set_fd_name_info) - obj_handle_t handle; /* handle to a file or directory */ - obj_handle_t rootdir; /* root directory */ -+ int link; /* link instead of renaming */ - VARARG(filename,string); /* new file name */ - @END - --- -2.5.0 - diff --git a/patches/ntdll-FileDispositionInformation/definition b/patches/ntdll-FileDispositionInformation/definition index c2599323..b139e548 100644 --- a/patches/ntdll-FileDispositionInformation/definition +++ b/patches/ntdll-FileDispositionInformation/definition @@ -1,4 +1,4 @@ # Fixes: [30397] Support for NtSetInformationFile class FileDispositionInformation # Fixes: [30399] Support for NtSetInformationFile class FileRenameInformation -Fixes: Support for NtSetInformationFile class FileLinkInformation +# Fixes: Support for NtSetInformationFile class FileLinkInformation Depends: server-File_Permissions diff --git a/patches/patchinstall.sh b/patches/patchinstall.sh index c8b94027..ded2d4fa 100755 --- a/patches/patchinstall.sh +++ b/patches/patchinstall.sh @@ -55,7 +55,7 @@ version() echo "Copyright (C) 2014-2015 the Wine Staging project authors." echo "" echo "Patchset to be applied on upstream Wine:" - echo " commit 5021e91940fe01a54e6ee91f9d9f246ce8f6dd84" + echo " commit 5ccc463a4e3ba181b96a161c3c8cd4bc0cb0e607" echo "" } @@ -215,7 +215,6 @@ patch_enable_all () enable_server_PeekMessage="$1" enable_server_Pipe_ObjectName="$1" enable_server_Realtime_Priority="$1" - enable_server_RootDirectory_File="$1" enable_server_Shared_Memory="$1" enable_server_Stored_ACLs="$1" enable_server_Timestamp_Compat="$1" @@ -731,9 +730,6 @@ patch_enable () server-Realtime_Priority) enable_server_Realtime_Priority="$2" ;; - server-RootDirectory_File) - enable_server_RootDirectory_File="$2" - ;; server-Shared_Memory) enable_server_Shared_Memory="$2" ;; @@ -1714,19 +1710,8 @@ if test "$enable_server_Stored_ACLs" -eq 1; then if test "$enable_server_File_Permissions" -gt 1; then abort "Patchset server-File_Permissions disabled, but server-Stored_ACLs depends on that." fi - if test "$enable_server_RootDirectory_File" -gt 1; then - abort "Patchset server-RootDirectory_File disabled, but server-Stored_ACLs depends on that." - fi enable_ntdll_DOS_Attributes=1 enable_server_File_Permissions=1 - enable_server_RootDirectory_File=1 -fi - -if test "$enable_server_RootDirectory_File" -eq 1; then - if test "$enable_ntdll_FileDispositionInformation" -gt 1; then - abort "Patchset ntdll-FileDispositionInformation disabled, but server-RootDirectory_File depends on that." - fi - enable_ntdll_FileDispositionInformation=1 fi if test "$enable_nvencodeapi_Video_Encoder" -eq 1; then @@ -3154,20 +3139,16 @@ fi # | * server-File_Permissions # | # | Modified files: -# | * dlls/ntdll/file.c, dlls/ntdll/tests/file.c, server/fd.c, server/protocol.def +# | * dlls/ntdll/tests/file.c, server/fd.c # | if test "$enable_ntdll_FileDispositionInformation" -eq 1; then patch_apply ntdll-FileDispositionInformation/0001-ntdll-tests-Added-tests-to-set-disposition-on-file-w.patch patch_apply ntdll-FileDispositionInformation/0002-server-Do-not-allow-to-set-disposition-on-file-which.patch patch_apply ntdll-FileDispositionInformation/0003-server-When-combining-root-and-name-make-sure-there-.patch - patch_apply ntdll-FileDispositionInformation/0004-ntdll-tests-Add-tests-for-FileLinkInformation-class.patch - patch_apply ntdll-FileDispositionInformation/0005-server-Implement-support-for-FileLinkInformation-cla.patch ( echo '+ { "Qian Hong", "ntdll/tests: Added tests to set disposition on file which is mapped to memory.", 1 },'; echo '+ { "Qian Hong", "server: Do not allow to set disposition on file which has a file mapping.", 1 },'; echo '+ { "Sebastian Lackner", "server: When combining root and name, make sure there is only one slash.", 2 },'; - echo '+ { "Qian Hong", "ntdll/tests: Add tests for FileLinkInformation class.", 1 },'; - echo '+ { "Sebastian Lackner", "server: Implement support for FileLinkInformation class in NtSetInformationFile.", 1 },'; ) >> "$patchlist" fi @@ -4361,25 +4342,10 @@ if test "$enable_server_Delete_On_Close" -eq 1; then ) >> "$patchlist" fi -# Patchset server-RootDirectory_File -# | -# | This patchset has the following (direct or indirect) dependencies: -# | * server-File_Permissions, ntdll-FileDispositionInformation -# | -# | Modified files: -# | * dlls/ntdll/tests/file.c, server/fd.c, server/file.c, server/file.h -# | -if test "$enable_server_RootDirectory_File" -eq 1; then - patch_apply server-RootDirectory_File/0001-server-Fix-handling-of-opening-a-file-with-RootDirec.patch - ( - echo '+ { "Sebastian Lackner", "server: Fix handling of opening a file with RootDirectory pointing to a file handle.", 3 },'; - ) >> "$patchlist" -fi - # Patchset server-Stored_ACLs # | # | This patchset has the following (direct or indirect) dependencies: -# | * ntdll-DOS_Attributes, server-File_Permissions, ntdll-FileDispositionInformation, server-RootDirectory_File +# | * ntdll-DOS_Attributes, server-File_Permissions # | # | This patchset fixes the following Wine bugs: # | * [#33576] Support for stored file ACLs @@ -4410,8 +4376,7 @@ fi # Patchset server-Inherited_ACLs # | # | This patchset has the following (direct or indirect) dependencies: -# | * ntdll-DOS_Attributes, server-File_Permissions, ntdll-FileDispositionInformation, server-RootDirectory_File, server- -# | Stored_ACLs +# | * ntdll-DOS_Attributes, server-File_Permissions, server-Stored_ACLs # | # | Modified files: # | * dlls/advapi32/tests/security.c, server/file.c diff --git a/patches/server-RootDirectory_File/0001-server-Fix-handling-of-opening-a-file-with-RootDirec.patch b/patches/server-RootDirectory_File/0001-server-Fix-handling-of-opening-a-file-with-RootDirec.patch deleted file mode 100644 index e3195272..00000000 --- a/patches/server-RootDirectory_File/0001-server-Fix-handling-of-opening-a-file-with-RootDirec.patch +++ /dev/null @@ -1,228 +0,0 @@ -From 7b50d145c867f5724e20120cd54995752279291a Mon Sep 17 00:00:00 2001 -From: Sebastian Lackner -Date: Fri, 29 May 2015 22:49:24 +0200 -Subject: server: Fix handling of opening a file with RootDirectory pointing to - a file handle. (v3) - -Changes in v2: - * Seek back to the beginning of file in duplicated file descriptor. ---- - dlls/ntdll/tests/file.c | 49 ++++++++++++++++++++++++++++++++++++++++++++++--- - server/fd.c | 34 +++++++++++++++++++++++++++------- - server/file.c | 23 ++++++++++++++++++++++- - server/file.h | 1 + - 4 files changed, 96 insertions(+), 11 deletions(-) - -diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c -index 1f009f6..fbf9daf 100644 ---- a/dlls/ntdll/tests/file.c -+++ b/dlls/ntdll/tests/file.c -@@ -297,7 +297,8 @@ static void create_file_test(void) - - static void open_file_test(void) - { -- static const WCHAR fooW[] = {'f','o','o',0}; -+ static const char testdata[] = "Hello World"; -+ static WCHAR fooW[] = {'f','o','o',0}; - NTSTATUS status; - HANDLE dir, root, handle, file; - WCHAR path[MAX_PATH], tmpfile[MAX_PATH]; -@@ -306,7 +307,8 @@ static void open_file_test(void) - IO_STATUS_BLOCK io; - UNICODE_STRING nameW; - UINT i, len; -- BOOL restart = TRUE; -+ BOOL ret, restart = TRUE; -+ DWORD numbytes; - - len = GetWindowsDirectoryW( path, MAX_PATH ); - pRtlDosPathNameToNtPathName_U( path, &nameW, NULL, NULL ); -@@ -432,6 +434,14 @@ static void open_file_test(void) - GetTempFileNameW( path, fooW, 0, tmpfile ); - pRtlDosPathNameToNtPathName_U( tmpfile, &nameW, NULL, NULL ); - -+ file = CreateFileW( tmpfile, FILE_WRITE_DATA, 0, NULL, CREATE_ALWAYS, 0, 0 ); -+ ok( file != INVALID_HANDLE_VALUE, "CreateFile error %d\n", GetLastError() ); -+ numbytes = 0xdeadbeef; -+ ret = WriteFile( file, testdata, sizeof(testdata) - 1, &numbytes, NULL ); -+ ok( ret, "WriteFile failed with error %u\n", GetLastError() ); -+ ok( numbytes == sizeof(testdata) - 1, "failed to write all data\n" ); -+ CloseHandle( file ); -+ - attr.Length = sizeof(attr); - attr.RootDirectory = 0; - attr.ObjectName = &nameW; -@@ -443,13 +453,46 @@ static void open_file_test(void) - ok( !status, "open %s failed %x\n", wine_dbgstr_w(nameW.Buffer), status ); - pRtlFreeUnicodeString( &nameW ); - -+ numbytes = 0xdeadbeef; -+ memset( data, 0, sizeof(data) ); -+ ret = ReadFile( file, data, sizeof(data), &numbytes, NULL ); -+ ok( ret, "ReadFile failed with error %u\n", GetLastError() ); -+ ok( numbytes == sizeof(testdata) - 1, "failed to read all data\n" ); -+ ok( !memcmp( data, testdata, sizeof(testdata) - 1 ), "testdata doesn't match\n" ); -+ -+ nameW.Length = sizeof(fooW) - sizeof(WCHAR); -+ nameW.Buffer = fooW; -+ attr.RootDirectory = file; -+ attr.ObjectName = &nameW; -+ status = pNtOpenFile( &root, SYNCHRONIZE|FILE_LIST_DIRECTORY, &attr, &io, -+ FILE_SHARE_READ, FILE_SYNCHRONOUS_IO_NONALERT ); -+ ok( status == STATUS_OBJECT_PATH_NOT_FOUND, -+ "expected STATUS_OBJECT_PATH_NOT_FOUND, got %08x\n", status ); -+ - nameW.Length = 0; - nameW.Buffer = NULL; - attr.RootDirectory = file; - attr.ObjectName = &nameW; - status = pNtOpenFile( &root, SYNCHRONIZE|FILE_LIST_DIRECTORY, &attr, &io, - FILE_SHARE_READ, FILE_SYNCHRONOUS_IO_NONALERT ); -- todo_wine ok( !status, "open %s failed %x\n", wine_dbgstr_w(tmpfile), status ); -+ ok( !status, "open %s failed %x\n", wine_dbgstr_w(tmpfile), status ); -+ -+ numbytes = SetFilePointer( file, 0, 0, FILE_CURRENT ); -+ ok( numbytes == sizeof(testdata) - 1, "SetFilePointer returned %u\n", numbytes ); -+ numbytes = SetFilePointer( root, 0, 0, FILE_CURRENT ); -+ ok( numbytes == 0, "SetFilePointer returned %u\n", numbytes ); -+ -+ numbytes = 0xdeadbeef; -+ memset( data, 0, sizeof(data) ); -+ ret = ReadFile( root, data, sizeof(data), &numbytes, NULL ); -+ ok( ret, "ReadFile failed with error %u\n", GetLastError() ); -+ ok( numbytes == sizeof(testdata) - 1, "failed to read all data\n" ); -+ ok( !memcmp( data, testdata, sizeof(testdata) - 1 ), "testdata doesn't match\n" ); -+ -+ numbytes = SetFilePointer( file, 0, 0, FILE_CURRENT ); -+ ok( numbytes == sizeof(testdata) - 1, "SetFilePointer returned %u\n", numbytes ); -+ numbytes = SetFilePointer( root, 0, 0, FILE_CURRENT ); -+ ok( numbytes == sizeof(testdata) - 1, "SetFilePointer returned %u\n", numbytes ); - - CloseHandle( file ); - CloseHandle( root ); -diff --git a/server/fd.c b/server/fd.c -index ae97a94..04c0e42 100644 ---- a/server/fd.c -+++ b/server/fd.c -@@ -1718,7 +1718,7 @@ void set_fd_user( struct fd *fd, const struct fd_ops *user_ops, struct object *u - fd->user = user; - } - --static char *dup_fd_name( struct fd *root, const char *name ) -+char *dup_fd_name( struct fd *root, const char *name ) - { - char *ret; - int len; -@@ -2325,14 +2325,36 @@ DECL_HANDLER(flush) - DECL_HANDLER(open_file_object) - { - struct unicode_str name; -- struct directory *root = NULL; -+ struct directory *root; - struct object *obj, *result; - - get_req_unicode_str( &name ); -- if (req->rootdir && !(root = get_directory_obj( current->process, req->rootdir, 0 ))) -- return; -+ if (req->rootdir) -+ { -+ if ((root = get_directory_obj( current->process, req->rootdir, 0 ))) -+ { -+ obj = open_object_dir( root, &name, req->attributes, NULL ); -+ release_object( root ); -+ } -+ else if (get_error() == STATUS_OBJECT_TYPE_MISMATCH && -+ (obj = (struct object *)get_file_obj( current->process, req->rootdir, 0 ))) -+ { -+ if (name.len) -+ { -+ release_object( obj ); -+ set_error( STATUS_OBJECT_PATH_NOT_FOUND ); -+ return; -+ } -+ clear_error(); -+ } -+ else return; -+ } -+ else -+ { -+ obj = open_object_dir( NULL, &name, req->attributes, NULL ); -+ } - -- if ((obj = open_object_dir( root, &name, req->attributes, NULL ))) -+ if (obj) - { - if ((result = obj->ops->open_file( obj, req->access, req->sharing, req->options ))) - { -@@ -2341,8 +2363,6 @@ DECL_HANDLER(open_file_object) - } - release_object( obj ); - } -- -- if (root) release_object( root ); - } - - /* get the Unix name from a file handle */ -diff --git a/server/file.c b/server/file.c -index b673bbc..56600d5 100644 ---- a/server/file.c -+++ b/server/file.c -@@ -67,6 +67,8 @@ static void file_dump( struct object *obj, int verbose ); - static struct fd *file_get_fd( struct object *obj ); - static struct security_descriptor *file_get_sd( struct object *obj ); - static int file_set_sd( struct object *obj, const struct security_descriptor *sd, unsigned int set_info ); -+static struct object *file_open_file( struct object *obj, unsigned int access, -+ unsigned int sharing, unsigned int options ); - static void file_destroy( struct object *obj ); - - static int file_get_poll_events( struct fd *fd ); -@@ -88,7 +90,7 @@ static const struct object_ops file_ops = - file_get_sd, /* get_sd */ - file_set_sd, /* set_sd */ - no_lookup_name, /* lookup_name */ -- no_open_file, /* open_file */ -+ file_open_file, /* open_file */ - fd_close_handle, /* close_handle */ - file_destroy /* destroy */ - }; -@@ -597,6 +599,25 @@ static int file_set_sd( struct object *obj, const struct security_descriptor *sd - return 1; - } - -+static struct object *file_open_file( struct object *obj, unsigned int access, -+ unsigned int sharing, unsigned int options ) -+{ -+ struct file *file = (struct file *)obj; -+ struct object *new_file = NULL; -+ char *unix_name; -+ -+ assert( obj->ops == &file_ops ); -+ -+ if ((unix_name = dup_fd_name( file->fd, "" ))) -+ { -+ new_file = create_file( NULL, unix_name, strlen(unix_name), access, -+ sharing, FILE_OPEN, options, 0, NULL ); -+ free( unix_name ); -+ } -+ else set_error( STATUS_OBJECT_TYPE_MISMATCH ); -+ return new_file; -+} -+ - static void file_destroy( struct object *obj ) - { - struct file *file = (struct file *)obj; -diff --git a/server/file.h b/server/file.h -index 460656f..47e6692 100644 ---- a/server/file.h -+++ b/server/file.h -@@ -82,6 +82,7 @@ extern void unlock_fd( struct fd *fd, file_pos_t offset, file_pos_t count ); - extern void allow_fd_caching( struct fd *fd ); - extern void set_fd_signaled( struct fd *fd, int signaled ); - extern int is_fd_signaled( struct fd *fd ); -+extern char *dup_fd_name( struct fd *root, const char *name ); - - extern int default_fd_signaled( struct object *obj, struct wait_queue_entry *entry ); - extern unsigned int default_fd_map_access( struct object *obj, unsigned int access ); --- -2.4.2 - diff --git a/patches/server-RootDirectory_File/definition b/patches/server-RootDirectory_File/definition deleted file mode 100644 index a329edf0..00000000 --- a/patches/server-RootDirectory_File/definition +++ /dev/null @@ -1,2 +0,0 @@ -Fixes: Fix handling of opening a file with RootDirectory pointing to a file handle -Depends: ntdll-FileDispositionInformation diff --git a/patches/server-Stored_ACLs/definition b/patches/server-Stored_ACLs/definition index 5850728d..03222c47 100644 --- a/patches/server-Stored_ACLs/definition +++ b/patches/server-Stored_ACLs/definition @@ -1,4 +1,3 @@ Depends: ntdll-DOS_Attributes Depends: server-File_Permissions -Depends: server-RootDirectory_File Fixes: [33576] Support for stored file ACLs