summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/llvm/Support/FileSystem.h55
-rw-r--r--lib/Support/PathV2.cpp10
-rw-r--r--lib/Support/Windows/PathV2.inc77
-rw-r--r--lib/Support/Windows/Windows.h10
-rw-r--r--unittests/Support/Path.cpp13
5 files changed, 152 insertions, 13 deletions
diff --git a/include/llvm/Support/FileSystem.h b/include/llvm/Support/FileSystem.h
index fbf1e0d..f8d3b77 100644
--- a/include/llvm/Support/FileSystem.h
+++ b/include/llvm/Support/FileSystem.h
@@ -544,19 +544,29 @@ class directory_entry {
public:
explicit directory_entry(const Twine &path, file_status st = file_status(),
- file_status symlink_st = file_status());
+ file_status symlink_st = file_status())
+ : Path(path.str())
+ , Status(st)
+ , SymlinkStatus(symlink_st) {}
+
+ directory_entry() {}
void assign(const Twine &path, file_status st = file_status(),
- file_status symlink_st = file_status());
+ file_status symlink_st = file_status()) {
+ Path = path.str();
+ Status = st;
+ SymlinkStatus = symlink_st;
+ }
+
void replace_filename(const Twine &filename, file_status st = file_status(),
file_status symlink_st = file_status());
- const SmallVectorImpl<char> &path() const;
+ StringRef path() const { return Path; }
error_code status(file_status &result) const;
error_code symlink_status(file_status &result) const;
- bool operator==(const directory_entry& rhs) const;
- bool operator!=(const directory_entry& rhs) const;
+ bool operator==(const directory_entry& rhs) const { return Path == rhs.Path; }
+ bool operator!=(const directory_entry& rhs) const { return !(*this == rhs); }
bool operator< (const directory_entry& rhs) const;
bool operator<=(const directory_entry& rhs) const;
bool operator> (const directory_entry& rhs) const;
@@ -567,16 +577,41 @@ public:
/// operator++ because we need an error_code. If it's really needed we can make
/// it call report_fatal_error on error.
class directory_iterator {
- // implementation directory iterator status
+ intptr_t IterationHandle;
+ directory_entry CurrentEntry;
+
+ // Platform implementations implement these functions to handle iteration.
+ friend error_code directory_iterator_construct(directory_iterator& it,
+ const StringRef &path);
+ friend error_code directory_iterator_increment(directory_iterator& it);
+ friend error_code directory_iterator_destruct(directory_iterator& it);
public:
- explicit directory_iterator(const Twine &path, error_code &ec);
+ explicit directory_iterator(const Twine &path, error_code &ec)
+ : IterationHandle(0) {
+ SmallString<128> path_storage;
+ ec = directory_iterator_construct(*this, path.toStringRef(path_storage));
+ }
+
+ /// Construct end iterator.
+ directory_iterator() : IterationHandle(0) {}
+
+ ~directory_iterator() {
+ directory_iterator_destruct(*this);
+ }
+
// No operator++ because we need error_code.
- directory_iterator &increment(error_code &ec);
+ directory_iterator &increment(error_code &ec) {
+ ec = directory_iterator_increment(*this);
+ return *this;
+ }
- const directory_entry &operator*() const;
- const directory_entry *operator->() const;
+ const directory_entry &operator*() const { return CurrentEntry; }
+ const directory_entry *operator->() const { return &CurrentEntry; };
+ bool operator!=(const directory_iterator &RHS) const {
+ return CurrentEntry != RHS.CurrentEntry;
+ }
// Other members as required by
// C++ Std, 24.1.1 Input iterators [input.iterators]
};
diff --git a/lib/Support/PathV2.cpp b/lib/Support/PathV2.cpp
index 73896ed..639b323 100644
--- a/lib/Support/PathV2.cpp
+++ b/lib/Support/PathV2.cpp
@@ -688,6 +688,16 @@ error_code create_directories(const Twine &path, bool &existed) {
return create_directory(p, existed);
}
+void directory_entry::replace_filename(const Twine &filename, file_status st,
+ file_status symlink_st) {
+ SmallString<128> path(Path.begin(), Path.end());
+ path::remove_filename(path);
+ path::append(path, filename);
+ Path = path.str();
+ Status = st;
+ SymlinkStatus = symlink_st;
+}
+
} // end namespace fs
} // end namespace sys
} // end namespace llvm
diff --git a/lib/Support/Windows/PathV2.inc b/lib/Support/Windows/PathV2.inc
index 6bd541e..49343dc 100644
--- a/lib/Support/Windows/PathV2.inc
+++ b/lib/Support/Windows/PathV2.inc
@@ -121,6 +121,15 @@ namespace {
typedef ScopedHandle<HCRYPTPROV, HCRYPTPROV(INVALID_HANDLE_VALUE),
BOOL (WINAPI*)(HCRYPTPROV), CryptReleaseContext>
ScopedCryptContext;
+ bool is_separator(const wchar_t value) {
+ switch (value) {
+ case L'\\':
+ case L'/':
+ return true;
+ default:
+ return false;
+ }
+ }
}
namespace llvm {
@@ -598,6 +607,74 @@ retry_create_file:
result_fd = fd;
return success;
}
+
+error_code directory_iterator_construct(directory_iterator& it,
+ const StringRef &path) {
+ SmallVector<wchar_t, 128> path_utf16;
+
+ if (error_code ec = UTF8ToUTF16(path,
+ path_utf16))
+ return ec;
+
+ // Convert path to the format that Windows is happy with.
+ if (path_utf16.size() > 0 &&
+ !is_separator(path_utf16[path.size() - 1]) &&
+ path_utf16[path.size() - 1] != L':') {
+ path_utf16.push_back(L'\\');
+ path_utf16.push_back(L'*');
+ } else {
+ path_utf16.push_back(L'*');
+ }
+
+ // Get the first directory entry.
+ WIN32_FIND_DATAW FirstFind;
+ ScopedFindHandle FindHandle(::FindFirstFileW(path_utf16.c_str(), &FirstFind));
+ if (!FindHandle)
+ return windows_error(::GetLastError());
+
+ // Construct the current directory entry.
+ SmallString<128> directory_entry_path_utf8;
+ if (error_code ec = UTF16ToUTF8(FirstFind.cFileName,
+ ::wcslen(FirstFind.cFileName),
+ directory_entry_path_utf8))
+ return ec;
+
+ it.IterationHandle = intptr_t(FindHandle.take());
+ it.CurrentEntry = directory_entry(path);
+ it.CurrentEntry.replace_filename(Twine(directory_entry_path_utf8));
+
+ return success;
+}
+
+error_code directory_iterator_destruct(directory_iterator& it) {
+ if (it.IterationHandle != 0)
+ // Closes the handle if it's valid.
+ ScopedFindHandle close(HANDLE(it.IterationHandle));
+ it.IterationHandle = 0;
+ it.CurrentEntry = directory_entry();
+ return success;
+}
+
+error_code directory_iterator_increment(directory_iterator& it) {
+ WIN32_FIND_DATAW FindData;
+ if (!::FindNextFileW(HANDLE(it.IterationHandle), &FindData)) {
+ error_code ec = windows_error(::GetLastError());
+ // Check for end.
+ if (ec == windows_error::no_more_files)
+ return directory_iterator_destruct(it);
+ return ec;
+ }
+
+ SmallString<128> directory_entry_path_utf8;
+ if (error_code ec = UTF16ToUTF8(FindData.cFileName,
+ ::wcslen(FindData.cFileName),
+ directory_entry_path_utf8))
+ return ec;
+
+ it.CurrentEntry.replace_filename(Twine(directory_entry_path_utf8));
+ return success;
+}
+
} // end namespace fs
} // end namespace sys
} // end namespace llvm
diff --git a/lib/Support/Windows/Windows.h b/lib/Support/Windows/Windows.h
index 0233a42..9ee9d1f 100644
--- a/lib/Support/Windows/Windows.h
+++ b/lib/Support/Windows/Windows.h
@@ -94,7 +94,11 @@ public:
return Handle == InvalidHandle ? 0 : unspecified_bool_true;
}
- typedef ScopedHandle<HANDLE, INVALID_HANDLE_VALUE,
- BOOL (WINAPI*)(HANDLE), ::FindClose>
- ScopedFindHandle;
+ bool operator!() const {
+ return Handle == InvalidHandle;
+ }
};
+
+typedef ScopedHandle<HANDLE, INVALID_HANDLE_VALUE,
+ BOOL (WINAPI*)(HANDLE), ::FindClose>
+ ScopedFindHandle;
diff --git a/unittests/Support/Path.cpp b/unittests/Support/Path.cpp
index 7d94bc3..76a16a3 100644
--- a/unittests/Support/Path.cpp
+++ b/unittests/Support/Path.cpp
@@ -9,6 +9,7 @@
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/PathV2.h"
+#include "llvm/Support/ErrorHandling.h"
#include "gtest/gtest.h"
@@ -168,6 +169,18 @@ TEST(Support, Path) {
// Make sure Temp1 doesn't exist.
ASSERT_FALSE(fs::exists(Twine(TempPath), TempFileExists));
EXPECT_FALSE(TempFileExists);
+
+ // I've yet to do directory iteration on Unix.
+#ifdef LLVM_ON_WIN32
+ error_code ec;
+ for (fs::directory_iterator i(".", ec), e; i != e; i.increment(ec)) {
+ if (ec) {
+ errs() << ec.message() << '\n';
+ errs().flush();
+ report_fatal_error("Directory iteration failed!");
+ }
+ }
+#endif
}
} // anonymous namespace