The branch, master has been updated
       via  baf1d520044 smbd: fill fsp_flas.posix_append in open_file_ntcreate()
       via  e18a5381a82 tests: test SMB3 POSIX append-IO behaviour
       via  ec3e1927bae smbd: allow VFS_PWRITE_APPEND_OFFSET in 
vfs_valid_pwrite_range()
       via  69cdd233b5d smbd: assert fsp->fsp_flags.posix_append and offset in 
smbd_smb2_write_send()
       via  25c1ccb01b1 smbd: prepare smb2_write.c for handling a negative 
offset
       via  dcd329a359a vfs_default: implement POSIX append-IO
       via  2f287538bfa s3/lib: use VFS_PWRITE_APPEND_OFFSET in 
default_sys_recvfile()
       via  9c41e36af7e vfs: implement POSIX append-IO in vfs_pwrite_data()
       via  442bbee9bc1 vfs_io_uring: implement POSIX append-IO
       via  5f265cb77d7 vfs_aio_fork: implement POSIX append-IO
       via  127429a38ed lib: add sys_write_full()
       via  f67ad08bc69 smbd: check for VFS_PWRITE_APPEND_OFFSET in 
vfs_fill_sparse()
       via  62cc18dcac2 smbd: add vfs_valid_allocation_range() as a copy of 
vfs_valid_pwrite_range()
       via  ea7ca1189c7 s3/pylibsmb: add VFS_PWRITE_APPEND_OFFSET
       via  8d9d06e653a vfs: add VFS_PWRITE_APPEND_OFFSET
       via  38d1bbf69aa vfs: add fsp_flags.posix_append
       via  47c5d97d82b smbd: fix access_mask to FILE_APPEND_DATA mapping for 
POSIX opens
       via  5c36cd2b9e6 tests: add a test for copy-chunk on a POSIX handle
       via  c9001999ca3 tests: use libsmb.unix_mode_to_wire() in smb3unix.py
       via  63d59c15bb8 tests: use clean_file() from our superclass in 
smb3unix.py
       via  5c7b8793d75 pylibsmb: add "copy_chunk"
       via  aa0d0e3c91f smbtorture: verify Windows SEC_FILE_APPEND_DATA 
behaviour
       via  dc68aad8d16 smbd: fix an invalid memory access
      from  4e36eec2445 fruit: fixup size_t overflow check

https://git.samba.org/?p=samba.git;a=shortlog;h=master


- Log -----------------------------------------------------------------
commit baf1d520044f9d796ad545862572f0e7319dff04
Author: Ralph Boehme <[email protected]>
Date:   Thu Dec 5 10:26:59 2024 +0100

    smbd: fill fsp_flas.posix_append in open_file_ntcreate()
    
    This small changes enables the new append-IO machinery.
    
    Signed-off-by: Ralph Boehme <[email protected]>
    Reviewed-by: Jeremy Allison <[email protected]>
    
    Autobuild-User(master): Jeremy Allison <[email protected]>
    Autobuild-Date(master): Tue Jan  7 23:05:57 UTC 2025 on atb-devel-224

commit e18a5381a82e4fd740c9ef2601f24c9e6d1883df
Author: Ralph Boehme <[email protected]>
Date:   Thu Nov 28 12:12:26 2024 +0100

    tests: test SMB3 POSIX append-IO behaviour
    
    Signed-off-by: Ralph Boehme <[email protected]>
    Reviewed-by: Jeremy Allison <[email protected]>

commit ec3e1927bae6989859186d1f8981492c00d1f929
Author: Ralph Boehme <[email protected]>
Date:   Fri Nov 29 14:09:12 2024 +0100

    smbd: allow VFS_PWRITE_APPEND_OFFSET in vfs_valid_pwrite_range()
    
    Signed-off-by: Ralph Boehme <[email protected]>
    Reviewed-by: Jeremy Allison <[email protected]>

commit 69cdd233b5d2690f7aa19e6c3fedfaf3e8bd6f99
Author: Ralph Boehme <[email protected]>
Date:   Fri Nov 22 19:41:51 2024 +0100

    smbd: assert fsp->fsp_flags.posix_append and offset in 
smbd_smb2_write_send()
    
    Signed-off-by: Ralph Boehme <[email protected]>
    Reviewed-by: Jeremy Allison <[email protected]>

commit 25c1ccb01b14dbc44506f4a593434f0d7037f5b3
Author: Ralph Boehme <[email protected]>
Date:   Fri Nov 22 19:40:38 2024 +0100

    smbd: prepare smb2_write.c for handling a negative offset
    
    Use off_t instead of uint64_t for the offset in order to support negative
    offsets coming in over the wire for SMB3 POSIX append-IO which enforces
    offset=VFS_PWRITE_APPEND_OFFSET (-1) for all writes.
    
    Signed-off-by: Ralph Boehme <[email protected]>
    Reviewed-by: Jeremy Allison <[email protected]>

commit dcd329a359a1fffc20f6407e7bd7b615a17e693e
Author: Ralph Boehme <[email protected]>
Date:   Fri Nov 22 19:38:33 2024 +0100

    vfs_default: implement POSIX append-IO
    
    Signed-off-by: Ralph Boehme <[email protected]>
    Reviewed-by: Jeremy Allison <[email protected]>

