Qian Hong : ntdll: Truncate files through the server.

Alexandre Julliard julliard at winehq.org
Tue Jun 29 15:58:26 CDT 2021


Module: wine
Branch: master
Commit: 4e84a553a8f0e14dd9c36ea280003d8d96e6a9cd
URL:    https://source.winehq.org/git/wine.git/?a=commit;h=4e84a553a8f0e14dd9c36ea280003d8d96e6a9cd

Author: Qian Hong <qhong at codeweavers.com>
Date:   Fri Jun 25 00:28:51 2021 -0500

ntdll: Truncate files through the server.

Signed-off-by: Zebediah Figura <z.figura12 at gmail.com>
Signed-off-by: Alexandre Julliard <julliard at 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 */
+ at REQ(set_fd_eof_info)
+    obj_handle_t handle;        /* handle to a file or directory */
+    file_pos_t   eof;           /* offset of eof of file */
+ at 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",




More information about the wine-cvs mailing list