diff --git a/include/__filesystem/directory_entry.h b/include/__filesystem/directory_entry.h index bb7a061..a839bcf 100644 --- a/include/__filesystem/directory_entry.h +++ b/include/__filesystem/directory_entry.h @@ -271,6 +271,8 @@ private: _Empty, _IterSymlink, _IterNonSymlink, + _IterCachedSymlink, + _IterCachedNonSymlink, _RefreshSymlink, _RefreshSymlinkUnresolved, _RefreshNonSymlink @@ -315,6 +317,30 @@ private: return __data; } + _LIBCPP_INLINE_VISIBILITY + 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_INLINE_VISIBILITY void __assign_iter_entry(_Path&& __p, __cached_data __dt) { __p_ = _VSTD::move(__p); @@ -359,12 +385,14 @@ 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 _IterNonSymlink: + case _IterCachedNonSymlink: case _RefreshNonSymlink: file_status __st(__data_.__type_); if (__ec && !_VSTD_FS::exists(__st)) @@ -381,9 +409,11 @@ private: switch (__data_.__cache_type_) { case _Empty: case _IterSymlink: + case _IterCachedSymlink: case _RefreshSymlinkUnresolved: return __status(__p_, __ec).type(); case _IterNonSymlink: + case _IterCachedNonSymlink: case _RefreshNonSymlink: case _RefreshSymlink: { file_status __st(__data_.__type_); @@ -403,8 +433,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_); @@ -419,8 +451,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_); @@ -434,8 +468,10 @@ private: case _Empty: case _IterNonSymlink: case _IterSymlink: + case _IterCachedSymlink: case _RefreshSymlinkUnresolved: return _VSTD_FS::__file_size(__p_, __ec); + case _IterCachedNonSymlink: case _RefreshSymlink: case _RefreshNonSymlink: { error_code __m_ec; @@ -459,6 +495,8 @@ private: case _Empty: case _IterNonSymlink: case _IterSymlink: + case _IterCachedNonSymlink: + case _IterCachedSymlink: case _RefreshSymlinkUnresolved: return _VSTD_FS::__hard_link_count(__p_, __ec); case _RefreshSymlink: @@ -480,6 +518,8 @@ private: case _IterSymlink: case _RefreshSymlinkUnresolved: return _VSTD_FS::__last_write_time(__p_, __ec); + case _IterCachedNonSymlink: + case _IterCachedSymlink: case _RefreshSymlink: case _RefreshNonSymlink: { error_code __m_ec; diff --git a/src/filesystem/directory_iterator.cpp b/src/filesystem/directory_iterator.cpp index 151fb2f..cf9d631 100644 --- a/src/filesystem/directory_iterator.cpp +++ b/src/filesystem/directory_iterator.cpp @@ -80,14 +80,12 @@ 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_))); + 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 d3a668f..7bc0a4d 100644 --- a/src/filesystem/file_descriptor.h +++ b/src/filesystem/file_descriptor.h @@ -99,11 +99,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