commit 2f287538bfaf139fb319c732037bf1f9d63d7e50
Author: Ralph Boehme <[email protected]>
Date:   Fri Nov 29 14:06:39 2024 +0100

    s3/lib: use VFS_PWRITE_APPEND_OFFSET in default_sys_recvfile()
    
    Note that splice() itself doesn't work with an O_APPEND outfd:
    
    
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=efc968d450e013049a662d22727cf132618dcb2f
    
    Hence for the real splice() codepath itself no changes are needed, as splice
    will just fail with EINVAL triggering the fallback code.
    
    Signed-off-by: Ralph Boehme <[email protected]>
    Reviewed-by: Jeremy Allison <[email protected]>

commit 9c41e36af7e136db4eb85c29c555192965b3c371
Author: Ralph Boehme <[email protected]>
Date:   Sun Nov 24 08:23:36 2024 +0100

    vfs: implement POSIX append-IO in vfs_pwrite_data()
    
    This basically just avoids clobbering a possible 
offset=VFS_PWRITE_APPEND_OFFSET
    when calling SMB_VFS_PWRITE().
    
    Signed-off-by: Ralph Boehme <[email protected]>
    Reviewed-by: Jeremy Allison <[email protected]>

commit 442bbee9bc106f75c066cca7cdc7ef4ebd55921a
Author: Ralph Boehme <[email protected]>
Date:   Sun Nov 24 09:27:36 2024 +0100

    vfs_io_uring: implement POSIX append-IO
    
    Signed-off-by: Ralph Boehme <[email protected]>
    Reviewed-by: Jeremy Allison <[email protected]>

commit 5f265cb77d732d4d1527d092a056dfaf48362888
Author: Ralph Boehme <[email protected]>
Date:   Sun Nov 24 08:10:25 2024 +0100

    vfs_aio_fork: implement POSIX append-IO
    
    Signed-off-by: Ralph Boehme <[email protected]>
    Reviewed-by: Jeremy Allison <[email protected]>

commit 127429a38ed4edb238e7d2a38dbae426e22751fe
Author: Ralph Boehme <[email protected]>
Date:   Sun Nov 24 08:08:26 2024 +0100

    lib: add sys_write_full()
    
    Basically a copy of sys_pwrite_full(), calling write() instead of pwrite().
    
    Signed-off-by: Ralph Boehme <[email protected]>
    Reviewed-by: Jeremy Allison <[email protected]>

commit f67ad08bc696b58cb416f45897ea1f7b3dd4f908
Author: Ralph Boehme <[email protected]>
Date:   Fri Nov 29 13:04:36 2024 +0100

    smbd: check for VFS_PWRITE_APPEND_OFFSET in vfs_fill_sparse()
    
    This is the only place a function dealing with allocation and file length 
being
    called from the write IO path. In the case of POSIX append-IO with
    offset=VFS_PWRITE_APPEND_OFFSET vfs_fill_sparse() must be a noop.
    
    Signed-off-by: Ralph Boehme <[email protected]>
    Reviewed-by: Jeremy Allison <[email protected]>

commit 62cc18dcac29b803d191af7d7800067a23a33458
Author: Ralph Boehme <[email protected]>
Date:   Fri Nov 29 13:00:30 2024 +0100

    smbd: add vfs_valid_allocation_range() as a copy of vfs_valid_pwrite_range()
    
    Not a copy of the whole code obviously, a copy of behaviour. A subsequent 
commit
    will further change vfs_valid_pwrite_range().
    
    Existing callers of vfs_valid_pwrite_range() that are not calling it in the
    write-IO codepath, but when dealing with allocation and size, are converted 
to
    use vfs_valid_allocation_range().
    
    No change in behaviour.
    
    Signed-off-by: Ralph Boehme <[email protected]>
    Reviewed-by: Jeremy Allison <[email protected]>

commit ea7ca1189c7d5ae1b8263e8d565cbccdff1334a1
Author: Ralph Boehme <[email protected]>
Date:   Thu Nov 28 08:08:46 2024 +0100

    s3/pylibsmb: add VFS_PWRITE_APPEND_OFFSET
    
    Signed-off-by: Ralph Boehme <[email protected]>
    Reviewed-by: Jeremy Allison <[email protected]>

commit 8d9d06e653a9bc2abbd9f0a3ba233138b1ff4540
Author: Ralph Boehme <[email protected]>
Date:   Fri Nov 22 19:36:18 2024 +0100

    vfs: add VFS_PWRITE_APPEND_OFFSET
    
    Signed-off-by: Ralph Boehme <[email protected]>
    Reviewed-by: Jeremy Allison <[email protected]>

commit 38d1bbf69aa8957fd8ad7c0963d66b6ead71e579
Author: Ralph Boehme <[email protected]>
Date:   Fri Nov 22 19:36:39 2024 +0100

    vfs: add fsp_flags.posix_append
    
    Signed-off-by: Ralph Boehme <[email protected]>
    Reviewed-by: Jeremy Allison <[email protected]>

