1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
|
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<uint64_t>(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<perms>(st_mode) & perms::mask;
}
#endif // !_LIBCPP_WIN32API
|