mirror of
https://github.com/NixOS/nix.git
synced 2024-11-26 00:32:28 +00:00
Factor out the Unix-specific parts of canonPathInner
This prepares the code to also support Windows paths in the next commit.
This commit is contained in:
parent
60936f28e5
commit
4531585275
@ -8,7 +8,7 @@ CanonPath CanonPath::root = CanonPath("/");
|
||||
|
||||
static std::string absPathPure(std::string_view path)
|
||||
{
|
||||
return canonPathInner(path, [](auto &, auto &){});
|
||||
return canonPathInner<UnixPathTrait>(path, [](auto &, auto &){});
|
||||
}
|
||||
|
||||
CanonPath::CanonPath(std::string_view raw)
|
||||
|
@ -10,6 +10,39 @@
|
||||
|
||||
namespace nix {
|
||||
|
||||
/**
|
||||
* Unix-style path primives.
|
||||
*
|
||||
* Nix'result own "logical" paths are always Unix-style. So this is always
|
||||
* used for that, and additionally used for native paths on Unix.
|
||||
*/
|
||||
struct UnixPathTrait
|
||||
{
|
||||
using CharT = char;
|
||||
|
||||
using String = std::string;
|
||||
|
||||
using StringView = std::string_view;
|
||||
|
||||
constexpr static char preferredSep = '/';
|
||||
|
||||
static inline bool isPathSep(char c)
|
||||
{
|
||||
return c == '/';
|
||||
}
|
||||
|
||||
static inline size_t findPathSep(StringView path, size_t from = 0)
|
||||
{
|
||||
return path.find('/', from);
|
||||
}
|
||||
|
||||
static inline size_t rfindPathSep(StringView path, size_t from = StringView::npos)
|
||||
{
|
||||
return path.rfind('/', from);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Core pure path canonicalization algorithm.
|
||||
*
|
||||
@ -24,25 +57,26 @@ namespace nix {
|
||||
* This is a chance to modify those two paths in arbitrary way, e.g. if
|
||||
* "result" points to a symlink.
|
||||
*/
|
||||
typename std::string canonPathInner(
|
||||
std::string_view remaining,
|
||||
template<class PathDict>
|
||||
typename PathDict::String canonPathInner(
|
||||
typename PathDict::StringView remaining,
|
||||
auto && hookComponent)
|
||||
{
|
||||
assert(remaining != "");
|
||||
|
||||
std::string result;
|
||||
typename PathDict::String result;
|
||||
result.reserve(256);
|
||||
|
||||
while (true) {
|
||||
|
||||
/* Skip slashes. */
|
||||
while (!remaining.empty() && remaining[0] == '/')
|
||||
while (!remaining.empty() && PathDict::isPathSep(remaining[0]))
|
||||
remaining.remove_prefix(1);
|
||||
|
||||
if (remaining.empty()) break;
|
||||
|
||||
auto nextComp = ({
|
||||
auto nextPathSep = remaining.find('/');
|
||||
auto nextPathSep = PathDict::findPathSep(remaining);
|
||||
nextPathSep == remaining.npos ? remaining : remaining.substr(0, nextPathSep);
|
||||
});
|
||||
|
||||
@ -53,14 +87,14 @@ typename std::string canonPathInner(
|
||||
/* If `..', delete the last component. */
|
||||
else if (nextComp == "..")
|
||||
{
|
||||
if (!result.empty()) result.erase(result.rfind('/'));
|
||||
if (!result.empty()) result.erase(PathDict::rfindPathSep(result));
|
||||
remaining.remove_prefix(2);
|
||||
}
|
||||
|
||||
/* Normal component; copy it. */
|
||||
else {
|
||||
result += '/';
|
||||
if (const auto slash = remaining.find('/'); slash == result.npos) {
|
||||
result += PathDict::preferredSep;
|
||||
if (const auto slash = PathDict::findPathSep(remaining); slash == result.npos) {
|
||||
result += remaining;
|
||||
remaining = {};
|
||||
} else {
|
||||
@ -73,7 +107,7 @@ typename std::string canonPathInner(
|
||||
}
|
||||
|
||||
if (result.empty())
|
||||
result = "/";
|
||||
result = typename PathDict::String { PathDict::preferredSep };
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -78,7 +78,7 @@ Path canonPath(PathView path, bool resolveSymlinks)
|
||||
arbitrary (but high) limit to prevent infinite loops. */
|
||||
unsigned int followCount = 0, maxFollow = 1024;
|
||||
|
||||
return canonPathInner(
|
||||
return canonPathInner<UnixPathTrait>(
|
||||
path,
|
||||
[&followCount, &temp, maxFollow, resolveSymlinks]
|
||||
(std::string & result, std::string_view & remaining) {
|
||||
|
Loading…
Reference in New Issue
Block a user