Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion src/smbclient/_io.py
Original file line number Diff line number Diff line change
Expand Up @@ -381,7 +381,11 @@ class SMBRawIO(io.RawIOBase):
def __init__(
self, path, mode="r", share_access=None, desired_access=None, file_attributes=None, create_options=0, **kwargs
):
tree, fd_path = get_smb_tree(path, **kwargs)
# get_smb_tree runs outside the SMBFileTransaction layer that normally translates these.
try:
tree, fd_path = get_smb_tree(path, **kwargs)
except SMBResponseException as exc:
raise SMBOSError(exc.status, path) from exc

self.share_access = share_access
self.fd = Open(tree, fd_path)
Expand Down
11 changes: 11 additions & 0 deletions tests/test_smbclient_os.py
Original file line number Diff line number Diff line change
Expand Up @@ -2186,3 +2186,14 @@ def test_dfs_nonexisting_path(smb_dfs_share):

with pytest.raises(SMBOSError):
smbclient.lstat(fake_file)


def test_open_file_missing_share_raises_os_error(smb_real):
# A missing share fails tree connect with STATUS_BAD_NETWORK_NAME, a non-OSError
# that must surface as SMBOSError so except OSError / ignore_errors callers catch it.
bad_path = rf"\\{smb_real[2]}\does_not_exist\file.txt"

with pytest.raises(SMBOSError) as exc_info:
smbclient.open_file(bad_path, username=smb_real[0], password=smb_real[1], port=smb_real[3])

assert exc_info.value.filename == bad_path
21 changes: 20 additions & 1 deletion tests/test_smbclient_pool.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,13 @@
import smbclient._io as io
import smbclient._pool as pool
from smbprotocol.dfs import DFSReferralResponse
from smbprotocol.exceptions import BadNetworkName, InvalidParameter, ObjectPathNotFound
from smbprotocol.exceptions import (
BadNetworkName,
InvalidParameter,
ObjectPathNotFound,
SMBOSError,
)
from smbprotocol.header import NtStatus

from .conftest import DC_REFERRAL, DOMAIN_NAME, DOMAIN_REFERRAL

Expand Down Expand Up @@ -150,3 +156,16 @@ def test_resolve_dfs_referral_no_links(reset_config, monkeypatch, mocker):

with pytest.raises(ObjectPathNotFound):
list(io._resolve_dfs(raw_io))


def test_raw_io_translates_smb_response_to_os_error(mocker):
# Anything escaping get_smb_tree here must surface as OSError so the
# rmtree, remove, rmdir, and scandir error paths route it correctly.
mocker.patch.object(io, "get_smb_tree", side_effect=BadNetworkName())

path = r"\\server\share\missing"
with pytest.raises(SMBOSError) as exc_info:
io.SMBRawIO(path)

assert exc_info.value.ntstatus == NtStatus.STATUS_BAD_NETWORK_NAME
assert exc_info.value.filename == path
Loading