From 436686bf0f21c74f18e79167a42a45c2215cc0fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Schoentgen?= Date: Wed, 26 May 2021 17:11:07 +0200 Subject: [PATCH] Windows legacy: fix handling of UNC names MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The legacy implementation was not handling UNC names properly: Traceback (most recent call last): File "check.py", line 6, in send2trash(str(file)) File "\...\plat_win_legacy.py", line 79, in send2trash paths = [get_short_path_name(path) for path in paths] File "\...\plat_win_legacy.py", line 79, in paths = [get_short_path_name(path) for path in paths] File "\...\plat_win_legacy.py", line 62, in get_short_path_name raise WindowsError(err_no, FormatError(err_no), long_name[4:]) OSError: [Errno 123] La syntaxe du nom de fichier, de répertoire ou de volume est incorrecte.: '\\\\SERVER\\folder\\file.txt' --- send2trash/plat_win_legacy.py | 47 ++++++++++++++++++++++++++++++----- 1 file changed, 41 insertions(+), 6 deletions(-) diff --git a/send2trash/plat_win_legacy.py b/send2trash/plat_win_legacy.py index e8955b8..4a35ad7 100644 --- a/send2trash/plat_win_legacy.py +++ b/send2trash/plat_win_legacy.py @@ -51,18 +51,53 @@ FOF_ALLOWUNDO = 64 FOF_NOERRORUI = 1024 +def prefix_and_path(path): + r"""Guess the long-path prefix based on the kind of *path*. + Local paths (C:\folder\file.ext) and UNC names (\\server\folder\file.ext) + are handled. + + Return a tuple of the long-path prefix and the prefixed path. + """ + prefix, long_path = "\\\\?\\", path + + if not path.startswith(prefix): + if path.startswith("\\\\"): + # Likely a UNC name + prefix = "\\\\?\\UNC" + long_path = prefix + path[1:] + else: + # Likely a local path + long_path = prefix + path + elif path.startswith(prefix + "UNC\\"): + # UNC name with long-path prefix + prefix = "\\\\?\\UNC" + + return prefix, long_path + + +def get_awaited_path_from_prefix(prefix, path): + """Guess the correct path to pass to the SHFileOperationW() call. + The long-path prefix must be removed, so we should take care of + different long-path prefixes. + """ + if prefix == "\\\\?\\UNC": + # We need to prepend a backslash for UNC names, as it was removed + # in prefix_and_path(). + return "\\" + path[len(prefix) :] + return path[len(prefix) :] + + def get_short_path_name(long_name): - if not long_name.startswith("\\\\?\\"): - long_name = "\\\\?\\" + long_name - buf_size = GetShortPathNameW(long_name, None, 0) + prefix, long_path = prefix_and_path(long_name) + buf_size = GetShortPathNameW(long_path, None, 0) # FIX: https://github.com/hsoft/send2trash/issues/31 # If buffer size is zero, an error has occurred. if not buf_size: err_no = GetLastError() - raise WindowsError(err_no, FormatError(err_no), long_name[4:]) + raise WindowsError(err_no, FormatError(err_no), long_path) output = create_unicode_buffer(buf_size) - GetShortPathNameW(long_name, output, buf_size) - return output.value[4:] # Remove '\\?\' for SHFileOperationW + GetShortPathNameW(long_path, output, buf_size) + return get_awaited_path_from_prefix(prefix, output.value) def send2trash(paths):