commit 47c5d97d82b4ed6ad3cd4bf91b5824234af1b319
Author: Ralph Boehme <[email protected]>
Date:   Sat Nov 9 16:15:08 2024 +0100

    smbd: fix access_mask to FILE_APPEND_DATA mapping for POSIX opens
    
    Only use POSIX O_APPEND flag if the client requested FILE_APPEND_DATA 
without
    FILE_WRITE_DATA.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=15751
    
    Signed-off-by: Ralph Boehme <[email protected]>
    Reviewed-by: Jeremy Allison <[email protected]>

commit 5c36cd2b9e6e2df7b9bedef71a9ba32820d89449
Author: Ralph Boehme <[email protected]>
Date:   Mon Nov 11 10:39:15 2024 +0100

    tests: add a test for copy-chunk on a POSIX handle
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=15751
    
    Signed-off-by: Ralph Boehme <[email protected]>
    Reviewed-by: Jeremy Allison <[email protected]>

commit c9001999ca3e3a43e197767420dd7649dad4f858
Author: Ralph Boehme <[email protected]>
Date:   Thu Dec 5 10:20:00 2024 +0100

    tests: use libsmb.unix_mode_to_wire() in smb3unix.py
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=15751
    
    Signed-off-by: Ralph Boehme <[email protected]>
    Reviewed-by: Jeremy Allison <[email protected]>

commit 63d59c15bb81daf55d21bbab1d868f034d125a78
Author: Ralph Boehme <[email protected]>
Date:   Mon Nov 11 10:38:05 2024 +0100

    tests: use clean_file() from our superclass in smb3unix.py
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=15751
    
    Signed-off-by: Ralph Boehme <[email protected]>
    Reviewed-by: Jeremy Allison <[email protected]>

commit 5c7b8793d753fe47720a95cff3fad72827ca4f82
Author: Ralph Boehme <[email protected]>
Date:   Mon Nov 11 08:06:13 2024 +0100

    pylibsmb: add "copy_chunk"
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=15751
    
    Signed-off-by: Ralph Boehme <[email protected]>
    Reviewed-by: Jeremy Allison <[email protected]>

commit aa0d0e3c91f914464d7b22391d74be9845cf17f9
Author: Ralph Boehme <[email protected]>
Date:   Sat Nov 9 16:00:39 2024 +0100

    smbtorture: verify Windows SEC_FILE_APPEND_DATA behaviour
    
    This test proves that Windows will not enforce append behaviour when using
    SEC_FILE_APPEND_DATA: writing with an offset and length into existing data 
is
    not mapped to an append operation. According to
    
    
https://learn.microsoft.com/en-us/windows/win32/api/winternl/nf-winternl-ntcreatefile
    
    Windows internal APIs seemt to support append-IO:
    
      If only the FILE_APPEND_DATA and SYNCHRONIZE flags are set, the caller can
      write only to the end of the file, and any offset information on writes 
to the
      file is ignored. However, the file is automatically extended as necessary 
for
      this type of write operation.
    
    ...but at least over SMB2 it doesn't work.
    
    This also demonstrates that Windows behaves as documented in the footnote in
    
    MS-SMB2 3.3.5.13 "Receiving an SMB2 WRITE Request":
    
      If the range being written to is within the existing file size and
      Open.GrantedAccess does not include FILE_WRITE_DATA, or if the range being
      written to extends the file size and Open.GrantedAccess does not include
      FILE_APPEND_DATA, the server SHOULD<358> fail the request with
      STATUS_ACCESS_DENIED.
    
    MS-SMB2 <358> Section 3.3.5.13:
    
      Windows SMB2 servers allow the operation when either FILE_APPEND_DATA or
      FILE_WRITE_DATA is set in Open.GrantedAccess.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=15751
    
    Signed-off-by: Ralph Boehme <[email protected]>

commit dc68aad8d164a0cbf21ff3fee36e208255f352e3
Author: Ralph Boehme <[email protected]>
Date:   Fri Nov 22 10:21:14 2024 +0100

    smbd: fix an invalid memory access
    
    This was introduced by f86208d272cfa0ce6753b02d3f5b1cce4fd91e2e:
    
    ==47833== Invalid read of size 1
    ==47833==    at 0x4846782: strlen (vg_replace_strmem.c:494)
    ==47833==    by 0x4F9D257: __vfprintf_internal (vfprintf-process-arg.c:397)
    ==47833==    by 0x4FBD3A5: __vasprintf_internal (vasprintf.c:57)
    ==47833==    by 0x4EBDFFD: __dbgtext_va (debug.c:1939)
    ==47833==    by 0x4EBE125: dbgtext (debug.c:1960)
    ==47833==    by 0x49A9E77: exit_server_common (server_exit.c:230)
    ==47833==    by 0x49A9EE6: smbd_exit_server_cleanly (server_exit.c:247)
    ==47833==    by 0x4ECA2EF: exit_server_cleanly (smbd_shim.c:113)
    ==47833==    by 0x495E72B: smbd_server_connection_terminate_done 
