diff options
Diffstat (limited to 'packages/meshbay-common/src/meshbay_common/paths.py')
| -rw-r--r-- | packages/meshbay-common/src/meshbay_common/paths.py | 24 |
1 files changed, 15 insertions, 9 deletions
diff --git a/packages/meshbay-common/src/meshbay_common/paths.py b/packages/meshbay-common/src/meshbay_common/paths.py index 8be4680..059bf09 100644 --- a/packages/meshbay-common/src/meshbay_common/paths.py +++ b/packages/meshbay-common/src/meshbay_common/paths.py @@ -19,7 +19,7 @@ from __future__ import annotations import os import re import unicodedata -from pathlib import Path, PurePath +from pathlib import Path # Windows refuses these as a basename, with or without an extension: `AUX.txt` # is as impossible as `AUX`. A group indexed on Linux can hold them, and a @@ -39,6 +39,9 @@ _RESERVED_CHARS = set('<>:"/\\|?*') | {chr(c) for c in range(32)} | BIDI_CONTROL # Windows without long-path support. A deep media library reaches this. MAX_PATH_WINDOWS = 260 +# Creating a directory is refused twelve characters earlier (room for an 8.3 +# name), and listing one adds `\*`: the extended form starts there. +_EXTENDED_FROM = MAX_PATH_WINDOWS - 12 def nfc(text: str) -> str: @@ -102,19 +105,22 @@ def long_path(path: Path | str) -> str: """ A path string safe to hand to the OS. - On Windows, prefix with `\\\\?\\` so `MAX_PATH` does not truncate a deep - library. The prefix requires an absolute, already-normalized path, and it is - a no-op everywhere else. + On Windows, a path that reaches `MAX_PATH` is refused by every call unless + the system's `LongPathsEnabled` is set, which it is not by default and which + a program cannot set for itself. The extended form (`\\\\?\\`) is accepted + whatever the setting, so a long path gets it. The form skips the system's + normalisation, so the path is normalised here first. A no-op everywhere + else, and for a path short enough to need nothing. """ text = str(path) if os.name != "nt" or text.startswith("\\\\?\\"): return text - resolved = str(PurePath(text)) - if len(resolved) < MAX_PATH_WINDOWS and not text.startswith("\\\\"): + full = os.path.normpath(text) if os.path.isabs(text) else os.path.abspath(text) + if len(full) < _EXTENDED_FROM: return text - if text.startswith("\\\\"): # UNC: \\server\share → \\?\UNC\server\share - return "\\\\?\\UNC" + text[1:] - return "\\\\?\\" + text + if full.startswith("\\\\"): # UNC: \\server\share → \\?\UNC\server\share + return "\\\\?\\UNC" + full[1:] + return "\\\\?\\" + full def find_fold_collisions(names: list[str]) -> dict[str, list[str]]: |