Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package python-smbprotocol for 
openSUSE:Factory checked in at 2026-04-04 19:07:54
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-smbprotocol (Old)
 and      /work/SRC/openSUSE:Factory/.python-smbprotocol.new.21863 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-smbprotocol"

Sat Apr  4 19:07:54 2026 rev:25 rq:1344560 version:1.16.1

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-smbprotocol/python-smbprotocol.changes    
2026-02-10 21:14:44.129378090 +0100
+++ 
/work/SRC/openSUSE:Factory/.python-smbprotocol.new.21863/python-smbprotocol.changes
 2026-04-04 19:09:49.903064263 +0200
@@ -1,0 +2,9 @@
+Thu Apr  2 06:17:39 UTC 2026 - Martin Hauke <[email protected]>
+
+- Update to version 1.16.1
+  * Fix create_context offset when opening a dir/file.
+  * Fix Memory Leaks in Structure and Structure Subclasses.
+  * Fix copyfile fallback when server-side SMB copy is unsupported.
+  * Handle ECONNABORTED and avoid joining the current thread.
+
+-------------------------------------------------------------------

Old:
----
  python-smbprotocol-1.16.0.tar.gz

New:
----
  python-smbprotocol-1.16.1.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-smbprotocol.spec ++++++
--- /var/tmp/diff_new_pack.hZ6nAL/_old  2026-04-04 19:09:50.387084108 +0200
+++ /var/tmp/diff_new_pack.hZ6nAL/_new  2026-04-04 19:09:50.387084108 +0200
@@ -17,7 +17,7 @@
 
 
 Name:           python-smbprotocol
-Version:        1.16.0
+Version:        1.16.1
 Release:        0
 Summary:        SMBv2/v3 client for Python 2 and 3
 License:        MIT

++++++ python-smbprotocol-1.16.0.tar.gz -> python-smbprotocol-1.16.1.tar.gz 
++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/smbprotocol-1.16.0/CHANGELOG.md 
new/smbprotocol-1.16.1/CHANGELOG.md
--- old/smbprotocol-1.16.0/CHANGELOG.md 2026-02-09 01:47:32.000000000 +0100
+++ new/smbprotocol-1.16.1/CHANGELOG.md 2026-04-02 04:49:28.000000000 +0200
@@ -1,5 +1,13 @@
 # Changelog
 
+## 1.16.1 - 2026-04-02
+
+* Fix memory leaks in `Structure` and subclasses by converting lambda default 
values to static methods and using `weakref.proxy` to prevent circular 
references
+* Fix `smbclient.shutil.copyfile` to fallback to client-side copy when 
server-side SMB copy is not supported (`STATUS_NOT_SUPPORTED`)
+* Fix create context offset calculation when opening a file or directory
+* Fix potential deadlock when worker thread attempts to disconnect and join 
itself
+* Handle `ECONNABORTED` socket error during connection teardown
+
 ## 1.16.0 - 2026-02-09
 
 * Drop support for Python 3.8, minimum version is now 3.9
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/smbprotocol-1.16.0/pyproject.toml 
new/smbprotocol-1.16.1/pyproject.toml
--- old/smbprotocol-1.16.0/pyproject.toml       2026-02-09 01:47:32.000000000 
+0100
+++ new/smbprotocol-1.16.1/pyproject.toml       2026-04-02 04:49:28.000000000 
+0200
@@ -6,7 +6,7 @@
 
 [project]
 name = "smbprotocol"
-version = "1.16.0"
+version = "1.16.1"
 description = "Interact with a server using the SMB 2/3 Protocol"
 readme = "README.md"
 requires-python = ">=3.9"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/smbprotocol-1.16.0/src/smbclient/shutil.py 
new/smbprotocol-1.16.1/src/smbclient/shutil.py
--- old/smbprotocol-1.16.0/src/smbclient/shutil.py      2026-02-09 
01:47:32.000000000 +0100
+++ new/smbprotocol-1.16.1/src/smbclient/shutil.py      2026-04-02 
04:49:28.000000000 +0200
@@ -29,7 +29,9 @@
 )
 from smbclient.path import isdir, islink, samefile
 from smbprotocol import MAX_PAYLOAD_SIZE
+from smbprotocol.exceptions import SMBOSError
 from smbprotocol.file_info import FileAttributes, FileBasicInformation
+from smbprotocol.header import NtStatus
 from smbprotocol.open import CreateOptions, FilePipePrinterAccessMask
 from smbprotocol.structure import DateTimeField
 
