Index: libcxx/src/filesystem/directory_iterator.cpp =================================================================== --- libcxx/src/filesystem/directory_iterator.cpp +++ libcxx/src/filesystem/directory_iterator.cpp @@ -10,6 +10,7 @@ #include "__config" #if defined(_LIBCPP_WIN32API) #define WIN32_LEAN_AND_MEAN +#define NOMINMAX #include #else #include @@ -73,15 +74,18 @@ } #else -static file_type get_file_type(const WIN32_FIND_DATA& data) { - //auto attrs = data.dwFileAttributes; - // FIXME(EricWF) - return file_type::unknown; +static file_type get_file_type(const WIN32_FIND_DATAW& data) { + if (data.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT && + data.dwReserved0 == IO_REPARSE_TAG_SYMLINK) + return file_type::symlink; + if (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + return file_type::directory; + return file_type::regular; } -static uintmax_t get_file_size(const WIN32_FIND_DATA& data) { - return (data.nFileSizeHigh * (MAXDWORD + 1)) + data.nFileSizeLow; +static uintmax_t get_file_size(const WIN32_FIND_DATAW& data) { + return (static_cast(data.nFileSizeHigh) << 32) + data.nFileSizeLow; } -static file_time_type get_write_time(const WIN32_FIND_DATA& data) { +static file_time_type get_write_time(const WIN32_FIND_DATAW& data) { ULARGE_INTEGER tmp; const FILETIME& time = data.ftLastWriteTime; tmp.u.LowPart = time.dwLowDateTime; @@ -110,15 +114,21 @@ __dir_stream(const path& root, directory_options opts, error_code& ec) : __stream_(INVALID_HANDLE_VALUE), __root_(root) { - __stream_ = ::FindFirstFile(root.c_str(), &__data_); + if (root.native().empty()) { + ec = make_error_code(errc::no_such_file_or_directory); + return; + } + __stream_ = ::FindFirstFileW((root / "*").c_str(), &__data_); if (__stream_ == INVALID_HANDLE_VALUE) { - ec = error_code(::GetLastError(), generic_category()); + ec = detail::make_windows_error(GetLastError()); const bool ignore_permission_denied = bool(opts & directory_options::skip_permission_denied); if (ignore_permission_denied && ec.value() == ERROR_ACCESS_DENIED) ec.clear(); return; } + if (!assign()) + advance(ec); } ~__dir_stream() noexcept { @@ -130,35 +140,39 @@ 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; - // FIXME: Cache more of this - //directory_entry::__cached_data cdata; - //cdata.__type_ = get_file_type(__data_); - //cdata.__size_ = get_file_size(__data_); - //cdata.__write_time_ = get_write_time(__data_); - __entry_.__assign_iter_entry( - __root_ / __data_.cFileName, - directory_entry::__create_iter_result(detail::get_file_type(__data))); - return true; + while (::FindNextFileW(__stream_, &__data_)) { + if (assign()) + return true; } - ec = error_code(::GetLastError(), generic_category()); close(); return false; } + bool assign() { + if (!wcscmp(__data_.cFileName, L".") || !wcscmp(__data_.cFileName, L"..")) + return false; + // FIXME: Cache more of this + //directory_entry::__cached_data cdata; + //cdata.__type_ = get_file_type(__data_); + //cdata.__size_ = get_file_size(__data_); + //cdata.__write_time_ = get_write_time(__data_); + __entry_.__assign_iter_entry( + __root_ / __data_.cFileName, + directory_entry::__create_iter_result(detail::get_file_type(__data_))); + return true; + } + private: error_code close() noexcept { error_code ec; if (!::FindClose(__stream_)) - ec = error_code(::GetLastError(), generic_category()); + ec = detail::make_windows_error(GetLastError()); __stream_ = INVALID_HANDLE_VALUE; return ec; } HANDLE __stream_{INVALID_HANDLE_VALUE}; - WIN32_FIND_DATA __data_; + WIN32_FIND_DATAW __data_; public: path __root_; Index: libcxx/src/filesystem/filesystem_common.h =================================================================== --- libcxx/src/filesystem/filesystem_common.h +++ libcxx/src/filesystem/filesystem_common.h @@ -17,11 +17,13 @@ #include "cstdlib" #include "ctime" +#if !defined(_LIBCPP_WIN32API) #include #include #include #include // for ::utimes as used in __last_write_time #include /* values for fchmodat */ +#endif #include "../include/apple_availability.h" @@ -47,6 +49,12 @@ _LIBCPP_BEGIN_NAMESPACE_FILESYSTEM namespace detail { + +#if defined(_LIBCPP_WIN32API) +// Non anonymous, to allow access from two translation units. +errc __win_err_to_errc(int err); +#endif + namespace { static string format_string_imp(const char* msg, ...) { @@ -118,6 +126,12 @@ return error_code(errno, generic_category()); } +#if defined(_LIBCPP_WIN32API) +error_code make_windows_error(int err) { + return make_error_code(__win_err_to_errc(err)); +} +#endif + template T error_value(); template <> Index: libcxx/src/filesystem/operations.cpp =================================================================== --- libcxx/src/filesystem/operations.cpp +++ libcxx/src/filesystem/operations.cpp @@ -317,6 +317,76 @@ // POSIX HELPERS +#if defined(_LIBCPP_WIN32API) +// A separate namespace scope, to define the non-anonymous __win_err_to_errc +// which is accessed from multiple translation units. +namespace detail { +namespace { +constexpr struct { + DWORD win; + errc errc; +} win_error_mapping[] = { + { ERROR_ACCESS_DENIED, errc::permission_denied }, + { ERROR_ALREADY_EXISTS, errc::file_exists }, + { ERROR_BAD_NETPATH, errc::no_such_file_or_directory }, + { ERROR_BAD_UNIT, errc::no_such_device }, + { ERROR_BROKEN_PIPE, errc::broken_pipe }, + { ERROR_BUFFER_OVERFLOW, errc::filename_too_long }, + { ERROR_BUSY, errc::device_or_resource_busy }, + { ERROR_BUSY_DRIVE, errc::device_or_resource_busy }, + { ERROR_CANNOT_MAKE, errc::permission_denied }, + { ERROR_CANTOPEN, errc::io_error }, + { ERROR_CANTREAD, errc::io_error }, + { ERROR_CANTWRITE, errc::io_error }, + { ERROR_CURRENT_DIRECTORY, errc::permission_denied }, + { ERROR_DEV_NOT_EXIST, errc::no_such_device }, + { ERROR_DEVICE_IN_USE, errc::device_or_resource_busy }, + { ERROR_DIR_NOT_EMPTY, errc::directory_not_empty }, + { ERROR_DIRECTORY, errc::invalid_argument }, + { ERROR_DISK_FULL, errc::no_space_on_device }, + { ERROR_FILE_EXISTS, errc::file_exists }, + { ERROR_FILE_NOT_FOUND, errc::no_such_file_or_directory }, + { ERROR_HANDLE_DISK_FULL, errc::no_space_on_device }, + { ERROR_INVALID_ACCESS, errc::permission_denied }, + { ERROR_INVALID_DRIVE, errc::no_such_device }, + { ERROR_INVALID_FUNCTION, errc::function_not_supported }, + { ERROR_INVALID_HANDLE, errc::invalid_argument }, + { ERROR_INVALID_NAME, errc::no_such_file_or_directory }, + { ERROR_INVALID_PARAMETER, errc::invalid_argument }, + { ERROR_LOCK_VIOLATION, errc::no_lock_available }, + { ERROR_LOCKED, errc::no_lock_available }, + { ERROR_NEGATIVE_SEEK, errc::invalid_argument }, + { ERROR_NOACCESS, errc::permission_denied }, + { ERROR_NOT_ENOUGH_MEMORY, errc::not_enough_memory }, + { ERROR_NOT_READY, errc::resource_unavailable_try_again }, + { ERROR_NOT_SAME_DEVICE, errc::cross_device_link }, + { ERROR_NOT_SUPPORTED, errc::not_supported }, + { ERROR_OPEN_FAILED, errc::io_error }, + { ERROR_OPEN_FILES, errc::device_or_resource_busy }, + { ERROR_OPERATION_ABORTED, errc::operation_canceled }, + { ERROR_OUTOFMEMORY, errc::not_enough_memory }, + { ERROR_PATH_NOT_FOUND, errc::no_such_file_or_directory }, + { ERROR_READ_FAULT, errc::io_error }, + { ERROR_REPARSE_TAG_INVALID, errc::invalid_argument }, + { ERROR_RETRY, errc::resource_unavailable_try_again }, + { ERROR_SEEK, errc::io_error }, + { ERROR_SHARING_VIOLATION, errc::permission_denied }, + { ERROR_TOO_MANY_OPEN_FILES, errc::too_many_files_open }, + { ERROR_WRITE_FAULT, errc::io_error }, + { ERROR_WRITE_PROTECT, errc::permission_denied }, +}; +} // namespace + +errc __win_err_to_errc(int err) { + for (const auto &pair : win_error_mapping) + if (pair.win == static_cast(err)) + return pair.errc; + return errc::invalid_argument; +} + +} // namespace detail +#endif + namespace detail { namespace {