server: Implement support for FileLinkInformation class in NtSetInformationFile.

This commit is contained in:
Sebastian Lackner 2015-08-21 07:25:12 +02:00 committed by Alexandre Julliard
parent 57d443824a
commit 1f2a443cb4
7 changed files with 101 additions and 33 deletions

View File

@ -2813,6 +2813,50 @@ NTSTATUS WINAPI NtSetInformationFile(HANDLE handle, PIO_STATUS_BLOCK io,
{ {
req->handle = wine_server_obj_handle( handle ); req->handle = wine_server_obj_handle( handle );
req->rootdir = wine_server_obj_handle( attr.RootDirectory ); 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 ); wine_server_add_data( req, unix_name.Buffer, unix_name.Length );
io->u.Status = wine_server_call( req ); io->u.Status = wine_server_call( req );
} }

View File

@ -2113,12 +2113,12 @@ static void test_file_link_information(void)
U(io).Status = 0xdeadbeef; U(io).Status = 0xdeadbeef;
res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, FileLinkInformation ); 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 ); 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( res == STATUS_SUCCESS, "res expected STATUS_SUCCESS, got %x\n", res );
fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
ok( !fileDeleted, "file should exist\n" ); ok( !fileDeleted, "file should exist\n" );
fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; 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) ); 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 ); 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; U(io).Status = 0xdeadbeef;
res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, FileLinkInformation ); 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( 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; fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
ok( !fileDeleted, "file should exist\n" ); ok( !fileDeleted, "file should exist\n" );
fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
@ -2181,8 +2181,8 @@ static void test_file_link_information(void)
U(io).Status = 0xdeadbeef; U(io).Status = 0xdeadbeef;
res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, FileLinkInformation ); 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 ); 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( res == STATUS_SUCCESS, "res expected STATUS_SUCCESS, got %x\n", res );
fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
ok( !fileDeleted, "file should exist\n" ); ok( !fileDeleted, "file should exist\n" );
fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
@ -2215,7 +2215,7 @@ static void test_file_link_information(void)
U(io).Status = 0xdeadbeef; U(io).Status = 0xdeadbeef;
res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, FileLinkInformation ); 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( 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; fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
ok( !fileDeleted, "file should exist\n" ); ok( !fileDeleted, "file should exist\n" );
fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; 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; U(io).Status = 0xdeadbeef;
res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, FileLinkInformation ); 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( 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; fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
ok( !fileDeleted, "file should exist\n" ); ok( !fileDeleted, "file should exist\n" );
fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
@ -2284,7 +2284,7 @@ static void test_file_link_information(void)
U(io).Status = 0xdeadbeef; U(io).Status = 0xdeadbeef;
res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, FileLinkInformation ); 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( 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; fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
ok( !fileDeleted, "file should exist\n" ); ok( !fileDeleted, "file should exist\n" );
fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
@ -2331,7 +2331,7 @@ static void test_file_link_information(void)
U(io).Status = 0xdeadbeef; U(io).Status = 0xdeadbeef;
res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, FileLinkInformation ); 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( 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; fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
ok( !fileDeleted, "file should exist\n" ); ok( !fileDeleted, "file should exist\n" );
fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
@ -2365,7 +2365,7 @@ static void test_file_link_information(void)
U(io).Status = 0xdeadbeef; U(io).Status = 0xdeadbeef;
res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, FileLinkInformation ); 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( 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 */, 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 ); "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; fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
ok( !fileDeleted, "file should exist\n" ); ok( !fileDeleted, "file should exist\n" );
@ -2402,7 +2402,7 @@ static void test_file_link_information(void)
U(io).Status = 0xdeadbeef; U(io).Status = 0xdeadbeef;
res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, FileLinkInformation ); 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( 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 */, 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 ); "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; fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
ok( !fileDeleted, "file should exist\n" ); ok( !fileDeleted, "file should exist\n" );
@ -2437,7 +2437,7 @@ static void test_file_link_information(void)
U(io).Status = 0xdeadbeef; U(io).Status = 0xdeadbeef;
res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, FileLinkInformation ); 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( 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; fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
ok( !fileDeleted, "file should exist\n" ); ok( !fileDeleted, "file should exist\n" );
fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
@ -2473,7 +2473,7 @@ static void test_file_link_information(void)
U(io).Status = 0xdeadbeef; U(io).Status = 0xdeadbeef;
res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, FileLinkInformation ); 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( 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; fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
ok( !fileDeleted, "file should exist\n" ); ok( !fileDeleted, "file should exist\n" );
fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
@ -2510,7 +2510,7 @@ static void test_file_link_information(void)
U(io).Status = 0xdeadbeef; U(io).Status = 0xdeadbeef;
res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, FileLinkInformation ); 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( 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 */, 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 ); "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; fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
ok( !fileDeleted, "file should exist\n" ); ok( !fileDeleted, "file should exist\n" );
@ -2547,7 +2547,7 @@ static void test_file_link_information(void)
U(io).Status = 0xdeadbeef; U(io).Status = 0xdeadbeef;
res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, FileLinkInformation ); 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( 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; fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
ok( !fileDeleted, "file should exist\n" ); ok( !fileDeleted, "file should exist\n" );
fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
@ -2586,7 +2586,7 @@ static void test_file_link_information(void)
U(io).Status = 0xdeadbeef; U(io).Status = 0xdeadbeef;
res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, FileLinkInformation ); 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( 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; fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
ok( !fileDeleted, "file should exist\n" ); ok( !fileDeleted, "file should exist\n" );
fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
@ -2620,7 +2620,7 @@ static void test_file_link_information(void)
U(io).Status = 0xdeadbeef; U(io).Status = 0xdeadbeef;
res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, FileLinkInformation ); 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( 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; fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
ok( !fileDeleted, "file should exist\n" ); ok( !fileDeleted, "file should exist\n" );
fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
@ -2653,7 +2653,7 @@ static void test_file_link_information(void)
U(io).Status = 0xdeadbeef; U(io).Status = 0xdeadbeef;
res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, FileLinkInformation ); 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( 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; fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
ok( !fileDeleted, "file should exist\n" ); ok( !fileDeleted, "file should exist\n" );
fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
@ -2686,12 +2686,12 @@ static void test_file_link_information(void)
U(io).Status = 0xdeadbeef; U(io).Status = 0xdeadbeef;
res = pNtSetInformationFile( handle, &io, fli, sizeof(FILE_LINK_INFORMATION) + fli->FileNameLength, FileLinkInformation ); 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 ); 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( res == STATUS_SUCCESS, "res expected STATUS_SUCCESS, got %x\n", res );
fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; fileDeleted = GetFileAttributesW( oldpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND;
ok( !fileDeleted, "file should exist\n" ); ok( !fileDeleted, "file should exist\n" );
fileDeleted = GetFileAttributesW( newpath ) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND; 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) ); 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 ); res = pNtQueryInformationFile( handle, &io, fni, sizeof(FILE_NAME_INFORMATION) + MAX_PATH * sizeof(WCHAR), FileNameInformation );