@@ -184,8 +186,13 @@
         if is_same:
             raise shutil.Error(f"'{src}' and '{dst}' are the same file, cannot 
copy")
 
-        smbclient_copyfile(src, dst, **kwargs)
-        return dst
+        # Attempt server side copy, if it fails fall back to copying the file 
in chunks using copyfileobj
+        try:
+            smbclient_copyfile(src, dst, **kwargs)
+            return dst
+        except SMBOSError as err:
+            if err.ntstatus != NtStatus.STATUS_NOT_SUPPORTED:
+                raise
 
     # Finally we are copying across different roots so we just chunk the data 
using copyfileobj
     with src_open(src, mode="rb", **src_open_kwargs) as src_fd, dst_open(dst, 
mode="wb", **dst_kwargs) as dst_fd:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/smbprotocol-1.16.0/src/smbprotocol/connection.py 
new/smbprotocol-1.16.1/src/smbprotocol/connection.py
--- old/smbprotocol-1.16.0/src/smbprotocol/connection.py        2026-02-09 
01:47:32.000000000 +0100
+++ new/smbprotocol-1.16.1/src/smbprotocol/connection.py        2026-04-02 
04:49:28.000000000 +0200
@@ -241,7 +241,7 @@
                     "negotiate_context_offset",
                     IntField(
                         size=4,
-                        default=lambda s: 
self._negotiate_context_offset_value(s),
+                        
default=SMB3NegotiateRequest._negotiate_context_offset_value,
                     ),
                 ),
                 (
@@ -263,47 +263,55 @@
                 (
                     "padding",
                     BytesField(
-                        size=lambda s: self._padding_size(s),
-                        default=lambda s: b"\x00" * self._padding_size(s),
+                        size=SMB3NegotiateRequest._padding_size,
+                        default=SMB3NegotiateRequest._default_padding_size,
                     ),
                 ),
                 (
                     "negotiate_context_list",
                     ListField(
                         list_count=lambda s: 
s["negotiate_context_count"].get_value(),
-                        unpack_func=lambda s, d: 
self._negotiate_context_list(s, d),
+                        
unpack_func=SMB3NegotiateRequest._negotiate_context_list,
                     ),
                 ),
             ]
         )
         super().__init__()
 
-    def _negotiate_context_offset_value(self, structure):
+    @staticmethod
+    def _negotiate_context_offset_value(structure):
         # The offset from the beginning of the SMB2 header to the first, 8-byte
         # aligned, negotiate context
         header_size = 64
         negotiate_size = structure["structure_size"].get_value()
         dialect_size = len(structure["dialects"])
-        padding_size = self._padding_size(structure)
+        padding_size = SMB3NegotiateRequest._padding_size(structure)
         return header_size + negotiate_size + dialect_size + padding_size
 
-    def _padding_size(self, structure):
+    @staticmethod
+    def _padding_size(structure):
         # Padding between the end of the buffer value and the first Negotiate
         # context value so that the first value is 8-byte aligned. Padding is
         # 4 is there are no dialects specified
         mod = (structure["dialect_count"].get_value() * 2) % 8
         return 0 if mod == 0 else mod
 
-    def _negotiate_context_list(self, structure, data):
+    @staticmethod
+    def _default_padding_size(structure):
+        return b"\x00" * SMB3NegotiateRequest._padding_size(structure)
+
+    @staticmethod
+    def _negotiate_context_list(structure, data):
         context_count = structure["negotiate_context_count"].get_value()
         context_list = []
         for idx in range(0, context_count):
-            field, data = self._parse_negotiate_context_entry(data)
+            field, data = 
SMB3NegotiateRequest._parse_negotiate_context_entry(data)
             context_list.append(field)
 
         return context_list
 
-    def _parse_negotiate_context_entry(self, data):
+    @staticmethod
+    def _parse_negotiate_context_entry(data):
         data_length = struct.unpack("<H", data[2:4])[0]
         negotiate_context = SMB2NegotiateContextRequest()
         negotiate_context.unpack(data[: data_length + 8])
@@ -345,7 +353,7 @@
                     "data",
                     StructureField(
                         size=lambda s: s["data_length"].get_value(),
-                        structure_type=lambda s: self._data_structure_type(s),
+                        
structure_type=SMB2NegotiateContextRequest._data_structure_type,
                     ),
                 ),
                 # not actually a field but each list entry must start at the 8 
byte
@@ -353,15 +361,16 @@
                 (
                     "padding",
                     BytesField(
-                        size=lambda s: self._padding_size(s),
-                        default=lambda s: b"\x00" * self._padding_size(s),
+                        size=SMB2NegotiateContextRequest._padding_size,
+                        
default=SMB2NegotiateContextRequest._default_padding_size,
                     ),
                 ),
             ]
         )
         super().__init__()
 
-    def _data_structure_type(self, structure):
+    @staticmethod
+    def _data_structure_type(structure):
         con_type = structure["context_type"].get_value()
         if con_type == 
NegotiateContextType.SMB2_PREAUTH_INTEGRITY_CAPABILITIES:
             return SMB2PreauthIntegrityCapabilities