(smb2_server.c:1758)
    ==47833==    by 0x4D4ED6A: _tevent_req_notify_callback (tevent_req.c:177)
    ==47833==    by 0x4D4EEFB: tevent_req_finish (tevent_req.c:234)
    ==47833==    by 0x4D4F02A: tevent_req_trigger (tevent_req.c:291)
    ==47833==  Address 0xb8cf820 is 96 bytes inside a block of size 123 free'd
    ==47833==    at 0x484317B: free (vg_replace_malloc.c:872)
    ==47833==    by 0x4CF8950: _tc_free_internal (talloc.c:1222)
    ==47833==    by 0x4CF993E: _tc_free_children_internal (talloc.c:1669)
    ==47833==    by 0x4CF8830: _tc_free_internal (talloc.c:1184)
    ==47833==    by 0x4CF993E: _tc_free_children_internal (talloc.c:1669)
    ==47833==    by 0x4CF8830: _tc_free_internal (talloc.c:1184)
    ==47833==    by 0x4CF89F7: _talloc_free_internal (talloc.c:1248)
    ==47833==    by 0x4CF9D93: _talloc_free (talloc.c:1792)
    ==47833==    by 0x495E700: smbd_server_connection_terminate_done 
(smb2_server.c:1748)
    ==47833==    by 0x4D4ED6A: _tevent_req_notify_callback (tevent_req.c:177)
    ==47833==    by 0x4D4EEFB: tevent_req_finish (tevent_req.c:234)
    ==47833==    by 0x4D4F02A: tevent_req_trigger (tevent_req.c:291)
    ==47833==  Block was alloc'd at
    ==47833==    at 0x48407B4: malloc (vg_replace_malloc.c:381)
    ==47833==    by 0x4CF7CAC: __talloc_with_prefix (talloc.c:783)
    ==47833==    by 0x4CF7E46: __talloc (talloc.c:825)
    ==47833==    by 0x4CFB007: __talloc_strlendup (talloc.c:2454)
    ==47833==    by 0x4CFB0BD: talloc_strdup (talloc.c:2470)
    ==47833==    by 0x495E7B6: smbd_server_connection_terminate_ex 
(smb2_server.c:1775)
    ==47833==    by 0x4969222: smbd_smb2_connection_handler (smb2_server.c:5291)
    ==47833==    by 0x4D4CAE2: tevent_common_invoke_fd_handler (tevent_fd.c:174)
    ==47833==    by 0x4D596D5: epoll_event_loop (tevent_epoll.c:696)
    ==47833==    by 0x4D59E5E: epoll_event_loop_once (tevent_epoll.c:926)
    ==47833==    by 0x4D5529C: std_event_loop_once (tevent_standard.c:110)
    ==47833==    by 0x4D4B3B9: _tevent_loop_once (tevent.c:820)
    ==47833==
    
    state was a child of "xconn", so when xconn was freed state went away.
    
    As reason is used at the very end of exit_server_common() after *all* global
    objects that could be used as talloc parent are freed, there's just no 
other way
    to make "reason" a talloc string then allocating it from the NULL context 
right
    away.
    
    Signed-off-by: Ralph Boehme <[email protected]>
    Reviewed-by: Jeremy Allison <[email protected]>

-----------------------------------------------------------------------

Summary of changes:
 lib/util/sys_rw.c                 |  38 +++++++++++
 lib/util/sys_rw.h                 |   1 +
 python/samba/tests/smb3unix.py    | 128 ++++++++++++++++++++++++++++++-------
 source3/include/vfs.h             |   4 ++
 source3/lib/recvfile.c            |   2 +-
 source3/libsmb/pylibsmb.c         |  83 ++++++++++++++++++++++++
 source3/modules/vfs_aio_fork.c    |  18 +++++-
 source3/modules/vfs_default.c     |  37 +++++++++--
 source3/modules/vfs_io_uring.c    |  40 ++++++++++--
 source3/smbd/fileio.c             |   2 +-
 source3/smbd/open.c               |   6 +-
 source3/smbd/proto.h              |   5 +-
 source3/smbd/smb2_aio.c           |   2 +-
 source3/smbd/smb2_server.c        |   2 +-
 source3/smbd/smb2_write.c         |  22 +++++--
 source3/smbd/vfs.c                |  43 ++++++++++---
 source3/wscript                   |   2 +-
 source4/torture/smb2/read_write.c | 130 ++++++++++++++++++++++++++++++++++++++
 18 files changed, 507 insertions(+), 58 deletions(-)


Changeset truncated at 500 lines:

diff --git a/lib/util/sys_rw.c b/lib/util/sys_rw.c
index d25a42b7082..957eafb4aa8 100644
--- a/lib/util/sys_rw.c
+++ b/lib/util/sys_rw.c
@@ -293,3 +293,41 @@ ssize_t sys_pwrite_full(int fd, const void *buf, size_t 
count, off_t off)
 
        return total_written;
 }
