diff --git a/README.md b/README.md index c85fa6b3..3edd0148 100644 --- a/README.md +++ b/README.md @@ -59,7 +59,7 @@ try: from gssapi.raw import inquire_sec_context_by_oid print("python-gssapi extension is available") except ImportError as exc: - print("python-gssapi extension is not available: %s" % str(exc)) + print(f"python-gssapi extension is not available: {exc}") ``` If it isn't available, then either a newer version of the system's gssapi implementation needs to be setup and diff --git a/build_helpers/check-smb.py b/build_helpers/check-smb.py index 9d1db9d5..17e52a71 100755 --- a/build_helpers/check-smb.py +++ b/build_helpers/check-smb.py @@ -1,13 +1,17 @@ +import logging import os import time import uuid from smbprotocol.connection import Connection +log = logging.getLogger(__name__) +logging.basicConfig(level=logging.INFO) + def test_connection(server, port): conn = Connection(uuid.uuid4(), server, port=port) - print("Opening connection to %s:%d" % (server, port)) + log.info("Opening connection to %s:%d", server, port) conn.connect(timeout=5) conn.disconnect(True) @@ -15,22 +19,22 @@ def test_connection(server, port): if __name__ == "__main__": server = os.environ.get("SMB_SERVER", "127.0.0.1") port = int(os.environ.get("SMB_PORT", 445)) - print("Waiting for SMB server to be online") + log.info("Waiting for SMB server to be online") attempt = 1 total_attempts = 20 while attempt < total_attempts: - print("Starting attempt %d" % attempt) + log.info("Starting attempt %d", attempt) try: test_connection(server, port) break except Exception as e: - print("Connection attempt %d failed: %s" % (attempt, str(e))) + log.info("Connection attempt %d failed: %s", attempt, e) attempt += 1 if attempt == total_attempts: - raise Exception("Timeout while waiting for SMB server to come online") + raise Exception("Timeout while waiting for SMB server to come online") from e - print("Sleeping for 5 seconds before next attempt") + log.info("Sleeping for 5 seconds before next attempt") time.sleep(5) - print("Connection successful") + log.info("Connection successful") diff --git a/examples/high-level/directory-management.py b/examples/high-level/directory-management.py index 3eef9396..e63f234e 100644 --- a/examples/high-level/directory-management.py +++ b/examples/high-level/directory-management.py @@ -1,6 +1,11 @@ +import logging + from smbclient import listdir, mkdir, register_session, rmdir, scandir from smbclient.path import isdir +log = logging.getLogger(__name__) +logging.basicConfig(level=logging.INFO) + # Optional - register the server with explicit credentials register_session("server", username="admin", password="pass") @@ -12,18 +17,18 @@ # Checking whether a file is a directory d_filename = r"\\server\share\directory" -print("Is file {} dir?: {}".format(d_filename, isdir(d_filename))) +log.info("Is file %s dir?: %b", d_filename, isdir(d_filename)) # List the files/directories inside a dir for filename in listdir(r"\\server\share\directory"): - print(filename) + log.info(filename) # Use scandir as a more efficient directory listing as it already contains info like stat and attributes. for file_info in scandir(r"\\server\share\directory"): file_inode = file_info.inode() if file_info.is_file(): - print("File: %s %d" % (file_info.name, file_inode)) + log.info("File: %s %d", file_info.name, file_inode) elif file_info.is_dir(): - print("Dir: %s %d" % (file_info.name, file_inode)) + log.info("Dir: %s %d", file_info.name, file_inode) else: - print("Symlink: %s %d" % (file_info.name, file_inode)) + log.info("Symlink: %s %d", file_info.name, file_inode) diff --git a/examples/low-level/directory-management.py b/examples/low-level/directory-management.py index 18ac9cf0..74a2b2d1 100644 --- a/examples/low-level/directory-management.py +++ b/examples/low-level/directory-management.py @@ -1,3 +1,4 @@ +import logging import uuid from smbprotocol.connection import Connection @@ -15,11 +16,14 @@ from smbprotocol.session import Session from smbprotocol.tree import TreeConnect +log = logging.getLogger(__name__) +logging.basicConfig(level=logging.INFO) + server = "127.0.0.1" port = 445 username = "smbuser" password = "smbpassword" -share = r"\\%s\share" % server +share = rf"\\{server}\share" dir_name = "directory" connection = Connection(uuid.uuid4(), server, port) @@ -55,7 +59,7 @@ ) compound_messages = [ - directory_file.write("Hello World".encode("utf-8"), 0, send=False), + directory_file.write(b"Hello World", 0, send=False), dir_open.query_directory("*", FileInformationClass.FILE_NAMES_INFORMATION, send=False), directory_file.close(False, send=False), dir_open.close(False, send=False), @@ -70,7 +74,7 @@ for dir_file in responses[1]: dir_files.append(dir_file["file_name"].get_value().decode("utf-16-le")) - print("Directory '%s\\%s' contains the files: '%s'" % (share, dir_name, "', '".join(dir_files))) + log.info("Directory '%s\\%s' contains the files: %s", share, dir_name, ", ".join(repr(file) for file in dir_files)) # delete a directory (note the dir needs to be empty to delete on close) dir_open = Open(tree, dir_name) diff --git a/examples/low-level/file-management.py b/examples/low-level/file-management.py index a2e39032..beb5ec8e 100644 --- a/examples/low-level/file-management.py +++ b/examples/low-level/file-management.py @@ -1,3 +1,4 @@ +import logging import uuid from smbprotocol.connection import Connection @@ -27,11 +28,14 @@ from smbprotocol.structure import FlagField from smbprotocol.tree import TreeConnect +log = logging.getLogger(__name__) +logging.basicConfig(level=logging.INFO) + server = "127.0.0.1" port = 445 username = "smbuser" password = "smbpassword" -share = r"\\%s\share" % server +share = rf"\\{server}\share" file_name = "file-test.txt" connection = Connection(uuid.uuid4(), server, port) @@ -83,7 +87,7 @@ # flag field, set the value and get the human readble string max_access = FlagField(size=4, flag_type=FilePipePrinterAccessMask, flag_strict=False) max_access.set_value(open_info[0]["maximal_access"].get_value()) - print("Maximum access mask for file %s\\%s: %s" % (share, file_name, str(max_access))) + log.info("Maximum access mask for file %s\\%s: %s", share, file_name, max_access) # write to a file text = "Hello World, what a nice day to play with SMB" @@ -91,7 +95,7 @@ # read from a file file_text = file_open.read(0, 1024) - print("Text of file %s\\%s: %s" % (share, file_name, file_text.decode("utf-8"))) + log.info("Text of file %s\\%s: %s", share, file_name, file_text.decode("utf-8")) file_open.close(False) # read and delete a file in a single SMB packet instead of 3 @@ -116,6 +120,6 @@ for i, request in enumerate(requests): response = delete_msgs[i][1](request) responses.append(response) - print("Text of file when reading/deleting in 1 request: %s" % responses[1].decode("utf-8")) + log.info("Text of file when reading/deleting in 1 request: %s", responses[1].decode("utf-8")) finally: connection.disconnect(True) diff --git a/reports/coverage.coverage b/reports/coverage.coverage new file mode 100644 index 00000000..1c408cf2 Binary files /dev/null and b/reports/coverage.coverage differ diff --git a/reports/junit/python-3.11.3-Linux-6.4.9-1-MANJARO-x86_64-with-glibc2.38.xml b/reports/junit/python-3.11.3-Linux-6.4.9-1-MANJARO-x86_64-with-glibc2.38.xml new file mode 100644 index 00000000..d6c593a7 --- /dev/null +++ b/reports/junit/python-3.11.3-Linux-6.4.9-1-MANJARO-x86_64-with-glibc2.38.xml @@ -0,0 +1 @@ +/home/maxim/Repo/smbprotocol/tests/test_change_notify.py:121: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_change_notify.py:189: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_change_notify.py:280: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_change_notify.py:345: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_change_notify.py:376: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_change_notify.py:417: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_connection.py:860: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_connection.py:877: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_connection.py:894: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_connection.py:911: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_connection.py:928: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_connection.py:949: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_connection.py:972: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_connection.py:982: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_connection.py:1063: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_connection.py:1076: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_connection.py:1094: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_connection.py:1113: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_connection.py:1132: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_connection.py:1144: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_connection.py:1158: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_open.py:1167: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_open.py:1211: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_open.py:1255: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_open.py:1299: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_open.py:1343: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_open.py:1387: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_open.py:1410: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_open.py:1454: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_open.py:1499: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_open.py:1499: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_open.py:1539: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_open.py:1565: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_open.py:1595: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_open.py:1624: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_open.py:1654: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_open.py:1679: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_open.py:1713: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_open.py:1740: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_open.py:1773: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_open.py:1800: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_open.py:1833: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_open.py:1893: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_open.py:1936: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_open.py:1979: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_open.py:2066: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_open.py:2153: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_open.py:2180: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_open.py:2209: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_open.py:2238: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_open.py:2262: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_open.py:2301: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_open.py:2331: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_session.py:106: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_session.py:126: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_session.py:146: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_session.py:170: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_session.py:194: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_session.py:220: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_session.py:244: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_session.py:255: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_session.py:270: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_session.py:311: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:37: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:37: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:48: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:48: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:59: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:59: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:77: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:77: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:90: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:90: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:101: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:101: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:112: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:112: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:130: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:130: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:136: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:136: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:142: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:142: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:148: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:148: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:163: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:163: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:172: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:172: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:194: cannot create symlinks on Samba/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:194: cannot create symlinks on Samba/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:214: cannot create symlinks on Samba/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:214: cannot create symlinks on Samba/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:234: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:234: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:234: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:234: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:247: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:247: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:257: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:257: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:257: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:257: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:284: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:284: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:297: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:297: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:302: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:302: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:325: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:325: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:347: cannot create symlinks on Samba/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:347: cannot create symlinks on Samba/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:366: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:366: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:377: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:377: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:384: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:384: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:394: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:394: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:400: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:400: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:411: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:411: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:417: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:417: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:432: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:432: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:473: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:473: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:504: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:504: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:533: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:533: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:564: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:564: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:576: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:576: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:602: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:602: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:628: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:628: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:649: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:649: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:670: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:670: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:681: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:681: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:692: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:692: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:700: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:700: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:711: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:711: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:718: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:718: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:740: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:740: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:764: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:764: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:778: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:778: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:783: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:783: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:788: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:788: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:793: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:793: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:802: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:802: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:815: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:815: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:821: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:821: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:844: cannot create symlinks on Samba/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:844: cannot create symlinks on Samba/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:860: cannot create symlinks on Samba/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:860: cannot create symlinks on Samba/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:876: cannot create symlinks on Samba/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:876: cannot create symlinks on Samba/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:889: cannot create symlinks on Samba/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:889: cannot create symlinks on Samba/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:902: cannot create symlinks on Samba/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:902: cannot create symlinks on Samba/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:916: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:916: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:940: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:940: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:951: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:951: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:966: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:966: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:978: cannot create symlinks on Samba/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:978: cannot create symlinks on Samba/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:991: cannot create symlinks on Samba/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:991: cannot create symlinks on Samba/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:1007: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:1007: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:1023: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:1023: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:1034: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:1034: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:1044: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:1044: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:1050: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:1050: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:1058: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:1058: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:1074: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:1074: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:1099: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:1099: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:1122: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:1122: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:1135: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:1135: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:1148: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:1148: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:1161: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:1161: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:1171: cannot create symlinks on Samba/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:1171: cannot create symlinks on Samba/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:1184: cannot create symlinks on Samba/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:1184: cannot create symlinks on Samba/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:1198: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:1198: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:1218: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:1218: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:1263: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:1263: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:1285: cannot create symlinks on Samba/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:1285: cannot create symlinks on Samba/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:1313: cannot create symlinks on Samba/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:1313: cannot create symlinks on Samba/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:1328: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:1382: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:1382: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:1422: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:1422: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:1466: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:1466: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:1476: cannot create symlinks on Samba/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:1476: cannot create symlinks on Samba/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:1493: cannot create symlinks on Samba/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:1493: cannot create symlinks on Samba/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:1507: cannot create symlinks on Samba/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:1507: cannot create symlinks on Samba/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:1525: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:1525: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:1534: cannot create symlinks on Samba/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:1534: cannot create symlinks on Samba/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:1551: cannot create symlinks on Samba/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:1551: cannot create symlinks on Samba/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:1574: cannot create symlinks on Samba/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:1574: cannot create symlinks on Samba/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:1591: cannot create symlinks on Samba/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:1591: cannot create symlinks on Samba/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:1612: cannot create symlinks on Samba/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:1612: cannot create symlinks on Samba/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:1637: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:1637: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:1643: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:1643: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:1649: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:1649: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:1665: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:1665: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:1676: Samba does not update timestamps/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:1676: Samba does not update timestamps/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:1697: Samba does not update timestamps/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:1697: Samba does not update timestamps/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:1718: Samba does not update timestamps/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:1718: Samba does not update timestamps/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:1738: Samba does not update timestamps/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:1738: Samba does not update timestamps/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:1770: Samba does not update timestamps/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:1770: Samba does not update timestamps/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:1793: cannot create symlinks on Samba/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:1793: cannot create symlinks on Samba/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:1816: cannot create symlinks on Samba/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:1816: cannot create symlinks on Samba/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:1839: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:1839: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:1860: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:1860: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:1878: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:1878: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:1886: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:1886: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:1898: cannot create symlinks on Samba/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:1898: cannot create symlinks on Samba/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:1926: cannot create symlinks on Samba/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:1926: cannot create symlinks on Samba/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:1951: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:1951: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:1988: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:1988: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:1996: cannot create symlinks on Samba/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:1996: cannot create symlinks on Samba/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:2018: cannot create symlinks on Samba/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:2018: cannot create symlinks on Samba/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:2040: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:2040: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:2061: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:2061: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:2061: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:2084: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:2084: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:2084: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:2102: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:2102: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:2102: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_os.py:2126: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_path.py:26: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_path.py:26: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_path.py:37: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_path.py:37: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_path.py:42: cannot create symlinks on Samba/home/maxim/Repo/smbprotocol/tests/test_smbclient_path.py:42: cannot create symlinks on Samba/home/maxim/Repo/smbprotocol/tests/test_smbclient_path.py:54: cannot create symlinks on Samba/home/maxim/Repo/smbprotocol/tests/test_smbclient_path.py:54: cannot create symlinks on Samba/home/maxim/Repo/smbprotocol/tests/test_smbclient_path.py:69: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_path.py:69: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_path.py:80: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_path.py:80: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_path.py:85: cannot create symlinks on Samba/home/maxim/Repo/smbprotocol/tests/test_smbclient_path.py:85: cannot create symlinks on Samba/home/maxim/Repo/smbprotocol/tests/test_smbclient_path.py:97: cannot create symlinks on Samba/home/maxim/Repo/smbprotocol/tests/test_smbclient_path.py:97: cannot create symlinks on Samba/home/maxim/Repo/smbprotocol/tests/test_smbclient_path.py:112: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_path.py:112: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_path.py:122: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_path.py:122: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_path.py:132: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_path.py:132: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_path.py:142: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_path.py:142: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_path.py:151: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_path.py:151: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_path.py:155: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_path.py:155: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_path.py:159: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_path.py:159: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_path.py:166: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_path.py:166: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_path.py:172: cannot create symlinks on Samba/home/maxim/Repo/smbprotocol/tests/test_smbclient_path.py:172: cannot create symlinks on Samba/home/maxim/Repo/smbprotocol/tests/test_smbclient_path.py:186: cannot create symlinks on Samba/home/maxim/Repo/smbprotocol/tests/test_smbclient_path.py:186: cannot create symlinks on Samba/home/maxim/Repo/smbprotocol/tests/test_smbclient_path.py:198: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_path.py:198: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_path.py:202: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_path.py:202: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_path.py:206: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_path.py:206: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_path.py:213: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_path.py:213: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_path.py:219: cannot create symlinks on Samba/home/maxim/Repo/smbprotocol/tests/test_smbclient_path.py:219: cannot create symlinks on Samba/home/maxim/Repo/smbprotocol/tests/test_smbclient_path.py:232: cannot create symlinks on Samba/home/maxim/Repo/smbprotocol/tests/test_smbclient_path.py:232: cannot create symlinks on Samba/home/maxim/Repo/smbprotocol/tests/test_smbclient_path.py:244: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_path.py:244: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_path.py:248: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_path.py:248: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_path.py:252: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_path.py:252: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_path.py:259: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_path.py:259: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_path.py:265: cannot create symlinks on Samba/home/maxim/Repo/smbprotocol/tests/test_smbclient_path.py:265: cannot create symlinks on Samba/home/maxim/Repo/smbprotocol/tests/test_smbclient_path.py:279: cannot create symlinks on Samba/home/maxim/Repo/smbprotocol/tests/test_smbclient_path.py:279: cannot create symlinks on Samba/home/maxim/Repo/smbprotocol/tests/test_smbclient_path.py:291: cannot create symlinks on Samba/home/maxim/Repo/smbprotocol/tests/test_smbclient_path.py:291: cannot create symlinks on Samba/home/maxim/Repo/smbprotocol/tests/test_smbclient_path.py:304: cannot create symlinks on Samba/home/maxim/Repo/smbprotocol/tests/test_smbclient_path.py:304: cannot create symlinks on Samba/home/maxim/Repo/smbprotocol/tests/test_smbclient_path.py:316: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_path.py:316: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_path.py:329: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_path.py:329: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_path.py:341: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_path.py:341: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_path.py:353: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_path.py:353: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_path.py:365: cannot create symlinks on Samba/home/maxim/Repo/smbprotocol/tests/test_smbclient_path.py:365: cannot create symlinks on Samba/home/maxim/Repo/smbprotocol/tests/test_smbclient_path.py:380: cannot create symlinks on Samba/home/maxim/Repo/smbprotocol/tests/test_smbclient_path.py:380: cannot create symlinks on Samba/home/maxim/Repo/smbprotocol/tests/test_smbclient_shutil.py:79: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_shutil.py:79: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_shutil.py:89: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_shutil.py:89: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_shutil.py:117: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_shutil.py:117: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_shutil.py:141: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_shutil.py:141: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_shutil.py:162: Samba does not update timestamps/home/maxim/Repo/smbprotocol/tests/test_smbclient_shutil.py:162: Samba does not update timestamps/home/maxim/Repo/smbprotocol/tests/test_smbclient_shutil.py:189: Samba does not update timestamps/home/maxim/Repo/smbprotocol/tests/test_smbclient_shutil.py:189: Samba does not update timestamps/home/maxim/Repo/smbprotocol/tests/test_smbclient_shutil.py:217: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_shutil.py:217: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_shutil.py:238: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_shutil.py:238: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_shutil.py:248: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_shutil.py:248: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_shutil.py:262: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_shutil.py:262: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_shutil.py:279: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_shutil.py:279: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_shutil.py:294: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_shutil.py:294: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_shutil.py:324: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_shutil.py:324: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_shutil.py:335: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_shutil.py:335: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_shutil.py:349: cannot create symlinks on Samba/home/maxim/Repo/smbprotocol/tests/test_smbclient_shutil.py:349: cannot create symlinks on Samba/home/maxim/Repo/smbprotocol/tests/test_smbclient_shutil.py:370: cannot create symlinks on Samba/home/maxim/Repo/smbprotocol/tests/test_smbclient_shutil.py:370: cannot create symlinks on Samba/home/maxim/Repo/smbprotocol/tests/test_smbclient_shutil.py:392: cannot create symlinks on Samba/home/maxim/Repo/smbprotocol/tests/test_smbclient_shutil.py:392: cannot create symlinks on Samba/home/maxim/Repo/smbprotocol/tests/test_smbclient_shutil.py:405: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_shutil.py:405: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_shutil.py:431: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_shutil.py:431: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_shutil.py:460: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_shutil.py:460: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_shutil.py:484: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_shutil.py:484: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_shutil.py:512: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_shutil.py:512: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_shutil.py:631: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_shutil.py:631: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_shutil.py:636: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_shutil.py:636: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_shutil.py:641: cannot create symlinks on Samba/home/maxim/Repo/smbprotocol/tests/test_smbclient_shutil.py:641: cannot create symlinks on Samba/home/maxim/Repo/smbprotocol/tests/test_smbclient_shutil.py:681: cannot create symlinks on Samba/home/maxim/Repo/smbprotocol/tests/test_smbclient_shutil.py:681: cannot create symlinks on Samba/home/maxim/Repo/smbprotocol/tests/test_smbclient_shutil.py:721: Samba does not update timestamps/home/maxim/Repo/smbprotocol/tests/test_smbclient_shutil.py:721: Samba does not update timestamps/home/maxim/Repo/smbprotocol/tests/test_smbclient_shutil.py:743: Samba does not update timestamps/home/maxim/Repo/smbprotocol/tests/test_smbclient_shutil.py:743: Samba does not update timestamps/home/maxim/Repo/smbprotocol/tests/test_smbclient_shutil.py:766: Samba does not update timestamps/home/maxim/Repo/smbprotocol/tests/test_smbclient_shutil.py:766: Samba does not update timestamps/home/maxim/Repo/smbprotocol/tests/test_smbclient_shutil.py:790: Samba does not update timestamps/home/maxim/Repo/smbprotocol/tests/test_smbclient_shutil.py:790: Samba does not update timestamps/home/maxim/Repo/smbprotocol/tests/test_smbclient_shutil.py:891: cannot create symlinks on Samba/home/maxim/Repo/smbprotocol/tests/test_smbclient_shutil.py:891: cannot create symlinks on Samba/home/maxim/Repo/smbprotocol/tests/test_smbclient_shutil.py:927: cannot create symlinks on Samba/home/maxim/Repo/smbprotocol/tests/test_smbclient_shutil.py:927: cannot create symlinks on Samba/home/maxim/Repo/smbprotocol/tests/test_smbclient_shutil.py:965: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_shutil.py:965: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_shutil.py:970: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_shutil.py:970: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_shutil.py:975: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_shutil.py:975: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_shutil.py:981: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_shutil.py:981: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_shutil.py:1067: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_shutil.py:1067: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_shutil.py:1079: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_shutil.py:1079: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_shutil.py:1116: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_shutil.py:1116: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_shutil.py:1152: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_shutil.py:1152: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_shutil.py:1179: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_shutil.py:1179: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_shutil.py:1206: Samba does not update timestamps/home/maxim/Repo/smbprotocol/tests/test_smbclient_shutil.py:1206: Samba does not update timestamps/home/maxim/Repo/smbprotocol/tests/test_smbclient_shutil.py:1288: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_shutil.py:1288: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_shutil.py:1324: cannot create symlinks on Samba/home/maxim/Repo/smbprotocol/tests/test_smbclient_shutil.py:1324: cannot create symlinks on Samba/home/maxim/Repo/smbprotocol/tests/test_smbclient_shutil.py:1359: cannot create symlinks on Samba/home/maxim/Repo/smbprotocol/tests/test_smbclient_shutil.py:1359: cannot create symlinks on Samba/home/maxim/Repo/smbprotocol/tests/test_smbclient_shutil.py:1390: cannot create symlinks on Samba/home/maxim/Repo/smbprotocol/tests/test_smbclient_shutil.py:1390: cannot create symlinks on Samba/home/maxim/Repo/smbprotocol/tests/test_smbclient_shutil.py:1417: cannot create symlinks on Samba/home/maxim/Repo/smbprotocol/tests/test_smbclient_shutil.py:1417: cannot create symlinks on Samba/home/maxim/Repo/smbprotocol/tests/test_smbclient_shutil.py:1434: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_shutil.py:1434: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_shutil.py:1460: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_shutil.py:1460: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_shutil.py:1484: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_shutil.py:1484: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_smbclient_shutil.py:1510: cannot create symlinks on Samba/home/maxim/Repo/smbprotocol/tests/test_smbclient_shutil.py:1510: cannot create symlinks on Samba/home/maxim/Repo/smbprotocol/tests/test_tree.py:104: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_tree.py:120: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_tree.py:136: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_tree.py:152: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_tree.py:168: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_tree.py:184: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_tree.py:196: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_tree.py:212: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_tree.py:226: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_tree.py:244: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_tree.py:244: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_tree.py:244: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_tree.py:244: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_tree.py:272: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_tree.py:272: The SMB_SHARE env var was not set, integration tests will be skipped/home/maxim/Repo/smbprotocol/tests/test_tree.py:272: The SMB_SHARE env var was not set, integration tests will be skipped \ No newline at end of file diff --git a/setup.py b/setup.py index 1939b8e2..dc8676d5 100644 --- a/setup.py +++ b/setup.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- # Copyright: (c) 2019, Jordan Borean (@jborean93) # MIT License (see LICENSE or https://opensource.org/licenses/MIT) diff --git a/src/smbclient/__init__.py b/src/smbclient/__init__.py index eaec4af4..151ae647 100644 --- a/src/smbclient/__init__.py +++ b/src/smbclient/__init__.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright: (c) 2019, Jordan Borean (@jborean93) # MIT License (see LICENSE or https://opensource.org/licenses/MIT) diff --git a/src/smbclient/_io.py b/src/smbclient/_io.py index b2032ae9..f836c9d5 100644 --- a/src/smbclient/_io.py +++ b/src/smbclient/_io.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright: (c) 2019, Jordan Borean (@jborean93) # MIT License (see LICENSE or https://opensource.org/licenses/MIT) @@ -52,9 +51,8 @@ def _parse_share_access(raw, mode): for c in raw: access_val = share_access_map.get(c) if access_val is None: - raise ValueError( - "Invalid share_access char %s, can only be %s" % (c, ", ".join(sorted(share_access_map.keys()))) - ) + chars = ", ".join(sorted(share_access_map.keys())) + raise ValueError(f"Invalid share_access char {c}, can only be {chars}") share_access |= access_val if "r" in mode: @@ -82,12 +80,15 @@ def _parse_mode(raw, invalid=""): for c in raw: dispo_val = disposition_map.get(c) if dispo_val is None: - raise ValueError("Invalid mode char %s, can only be %s" % (c, ", ".join(sorted(disposition_map.keys())))) + chars = ", ".join(sorted(disposition_map.keys())) + raise ValueError( + f"Invalid mode char {c}, can only be {chars}", + ) create_disposition |= dispo_val if create_disposition == 0: - raise ValueError("Invalid mode value %s, must contain at least r, w, x, or a" % raw) + raise ValueError(f"Invalid mode value {raw}, must contain at least r, w, x, or a") return create_disposition @@ -102,7 +103,7 @@ def _chunk_size(connection, length, operation): :param operation: The operation the chunk is for: 'read', 'write', 'transact' :return: The size of the chunk we can use and the number of credits to request for the next operation. """ - max_size = getattr(connection, "max_%s_size" % operation) + max_size = getattr(connection, f"max_{operation}_size") # Determine the maximum data length we can send for the operation. We do this by checking the available credits and # calculating whatever is the smallest; length, negotiated operation size, available credit size). @@ -141,7 +142,7 @@ def _resolve_dfs(raw_io): if not info: raise ObjectPathNotFound() - connection_kwargs = getattr(raw_io, "_%s__kwargs" % SMBRawIO.__name__, {}) + connection_kwargs = getattr(raw_io, f"_{SMBRawIO.__name__}__kwargs", {}) for target in info: new_path = raw_path.replace(info.dfs_path, target.target_path, 1) @@ -150,7 +151,7 @@ def _resolve_dfs(raw_io): tree, fd_path = get_smb_tree(new_path, **connection_kwargs) except SMBResponseException as link_exc: - log.warning("Failed to connect to DFS link target %s: %s", str(target), link_exc) + log.warning("Failed to connect to DFS link target %s", target, exc_info=link_exc) continue # Record the target that worked for future reference. @@ -612,8 +613,7 @@ def query_directory(self, pattern, info_class): break query_flags = 0 # Only the first request should have set SMB2_RESTART_SCANS - for entry in entries: - yield entry + yield from entries def readable(self): return False diff --git a/src/smbclient/_os.py b/src/smbclient/_os.py index 63d17741..859fa161 100644 --- a/src/smbclient/_os.py +++ b/src/smbclient/_os.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright: (c) 2019, Jordan Borean (@jborean93) # MIT License (see LICENSE or https://opensource.org/licenses/MIT) @@ -102,7 +101,7 @@ ) -def is_remote_path(path): # type: (str) -> bool +def is_remote_path(path: str) -> bool: """ Returns True iff the given path is a remote SMB path (rather than a local path). @@ -182,9 +181,8 @@ def copyfile(src, dst, **kwargs): copychunk_response = SMB2SrvCopyChunkResponse() copychunk_response.unpack(result) if copychunk_response["chunks_written"].get_value() != len(batch): - raise IOError( - "Failed to copy all the chunks in a server side copyfile: '%s' -> '%s'" - % (norm_src, norm_dst) + raise OSError( + f"Failed to copy all the chunks in a server side copyfile: '{norm_src}' -> '{norm_dst}'" ) @@ -433,7 +431,7 @@ def readlink(path, **kwargs): reparse_buffer = _get_reparse_point(norm_path, **kwargs) reparse_tag = reparse_buffer["reparse_tag"] if reparse_tag.get_value() != ReparseTags.IO_REPARSE_TAG_SYMLINK: - raise ValueError("Cannot read link of reparse point with tag %s at '%s'" % (str(reparse_tag), norm_path)) + raise ValueError(f"Cannot read link of reparse point with tag {reparse_tag} at '{norm_path}'") symlink_buffer = SymbolicLinkReparseDataBuffer() symlink_buffer.unpack(reparse_buffer["data_buffer"].get_value()) @@ -549,7 +547,7 @@ def scandir(path, search_pattern="*", **kwargs): continue dir_entry = SMBDirEntry( - SMBRawIO("%s\\%s" % (path, filename), **kwargs), dir_info, connection_cache=connection_cache + SMBRawIO(rf"{path}\{filename}", **kwargs), dir_info, connection_cache=connection_cache ) yield dir_entry @@ -696,12 +694,12 @@ def symlink(src, dst, target_is_directory=False, **kwargs): norm_src = ntpath.abspath(ntpath.join(dst_dir, norm_src)) else: flags = SymbolicLinkFlags.SYMLINK_FLAG_ABSOLUTE - substitute_name = "\\??\\UNC\\%s" % norm_src[2:] + substitute_name = "\\??\\UNC\\" + norm_src[2:] src_drive = ntpath.splitdrive(norm_src)[0] dst_drive = ntpath.splitdrive(norm_dst)[0] if src_drive.lower() != dst_drive.lower(): - raise ValueError("Resolved link src root '%s' must be the same as the dst root '%s'" % (src_drive, dst_drive)) + raise ValueError(f"Resolved link src root '{src_drive}' must be the same as the dst root '{dst_drive}'") try: src_stat = stat(norm_src, **kwargs) @@ -901,13 +899,11 @@ def walk(top, topdown=True, onerror=None, follow_symlinks=False, **kwargs): if not follow_symlinks and py_stat.S_ISLNK(lstat(dirpath, **kwargs).st_mode): continue - for dir_top, dir_dirs, dir_files in walk(dirpath, **walk_kwargs): - yield dir_top, dir_dirs, dir_files + yield from walk(dirpath, **walk_kwargs) else: # On a bottom up approach we yield the sub directories before the top path. for dirpath in bottom_up_dirs: - for dir_top, dir_dirs, dir_files in walk(dirpath, **walk_kwargs): - yield dir_top, dir_dirs, dir_files + yield from walk(dirpath, **walk_kwargs) yield top, dirs, files @@ -1095,7 +1091,7 @@ def _get_reparse_point(path, **kwargs): def _rename_information(src, dst, replace_if_exists=False, **kwargs): verb = "replace" if replace_if_exists else "rename" if not is_remote_path(ntpath.normpath(dst)): - raise ValueError("dst must be an absolute path to where the file or directory should be %sd." % verb) + raise ValueError(f"dst must be an absolute path to where the file or directory should be {verb}d.") raw_args = dict(kwargs) raw_args.update( @@ -1126,7 +1122,7 @@ def _rename_information(src, dst, replace_if_exists=False, **kwargs): dst_share = ntpath.normpath(dst_raw.fd.tree_connect.share_name).split("\\")[-1] if src_guid != dst_guid or src_share.lower() != dst_share.lower(): - raise ValueError("Cannot %s a file to a different root than the src." % verb) + raise ValueError(f"Cannot {verb} a file to a different root than the src.") dst_tree = dst_raw.fd.tree_connect dst_path = dst_raw.fd.file_name @@ -1181,7 +1177,7 @@ def __init__(self, raw, dir_info, connection_cache=None): self._connection_cache = connection_cache def __str__(self): - return "<{0}: {1!r}>".format(self.__class__.__name__, self.name) + return f"<{self.__class__.__name__}: {self.name!r}>" @property def name(self): diff --git a/src/smbclient/_pool.py b/src/smbclient/_pool.py index 14e80395..c5c8cf1f 100644 --- a/src/smbclient/_pool.py +++ b/src/smbclient/_pool.py @@ -1,13 +1,12 @@ -# -*- coding: utf-8 -*- # Copyright: (c) 2019, Jordan Borean (@jborean93) # MIT License (see LICENSE or https://opensource.org/licenses/MIT) +from __future__ import annotations + import atexit import logging import ntpath -import typing import uuid -import warnings from smbprotocol._text import to_text from smbprotocol.connection import Capabilities, Connection @@ -59,7 +58,7 @@ def __call__(cls, *args, **kwargs): return config -class ClientConfig(object, metaclass=_ConfigSingleton): +class ClientConfig(metaclass=_ConfigSingleton): """SMB Client global settings This class defines global settings for the client that affects all connections that the client makes. When setting @@ -99,9 +98,9 @@ def __init__( self.skip_dfs = skip_dfs self.auth_protocol = auth_protocol self.require_secure_negotiate = require_secure_negotiate - self._domain_controller = domain_controller # type: Optional[str] - self._domain_cache = [] # type: List[DomainEntry] - self._referral_cache = [] # type: List[ReferralEntry] + self._domain_controller: str | None = domain_controller + self._domain_cache: list[DomainEntry] = [] + self._referral_cache: list[ReferralEntry] = [] @property def domain_controller(self): @@ -119,13 +118,14 @@ def domain_controller(self, value): if not value or self.skip_dfs: return - ipc_tree = get_smb_tree("\\\\%s\\IPC$" % value)[0] + ipc_tree = get_smb_tree(rf"\\{value}\IPC$")[0] try: domain_referral_response = dfs_request(ipc_tree, "") except InvalidParameter: log.warning( "Specified domain controller %s return STATUS_INVALID_PARAMETER, cannot use as DFS domain " - "cache source" % value + "cache source", + value, ) return @@ -139,13 +139,13 @@ def cache_referral(self, referral): if referral["number_of_referrals"].get_value() > 0: self._referral_cache.append(ReferralEntry(referral)) - def lookup_domain(self, domain_name): # type: (str) -> Optional[DomainEntry] + def lookup_domain(self, domain_name: str) -> DomainEntry | None: # TODO: Check domain referral expiry and resend request if expired for domain in self._domain_cache: if domain.domain_name.lower() == ("\\" + domain_name.lower()): return domain - def lookup_referral(self, path_components: typing.List[str]) -> typing.Optional[ReferralEntry]: + def lookup_referral(self, path_components: list[str]) -> ReferralEntry | None: """Checks if the path exists in the DFS referral cache.""" # A lookup in ReferralCache involves searching for an entry with DFSPathPrefix that is a complete prefix of the # path being looked up. @@ -169,7 +169,7 @@ def set(self, **config): domain_controller = False for key, value in config.items(): if key.startswith("_"): - raise ValueError("Cannot set private attribute %s" % key) + raise ValueError(f"Cannot set private attribute {key}") elif key == "domain_controller": # This must be set last in case we are setting any username/password used for a domain referral lookup. @@ -186,7 +186,7 @@ def _clear_expired_cache(self) -> None: self._referral_cache = [refferal for refferal in self._referral_cache if not refferal.is_expired] -def dfs_request(tree, path): # type: (TreeConnect, str) -> DFSReferralResponse +def dfs_request(tree: TreeConnect, path: str) -> DFSReferralResponse: """Send a DFS Referral request to the IPC tree and return the referrals.""" dfs_referral = DFSReferralRequest() dfs_referral["request_file_name"] = to_text(path) @@ -219,7 +219,7 @@ def delete_session(server, port=445, connection_cache=None): :param port: The port used for the server. :param connection_cache: Connection cache to be used with """ - connection_key = "%s:%s" % (server.lower(), port) + connection_key = f"{server.lower()}:{port}" if connection_cache is None: connection_cache = _SMB_CONNECTIONS @@ -284,14 +284,14 @@ def get_smb_tree( if domain_referral and not domain_referral.is_valid: # If the path is a valid domain name but our domain referral is not currently valid, issue a DC referral # to our known domain controller. - ipc_tree = get_smb_tree("\\\\%s\\IPC$" % client_config.domain_controller, **get_kwargs)[0] + ipc_tree = get_smb_tree(rf"\\{client_config.domain_controller}\IPC$", **get_kwargs)[0] referral_response = dfs_request(ipc_tree, domain_referral.domain_name) domain_referral.process_dc_referral(referral_response) if domain_referral: # Use the dc hint as the source for the root referral request - ipc_tree = get_smb_tree("\\%s\\IPC$" % domain_referral.dc_hint, **get_kwargs)[0] - referral_response = dfs_request(ipc_tree, "\\%s\\%s" % (path_split[0], path_split[1])) + ipc_tree = get_smb_tree(rf"\{domain_referral.dc_hint}\IPC$", **get_kwargs)[0] + referral_response = dfs_request(ipc_tree, rf"\{path_split[0]}\{path_split[1]}") client_config.cache_referral(referral_response) referral = client_config.lookup_referral(path_split) if not referral: @@ -312,7 +312,7 @@ def get_smb_tree( auth_protocol=auth_protocol, ) - share_path = "\\\\%s\\%s" % (server, path_split[1]) + share_path = rf"\\{server}\{path_split[1]}" tree = next((t for t in session.tree_connect_table.values() if t.share_name == share_path), None) if not tree: tree = TreeConnect(session, share_path) @@ -324,14 +324,14 @@ def get_smb_tree( if not session.connection.server_capabilities.has_flag(Capabilities.SMB2_GLOBAL_CAP_DFS): raise - ipc_path = "\\\\%s\\IPC$" % server + ipc_path = rf"\\{server}\IPC$" if path == ipc_path: # In case we already tried connecting to IPC$ but that failed. raise # The share could be a DFS root, issue a root referral request to the hostname and cache the result. ipc_tree = get_smb_tree(ipc_path, **get_kwargs)[0] try: - referral = dfs_request(ipc_tree, "\\%s\\%s" % (path_split[0], path_split[1])) + referral = dfs_request(ipc_tree, rf"\{path_split[0]}\{path_split[1]}") except FSDriverRequired: # If the DFS Request fails with STATUS_FS_DRIVER_REQUIRED then # the server doesn't support DFS requests and the original @@ -396,7 +396,7 @@ def register_session( :param require_signing: Whether signing is required on SMB messages sent over this session. Defaults to True. :return: The Session that was registered or already existed in the pool. """ - connection_key = "%s:%s" % (server.lower(), port) + connection_key = f"{server.lower()}:{port}" if connection_cache is None: connection_cache = _SMB_CONNECTIONS @@ -448,7 +448,7 @@ def reset_connection_cache(fail_on_error=True, connection_cache=None): if fail_on_error: raise else: - warnings.warn("Failed to close connection %s: %s" % (name, str(e))) + log.warning("Failed to close connection %s", name, exc_info=e) atexit.register(reset_connection_cache, fail_on_error=False) diff --git a/src/smbclient/path.py b/src/smbclient/path.py index b6027edd..c3b4d44a 100644 --- a/src/smbclient/path.py +++ b/src/smbclient/path.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright: (c) 2019, Jordan Borean (@jborean93) # MIT License (see LICENSE or https://opensource.org/licenses/MIT) diff --git a/src/smbclient/shutil.py b/src/smbclient/shutil.py index c9d7aefe..30146bc7 100644 --- a/src/smbclient/shutil.py +++ b/src/smbclient/shutil.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright: (c) 2019, Jordan Borean (@jborean93) and other contributors # MIT License (see LICENSE or https://opensource.org/licenses/MIT) @@ -173,7 +172,7 @@ def copyfile(src, dst, follow_symlinks=True, **kwargs): raise if is_same: - raise shutil.Error("'%s' and '%s' are the same file, cannot copy" % (src, dst)) + raise shutil.Error(f"'{src}' and '{dst}' are the same file, cannot copy") smbclient_copyfile(src, dst, **kwargs) return dst diff --git a/src/smbprotocol/__init__.py b/src/smbprotocol/__init__.py index 2dd7a52a..3beb7344 100644 --- a/src/smbprotocol/__init__.py +++ b/src/smbprotocol/__init__.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright: (c) 2019, Jordan Borean (@jborean93) # MIT License (see LICENSE or https://opensource.org/licenses/MIT) diff --git a/src/smbprotocol/_text.py b/src/smbprotocol/_text.py index 71eb8abd..683386ae 100644 --- a/src/smbprotocol/_text.py +++ b/src/smbprotocol/_text.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright: (c) 2019, Jordan Borean (@jborean93) # MIT License (see LICENSE or https://opensource.org/licenses/MIT) diff --git a/src/smbprotocol/change_notify.py b/src/smbprotocol/change_notify.py index c7ecb31a..1565b473 100644 --- a/src/smbprotocol/change_notify.py +++ b/src/smbprotocol/change_notify.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright: (c) 2019, Jordan Borean (@jborean93) # MIT License (see LICENSE or https://opensource.org/licenses/MIT) @@ -280,8 +279,10 @@ def start(self, completion_filter, flags=0, output_buffer_length=65536, send=Tru change_notify["completion_filter"] = completion_filter log.info( - "Session: %s, Tree Connect: %s , Open: %s - sending SMB2 Change Notify request" - % (self.open.tree_connect.session.username, self.open.tree_connect.share_name, self.open.file_name) + "Session: %s, Tree Connect: %s , Open: %s - sending SMB2 Change Notify request", + self.open.tree_connect.session.username, + self.open.tree_connect.share_name, + self.open.file_name, ) log.debug(change_notify) if send: @@ -326,5 +327,5 @@ def _on_response(self): self._t_exc = exc finally: - log.debug("Firing response event for %s change notify" % self.open.file_name) + log.debug("Firing response event for %s change notify", self.open.file_name) self.response_event.set() diff --git a/src/smbprotocol/connection.py b/src/smbprotocol/connection.py index ce663cb6..be06a403 100644 --- a/src/smbprotocol/connection.py +++ b/src/smbprotocol/connection.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright: (c) 2019, Jordan Borean (@jborean93) # MIT License (see LICENSE or https://opensource.org/licenses/MIT) @@ -740,8 +739,11 @@ def __init__(self, guid, server_name, port=445, require_signing=True): sent over this connection """ log.info( - "Initialising connection, guid: %s, require_signing: %s, " - "server_name: %s, port: %d" % (guid, require_signing, server_name, port) + "Initialising connection, guid: %s, require_signing: %s, server_name: %s, port: %d", + guid, + require_signing, + server_name, + port, ) self.server_name = server_name self.port = port @@ -860,7 +862,7 @@ def connect(self, dialect=None, timeout=60, preferred_encryption_algos=None, pre self.transport = Tcp(self.server_name, self.port, timeout) self.transport.connect() t_worker = threading.Thread( - target=self._process_message_thread, name="msg_worker-%s:%s" % (self.server_name, self.port) + target=self._process_message_thread, name=f"msg_worker-{self.server_name}:{self.port}" ) t_worker.daemon = True t_worker.start() @@ -878,7 +880,7 @@ def connect(self, dialect=None, timeout=60, preferred_encryption_algos=None, pre SigningAlgorithms.HMAC_SHA256, ] smb_response = self._send_smb2_negotiate(dialect, timeout, enc_algos, sign_algos) - log.info("Negotiated dialect: %s" % str(smb_response["dialect_revision"])) + log.info("Negotiated dialect: %s", smb_response["dialect_revision"]) self.dialect = smb_response["dialect_revision"].get_value() self.max_transact_size = smb_response["max_transact_size"].get_value() self.max_read_size = smb_response["max_read_size"].get_value() @@ -890,7 +892,7 @@ def connect(self, dialect=None, timeout=60, preferred_encryption_algos=None, pre SecurityMode.SMB2_NEGOTIATE_SIGNING_REQUIRED ): self.require_signing = True - log.info("Connection require signing: %s" % self.require_signing) + log.info("Connection require signing: %s", self.require_signing) capabilities = smb_response["capabilities"] self.server_capabilities = capabilities @@ -1006,9 +1008,10 @@ def receive(self, request, wait=True, timeout=None, resolve_symlinks=True): while True: iter_timeout = int(max(timeout - (time.time() - start_time), 1)) if timeout is not None else None if not request.response_event.wait(timeout=iter_timeout): + value = request.message["message_id"].get_value() raise SMBException( - "Connection timeout of %d seconds exceeded while waiting for a message id %s " - "response from the server" % (timeout, request.message["message_id"].get_value()) + f"Connection timeout of {timeout} seconds exceeded while waiting for a message id {value} " + "response from the server" ) # Use a lock on the request so that in the case of a pending response we have exclusive lock on the event @@ -1044,9 +1047,7 @@ def receive(self, request, wait=True, timeout=None, resolve_symlinks=True): ) exp = SMBResponseException(response) - reparse_buffer = next( - (e for e in exp.error_details if isinstance(e, SMB2SymbolicLinkErrorResponse)) - ) + reparse_buffer = next(e for e in exp.error_details if isinstance(e, SMB2SymbolicLinkErrorResponse)) new_path = reparse_buffer.resolve_path(original_path)[len(tree_share_name) :] new_open = Open(tree, new_path) @@ -1151,7 +1152,7 @@ def verify_signature(self, header, session_id, force=False): session = self.session_table.get(session_id, None) if session is None: - raise SMBException("Failed to find session %s for message verification" % session_id) + raise SMBException(f"Failed to find session {session_id} for message verification") expected = self._generate_signature( header.pack(), @@ -1162,9 +1163,10 @@ def verify_signature(self, header, session_id, force=False): ) actual = header["signature"].get_value() if actual != expected: + actual_signature = binascii.hexlify(actual).decode() + expected_signature = binascii.hexlify(expected).decode() raise SMBException( - "Server message signature could not be verified: %s != %s" - % (binascii.hexlify(actual).decode(), binascii.hexlify(expected).decode()) + f"Server message signature could not be verified: {actual_signature} != {expected_signature}", ) def _check_worker_running(self): @@ -1221,8 +1223,8 @@ def _send( credits_available = sequence_window_high - sequence_window_low if credit_charge > credits_available: raise SMBException( - "Request requires %d credits but only %d credits are available" - % (credit_charge, credits_available) + f"Request requires {credit_charge} credits but only {credits_available} " + "credits are available" ) current_id = message_id or sequence_window_low @@ -1471,17 +1473,15 @@ def _encrypt(self, b_data, session): return header def _decrypt(self, message): - if message["flags"].get_value() != 0x0001: - error_msg = "Expecting flag of 0x0001 but got %s in the SMB Transform Header Response" % format( - message["flags"].get_value(), "x" - ) + value = message["flags"].get_value() + if value != 0x0001: + error_msg = f"Expecting flag of 0x0001 but got {value:x} in the SMB Transform Header Response" raise SMBException(error_msg) session_id = message["session_id"].get_value() session = self.session_table.get(session_id, None) if session is None: - error_msg = "Failed to find valid session %s for message decryption" % session_id - raise SMBException(error_msg) + raise SMBException(f"Failed to find valid session {session_id} for message decryption") if self.dialect >= Dialects.SMB_3_1_1: cipher_id = self.cipher_id @@ -1537,14 +1537,14 @@ def _send_smb2_negotiate(self, dialect, timeout, encryption_algorithms, signing_ highest_dialect = sorted(negotiated_dialects)[-1] self.negotiated_dialects = neg_req["dialects"] = negotiated_dialects log.info( - "Negotiating with SMB2 protocol with highest client dialect " - "of: %s" % [dialect for dialect, v in vars(Dialects).items() if v == highest_dialect][0] + "Negotiating with SMB2 protocol with highest client dialect of: %s", + [dialect for dialect, v in vars(Dialects).items() if v == highest_dialect][0], ) neg_req["security_mode"] = self.client_security_mode if highest_dialect >= Dialects.SMB_2_1_0: - log.debug("Adding client guid %s to negotiate request" % self.client_guid) + log.debug("Adding client guid %s to negotiate request", self.client_guid) neg_req["client_guid"] = self.client_guid else: @@ -1552,7 +1552,7 @@ def _send_smb2_negotiate(self, dialect, timeout, encryption_algorithms, signing_ self.client_guid = None if highest_dialect >= Dialects.SMB_3_0_0: - log.debug("Adding client capabilities %d to negotiate request" % self.client_capabilities) + log.debug("Adding client capabilities %d to negotiate request", self.client_capabilities) neg_req["capabilities"] = self.client_capabilities else: @@ -1566,7 +1566,8 @@ def _send_smb2_negotiate(self, dialect, timeout, encryption_algorithms, signing_ int_cap["data"]["hash_algorithms"] = [HashAlgorithms.SHA_512] int_cap["data"]["salt"] = self.salt log.debug( - "Adding preauth integrity capabilities of hash SHA512 and salt %s to negotiate request" % self.salt + "Adding preauth integrity capabilities of hash SHA512 and salt %s to negotiate request", + self.salt, ) enc_cap = SMB2NegotiateContextRequest() @@ -1699,7 +1700,7 @@ def cancel(self): return message_id = self.message["message_id"].get_value() - log.info("Cancelling message %s" % message_id) + log.info("Cancelling message %s", message_id) self._connection.send( SMB2CancelRequest(), sid=self.session_id, credit_request=0, message_id=message_id, async_id=self.async_id ) diff --git a/src/smbprotocol/create_contexts.py b/src/smbprotocol/create_contexts.py index 6b0bb1a9..d6426edd 100644 --- a/src/smbprotocol/create_contexts.py +++ b/src/smbprotocol/create_contexts.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright: (c) 2019, Jordan Borean (@jborean93) # MIT License (see LICENSE or https://opensource.org/licenses/MIT) diff --git a/src/smbprotocol/dfs.py b/src/smbprotocol/dfs.py index 6e46f1d1..37cccbe0 100644 --- a/src/smbprotocol/dfs.py +++ b/src/smbprotocol/dfs.py @@ -1,8 +1,11 @@ # Copyright: (c) 2020, Jordan Borean (@jborean93) # MIT License (see LICENSE or https://opensource.org/licenses/MIT) +from __future__ import annotations + import time from collections import OrderedDict, namedtuple +from typing import Iterator from smbprotocol.structure import ( BytesField, @@ -41,24 +44,24 @@ class DomainEntry: domain_list (List[str]): A list of known domain controller hostnames for the domain. """ - def __init__(self, referral): # type: (DFSReferralEntryV3) -> None + def __init__(self, referral: DFSReferralEntryV3): self.domain_list = [] - self._referral = referral # type: DFSReferralEntryV3 - self._start_time = time.time() # type: float - self._domain_hint_idx = None # type: Optional[int] + self._referral = referral + self._start_time: float = time.time() + self._domain_hint_idx: int | None = None @property - def domain_name(self): # type: () -> str + def domain_name(self) -> str: """The domain DFS path.""" return self._referral.dfs_path @property - def dc_hint(self): # type: () -> str + def dc_hint(self) -> str: """The last known good domain hostname in domain_list.""" return self.domain_list[self._domain_hint_idx] @dc_hint.setter - def dc_hint(self, value): # type: (str) -> None + def dc_hint(self, value: str) -> None: for idx, target in enumerate(self.domain_list): if target == value: self._domain_hint_idx = idx @@ -68,16 +71,16 @@ def dc_hint(self, value): # type: (str) -> None raise ValueError("The specific domain hint does not exist in this domain cache entry") @property - def is_expired(self): # type: () -> bool + def is_expired(self) -> bool: """Whether the hint has expired or not.""" return ((time.time() - self._start_time) - self._referral["time_to_live"].get_value()) >= 0 @property - def is_valid(self): # type: () -> bool + def is_valid(self) -> bool: """Whether the domain entry has had a DC referral response or not.""" return self._domain_hint_idx is not None and not self.is_expired - def process_dc_referral(self, referral): # type: (DFSReferralResponse) -> None + def process_dc_referral(self, referral: DFSReferralResponse) -> None: if self._domain_hint_idx is None: self._domain_hint_idx = 0 @@ -96,54 +99,53 @@ class ReferralEntry: referral: The DFSReferralResponse to cache. """ - def __init__(self, referral): # type: (DFSReferralResponse) -> None + def __init__(self, referral: DFSReferralResponse): referrals = referral["referral_entries"].get_value() self._referral_header_flags = referral["referral_header_flags"] - self._referrals = referrals # type: List[Union[DFSReferralEntryV1, DFSReferralEntryV2, DFSReferralEntryV3]] - self._start_time = time.time() # type: float - self._target_hint_idx = 0 # type: int + self._referrals: list[DFSReferralEntryV1 | DFSReferralEntryV2 | DFSReferralEntryV3] = referrals + self._start_time: float = time.time() + self._target_hint_idx: int = 0 @property - def dfs_path(self): # type: () -> str + def dfs_path(self) -> str: return self._referrals[self._target_hint_idx].dfs_path @property - def is_root(self): # type: () -> bool + def is_root(self) -> bool: return self._referrals[self._target_hint_idx]["server_type"].has_flag(DFSServerTypes.ROOT_TARGETS) @property - def is_link(self): # type: () -> bool + def is_link(self) -> bool: return not self.is_root # @property - # def is_interlink(self): # type: () -> bool + # def is_interlink(self) -> bool: # return False @property - def is_expired(self): # type: () -> bool + def is_expired(self) -> bool: referral = self._referrals[self._target_hint_idx] return ((time.time() - self._start_time) - referral["time_to_live"].get_value()) >= 0 @property - def target_failback(self): # type: () -> bool + def target_failback(self) -> bool: return self._referral_header_flags.has_flag(DFSReferralHeaderFlags.TARGET_FAIL_BACK) @property - def target_hint(self): # type: () -> DFSTarget + def target_hint(self) -> DFSTarget: return self.target_list[self._target_hint_idx] @target_hint.setter - def target_hint(self, value): # type: (DFSTarget) -> None + def target_hint(self, value: DFSTarget) -> None: for idx, target in enumerate(self.target_list): if target == value: self._target_hint_idx = idx break - else: raise ValueError("The specific target hint does not exist in this referral entry") @property - def target_list(self): # type: () -> List[DFSTarget] + def target_list(self) -> list[DFSTarget]: return [ DFSTarget( target_path=e.network_address, @@ -152,7 +154,7 @@ def target_list(self): # type: () -> List[DFSTarget] for e in self._referrals ] - def __iter__(self): # type: () -> Iterator[DFSTarget] + def __iter__(self) -> Iterator[DFSTarget]: """Iterates through the target_list with a priority being the hinted value.""" yield self.target_list[self._target_hint_idx] @@ -387,7 +389,7 @@ def process_string_buffer(self, buffer, entry_offset): buffer_fields = ["dfs_path", "dfs_alternate_path", "network_address"] for field_name in buffer_fields: - field_offset = self["%s_offset" % field_name].get_value() + field_offset = self[f"{field_name}_offset"].get_value() if field_offset == 0: continue @@ -433,7 +435,7 @@ def process_string_buffer(self, buffer, entry_offset): buffer_fields.insert(1, "dfs_alternate_path") for field_name in buffer_fields: - field_offset = self["%s_offset" % field_name].get_value() + field_offset = self[f"{field_name}_offset"].get_value() if field_offset == 0: continue diff --git a/src/smbprotocol/exceptions.py b/src/smbprotocol/exceptions.py index a9ec482f..8508eed0 100644 --- a/src/smbprotocol/exceptions.py +++ b/src/smbprotocol/exceptions.py @@ -1,13 +1,15 @@ -# -*- coding: utf-8 -*- # Copyright: (c) 2019, Jordan Borean (@jborean93) # MIT License (see LICENSE or https://opensource.org/licenses/MIT) +from __future__ import annotations + import binascii import errno import ntpath import os import socket from collections import OrderedDict +from typing import Any from smbprotocol import Dialects from smbprotocol._text import to_bytes, to_text @@ -47,7 +49,7 @@ class SMBOSError(OSError, SMBException): def __init__(self, ntstatus, filename, filename2=None): self.ntstatus = ntstatus - self.filename2 = str(filename2) if filename2 else None + self.filename2 = os.fspath(filename2) if filename2 else None ntstatus_name = "STATUS_UNKNOWN" for name, val in vars(NtStatus).items(): @@ -70,19 +72,18 @@ def __init__(self, ntstatus, filename, filename2=None): NtStatus.STATUS_NOT_A_DIRECTORY: errno.ENOTDIR, NtStatus.STATUS_DIRECTORY_NOT_EMPTY: errno.ENOTEMPTY, NtStatus.STATUS_END_OF_FILE: getattr(errno, "ENODATA", 120), # Not present on py2 for Windows. - }.get(ntstatus, (0, "Unknown NtStatus error returned '%s'" % ntstatus_name)) + }.get(ntstatus, (0, f"Unknown NtStatus error returned '{ntstatus_name}'")) if not isinstance(error_details, tuple): error_details = (error_details, os.strerror(error_details)) - super().__init__(error_details[0], error_details[1], str(filename)) + super().__init__(error_details[0], error_details[1], os.fspath(filename)) def __str__(self): - msg = "[Error {0}] [NtStatus 0x{1}] {2}: '{3}'".format( - self.errno, format(self.ntstatus, "x").zfill(8), self.strerror, self.filename - ) + status = format(self.ntstatus, "x").zfill(8) + msg = f"[Error {self.errno}] [NtStatus 0x{status}] {self.strerror}: '{self.filename}'" if self.filename2: - msg += " -> '%s'" % self.filename2 + msg += f" -> '{self.filename2}'" return msg @@ -90,10 +91,9 @@ def __str__(self): class SMBLinkRedirectionError(SMBException): @property def message(self): - msg = "Encountered symlink at '%s' that points to '%s' which cannot be redirected: %s" % ( - str(self.path), - str(self.target), - str(self.args[0]), + msg = ( + f"Encountered symlink at '{self.path}' that points to " + f"'{self.target}' which cannot be redirected: {self.args[0]}" ) return msg @@ -141,11 +141,9 @@ def message(self): required_dialect = self._get_dialect_name(self.required_dialect) negotiated_dialect = self._get_dialect_name(self.negotiated_dialect) - msg = "%s is not available on the negotiated dialect %s, requires dialect %s%s" % ( - self.feature_name, - negotiated_dialect, - required_dialect, - msg_suffix, + msg = ( + f"{self.feature_name} is not available on the negotiated dialect {negotiated_dialect}, " + f"requires dialect {required_dialect}{msg_suffix}" ) return msg @@ -169,9 +167,7 @@ def __init__(cls, name, bases, attributes): return if not hasattr(cls, "_STATUS_CODE"): - raise ValueError( - "%s.%s does not have the _STATUS_CODE class attribute set" % (cls.__module__, cls.__name__) - ) + raise ValueError(f"{cls.__module__}.{cls.__name__} does not have the _STATUS_CODE class attribute set") cls.__registry[cls._STATUS_CODE] = cls @@ -201,11 +197,11 @@ class SMBResponseException(SMBException, metaclass=_SMBErrorRegistry): _BASE_MESSAGE = "Unknown error." - def __init__(self, header): # type: (SMB2HeaderResponse) -> None + def __init__(self, header: SMB2HeaderResponse): self.header = header @property - def error_details(self): # type: () -> List[any] + def error_details(self) -> list[Any]: # list of error_details returned by the server, currently used in # the SMB 3.1.1 error response for certain situations error = SMB2ErrorResponse() @@ -235,7 +231,7 @@ def error_details(self): # type: () -> List[any] return error_details @property - def message(self): # type: () -> str + def message(self) -> str: error_details = [] for detail in self.error_details: @@ -243,7 +239,7 @@ def message(self): # type: () -> str flag = str(detail["flags"]) print_name = detail.get_print_name() sub_name = detail.get_substitute_name() - error_details.append("Flag: %s, Print Name: %s, Substitute Name: %s" % (flag, print_name, sub_name)) + error_details.append(f"Flag: {flag}, Print Name: {print_name}, Substitute Name: {sub_name}") elif isinstance(detail, SMB2ShareRedirectErrorContext): ip_addresses = [] @@ -251,19 +247,19 @@ def message(self): # type: () -> str ip_addresses.append(ip_addr.get_ipaddress()) resource_name = to_text(detail["resource_name"].get_value(), encoding="utf-16-le") - error_details.append( - "IP Addresses: '%s', Resource Name: %s" % ("', '".join(ip_addresses), resource_name) - ) + addresses = "', '".join(ip_addresses) + error_details.append(f"IP Addresses: '{addresses}', Resource Name: {resource_name}") else: # unknown error details in response, output raw bytes - error_details.append("Raw: %s" % to_text(binascii.hexlify(detail))) + error_details.append("Raw: " + to_text(binascii.hexlify(detail))) - error_msg = "%s %s: 0x%s" % (self._BASE_MESSAGE, str(self.header["status"]), format(self.status, "x").zfill(8)) + status = format(self.status, "x").zfill(8) + error_msg = f"{self._BASE_MESSAGE} {self.header['status']}: 0x{status}" if error_details: - error_msg += " - %s" % ", ".join(error_details) + error_msg += " - " + (", ".join(error_details)) - return "Received unexpected status from the server: %s" % error_msg + return f"Received unexpected status from the server: {error_msg}" @property def status(self): diff --git a/src/smbprotocol/file_info.py b/src/smbprotocol/file_info.py index 0fc4df71..b54f6090 100644 --- a/src/smbprotocol/file_info.py +++ b/src/smbprotocol/file_info.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright: (c) 2019, Jordan Borean (@jborean93) # MIT License (see LICENSE or https://opensource.org/licenses/MIT) diff --git a/src/smbprotocol/header.py b/src/smbprotocol/header.py index 8142d3d8..fb3a0301 100644 --- a/src/smbprotocol/header.py +++ b/src/smbprotocol/header.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright: (c) 2020, Jordan Borean (@jborean93) # MIT License (see LICENSE or https://opensource.org/licenses/MIT) diff --git a/src/smbprotocol/ioctl.py b/src/smbprotocol/ioctl.py index 662f5bf2..cf2c5876 100644 --- a/src/smbprotocol/ioctl.py +++ b/src/smbprotocol/ioctl.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright: (c) 2019, Jordan Borean (@jborean93) # MIT License (see LICENSE or https://opensource.org/licenses/MIT) diff --git a/src/smbprotocol/open.py b/src/smbprotocol/open.py index 6885b489..14467d4c 100644 --- a/src/smbprotocol/open.py +++ b/src/smbprotocol/open.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright: (c) 2019, Jordan Borean (@jborean93) # MIT License (see LICENSE or https://opensource.org/licenses/MIT) @@ -1150,8 +1149,10 @@ def create( return create, self._create_response log.info( - "Session: %s, Tree Connect: %s - sending SMB2 Create Request " - "for file %s" % (self.tree_connect.session.username, self.tree_connect.share_name, self.file_name) + "Session: %s, Tree Connect: %s - sending SMB2 Create Request for file %s", + self.tree_connect.session.username, + self.tree_connect.share_name, + self.file_name, ) log.debug(create) @@ -1160,8 +1161,9 @@ def create( def _create_response(self, request): log.info( - "Session: %s, Tree Connect: %s - receiving SMB2 Create " - "Response" % (self.tree_connect.session.username, self.tree_connect.share_name) + "Session: %s, Tree Connect: %s - receiving SMB2 Create Response", + self.tree_connect.session.username, + self.tree_connect.share_name, ) response = self.connection.receive(request) create_response = SMB2CreateResponse() @@ -1222,8 +1224,8 @@ def read(self, offset, length, min_length=0, unbuffered=False, wait=True, send=T """ if length > self.connection.max_read_size: raise SMBException( - "The requested read length %d is greater than " - "the maximum negotiated read size %d" % (length, self.connection.max_read_size) + f"The requested read length {length} is greater than " + f"the maximum negotiated read size {self.connection.max_read_size}" ) read = SMB2ReadRequest() @@ -1244,8 +1246,10 @@ def read(self, offset, length, min_length=0, unbuffered=False, wait=True, send=T return read, self._read_response log.info( - "Session: %s, Tree Connect ID: %s - sending SMB2 Read " - "Request for file %s" % (self.tree_connect.session.username, self.tree_connect.share_name, self.file_name) + "Session: %s, Tree Connect ID: %s - sending SMB2 Read Request for file %s", + self.tree_connect.session.username, + self.tree_connect.share_name, + self.file_name, ) log.debug(read) request = self.connection.send(read, self.tree_connect.session.session_id, self.tree_connect.tree_connect_id) @@ -1253,8 +1257,9 @@ def read(self, offset, length, min_length=0, unbuffered=False, wait=True, send=T def _read_response(self, request, wait=True): log.info( - "Session: %s, Tree Connect ID: %s - receiving SMB2 Read " - "Response" % (self.tree_connect.session.username, self.tree_connect.share_name) + "Session: %s, Tree Connect ID: %s - receiving SMB2 Read Response", + self.tree_connect.session.username, + self.tree_connect.share_name, ) response = self.connection.receive(request, wait=wait) read_response = SMB2ReadResponse() @@ -1288,8 +1293,8 @@ def write(self, data, offset=0, write_through=False, unbuffered=False, wait=True data_len = len(data) if data_len > self.connection.max_write_size: raise SMBException( - "The requested write length %d is greater than " - "the maximum negotiated write size %d" % (data_len, self.connection.max_write_size) + f"The requested write length {data_len} is greater than " + f"the maximum negotiated write size {self.connection.max_write_size}" ) write = SMB2WriteRequest() @@ -1316,8 +1321,10 @@ def write(self, data, offset=0, write_through=False, unbuffered=False, wait=True return write, self._write_response log.info( - "Session: %s, Tree Connect: %s - sending SMB2 Write Request " - "for file %s" % (self.tree_connect.session.username, self.tree_connect.share_name, self.file_name) + "Session: %s, Tree Connect: %s - sending SMB2 Write Request for file %s", + self.tree_connect.session.username, + self.tree_connect.share_name, + self.file_name, ) log.debug(write) request = self.connection.send(write, self.tree_connect.session.session_id, self.tree_connect.tree_connect_id) @@ -1325,8 +1332,9 @@ def write(self, data, offset=0, write_through=False, unbuffered=False, wait=True def _write_response(self, request, wait=True): log.info( - "Session: %s, Tree Connect: %s - receiving SMB2 Write " - "Response" % (self.tree_connect.session.username, self.tree_connect.share_name) + "Session: %s, Tree Connect: %s - receiving SMB2 Write Response", + self.tree_connect.session.username, + self.tree_connect.share_name, ) response = self.connection.receive(request, wait=wait) write_response = SMB2WriteResponse() @@ -1357,8 +1365,10 @@ def flush(self, send=True): return flush, self._flush_response log.info( - "Session: %s, Tree Connect: %s - sending SMB2 Flush Request " - "for file %s" % (self.tree_connect.session.username, self.tree_connect.share_name, self.file_name) + "Session: %s, Tree Connect: %s - sending SMB2 Flush Request for file %s", + self.tree_connect.session.username, + self.tree_connect.share_name, + self.file_name, ) log.debug(flush) request = self.connection.send(flush, self.tree_connect.session.session_id, self.tree_connect.tree_connect_id) @@ -1366,8 +1376,9 @@ def flush(self, send=True): def _flush_response(self, request): log.info( - "Session: %s, Tree Connect: %s - receiving SMB2 Flush " - "Response" % (self.tree_connect.session.username, self.tree_connect.share_name) + "Session: %s, Tree Connect: %s - receiving SMB2 Flush Response", + self.tree_connect.session.username, + self.tree_connect.share_name, ) response = self.connection.receive(request) flush_response = SMB2FlushResponse() @@ -1415,9 +1426,10 @@ def query_directory( return query, self._query_directory_response log.info( - "Session: %s, Tree Connect: %s - sending SMB2 Query " - "Directory Request for directory %s" - % (self.tree_connect.session.username, self.tree_connect.share_name, self.file_name) + "Session: %s, Tree Connect: %s - sending SMB2 Query Directory Request for directory %s", + self.tree_connect.session.username, + self.tree_connect.share_name, + self.file_name, ) log.debug(query) request = self.connection.send(query, self.tree_connect.session.session_id, self.tree_connect.tree_connect_id) @@ -1425,8 +1437,9 @@ def query_directory( def _query_directory_response(self, request): log.info( - "Session: %s, Tree Connect: %s - receiving SMB2 Query " - "Response" % (self.tree_connect.session.username, self.tree_connect.share_name) + "Session: %s, Tree Connect: %s - receiving SMB2 Query Response", + self.tree_connect.session.username, + self.tree_connect.share_name, ) response = self.connection.receive(request) query_response = SMB2QueryDirectoryResponse() @@ -1470,8 +1483,10 @@ def close(self, get_attributes=False, send=True): return close, self._close_response log.info( - "Session: %s, Tree Connect: %s - sending SMB2 Close Request " - "for file %s" % (self.tree_connect.session.username, self.tree_connect.share_name, self.file_name) + "Session: %s, Tree Connect: %s - sending SMB2 Close Request for file %s", + self.tree_connect.session.username, + self.tree_connect.share_name, + self.file_name, ) log.debug(close) request = self.connection.send(close, self.tree_connect.session.session_id, self.tree_connect.tree_connect_id) @@ -1479,8 +1494,9 @@ def close(self, get_attributes=False, send=True): def _close_response(self, request): log.info( - "Session: %s, Tree Connect: %s - receiving SMB2 Close " - "Response" % (self.tree_connect.session.username, self.tree_connect.share_name) + "Session: %s, Tree Connect: %s - receiving SMB2 Close Response", + self.tree_connect.session.username, + self.tree_connect.share_name, ) try: response = self.connection.receive(request) diff --git a/src/smbprotocol/query_info.py b/src/smbprotocol/query_info.py index ef56ccad..88c20227 100644 --- a/src/smbprotocol/query_info.py +++ b/src/smbprotocol/query_info.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright: (c) 2019, Jordan Borean (@jborean93) # MIT License (see LICENSE or https://opensource.org/licenses/MIT) diff --git a/src/smbprotocol/reparse_point.py b/src/smbprotocol/reparse_point.py index d8ed4126..70829dad 100644 --- a/src/smbprotocol/reparse_point.py +++ b/src/smbprotocol/reparse_point.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright: (c) 2019, Jordan Borean (@jborean93) # MIT License (see LICENSE or https://opensource.org/licenses/MIT) @@ -201,7 +200,7 @@ def resolve_link(self, path): return ntpath.abspath(link_target) def _get_name(self, prefix): - offset = self["%s_name_offset" % prefix].get_value() - length = self["%s_name_length" % prefix].get_value() + offset = self[f"{prefix}_name_offset"].get_value() + length = self[f"{prefix}_name_length"].get_value() b_name = self["buffer"].get_value()[offset : offset + length] return to_text(b_name, encoding="utf-16-le") diff --git a/src/smbprotocol/security_descriptor.py b/src/smbprotocol/security_descriptor.py index 0d7636db..bbfc7ca7 100644 --- a/src/smbprotocol/security_descriptor.py +++ b/src/smbprotocol/security_descriptor.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright: (c) 2019, Jordan Borean (@jborean93) # MIT License (see LICENSE or https://opensource.org/licenses/MIT) @@ -158,7 +157,8 @@ def __str__(self): revision = self["revision"].get_value() id_authority = self["identifier_authority"].get_value() sub_authorities = self["sub_authorities"].get_value() - sid_string = "S-%d-%d-%s" % (revision, id_authority, "-".join(str(x) for x in sub_authorities)) + authorities_string = "-".join(str(x) for x in sub_authorities) + sid_string = f"S-{revision}-{id_authority}-{authorities_string}" return sid_string def from_string(self, sid_string): @@ -389,7 +389,7 @@ def _rebuild_buffer(self): for field, value in self._buffer.items(): if not value: continue - offset_field = "offset_%s" % field + offset_field = f"offset_{field}" field_bytes = value.pack() buffer += field_bytes self[offset_field].set_value(offset_count) diff --git a/src/smbprotocol/session.py b/src/smbprotocol/session.py index 56c36fde..f521173f 100644 --- a/src/smbprotocol/session.py +++ b/src/smbprotocol/session.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright: (c) 2019, Jordan Borean (@jborean93) # MIT License (see LICENSE or https://opensource.org/licenses/MIT) @@ -216,7 +215,7 @@ def __init__(self, connection, username=None, password=None, require_encryption= values are 'negotiate', 'ntlm' or 'kerberos'. Defaults to 'negotiate'. """ - log.info("Initialising session with username: %s" % username) + log.info("Initialising session with username: %s", username) self._connected = False self.session_id = 0 self.require_encryption = require_encryption @@ -272,7 +271,7 @@ def connect(self): protocol=self.auth_protocol, ) except spnego.exceptions.SpnegoError as err: - raise SMBAuthenticationError("Failed to authenticate with server: %s" % str(err.message)) + raise SMBAuthenticationError(f"Failed to authenticate with server: {err}") from err in_token = self.connection.gss_negotiate_token if self.auth_protocol != "negotiate": @@ -282,7 +281,7 @@ def connect(self): try: out_token = context.step(in_token) except spnego.exceptions.SpnegoError as err: - raise SMBAuthenticationError("Failed to authenticate with server: %s" % str(err.message)) + raise SMBAuthenticationError(f"Failed to authenticate with server: {err}") from err if not out_token: break @@ -320,7 +319,7 @@ def connect(self): if status == NtStatus.STATUS_MORE_PROCESSING_REQUIRED: log.info("More processing is required for SMB2_SESSION_SETUP") - log.info("Setting session id to %s" % self.session_id) + log.info("Setting session id to %s", self.session_id) self._connected = True # Move the session from the preauth table to the actual session table. @@ -412,13 +411,13 @@ def disconnect(self, close=True): for tree in list(self.tree_connect_table.values()): tree.disconnect() - log.info("Session: %s - Logging off of SMB Session" % self.username) + log.info("Session: %s - Logging off of SMB Session", self.username) logoff = SMB2Logoff() - log.info("Session: %s - Sending Logoff message" % self.username) + log.info("Session: %s - Sending Logoff message", self.username) log.debug(logoff) request = self.connection.send(logoff, sid=self.session_id) - log.info("Session: %s - Receiving Logoff response" % self.username) + log.info("Session: %s - Receiving Logoff response", self.username) res = self.connection.receive(request) res_logoff = SMB2Logoff() res_logoff.unpack(res["data"].get_value()) diff --git a/src/smbprotocol/structure.py b/src/smbprotocol/structure.py index d9726551..7f20d8ec 100644 --- a/src/smbprotocol/structure.py +++ b/src/smbprotocol/structure.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright: (c) 2019, Jordan Borean (@jborean93) # MIT License (see LICENSE or https://opensource.org/licenses/MIT) @@ -71,11 +70,10 @@ def __str__(self): # the field header is slightly different for a StructureField # remove the leading space and put the value on the next line if isinstance(field, StructureField): - field_header = "%s =\n%s" + field_string = f"{field.name} =\n{field}" else: - field_header = "%s = %s" + field_string = f"{field.name} = {field}" - field_string = field_header % (field.name, str(field)) field_strings.append(_indent_lines(field_string, TAB)) field_strings.append("") @@ -87,8 +85,9 @@ def __str__(self): ) field_strings.append(hex_wrapper.fill(raw_hex)) - string = "%s:\n%s" % (to_text(struct_name), "\n".join([to_text(s) for s in field_strings])) - + struct_name = to_text(struct_name) + field_names = "\n".join([to_text(s) for s in field_strings]) + string = f"{struct_name}:\n{field_names}" return string def __setitem__(self, key, value): @@ -125,7 +124,7 @@ def unpack(self, data): def _get_field(self, key): field = self.fields.get(key, None) if field is None: - raise ValueError("Structure does not contain field %s" % key) + raise ValueError(f"Structure does not contain field {key}") return field @@ -150,7 +149,7 @@ def __init__(self, little_endian=True, default=None, size=None): self.little_endian = little_endian if not (size is None or isinstance(size, int) or isinstance(size, types.LambdaType)): - raise InvalidFieldDefinition("%s size for field must be an int or None for a variable length" % field_type) + raise InvalidFieldDefinition(f"{field_type} size for field must be an int or None for a variable length") self.size = size self.default = default self.value = None @@ -161,6 +160,10 @@ def __str__(self): def __len__(self): return self._get_packed_size() + @property + def _endian_prefix(self): + return "<" if self.little_endian else ">" + def pack(self): """ Packs the field value into a byte string so it can be sent to the @@ -172,10 +175,11 @@ def pack(self): value = self._get_calculated_value(self.value) packed_value = self._pack_value(value) size = self._get_calculated_size(self.size, packed_value) - if len(packed_value) != size: + packed_value_len = len(packed_value) + if packed_value_len != size: raise ValueError( - "Invalid packed data length for field %s of %d " - "does not fit field size of %d" % (self.name, len(packed_value), size) + f"Invalid packed data length for field {self.name} of {packed_value_len} " + f"does not fit field size of {size}" ) return packed_value @@ -310,7 +314,7 @@ def _get_struct_format(self, size, unsigned=True): struct_format = {1: "B", 2: "H", 4: "L", 8: "Q"} if size not in struct_format.keys(): - raise InvalidFieldDefinition("Cannot struct format of size %s" % size) + raise InvalidFieldDefinition(f"Cannot struct format of size {size}") format_char = struct_format[size] if not unsigned: format_char = format_char.lower() @@ -329,13 +333,12 @@ def __init__(self, size, unsigned=True, **kwargs): :param kwargs: Any other kwarg to be sent to Field() """ if size not in [1, 2, 4, 8]: - raise InvalidFieldDefinition("IntField size must have a value of 1, 2, 4, or 8 not %s" % str(size)) + raise InvalidFieldDefinition(f"IntField size must have a value of 1, 2, 4, or 8 not {size}") self.unsigned = unsigned super().__init__(size=size, **kwargs) def _pack_value(self, value): - format = self._get_struct_format(self.size, self.unsigned) - struct_string = "%s%s" % ("<" if self.little_endian else ">", format) + struct_string = self._endian_prefix + self._get_struct_format(self.size, self.unsigned) packed_int = struct.pack(struct_string, value) return packed_int @@ -345,13 +348,12 @@ def _parse_value(self, value): elif isinstance(value, types.LambdaType): int_value = value elif isinstance(value, bytes): - format = self._get_struct_format(self.size, self.unsigned) - struct_string = "%s%s" % ("<" if self.little_endian else ">", format) + struct_string = self._endian_prefix + self._get_struct_format(self.size, self.unsigned) int_value = struct.unpack(struct_string, value)[0] elif isinstance(value, int): int_value = value else: - raise TypeError("Cannot parse value for field %s of type %s to an int" % (self.name, type(value).__name__)) + raise TypeError(f"Cannot parse value for field {self.name} of type {type(value).__name__} to an int") return int_value def _get_packed_size(self): @@ -377,17 +379,14 @@ def _parse_value(self, value): elif isinstance(value, types.LambdaType): bytes_value = value elif isinstance(value, int): - format = self._get_struct_format(self.size) - struct_string = "%s%s" % ("<" if self.little_endian else ">", format) + struct_string = self._endian_prefix + self._get_struct_format(self.size) bytes_value = struct.pack(struct_string, value) elif isinstance(value, Structure): bytes_value = value.pack() elif isinstance(value, bytes): bytes_value = value else: - raise TypeError( - "Cannot parse value for field %s of type %s to a byte string" % (self.name, type(value).__name__) - ) + raise TypeError(f"Cannot parse value for field {self.name} of type {type(value).__name__} to a byte string") return bytes_value def _get_packed_size(self): @@ -487,7 +486,7 @@ def _parse_value(self, value): # manually parse each list entry to the field type specified list_value = value else: - raise TypeError("Cannot parse value for field %s of type %s to a list" % (self.name, type(value).__name__)) + raise TypeError(f"Cannot parse value for field {self.name} of type {type(value).__name__} to a list") list_value = [self._parse_sub_value(v) for v in list_value] return list_value @@ -500,12 +499,12 @@ def _parse_sub_value(self, value): structure_type=type(value), default=value, ) - new_field.name = "%s list entry" % self.name + new_field.name = f"{self.name} list entry" new_field.structure = value new_field.set_value(new_field.default) else: new_field = copy.deepcopy(self.list_type) - new_field.name = "%s list entry" % self.name + new_field.name = f"{self.name} list entry" new_field.set_value(value) return new_field @@ -522,7 +521,8 @@ def _to_string(self): if len(list_string) == 0: string = "[]" else: - string = "[\n%s\n]" % ",\n".join(list_string) + list_str = ",\n".join(list_string) + string = f"[\n{list_str}\n]" return string def _create_list_from_bytes(self, list_count, list_type, value): @@ -583,9 +583,7 @@ def _parse_value(self, value): elif isinstance(value, Structure): structure_value = value else: - raise TypeError( - "Cannot parse value for field %s of type %s to a structure" % (self.name, type(value).__name__) - ) + raise TypeError(f"Cannot parse value for field {self.name} of type {type(value).__name__} to a structure") if isinstance(structure_value, bytes) and self.structure_type and structure_value != b"": if isinstance(self.structure_type, types.LambdaType): @@ -608,7 +606,7 @@ def _to_string(self): def _get_field(self, key): structure_value = self._get_calculated_value(self.value) if isinstance(structure_value, bytes): - raise ValueError("Cannot get field %s when structure is defined as a byte string" % key) + raise ValueError(f"Cannot get field {key} when structure is defined as a byte string") field = structure_value._get_field(key) return field @@ -634,7 +632,7 @@ def __init__(self, size=None, **kwargs): :param kwargs: Any other kwarg to be sent to Field() """ if not (size is None or size == 8): - raise InvalidFieldDefinition("DateTimeField type must have a size of 8 not %d" % size) + raise InvalidFieldDefinition(f"DateTimeField type must have a size of 8 not {size}") super().__init__(size=8, **kwargs) def _pack_value(self, value): @@ -644,8 +642,7 @@ def _pack_value(self, value): epoch_time_ms = td.microseconds + (td.seconds + td.days * 24 * 3600) * 10**6 ns100 = self.EPOCH_FILETIME + (epoch_time_ms * 10) - format = self._get_struct_format(8) - struct_string = "%s%s" % ("<" if self.little_endian else ">", format) + struct_string = self._endian_prefix + self._get_struct_format(8) bytes_value = struct.pack(struct_string, ns100) return bytes_value @@ -656,8 +653,7 @@ def _parse_value(self, value): elif isinstance(value, types.LambdaType): datetime_value = value elif isinstance(value, bytes): - format = self._get_struct_format(8) - struct_string = "%s%s" % ("<" if self.little_endian else ">", format) + struct_string = self._endian_prefix + self._get_struct_format(8) int_value = struct.unpack(struct_string, value)[0] return self._parse_value(int_value) # just parse the value again elif isinstance(value, int): @@ -671,9 +667,7 @@ def _parse_value(self, value): elif isinstance(value, datetime.datetime): datetime_value = value else: - raise TypeError( - "Cannot parse value for field %s of type %s to a datetime" % (self.name, type(value).__name__) - ) + raise TypeError(f"Cannot parse value for field {self.name} of type {type(value).__name__} to a datetime") return datetime_value def _get_packed_size(self): @@ -694,7 +688,7 @@ def __init__(self, size=None, **kwargs): :param kwargs: Any other kwarg to be sent to Field() """ if not (size is None or size == 16): - raise InvalidFieldDefinition("UuidField type must have a size of 16 not %d" % size) + raise InvalidFieldDefinition(f"UuidField type must have a size of 16 not {size}") super().__init__(size=16, **kwargs) def _pack_value(self, value): @@ -717,7 +711,7 @@ def _parse_value(self, value): elif isinstance(value, types.LambdaType): uuid_value = value else: - raise TypeError("Cannot parse value for field %s of type %s to a uuid" % (self.name, type(value).__name__)) + raise TypeError(f"Cannot parse value for field {self.name} of type {type(value).__name__} to a uuid") return uuid_value def _get_packed_size(self): @@ -743,7 +737,7 @@ def _parse_value(self, value): break if not valid and int_value != 0 and self.enum_strict: - raise ValueError("Enum value %d does not exist in enum type %s" % (int_value, self.enum_type)) + raise ValueError(f"Enum value {int_value} does not exist in enum type {self.enum_type}") return int_value def _to_string(self): @@ -754,9 +748,9 @@ def _to_string(self): enum_name = enum break if enum_name is None: - return "(%d) UNKNOWN_ENUM" % value + return f"({value}) UNKNOWN_ENUM" else: - return "(%d) %s" % (value, enum_name) + return f"({value}) {enum_name}" class FlagField(IntField): @@ -773,7 +767,7 @@ def set_flag(self, flag): break if not valid and self.flag_strict: - raise ValueError("Flag value does not exist in flag type %s" % self.flag_type) + raise ValueError(f"Flag value does not exist in flag type {self.flag_type}") self.set_value(self.value | flag) def has_flag(self, flag): @@ -786,7 +780,7 @@ def _parse_value(self, value): if isinstance(value, int): current_val &= ~value if current_val != 0 and self.flag_strict: - raise ValueError("Invalid flag for field %s value set %d" % (self.name, current_val)) + raise ValueError(f"Invalid flag for field {self.name} value set {current_val}") return int_value @@ -799,7 +793,7 @@ def _to_string(self): if isinstance(value, int) and self.has_flag(value): flags.append(flag) flags.sort() - return "(%d) %s" % (field_value, ", ".join(flags)) + return f"({field_value}) " + (", ".join(flags)) class BoolField(Field): @@ -811,7 +805,7 @@ def __init__(self, size=1, **kwargs): :param kwargs: Any other kwargs to be sent to Field() """ if size != 1: - raise InvalidFieldDefinition("BoolField size must have a value of 1, not %d" % size) + raise InvalidFieldDefinition(f"BoolField size must have a value of 1, not {size}") super().__init__(size=size, **kwargs) def _pack_value(self, value): @@ -827,7 +821,7 @@ def _parse_value(self, value): elif isinstance(value, types.LambdaType): bool_value = value else: - raise TypeError("Cannot parse value for field %s of type %s to a bool" % (self.name, type(value).__name__)) + raise TypeError(f"Cannot parse value for field {self.name} of type {type(value).__name__} to a bool") return bool_value def _get_packed_size(self): @@ -858,9 +852,7 @@ def _parse_value(self, value): elif isinstance(value, types.LambdaType): text_value = value else: - raise TypeError( - "Cannot parse value for field %s of type %s to a text string" % (self.name, type(value).__name__) - ) + raise TypeError(f"Cannot parse value for field {self.name} of type {type(value).__name__} to a text string") return text_value diff --git a/src/smbprotocol/transport.py b/src/smbprotocol/transport.py index 3ba05b35..052b43a4 100644 --- a/src/smbprotocol/transport.py +++ b/src/smbprotocol/transport.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright: (c) 2019, Jordan Borean (@jborean93) # MIT License (see LICENSE or https://opensource.org/licenses/MIT) @@ -66,7 +65,7 @@ def connect(self): try: self._sock = socket.create_connection((self.server, self.port), timeout=self.timeout) except (OSError, socket.gaierror) as err: - raise ValueError("Failed to connect to '%s:%s': %s" % (self.server, self.port, str(err))) from err + raise ValueError(f"Failed to connect to '{self.server}:{self.port}'") from err self._sock.settimeout(None) # Make sure the socket is in blocking mode. self.connected = True @@ -79,7 +78,7 @@ def close(self): # which returns b'' meaning it was closed. try: self._sock.shutdown(socket.SHUT_RDWR) - except socket.error as e: # pragma: no cover + except OSError as e: # pragma: no cover # Avoid collecting coverage here to avoid CI failing due to race condition differences if e.errno != errno.ENOTCONN: raise @@ -98,8 +97,7 @@ def send(self, header): data_length = len(b_msg) if data_length > self.MAX_SIZE: raise ValueError( - "Data to be sent over Direct TCP size %d exceeds the max length allowed %d" - % (data_length, self.MAX_SIZE) + f"Data to be sent over Direct TCP size {data_length} exceeds the max length allowed {self.MAX_SIZE}" ) tcp_packet = DirectTCPPacket() @@ -127,7 +125,7 @@ def _recv(self, length, timeout): offset = 0 while offset < length: read_len = length - offset - log.debug("Socket recv(%s) (total %s)" % (read_len, length)) + log.debug(f"Socket recv({read_len}) (total {length})") start_time = timeit.default_timer() @@ -144,7 +142,7 @@ def _recv(self, length, timeout): try: b_data = self._sock.recv(read_len) - except socket.error as e: + 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]: @@ -153,7 +151,7 @@ def _recv(self, length, timeout): b_data = b"" read_len = len(b_data) - log.debug("Socket recv() returned %s bytes (total %s)" % (read_len, length)) + log.debug(f"Socket recv() returned {read_len} bytes (total {length})") if read_len == 0: self.close() diff --git a/src/smbprotocol/tree.py b/src/smbprotocol/tree.py index 94f3e37d..7383aeb9 100644 --- a/src/smbprotocol/tree.py +++ b/src/smbprotocol/tree.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright: (c) 2019, Jordan Borean (@jborean93) # MIT License (see LICENSE or https://opensource.org/licenses/MIT) @@ -236,16 +235,16 @@ def connect(self, require_secure_negotiate=True): verify the negotiation parameters with the server to prevent SMB downgrade attacks """ - log.info("Session: %s - Creating connection to share %s" % (self.session.username, self.share_name)) + log.info(f"Session: {self.session.username} - Creating connection to share {self.share_name}") utf_share_name = self.share_name.encode("utf-16-le") connect = SMB2TreeConnectRequest() connect["buffer"] = utf_share_name - log.info("Session: %s - Sending Tree Connect message" % self.session.username) + log.info("Session: %s - Sending Tree Connect message", self.session.username) log.debug(connect) request = self.session.connection.send(connect, sid=self.session.session_id) - log.info("Session: %s - Receiving Tree Connect response" % self.session.username) + log.info("Session: %s - Receiving Tree Connect response", self.session.username) response = self.session.connection.receive(request) tree_response = SMB2TreeConnectResponse() tree_response.unpack(response["data"].get_value()) @@ -253,7 +252,7 @@ def connect(self, require_secure_negotiate=True): # https://msdn.microsoft.com/en-us/library/cc246687.aspx self.tree_connect_id = response["tree_id"].get_value() - log.info("Session: %s - Created tree connection with ID %d" % (self.session.username, self.tree_connect_id)) + log.info("Session: %s - Created tree connection with ID %d", self.session.username, self.tree_connect_id) self._connected = True self.session.tree_connect_table[self.tree_connect_id] = self @@ -277,16 +276,14 @@ def disconnect(self): if not self._connected: return - log.info("Session: %s, Tree: %s - Disconnecting from Tree Connect" % (self.session.username, self.share_name)) + log.info(f"Session: {self.session.username}, Tree: {self.share_name} - Disconnecting from Tree Connect") req = SMB2TreeDisconnect() - log.info("Session: %s, Tree: %s - Sending Tree Disconnect message" % (self.session.username, self.share_name)) + log.info(f"Session: {self.session.username}, Tree: {self.share_name} - Sending Tree Disconnect message") log.debug(req) request = self.session.connection.send(req, sid=self.session.session_id, tid=self.tree_connect_id) - log.info( - "Session: %s, Tree: %s - Receiving Tree Disconnect response" % (self.session.username, self.share_name) - ) + log.info(f"Session: {self.session.username}, Tree: {self.share_name} - Receiving Tree Disconnect response") res = self.session.connection.receive(request) res_disconnect = SMB2TreeDisconnect() res_disconnect.unpack(res["data"].get_value()) @@ -295,8 +292,8 @@ def disconnect(self): del self.session.tree_connect_table[self.tree_connect_id] def _verify_dialect_negotiate(self): - log_header = "Session: %s, Tree: %s" % (self.session.username, self.share_name) - log.info("%s - Running secure negotiate process" % log_header) + log_header = f"Session: {self.session.username}, Tree: {self.share_name}" + log.info("%s - Running secure negotiate process", log_header) if not self.session.signing_key: # This will only happen if we authenticated with the guest or anonymous user. @@ -324,13 +321,13 @@ def _verify_dialect_negotiate(self): ioctl_request["buffer"] = val_neg ioctl_request["max_output_response"] = len(val_neg) ioctl_request["flags"] = IOCTLFlags.SMB2_0_IOCTL_IS_FSCTL - log.info("%s - Sending Secure Negotiate Validation message" % log_header) + log.info("%s - Sending Secure Negotiate Validation message", log_header) log.debug(ioctl_request) request = self.session.connection.send( ioctl_request, sid=self.session.session_id, tid=self.tree_connect_id, force_signature=True ) - log.info("%s - Receiving secure negotiation response" % log_header) + log.info("%s - Receiving secure negotiation response", log_header) try: response = self.session.connection.receive(request) @@ -349,7 +346,7 @@ def _verify_dialect_negotiate(self): ioctl_resp.unpack(response["data"].get_value()) log.debug(ioctl_resp) - log.info("%s - Unpacking secure negotiate response info" % log_header) + log.info("%s - Unpacking secure negotiate response info", log_header) val_resp = SMB2ValidateNegotiateInfoResponse() val_resp.unpack(ioctl_resp["buffer"].get_value()) log.debug(val_resp) @@ -364,12 +361,11 @@ def _verify_dialect_negotiate(self): "server security mode", val_resp["security_mode"].get_value(), self.session.connection.server_security_mode ) self._verify("server dialect", val_resp["dialect"].get_value(), self.session.connection.dialect) - log.info("Session: %d, Tree: %d - Secure negotiate complete" % (self.session.session_id, self.tree_connect_id)) + log.info("Session: %d, Tree: %d - Secure negotiate complete", self.session.session_id, self.tree_connect_id) def _verify(self, check, actual, expected): - log_header = "Session: %d, Tree: %d" % (self.session.session_id, self.tree_connect_id) if actual != expected: + log_header = f"Session: {self.session.session_id}, Tree: {self.tree_connect_id}" raise SMBException( - "%s - Secure negotiate failed to verify %s, " - "Actual: %s, Expected: %s" % (log_header, check, actual, expected) + f"{log_header} - Secure negotiate failed to verify {check}, Actual: {actual}, Expected: {expected}", ) diff --git a/tests/__init__.py b/tests/__init__.py index b6f1b33a..a687ba1a 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -1,3 +1,2 @@ -# -*- coding: utf-8 -*- # Copyright: (c) 2019, Jordan Borean (@jborean93) # MIT License (see LICENSE or https://opensource.org/licenses/MIT) diff --git a/tests/conftest.py b/tests/conftest.py index ae47c8d2..ffa2f34b 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright: (c) 2019, Jordan Borean (@jborean93) # MIT License (see LICENSE or https://opensource.org/licenses/MIT) @@ -167,8 +166,8 @@ def smb_real(): share = os.environ.get("SMB_SHARE", "share") if server: - share = r"\\%s\%s" % (server, share) - encrypted_share = "%s-encrypted" % share + share = rf"\\{server}\{share}" + encrypted_share = f"{share}-encrypted" return username, password, server, int(port), share, encrypted_share else: pytest.skip("The SMB_SHARE env var was not set, integration tests will be skipped") @@ -183,7 +182,8 @@ def smb_real(): ) def smb_share(request, smb_real): # Use some non ASCII chars to test out edge cases by default. - share_path = "%s\\%s" % (smb_real[request.param[1]], "Pýtæs†-[%s] 💩" % time.time()) + test_folder = f"Pýtæs†-[{time.time()}] 💩" + share_path = rf"{smb_real[request.param[1]]}\{test_folder}" delete_session(smb_real[2]) # Test out forward slashes also work with the share-encrypted test @@ -206,14 +206,14 @@ def smb_share(request, smb_real): ids=["dfs-root", "dfs-single-target", "dfs-broken-target"], ) def smb_dfs_share(request, smb_real): - test_folder = "Pýtæs†-[%s] 💩" % time.time() + test_folder = f"Pýtæs†-[{time.time()}] 💩" if request.param[1]: - target_share_path = "%s\\%s" % (smb_real[request.param[1]], test_folder) - dfs_path = "\\\\%s\\dfs\\%s\\%s" % (smb_real[2], request.param[0], test_folder) + target_share_path = rf"{smb_real[request.param[1]]}\{test_folder}" + dfs_path = rf"\\{smb_real[2]}\dfs\{request.param[0]}\{test_folder}" else: - target_share_path = "\\\\%s\\dfs\\%s" % (smb_real[2], test_folder) + target_share_path = rf"\\{smb_real[2]}\dfs\{test_folder}" dfs_path = target_share_path mkdir(target_share_path, username=smb_real[0], password=smb_real[1], port=smb_real[3]) diff --git a/tests/test_change_notify.py b/tests/test_change_notify.py index 422a5ed7..1ffd0594 100644 --- a/tests/test_change_notify.py +++ b/tests/test_change_notify.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright: (c) 2019, Jordan Borean (@jborean93) # MIT License (see LICENSE or https://opensource.org/licenses/MIT) diff --git a/tests/test_connection.py b/tests/test_connection.py index 67885c3d..644e5d0e 100644 --- a/tests/test_connection.py +++ b/tests/test_connection.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright: (c) 2019, Jordan Borean (@jborean93) # MIT License (see LICENSE or https://opensource.org/licenses/MIT) diff --git a/tests/test_create_contexts.py b/tests/test_create_contexts.py index 70e0745f..a95e5d1a 100644 --- a/tests/test_create_contexts.py +++ b/tests/test_create_contexts.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright: (c) 2019, Jordan Borean (@jborean93) # MIT License (see LICENSE or https://opensource.org/licenses/MIT) @@ -59,11 +58,11 @@ class TestSMB2CreateContextName: def test_create_message(self): ea_buffer1 = SMB2CreateEABuffer() ea_buffer1["ea_name"] = "Authors\x00".encode("ascii") - ea_buffer1["ea_value"] = "Jordan Borean".encode("utf-8") + ea_buffer1["ea_value"] = b"Jordan Borean" ea_buffer2 = SMB2CreateEABuffer() ea_buffer2["ea_name"] = "Title\x00".encode("ascii") - ea_buffer2["ea_value"] = "Jordan Borean Title".encode("utf-8") + ea_buffer2["ea_value"] = b"Jordan Borean Title" ea_buffers = SMB2CreateContextRequest() ea_buffers["buffer_name"] = CreateContextName.SMB2_CREATE_EA_BUFFER diff --git a/tests/test_dfs.py b/tests/test_dfs.py index 9479a03f..1476130a 100644 --- a/tests/test_dfs.py +++ b/tests/test_dfs.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright: (c) 2019, Jordan Borean (@jborean93) # MIT License (see LICENSE or https://opensource.org/licenses/MIT) diff --git a/tests/test_exceptions.py b/tests/test_exceptions.py index 1f4551fb..f4795b6b 100644 --- a/tests/test_exceptions.py +++ b/tests/test_exceptions.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- -# Copyright: (c) 2019, Jordan Borean# -*- coding: utf-8 -*- (@jborean93) # MIT License (see LICENSE or https://opensource.org/licenses/MIT) import re diff --git a/tests/test_file_info.py b/tests/test_file_info.py index 3cb3d3c5..ce5535cc 100644 --- a/tests/test_file_info.py +++ b/tests/test_file_info.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright: (c) 2019, Jordan Borean (@jborean93) # MIT License (see LICENSE or https://opensource.org/licenses/MIT) diff --git a/tests/test_header.py b/tests/test_header.py index 51cb4864..1175c8b0 100644 --- a/tests/test_header.py +++ b/tests/test_header.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright: (c) 2020, Jordan Borean (@jborean93) # MIT License (see LICENSE or https://opensource.org/licenses/MIT) diff --git a/tests/test_ioctl.py b/tests/test_ioctl.py index 8e8fca33..7f94ee34 100644 --- a/tests/test_ioctl.py +++ b/tests/test_ioctl.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright: (c) 2019, Jordan Borean (@jborean93) # MIT License (see LICENSE or https://opensource.org/licenses/MIT) diff --git a/tests/test_open.py b/tests/test_open.py index d9f596cf..86d2c1d0 100644 --- a/tests/test_open.py +++ b/tests/test_open.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright: (c) 2019, Jordan Borean (@jborean93) # MIT License (see LICENSE or https://opensource.org/licenses/MIT) diff --git a/tests/test_query_info.py b/tests/test_query_info.py index 2ae9284a..a6e48120 100644 --- a/tests/test_query_info.py +++ b/tests/test_query_info.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright: (c) 2019, Jordan Borean (@jborean93) # MIT License (see LICENSE or https://opensource.org/licenses/MIT) diff --git a/tests/test_reparse_point.py b/tests/test_reparse_point.py index 3b9255e3..97650428 100644 --- a/tests/test_reparse_point.py +++ b/tests/test_reparse_point.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright: (c) 2019, Jordan Borean (@jborean93) # MIT License (see LICENSE or https://opensource.org/licenses/MIT) diff --git a/tests/test_security_descriptor.py b/tests/test_security_descriptor.py index 385918bb..38f1cdfe 100644 --- a/tests/test_security_descriptor.py +++ b/tests/test_security_descriptor.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright: (c) 2019, Jordan Borean (@jborean93) # MIT License (see LICENSE or https://opensource.org/licenses/MIT) diff --git a/tests/test_session.py b/tests/test_session.py index 3ecb177d..5efd6d45 100644 --- a/tests/test_session.py +++ b/tests/test_session.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright: (c) 2019, Jordan Borean (@jborean93) # MIT License (see LICENSE or https://opensource.org/licenses/MIT) diff --git a/tests/test_smbclient_os.py b/tests/test_smbclient_os.py index 37a3493c..da91c20a 100644 --- a/tests/test_smbclient_os.py +++ b/tests/test_smbclient_os.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright: (c) 2019, Jordan Borean (@jborean93) # MIT License (see LICENSE or https://opensource.org/licenses/MIT) @@ -283,7 +282,7 @@ def test_listdir(dirname, smb_share): def test_listdir_with_pattern(smb_share): for filename in ["file.txt", "file-test1.txt", "file-test1a.txt"]: - with smbclient.open_file("%s\\%s" % (smb_share, filename), mode="w") as fd: + with smbclient.open_file(rf"{smb_share}\{filename}", mode="w") as fd: fd.write("content") actual = smbclient.listdir(smb_share, search_pattern="file-test*.txt") @@ -430,7 +429,7 @@ def test_makedirs_file_as_parent(smb_share): def test_read_text_file(smb_share): - file_path = "%s\\%s" % (smb_share, "file.txt") + file_path = rf"{smb_share}\file.txt" file_contents = "File Contents\nNewline" expected = "[NtStatus 0xc0000034] No such file or directory" @@ -471,7 +470,7 @@ def test_read_text_file(smb_share): def test_read_byte_file(smb_share): - file_path = "%s\\%s" % (smb_share, "file.txt") + file_path = rf"{smb_share}\file.txt" file_contents = b"\x00\x01\x02\x03" expected = "[NtStatus 0xc0000034] No such file or directory" @@ -502,7 +501,7 @@ def test_read_byte_file(smb_share): def test_write_text_file(smb_share): - file_path = "%s\\%s" % (smb_share, "file.txt") + file_path = rf"{smb_share}\file.txt" file_contents = "File Contents\nNewline" with smbclient.open_file(file_path, mode="w") as fd: @@ -531,7 +530,7 @@ def test_write_text_file(smb_share): def test_write_byte_file(smb_share): - file_path = "%s\\%s" % (smb_share, "file.txt") + file_path = rf"{smb_share}\file.txt" file_contents = b"File Contents\nNewline" with smbclient.open_file(file_path, mode="wb") as fd: @@ -562,7 +561,7 @@ def test_write_byte_file(smb_share): # https://github.com/jborean93/smbprotocol/issues/20 def test_read_large_text_file(smb_share): - file_path = "%s\\%s" % (smb_share, "file.txt") + file_path = rf"{smb_share}\file.txt" file_contents = "a" * 131074 with smbclient.open_file(file_path, mode="w") as fd: @@ -574,7 +573,7 @@ def test_read_large_text_file(smb_share): def test_write_exclusive_text_file(smb_share): - file_path = "%s\\%s" % (smb_share, "file.txt") + file_path = rf"{smb_share}\file.txt" file_contents = "File Contents\nNewline" with smbclient.open_file(file_path, mode="x") as fd: @@ -600,7 +599,7 @@ def test_write_exclusive_text_file(smb_share): def test_write_exclusive_byte_file(smb_share): - file_path = "%s\\%s" % (smb_share, "file.txt") + file_path = rf"{smb_share}\file.txt" file_contents = b"File Contents\nNewline" with smbclient.open_file(file_path, mode="xb") as fd: @@ -626,7 +625,7 @@ def test_write_exclusive_byte_file(smb_share): def test_append_text_file(smb_share): - file_path = "%s\\%s" % (smb_share, "file.txt") + file_path = rf"{smb_share}\file.txt" with smbclient.open_file(file_path, mode="a") as fd: assert isinstance(fd, io.TextIOWrapper) @@ -647,7 +646,7 @@ def test_append_text_file(smb_share): def test_append_byte_file(smb_share): - file_path = "%s\\%s" % (smb_share, "file.txt") + file_path = rf"{smb_share}\file.txt" with smbclient.open_file(file_path, mode="ab") as fd: assert isinstance(fd, io.BufferedWriter) @@ -668,7 +667,7 @@ def test_append_byte_file(smb_share): def test_read_write_text_file(smb_share): - file_path = "%s\\%s" % (smb_share, "file.txt") + file_path = rf"{smb_share}\file.txt" with smbclient.open_file(file_path, mode="w+") as fd: fd.write("abc") @@ -679,7 +678,7 @@ def test_read_write_text_file(smb_share): def test_read_write_byte_file(smb_share): - file_path = "%s\\%s" % (smb_share, "file.txt") + file_path = rf"{smb_share}\file.txt" with smbclient.open_file(file_path, mode="bw+") as fd: fd.write(b"abc") @@ -690,7 +689,7 @@ def test_read_write_byte_file(smb_share): def test_open_directory_fail(smb_share): - dir_path = "%s\\%s" % (smb_share, "dir") + dir_path = rf"{smb_share}\dir" smbclient.mkdir(dir_path) with pytest.raises(OSError, match=re.escape("[NtStatus 0xc00000ba] Is a directory: ")): @@ -709,14 +708,14 @@ def test_open_directory_with_correct_file_type(smb_share): def test_open_file_in_missing_dir(smb_share): - file_path = "%s\\dir\\%s" % (smb_share, "file.txt") + file_path = rf"{smb_share}\dir\file.txt" with pytest.raises(OSError, match=re.escape("[NtStatus 0xc000003a] No such file or directory: ")): smbclient.open_file(file_path) def test_open_file_with_read_share_access(smb_share): - file_path = "%s\\%s" % (smb_share, "file.txt") + file_path = rf"{smb_share}\file.txt" with smbclient.open_file(file_path, mode="w") as fd: fd.write("contents") @@ -738,7 +737,7 @@ def test_open_file_with_read_share_access(smb_share): def test_open_file_with_write_share_access(smb_share): - file_path = "%s\\%s" % (smb_share, "file.txt") + file_path = rf"{smb_share}\file.txt" with smbclient.open_file(file_path, mode="w") as fd: expected = ( @@ -762,7 +761,7 @@ def test_open_file_with_write_share_access(smb_share): def test_open_file_with_read_write_access(smb_share): - file_path = "%s\\%s" % (smb_share, "file.txt") + file_path = rf"{smb_share}\file.txt" with smbclient.open_file(file_path, mode="w", share_access="rw") as fd: fd.write("content") @@ -1262,7 +1261,7 @@ def test_scandir(smb_share): def test_scamdir_with_pattern(smb_share): for filename in ["file.txt", "file-test1.txt", "file-test1a.txt"]: - with smbclient.open_file("%s\\%s" % (smb_share, filename), mode="w") as fd: + with smbclient.open_file(rf"{smb_share}\{filename}", mode="w") as fd: fd.write("content") count = 0 @@ -1326,7 +1325,9 @@ def test_scandir_with_broken_symlink(smb_share): def test_scandir_with_cache(smb_real): - share_path = "%s\\%s" % (smb_real[4], "Pýtæs†-[%s] 💩" % time.time()) + share = smb_real[4] + test_folder = f"Pýtæs†-[{time.time()}] 💩" + share_path = rf"{share}\{test_folder}" cache = {} smbclient.mkdir(share_path, username=smb_real[0], password=smb_real[1], port=smb_real[3], connection_cache=cache) @@ -1840,7 +1841,7 @@ def test_walk_topdown(smb_share): smbclient.makedirs("%s\\dir1\\dir2\\dir3" % smb_share) for name in ["file1.txt", "dir1\\file2.txt", "dir1\\dir2\\file3.txt", "dir1\\dir2\\dir3\\file4.txt"]: - with smbclient.open_file("%s\\%s" % (smb_share, name), mode="w") as fd: + with smbclient.open_file(rf"{smb_share}\{name}", mode="w") as fd: fd.write("content") scanned_files = [] @@ -1861,7 +1862,7 @@ def test_walk_bottomup(smb_share): smbclient.makedirs("%s\\dir1\\dir2\\dir3" % smb_share) for name in ["file1.txt", "dir1\\file2.txt", "dir1\\dir2\\file3.txt", "dir1\\dir2\\dir3\\file4.txt"]: - with smbclient.open_file("%s\\%s" % (smb_share, name), mode="w") as fd: + with smbclient.open_file(rf"{smb_share}\{name}", mode="w") as fd: fd.write("content") scanned_files = [] diff --git a/tests/test_smbclient_path.py b/tests/test_smbclient_path.py index 9f22a6a8..edf45ea1 100644 --- a/tests/test_smbclient_path.py +++ b/tests/test_smbclient_path.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright: (c) 2019, Jordan Borean (@jborean93) # MIT License (see LICENSE or https://opensource.org/licenses/MIT) diff --git a/tests/test_smbclient_pool.py b/tests/test_smbclient_pool.py index eaeaed37..02c5e489 100644 --- a/tests/test_smbclient_pool.py +++ b/tests/test_smbclient_pool.py @@ -1,7 +1,8 @@ -# -*- coding: utf-8 -*- # Copyright: (c) 2020, Jordan Borean (@jborean93) # MIT License (see LICENSE or https://opensource.org/licenses/MIT) +import logging + import pytest import smbclient._io as io @@ -89,16 +90,14 @@ def test_reset_connection_error_fail(mocker): pool.reset_connection_cache(connection_cache={"conn": connection_mock}) -def test_reset_connection_error_warning(monkeypatch, mocker): +def test_reset_connection_error_warning(mocker, caplog): connection_mock = mocker.MagicMock() connection_mock.disconnect.side_effect = Exception("exception") - warning_mock = mocker.MagicMock() - monkeypatch.setattr(pool.warnings, "warn", warning_mock) - pool.reset_connection_cache(fail_on_error=False, connection_cache={"conn": connection_mock}) + with caplog.at_level(logging.WARNING): + pool.reset_connection_cache(fail_on_error=False, connection_cache={"conn": connection_mock}) - assert warning_mock.call_count == 1 - assert warning_mock.call_args[0][0] == "Failed to close connection conn: exception" + assert "Failed to close connection conn" in caplog.text def test_dfs_referral_no_links_no_domain(reset_config, monkeypatch, mocker): @@ -134,7 +133,7 @@ def test_dfs_referral_no_links_from_domain(reset_config, monkeypatch, mocker): config.domain_controller = DOMAIN_NAME with pytest.raises(ObjectPathNotFound): - actual_get_smb_tree(f"\\\\{DOMAIN_NAME}\\dfs") + actual_get_smb_tree(rf"\\{DOMAIN_NAME}\dfs") def test_resolve_dfs_referral_no_links(reset_config, monkeypatch, mocker): diff --git a/tests/test_smbclient_shutil.py b/tests/test_smbclient_shutil.py index 5b8fd56a..36258ffa 100644 --- a/tests/test_smbclient_shutil.py +++ b/tests/test_smbclient_shutil.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright: (c) 2019, Jordan Borean (@jborean93) # MIT License (see LICENSE or https://opensource.org/licenses/MIT) @@ -109,7 +108,7 @@ def test_copy_from_local(smb_share, tmp_path): ctypes.windll.kernel32.SetFileTime(handle, ref_time, ref_time, ref_time) ctypes.windll.kernel32.CloseHandle(handle) - dst_filename = "{}\\target.txt".format(smb_share) + dst_filename = f"{smb_share}\\target.txt" copy_from_to(str(src_filename), dst_filename) diff --git a/tests/test_structure.py b/tests/test_structure.py index 47f54637..f262778a 100644 --- a/tests/test_structure.py +++ b/tests/test_structure.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright: (c) 2019, Jordan Borean (@jborean93) # MIT License (see LICENSE or https://opensource.org/licenses/MIT) diff --git a/tests/test_text.py b/tests/test_text.py index 87edb6be..232178de 100644 --- a/tests/test_text.py +++ b/tests/test_text.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright: (c) 2019, Jordan Borean (@jborean93) # MIT License (see LICENSE or https://opensource.org/licenses/MIT) diff --git a/tests/test_transport.py b/tests/test_transport.py index 5fa89000..960350ca 100644 --- a/tests/test_transport.py +++ b/tests/test_transport.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright: (c) 2019, Jordan Borean (@jborean93) # MIT License (see LICENSE or https://opensource.org/licenses/MIT) @@ -74,7 +73,7 @@ def test_normal_fail_message_too_big(self): def test_invalid_host(self): tcp = Tcp("fake-host", 445) - with pytest.raises(ValueError, match=re.escape("Failed to connect to 'fake-host:445': ")): + with pytest.raises(ValueError, match=re.escape("Failed to connect to 'fake-host:445'")): tcp.connect() diff --git a/tests/test_tree.py b/tests/test_tree.py index f2a53ec4..92206530 100644 --- a/tests/test_tree.py +++ b/tests/test_tree.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright: (c) 2019, Jordan Borean (@jborean93) # MIT License (see LICENSE or https://opensource.org/licenses/MIT)