@@ -372,10 +381,15 @@
         elif con_type == NegotiateContextType.SMB2_SIGNING_CAPABILITIES:
             return SMB2SigningCapabilities
 
-    def _padding_size(self, structure):
+    @staticmethod
+    def _padding_size(structure):
         data_size = len(structure["data"])
         return 8 - (data_size % 8 or 8)
 
+    @staticmethod
+    def _default_padding_size(structure):
+        return b"\x00" * SMB2NegotiateContextRequest._padding_size(structure)
+
 
 class SMB2PreauthIntegrityCapabilities(Structure):
     """
@@ -548,7 +562,7 @@
                     "negotiate_context_count",
                     IntField(
                         size=2,
-                        default=lambda s: 
self._negotiate_context_count_value(s),
+                        
default=SMB2NegotiateResponse._negotiate_context_count_value,
                     ),
                 ),
                 ("server_guid", UuidField()),
@@ -576,7 +590,7 @@
                     "negotiate_context_offset",
                     IntField(
                         size=4,
-                        default=lambda s: 
self._negotiate_context_offset_value(s),
+                        
default=SMB2NegotiateResponse._negotiate_context_offset_value,
                     ),
                 ),
                 (
@@ -588,22 +602,23 @@
                 (
                     "padding",
                     BytesField(
-                        size=lambda s: self._padding_size(s),
-                        default=lambda s: b"\x00" * self._padding_size(s),
+                        size=SMB2NegotiateResponse._padding_size,
+                        default=SMB2NegotiateResponse._default_padding_size,
                     ),
                 ),
                 (
                     "negotiate_context_list",
                     ListField(
                         list_count=lambda s: 
s["negotiate_context_count"].get_value(),
-                        unpack_func=lambda s, d: 
self._negotiate_context_list(s, d),
+                        
unpack_func=SMB2NegotiateResponse._negotiate_context_list,
                     ),
                 ),
             ]
         )
         super().__init__()
 
-    def _negotiate_context_count_value(self, structure):
+    @staticmethod
+    def _negotiate_context_count_value(structure):
         # If the dialect_revision is SMBv3.1.1, this field specifies the
         # number of negotiate contexts in negotiate_context_list; otherwise
         # this field must not be used and must be reserved (0).
@@ -612,7 +627,8 @@
         else:
             return None
 
-    def _negotiate_context_offset_value(self, structure):
+    @staticmethod
+    def _negotiate_context_offset_value(structure):
         # If the dialect_revision is SMBv3.1.1, this field specifies the offset
         # from the beginning of the SMB2 header to the first 8-byte
         # aligned negotiate context entry in negotiate_context_list; otherwise
@@ -620,12 +636,13 @@
         if structure["dialect_revision"].get_value() == Dialects.SMB_3_1_1:
             buffer_offset = structure["security_buffer_offset"].get_value()
             buffer_size = structure["security_buffer_length"].get_value()
-            padding_size = self._padding_size(structure)
+            padding_size = SMB2NegotiateResponse._padding_size(structure)
             return buffer_offset + buffer_size + padding_size
         else:
             return None
 
-    def _padding_size(self, structure):
+    @staticmethod
+    def _padding_size(structure):
         # Padding between the end of the buffer value and the first Negotiate
         # context value so that the first value is 8-byte aligned. Padding is
         # not required if there are not negotiate contexts
@@ -635,16 +652,22 @@
         mod = structure["security_buffer_length"].get_value() % 8
         return 0 if mod == 0 else 8 - mod
 
-    def _negotiate_context_list(self, structure, data):
+    @staticmethod
+    def _default_padding_size(structure):
+        return b"\x00" * SMB2NegotiateResponse._padding_size(structure)
+
+    @staticmethod
+    def _negotiate_context_list(structure, data):
         context_count = structure["negotiate_context_count"].get_value()
         context_list = []
         for idx in range(0, context_count):
-            field, data = self._parse_negotiate_context_entry(data)
+            field, data = 
SMB2NegotiateResponse._parse_negotiate_context_entry(data)
             context_list.append(field)
 
         return context_list
 
-    def _parse_negotiate_context_entry(self, data):
+    @staticmethod
+    def _parse_negotiate_context_entry(data):
         data_length = struct.unpack("<H", data[2:4])[0]
         negotiate_context = SMB2NegotiateContextRequest()
         negotiate_context.unpack(data[: data_length + 8])
@@ -953,7 +976,7 @@
 
         log.info("Disconnecting transport connection")
         self.transport.close()
-        if self._t_worker:
+        if self._t_worker and self._t_worker.ident != threading.get_ident():
             self._t_worker.join(timeout=2)
 
     def send(
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/smbprotocol-1.16.0/src/smbprotocol/create_contexts.py 
new/smbprotocol-1.16.1/src/smbprotocol/create_contexts.py
--- old/smbprotocol-1.16.0/src/smbprotocol/create_contexts.py   2026-02-09 
01:47:32.000000000 +0100
+++ new/smbprotocol-1.16.1/src/smbprotocol/create_contexts.py   2026-04-02 
04:49:28.000000000 +0200
@@ -158,12 +158,15 @@
                 ("name_offset", IntField(size=2, default=16)),
                 ("name_length", IntField(size=2, default=lambda s: 
len(s["buffer_name"]))),
                 ("reserved", IntField(size=2)),
-                ("data_offset", IntField(size=2, default=lambda s: 
self._buffer_data_offset(s))),
+                ("data_offset", IntField(size=2, 
default=SMB2CreateContextRequest._buffer_data_offset)),
                 ("data_length", IntField(size=4, default=lambda s: 
len(s["buffer_data"]))),
                 ("buffer_name", BytesField(size=lambda s: 
s["name_length"].get_value())),
                 (
                     "padding",
-                    BytesField(size=lambda s: self._padding_size(s), 
default=lambda s: b"\x00" * self._padding_size(s)),
+                    BytesField(
+                        size=SMB2CreateContextRequest._padding_size,
+                        default=SMB2CreateContextRequest._default_padding_size,
+                    ),
                 ),
                 ("buffer_data", BytesField(size=lambda s: 
s["data_length"].get_value())),
                 # not actually a field but each list entry must start at the 8 
byte
@@ -171,20 +174,23 @@
                 (
                     "padding2",
                     BytesField(
-                        size=lambda s: self._padding2_size(s), default=lambda 
s: b"\x00" * self._padding2_size(s)
+                        size=SMB2CreateContextRequest._padding2_size,
+                        
default=SMB2CreateContextRequest._default_padding2_size,
                     ),
                 ),
             ]
         )
         super().__init__()
 
-    def _buffer_data_offset(self, structure):
+    @staticmethod
+    def _buffer_data_offset(structure):
         if structure["data_length"].get_value() == 0:
             return 0
         else:
             return structure["name_offset"].get_value() + 
len(structure["buffer_name"]) + len(structure["padding"])
 
-    def _padding_size(self, structure):
+    @staticmethod
+    def _padding_size(structure):
         if structure["data_length"].get_value() == 0:
             return 0
 
@@ -192,11 +198,20 @@
         mod = buffer_name_len % 8
         return mod if mod == 0 else 8 - mod
 
-    def _padding2_size(self, structure):
+    @staticmethod
+    def _default_padding_size(structure):
+        return b"\x00" * SMB2CreateContextRequest._padding_size(structure)
+
+    @staticmethod
+    def _padding2_size(structure):
         data_length = len(structure["buffer_name"]) + 
len(structure["padding"]) + len(structure["buffer_data"])
         mod = data_length % 8
         return mod if mod == 0 else 8 - mod
 
+    @staticmethod
+    def _default_padding2_size(structure):
+        return b"\x00" * SMB2CreateContextRequest._padding2_size(structure)
+
     def get_context_data(self):
         """
         Get the buffer_data value of a context response and try to convert it
