From 511590976c7846aebb6652df9f35ffeec5364f5c Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Mon, 10 Oct 2022 18:56:19 +0200 Subject: [PATCH] Fix handling of relative paths In particular, 'path:..' got turned into 'path:.' because isRelative() returned a CanonPath, which cannot represent '..'. Reported by @erikarvstedt. --- src/libexpr/flake/flake.cc | 2 +- src/libfetchers/fetchers.cc | 2 +- src/libfetchers/fetchers.hh | 4 ++-- src/libfetchers/path.cc | 4 ++-- src/libutil/canon-path.cc | 1 + 5 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/libexpr/flake/flake.cc b/src/libexpr/flake/flake.cc index e4210c0cf..05fd301e1 100644 --- a/src/libexpr/flake/flake.cc +++ b/src/libexpr/flake/flake.cc @@ -434,7 +434,7 @@ LockedFlake lockFlake( if (auto relativePath = input.ref->input.isRelative()) { SourcePath inputSourcePath { overridenSourcePath.accessor, - *overridenSourcePath.path.parent() + *relativePath + CanonPath(*relativePath, *overridenSourcePath.path.parent()) }; return readFlake(state, *input.ref, *input.ref, *input.ref, inputSourcePath, inputPath); } else diff --git a/src/libfetchers/fetchers.cc b/src/libfetchers/fetchers.cc index 2c958276b..98dcf38e4 100644 --- a/src/libfetchers/fetchers.cc +++ b/src/libfetchers/fetchers.cc @@ -95,7 +95,7 @@ bool Input::isLocked() const return scheme && scheme->isLocked(*this); } -std::optional Input::isRelative() const +std::optional Input::isRelative() const { assert(scheme); return scheme->isRelative(*this); diff --git a/src/libfetchers/fetchers.hh b/src/libfetchers/fetchers.hh index a890a5ef0..c2753da30 100644 --- a/src/libfetchers/fetchers.hh +++ b/src/libfetchers/fetchers.hh @@ -53,7 +53,7 @@ public: /* Only for relative path flakes, i.e. 'path:./foo', returns the relative path, i.e. './foo'. */ - std::optional isRelative() const; + std::optional isRelative() const; bool operator ==(const Input & other) const; @@ -138,7 +138,7 @@ struct InputScheme virtual bool isLocked(const Input & input) const { return false; } - virtual std::optional isRelative(const Input & input) const + virtual std::optional isRelative(const Input & input) const { return std::nullopt; } virtual std::optional getFingerprint(ref store, const Input & input) const; diff --git a/src/libfetchers/path.cc b/src/libfetchers/path.cc index 72596841f..96e34af79 100644 --- a/src/libfetchers/path.cc +++ b/src/libfetchers/path.cc @@ -78,13 +78,13 @@ struct PathInputScheme : InputScheme }; } - std::optional isRelative(const Input & input) const override + std::optional isRelative(const Input & input) const override { auto path = getStrAttr(input.attrs, "path"); if (hasPrefix(path, "/")) return std::nullopt; else - return CanonPath(path); + return path; } bool isLocked(const Input & input) const override diff --git a/src/libutil/canon-path.cc b/src/libutil/canon-path.cc index 79951c933..b132b4262 100644 --- a/src/libutil/canon-path.cc +++ b/src/libutil/canon-path.cc @@ -61,6 +61,7 @@ CanonPath CanonPath::operator + (const CanonPath & x) const void CanonPath::push(std::string_view c) { assert(c.find('/') == c.npos); + assert(c != "." && c != ".."); if (!isRoot()) path += '/'; path += c; }