diff --git a/src/smbclient/_io.py b/src/smbclient/_io.py index 7b063a2..539c40d 100644 --- a/src/smbclient/_io.py +++ b/src/smbclient/_io.py @@ -9,6 +9,7 @@ from smbprotocol import MAX_PAYLOAD_SIZE from smbprotocol.exceptions import ( NoMoreFiles, + NoSuchFile, ObjectNameNotFound, ObjectPathNotFound, PathNotCovered, @@ -651,7 +652,10 @@ def query_directory(self, pattern, info_class): while True: try: entries = self.fd.query_directory(pattern, info_class, flags=query_flags) - except NoMoreFiles: + except (NoMoreFiles, NoSuchFile): + # MS-SMB2 3.3.5.18 lists both as QUERY_DIRECTORY end codes. A server + # returns STATUS_NO_SUCH_FILE when the search pattern matches no files. + # Treat either as end of enumeration. break except (PathNotCovered, ObjectNameNotFound, ObjectPathNotFound): # The MS-DFSC docs state that STATUS_PATH_NOT_COVERED is used when encountering a DFS link to a diff --git a/tests/test_smbclient_os.py b/tests/test_smbclient_os.py index 5ffcdfb..e1387e2 100644 --- a/tests/test_smbclient_os.py +++ b/tests/test_smbclient_os.py @@ -1292,6 +1292,22 @@ def test_scandir_with_pattern(smb_share): assert names == ["file-test1.txt"] +def test_scandir_empty_directory(smb_share): + # Some servers return STATUS_NO_SUCH_FILE here instead of STATUS_NO_MORE_FILES. + empty_dir = rf"{smb_share}\empty" + smbclient.mkdir(empty_dir) + + assert list(smbclient.scandir(empty_dir)) == [] + + +def test_scandir_with_non_matching_pattern(smb_share): + # Samba returns STATUS_NO_SUCH_FILE here instead of STATUS_NO_MORE_FILES. + with smbclient.open_file(rf"{smb_share}\file.txt", mode="w") as fd: + fd.write("x") + + assert list(smbclient.scandir(smb_share, search_pattern="nomatch_*")) == [] + + @pytest.mark.skipif( os.name != "nt" and not os.environ.get("SMB_FORCE", False), reason="cannot create symlinks on Samba" )