Commit 1f2a443c authored by Sebastian Lackner's avatar Sebastian Lackner Committed by Alexandre Julliard

server: Implement support for FileLinkInformation class in NtSetInformationFile.

parent 57d44382
......@@ -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 );
}
......
......@@ -5099,8 +5099,8 @@ struct set_fd_name_info_request
struct request_header __header;
obj_handle_t handle;
obj_handle_t rootdir;
int link;
/* VARARG(filename,string); */
char __pad_20[4];
};
struct set_fd_name_info_reply
{
......@@ -6149,6 +6149,6 @@ union generic_reply
struct terminate_job_reply terminate_job_reply;
};
#define SERVER_PROTOCOL_VERSION 486
#define SERVER_PROTOCOL_VERSION 487
#endif /* __WINE_WINE_SERVER_PROTOCOL_H */
......@@ -2255,7 +2255,8 @@ 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 create_link )
{
struct inode *inode;
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;
}
/* 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 ))
{
/* 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 */
if (fd->unix_fd != -1 && !fstat( fd->unix_fd, &st ) &&
S_ISDIR( st.st_mode ) && unlink( name ))
if (create_link || (fd->unix_fd != -1 &&
!fstat( fd->unix_fd, &st ) && S_ISDIR( st.st_mode )))
{
if (unlink( name ))
{
file_set_error();
goto failed;
}
}
}
if (create_link)
{
if (link( fd->unix_name, name ))
file_set_error();
free( name );
return;
}
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 )))
{
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 );
......
......@@ -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
......
......@@ -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( 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, link) == 20 );
C_ASSERT( sizeof(struct set_fd_name_info_request) == 24 );
C_ASSERT( FIELD_OFFSET(struct get_window_layered_info_request, handle) == 12 );
C_ASSERT( sizeof(struct get_window_layered_info_request) == 16 );
......
......@@ -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, ", rootdir=%04x", req->rootdir );
fprintf( stderr, ", link=%d", req->link );
dump_varargs_string( ", filename=", cur_size );
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment