diff --git a/libcxx/src/filesystem/directory_iterator.cpp b/libcxx/src/filesystem/directory_iterator.cpp --- a/libcxx/src/filesystem/directory_iterator.cpp +++ b/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 @@ -72,16 +73,20 @@ } } #else +// defined(_LIBCPP_WIN32API) -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 +115,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 +141,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_; diff --git a/libcxx/src/filesystem/filesystem_common.h b/libcxx/src/filesystem/filesystem_common.h --- a/libcxx/src/filesystem/filesystem_common.h +++ b/libcxx/src/filesystem/filesystem_common.h @@ -17,11 +17,13 @@ #include "cstdlib" #include "ctime" -#include -#include -#include -#include // for ::utimes as used in __last_write_time -#include /* values for fchmodat */ +#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 <> diff --git a/libcxx/src/filesystem/operations.cpp b/libcxx/src/filesystem/operations.cpp --- a/libcxx/src/filesystem/operations.cpp +++ b/libcxx/src/filesystem/operations.cpp @@ -309,6 +309,73 @@ // POSIX HELPERS +#if defined(_LIBCPP_WIN32API) +namespace detail { + +errc __win_err_to_errc(int err) { + 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}, + }; + + 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 {