@@ -278,13 +293,14 @@
                 # alignment
                 (
                     "padding",
-                    BytesField(size=lambda s: self._padding_size(s), 
default=lambda s: b"\x00" * self._padding_size(s)),
+                    BytesField(size=SMB2CreateEABuffer._padding_size, 
default=SMB2CreateEABuffer._default_padding_size),
                 ),
             ]
         )
         super().__init__()
 
-    def _padding_size(self, structure):
+    @staticmethod
+    def _padding_size(structure):
         if structure["next_entry_offset"].get_value() == 0:
             return 0
 
@@ -293,6 +309,10 @@
         return mod if mod == 0 else 4 - mod
 
     @staticmethod
+    def _default_padding_size(structure):
+        return b"\x00" * SMB2CreateEABuffer._padding_size(structure)
+
+    @staticmethod
     def pack_multiple(messages):
         """
         Converts a list of SMB2CreateEABuffer structures and packs them as a
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/smbprotocol-1.16.0/src/smbprotocol/exceptions.py 
new/smbprotocol-1.16.1/src/smbprotocol/exceptions.py
--- old/smbprotocol-1.16.0/src/smbprotocol/exceptions.py        2026-02-09 
01:47:32.000000000 +0100
+++ new/smbprotocol-1.16.1/src/smbprotocol/exceptions.py        2026-04-02 
04:49:28.000000000 +0200
@@ -696,14 +696,15 @@
                         size=lambda s: s["byte_count"].get_value(),
                         list_count=lambda s: 
s["error_context_count"].get_value(),
                         
list_type=StructureField(structure_type=SMB2ErrorContextResponse),
-                        unpack_func=lambda s, d: self._error_data_value(s, d),
+                        unpack_func=SMB2ErrorResponse._error_data_value,
                     ),
                 ),
             ]
         )
         super().__init__()
 
-    def _error_data_value(self, structure, data):
+    @staticmethod
+    def _error_data_value(structure, data):
         context_responses = []
 
         while len(data) > 0:
@@ -801,12 +802,13 @@
                 ("reserved", IntField(size=2)),
                 # use the get/set_name functions to get/set these values as 
they
                 # also (d)encode the text and set the length and offset 
accordingly
-                ("path_buffer", BytesField(size=lambda s: 
self._get_name_length(s, True))),
+                ("path_buffer", 
BytesField(size=SMB2SymbolicLinkErrorResponse._get_name_length)),
             ]
         )
         super().__init__()
 
-    def _get_name_length(self, structure, first):
+    @staticmethod
+    def _get_name_length(structure, first=True):
         print_name_len = structure["print_name_length"].get_value()
         sub_name_len = structure["substitute_name_length"].get_value()
         return print_name_len + sub_name_len
@@ -898,7 +900,7 @@
             [
                 ("structure_size", IntField(size=4, default=lambda s: len(s))),
                 ("notification_type", IntField(size=4, default=3)),
-                ("resource_name_offset", IntField(size=4, default=lambda s: 
self._resource_name_offset(s))),
+                ("resource_name_offset", IntField(size=4, 
default=SMB2ShareRedirectErrorContext._resource_name_offset)),
                 ("resource_name_length", IntField(size=4, default=lambda s: 
len(s["resource_name"]))),
                 ("flags", IntField(size=2, default=0)),
                 ("target_type", IntField(size=2, default=0)),
@@ -916,7 +918,8 @@
         )
         super().__init__()
 
-    def _resource_name_offset(self, structure):
+    @staticmethod
+    def _resource_name_offset(structure):
         min_structure_size = 24
         addr_list_size = len(structure["ip_addr_move_list"])
         return min_structure_size + addr_list_size
@@ -935,29 +938,36 @@
             [
                 ("type", EnumField(size=4, enum_type=IpAddrType)),
                 ("reserved", IntField(size=4)),
-                ("ip_address", BytesField(size=lambda s: 
self._ip_address_size(s))),
+                ("ip_address", 
BytesField(size=SMB2MoveDstIpAddrStructure._ip_address_size)),
                 (
                     "reserved2",
                     BytesField(
-                        size=lambda s: self._reserved2_size(s), default=lambda 
s: b"\x00" * self._reserved2_size(s)
+                        size=SMB2MoveDstIpAddrStructure._reserved2_size,
+                        
default=SMB2MoveDstIpAddrStructure._default_reserved2_size,
                     ),
                 ),
             ]
         )
         super().__init__()
 
-    def _ip_address_size(self, structure):
+    @staticmethod
+    def _ip_address_size(structure):
         if structure["type"].get_value() == IpAddrType.MOVE_DST_IPADDR_V4:
             return 4
         else:
             return 16
 
-    def _reserved2_size(self, structure):
+    @staticmethod
+    def _reserved2_size(structure):
         if structure["type"].get_value() == IpAddrType.MOVE_DST_IPADDR_V4:
             return 12
         else:
             return 0
 
+    @staticmethod
+    def _default_reserved2_size(structure):
+        return b"\x00" * SMB2MoveDstIpAddrStructure._reserved2_size(structure)
+
     def get_ipaddress(self):
         # get's the IP address in a human readable format
         ip_address = self["ip_address"].get_value()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/smbprotocol-1.16.0/src/smbprotocol/ioctl.py 
new/smbprotocol-1.16.1/src/smbprotocol/ioctl.py
--- old/smbprotocol-1.16.0/src/smbprotocol/ioctl.py     2026-02-09 
01:47:32.000000000 +0100
+++ new/smbprotocol-1.16.1/src/smbprotocol/ioctl.py     2026-04-02 
04:49:28.000000000 +0200
@@ -136,7 +136,7 @@
                     ),
                 ),
                 ("file_id", BytesField(size=16)),
-                ("input_offset", IntField(size=4, default=lambda s: 
self._buffer_offset_value(s))),
+                ("input_offset", IntField(size=4, 
default=SMB2IOCTLRequest._buffer_offset_value)),
                 (
                     "input_count",
                     IntField(
@@ -145,7 +145,7 @@
                     ),
                 ),
                 ("max_input_response", IntField(size=4)),
-                ("output_offset", IntField(size=4, default=lambda s: 
self._buffer_offset_value(s))),
+                ("output_offset", IntField(size=4, 
default=SMB2IOCTLRequest._buffer_offset_value)),
                 ("output_count", IntField(size=4, default=0)),
                 ("max_output_response", IntField(size=4)),
                 (
@@ -161,7 +161,8 @@
         )
         super().__init__()
 
-    def _buffer_offset_value(self, structure):
+    @staticmethod
+    def _buffer_offset_value(structure):
         # The offset from the beginning of the SMB2 header to the value of the
         # buffer, 0 if no buffer is set
         if len(structure["buffer"]) > 0:
@@ -497,39 +498,46 @@
                 (
                     "buffer",
                     StructureField(
-                        size=lambda s: self._get_buffer_size(s),
-                        structure_type=lambda s: 
self._get_buffer_structure_type(s),
+                        size=SockAddrStorage._get_buffer_size,
+                        
structure_type=SockAddrStorage._get_buffer_structure_type,
                     ),
                 ),
                 (
                     "reserved",
                     BytesField(
-                        size=lambda s: self._get_reserved_size(s),
-                        default=lambda s: b"\x00" * self._get_reserved_size(s),
+                        size=SockAddrStorage._get_reserved_size,
+                        default=SockAddrStorage._default_get_reserved_size,
                     ),
                 ),
             ]
         )
         super().__init__()
 
-    def _get_buffer_size(self, structure):
+    @staticmethod
+    def _get_buffer_size(structure):
         if structure["family"].get_value() == SockAddrFamily.INTER_NETWORK:
             return 14
         else:
             return 26
 
-    def _get_buffer_structure_type(self, structure):
+    @staticmethod
+    def _get_buffer_structure_type(structure):
         if structure["family"].get_value() == SockAddrFamily.INTER_NETWORK:
             return SockAddrIn
         else:
             return SockAddrIn6
 
-    def _get_reserved_size(self, structure):
+    @staticmethod
+    def _get_reserved_size(structure):
         if structure["family"].get_value() == SockAddrFamily.INTER_NETWORK:
             return 112
         else:
             return 100
 
+    @staticmethod
+    def _default_get_reserved_size(structure):
+        return b"\x00" * SockAddrStorage._get_reserved_size(structure)
+
 
 class SockAddrIn(Structure):
     """
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/smbprotocol-1.16.0/src/smbprotocol/open.py 
new/smbprotocol-1.16.1/src/smbprotocol/open.py
--- old/smbprotocol-1.16.0/src/smbprotocol/open.py      2026-02-09 
01:47:32.000000000 +0100
+++ new/smbprotocol-1.16.1/src/smbprotocol/open.py      2026-04-02 
04:49:28.000000000 +0200
@@ -349,56 +349,65 @@
                 ("create_disposition", EnumField(size=4, 
enum_type=CreateDisposition)),
                 ("create_options", FlagField(size=4, flag_type=CreateOptions)),
                 ("name_offset", IntField(size=2, default=120)),  # (header 
