[libcxx] r293531 - experimental: port directory_iterator to Windows

Saleem Abdulrasool via cfe-commits cfe-commits at lists.llvm.org
Mon Jan 30 10:50:34 PST 2017


Author: compnerd
Date: Mon Jan 30 12:50:34 2017
New Revision: 293531

URL: http://llvm.org/viewvc/llvm-project?rev=293531&view=rev
Log:
experimental: port directory_iterator to Windows

This adds a basic first cut implementation for directory_iterator on
Windows.  It uses the FindFirstFile/FindNextFile which has the same
restrictions as opendir/readdir where there exists a TOCTOU race
condition.

Modified:
    libcxx/trunk/src/experimental/filesystem/directory_iterator.cpp

Modified: libcxx/trunk/src/experimental/filesystem/directory_iterator.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/src/experimental/filesystem/directory_iterator.cpp?rev=293531&r1=293530&r2=293531&view=diff
==============================================================================
--- libcxx/trunk/src/experimental/filesystem/directory_iterator.cpp (original)
+++ libcxx/trunk/src/experimental/filesystem/directory_iterator.cpp Mon Jan 30 12:50:34 2017
@@ -8,17 +8,24 @@
 //===----------------------------------------------------------------------===//
 
 #include "experimental/filesystem"
+#if defined(_WIN32)
+#define WIN32_LEAN_AND_MEAN
+#include <Windows.h>
+#else
 #include <dirent.h>
+#endif
 #include <errno.h>
 
 _LIBCPP_BEGIN_NAMESPACE_EXPERIMENTAL_FILESYSTEM
 
 namespace { namespace detail {
 
+#if !defined(_WIN32)
 inline error_code capture_errno() {
     _LIBCPP_ASSERT(errno, "Expected errno to be non-zero");
     return error_code{errno, std::generic_category()};
 }
+#endif
 
 template <class ...Args>
 inline bool set_or_throw(std::error_code& my_ec,
@@ -33,6 +40,7 @@ inline bool set_or_throw(std::error_code
     return false;
 }
 
+#if !defined(_WIN32)
 inline path::string_type posix_readdir(DIR *dir_stream, error_code& ec) {
     struct dirent* dir_entry_ptr = nullptr;
     errno = 0; // zero errno in order to detect errors
@@ -44,11 +52,74 @@ inline path::string_type posix_readdir(D
         return dir_entry_ptr->d_name;
     }
 }
+#endif
 
 }}                                                       // namespace detail
 
 using detail::set_or_throw;
 
+#if defined(_WIN32)
+class __dir_stream {
+public:
+  __dir_stream() = delete;
+  __dir_stream& operator=(const __dir_stream&) = delete;
+
+  __dir_stream(__dir_stream&& __ds) noexcept
+      : __stream_(__ds.__stream_), __root_(std::move(__ds.__root_)),
+        __entry_(std::move(__ds.__entry_)) {
+    ds.__stream_ = INVALID_HANDLE_VALUE;
+  }
+
+  __dir_stream(const path& root, directory_options opts, error_code& ec)
+      : __stream_(INVALID_HANDLE_VALUE), __root_(root) {
+    __stream_ = ::FindFirstFile(root.c_str(), &__data_);
+    if (__stream_ == INVALID_HANDLE_VALUE) {
+      ec = error_code(::GetLastError(), std::generic_category());
+      const bool ignore_permission_denied =
+          bool(opts & directory_options::skip_permission_denied);
+      if (ignore_permission_denied && ec.value() == ERROR_ACCESS_DENIED)
+        ec.clear();
+      return;
+    }
+  }
+
+  ~__dir_stream() noexcept {
+    if (__stream_ == INVALID_HANDLE_VALUE)
+      return;
+    close();
+  }
+
+  bool good() const noexcept { return __stream_ != INVALID_HANDLE_VALUE; }
+
+  bool advance(error_code& ec) {
+    while (::FindNextFile(__stream_, &__data_)) {
+      if (!strcmp(__data_.cFileName, ".") || strcmp(__data_.cFileName, ".."))
+        continue;
+      __entry_.assign(__root_ / __data_.cFileName);
+      return true;
+    }
+    ec = error_code(::GetLastError(), std::generic_category());
+    close();
+    return false;
+  }
+
+private:
+  std::error_code close() noexcept {
+    std::error_code ec;
+    if (!::FindClose(__stream_))
+      ec = error_code(::GetLastError(), std::generic_category());
+    __stream_ = INVALID_HANDLE_VALUE;
+    return ec;
+  }
+
+  HANDLE __stream_{INVALID_HANDLE_VALUE};
+  WIN32_FIND_DATA __data_;
+
+public:
+  path __root_;
+  directory_entry __entry_;
+};
+#else
 class __dir_stream {
 public:
     __dir_stream() = delete;
@@ -110,6 +181,7 @@ public:
     path __root_;
     directory_entry __entry_;
 };
+#endif
 
 // directory_iterator
 




More information about the cfe-commits mailing list