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