Skip to content

Commit

Permalink
Clean path manually to avoid resolution of symlinks via normpath.
Browse files Browse the repository at this point in the history
  • Loading branch information
LTLA committed Aug 6, 2024
1 parent afd2115 commit 32beb21
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 5 deletions.
29 changes: 29 additions & 0 deletions src/sewerrat/_utils.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import requests
import os


def format_error(res):
Expand All @@ -10,3 +11,31 @@ def format_error(res):
return requests.HTTPError(res.status_code, res.text)
else:
return requests.HTTPError(res.status_code)


def clean_path(path: str) -> str:
# Don't use os.path.abspath, as this calls normpath; you would end up
# resolving symlinks that the user wants to respect, e.g., for mounted
# drives with aliased locations to network shares. Rather, we just do the
# bare minimum required to obtain a clean absolute path, analogous to
# Golang's filepath.Clean().
if not path.startswith('/'):
path = os.getcwd() + "/" + path

components = path.split("/")
keep = []
for comp in components:
if comp == "..":
if len(keep):
keep.pop()
elif comp == "":
# no-op, it's a redundant '//' or we're at the start.
pass
elif comp == ".":
# no-op as well.
pass
else:
keep.append(comp)

keep = [""] + keep # add back the root.
return '/'.join(keep)
2 changes: 1 addition & 1 deletion src/sewerrat/deregister.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ def deregister(path: str, url: str, retry: int = 3, wait: float = 1):
Number of seconds to wait for a file write to synchronise before
requesting verification during each retry.
"""
path = os.path.abspath(path)
path = ut.clean_path(path)
res = requests.post(url + "/deregister/start", json = { "path": path }, allow_redirects=True)
if res.status_code >= 300:
raise ut.format_error(res)
Expand Down
5 changes: 1 addition & 4 deletions src/sewerrat/register.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,7 @@ def register(path: str, names: List[str], url: str, retry: int = 3, wait: int =
if len(names) == 0:
raise ValueError("expected at least one entry in 'names'")

path = os.path.abspath(path)
if url is None:
url = rest_url()

path = ut.clean_path(path)
res = requests.post(url + "/register/start", json = { "path": path }, allow_redirects=True)
if res.status_code >= 300:
raise ut.format_error(res)
Expand Down
25 changes: 25 additions & 0 deletions tests/test_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
from sewerrat import _utils as ut


def test_clean_path():
x = ut.clean_path("foo/bar")
assert x.endswith("/foo/bar")
assert x.startswith("/")

x = ut.clean_path("//absd//a//foo/bar")
assert x == "/absd/a/foo/bar"

x = ut.clean_path("//absd//a//../foo/bar")
assert x == "/absd/foo/bar"

x = ut.clean_path("/xxxx/bbb/../../foo/bar")
assert x == "/foo/bar"

x = ut.clean_path("/../absd")
assert x == "/absd"

x = ut.clean_path("/absd/./bar/./")
assert x == "/absd/bar"

x = ut.clean_path("/a/b/c/d/")
assert x == "/a/b/c/d"

0 comments on commit 32beb21

Please sign in to comment.