size 64) + (structure size 56)
-                ("name_length", IntField(size=2, default=lambda s: 
self._name_length(s))),
-                ("create_contexts_offset", IntField(size=4, default=lambda s: 
self._create_contexts_offset(s))),
+                ("name_length", IntField(size=2, 
default=SMB2CreateRequest._name_length)),
+                ("create_contexts_offset", IntField(size=4, 
default=SMB2CreateRequest._create_contexts_offset)),
                 ("create_contexts_length", IntField(size=4, default=lambda s: 
len(s["buffer_contexts"]))),
                 # Technically these are all under buffer but we split it to 
make
                 # things easier
                 (
                     "buffer_path",
                     BytesField(
-                        size=lambda s: self._buffer_path_size(s),
+                        size=SMB2CreateRequest._buffer_path_size,
                     ),
                 ),
                 (
                     "padding",
-                    BytesField(size=lambda s: self._padding_size(s), 
default=lambda s: b"\x00" * self._padding_size(s)),
+                    BytesField(size=SMB2CreateRequest._padding_size, 
default=SMB2CreateRequest._default_padding_size),
                 ),
                 (
                     "buffer_contexts",
                     ListField(
                         size=lambda s: s["create_contexts_length"].get_value(),
                         
list_type=StructureField(structure_type=create_con_req),
-                        unpack_func=lambda s, d: self._buffer_context_list(s, 
d),
+                        unpack_func=SMB2CreateRequest._buffer_context_list,
                     ),
                 ),
             ]
         )
         super().__init__()
 