View File

@ -5099,8 +5099,8 @@ struct set_fd_name_info_request
struct request_header __header; struct request_header __header;
obj_handle_t handle; obj_handle_t handle;
obj_handle_t rootdir; obj_handle_t rootdir;
int link;
/* VARARG(filename,string); */ /* VARARG(filename,string); */
char __pad_20[4];
}; };
struct set_fd_name_info_reply struct set_fd_name_info_reply
{ {
@ -6149,6 +6149,6 @@ union generic_reply
struct terminate_job_reply terminate_job_reply; struct terminate_job_reply terminate_job_reply;
}; };
#define SERVER_PROTOCOL_VERSION 486 #define SERVER_PROTOCOL_VERSION 487
#endif /* __WINE_WINE_SERVER_PROTOCOL_H */ #endif /* __WINE_WINE_SERVER_PROTOCOL_H */

View File

@ -2255,7 +2255,8 @@ static void set_fd_disposition( struct fd *fd, int unlink )
} }
/* set new name for the fd */ /* 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 create_link )
{ {
struct inode *inode; struct inode *inode;
struct stat st; struct stat st;
@ -2287,6 +2288,14 @@ static void set_fd_name( struct fd *fd, struct fd *root, const char *nameptr, da
name = combined_name; name = combined_name;
} }
/* when creating a hard link, source cannot be a dir */
if (create_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 )) if (!stat( name, &st ))
{ {
/* can't replace directories or special files */ /* can't replace directories or special files */
@ -2308,14 +2317,26 @@ 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 */ /* rename() cannot replace files with directories */
if (fd->unix_fd != -1 && !fstat( fd->unix_fd, &st ) && if (create_link || (fd->unix_fd != -1 &&
S_ISDIR( st.st_mode ) && unlink( name )) !fstat( fd->unix_fd, &st ) && S_ISDIR( st.st_mode )))
{
if (unlink( name ))
{ {
file_set_error(); file_set_error();
goto failed; goto failed;
} }
} }
}
if (create_link)
{
if (link( fd->unix_name, name ))
file_set_error();
free( name );
return;
}
if (rename( fd->unix_name, name )) if (rename( fd->unix_name, name ))
{ {
@ -2556,7 +2577,7 @@ DECL_HANDLER(set_fd_name_info)
if ((fd = get_handle_fd_obj( current->process, req->handle, 0 ))) 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 ); release_object( fd );
} }
if (root_fd) release_object( root_fd ); if (root_fd) release_object( root_fd );

