Rebase against 5ccc463a4e3ba181b96a161c3c8cd4bc0cb0e607.

This commit is contained in:
Sebastian Lackner 2015-08-21 16:54:56 +02:00
parent 1dc5f2f601
commit f3b30373fb
9 changed files with 13 additions and 1353 deletions

View File

@ -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))

View File

@ -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 <sebastian@fds-team.de>
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++;

View File

@ -1,730 +0,0 @@
From 3a74e4ad232bb6c15925d15225c0ec039143177b Mon Sep 17 00:00:00 2001
From: Qian Hong <qhong@codeweavers.com>
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

View File

@ -1,344 +0,0 @@
From 33b20afef41c75ec5fb2407ec226daef12039c97 Mon Sep 17 00:00:00 2001
From: Sebastian Lackner <sebastian@fds-team.de>
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

View File

@ -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

View File

@ -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

View File

@ -1,228 +0,0 @@
From 7b50d145c867f5724e20120cd54995752279291a Mon Sep 17 00:00:00 2001
From: Sebastian Lackner <sebastian@fds-team.de>
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

View File

@ -1,2 +0,0 @@
Fixes: Fix handling of opening a file with RootDirectory pointing to a file handle
Depends: ntdll-FileDispositionInformation

View File

@ -1,4 +1,3 @@
Depends: ntdll-DOS_Attributes
Depends: server-File_Permissions
Depends: server-RootDirectory_File
Fixes: [33576] Support for stored file ACLs