-    def _name_length(self, structure):
+    @staticmethod
+    def _name_length(structure):
         buffer_path = structure["buffer_path"].get_value()
         return len(buffer_path) if buffer_path != b"\x00\x00" else 0
 
-    def _create_contexts_offset(self, structure):
+    @staticmethod
+    def _create_contexts_offset(structure):
         if len(structure["buffer_contexts"]) == 0:
             return 0
         else:
             return structure["name_offset"].get_value() + 
len(structure["padding"]) + len(structure["buffer_path"])
 
-    def _buffer_path_size(self, structure):
+    @staticmethod
+    def _buffer_path_size(structure):
         name_length = structure["name_length"].get_value()
         return name_length if name_length != 0 else 2
 
-    def _padding_size(self, structure):
+    @staticmethod
+    def _padding_size(structure):
         # no padding is needed if there are no contexts
         if structure["create_contexts_length"].get_value() == 0:
             return 0
 
-        mod = structure["name_length"].get_value() % 8
+        mod = len(structure["buffer_path"]) % 8
         return 0 if mod == 0 else 8 - mod
 
-    def _buffer_context_list(self, structure, data):
+    @staticmethod
+    def _default_padding_size(structure):
+        return b"\x00" * SMB2CreateRequest._padding_size(structure)
+
+    @staticmethod
+    def _buffer_context_list(structure, data):
         context_list = []
         last_context = data == b""
         while not last_context:
@@ -445,27 +454,29 @@
                 ),
                 ("reserved2", IntField(size=4)),
                 ("file_id", BytesField(size=16)),
-                ("create_contexts_offset", IntField(size=4, default=lambda s: 
self._create_contexts_offset(s))),
+                ("create_contexts_offset", IntField(size=4, 
default=SMB2CreateResponse._create_contexts_offset)),
                 ("create_contexts_length", IntField(size=4, default=lambda s: 
len(s["buffer"]))),
                 (
                     "buffer",
                     ListField(
                         size=lambda s: s["create_contexts_length"].get_value(),
                         
list_type=StructureField(structure_type=create_con_req),
-                        unpack_func=lambda s, d: self._buffer_context_list(s, 
d),
+                        unpack_func=SMB2CreateResponse._buffer_context_list,
                     ),
                 ),
             ]
         )
         super().__init__()
 
-    def _create_contexts_offset(self, structure):
+    @staticmethod
+    def _create_contexts_offset(structure):
         if len(structure["buffer"]) == 0:
             return 0
         else:
             return 152
 
-    def _buffer_context_list(self, structure, data):
+    @staticmethod
+    def _buffer_context_list(structure, data):
         context_list = []
         last_context = data == b""
         while not last_context:
@@ -596,26 +607,29 @@
                 ("minimum_count", IntField(size=4)),
                 ("channel", FlagField(size=4, flag_type=ReadWriteChannel)),
                 ("remaining_bytes", IntField(size=4)),
-                ("read_channel_info_offset", IntField(size=2, default=lambda 
s: self._get_read_channel_info_offset(s))),
-                ("read_channel_info_length", IntField(size=2, default=lambda 
s: self._get_read_channel_info_length(s))),
-                ("buffer", BytesField(size=lambda s: 
self._get_buffer_length(s), default=b"\x00")),
+                ("read_channel_info_offset", IntField(size=2, 
default=SMB2ReadRequest._get_read_channel_info_offset)),
+                ("read_channel_info_length", IntField(size=2, 
default=SMB2ReadRequest._get_read_channel_info_length)),
+                ("buffer", BytesField(size=SMB2ReadRequest._get_buffer_length, 
default=b"\x00")),
             ]
         )
         super().__init__()
 
-    def _get_read_channel_info_offset(self, structure):
+    @staticmethod
+    def _get_read_channel_info_offset(structure):
         if structure["channel"].get_value() == 0:
             return 0
         else:
             return 64 + structure["structure_size"].get_value() - 1
 
-    def _get_read_channel_info_length(self, structure):
+    @staticmethod
+    def _get_read_channel_info_length(structure):
         if structure["channel"].get_value() == 0:
             return 0
         else:
             return len(structure["buffer"].get_value())
 
-    def _get_buffer_length(self, structure):
+    @staticmethod
+    def _get_buffer_length(structure):
         # buffer should contain 1 byte of \x00 and not be empty
         if structure["channel"].get_value() == 0:
             return 1
@@ -673,7 +687,7 @@
                 ("remaining_bytes", IntField(size=4)),
                 (
                     "write_channel_info_offset",
-                    IntField(size=2, default=lambda s: 
self._get_write_channel_info_offset(s)),
+                    IntField(size=2, 
default=SMB2WriteRequest._get_write_channel_info_offset),
                 ),
                 ("write_channel_info_length", IntField(size=2, default=lambda 
s: len(s["buffer_channel_info"]))),
                 ("flags", FlagField(size=4, flag_type=WriteFlags)),
@@ -683,7 +697,8 @@
         )
         super().__init__()
 
-    def _get_write_channel_info_offset(self, structure):
+    @staticmethod
+    def _get_write_channel_info_offset(structure):
         if len(structure["buffer_channel_info"]) == 0:
             return 0
         else:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/smbprotocol-1.16.0/src/smbprotocol/security_descriptor.py 
