diff --git a/include/__filesystem/directory_entry.h b/include/__filesystem/directory_entry.h index 016ad94..90e44f5 100644 --- a/include/__filesystem/directory_entry.h +++ b/include/__filesystem/directory_entry.h @@ -202,7 +202,9 @@ private: _IterNonSymlink, _RefreshSymlink, _RefreshSymlinkUnresolved, - _RefreshNonSymlink + _RefreshNonSymlink, + _IterCachedSymlink, + _IterCachedNonSymlink }; struct __cached_data { @@ -241,6 +243,29 @@ private: return __data; } + _LIBCPP_HIDE_FROM_ABI static __cached_data + __create_iter_cached_result(file_type __ft, uintmax_t __size, perms __perm, file_time_type __write_time) { + __cached_data __data; + __data.__type_ = __ft; + __data.__size_ = __size; + __data.__write_time_ = __write_time; + if (__ft == file_type::symlink) + __data.__sym_perms_ = __perm; + else + __data.__non_sym_perms_ = __perm; + __data.__cache_type_ = [&]() { + switch (__ft) { + case file_type::none: + return _Empty; + case file_type::symlink: + return _IterCachedSymlink; + default: + return _IterCachedNonSymlink; + } + }(); + return __data; + } + _LIBCPP_HIDE_FROM_ABI void __assign_iter_entry(_Path&& __p, __cached_data __dt) { __p_ = std::move(__p); __data_ = __dt; @@ -282,13 +307,15 @@ private: case _Empty: return __symlink_status(__p_, __ec).type(); case _IterSymlink: + case _IterCachedSymlink: case _RefreshSymlink: case _RefreshSymlinkUnresolved: if (__ec) __ec->clear(); return file_type::symlink; + case _IterCachedNonSymlink: case _IterNonSymlink: - case _RefreshNonSymlink: + case _RefreshNonSymlink: { file_status __st(__data_.__type_); if (__ec && !filesystem::exists(__st)) *__ec = make_error_code(errc::no_such_file_or_directory); @@ -296,6 +323,7 @@ private: __ec->clear(); return __data_.__type_; } + } __libcpp_unreachable(); } @@ -303,8 +331,10 @@ private: switch (__data_.__cache_type_) { case _Empty: case _IterSymlink: + case _IterCachedSymlink: case _RefreshSymlinkUnresolved: return __status(__p_, __ec).type(); + case _IterCachedNonSymlink: case _IterNonSymlink: case _RefreshNonSymlink: case _RefreshSymlink: { @@ -324,8 +354,10 @@ private: case _Empty: case _IterNonSymlink: case _IterSymlink: + case _IterCachedSymlink: case _RefreshSymlinkUnresolved: return __status(__p_, __ec); + case _IterCachedNonSymlink: case _RefreshNonSymlink: case _RefreshSymlink: return file_status(__get_ft(__ec), __data_.__non_sym_perms_); @@ -339,8 +371,10 @@ private: case _IterNonSymlink: case _IterSymlink: return __symlink_status(__p_, __ec); + case _IterCachedNonSymlink: case _RefreshNonSymlink: return file_status(__get_sym_ft(__ec), __data_.__non_sym_perms_); + case _IterCachedSymlink: case _RefreshSymlink: case _RefreshSymlinkUnresolved: return file_status(__get_sym_ft(__ec), __data_.__sym_perms_); @@ -353,8 +387,10 @@ private: case _Empty: case _IterNonSymlink: case _IterSymlink: + case _IterCachedSymlink: case _RefreshSymlinkUnresolved: return filesystem::__file_size(__p_, __ec); + case _IterCachedNonSymlink: case _RefreshSymlink: case _RefreshNonSymlink: { error_code __m_ec; @@ -375,6 +411,8 @@ private: case _Empty: case _IterNonSymlink: case _IterSymlink: + case _IterCachedNonSymlink: + case _IterCachedSymlink: case _RefreshSymlinkUnresolved: return filesystem::__hard_link_count(__p_, __ec); case _RefreshSymlink: @@ -393,8 +431,10 @@ private: case _Empty: case _IterNonSymlink: case _IterSymlink: + case _IterCachedSymlink: case _RefreshSymlinkUnresolved: return filesystem::__last_write_time(__p_, __ec); + case _IterCachedNonSymlink: case _RefreshSymlink: case _RefreshNonSymlink: { error_code __m_ec; diff --git a/src/filesystem/directory_iterator.cpp b/src/filesystem/directory_iterator.cpp index dceb348..d7ed9a3 100644 --- a/src/filesystem/directory_iterator.cpp +++ b/src/filesystem/directory_iterator.cpp @@ -77,13 +77,13 @@ public: 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_))); + __root_ / __data_.cFileName, + directory_entry::__create_iter_cached_result( + detail::get_file_type(__data_), + detail::get_file_size(__data_), + detail::get_file_perm(__data_), + detail::get_write_time(__data_))); return true; } diff --git a/src/filesystem/file_descriptor.h b/src/filesystem/file_descriptor.h index 50178ff..2c9e0d7 100644 --- a/src/filesystem/file_descriptor.h +++ b/src/filesystem/file_descriptor.h @@ -97,11 +97,18 @@ inline uintmax_t get_file_size(const WIN32_FIND_DATAW& data) { return (static_cast(data.nFileSizeHigh) << 32) + data.nFileSizeLow; } inline file_time_type get_write_time(const WIN32_FIND_DATAW& data) { - ULARGE_INTEGER tmp; + using detail::fs_time; const FILETIME& time = data.ftLastWriteTime; - tmp.u.LowPart = time.dwLowDateTime; - tmp.u.HighPart = time.dwHighDateTime; - return file_time_type(file_time_type::duration(tmp.QuadPart)); + auto ts = filetime_to_timespec(time); + if (!fs_time::is_representable(ts)) + return file_time_type::min(); + return fs_time::convert_from_timespec(ts); +} +inline perms get_file_perm(const WIN32_FIND_DATAW& data) { + unsigned st_mode = 0555; // Read-only + if (!(data.dwFileAttributes & FILE_ATTRIBUTE_READONLY)) + st_mode |= 0222; // Write + return static_cast(st_mode) & perms::mask; } #endif // !_LIBCPP_WIN32API