aboutsummaryrefslogtreecommitdiffstats
path: root/packages/meshbay-common/src/meshbay_common
diff options
context:
space:
mode:
Diffstat (limited to 'packages/meshbay-common/src/meshbay_common')
-rw-r--r--packages/meshbay-common/src/meshbay_common/paths.py24
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]]: