{
const path pa = absolute(p, base);
path result;
+
#ifdef _GLIBCXX_USE_REALPATH
char_ptr buf{ nullptr };
# if _XOPEN_VERSION < 700
}
#endif
- auto fail = [&ec, &result](int e) mutable {
- if (!ec.value())
- ec.assign(e, std::generic_category());
- result.clear();
- };
-
if (!exists(pa, ec))
- {
- fail(ENOENT);
- return result;
- }
- // else we can assume no unresolvable symlink loops
+ return result;
+ // else: we know there are (currently) no unresolvable symlink loops
result = pa.root_path();
for (auto& f : pa.relative_path())
cmpts.push_back(f);
- while (!cmpts.empty())
+ int max_allowed_symlinks = 40;
+
+ while (!cmpts.empty() && !ec)
{
path f = std::move(cmpts.front());
cmpts.pop_front();
- if (f.compare(".") == 0)
+ if (is_dot(f))
{
- if (!is_directory(result, ec))
- {
- fail(ENOTDIR);
- break;
- }
+ if (!is_directory(result, ec) && !ec)
+ ec.assign(ENOTDIR, std::generic_category());
}
- else if (f.compare("..") == 0)
+ else if (is_dotdot(f))
{
auto parent = result.parent_path();
if (parent.empty())
if (is_symlink(result, ec))
{
path link = read_symlink(result, ec);
- if (!ec.value())
+ if (!ec)
{
- if (link.is_absolute())
+ if (--max_allowed_symlinks == 0)
+ ec.assign(ELOOP, std::generic_category());
+ else
{
- result = link.root_path();
- link = link.relative_path();
+ if (link.is_absolute())
+ {
+ result = link.root_path();
+ link = link.relative_path();
+ }
+ else
+ result.remove_filename();
+
+ cmpts.insert(cmpts.begin(), link.begin(), link.end());
}
- else
- result.remove_filename();
-
- cmpts.insert(cmpts.begin(), link.begin(), link.end());
}
}
-
- if (ec.value() || !exists(result, ec))
- {
- fail(ENOENT);
- break;
- }
}
}
+
+ if (ec || !exists(result, ec))
+ result.clear();
+
return result;
}