Module: wine Branch: master Commit: 4e84a553a8f0e14dd9c36ea280003d8d96e6a9cd URL: https://source.winehq.org/git/wine.git/?a=commit;h=4e84a553a8f0e14dd9c36ea28...
Author: Qian Hong qhong@codeweavers.com Date: Fri Jun 25 00:28:51 2021 -0500
ntdll: Truncate files through the server.
Signed-off-by: Zebediah Figura z.figura12@gmail.com Signed-off-by: Alexandre Julliard julliard@winehq.org
---
dlls/ntdll/unix/file.c | 23 +++++------------------ include/wine/server_protocol.h | 18 +++++++++++++++++- server/fd.c | 37 +++++++++++++++++++++++++++++++++++++ server/file.h | 1 + server/mapping.c | 2 +- server/protocol.def | 7 +++++++ server/request.h | 5 +++++ server/trace.c | 9 +++++++++ 8 files changed, 82 insertions(+), 20 deletions(-)
diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c index 21f5d10f3f8..1a57a112a59 100644 --- a/dlls/ntdll/unix/file.c +++ b/dlls/ntdll/unix/file.c @@ -4360,28 +4360,15 @@ NTSTATUS WINAPI NtSetInformationFile( HANDLE handle, IO_STATUS_BLOCK *io, case FileEndOfFileInformation: if (len >= sizeof(FILE_END_OF_FILE_INFORMATION)) { - struct stat st; const FILE_END_OF_FILE_INFORMATION *info = ptr;
- if ((io->u.Status = server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL ))) - return io->u.Status; - - /* first try normal truncate */ - if (ftruncate( fd, (off_t)info->EndOfFile.QuadPart ) != -1) break; - - /* now check for the need to extend the file */ - if (fstat( fd, &st ) != -1 && (off_t)info->EndOfFile.QuadPart > st.st_size) + SERVER_START_REQ( set_fd_eof_info ) { - static const char zero; - - /* extend the file one byte beyond the requested size and then truncate it */ - /* this should work around ftruncate implementations that can't extend files */ - if (pwrite( fd, &zero, 1, (off_t)info->EndOfFile.QuadPart ) != -1 && - ftruncate( fd, (off_t)info->EndOfFile.QuadPart ) != -1) break; + req->handle = wine_server_obj_handle( handle ); + req->eof = info->EndOfFile.QuadPart; + io->u.Status = wine_server_call( req ); } - io->u.Status = errno_to_status( errno ); - - if (needs_close) close( fd ); + SERVER_END_REQ; } else io->u.Status = STATUS_INVALID_PARAMETER_3; break; diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index 58310a4d9a2..51ee6ee4aa3 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -5083,6 +5083,19 @@ struct set_fd_name_info_reply
+struct set_fd_eof_info_request +{ + struct request_header __header; + obj_handle_t handle; + file_pos_t eof; +}; +struct set_fd_eof_info_reply +{ + struct reply_header __header; +}; + + + struct get_window_layered_info_request { struct request_header __header; @@ -5640,6 +5653,7 @@ enum request REQ_set_fd_completion_mode, REQ_set_fd_disp_info, REQ_set_fd_name_info, + REQ_set_fd_eof_info, REQ_get_window_layered_info, REQ_set_window_layered_info, REQ_alloc_user_handle, @@ -5919,6 +5933,7 @@ union generic_request struct set_fd_completion_mode_request set_fd_completion_mode_request; struct set_fd_disp_info_request set_fd_disp_info_request; struct set_fd_name_info_request set_fd_name_info_request; + struct set_fd_eof_info_request set_fd_eof_info_request; struct get_window_layered_info_request get_window_layered_info_request; struct set_window_layered_info_request set_window_layered_info_request; struct alloc_user_handle_request alloc_user_handle_request; @@ -6196,6 +6211,7 @@ union generic_reply struct set_fd_completion_mode_reply set_fd_completion_mode_reply; struct set_fd_disp_info_reply set_fd_disp_info_reply; struct set_fd_name_info_reply set_fd_name_info_reply; + struct set_fd_eof_info_reply set_fd_eof_info_reply; struct get_window_layered_info_reply get_window_layered_info_reply; struct set_window_layered_info_reply set_window_layered_info_reply; struct alloc_user_handle_reply alloc_user_handle_reply; @@ -6220,7 +6236,7 @@ union generic_reply
/* ### protocol_version begin ### */
-#define SERVER_PROTOCOL_VERSION 717 +#define SERVER_PROTOCOL_VERSION 718
/* ### protocol_version end ### */
diff --git a/server/fd.c b/server/fd.c index e326354d127..7204a8c51ba 100644 --- a/server/fd.c +++ b/server/fd.c @@ -2630,6 +2630,32 @@ failed: free( name ); }
+static void set_fd_eof( struct fd *fd, file_pos_t eof ) +{ + struct stat st; + + if (!fd->inode) + { + set_error( STATUS_OBJECT_TYPE_MISMATCH ); + return; + } + + if (fd->unix_fd == -1) + { + set_error( fd->no_fd_status ); + return; + } + + /* first try normal truncate */ + if (ftruncate( fd->unix_fd, eof ) != -1) return; + + /* now check for the need to extend the file */ + if (fstat( fd->unix_fd, &st ) != -1 && eof > st.st_size) + grow_file( fd->unix_fd, eof ); + else + file_set_error(); +} + struct completion *fd_get_completion( struct fd *fd, apc_param_t *p_key ) { *p_key = fd->comp_key; @@ -2922,3 +2948,14 @@ DECL_HANDLER(set_fd_name_info) } if (root_fd) release_object( root_fd ); } + +/* set fd eof information */ +DECL_HANDLER(set_fd_eof_info) +{ + struct fd *fd = get_handle_fd_obj( current->process, req->handle, 0 ); + if (fd) + { + set_fd_eof( fd, req->eof ); + release_object( fd ); + } +} diff --git a/server/file.h b/server/file.h index b8bc7645b19..10b5c0d0493 100644 --- a/server/file.h +++ b/server/file.h @@ -168,6 +168,7 @@ extern int is_file_executable( const char *name );
struct memory_view;
+extern int grow_file( int unix_fd, file_pos_t new_size ); extern struct memory_view *find_mapped_view( struct process *process, client_ptr_t base ); extern struct memory_view *get_exe_view( struct process *process ); extern struct file *get_view_file( const struct memory_view *view, unsigned int access, unsigned int sharing ); diff --git a/server/mapping.c b/server/mapping.c index 529ce43bac9..2df337a172c 100644 --- a/server/mapping.c +++ b/server/mapping.c @@ -241,7 +241,7 @@ static void shared_map_destroy( struct object *obj ) }
/* extend a file beyond the current end of file */ -static int grow_file( int unix_fd, file_pos_t new_size ) +int grow_file( int unix_fd, file_pos_t new_size ) { static const char zero; off_t size = new_size; diff --git a/server/protocol.def b/server/protocol.def index 5d165e7bfa4..557311e2b3f 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -3535,6 +3535,13 @@ struct handle_info @END
+/* set fd eof information */ +@REQ(set_fd_eof_info) + obj_handle_t handle; /* handle to a file or directory */ + file_pos_t eof; /* offset of eof of file */ +@END + + /* Retrieve layered info for a window */ @REQ(get_window_layered_info) user_handle_t handle; /* handle to the window */ diff --git a/server/request.h b/server/request.h index defb3a640fd..0221cbd33ae 100644 --- a/server/request.h +++ b/server/request.h @@ -371,6 +371,7 @@ DECL_HANDLER(add_fd_completion); DECL_HANDLER(set_fd_completion_mode); DECL_HANDLER(set_fd_disp_info); DECL_HANDLER(set_fd_name_info); +DECL_HANDLER(set_fd_eof_info); DECL_HANDLER(get_window_layered_info); DECL_HANDLER(set_window_layered_info); DECL_HANDLER(alloc_user_handle); @@ -649,6 +650,7 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] = (req_handler)req_set_fd_completion_mode, (req_handler)req_set_fd_disp_info, (req_handler)req_set_fd_name_info, + (req_handler)req_set_fd_eof_info, (req_handler)req_get_window_layered_info, (req_handler)req_set_window_layered_info, (req_handler)req_alloc_user_handle, @@ -2141,6 +2143,9 @@ C_ASSERT( FIELD_OFFSET(struct set_fd_name_info_request, namelen) == 20 ); C_ASSERT( FIELD_OFFSET(struct set_fd_name_info_request, link) == 24 ); C_ASSERT( FIELD_OFFSET(struct set_fd_name_info_request, replace) == 28 ); C_ASSERT( sizeof(struct set_fd_name_info_request) == 32 ); +C_ASSERT( FIELD_OFFSET(struct set_fd_eof_info_request, handle) == 12 ); +C_ASSERT( FIELD_OFFSET(struct set_fd_eof_info_request, eof) == 16 ); +C_ASSERT( sizeof(struct set_fd_eof_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 ); C_ASSERT( FIELD_OFFSET(struct get_window_layered_info_reply, color_key) == 8 ); diff --git a/server/trace.c b/server/trace.c index 406be00008e..bbdf17feb1a 100644 --- a/server/trace.c +++ b/server/trace.c @@ -4355,6 +4355,12 @@ static void dump_set_fd_name_info_request( const struct set_fd_name_info_request dump_varargs_string( ", filename=", cur_size ); }
+static void dump_set_fd_eof_info_request( const struct set_fd_eof_info_request *req ) +{ + fprintf( stderr, " handle=%04x", req->handle ); + dump_uint64( ", eof=", &req->eof ); +} + static void dump_get_window_layered_info_request( const struct get_window_layered_info_request *req ) { fprintf( stderr, " handle=%08x", req->handle ); @@ -4792,6 +4798,7 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = { (dump_func)dump_set_fd_completion_mode_request, (dump_func)dump_set_fd_disp_info_request, (dump_func)dump_set_fd_name_info_request, + (dump_func)dump_set_fd_eof_info_request, (dump_func)dump_get_window_layered_info_request, (dump_func)dump_set_window_layered_info_request, (dump_func)dump_alloc_user_handle_request, @@ -5067,6 +5074,7 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = { NULL, NULL, NULL, + NULL, (dump_func)dump_get_window_layered_info_reply, NULL, (dump_func)dump_alloc_user_handle_reply, @@ -5342,6 +5350,7 @@ static const char * const req_names[REQ_NB_REQUESTS] = { "set_fd_completion_mode", "set_fd_disp_info", "set_fd_name_info", + "set_fd_eof_info", "get_window_layered_info", "set_window_layered_info", "alloc_user_handle",