Add CanonPath::makeRelative()

This commit is contained in:
Eelco Dolstra 2023-03-30 15:48:39 +02:00
parent 1829e7ccac
commit 7ebaf0252a
3 changed files with 44 additions and 0 deletions

View file

@ -100,4 +100,30 @@ std::ostream & operator << (std::ostream & stream, const CanonPath & path)
return stream; return stream;
} }
std::string CanonPath::makeRelative(const CanonPath & path) const
{
auto p1 = begin();
auto p2 = path.begin();
for (; p1 != end() && p2 != path.end() && *p1 == *p2; ++p1, ++p2) ;
if (p1 == end() && p2 == path.end())
return ".";
else if (p1 == end())
return std::string(p2.remaining);
else {
std::string res;
while (p1 != end()) {
++p1;
if (!res.empty()) res += '/';
res += "..";
}
if (p2 != path.end()) {
if (!res.empty()) res += '/';
res += p2.remaining;
}
return res;
}
}
} }

View file

@ -85,6 +85,9 @@ public:
bool operator != (const Iterator & x) const bool operator != (const Iterator & x) const
{ return remaining.data() != x.remaining.data(); } { return remaining.data() != x.remaining.data(); }
bool operator == (const Iterator & x) const
{ return !(*this != x); }
const std::string_view operator * () const const std::string_view operator * () const
{ return remaining.substr(0, slash); } { return remaining.substr(0, slash); }
@ -166,6 +169,10 @@ public:
the `allowed` paths are within `this`. (The latter condition the `allowed` paths are within `this`. (The latter condition
ensures access to the parents of allowed paths.) */ ensures access to the parents of allowed paths.) */
bool isAllowed(const std::set<CanonPath> & allowed) const; bool isAllowed(const std::set<CanonPath> & allowed) const;
/* Return a representation `x` of `path` relative to `this`, i.e.
`CanonPath(this.makeRelative(x), this) == path`. */
std::string makeRelative(const CanonPath & path) const;
}; };
std::ostream & operator << (std::ostream & stream, const CanonPath & path); std::ostream & operator << (std::ostream & stream, const CanonPath & path);

View file

@ -152,4 +152,15 @@ namespace nix {
ASSERT_TRUE (CanonPath("/").isAllowed(allowed)); ASSERT_TRUE (CanonPath("/").isAllowed(allowed));
} }
} }
TEST(CanonPath, makeRelative) {
CanonPath d("/foo/bar");
ASSERT_EQ(d.makeRelative(CanonPath("/foo/bar")), ".");
ASSERT_EQ(d.makeRelative(CanonPath("/foo")), "..");
ASSERT_EQ(d.makeRelative(CanonPath("/")), "../..");
ASSERT_EQ(d.makeRelative(CanonPath("/foo/bar/xyzzy")), "xyzzy");
ASSERT_EQ(d.makeRelative(CanonPath("/foo/bar/xyzzy/bla")), "xyzzy/bla");
ASSERT_EQ(d.makeRelative(CanonPath("/foo/xyzzy/bla")), "../xyzzy/bla");
ASSERT_EQ(d.makeRelative(CanonPath("/xyzzy/bla")), "../../xyzzy/bla");
}
} }