+
+/*******************************************************************
+ A write wrapper that will deal with EINTR and never allow a short
+ write unless the file system returns an error.
+********************************************************************/
+
+ssize_t sys_write_full(int fd, const void *buf, size_t count)
+{
+       ssize_t total_written = 0;
+       const uint8_t *curr_buf = (const uint8_t *)buf;
+       size_t curr_count = count;
+
+       while (curr_count != 0) {
+               ssize_t ret = sys_write(fd,
+                                       curr_buf,
+                                       curr_count);
+               if (ret == -1) {
+                       return -1;
+               }
+               if (ret == 0) {
+                       /* Ensure we can never spin. */
+                       errno = ENOSPC;
+                       return -1;
+               }
+
+               if (ret > curr_count) {
+                       errno = EIO;
+                       return -1;
+               }
+
+               curr_buf += ret;
+               curr_count -= ret;
+
+               total_written += ret;
+       }
+
+       return total_written;
+}
diff --git a/lib/util/sys_rw.h b/lib/util/sys_rw.h
index 3812159a362..f62d797ec77 100644
--- a/lib/util/sys_rw.h
+++ b/lib/util/sys_rw.h
@@ -41,5 +41,6 @@ ssize_t sys_pread(int fd, void *buf, size_t count, off_t off);
 ssize_t sys_pread_full(int fd, void *buf, size_t count, off_t off);
 ssize_t sys_pwrite(int fd, const void *buf, size_t count, off_t off);
 ssize_t sys_pwrite_full(int fd, const void *buf, size_t count, off_t off);
+ssize_t sys_write_full(int fd, const void *buf, size_t count);
 
 #endif
diff --git a/python/samba/tests/smb3unix.py b/python/samba/tests/smb3unix.py
index 7d2529ad747..5c8ab182061 100644
--- a/python/samba/tests/smb3unix.py
+++ b/python/samba/tests/smb3unix.py
@@ -132,14 +132,6 @@ class Smb3UnixTests(samba.tests.libsmb.LibsmbTests):
         e = cm.exception
         self.assertEqual(e.args[0], ntstatus.NT_STATUS_INVALID_PARAMETER)
 
-    def delete_test_file(self, c, fname, mode=0):
-        f,_,cc_out = c.create_ex(fname,
-                        DesiredAccess=security.SEC_STD_ALL,
-                        CreateDisposition=libsmb.FILE_OPEN,
-                        CreateContexts=[posix_context(mode)])
-        c.delete_on_close(f, True)
-        c.close(f)
-
     def test_posix_query_dir(self):
         test_files = []
         try:
@@ -153,9 +145,10 @@ class Smb3UnixTests(samba.tests.libsmb.LibsmbTests):
 
             for i in range(10):
                 fname = '\\test%d' % i
+                wire_mode = libsmb.unix_mode_to_wire(0o744)
                 f,_,cc_out = c.create_ex(fname,
                                 CreateDisposition=libsmb.FILE_OPEN_IF,
-                                CreateContexts=[posix_context(0o744)])
+                                CreateContexts=[posix_context(wire_mode)])
                 c.close(f)
                 test_files.append(fname)
 
@@ -170,7 +163,7 @@ class Smb3UnixTests(samba.tests.libsmb.LibsmbTests):
         finally:
             if len(test_files) > 0:
                 for fname in test_files:
-                    self.delete_test_file(c, fname)
+                    self.clean_file(c, fname)
 
     def test_posix_reserved_char(self):
         c = libsmb.Conn(
@@ -186,10 +179,11 @@ class Smb3UnixTests(samba.tests.libsmb.LibsmbTests):
 
         for fname in test_files:
             try:
+                wire_mode = libsmb.unix_mode_to_wire(0o744)
                 f,_,cc_out = c.create_ex('\\%s' % fname,
                                 CreateDisposition=libsmb.FILE_CREATE,
                                 DesiredAccess=security.SEC_STD_DELETE,
-                                CreateContexts=[posix_context(0o744)])
+                                CreateContexts=[posix_context(wire_mode)])
             except NTSTATUSError as e:
                 self.fail(e)
             c.delete_on_close(f, True)
@@ -204,10 +198,11 @@ class Smb3UnixTests(samba.tests.libsmb.LibsmbTests):
             posix=True)
         self.assertTrue(c.have_posix())
 
+        wire_mode = libsmb.unix_mode_to_wire(0o744)
         f,_,cc_out = c.create_ex('\\TESTING999',
                         DesiredAccess=security.SEC_STD_ALL,
                         CreateDisposition=libsmb.FILE_CREATE,
-                        CreateContexts=[posix_context(0o744)])
+                        CreateContexts=[posix_context(wire_mode)])
         c.delete_on_close(f, True)
         c.close(f)
 
@@ -221,18 +216,20 @@ class Smb3UnixTests(samba.tests.libsmb.LibsmbTests):
                 posix=True)
             self.assertTrue(c.have_posix())
 
+            wire_mode = libsmb.unix_mode_to_wire(0o644)
             f,_,cc_out = c.create_ex('\\xx',
                             DesiredAccess=security.SEC_STD_ALL,
                             CreateDisposition=libsmb.FILE_CREATE,
-                            CreateContexts=[posix_context(0o644)])
+                            CreateContexts=[posix_context(wire_mode)])
             c.close(f)
 
             fail = False
+            wire_mode = libsmb.unix_mode_to_wire(0)
             try:
                 f,_,cc_out = c.create_ex('\\XX',
                                 DesiredAccess=security.SEC_STD_ALL,
                                 CreateDisposition=libsmb.FILE_OPEN,
-                                CreateContexts=[posix_context(0)])
+                                CreateContexts=[posix_context(wire_mode)])
             except NTSTATUSError:
                 pass
             else:
