diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2020-07-26 19:36:28 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2020-07-26 19:36:28 +0000 |
commit | cfca06d7963fa0909f90483b42a6d7d194d01e08 (patch) | |
tree | 209fb2a2d68f8f277793fc8df46c753d31bc853b /llvm/lib/Support/Path.cpp | |
parent | 706b4fc47bbc608932d3b491ae19a3b9cde9497b (diff) |
Notes
Diffstat (limited to 'llvm/lib/Support/Path.cpp')
-rw-r--r-- | llvm/lib/Support/Path.cpp | 154 |
1 files changed, 85 insertions, 69 deletions
diff --git a/llvm/lib/Support/Path.cpp b/llvm/lib/Support/Path.cpp index 3c9a08cb4077..37b3086fddf5 100644 --- a/llvm/lib/Support/Path.cpp +++ b/llvm/lib/Support/Path.cpp @@ -496,49 +496,44 @@ void replace_extension(SmallVectorImpl<char> &path, const Twine &extension, path.append(ext.begin(), ext.end()); } -bool replace_path_prefix(SmallVectorImpl<char> &Path, - const StringRef &OldPrefix, const StringRef &NewPrefix, - Style style, bool strict) { +static bool starts_with(StringRef Path, StringRef Prefix, + Style style = Style::native) { + // Windows prefix matching : case and separator insensitive + if (real_style(style) == Style::windows) { + if (Path.size() < Prefix.size()) + return false; + for (size_t I = 0, E = Prefix.size(); I != E; ++I) { + bool SepPath = is_separator(Path[I], style); + bool SepPrefix = is_separator(Prefix[I], style); + if (SepPath != SepPrefix) + return false; + if (!SepPath && toLower(Path[I]) != toLower(Prefix[I])) + return false; + } + return true; + } + return Path.startswith(Prefix); +} + +bool replace_path_prefix(SmallVectorImpl<char> &Path, StringRef OldPrefix, + StringRef NewPrefix, Style style) { if (OldPrefix.empty() && NewPrefix.empty()) return false; StringRef OrigPath(Path.begin(), Path.size()); - StringRef OldPrefixDir; - - if (!strict && OldPrefix.size() > OrigPath.size()) + if (!starts_with(OrigPath, OldPrefix, style)) return false; - // Ensure OldPrefixDir does not have a trailing separator. - if (!OldPrefix.empty() && is_separator(OldPrefix.back())) - OldPrefixDir = parent_path(OldPrefix, style); - else - OldPrefixDir = OldPrefix; - - if (!OrigPath.startswith(OldPrefixDir)) - return false; - - if (OrigPath.size() > OldPrefixDir.size()) - if (!is_separator(OrigPath[OldPrefixDir.size()], style) && strict) - return false; - // If prefixes have the same size we can simply copy the new one over. - if (OldPrefixDir.size() == NewPrefix.size() && !strict) { + if (OldPrefix.size() == NewPrefix.size()) { llvm::copy(NewPrefix, Path.begin()); return true; } - StringRef RelPath = OrigPath.substr(OldPrefixDir.size()); + StringRef RelPath = OrigPath.substr(OldPrefix.size()); SmallString<256> NewPath; - path::append(NewPath, style, NewPrefix); - if (!RelPath.empty()) { - if (!is_separator(RelPath[0], style) || !strict) - path::append(NewPath, style, RelPath); - else - path::append(NewPath, style, relative_path(RelPath, style)); - } - + (Twine(NewPrefix) + RelPath).toVector(NewPath); Path.swap(NewPath); - return true; } @@ -564,21 +559,15 @@ void native(SmallVectorImpl<char> &Path, Style style) { Path = PathHome; } } else { - for (auto PI = Path.begin(), PE = Path.end(); PI < PE; ++PI) { - if (*PI == '\\') { - auto PN = PI + 1; - if (PN < PE && *PN == '\\') - ++PI; // increment once, the for loop will move over the escaped slash - else - *PI = '/'; - } - } + for (auto PI = Path.begin(), PE = Path.end(); PI < PE; ++PI) + if (*PI == '\\') + *PI = '/'; } } std::string convert_to_slash(StringRef path, Style style) { if (real_style(style) != Style::windows) - return path; + return std::string(path); std::string s = path.str(); std::replace(s.begin(), s.end(), '\\', '/'); @@ -708,43 +697,69 @@ StringRef remove_leading_dotslash(StringRef Path, Style style) { return Path; } -static SmallString<256> remove_dots(StringRef path, bool remove_dot_dot, - Style style) { +// Remove path traversal components ("." and "..") when possible, and +// canonicalize slashes. +bool remove_dots(SmallVectorImpl<char> &the_path, bool remove_dot_dot, + Style style) { + style = real_style(style); + StringRef remaining(the_path.data(), the_path.size()); + bool needs_change = false; SmallVector<StringRef, 16> components; - // Skip the root path, then look for traversal in the components. - StringRef rel = path::relative_path(path, style); - for (StringRef C : - llvm::make_range(path::begin(rel, style), path::end(rel))) { - if (C == ".") - continue; - // Leading ".." will remain in the path unless it's at the root. - if (remove_dot_dot && C == "..") { + // Consume the root path, if present. + StringRef root = path::root_path(remaining, style); + bool absolute = !root.empty(); + if (absolute) + remaining = remaining.drop_front(root.size()); + + // Loop over path components manually. This makes it easier to detect + // non-preferred slashes and double separators that must be canonicalized. + while (!remaining.empty()) { + size_t next_slash = remaining.find_first_of(separators(style)); + if (next_slash == StringRef::npos) + next_slash = remaining.size(); + StringRef component = remaining.take_front(next_slash); + remaining = remaining.drop_front(next_slash); + + // Eat the slash, and check if it is the preferred separator. + if (!remaining.empty()) { + needs_change |= remaining.front() != preferred_separator(style); + remaining = remaining.drop_front(); + // The path needs to be rewritten if it has a trailing slash. + // FIXME: This is emergent behavior that could be removed. + needs_change |= remaining.empty(); + } + + // Check for path traversal components or double separators. + if (component.empty() || component == ".") { + needs_change = true; + } else if (remove_dot_dot && component == "..") { + needs_change = true; + // Do not allow ".." to remove the root component. If this is the + // beginning of a relative path, keep the ".." component. if (!components.empty() && components.back() != "..") { components.pop_back(); - continue; + } else if (!absolute) { + components.push_back(component); } - if (path::is_absolute(path, style)) - continue; + } else { + components.push_back(component); } - components.push_back(C); } - SmallString<256> buffer = path::root_path(path, style); - for (StringRef C : components) - path::append(buffer, style, C); - return buffer; -} - -bool remove_dots(SmallVectorImpl<char> &path, bool remove_dot_dot, - Style style) { - StringRef p(path.data(), path.size()); - - SmallString<256> result = remove_dots(p, remove_dot_dot, style); - if (result == path) + // Avoid rewriting the path unless we have to. + if (!needs_change) return false; - path.swap(result); + SmallString<256> buffer = root; + if (!components.empty()) { + buffer += components[0]; + for (StringRef C : makeArrayRef(components).drop_front()) { + buffer += preferred_separator(style); + buffer += C; + } + } + the_path.swap(buffer); return true; } @@ -1114,7 +1129,7 @@ void directory_entry::replace_filename(const Twine &Filename, file_type Type, basic_file_status Status) { SmallString<128> PathStr = path::parent_path(Path); path::append(PathStr, Filename); - this->Path = PathStr.str(); + this->Path = std::string(PathStr.str()); this->Type = Type; this->Status = Status; } @@ -1142,7 +1157,8 @@ ErrorOr<perms> getPermissions(const Twine &Path) { namespace llvm { namespace sys { namespace fs { -TempFile::TempFile(StringRef Name, int FD) : TmpName(Name), FD(FD) {} +TempFile::TempFile(StringRef Name, int FD) + : TmpName(std::string(Name)), FD(FD) {} TempFile::TempFile(TempFile &&Other) { *this = std::move(Other); } TempFile &TempFile::operator=(TempFile &&Other) { TmpName = std::move(Other.TmpName); |