new/smbprotocol-1.16.1/src/smbprotocol/security_descriptor.py
--- old/smbprotocol-1.16.0/src/smbprotocol/security_descriptor.py       
2026-02-09 01:47:32.000000000 +0100
+++ new/smbprotocol-1.16.1/src/smbprotocol/security_descriptor.py       
2026-04-02 04:49:28.000000000 +0200
@@ -271,14 +271,15 @@
                     "aces",
                     ListField(
                         list_count=lambda s: s["ace_count"].get_value(),
-                        unpack_func=lambda s, d: self._unpack_aces(s, d),
+                        unpack_func=AclPacket._unpack_aces,
                     ),
                 ),
             ]
         )
         super().__init__()
 
-    def _unpack_aces(self, structure, data):
+    @staticmethod
+    def _unpack_aces(structure, data):
         aces = []
         while data != b"" and len(aces) < structure["ace_count"].value:
             ace_type = struct.unpack("<B", data[:1])[0]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/smbprotocol-1.16.0/src/smbprotocol/structure.py 
new/smbprotocol-1.16.1/src/smbprotocol/structure.py
--- old/smbprotocol-1.16.0/src/smbprotocol/structure.py 2026-02-09 
01:47:32.000000000 +0100
+++ new/smbprotocol-1.16.1/src/smbprotocol/structure.py 2026-04-02 
04:49:28.000000000 +0200
@@ -9,6 +9,7 @@
 import textwrap
 import types
 import uuid
+import weakref
 from abc import ABCMeta, abstractmethod
 from binascii import hexlify
 
@@ -58,7 +59,7 @@
         # relies on the full structure (self) being available and error
         # messages use the field name to be helpful
         for name, field in self.fields.items():
-            field.structure = self
+            field.structure = weakref.proxy(self)
             field.name = name
             field.set_value(field.default)
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/smbprotocol-1.16.0/src/smbprotocol/transport.py 
new/smbprotocol-1.16.1/src/smbprotocol/transport.py
--- old/smbprotocol-1.16.0/src/smbprotocol/transport.py 2026-02-09 
01:47:32.000000000 +0100
+++ new/smbprotocol-1.16.1/src/smbprotocol/transport.py 2026-04-02 
04:49:28.000000000 +0200
@@ -145,7 +145,7 @@
                 except OSError as e:
                     # Windows will raise this error if the socket has been 
shutdown, Linux return returns an empty byte
                     # string so we just replicate that.
-                    if e.errno not in [errno.ESHUTDOWN, errno.ECONNRESET]:
+                    if e.errno not in [errno.ESHUTDOWN, errno.ECONNRESET, 
errno.ECONNABORTED]:
                         # Avoid collecting coverage here to avoid CI failing 
due to race condition differences
                         raise  # pragma: no cover
                     b_data = b""
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/smbprotocol-1.16.0/tests/test_smbclient_shutil.py 
new/smbprotocol-1.16.1/tests/test_smbclient_shutil.py
--- old/smbprotocol-1.16.0/tests/test_smbclient_shutil.py       2026-02-09 
01:47:32.000000000 +0100
+++ new/smbprotocol-1.16.1/tests/test_smbclient_shutil.py       2026-04-02 
04:49:28.000000000 +0200
@@ -9,6 +9,7 @@
 import shutil
 import stat
 import sys
+from unittest.mock import patch
 
 import pytest
 
@@ -30,6 +31,7 @@
 )
 from smbprotocol.exceptions import SMBOSError
 from smbprotocol.file_info import FileBasicInformation
+from smbprotocol.header import NtStatus
 from smbprotocol.open import CreateOptions, FileAttributes, 
FilePipePrinterAccessMask
 
 if os.name == "nt":
@@ -419,6 +421,32 @@
         copyfile(src_filename, "/tmp", follow_symlinks=False)
 
 
+def 
test_copyfile_falls_back_to_copyfile_obj_when_server_side_copy_not_supported(smb_share):
+    src_filename = "%s\\source.txt" % smb_share
+    dst_filename = "%s\\target.txt" % smb_share
+
+    with open_file(src_filename, mode="w") as fd:
+        fd.write("content")
+
+    with patch("smbclient.shutil.smbclient_copyfile") as mock_copy:
+
+        def raise_not_supported(*args, **kwargs):
+            raise SMBOSError(
+                NtStatus.STATUS_NOT_SUPPORTED,
+                src_filename,
+            )
+
+        mock_copy.side_effect = raise_not_supported
+        actual = copyfile(src=src_filename, dst=dst_filename)
+
+        # Check that initially the copyfile was attempted and then the 
fallback was used.
+        assert mock_copy.call_count == 1
+        assert actual == dst_filename
+
+        with open_file(dst_filename) as fd:
+            assert fd.read() == "content"
+
+
 def test_copymode_of_file(smb_share):
     src_filename = "%s\\source.txt" % smb_share
     dst_filename = "%s\\target.txt" % smb_share

Reply via email to