aboutsummaryrefslogtreecommitdiff
path: root/lib/Support/Path.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Support/Path.cpp')
-rw-r--r--lib/Support/Path.cpp192
1 files changed, 123 insertions, 69 deletions
diff --git a/lib/Support/Path.cpp b/lib/Support/Path.cpp
index f229f23a4f84..a806da23ec50 100644
--- a/lib/Support/Path.cpp
+++ b/lib/Support/Path.cpp
@@ -13,6 +13,7 @@
#include "llvm/Support/Path.h"
#include "llvm/ADT/ArrayRef.h"
+#include "llvm/Config/llvm-config.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/Errc.h"
#include "llvm/Support/ErrorHandling.h"
@@ -37,7 +38,7 @@ namespace {
using llvm::sys::path::Style;
inline Style real_style(Style style) {
-#ifdef LLVM_ON_WIN32
+#ifdef _WIN32
return (style == Style::posix) ? Style::posix : Style::windows;
#else
return (style == Style::windows) ? Style::windows : Style::posix;
@@ -90,10 +91,9 @@ namespace {
return path.substr(0, end);
}
+ // Returns the first character of the filename in str. For paths ending in
+ // '/', it returns the position of the '/'.
size_t filename_pos(StringRef str, Style style) {
- if (str.size() == 2 && is_separator(str[0], style) && str[0] == str[1])
- return 0;
-
if (str.size() > 0 && is_separator(str[str.size() - 1], style))
return str.size() - 1;
@@ -110,6 +110,8 @@ namespace {
return pos + 1;
}
+ // Returns the position of the root directory in str. If there is no root
+ // directory in str, it returns StringRef::npos.
size_t root_dir_start(StringRef str, Style style) {
// case "c:/"
if (real_style(style) == Style::windows) {
@@ -117,10 +119,6 @@ namespace {
return 2;
}
- // case "//"
- if (str.size() == 2 && is_separator(str[0], style) && str[0] == str[1])
- return StringRef::npos;
-
// case "//net"
if (str.size() > 3 && is_separator(str[0], style) && str[0] == str[1] &&
!is_separator(str[2], style)) {
@@ -134,22 +132,29 @@ namespace {
return StringRef::npos;
}
+ // Returns the position past the end of the "parent path" of path. The parent
+ // path will not end in '/', unless the parent is the root directory. If the
+ // path has no parent, 0 is returned.
size_t parent_path_end(StringRef path, Style style) {
size_t end_pos = filename_pos(path, style);
bool filename_was_sep =
path.size() > 0 && is_separator(path[end_pos], style);
- // Skip separators except for root dir.
- size_t root_dir_pos = root_dir_start(path.substr(0, end_pos), style);
-
- while (end_pos > 0 && (end_pos - 1) != root_dir_pos &&
+ // Skip separators until we reach root dir (or the start of the string).
+ size_t root_dir_pos = root_dir_start(path, style);
+ while (end_pos > 0 &&
+ (root_dir_pos == StringRef::npos || end_pos > root_dir_pos) &&
is_separator(path[end_pos - 1], style))
--end_pos;
- if (end_pos == 1 && root_dir_pos == 0 && filename_was_sep)
- return StringRef::npos;
+ if (end_pos == root_dir_pos && !filename_was_sep) {
+ // We've reached the root dir and the input path was *not* ending in a
+ // sequence of slashes. Include the root dir in the parent path.
+ return root_dir_pos + 1;
+ }
+ // Otherwise, just include before the last slash.
return end_pos;
}
} // end unnamed namespace
@@ -164,7 +169,7 @@ static std::error_code
createUniqueEntity(const Twine &Model, int &ResultFD,
SmallVectorImpl<char> &ResultPath, bool MakeAbsolute,
unsigned Mode, FSEntity Type,
- sys::fs::OpenFlags Flags = sys::fs::F_None) {
+ sys::fs::OpenFlags Flags = sys::fs::OF_None) {
SmallString<128> ModelStorage;
Model.toVector(ModelStorage);
@@ -196,8 +201,8 @@ retry_random_path:
switch (Type) {
case FS_File: {
if (std::error_code EC =
- sys::fs::openFileForWrite(Twine(ResultPath.begin()), ResultFD,
- Flags | sys::fs::F_Excl, Mode)) {
+ sys::fs::openFileForReadWrite(Twine(ResultPath.begin()), ResultFD,
+ sys::fs::CD_CreateNew, Flags, Mode)) {
if (EC == errc::file_exists)
goto retry_random_path;
return EC;
@@ -281,8 +286,8 @@ const_iterator &const_iterator::operator++() {
++Position;
}
- // Treat trailing '/' as a '.'.
- if (Position == Path.size()) {
+ // Treat trailing '/' as a '.', unless it is the root dir.
+ if (Position == Path.size() && Component != "/") {
--Position;
Component = ".";
return *this;
@@ -321,23 +326,23 @@ reverse_iterator rend(StringRef Path) {
}
reverse_iterator &reverse_iterator::operator++() {
- // If we're at the end and the previous char was a '/', return '.' unless
- // we are the root path.
size_t root_dir_pos = root_dir_start(Path, S);
- if (Position == Path.size() && Path.size() > root_dir_pos + 1 &&
- is_separator(Path[Position - 1], S)) {
- --Position;
- Component = ".";
- return *this;
- }
// Skip separators unless it's the root directory.
size_t end_pos = Position;
-
while (end_pos > 0 && (end_pos - 1) != root_dir_pos &&
is_separator(Path[end_pos - 1], S))
--end_pos;
+ // Treat trailing '/' as a '.', unless it is the root dir.
+ if (Position == Path.size() && !Path.empty() &&
+ is_separator(Path.back(), S) &&
+ (root_dir_pos == StringRef::npos || end_pos - 1 > root_dir_pos)) {
+ --Position;
+ Component = ".";
+ return *this;
+ }
+
// Find next separator.
size_t start_pos = filename_pos(Path.substr(0, end_pos), S);
Component = Path.slice(start_pos, end_pos);
@@ -751,51 +756,64 @@ std::error_code getUniqueID(const Twine Path, UniqueID &Result) {
std::error_code createUniqueFile(const Twine &Model, int &ResultFd,
SmallVectorImpl<char> &ResultPath,
- unsigned Mode, sys::fs::OpenFlags Flags) {
+ unsigned Mode) {
+ return createUniqueEntity(Model, ResultFd, ResultPath, false, Mode, FS_File);
+}
+
+static std::error_code createUniqueFile(const Twine &Model, int &ResultFd,
+ SmallVectorImpl<char> &ResultPath,
+ unsigned Mode, OpenFlags Flags) {
return createUniqueEntity(Model, ResultFd, ResultPath, false, Mode, FS_File,
Flags);
}
std::error_code createUniqueFile(const Twine &Model,
- SmallVectorImpl<char> &ResultPath) {
- int Dummy;
- return createUniqueEntity(Model, Dummy, ResultPath, false, 0, FS_Name);
+ SmallVectorImpl<char> &ResultPath,
+ unsigned Mode) {
+ int FD;
+ auto EC = createUniqueFile(Model, FD, ResultPath, Mode);
+ if (EC)
+ return EC;
+ // FD is only needed to avoid race conditions. Close it right away.
+ close(FD);
+ return EC;
}
static std::error_code
createTemporaryFile(const Twine &Model, int &ResultFD,
- llvm::SmallVectorImpl<char> &ResultPath, FSEntity Type,
- sys::fs::OpenFlags Flags) {
+ llvm::SmallVectorImpl<char> &ResultPath, FSEntity Type) {
SmallString<128> Storage;
StringRef P = Model.toNullTerminatedStringRef(Storage);
assert(P.find_first_of(separators(Style::native)) == StringRef::npos &&
"Model must be a simple filename.");
// Use P.begin() so that createUniqueEntity doesn't need to recreate Storage.
return createUniqueEntity(P.begin(), ResultFD, ResultPath, true,
- owner_read | owner_write, Type, Flags);
+ owner_read | owner_write, Type);
}
static std::error_code
createTemporaryFile(const Twine &Prefix, StringRef Suffix, int &ResultFD,
- llvm::SmallVectorImpl<char> &ResultPath, FSEntity Type,
- sys::fs::OpenFlags Flags = sys::fs::F_None) {
+ llvm::SmallVectorImpl<char> &ResultPath, FSEntity Type) {
const char *Middle = Suffix.empty() ? "-%%%%%%" : "-%%%%%%.";
return createTemporaryFile(Prefix + Middle + Suffix, ResultFD, ResultPath,
- Type, Flags);
+ Type);
}
std::error_code createTemporaryFile(const Twine &Prefix, StringRef Suffix,
int &ResultFD,
- SmallVectorImpl<char> &ResultPath,
- sys::fs::OpenFlags Flags) {
- return createTemporaryFile(Prefix, Suffix, ResultFD, ResultPath, FS_File,
- Flags);
+ SmallVectorImpl<char> &ResultPath) {
+ return createTemporaryFile(Prefix, Suffix, ResultFD, ResultPath, FS_File);
}
std::error_code createTemporaryFile(const Twine &Prefix, StringRef Suffix,
SmallVectorImpl<char> &ResultPath) {
- int Dummy;
- return createTemporaryFile(Prefix, Suffix, Dummy, ResultPath, FS_Name);
+ int FD;
+ auto EC = createTemporaryFile(Prefix, Suffix, FD, ResultPath);
+ if (EC)
+ return EC;
+ // FD is only needed to avoid race conditions. Close it right away.
+ close(FD);
+ return EC;
}
@@ -804,8 +822,22 @@ std::error_code createTemporaryFile(const Twine &Prefix, StringRef Suffix,
std::error_code createUniqueDirectory(const Twine &Prefix,
SmallVectorImpl<char> &ResultPath) {
int Dummy;
- return createUniqueEntity(Prefix + "-%%%%%%", Dummy, ResultPath,
- true, 0, FS_Dir);
+ return createUniqueEntity(Prefix + "-%%%%%%", Dummy, ResultPath, true, 0,
+ FS_Dir);
+}
+
+std::error_code
+getPotentiallyUniqueFileName(const Twine &Model,
+ SmallVectorImpl<char> &ResultPath) {
+ int Dummy;
+ return createUniqueEntity(Model, Dummy, ResultPath, false, 0, FS_Name);
+}
+
+std::error_code
+getPotentiallyUniqueTempFileName(const Twine &Prefix, StringRef Suffix,
+ SmallVectorImpl<char> &ResultPath) {
+ int Dummy;
+ return createTemporaryFile(Prefix, Suffix, Dummy, ResultPath, FS_Name);
}
static std::error_code make_absolute(const Twine &current_directory,
@@ -895,15 +927,7 @@ std::error_code create_directories(const Twine &Path, bool IgnoreExisting,
return create_directory(P, IgnoreExisting, Perms);
}
-std::error_code copy_file(const Twine &From, const Twine &To) {
- int ReadFD, WriteFD;
- if (std::error_code EC = openFileForRead(From, ReadFD))
- return EC;
- if (std::error_code EC = openFileForWrite(To, WriteFD, F_None)) {
- close(ReadFD);
- return EC;
- }
-
+static std::error_code copy_file_internal(int ReadFD, int WriteFD) {
const size_t BufSize = 4096;
char *Buf = new char[BufSize];
int BytesRead = 0, BytesWritten = 0;
@@ -920,8 +944,6 @@ std::error_code copy_file(const Twine &From, const Twine &To) {
if (BytesWritten < 0)
break;
}
- close(ReadFD);
- close(WriteFD);
delete[] Buf;
if (BytesRead < 0 || BytesWritten < 0)
@@ -929,6 +951,36 @@ std::error_code copy_file(const Twine &From, const Twine &To) {
return std::error_code();
}
+std::error_code copy_file(const Twine &From, const Twine &To) {
+ int ReadFD, WriteFD;
+ if (std::error_code EC = openFileForRead(From, ReadFD, OF_None))
+ return EC;
+ if (std::error_code EC =
+ openFileForWrite(To, WriteFD, CD_CreateAlways, OF_None)) {
+ close(ReadFD);
+ return EC;
+ }
+
+ std::error_code EC = copy_file_internal(ReadFD, WriteFD);
+
+ close(ReadFD);
+ close(WriteFD);
+
+ return EC;
+}
+
+std::error_code copy_file(const Twine &From, int ToFD) {
+ int ReadFD;
+ if (std::error_code EC = openFileForRead(From, ReadFD, OF_None))
+ return EC;
+
+ std::error_code EC = copy_file_internal(ReadFD, ToFD);
+
+ close(ReadFD);
+
+ return EC;
+}
+
ErrorOr<MD5::MD5Result> md5_contents(int FD) {
MD5 Hash;
@@ -951,7 +1003,7 @@ ErrorOr<MD5::MD5Result> md5_contents(int FD) {
ErrorOr<MD5::MD5Result> md5_contents(const Twine &Path) {
int FD;
- if (auto EC = openFileForRead(Path, FD))
+ if (auto EC = openFileForRead(Path, FD, OF_None))
return EC;
auto Result = md5_contents(FD);
@@ -1048,7 +1100,7 @@ ErrorOr<perms> getPermissions(const Twine &Path) {
#if defined(LLVM_ON_UNIX)
#include "Unix/Path.inc"
#endif
-#if defined(LLVM_ON_WIN32)
+#if defined(_WIN32)
#include "Windows/Path.inc"
#endif
@@ -1070,7 +1122,7 @@ Error TempFile::discard() {
Done = true;
std::error_code RemoveEC;
// On windows closing will remove the file.
-#ifndef LLVM_ON_WIN32
+#ifndef _WIN32
// Always try to close and remove.
if (!TmpName.empty()) {
RemoveEC = fs::remove(TmpName);
@@ -1094,14 +1146,15 @@ Error TempFile::keep(const Twine &Name) {
assert(!Done);
Done = true;
// Always try to close and rename.
-#ifdef LLVM_ON_WIN32
- // If we cant't cancel the delete don't rename.
- std::error_code RenameEC = cancelDeleteOnClose(FD);
+#ifdef _WIN32
+ // If we can't cancel the delete don't rename.
+ auto H = reinterpret_cast<HANDLE>(_get_osfhandle(FD));
+ std::error_code RenameEC = setDeleteDisposition(H, false);
if (!RenameEC)
RenameEC = rename_fd(FD, Name);
// If we can't rename, discard the temporary file.
if (RenameEC)
- removeFD(FD);
+ setDeleteDisposition(H, true);
#else
std::error_code RenameEC = fs::rename(TmpName, Name);
// If we can't rename, discard the temporary file.
@@ -1126,8 +1179,9 @@ Error TempFile::keep() {
assert(!Done);
Done = true;
-#ifdef LLVM_ON_WIN32
- if (std::error_code EC = cancelDeleteOnClose(FD))
+#ifdef _WIN32
+ auto H = reinterpret_cast<HANDLE>(_get_osfhandle(FD));
+ if (std::error_code EC = setDeleteDisposition(H, false))
return errorCodeToError(EC);
#else
sys::DontRemoveFileOnSignal(TmpName);
@@ -1147,12 +1201,12 @@ Error TempFile::keep() {
Expected<TempFile> TempFile::create(const Twine &Model, unsigned Mode) {
int FD;
SmallString<128> ResultPath;
- if (std::error_code EC = createUniqueFile(Model, FD, ResultPath, Mode,
- sys::fs::F_RW | sys::fs::F_Delete))
+ if (std::error_code EC =
+ createUniqueFile(Model, FD, ResultPath, Mode, OF_Delete))
return errorCodeToError(EC);
TempFile Ret(ResultPath, FD);
-#ifndef LLVM_ON_WIN32
+#ifndef _WIN32
if (sys::RemoveFileOnSignal(ResultPath)) {
// Make sure we delete the file when RemoveFileOnSignal fails.
consumeError(Ret.discard());