aboutsummaryrefslogtreecommitdiffstats
path: root/lib/Support/Windows/Path.inc
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Support/Windows/Path.inc')
-rw-r--r--lib/Support/Windows/Path.inc231
1 files changed, 137 insertions, 94 deletions
diff --git a/lib/Support/Windows/Path.inc b/lib/Support/Windows/Path.inc
index 7a1bc04..365031c 100644
--- a/lib/Support/Windows/Path.inc
+++ b/lib/Support/Windows/Path.inc
@@ -49,23 +49,6 @@ static std::error_code windows_error(DWORD E) {
return mapWindowsError(E);
}
-static std::error_code TempDir(SmallVectorImpl<char> &Result) {
- SmallVector<wchar_t, 64> Res;
-retry_temp_dir:
- DWORD Len = ::GetTempPathW(Res.capacity(), Res.begin());
-
- if (Len == 0)
- return windows_error(::GetLastError());
-
- if (Len > Res.capacity()) {
- Res.reserve(Len);
- goto retry_temp_dir;
- }
-
- Res.set_size(Len);
- return UTF16ToUTF8(Res.begin(), Res.size(), Result);
-}
-
static bool is_separator(const wchar_t value) {
switch (value) {
case L'\\':
@@ -76,6 +59,59 @@ static bool is_separator(const wchar_t value) {
}
}
+// Convert a UTF-8 path to UTF-16. Also, if the absolute equivalent of the
+// path is longer than CreateDirectory can tolerate, make it absolute and
+// prefixed by '\\?\'.
+static std::error_code widenPath(const Twine &Path8,
+ SmallVectorImpl<wchar_t> &Path16) {
+ const size_t MaxDirLen = MAX_PATH - 12; // Must leave room for 8.3 filename.
+
+ // Several operations would convert Path8 to SmallString; more efficient to
+ // do it once up front.
+ SmallString<128> Path8Str;
+ Path8.toVector(Path8Str);
+
+ // If we made this path absolute, how much longer would it get?
+ size_t CurPathLen;
+ if (llvm::sys::path::is_absolute(Twine(Path8Str)))
+ CurPathLen = 0; // No contribution from current_path needed.
+ else {
+ CurPathLen = ::GetCurrentDirectoryW(0, NULL);
+ if (CurPathLen == 0)
+ return windows_error(::GetLastError());
+ }
+
+ // Would the absolute path be longer than our limit?
+ if ((Path8Str.size() + CurPathLen) >= MaxDirLen &&
+ !Path8Str.startswith("\\\\?\\")) {
+ SmallString<2*MAX_PATH> FullPath("\\\\?\\");
+ if (CurPathLen) {
+ SmallString<80> CurPath;
+ if (std::error_code EC = llvm::sys::fs::current_path(CurPath))
+ return EC;
+ FullPath.append(CurPath);
+ }
+ // Traverse the requested path, canonicalizing . and .. as we go (because
+ // the \\?\ prefix is documented to treat them as real components).
+ // The iterators don't report separators and append() always attaches
+ // preferred_separator so we don't need to call native() on the result.
+ for (llvm::sys::path::const_iterator I = llvm::sys::path::begin(Path8Str),
+ E = llvm::sys::path::end(Path8Str);
+ I != E; ++I) {
+ if (I->size() == 1 && *I == ".")
+ continue;
+ if (I->size() == 2 && *I == "..")
+ llvm::sys::path::remove_filename(FullPath);
+ else
+ llvm::sys::path::append(FullPath, *I);
+ }
+ return UTF8ToUTF16(FullPath, Path16);
+ }
+
+ // Just use the caller's original path.
+ return UTF8ToUTF16(Path8Str, Path16);
+}
+
namespace llvm {
namespace sys {
namespace fs {
@@ -147,11 +183,9 @@ std::error_code current_path(SmallVectorImpl<char> &result) {
}
std::error_code create_directory(const Twine &path, bool IgnoreExisting) {
- SmallString<128> path_storage;
SmallVector<wchar_t, 128> path_utf16;
- if (std::error_code ec =
- UTF8ToUTF16(path.toStringRef(path_storage), path_utf16))
+ if (std::error_code ec = widenPath(path, path_utf16))
return ec;
if (!::CreateDirectoryW(path_utf16.begin(), NULL)) {
@@ -163,25 +197,14 @@ std::error_code create_directory(const Twine &path, bool IgnoreExisting) {
return std::error_code();
}
-std::error_code normalize_separators(SmallVectorImpl<char> &Path) {
- (void) Path;
- return std::error_code();
-}
-
// We can't use symbolic links for windows.
std::error_code create_link(const Twine &to, const Twine &from) {
- // Get arguments.
- SmallString<128> from_storage;
- SmallString<128> to_storage;
- StringRef f = from.toStringRef(from_storage);
- StringRef t = to.toStringRef(to_storage);
-
// Convert to utf-16.
SmallVector<wchar_t, 128> wide_from;
SmallVector<wchar_t, 128> wide_to;
- if (std::error_code ec = UTF8ToUTF16(f, wide_from))
+ if (std::error_code ec = widenPath(from, wide_from))
return ec;
- if (std::error_code ec = UTF8ToUTF16(t, wide_to))
+ if (std::error_code ec = widenPath(to, wide_to))
return ec;
if (!::CreateHardLinkW(wide_from.begin(), wide_to.begin(), NULL))
@@ -191,7 +214,6 @@ std::error_code create_link(const Twine &to, const Twine &from) {
}
std::error_code remove(const Twine &path, bool IgnoreNonExisting) {
- SmallString<128> path_storage;
SmallVector<wchar_t, 128> path_utf16;
file_status ST;
@@ -201,8 +223,7 @@ std::error_code remove(const Twine &path, bool IgnoreNonExisting) {
return std::error_code();
}
- if (std::error_code ec =
- UTF8ToUTF16(path.toStringRef(path_storage), path_utf16))
+ if (std::error_code ec = widenPath(path, path_utf16))
return ec;
if (ST.type() == file_type::directory_file) {
@@ -222,18 +243,12 @@ std::error_code remove(const Twine &path, bool IgnoreNonExisting) {
}
std::error_code rename(const Twine &from, const Twine &to) {
- // Get arguments.
- SmallString<128> from_storage;
- SmallString<128> to_storage;
- StringRef f = from.toStringRef(from_storage);
- StringRef t = to.toStringRef(to_storage);
-
// Convert to utf-16.
SmallVector<wchar_t, 128> wide_from;
SmallVector<wchar_t, 128> wide_to;
- if (std::error_code ec = UTF8ToUTF16(f, wide_from))
+ if (std::error_code ec = widenPath(from, wide_from))
return ec;
- if (std::error_code ec = UTF8ToUTF16(t, wide_to))
+ if (std::error_code ec = widenPath(to, wide_to))
return ec;
std::error_code ec = std::error_code();
@@ -254,11 +269,9 @@ std::error_code rename(const Twine &from, const Twine &to) {
}
std::error_code resize_file(const Twine &path, uint64_t size) {
- SmallString<128> path_storage;
SmallVector<wchar_t, 128> path_utf16;
- if (std::error_code ec =
- UTF8ToUTF16(path.toStringRef(path_storage), path_utf16))
+ if (std::error_code ec = widenPath(path, path_utf16))
return ec;
int fd = ::_wopen(path_utf16.begin(), O_BINARY | _O_RDWR, S_IWRITE);
@@ -273,49 +286,27 @@ std::error_code resize_file(const Twine &path, uint64_t size) {
return std::error_code(error, std::generic_category());
}
-std::error_code exists(const Twine &path, bool &result) {
- SmallString<128> path_storage;
- SmallVector<wchar_t, 128> path_utf16;
+std::error_code access(const Twine &Path, AccessMode Mode) {
+ SmallVector<wchar_t, 128> PathUtf16;
- if (std::error_code ec =
- UTF8ToUTF16(path.toStringRef(path_storage), path_utf16))
- return ec;
+ if (std::error_code EC = widenPath(Path, PathUtf16))
+ return EC;
- DWORD attributes = ::GetFileAttributesW(path_utf16.begin());
+ DWORD Attributes = ::GetFileAttributesW(PathUtf16.begin());
- if (attributes == INVALID_FILE_ATTRIBUTES) {
+ if (Attributes == INVALID_FILE_ATTRIBUTES) {
// See if the file didn't actually exist.
DWORD LastError = ::GetLastError();
if (LastError != ERROR_FILE_NOT_FOUND &&
LastError != ERROR_PATH_NOT_FOUND)
return windows_error(LastError);
- result = false;
- } else
- result = true;
- return std::error_code();
-}
-
-bool can_write(const Twine &Path) {
- // FIXME: take security attributes into account.
- SmallString<128> PathStorage;
- SmallVector<wchar_t, 128> PathUtf16;
-
- if (UTF8ToUTF16(Path.toStringRef(PathStorage), PathUtf16))
- return false;
-
- DWORD Attr = ::GetFileAttributesW(PathUtf16.begin());
- return (Attr != INVALID_FILE_ATTRIBUTES) && !(Attr & FILE_ATTRIBUTE_READONLY);
-}
+ return errc::no_such_file_or_directory;
+ }
-bool can_execute(const Twine &Path) {
- SmallString<128> PathStorage;
- SmallVector<wchar_t, 128> PathUtf16;
+ if (Mode == AccessMode::Write && (Attributes & FILE_ATTRIBUTE_READONLY))
+ return errc::permission_denied;
- if (UTF8ToUTF16(Path.toStringRef(PathStorage), PathUtf16))
- return false;
-
- DWORD Attr = ::GetFileAttributesW(PathUtf16.begin());
- return Attr != INVALID_FILE_ATTRIBUTES;
+ return std::error_code();
}
bool equivalent(file_status A, file_status B) {
@@ -424,7 +415,7 @@ std::error_code status(const Twine &path, file_status &result) {
return std::error_code();
}
- if (std::error_code ec = UTF8ToUTF16(path8, path_utf16))
+ if (std::error_code ec = widenPath(path8, path_utf16))
return ec;
DWORD attr = ::GetFileAttributesW(path_utf16.begin());
@@ -567,11 +558,10 @@ mapped_file_region::mapped_file_region(const Twine &path,
, FileDescriptor()
, FileHandle(INVALID_HANDLE_VALUE)
, FileMappingHandle() {
- SmallString<128> path_storage;
SmallVector<wchar_t, 128> path_utf16;
// Convert path to UTF-16.
- if ((ec = UTF8ToUTF16(path.toStringRef(path_storage), path_utf16)))
+ if ((ec = widenPath(path, path_utf16)))
return;
// Get file handle for creating a file mapping.
@@ -677,7 +667,7 @@ std::error_code detail::directory_iterator_construct(detail::DirIterState &it,
StringRef path){
SmallVector<wchar_t, 128> path_utf16;
- if (std::error_code ec = UTF8ToUTF16(path, path_utf16))
+ if (std::error_code ec = widenPath(path, path_utf16))
return ec;
// Convert path to the format that Windows is happy with.
@@ -760,11 +750,9 @@ std::error_code detail::directory_iterator_increment(detail::DirIterState &it) {
}
std::error_code openFileForRead(const Twine &Name, int &ResultFD) {
- SmallString<128> PathStorage;
SmallVector<wchar_t, 128> PathUTF16;
- if (std::error_code EC =
- UTF8ToUTF16(Name.toStringRef(PathStorage), PathUTF16))
+ if (std::error_code EC = widenPath(Name, PathUTF16))
return EC;
HANDLE H = ::CreateFileW(PathUTF16.begin(), GENERIC_READ,
@@ -799,11 +787,9 @@ std::error_code openFileForWrite(const Twine &Name, int &ResultFD,
assert((!(Flags & sys::fs::F_Excl) || !(Flags & sys::fs::F_Append)) &&
"Cannot specify both 'excl' and 'append' file creation flags!");
- SmallString<128> PathStorage;
SmallVector<wchar_t, 128> PathUTF16;
- if (std::error_code EC =
- UTF8ToUTF16(Name.toStringRef(PathStorage), PathUTF16))
+ if (std::error_code EC = widenPath(Name, PathUTF16))
return EC;
DWORD CreationDisposition;
@@ -867,6 +853,51 @@ bool home_directory(SmallVectorImpl<char> &result) {
return true;
}
+static bool getTempDirEnvVar(const char *Var, SmallVectorImpl<char> &Res) {
+ SmallVector<wchar_t, 128> NameUTF16;
+ if (windows::UTF8ToUTF16(Var, NameUTF16))
+ return false;
+
+ SmallVector<wchar_t, 1024> Buf;
+ size_t Size = 1024;
+ do {
+ Buf.reserve(Size);
+ Size =
+ GetEnvironmentVariableW(NameUTF16.data(), Buf.data(), Buf.capacity());
+ if (Size == 0)
+ return false;
+
+ // Try again with larger buffer.
+ } while (Size > Buf.capacity());
+ Buf.set_size(Size);
+
+ if (windows::UTF16ToUTF8(Buf.data(), Size, Res))
+ return false;
+ return true;
+}
+
+static bool getTempDirEnvVar(SmallVectorImpl<char> &Res) {
+ const char *EnvironmentVariables[] = {"TMP", "TEMP", "USERPROFILE"};
+ for (const char *Env : EnvironmentVariables) {
+ if (getTempDirEnvVar(Env, Res))
+ return true;
+ }
+ return false;
+}
+
+void system_temp_directory(bool ErasedOnReboot, SmallVectorImpl<char> &Result) {
+ (void)ErasedOnReboot;
+ Result.clear();
+
+ // Check whether the temporary directory is specified by an environment
+ // variable.
+ if (getTempDirEnvVar(Result))
+ return;
+
+ // Fall back to a system default.
+ const char *DefaultResult = "C:\\TEMP";
+ Result.append(DefaultResult, DefaultResult + strlen(DefaultResult));
+}
} // end namespace path
namespace windows {
@@ -896,11 +927,13 @@ std::error_code UTF8ToUTF16(llvm::StringRef utf8,
return std::error_code();
}
-std::error_code UTF16ToUTF8(const wchar_t *utf16, size_t utf16_len,
- llvm::SmallVectorImpl<char> &utf8) {
+static
+std::error_code UTF16ToCodePage(unsigned codepage, const wchar_t *utf16,
+ size_t utf16_len,
+ llvm::SmallVectorImpl<char> &utf8) {
if (utf16_len) {
// Get length.
- int len = ::WideCharToMultiByte(CP_UTF8, 0, utf16, utf16_len, utf8.begin(),
+ int len = ::WideCharToMultiByte(codepage, 0, utf16, utf16_len, utf8.begin(),
0, NULL, NULL);
if (len == 0)
@@ -910,7 +943,7 @@ std::error_code UTF16ToUTF8(const wchar_t *utf16, size_t utf16_len,
utf8.set_size(len);
// Now do the actual conversion.
- len = ::WideCharToMultiByte(CP_UTF8, 0, utf16, utf16_len, utf8.data(),
+ len = ::WideCharToMultiByte(codepage, 0, utf16, utf16_len, utf8.data(),
utf8.size(), NULL, NULL);
if (len == 0)
@@ -923,6 +956,16 @@ std::error_code UTF16ToUTF8(const wchar_t *utf16, size_t utf16_len,
return std::error_code();
}
+
+std::error_code UTF16ToUTF8(const wchar_t *utf16, size_t utf16_len,
+ llvm::SmallVectorImpl<char> &utf8) {
+ return UTF16ToCodePage(CP_UTF8, utf16, utf16_len, utf8);
+}
+
+std::error_code UTF16ToCurCP(const wchar_t *utf16, size_t utf16_len,
+ llvm::SmallVectorImpl<char> &utf8) {
+ return UTF16ToCodePage(CP_ACP, utf16, utf16_len, utf8);
+}
} // end namespace windows
} // end namespace sys
} // end namespace llvm