@@ -242,7 +239,7 @@ class Smb3UnixTests(samba.tests.libsmb.LibsmbTests):
             self.assertFalse(fail, "Opening uppercase file didn't fail")
 
         finally:
-            self.delete_test_file(c, '\\xx')
+            self.clean_file(c, '\\xx')
 
     def test_posix_perm_files(self):
         test_files = {}
@@ -267,10 +264,11 @@ class Smb3UnixTests(samba.tests.libsmb.LibsmbTests):
 
                 fname = 'testfile%04o' % perm
                 test_files[fname] = perm
+                wire_mode = libsmb.unix_mode_to_wire(perm)
                 f,_,cc_out = c.create_ex('\\%s' % fname,
                                 DesiredAccess=security.SEC_FILE_ALL,
                                 CreateDisposition=libsmb.FILE_CREATE,
-                                CreateContexts=[posix_context(perm)])
+                                CreateContexts=[posix_context(wire_mode)])
                 if perm & 0o200 == 0o200:
                     c.write(f, buffer=b"data", offset=0)
                 c.close(f)
@@ -281,7 +279,7 @@ class Smb3UnixTests(samba.tests.libsmb.LibsmbTests):
                                 DesiredAccess=security.SEC_STD_ALL,
                                 CreateDisposition=libsmb.FILE_CREATE,
                                 CreateOptions=libsmb.FILE_DIRECTORY_FILE,
-                                CreateContexts=[posix_context(perm)])
+                                CreateContexts=[posix_context(wire_mode)])
                 c.close(f)
 
             res = c.list("", info_level=libsmb.SMB2_FIND_POSIX_INFORMATION)
@@ -331,7 +329,7 @@ class Smb3UnixTests(samba.tests.libsmb.LibsmbTests):
         finally:
             if len(test_files) > 0:
                 for fname in test_files.keys():
-                    self.delete_test_file(c, '\\%s' % fname)
+                    self.clean_file(c, '\\%s' % fname)
 
     def test_share_root_null_sids_fid(self):
         c = libsmb.Conn(
@@ -411,8 +409,8 @@ class Smb3UnixTests(samba.tests.libsmb.LibsmbTests):
             self.assertTrue(str(cc.group).startswith("S-1-22-2-"))
 
         finally:
-            self.delete_test_file(c, '\\test_create_context_basic1_file')
-            self.delete_test_file(c, '\\test_create_context_basic1_dir')
+            self.clean_file(c, '\\test_create_context_basic1_file')
+            self.clean_file(c, '\\test_create_context_basic1_dir')
 
     def test_create_context_reparse(self):
         """
@@ -429,10 +427,11 @@ class Smb3UnixTests(samba.tests.libsmb.LibsmbTests):
 
             tag = 0x80000025
 
+            wire_mode = libsmb.unix_mode_to_wire(0o600)
             f,_,cc_out = c.create_ex('\\reparse',
                                      DesiredAccess=security.SEC_STD_ALL,
                                      CreateDisposition=libsmb.FILE_CREATE,
-                                     CreateContexts=[posix_context(0o600)])
+                                     CreateContexts=[posix_context(wire_mode)])
 
             cc = ndr_unpack(smb3posix.smb3_posix_cc_info, cc_out[0][1])
             self.assertEqual(cc.reparse_tag, 
libsmb.IO_REPARSE_TAG_RESERVED_ZERO)
@@ -442,17 +441,18 @@ class Smb3UnixTests(samba.tests.libsmb.LibsmbTests):
 
             c.close(f)
 
+            wire_mode = libsmb.unix_mode_to_wire(0o600)
             f,_,cc_out = c.create_ex('\\reparse',
                                      DesiredAccess=security.SEC_STD_ALL,
                                      CreateDisposition=libsmb.FILE_OPEN,
-                                     CreateContexts=[posix_context(0o600)])
+                                     CreateContexts=[posix_context(wire_mode)])
             c.close(f)
 
             cc = ndr_unpack(smb3posix.smb3_posix_cc_info, cc_out[0][1])
             self.assertEqual(cc.reparse_tag, tag)
 
         finally:
-            self.delete_test_file(c, '\\reparse')
+            self.clean_file(c, '\\reparse')
 
     def test_delete_on_close(self):
         """
@@ -473,12 +473,13 @@ class Smb3UnixTests(samba.tests.libsmb.LibsmbTests):
             CreateDisposition=libsmb.FILE_CREATE)
         self.addCleanup(self.clean_file, winconn, 'test_delete_on_close')
 
+        wire_mode = libsmb.unix_mode_to_wire(0o600)
         fdp,_,_ = posixconn.create_ex(
             'test_delete_on_close',
             DesiredAccess=security.SEC_FILE_WRITE_ATTRIBUTE | 
security.SEC_STD_DELETE,
             ShareAccess=0x07,
             CreateDisposition=libsmb.FILE_OPEN,
-            CreateContexts=[posix_context(0o600)])
+            CreateContexts=[posix_context(wire_mode)])
 
         winconn.delete_on_close(fdw, 1)
         posixconn.delete_on_close(fdp, 1)