View File

@ -3536,6 +3536,7 @@ enum coords_relative
@REQ(set_fd_name_info) @REQ(set_fd_name_info)
obj_handle_t handle; /* handle to a file or directory */ obj_handle_t handle; /* handle to a file or directory */
obj_handle_t rootdir; /* root directory */ obj_handle_t rootdir; /* root directory */
int link; /* link instead of renaming */
VARARG(filename,string); /* new file name */ VARARG(filename,string); /* new file name */
@END @END

View File

@ -2230,6 +2230,7 @@ C_ASSERT( FIELD_OFFSET(struct set_fd_disp_info_request, unlink) == 16 );
C_ASSERT( sizeof(struct set_fd_disp_info_request) == 24 ); C_ASSERT( sizeof(struct set_fd_disp_info_request) == 24 );
C_ASSERT( FIELD_OFFSET(struct set_fd_name_info_request, handle) == 12 ); C_ASSERT( FIELD_OFFSET(struct set_fd_name_info_request, handle) == 12 );
C_ASSERT( FIELD_OFFSET(struct set_fd_name_info_request, rootdir) == 16 ); C_ASSERT( FIELD_OFFSET(struct set_fd_name_info_request, rootdir) == 16 );
C_ASSERT( FIELD_OFFSET(struct set_fd_name_info_request, link) == 20 );
C_ASSERT( sizeof(struct set_fd_name_info_request) == 24 ); C_ASSERT( sizeof(struct set_fd_name_info_request) == 24 );
C_ASSERT( FIELD_OFFSET(struct get_window_layered_info_request, handle) == 12 ); C_ASSERT( FIELD_OFFSET(struct get_window_layered_info_request, handle) == 12 );
C_ASSERT( sizeof(struct get_window_layered_info_request) == 16 ); C_ASSERT( sizeof(struct get_window_layered_info_request) == 16 );

View File

@ -4146,6 +4146,7 @@ static void dump_set_fd_name_info_request( const struct set_fd_name_info_request
{ {
fprintf( stderr, " handle=%04x", req->handle ); fprintf( stderr, " handle=%04x", req->handle );
fprintf( stderr, ", rootdir=%04x", req->rootdir ); fprintf( stderr, ", rootdir=%04x", req->rootdir );
fprintf( stderr, ", link=%d", req->link );
dump_varargs_string( ", filename=", cur_size ); dump_varargs_string( ", filename=", cur_size );
} }