From b4ff6ddb32296f43439b4be79c7864f7ae7d14f1 Mon Sep 17 00:00:00 2001 From: Ondrej Holy Date: Wed, 13 Nov 2024 11:34:19 +0100 Subject: [PATCH] smb: Fix offset after truncate when appending The truncate operation is currently enabled when appending. However, the libsmbclient doesn't support O_APPEND flag property [1]. The offset is not reset after the truncate operation. This may lead to data corruptions. Let's explicitely seek to the desired offset when truncating to prevent this. [1] https://github.com/samba-team/samba/blob/e4e3f05/source3/libsmb/libsmb_file.c#L162-L183 --- daemon/gvfsbackendsmb.c | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/daemon/gvfsbackendsmb.c b/daemon/gvfsbackendsmb.c index c2075555..f287264b 100644 --- a/daemon/gvfsbackendsmb.c +++ b/daemon/gvfsbackendsmb.c @@ -780,6 +780,7 @@ typedef struct { char *uri; char *tmp_uri; char *backup_uri; + GVfsJobOpenForWriteMode mode; } SmbWriteHandle; static void @@ -824,6 +825,7 @@ do_create (GVfsBackend *backend, { handle = g_new0 (SmbWriteHandle, 1); handle->file = file; + handle->mode = job->mode; g_vfs_job_open_for_write_set_can_seek (job, TRUE); g_vfs_job_open_for_write_set_can_truncate (job, TRUE); @@ -869,6 +871,7 @@ do_append_to (GVfsBackend *backend, handle = g_new0 (SmbWriteHandle, 1); handle->file = file; + handle->mode = job->mode; g_vfs_job_open_for_write_set_initial_offset (job, initial_offset); @@ -1141,6 +1144,7 @@ do_replace (GVfsBackend *backend, handle->uri = uri; handle->tmp_uri = tmp_uri; handle->backup_uri = backup_uri; + handle->mode = job->mode; g_vfs_job_open_for_write_set_can_seek (job, TRUE); g_vfs_job_open_for_write_set_can_truncate (job, TRUE); @@ -1229,9 +1233,26 @@ do_truncate (GVfsBackend *backend, smbc_ftruncate = smbc_getFunctionFtruncate (op_backend->smb_context); if (smbc_ftruncate (op_backend->smb_context, handle->file, size) == -1) - g_vfs_job_failed_from_errno (G_VFS_JOB (job), errno); - else - g_vfs_job_succeeded (G_VFS_JOB (job)); + { + g_vfs_job_failed_from_errno (G_VFS_JOB (job), errno); + return; + } + + if (handle->mode == OPEN_FOR_WRITE_APPEND) + { + smbc_lseek_fn smbc_lseek; + off_t res; + + smbc_lseek = smbc_getFunctionLseek (op_backend->smb_context); + res = smbc_lseek (op_backend->smb_context, handle->file, size, SEEK_SET); + if (res == (off_t)-1) + { + g_vfs_job_failed_from_errno (G_VFS_JOB (job), errno); + return; + } + } + + g_vfs_job_succeeded (G_VFS_JOB (job)); } static void -- 2.46.2