@@ -509,3 +510,82 @@ class Smb3UnixTests(samba.tests.libsmb.LibsmbTests):
             winconn.get_posix_fs_info()
         e = cm.exception
         self.assertEqual(e.args[0], ntstatus.NT_STATUS_INVALID_INFO_CLASS)
+
+    def test_copy_chunk_posix(self):
+        """
+        Test copy-chunk works with a destination handle opened in POSIX mode
+        """
+        (_, c) = self.connections()
+
+        self.clean_file(c, '\\test_copy_chunk_posix_src')
+        self.clean_file(c, '\\test_copy_chunk_posix_dst')
+
+        wire_mode = libsmb.unix_mode_to_wire(0o644)
+
+        sh,*_ = c.create_ex('\\test_copy_chunk_posix_src',
+                          DesiredAccess=security.SEC_GENERIC_ALL,
+                          CreateDisposition=libsmb.FILE_CREATE,
+                          CreateContexts=[posix_context(wire_mode)])
+
+        dh,*_ = c.create_ex('\\test_copy_chunk_posix_dst',
+                          DesiredAccess=security.SEC_GENERIC_WRITE,
+                          CreateDisposition=libsmb.FILE_CREATE,
+                          CreateContexts=[posix_context(wire_mode)])
+
+        c.write(sh, buffer=b"data", offset=0)
+
+        try:
+            written = c.copy_chunk(sh, dh, 4, 0, 0)
+        except Exception as e:
+            self.fail(str(e))
+        finally:
+            c.close(sh)
+            c.close(dh)
+            self.clean_file(c, '\\test_copy_chunk_posix_src')
+            self.clean_file(c, '\\test_copy_chunk_posix_dst')
+
+    def test_append(self):
+        """
+        Test append-io behaviour
+        """
+        (wc, pc) = self.connections()
+
+        self.clean_file(pc, '\\test_append')
+        wire_mode = libsmb.unix_mode_to_wire(0o644)
+
+        ph,*_ = pc.create_ex('\\test_append',
+                             DesiredAccess=security.SEC_FILE_APPEND_DATA | 
security.SEC_FILE_READ_DATA,
+                             CreateDisposition=libsmb.FILE_CREATE,
+                             
ShareAccess=libsmb.FILE_SHARE_READ|libsmb.FILE_SHARE_WRITE,
+                             CreateContexts=[posix_context(wire_mode)])
+
+        wh,*_ = wc.create_ex('\\test_append',
+                             DesiredAccess=security.SEC_FILE_APPEND_DATA,
+                             
ShareAccess=libsmb.FILE_SHARE_READ|libsmb.FILE_SHARE_WRITE,
+                             CreateDisposition=libsmb.FILE_OPEN)
+
+        wc.write(wh, buffer=b"hello", offset=0)
+        wc.write(wh, buffer=b"h", offset=0)
+
+        try:
+            pc.write(ph, buffer=b"world", offset=0)
+        except Exception as e:
+            self.assertEqual(e.args[0], ntstatus.NT_STATUS_INVALID_PARAMETER)
+            pass
+        else:
+            pc.close(ph)
+            wc.close(wh)
+            self.clean_file(pc, '\\test_append')
+            self.fail("Write with offset=0 must fail on POSIX handle in append 
mode")
+
+        pc.write(ph, buffer=b" world", offset=libsmb.VFS_PWRITE_APPEND_OFFSET)
+
+        info = pc.qfileinfo(ph, libsmb.FSCC_FILE_POSIX_INFORMATION);
+        self.assertEqual(info['size'], 11)
+
+        data = pc.read(ph, 0, 11)
+        self.assertEqual(data, b'hello world')
+
+        pc.close(ph)
+        wc.close(wh)
+        self.clean_file(pc, '\\test_append')
diff --git a/source3/include/vfs.h b/source3/include/vfs.h
index ae1c4f95560..581148fa053 100644
--- a/source3/include/vfs.h
+++ b/source3/include/vfs.h
@@ -387,6 +387,7 @@
  * Version 50 - Remove FSP_POSIX_FLAGS_PATHNAMES, remove FSP_POSIX_FLAGS_RENAME
  *              and convert struct files_struct.posix_flags to
  *              struct files_struct.fsp_flags.posix_open
+ * Version 50 - Add struct files_struct.fsp_flags.posix_append
  */
 
 #define SMB_VFS_INTERFACE_VERSION 50
@@ -462,6 +463,7 @@ typedef struct files_struct {
                bool encryption_required : 1;
                bool fstat_before_close : 1;
                bool posix_open : 1;
+               bool posix_append : 1;
        } fsp_flags;
 
        struct tevent_timer *update_write_time_event;
@@ -916,6 +918,8 @@ struct vfs_rename_how {
        int flags;
 };
 
+#define VFS_PWRITE_APPEND_OFFSET -1
+
 /*
     Available VFS operations. These values must be in sync with vfs_ops struct
     (struct vfs_fn_pointers and struct vfs_handle_pointers inside of struct 
vfs_ops).
diff --git a/source3/lib/recvfile.c b/source3/lib/recvfile.c
index e1eb241d7bd..5adb3395989 100644
--- a/source3/lib/recvfile.c
+++ b/source3/lib/recvfile.c
@@ -63,7 +63,7 @@ static ssize_t default_sys_recvfile(int fromfd,
                return 0;
        }
 
-       if (tofd != -1 && offset != (off_t)-1) {
+       if (tofd != -1 && offset != (off_t)VFS_PWRITE_APPEND_OFFSET) {
                if (lseek(tofd, offset, SEEK_SET) == -1) {
                        if (errno != ESPIPE) {
                                return -1;
diff --git a/source3/libsmb/pylibsmb.c b/source3/libsmb/pylibsmb.c
index 7dc739897ad..97ae69ef50e 100644
--- a/source3/libsmb/pylibsmb.c
+++ b/source3/libsmb/pylibsmb.c
@@ -2935,6 +2935,82 @@ static PyObject *py_cli_fsctl(
        return result;
 }
 
+static int copy_chunk_cb(off_t n, void *priv)
+{
+       return 1;
+}
+
+static PyObject *py_cli_copy_chunk(struct py_cli_state *self,
+                                  PyObject *args,
+                                  PyObject *kwds)
+{
+       TALLOC_CTX *frame = talloc_stackframe();
+       struct tevent_req *req = NULL;
+       PyObject *result = NULL;
+       int fnum_src;
+       int fnum_dst;
+       unsigned long long size;
+       unsigned long long src_offset;
+       unsigned long long dst_offset;
+       off_t written;
+       static const char *kwlist[] = {
+               "fnum_src",
+               "fnum_dst",
+               "size",
+               "src_offset",
+               "dst_offset",
+               NULL,
+       };
+       NTSTATUS status;
+       bool ok;
+
+       if (smbXcli_conn_protocol(self->cli->conn) < PROTOCOL_SMB2_02) {
+               errno = EINVAL;
+               PyErr_SetFromErrno(PyExc_RuntimeError);
+               goto err;
+       }
+
+       ok = ParseTupleAndKeywords(
+                   args,
+                   kwds,
+                   "iiKKK",
+                   kwlist,
+                   &fnum_src,
+                   &fnum_dst,
+                   &size,
+                   &src_offset,
+                   &dst_offset);
+       if (!ok) {
+               goto err;
+       }
+
+       req = cli_smb2_splice_send(frame,
+                                  self->ev,
+                                  self->cli,
+                                  fnum_src,
+                                  fnum_dst,
+                                  size,
+                                  src_offset,
+                                  dst_offset,
+                                  copy_chunk_cb,
+                                  NULL);
+       if (!py_tevent_req_wait_exc(self, req)) {
+               goto err;
+       }
+
+       status = cli_smb2_splice_recv(req, &written);
+       if (!NT_STATUS_IS_OK(status)) {
+               PyErr_SetNTSTATUS(status);
+               goto err;
+       }
+
+       result = Py_BuildValue("K", written);
+
+err:
+       TALLOC_FREE(frame);
+       return result;
+}
+
 static PyMethodDef py_cli_state_methods[] = {
        { "settimeout", (PyCFunction)py_cli_settimeout, METH_VARARGS,
          "settimeout(new_timeout_msecs) => return old_timeout_msecs" },
@@ -3061,6 +3137,11 @@ static PyMethodDef py_cli_state_methods[] = {
          METH_VARARGS|METH_KEYWORDS,
          "mknod(path, mode | major, minor)",
        },
+       { "copy_chunk",
+         PY_DISCARD_FUNC_SIG(PyCFunction, py_cli_copy_chunk),
+         METH_VARARGS|METH_KEYWORDS,
+         "copy_chunk(fnum_src, fnum_dst, size, src_offset, dst_offset) -> 
written",
+       },
        { NULL, NULL, 0, NULL }
 };
 
@@ -3192,6 +3273,8 @@ MODULE_INIT_FUNC(libsmb_samba_cwrapper)
        ADD_FLAGS(FILE_SHARE_WRITE);
        ADD_FLAGS(FILE_SHARE_DELETE);
 
+       ADD_FLAGS(VFS_PWRITE_APPEND_OFFSET);
+
        /* change notify completion filter flags */
        ADD_FLAGS(FILE_NOTIFY_CHANGE_FILE_NAME);
        ADD_FLAGS(FILE_NOTIFY_CHANGE_DIR_NAME);
diff --git a/source3/modules/vfs_aio_fork.c b/source3/modules/vfs_aio_fork.c
index 87dcbdd6270..61ba71b5c59 100644
--- a/source3/modules/vfs_aio_fork.c
+++ b/source3/modules/vfs_aio_fork.c
@@ -98,6 +98,7 @@ fail:
 
 enum cmd_type {
        READ_CMD,
+       PWRITE_CMD,
        WRITE_CMD,
        FSYNC_CMD
 };
@@ -110,8 +111,11 @@ static const char *cmd_type_str(enum cmd_type cmd)
        case READ_CMD:
                result = "READ";
                break;
+       case PWRITE_CMD:
+               result = "PWRITE";
+               break;
        case WRITE_CMD:
-               result = "WRITE";


-- 
Samba Shared Repository


Reply via email to