Skip to content

Commit

Permalink
Fix rename operations for a DFS path (#191)
Browse files Browse the repository at this point in the history
  • Loading branch information
jborean93 authored Aug 23, 2022
1 parent 08b7dcf commit dabafb9
Show file tree
Hide file tree
Showing 4 changed files with 20 additions and 15 deletions.
12 changes: 0 additions & 12 deletions src/smbclient/_io.py
Original file line number Diff line number Diff line change
Expand Up @@ -352,18 +352,6 @@ def __init__(
):
tree, fd_path = get_smb_tree(path, **kwargs)

# When opening a file on a DFS tree the raw path used in the CREATE
# request is the the original DFS path as the server should normalise
# it and return STATUS_PATH_NOT_COVERED if it's served by a DFS target
# server. The fd_path returned by get_smb_tree is still kept as it's
# needed for rename operations that need the tree relative path to
# rename files/dirs to.
# https://github.com/jborean93/smbprotocol/issues/170
# https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/448cb979-7321-4598-89df-e5c97135b566
self._fd_path = fd_path
if tree.is_dfs_share:
fd_path = "\\".join(p for p in path.split("\\") if p)

self.share_access = share_access
self.fd = Open(tree, fd_path)
self._mode = mode
Expand Down
10 changes: 9 additions & 1 deletion src/smbclient/_os.py
Original file line number Diff line number Diff line change
Expand Up @@ -1128,10 +1128,18 @@ def _rename_information(src, dst, replace_if_exists=False, **kwargs):
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)

dst_tree = dst_raw.fd.tree_connect
dst_path = dst_raw.fd.file_name
if dst_tree.is_dfs_share and dst_path.startswith(dst_tree.share_name[2:]):
# Special handling when dst is on a DFS share, the renamed file
# should not include the DFS share itself that is present on the
# Open.file_name. Strip out that prefix if present.
dst_path = dst_path[len(dst_tree.share_name) - 1 :]

with SMBFileTransaction(src_raw) as transaction:
file_rename = FileRenameInformation()
file_rename["replace_if_exists"] = replace_if_exists
file_rename["file_name"] = to_text(dst_raw._fd_path)
file_rename["file_name"] = to_text(dst_path)
set_info(transaction, file_rename)


Expand Down
11 changes: 10 additions & 1 deletion src/smbclient/_pool.py
Original file line number Diff line number Diff line change
Expand Up @@ -329,8 +329,17 @@ def get_smb_tree(

return get_smb_tree(path, **get_kwargs)

# When opening a file on a DFS tree the raw path used in the CREATE
# request is the the original DFS path as the server should normalise
# it and return STATUS_PATH_NOT_COVERED if it's served by a DFS target
# server.
# https://github.com/jborean93/smbprotocol/issues/170
# https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/448cb979-7321-4598-89df-e5c97135b566
file_path = ""
if len(path_split) > 2:
if tree.is_dfs_share:
file_path = "\\".join(path_split)

elif len(path_split) > 2:
file_path = "\\".join(path_split[2:])

return tree, file_path
Expand Down
2 changes: 1 addition & 1 deletion src/smbprotocol/connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -1247,7 +1247,7 @@ def _send(
header["data"] = message.pack()
header["next_command"] = next_command

if is_dfs and message.COMMAND == Commands.SMB2_CREATE:
if is_dfs:
header["flags"].set_flag(Smb2Flags.SMB2_FLAGS_DFS_OPERATIONS)

if i != 0 and related:
Expand Down

0 comments on commit dabafb9

Please sign in to comment.