diff options
author | Li Jin <dragon-fly@qq.com> | 2021-04-21 09:36:25 +0800 |
---|---|---|
committer | Li Jin <dragon-fly@qq.com> | 2021-04-21 09:36:25 +0800 |
commit | b7bdf7d5d36825a1a750a74641f6d374dec5d67a (patch) | |
tree | 6b27eb6590e07c07f378305c51d0f5e0779faa83 /src/ghc | |
parent | b86e5af605a170a3559df0165eac3cb6b665dc49 (diff) | |
download | yuescript-b7bdf7d5d36825a1a750a74641f6d374dec5d67a.tar.gz yuescript-b7bdf7d5d36825a1a750a74641f6d374dec5d67a.tar.bz2 yuescript-b7bdf7d5d36825a1a750a74641f6d374dec5d67a.zip |
adjust some folder levels.
Diffstat (limited to 'src/ghc')
-rw-r--r-- | src/ghc/filesystem.hpp | 5210 | ||||
-rw-r--r-- | src/ghc/fs_std.hpp | 56 |
2 files changed, 0 insertions, 5266 deletions
diff --git a/src/ghc/filesystem.hpp b/src/ghc/filesystem.hpp deleted file mode 100644 index 7951369..0000000 --- a/src/ghc/filesystem.hpp +++ /dev/null | |||
@@ -1,5210 +0,0 @@ | |||
1 | //--------------------------------------------------------------------------------------- | ||
2 | // | ||
3 | // ghc::filesystem - A C++17-like filesystem implementation for C++11/C++14/C++17 | ||
4 | // | ||
5 | //--------------------------------------------------------------------------------------- | ||
6 | // | ||
7 | // Copyright (c) 2018, Steffen Schümann <s.schuemann@pobox.com> | ||
8 | // | ||
9 | // Permission is hereby granted, free of charge, to any person obtaining a copy | ||
10 | // of this software and associated documentation files (the "Software"), to deal | ||
11 | // in the Software without restriction, including without limitation the rights | ||
12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
13 | // copies of the Software, and to permit persons to whom the Software is | ||
14 | // furnished to do so, subject to the following conditions: | ||
15 | // | ||
16 | // The above copyright notice and this permission notice shall be included in all | ||
17 | // copies or substantial portions of the Software. | ||
18 | // | ||
19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
25 | // SOFTWARE. | ||
26 | // | ||
27 | //--------------------------------------------------------------------------------------- | ||
28 | // | ||
29 | // To dynamically select std::filesystem where available, you could use: | ||
30 | // | ||
31 | // #if defined(__cplusplus) && __cplusplus >= 201703L && defined(__has_include) && __has_include(<filesystem>) | ||
32 | // #include <filesystem> | ||
33 | // namespace fs = std::filesystem; | ||
34 | // #else | ||
35 | // #include <ghc/filesystem.hpp> | ||
36 | // namespace fs = ghc::filesystem; | ||
37 | // #endif | ||
38 | // | ||
39 | //--------------------------------------------------------------------------------------- | ||
40 | #ifndef GHC_FILESYSTEM_H | ||
41 | #define GHC_FILESYSTEM_H | ||
42 | |||
43 | // #define BSD manifest constant only in | ||
44 | // sys/param.h | ||
45 | #ifndef _WIN32 | ||
46 | #include <sys/param.h> | ||
47 | #endif | ||
48 | |||
49 | #ifndef GHC_OS_DETECTED | ||
50 | #if defined(__APPLE__) && defined(__MACH__) | ||
51 | #define GHC_OS_MACOS | ||
52 | #elif defined(__linux__) | ||
53 | #define GHC_OS_LINUX | ||
54 | #if defined(__ANDROID__) | ||
55 | #define GHC_OS_ANDROID | ||
56 | #endif | ||
57 | #elif defined(_WIN64) | ||
58 | #define GHC_OS_WINDOWS | ||
59 | #define GHC_OS_WIN64 | ||
60 | #elif defined(_WIN32) | ||
61 | #define GHC_OS_WINDOWS | ||
62 | #define GHC_OS_WIN32 | ||
63 | #elif defined(__svr4__) | ||
64 | #define GHC_OS_SYS5R4 | ||
65 | #elif defined(BSD) | ||
66 | #define GHC_OS_BSD | ||
67 | #else | ||
68 | #error "Operating system currently not supported!" | ||
69 | #endif | ||
70 | #define GHC_OS_DETECTED | ||
71 | #endif | ||
72 | |||
73 | #if defined(GHC_FILESYSTEM_IMPLEMENTATION) | ||
74 | #define GHC_EXPAND_IMPL | ||
75 | #define GHC_INLINE | ||
76 | #ifdef GHC_OS_WINDOWS | ||
77 | #define GHC_FS_API | ||
78 | #define GHC_FS_API_CLASS | ||
79 | #else | ||
80 | #define GHC_FS_API __attribute__((visibility("default"))) | ||
81 | #define GHC_FS_API_CLASS __attribute__((visibility("default"))) | ||
82 | #endif | ||
83 | #elif defined(GHC_FILESYSTEM_FWD) | ||
84 | #define GHC_INLINE | ||
85 | #ifdef GHC_OS_WINDOWS | ||
86 | #define GHC_FS_API extern | ||
87 | #define GHC_FS_API_CLASS | ||
88 | #else | ||
89 | #define GHC_FS_API extern | ||
90 | #define GHC_FS_API_CLASS | ||
91 | #endif | ||
92 | #else | ||
93 | #define GHC_EXPAND_IMPL | ||
94 | #define GHC_INLINE inline | ||
95 | #define GHC_FS_API | ||
96 | #define GHC_FS_API_CLASS | ||
97 | #endif | ||
98 | |||
99 | #ifdef GHC_EXPAND_IMPL | ||
100 | |||
101 | #ifdef GHC_OS_WINDOWS | ||
102 | #include <windows.h> | ||
103 | // additional includes | ||
104 | #include <shellapi.h> | ||
105 | #include <sys/stat.h> | ||
106 | #include <sys/types.h> | ||
107 | #include <wchar.h> | ||
108 | #include <winioctl.h> | ||
109 | #else | ||
110 | #include <dirent.h> | ||
111 | #include <fcntl.h> | ||
112 | #include <langinfo.h> | ||
113 | #include <sys/param.h> | ||
114 | #include <sys/stat.h> | ||
115 | #include <sys/statvfs.h> | ||
116 | #include <sys/time.h> | ||
117 | #include <sys/types.h> | ||
118 | #include <unistd.h> | ||
119 | #include <limits.h> | ||
120 | #ifdef GHC_OS_ANDROID | ||
121 | #include <android/api-level.h> | ||
122 | #endif | ||
123 | #endif | ||
124 | #ifdef GHC_OS_MACOS | ||
125 | #include <Availability.h> | ||
126 | #endif | ||
127 | |||
128 | #include <algorithm> | ||
129 | #include <cctype> | ||
130 | #include <chrono> | ||
131 | #include <clocale> | ||
132 | #include <cstdlib> | ||
133 | #include <cstring> | ||
134 | #include <fstream> | ||
135 | #include <functional> | ||
136 | #include <memory> | ||
137 | #include <stack> | ||
138 | #include <stdexcept> | ||
139 | #include <string> | ||
140 | #include <system_error> | ||
141 | #include <type_traits> | ||
142 | #include <utility> | ||
143 | #include <vector> | ||
144 | |||
145 | #else // GHC_EXPAND_IMPL | ||
146 | #include <chrono> | ||
147 | #include <fstream> | ||
148 | #include <memory> | ||
149 | #include <stack> | ||
150 | #include <stdexcept> | ||
151 | #include <string> | ||
152 | #include <system_error> | ||
153 | #ifdef GHC_OS_WINDOWS | ||
154 | #include <vector> | ||
155 | #endif | ||
156 | #endif // GHC_EXPAND_IMPL | ||
157 | |||
158 | //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||
159 | // Behaviour Switches (see README.md, should match the config in test/filesystem_test.cpp): | ||
160 | //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||
161 | // LWG #2682 disables the since then invalid use of the copy option create_symlinks on directories | ||
162 | // configure LWG conformance () | ||
163 | #define LWG_2682_BEHAVIOUR | ||
164 | //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||
165 | // LWG #2395 makes crate_directory/create_directories not emit an error if there is a regular | ||
166 | // file with that name, it is superceded by P1164R1, so only activate if really needed | ||
167 | // #define LWG_2935_BEHAVIOUR | ||
168 | //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||
169 | // LWG #2937 enforces that fs::equivalent emits an error, if !fs::exists(p1)||!exists(p2) | ||
170 | #define LWG_2937_BEHAVIOUR | ||
171 | //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||
172 | // UTF8-Everywhere is the original behaviour of ghc::filesystem. With this define you can | ||
173 | // enable the more standard conforming implementation option that uses wstring on Windows | ||
174 | // as ghc::filesystem::string_type. | ||
175 | // #define GHC_WIN_WSTRING_STRING_TYPE | ||
176 | //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||
177 | // Raise errors/exceptions when invalid unicode codepoints or UTF-8 sequences are found, | ||
178 | // instead of replacing them with the unicode replacement character (U+FFFD). | ||
179 | // #define GHC_RAISE_UNICODE_ERRORS | ||
180 | //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||
181 | |||
182 | // ghc::filesystem version in decimal (major * 10000 + minor * 100 + patch) | ||
183 | #define GHC_FILESYSTEM_VERSION 10301L | ||
184 | |||
185 | namespace ghc { | ||
186 | namespace filesystem { | ||
187 | |||
188 | // temporary existing exception type for yet unimplemented parts | ||
189 | class GHC_FS_API_CLASS not_implemented_exception : public std::logic_error | ||
190 | { | ||
191 | public: | ||
192 | not_implemented_exception() | ||
193 | : std::logic_error("function not implemented yet.") | ||
194 | { | ||
195 | } | ||
196 | }; | ||
197 | |||
198 | template<typename char_type> | ||
199 | class path_helper_base | ||
200 | { | ||
201 | public: | ||
202 | using value_type = char_type; | ||
203 | #ifdef GHC_OS_WINDOWS | ||
204 | static constexpr value_type preferred_separator = '\\'; | ||
205 | #else | ||
206 | static constexpr value_type preferred_separator = '/'; | ||
207 | #endif | ||
208 | }; | ||
209 | |||
210 | #if __cplusplus < 201703L | ||
211 | template <typename char_type> | ||
212 | constexpr char_type path_helper_base<char_type>::preferred_separator; | ||
213 | #endif | ||
214 | |||
215 | // 30.10.8 class path | ||
216 | class GHC_FS_API_CLASS path | ||
217 | #if defined(GHC_OS_WINDOWS) && defined(GHC_WIN_WSTRING_STRING_TYPE) | ||
218 | #define GHC_USE_WCHAR_T | ||
219 | : private path_helper_base<std::wstring::value_type> | ||
220 | { | ||
221 | public: | ||
222 | using path_helper_base<std::wstring::value_type>::value_type; | ||
223 | #else | ||
224 | : private path_helper_base<std::string::value_type> | ||
225 | { | ||
226 | public: | ||
227 | using path_helper_base<std::string::value_type>::value_type; | ||
228 | #endif | ||
229 | using string_type = std::basic_string<value_type>; | ||
230 | using path_helper_base<value_type>::preferred_separator; | ||
231 | |||
232 | // 30.10.10.1 enumeration format | ||
233 | /// The path format in wich the constructor argument is given. | ||
234 | enum format { | ||
235 | generic_format, ///< The generic format, internally used by | ||
236 | ///< ghc::filesystem::path with slashes | ||
237 | native_format, ///< The format native to the current platform this code | ||
238 | ///< is build for | ||
239 | auto_format, ///< Try to auto-detect the format, fallback to native | ||
240 | }; | ||
241 | |||
242 | template <class T> | ||
243 | struct _is_basic_string : std::false_type | ||
244 | { | ||
245 | }; | ||
246 | template <class CharT, class Traits, class Alloc> | ||
247 | struct _is_basic_string<std::basic_string<CharT, Traits, Alloc>> : std::true_type | ||
248 | { | ||
249 | }; | ||
250 | #ifdef __cpp_lib_string_view | ||
251 | template <class CharT> | ||
252 | struct _is_basic_string<std::basic_string_view<CharT>> : std::true_type | ||
253 | { | ||
254 | }; | ||
255 | #endif | ||
256 | |||
257 | template <typename T1, typename T2 = void> | ||
258 | using path_type = typename std::enable_if<!std::is_same<path, T1>::value, path>::type; | ||
259 | #ifdef GHC_USE_WCHAR_T | ||
260 | template <typename T> | ||
261 | using path_from_string = typename std::enable_if<_is_basic_string<T>::value || std::is_same<char const*, typename std::decay<T>::type>::value || std::is_same<char*, typename std::decay<T>::type>::value || | ||
262 | std::is_same<wchar_t const*, typename std::decay<T>::type>::value || std::is_same<wchar_t*, typename std::decay<T>::type>::value, | ||
263 | path>::type; | ||
264 | template <typename T> | ||
265 | using path_type_EcharT = typename std::enable_if<std::is_same<T, char>::value || std::is_same<T, char16_t>::value || std::is_same<T, char32_t>::value, path>::type; | ||
266 | #else | ||
267 | template <typename T> | ||
268 | using path_from_string = typename std::enable_if<_is_basic_string<T>::value || std::is_same<char const*, typename std::decay<T>::type>::value || std::is_same<char*, typename std::decay<T>::type>::value, path>::type; | ||
269 | template <typename T> | ||
270 | using path_type_EcharT = typename std::enable_if<std::is_same<T, char>::value || std::is_same<T, char16_t>::value || std::is_same<T, char32_t>::value || std::is_same<T, wchar_t>::value, path>::type; | ||
271 | #endif | ||
272 | // 30.10.8.4.1 constructors and destructor | ||
273 | path() noexcept; | ||
274 | path(const path& p); | ||
275 | path(path&& p) noexcept; | ||
276 | path(string_type&& source, format fmt = auto_format); | ||
277 | template <class Source, typename = path_from_string<Source>> | ||
278 | path(const Source& source, format fmt = auto_format); | ||
279 | template <class InputIterator> | ||
280 | path(InputIterator first, InputIterator last, format fmt = auto_format); | ||
281 | template <class Source, typename = path_from_string<Source>> | ||
282 | path(const Source& source, const std::locale& loc, format fmt = auto_format); | ||
283 | template <class InputIterator> | ||
284 | path(InputIterator first, InputIterator last, const std::locale& loc, format fmt = auto_format); | ||
285 | ~path(); | ||
286 | |||
287 | // 30.10.8.4.2 assignments | ||
288 | path& operator=(const path& p); | ||
289 | path& operator=(path&& p) noexcept; | ||
290 | path& operator=(string_type&& source); | ||
291 | path& assign(string_type&& source); | ||
292 | template <class Source> | ||
293 | path& operator=(const Source& source); | ||
294 | template <class Source> | ||
295 | path& assign(const Source& source); | ||
296 | template <class InputIterator> | ||
297 | path& assign(InputIterator first, InputIterator last); | ||
298 | |||
299 | // 30.10.8.4.3 appends | ||
300 | path& operator/=(const path& p); | ||
301 | template <class Source> | ||
302 | path& operator/=(const Source& source); | ||
303 | template <class Source> | ||
304 | path& append(const Source& source); | ||
305 | template <class InputIterator> | ||
306 | path& append(InputIterator first, InputIterator last); | ||
307 | |||
308 | // 30.10.8.4.4 concatenation | ||
309 | path& operator+=(const path& x); | ||
310 | path& operator+=(const string_type& x); | ||
311 | #ifdef __cpp_lib_string_view | ||
312 | path& operator+=(std::basic_string_view<value_type> x); | ||
313 | #endif | ||
314 | path& operator+=(const value_type* x); | ||
315 | path& operator+=(value_type x); | ||
316 | template <class Source> | ||
317 | path_from_string<Source>& operator+=(const Source& x); | ||
318 | template <class EcharT> | ||
319 | path_type_EcharT<EcharT>& operator+=(EcharT x); | ||
320 | template <class Source> | ||
321 | path& concat(const Source& x); | ||
322 | template <class InputIterator> | ||
323 | path& concat(InputIterator first, InputIterator last); | ||
324 | |||
325 | // 30.10.8.4.5 modifiers | ||
326 | void clear() noexcept; | ||
327 | path& make_preferred(); | ||
328 | path& remove_filename(); | ||
329 | path& replace_filename(const path& replacement); | ||
330 | path& replace_extension(const path& replacement = path()); | ||
331 | void swap(path& rhs) noexcept; | ||
332 | |||
333 | // 30.10.8.4.6 native format observers | ||
334 | const string_type& native() const; // this implementation doesn't support noexcept for native() | ||
335 | const value_type* c_str() const; // this implementation doesn't support noexcept for c_str() | ||
336 | operator string_type() const; | ||
337 | template <class EcharT, class traits = std::char_traits<EcharT>, class Allocator = std::allocator<EcharT>> | ||
338 | std::basic_string<EcharT, traits, Allocator> string(const Allocator& a = Allocator()) const; | ||
339 | std::string string() const; | ||
340 | std::wstring wstring() const; | ||
341 | std::string u8string() const; | ||
342 | std::u16string u16string() const; | ||
343 | std::u32string u32string() const; | ||
344 | |||
345 | // 30.10.8.4.7 generic format observers | ||
346 | template <class EcharT, class traits = std::char_traits<EcharT>, class Allocator = std::allocator<EcharT>> | ||
347 | std::basic_string<EcharT, traits, Allocator> generic_string(const Allocator& a = Allocator()) const; | ||
348 | const std::string& generic_string() const; // this is different from the standard, that returns by value | ||
349 | std::wstring generic_wstring() const; | ||
350 | std::string generic_u8string() const; | ||
351 | std::u16string generic_u16string() const; | ||
352 | std::u32string generic_u32string() const; | ||
353 | |||
354 | // 30.10.8.4.8 compare | ||
355 | int compare(const path& p) const noexcept; | ||
356 | int compare(const string_type& s) const; | ||
357 | #ifdef __cpp_lib_string_view | ||
358 | int compare(std::basic_string_view<value_type> s) const; | ||
359 | #endif | ||
360 | int compare(const value_type* s) const; | ||
361 | |||
362 | // 30.10.8.4.9 decomposition | ||
363 | path root_name() const; | ||
364 | path root_directory() const; | ||
365 | path root_path() const; | ||
366 | path relative_path() const; | ||
367 | path parent_path() const; | ||
368 | path filename() const; | ||
369 | path stem() const; | ||
370 | path extension() const; | ||
371 | |||
372 | // 30.10.8.4.10 query | ||
373 | bool empty() const noexcept; | ||
374 | bool has_root_name() const; | ||
375 | bool has_root_directory() const; | ||
376 | bool has_root_path() const; | ||
377 | bool has_relative_path() const; | ||
378 | bool has_parent_path() const; | ||
379 | bool has_filename() const; | ||
380 | bool has_stem() const; | ||
381 | bool has_extension() const; | ||
382 | bool is_absolute() const; | ||
383 | bool is_relative() const; | ||
384 | |||
385 | // 30.10.8.4.11 generation | ||
386 | path lexically_normal() const; | ||
387 | path lexically_relative(const path& base) const; | ||
388 | path lexically_proximate(const path& base) const; | ||
389 | |||
390 | // 30.10.8.5 iterators | ||
391 | class iterator; | ||
392 | using const_iterator = iterator; | ||
393 | iterator begin() const; | ||
394 | iterator end() const; | ||
395 | |||
396 | private: | ||
397 | using impl_value_type = std::string::value_type; | ||
398 | using impl_string_type = std::basic_string<impl_value_type>; | ||
399 | friend class directory_iterator; | ||
400 | void append_name(const char* name); | ||
401 | static constexpr impl_value_type generic_separator = '/'; | ||
402 | template <typename InputIterator> | ||
403 | class input_iterator_range | ||
404 | { | ||
405 | public: | ||
406 | typedef InputIterator iterator; | ||
407 | typedef InputIterator const_iterator; | ||
408 | typedef typename InputIterator::difference_type difference_type; | ||
409 | |||
410 | input_iterator_range(const InputIterator& first, const InputIterator& last) | ||
411 | : _first(first) | ||
412 | , _last(last) | ||
413 | { | ||
414 | } | ||
415 | |||
416 | InputIterator begin() const { return _first; } | ||
417 | InputIterator end() const { return _last; } | ||
418 | |||
419 | private: | ||
420 | InputIterator _first; | ||
421 | InputIterator _last; | ||
422 | }; | ||
423 | friend void swap(path& lhs, path& rhs) noexcept; | ||
424 | friend size_t hash_value(const path& p) noexcept; | ||
425 | static void postprocess_path_with_format(impl_string_type& p, format fmt); | ||
426 | impl_string_type _path; | ||
427 | #ifdef GHC_OS_WINDOWS | ||
428 | impl_string_type native_impl() const; | ||
429 | mutable string_type _native_cache; | ||
430 | #else | ||
431 | const impl_string_type& native_impl() const; | ||
432 | #endif | ||
433 | }; | ||
434 | |||
435 | // 30.10.8.6 path non-member functions | ||
436 | GHC_FS_API void swap(path& lhs, path& rhs) noexcept; | ||
437 | GHC_FS_API size_t hash_value(const path& p) noexcept; | ||
438 | GHC_FS_API bool operator==(const path& lhs, const path& rhs) noexcept; | ||
439 | GHC_FS_API bool operator!=(const path& lhs, const path& rhs) noexcept; | ||
440 | GHC_FS_API bool operator<(const path& lhs, const path& rhs) noexcept; | ||
441 | GHC_FS_API bool operator<=(const path& lhs, const path& rhs) noexcept; | ||
442 | GHC_FS_API bool operator>(const path& lhs, const path& rhs) noexcept; | ||
443 | GHC_FS_API bool operator>=(const path& lhs, const path& rhs) noexcept; | ||
444 | |||
445 | GHC_FS_API path operator/(const path& lhs, const path& rhs); | ||
446 | |||
447 | // 30.10.8.6.1 path inserter and extractor | ||
448 | template <class charT, class traits> | ||
449 | std::basic_ostream<charT, traits>& operator<<(std::basic_ostream<charT, traits>& os, const path& p); | ||
450 | template <class charT, class traits> | ||
451 | std::basic_istream<charT, traits>& operator>>(std::basic_istream<charT, traits>& is, path& p); | ||
452 | |||
453 | // 30.10.8.6.2 path factory functions | ||
454 | template <class Source, typename = path::path_from_string<Source>> | ||
455 | path u8path(const Source& source); | ||
456 | template <class InputIterator> | ||
457 | path u8path(InputIterator first, InputIterator last); | ||
458 | |||
459 | // 30.10.9 class filesystem_error | ||
460 | class GHC_FS_API_CLASS filesystem_error : public std::system_error | ||
461 | { | ||
462 | public: | ||
463 | filesystem_error(const std::string& what_arg, std::error_code ec); | ||
464 | filesystem_error(const std::string& what_arg, const path& p1, std::error_code ec); | ||
465 | filesystem_error(const std::string& what_arg, const path& p1, const path& p2, std::error_code ec); | ||
466 | const path& path1() const noexcept; | ||
467 | const path& path2() const noexcept; | ||
468 | const char* what() const noexcept override; | ||
469 | |||
470 | private: | ||
471 | std::string _what_arg; | ||
472 | std::error_code _ec; | ||
473 | path _p1, _p2; | ||
474 | }; | ||
475 | |||
476 | class GHC_FS_API_CLASS path::iterator | ||
477 | { | ||
478 | public: | ||
479 | using value_type = const path; | ||
480 | using difference_type = std::ptrdiff_t; | ||
481 | using pointer = const path*; | ||
482 | using reference = const path&; | ||
483 | using iterator_category = std::bidirectional_iterator_tag; | ||
484 | |||
485 | iterator(); | ||
486 | iterator(const impl_string_type::const_iterator& first, const impl_string_type::const_iterator& last, const impl_string_type::const_iterator& pos); | ||
487 | iterator& operator++(); | ||
488 | iterator operator++(int); | ||
489 | iterator& operator--(); | ||
490 | iterator operator--(int); | ||
491 | bool operator==(const iterator& other) const; | ||
492 | bool operator!=(const iterator& other) const; | ||
493 | reference operator*() const; | ||
494 | pointer operator->() const; | ||
495 | |||
496 | private: | ||
497 | impl_string_type::const_iterator increment(const std::string::const_iterator& pos) const; | ||
498 | impl_string_type::const_iterator decrement(const std::string::const_iterator& pos) const; | ||
499 | void updateCurrent(); | ||
500 | impl_string_type::const_iterator _first; | ||
501 | impl_string_type::const_iterator _last; | ||
502 | impl_string_type::const_iterator _root; | ||
503 | impl_string_type::const_iterator _iter; | ||
504 | path _current; | ||
505 | }; | ||
506 | |||
507 | struct space_info | ||
508 | { | ||
509 | uintmax_t capacity; | ||
510 | uintmax_t free; | ||
511 | uintmax_t available; | ||
512 | }; | ||
513 | |||
514 | // 30.10.10, enumerations | ||
515 | enum class file_type { | ||
516 | none, | ||
517 | not_found, | ||
518 | regular, | ||
519 | directory, | ||
520 | symlink, | ||
521 | block, | ||
522 | character, | ||
523 | fifo, | ||
524 | socket, | ||
525 | unknown, | ||
526 | }; | ||
527 | |||
528 | enum class perms : uint16_t { | ||
529 | none = 0, | ||
530 | |||
531 | owner_read = 0400, | ||
532 | owner_write = 0200, | ||
533 | owner_exec = 0100, | ||
534 | owner_all = 0700, | ||
535 | |||
536 | group_read = 040, | ||
537 | group_write = 020, | ||
538 | group_exec = 010, | ||
539 | group_all = 070, | ||
540 | |||
541 | others_read = 04, | ||
542 | others_write = 02, | ||
543 | others_exec = 01, | ||
544 | others_all = 07, | ||
545 | |||
546 | all = 0777, | ||
547 | set_uid = 04000, | ||
548 | set_gid = 02000, | ||
549 | sticky_bit = 01000, | ||
550 | |||
551 | mask = 07777, | ||
552 | unknown = 0xffff | ||
553 | }; | ||
554 | |||
555 | enum class perm_options : uint16_t { | ||
556 | replace = 3, | ||
557 | add = 1, | ||
558 | remove = 2, | ||
559 | nofollow = 4, | ||
560 | }; | ||
561 | |||
562 | enum class copy_options : uint16_t { | ||
563 | none = 0, | ||
564 | |||
565 | skip_existing = 1, | ||
566 | overwrite_existing = 2, | ||
567 | update_existing = 4, | ||
568 | |||
569 | recursive = 8, | ||
570 | |||
571 | copy_symlinks = 0x10, | ||
572 | skip_symlinks = 0x20, | ||
573 | |||
574 | directories_only = 0x40, | ||
575 | create_symlinks = 0x80, | ||
576 | create_hard_links = 0x100 | ||
577 | }; | ||
578 | |||
579 | enum class directory_options : uint16_t { | ||
580 | none = 0, | ||
581 | follow_directory_symlink = 1, | ||
582 | skip_permission_denied = 2, | ||
583 | }; | ||
584 | |||
585 | // 30.10.11 class file_status | ||
586 | class GHC_FS_API_CLASS file_status | ||
587 | { | ||
588 | public: | ||
589 | // 30.10.11.1 constructors and destructor | ||
590 | file_status() noexcept; | ||
591 | explicit file_status(file_type ft, perms prms = perms::unknown) noexcept; | ||
592 | file_status(const file_status&) noexcept; | ||
593 | file_status(file_status&&) noexcept; | ||
594 | ~file_status(); | ||
595 | // assignments: | ||
596 | file_status& operator=(const file_status&) noexcept; | ||
597 | file_status& operator=(file_status&&) noexcept; | ||
598 | // 30.10.11.3 modifiers | ||
599 | void type(file_type ft) noexcept; | ||
600 | void permissions(perms prms) noexcept; | ||
601 | // 30.10.11.2 observers | ||
602 | file_type type() const noexcept; | ||
603 | perms permissions() const noexcept; | ||
604 | |||
605 | private: | ||
606 | file_type _type; | ||
607 | perms _perms; | ||
608 | }; | ||
609 | |||
610 | using file_time_type = std::chrono::time_point<std::chrono::system_clock>; | ||
611 | |||
612 | // 30.10.12 Class directory_entry | ||
613 | class GHC_FS_API_CLASS directory_entry | ||
614 | { | ||
615 | public: | ||
616 | // 30.10.12.1 constructors and destructor | ||
617 | directory_entry() noexcept = default; | ||
618 | directory_entry(const directory_entry&) = default; | ||
619 | directory_entry(directory_entry&&) noexcept = default; | ||
620 | explicit directory_entry(const path& p); | ||
621 | directory_entry(const path& p, std::error_code& ec); | ||
622 | ~directory_entry(); | ||
623 | |||
624 | // assignments: | ||
625 | directory_entry& operator=(const directory_entry&) = default; | ||
626 | directory_entry& operator=(directory_entry&&) noexcept = default; | ||
627 | |||
628 | // 30.10.12.2 modifiers | ||
629 | void assign(const path& p); | ||
630 | void assign(const path& p, std::error_code& ec); | ||
631 | void replace_filename(const path& p); | ||
632 | void replace_filename(const path& p, std::error_code& ec); | ||
633 | void refresh(); | ||
634 | void refresh(std::error_code& ec) noexcept; | ||
635 | |||
636 | // 30.10.12.3 observers | ||
637 | const filesystem::path& path() const noexcept; | ||
638 | operator const filesystem::path&() const noexcept; | ||
639 | bool exists() const; | ||
640 | bool exists(std::error_code& ec) const noexcept; | ||
641 | bool is_block_file() const; | ||
642 | bool is_block_file(std::error_code& ec) const noexcept; | ||
643 | bool is_character_file() const; | ||
644 | bool is_character_file(std::error_code& ec) const noexcept; | ||
645 | bool is_directory() const; | ||
646 | bool is_directory(std::error_code& ec) const noexcept; | ||
647 | bool is_fifo() const; | ||
648 | bool is_fifo(std::error_code& ec) const noexcept; | ||
649 | bool is_other() const; | ||
650 | bool is_other(std::error_code& ec) const noexcept; | ||
651 | bool is_regular_file() const; | ||
652 | bool is_regular_file(std::error_code& ec) const noexcept; | ||
653 | bool is_socket() const; | ||
654 | bool is_socket(std::error_code& ec) const noexcept; | ||
655 | bool is_symlink() const; | ||
656 | bool is_symlink(std::error_code& ec) const noexcept; | ||
657 | uintmax_t file_size() const; | ||
658 | uintmax_t file_size(std::error_code& ec) const noexcept; | ||
659 | uintmax_t hard_link_count() const; | ||
660 | uintmax_t hard_link_count(std::error_code& ec) const noexcept; | ||
661 | file_time_type last_write_time() const; | ||
662 | file_time_type last_write_time(std::error_code& ec) const noexcept; | ||
663 | |||
664 | file_status status() const; | ||
665 | file_status status(std::error_code& ec) const noexcept; | ||
666 | |||
667 | file_status symlink_status() const; | ||
668 | file_status symlink_status(std::error_code& ec) const noexcept; | ||
669 | bool operator<(const directory_entry& rhs) const noexcept; | ||
670 | bool operator==(const directory_entry& rhs) const noexcept; | ||
671 | bool operator!=(const directory_entry& rhs) const noexcept; | ||
672 | bool operator<=(const directory_entry& rhs) const noexcept; | ||
673 | bool operator>(const directory_entry& rhs) const noexcept; | ||
674 | bool operator>=(const directory_entry& rhs) const noexcept; | ||
675 | |||
676 | private: | ||
677 | friend class directory_iterator; | ||
678 | filesystem::path _path; | ||
679 | file_status _status; | ||
680 | file_status _symlink_status; | ||
681 | uintmax_t _file_size = 0; | ||
682 | #ifndef GHC_OS_WINDOWS | ||
683 | uintmax_t _hard_link_count = 0; | ||
684 | #endif | ||
685 | time_t _last_write_time = 0; | ||
686 | }; | ||
687 | |||
688 | // 30.10.13 Class directory_iterator | ||
689 | class GHC_FS_API_CLASS directory_iterator | ||
690 | { | ||
691 | public: | ||
692 | class GHC_FS_API_CLASS proxy | ||
693 | { | ||
694 | public: | ||
695 | const directory_entry& operator*() const& noexcept { return _dir_entry; } | ||
696 | directory_entry operator*() && noexcept { return std::move(_dir_entry); } | ||
697 | |||
698 | private: | ||
699 | explicit proxy(const directory_entry& dir_entry) | ||
700 | : _dir_entry(dir_entry) | ||
701 | { | ||
702 | } | ||
703 | friend class directory_iterator; | ||
704 | friend class recursive_directory_iterator; | ||
705 | directory_entry _dir_entry; | ||
706 | }; | ||
707 | using iterator_category = std::input_iterator_tag; | ||
708 | using value_type = directory_entry; | ||
709 | using difference_type = std::ptrdiff_t; | ||
710 | using pointer = const directory_entry*; | ||
711 | using reference = const directory_entry&; | ||
712 | |||
713 | // 30.10.13.1 member functions | ||
714 | directory_iterator() noexcept; | ||
715 | explicit directory_iterator(const path& p); | ||
716 | directory_iterator(const path& p, directory_options options); | ||
717 | directory_iterator(const path& p, std::error_code& ec) noexcept; | ||
718 | directory_iterator(const path& p, directory_options options, std::error_code& ec) noexcept; | ||
719 | directory_iterator(const directory_iterator& rhs); | ||
720 | directory_iterator(directory_iterator&& rhs) noexcept; | ||
721 | ~directory_iterator(); | ||
722 | directory_iterator& operator=(const directory_iterator& rhs); | ||
723 | directory_iterator& operator=(directory_iterator&& rhs) noexcept; | ||
724 | const directory_entry& operator*() const; | ||
725 | const directory_entry* operator->() const; | ||
726 | directory_iterator& operator++(); | ||
727 | directory_iterator& increment(std::error_code& ec) noexcept; | ||
728 | |||
729 | // other members as required by 27.2.3, input iterators | ||
730 | proxy operator++(int) | ||
731 | { | ||
732 | proxy p{**this}; | ||
733 | ++*this; | ||
734 | return p; | ||
735 | } | ||
736 | bool operator==(const directory_iterator& rhs) const; | ||
737 | bool operator!=(const directory_iterator& rhs) const; | ||
738 | |||
739 | private: | ||
740 | friend class recursive_directory_iterator; | ||
741 | class impl; | ||
742 | std::shared_ptr<impl> _impl; | ||
743 | }; | ||
744 | |||
745 | // 30.10.13.2 directory_iterator non-member functions | ||
746 | GHC_FS_API directory_iterator begin(directory_iterator iter) noexcept; | ||
747 | GHC_FS_API directory_iterator end(const directory_iterator&) noexcept; | ||
748 | |||
749 | // 30.10.14 class recursive_directory_iterator | ||
750 | class GHC_FS_API_CLASS recursive_directory_iterator | ||
751 | { | ||
752 | public: | ||
753 | using iterator_category = std::input_iterator_tag; | ||
754 | using value_type = directory_entry; | ||
755 | using difference_type = std::ptrdiff_t; | ||
756 | using pointer = const directory_entry*; | ||
757 | using reference = const directory_entry&; | ||
758 | |||
759 | // 30.10.14.1 constructors and destructor | ||
760 | recursive_directory_iterator() noexcept; | ||
761 | explicit recursive_directory_iterator(const path& p); | ||
762 | recursive_directory_iterator(const path& p, directory_options options); | ||
763 | recursive_directory_iterator(const path& p, directory_options options, std::error_code& ec) noexcept; | ||
764 | recursive_directory_iterator(const path& p, std::error_code& ec) noexcept; | ||
765 | recursive_directory_iterator(const recursive_directory_iterator& rhs); | ||
766 | recursive_directory_iterator(recursive_directory_iterator&& rhs) noexcept; | ||
767 | ~recursive_directory_iterator(); | ||
768 | |||
769 | // 30.10.14.1 observers | ||
770 | directory_options options() const; | ||
771 | int depth() const; | ||
772 | bool recursion_pending() const; | ||
773 | |||
774 | const directory_entry& operator*() const; | ||
775 | const directory_entry* operator->() const; | ||
776 | |||
777 | // 30.10.14.1 modifiers recursive_directory_iterator& | ||
778 | recursive_directory_iterator& operator=(const recursive_directory_iterator& rhs); | ||
779 | recursive_directory_iterator& operator=(recursive_directory_iterator&& rhs) noexcept; | ||
780 | recursive_directory_iterator& operator++(); | ||
781 | recursive_directory_iterator& increment(std::error_code& ec) noexcept; | ||
782 | |||
783 | void pop(); | ||
784 | void pop(std::error_code& ec); | ||
785 | void disable_recursion_pending(); | ||
786 | |||
787 | // other members as required by 27.2.3, input iterators | ||
788 | directory_iterator::proxy operator++(int) | ||
789 | { | ||
790 | directory_iterator::proxy proxy{**this}; | ||
791 | ++*this; | ||
792 | return proxy; | ||
793 | } | ||
794 | bool operator==(const recursive_directory_iterator& rhs) const; | ||
795 | bool operator!=(const recursive_directory_iterator& rhs) const; | ||
796 | |||
797 | private: | ||
798 | struct recursive_directory_iterator_impl | ||
799 | { | ||
800 | directory_options _options; | ||
801 | bool _recursion_pending; | ||
802 | std::stack<directory_iterator> _dir_iter_stack; | ||
803 | recursive_directory_iterator_impl(directory_options options, bool recursion_pending) | ||
804 | : _options(options) | ||
805 | , _recursion_pending(recursion_pending) | ||
806 | { | ||
807 | } | ||
808 | }; | ||
809 | std::shared_ptr<recursive_directory_iterator_impl> _impl; | ||
810 | }; | ||
811 | |||
812 | // 30.10.14.2 directory_iterator non-member functions | ||
813 | GHC_FS_API recursive_directory_iterator begin(recursive_directory_iterator iter) noexcept; | ||
814 | GHC_FS_API recursive_directory_iterator end(const recursive_directory_iterator&) noexcept; | ||
815 | |||
816 | // 30.10.15 filesystem operations | ||
817 | GHC_FS_API path absolute(const path& p); | ||
818 | GHC_FS_API path absolute(const path& p, std::error_code& ec); | ||
819 | |||
820 | GHC_FS_API path canonical(const path& p); | ||
821 | GHC_FS_API path canonical(const path& p, std::error_code& ec); | ||
822 | |||
823 | GHC_FS_API void copy(const path& from, const path& to); | ||
824 | GHC_FS_API void copy(const path& from, const path& to, std::error_code& ec) noexcept; | ||
825 | GHC_FS_API void copy(const path& from, const path& to, copy_options options); | ||
826 | GHC_FS_API void copy(const path& from, const path& to, copy_options options, std::error_code& ec) noexcept; | ||
827 | |||
828 | GHC_FS_API bool copy_file(const path& from, const path& to); | ||
829 | GHC_FS_API bool copy_file(const path& from, const path& to, std::error_code& ec) noexcept; | ||
830 | GHC_FS_API bool copy_file(const path& from, const path& to, copy_options option); | ||
831 | GHC_FS_API bool copy_file(const path& from, const path& to, copy_options option, std::error_code& ec) noexcept; | ||
832 | |||
833 | GHC_FS_API void copy_symlink(const path& existing_symlink, const path& new_symlink); | ||
834 | GHC_FS_API void copy_symlink(const path& existing_symlink, const path& new_symlink, std::error_code& ec) noexcept; | ||
835 | |||
836 | GHC_FS_API bool create_directories(const path& p); | ||
837 | GHC_FS_API bool create_directories(const path& p, std::error_code& ec) noexcept; | ||
838 | |||
839 | GHC_FS_API bool create_directory(const path& p); | ||
840 | GHC_FS_API bool create_directory(const path& p, std::error_code& ec) noexcept; | ||
841 | |||
842 | GHC_FS_API bool create_directory(const path& p, const path& attributes); | ||
843 | GHC_FS_API bool create_directory(const path& p, const path& attributes, std::error_code& ec) noexcept; | ||
844 | |||
845 | GHC_FS_API void create_directory_symlink(const path& to, const path& new_symlink); | ||
846 | GHC_FS_API void create_directory_symlink(const path& to, const path& new_symlink, std::error_code& ec) noexcept; | ||
847 | |||
848 | GHC_FS_API void create_hard_link(const path& to, const path& new_hard_link); | ||
849 | GHC_FS_API void create_hard_link(const path& to, const path& new_hard_link, std::error_code& ec) noexcept; | ||
850 | |||
851 | GHC_FS_API void create_symlink(const path& to, const path& new_symlink); | ||
852 | GHC_FS_API void create_symlink(const path& to, const path& new_symlink, std::error_code& ec) noexcept; | ||
853 | |||
854 | GHC_FS_API path current_path(); | ||
855 | GHC_FS_API path current_path(std::error_code& ec); | ||
856 | GHC_FS_API void current_path(const path& p); | ||
857 | GHC_FS_API void current_path(const path& p, std::error_code& ec) noexcept; | ||
858 | |||
859 | GHC_FS_API bool exists(file_status s) noexcept; | ||
860 | GHC_FS_API bool exists(const path& p); | ||
861 | GHC_FS_API bool exists(const path& p, std::error_code& ec) noexcept; | ||
862 | |||
863 | GHC_FS_API bool equivalent(const path& p1, const path& p2); | ||
864 | GHC_FS_API bool equivalent(const path& p1, const path& p2, std::error_code& ec) noexcept; | ||
865 | |||
866 | GHC_FS_API uintmax_t file_size(const path& p); | ||
867 | GHC_FS_API uintmax_t file_size(const path& p, std::error_code& ec) noexcept; | ||
868 | |||
869 | GHC_FS_API uintmax_t hard_link_count(const path& p); | ||
870 | GHC_FS_API uintmax_t hard_link_count(const path& p, std::error_code& ec) noexcept; | ||
871 | |||
872 | GHC_FS_API bool is_block_file(file_status s) noexcept; | ||
873 | GHC_FS_API bool is_block_file(const path& p); | ||
874 | GHC_FS_API bool is_block_file(const path& p, std::error_code& ec) noexcept; | ||
875 | GHC_FS_API bool is_character_file(file_status s) noexcept; | ||
876 | GHC_FS_API bool is_character_file(const path& p); | ||
877 | GHC_FS_API bool is_character_file(const path& p, std::error_code& ec) noexcept; | ||
878 | GHC_FS_API bool is_directory(file_status s) noexcept; | ||
879 | GHC_FS_API bool is_directory(const path& p); | ||
880 | GHC_FS_API bool is_directory(const path& p, std::error_code& ec) noexcept; | ||
881 | GHC_FS_API bool is_empty(const path& p); | ||
882 | GHC_FS_API bool is_empty(const path& p, std::error_code& ec) noexcept; | ||
883 | GHC_FS_API bool is_fifo(file_status s) noexcept; | ||
884 | GHC_FS_API bool is_fifo(const path& p); | ||
885 | GHC_FS_API bool is_fifo(const path& p, std::error_code& ec) noexcept; | ||
886 | GHC_FS_API bool is_other(file_status s) noexcept; | ||
887 | GHC_FS_API bool is_other(const path& p); | ||
888 | GHC_FS_API bool is_other(const path& p, std::error_code& ec) noexcept; | ||
889 | GHC_FS_API bool is_regular_file(file_status s) noexcept; | ||
890 | GHC_FS_API bool is_regular_file(const path& p); | ||
891 | GHC_FS_API bool is_regular_file(const path& p, std::error_code& ec) noexcept; | ||
892 | GHC_FS_API bool is_socket(file_status s) noexcept; | ||
893 | GHC_FS_API bool is_socket(const path& p); | ||
894 | GHC_FS_API bool is_socket(const path& p, std::error_code& ec) noexcept; | ||
895 | GHC_FS_API bool is_symlink(file_status s) noexcept; | ||
896 | GHC_FS_API bool is_symlink(const path& p); | ||
897 | GHC_FS_API bool is_symlink(const path& p, std::error_code& ec) noexcept; | ||
898 | |||
899 | GHC_FS_API file_time_type last_write_time(const path& p); | ||
900 | GHC_FS_API file_time_type last_write_time(const path& p, std::error_code& ec) noexcept; | ||
901 | GHC_FS_API void last_write_time(const path& p, file_time_type new_time); | ||
902 | GHC_FS_API void last_write_time(const path& p, file_time_type new_time, std::error_code& ec) noexcept; | ||
903 | |||
904 | GHC_FS_API void permissions(const path& p, perms prms, perm_options opts = perm_options::replace); | ||
905 | GHC_FS_API void permissions(const path& p, perms prms, std::error_code& ec) noexcept; | ||
906 | GHC_FS_API void permissions(const path& p, perms prms, perm_options opts, std::error_code& ec); | ||
907 | |||
908 | GHC_FS_API path proximate(const path& p, std::error_code& ec); | ||
909 | GHC_FS_API path proximate(const path& p, const path& base = current_path()); | ||
910 | GHC_FS_API path proximate(const path& p, const path& base, std::error_code& ec); | ||
911 | |||
912 | GHC_FS_API path read_symlink(const path& p); | ||
913 | GHC_FS_API path read_symlink(const path& p, std::error_code& ec); | ||
914 | |||
915 | GHC_FS_API path relative(const path& p, std::error_code& ec); | ||
916 | GHC_FS_API path relative(const path& p, const path& base = current_path()); | ||
917 | GHC_FS_API path relative(const path& p, const path& base, std::error_code& ec); | ||
918 | |||
919 | GHC_FS_API bool remove(const path& p); | ||
920 | GHC_FS_API bool remove(const path& p, std::error_code& ec) noexcept; | ||
921 | |||
922 | GHC_FS_API uintmax_t remove_all(const path& p); | ||
923 | GHC_FS_API uintmax_t remove_all(const path& p, std::error_code& ec) noexcept; | ||
924 | |||
925 | GHC_FS_API void rename(const path& from, const path& to); | ||
926 | GHC_FS_API void rename(const path& from, const path& to, std::error_code& ec) noexcept; | ||
927 | |||
928 | GHC_FS_API void resize_file(const path& p, uintmax_t size); | ||
929 | GHC_FS_API void resize_file(const path& p, uintmax_t size, std::error_code& ec) noexcept; | ||
930 | |||
931 | GHC_FS_API space_info space(const path& p); | ||
932 | GHC_FS_API space_info space(const path& p, std::error_code& ec) noexcept; | ||
933 | |||
934 | GHC_FS_API file_status status(const path& p); | ||
935 | GHC_FS_API file_status status(const path& p, std::error_code& ec) noexcept; | ||
936 | |||
937 | GHC_FS_API bool status_known(file_status s) noexcept; | ||
938 | |||
939 | GHC_FS_API file_status symlink_status(const path& p); | ||
940 | GHC_FS_API file_status symlink_status(const path& p, std::error_code& ec) noexcept; | ||
941 | |||
942 | GHC_FS_API path temp_directory_path(); | ||
943 | GHC_FS_API path temp_directory_path(std::error_code& ec) noexcept; | ||
944 | |||
945 | GHC_FS_API path weakly_canonical(const path& p); | ||
946 | GHC_FS_API path weakly_canonical(const path& p, std::error_code& ec) noexcept; | ||
947 | |||
948 | // Non-C++17 add-on std::fstream wrappers with path | ||
949 | template <class charT, class traits = std::char_traits<charT>> | ||
950 | class basic_filebuf : public std::basic_filebuf<charT, traits> | ||
951 | { | ||
952 | public: | ||
953 | basic_filebuf() {} | ||
954 | ~basic_filebuf() override {} | ||
955 | basic_filebuf(const basic_filebuf&) = delete; | ||
956 | const basic_filebuf& operator=(const basic_filebuf&) = delete; | ||
957 | basic_filebuf<charT, traits>* open(const path& p, std::ios_base::openmode mode) | ||
958 | { | ||
959 | #if defined(GHC_OS_WINDOWS) && !defined(__GNUC__) | ||
960 | return std::basic_filebuf<charT, traits>::open(p.wstring().c_str(), mode) ? this : 0; | ||
961 | #else | ||
962 | return std::basic_filebuf<charT, traits>::open(p.string().c_str(), mode) ? this : 0; | ||
963 | #endif | ||
964 | } | ||
965 | }; | ||
966 | |||
967 | template <class charT, class traits = std::char_traits<charT>> | ||
968 | class basic_ifstream : public std::basic_ifstream<charT, traits> | ||
969 | { | ||
970 | public: | ||
971 | basic_ifstream() {} | ||
972 | #if defined(GHC_OS_WINDOWS) && !defined(__GNUC__) | ||
973 | explicit basic_ifstream(const path& p, std::ios_base::openmode mode = std::ios_base::in) | ||
974 | : std::basic_ifstream<charT, traits>(p.wstring().c_str(), mode) | ||
975 | { | ||
976 | } | ||
977 | void open(const path& p, std::ios_base::openmode mode = std::ios_base::in) { std::basic_ifstream<charT, traits>::open(p.wstring().c_str(), mode); } | ||
978 | #else | ||
979 | explicit basic_ifstream(const path& p, std::ios_base::openmode mode = std::ios_base::in) | ||
980 | : std::basic_ifstream<charT, traits>(p.string().c_str(), mode) | ||
981 | { | ||
982 | } | ||
983 | void open(const path& p, std::ios_base::openmode mode = std::ios_base::in) { std::basic_ifstream<charT, traits>::open(p.string().c_str(), mode); } | ||
984 | #endif | ||
985 | basic_ifstream(const basic_ifstream&) = delete; | ||
986 | const basic_ifstream& operator=(const basic_ifstream&) = delete; | ||
987 | ~basic_ifstream() override {} | ||
988 | }; | ||
989 | |||
990 | template <class charT, class traits = std::char_traits<charT>> | ||
991 | class basic_ofstream : public std::basic_ofstream<charT, traits> | ||
992 | { | ||
993 | public: | ||
994 | basic_ofstream() {} | ||
995 | #if defined(GHC_OS_WINDOWS) && !defined(__GNUC__) | ||
996 | explicit basic_ofstream(const path& p, std::ios_base::openmode mode = std::ios_base::out) | ||
997 | : std::basic_ofstream<charT, traits>(p.wstring().c_str(), mode) | ||
998 | { | ||
999 | } | ||
1000 | void open(const path& p, std::ios_base::openmode mode = std::ios_base::out) { std::basic_ofstream<charT, traits>::open(p.wstring().c_str(), mode); } | ||
1001 | #else | ||
1002 | explicit basic_ofstream(const path& p, std::ios_base::openmode mode = std::ios_base::out) | ||
1003 | : std::basic_ofstream<charT, traits>(p.string().c_str(), mode) | ||
1004 | { | ||
1005 | } | ||
1006 | void open(const path& p, std::ios_base::openmode mode = std::ios_base::out) { std::basic_ofstream<charT, traits>::open(p.string().c_str(), mode); } | ||
1007 | #endif | ||
1008 | basic_ofstream(const basic_ofstream&) = delete; | ||
1009 | const basic_ofstream& operator=(const basic_ofstream&) = delete; | ||
1010 | ~basic_ofstream() override {} | ||
1011 | }; | ||
1012 | |||
1013 | template <class charT, class traits = std::char_traits<charT>> | ||
1014 | class basic_fstream : public std::basic_fstream<charT, traits> | ||
1015 | { | ||
1016 | public: | ||
1017 | basic_fstream() {} | ||
1018 | #if defined(GHC_OS_WINDOWS) && !defined(__GNUC__) | ||
1019 | explicit basic_fstream(const path& p, std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out) | ||
1020 | : std::basic_fstream<charT, traits>(p.wstring().c_str(), mode) | ||
1021 | { | ||
1022 | } | ||
1023 | void open(const path& p, std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out) { std::basic_fstream<charT, traits>::open(p.wstring().c_str(), mode); } | ||
1024 | #else | ||
1025 | explicit basic_fstream(const path& p, std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out) | ||
1026 | : std::basic_fstream<charT, traits>(p.string().c_str(), mode) | ||
1027 | { | ||
1028 | } | ||
1029 | void open(const path& p, std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out) { std::basic_fstream<charT, traits>::open(p.string().c_str(), mode); } | ||
1030 | #endif | ||
1031 | basic_fstream(const basic_fstream&) = delete; | ||
1032 | const basic_fstream& operator=(const basic_fstream&) = delete; | ||
1033 | ~basic_fstream() override {} | ||
1034 | }; | ||
1035 | |||
1036 | typedef basic_filebuf<char> filebuf; | ||
1037 | typedef basic_filebuf<wchar_t> wfilebuf; | ||
1038 | typedef basic_ifstream<char> ifstream; | ||
1039 | typedef basic_ifstream<wchar_t> wifstream; | ||
1040 | typedef basic_ofstream<char> ofstream; | ||
1041 | typedef basic_ofstream<wchar_t> wofstream; | ||
1042 | typedef basic_fstream<char> fstream; | ||
1043 | typedef basic_fstream<wchar_t> wfstream; | ||
1044 | |||
1045 | class GHC_FS_API_CLASS u8arguments | ||
1046 | { | ||
1047 | public: | ||
1048 | u8arguments(int& argc, char**& argv); | ||
1049 | ~u8arguments() | ||
1050 | { | ||
1051 | _refargc = _argc; | ||
1052 | _refargv = _argv; | ||
1053 | } | ||
1054 | |||
1055 | bool valid() const { return _isvalid; } | ||
1056 | |||
1057 | private: | ||
1058 | int _argc; | ||
1059 | char** _argv; | ||
1060 | int& _refargc; | ||
1061 | char**& _refargv; | ||
1062 | bool _isvalid; | ||
1063 | #ifdef GHC_OS_WINDOWS | ||
1064 | std::vector<std::string> _args; | ||
1065 | std::vector<char*> _argp; | ||
1066 | #endif | ||
1067 | }; | ||
1068 | |||
1069 | //------------------------------------------------------------------------------------------------- | ||
1070 | // Implementation | ||
1071 | //------------------------------------------------------------------------------------------------- | ||
1072 | |||
1073 | namespace detail { | ||
1074 | // GHC_FS_API void postprocess_path_with_format(path::impl_string_type& p, path::format fmt); | ||
1075 | enum utf8_states_t { S_STRT = 0, S_RJCT = 8 }; | ||
1076 | GHC_FS_API void appendUTF8(std::string& str, uint32_t unicode); | ||
1077 | GHC_FS_API bool is_surrogate(uint32_t c); | ||
1078 | GHC_FS_API bool is_high_surrogate(uint32_t c); | ||
1079 | GHC_FS_API bool is_low_surrogate(uint32_t c); | ||
1080 | GHC_FS_API unsigned consumeUtf8Fragment(const unsigned state, const uint8_t fragment, uint32_t& codepoint); | ||
1081 | enum class portable_error { | ||
1082 | none = 0, | ||
1083 | exists, | ||
1084 | not_found, | ||
1085 | not_supported, | ||
1086 | not_implemented, | ||
1087 | invalid_argument, | ||
1088 | is_a_directory, | ||
1089 | }; | ||
1090 | GHC_FS_API std::error_code make_error_code(portable_error err); | ||
1091 | #ifdef GHC_OS_WINDOWS | ||
1092 | GHC_FS_API std::error_code make_system_error(uint32_t err = 0); | ||
1093 | #else | ||
1094 | GHC_FS_API std::error_code make_system_error(int err = 0); | ||
1095 | #endif | ||
1096 | } // namespace detail | ||
1097 | |||
1098 | namespace detail { | ||
1099 | |||
1100 | #ifdef GHC_EXPAND_IMPL | ||
1101 | |||
1102 | GHC_INLINE std::error_code make_error_code(portable_error err) | ||
1103 | { | ||
1104 | #ifdef GHC_OS_WINDOWS | ||
1105 | switch (err) { | ||
1106 | case portable_error::none: | ||
1107 | return std::error_code(); | ||
1108 | case portable_error::exists: | ||
1109 | return std::error_code(ERROR_ALREADY_EXISTS, std::system_category()); | ||
1110 | case portable_error::not_found: | ||
1111 | return std::error_code(ERROR_PATH_NOT_FOUND, std::system_category()); | ||
1112 | case portable_error::not_supported: | ||
1113 | return std::error_code(ERROR_NOT_SUPPORTED, std::system_category()); | ||
1114 | case portable_error::not_implemented: | ||
1115 | return std::error_code(ERROR_CALL_NOT_IMPLEMENTED, std::system_category()); | ||
1116 | case portable_error::invalid_argument: | ||
1117 | return std::error_code(ERROR_INVALID_PARAMETER, std::system_category()); | ||
1118 | case portable_error::is_a_directory: | ||
1119 | #ifdef ERROR_DIRECTORY_NOT_SUPPORTED | ||
1120 | return std::error_code(ERROR_DIRECTORY_NOT_SUPPORTED, std::system_category()); | ||
1121 | #else | ||
1122 | return std::error_code(ERROR_NOT_SUPPORTED, std::system_category()); | ||
1123 | #endif | ||
1124 | } | ||
1125 | #else | ||
1126 | switch (err) { | ||
1127 | case portable_error::none: | ||
1128 | return std::error_code(); | ||
1129 | case portable_error::exists: | ||
1130 | return std::error_code(EEXIST, std::system_category()); | ||
1131 | case portable_error::not_found: | ||
1132 | return std::error_code(ENOENT, std::system_category()); | ||
1133 | case portable_error::not_supported: | ||
1134 | return std::error_code(ENOTSUP, std::system_category()); | ||
1135 | case portable_error::not_implemented: | ||
1136 | return std::error_code(ENOSYS, std::system_category()); | ||
1137 | case portable_error::invalid_argument: | ||
1138 | return std::error_code(EINVAL, std::system_category()); | ||
1139 | case portable_error::is_a_directory: | ||
1140 | return std::error_code(EISDIR, std::system_category()); | ||
1141 | } | ||
1142 | #endif | ||
1143 | return std::error_code(); | ||
1144 | } | ||
1145 | |||
1146 | #ifdef GHC_OS_WINDOWS | ||
1147 | GHC_INLINE std::error_code make_system_error(uint32_t err) | ||
1148 | { | ||
1149 | return std::error_code(err ? static_cast<int>(err) : static_cast<int>(::GetLastError()), std::system_category()); | ||
1150 | } | ||
1151 | #else | ||
1152 | GHC_INLINE std::error_code make_system_error(int err) | ||
1153 | { | ||
1154 | return std::error_code(err ? err : errno, std::system_category()); | ||
1155 | } | ||
1156 | #endif | ||
1157 | |||
1158 | #endif // GHC_EXPAND_IMPL | ||
1159 | |||
1160 | template <typename Enum> | ||
1161 | using EnableBitmask = typename std::enable_if<std::is_same<Enum, perms>::value || std::is_same<Enum, perm_options>::value || std::is_same<Enum, copy_options>::value || std::is_same<Enum, directory_options>::value, Enum>::type; | ||
1162 | } // namespace detail | ||
1163 | |||
1164 | template <typename Enum> | ||
1165 | detail::EnableBitmask<Enum> operator&(Enum X, Enum Y) | ||
1166 | { | ||
1167 | using underlying = typename std::underlying_type<Enum>::type; | ||
1168 | return static_cast<Enum>(static_cast<underlying>(X) & static_cast<underlying>(Y)); | ||
1169 | } | ||
1170 | |||
1171 | template <typename Enum> | ||
1172 | detail::EnableBitmask<Enum> operator|(Enum X, Enum Y) | ||
1173 | { | ||
1174 | using underlying = typename std::underlying_type<Enum>::type; | ||
1175 | return static_cast<Enum>(static_cast<underlying>(X) | static_cast<underlying>(Y)); | ||
1176 | } | ||
1177 | |||
1178 | template <typename Enum> | ||
1179 | detail::EnableBitmask<Enum> operator^(Enum X, Enum Y) | ||
1180 | { | ||
1181 | using underlying = typename std::underlying_type<Enum>::type; | ||
1182 | return static_cast<Enum>(static_cast<underlying>(X) ^ static_cast<underlying>(Y)); | ||
1183 | } | ||
1184 | |||
1185 | template <typename Enum> | ||
1186 | detail::EnableBitmask<Enum> operator~(Enum X) | ||
1187 | { | ||
1188 | using underlying = typename std::underlying_type<Enum>::type; | ||
1189 | return static_cast<Enum>(~static_cast<underlying>(X)); | ||
1190 | } | ||
1191 | |||
1192 | template <typename Enum> | ||
1193 | detail::EnableBitmask<Enum>& operator&=(Enum& X, Enum Y) | ||
1194 | { | ||
1195 | X = X & Y; | ||
1196 | return X; | ||
1197 | } | ||
1198 | |||
1199 | template <typename Enum> | ||
1200 | detail::EnableBitmask<Enum>& operator|=(Enum& X, Enum Y) | ||
1201 | { | ||
1202 | X = X | Y; | ||
1203 | return X; | ||
1204 | } | ||
1205 | |||
1206 | template <typename Enum> | ||
1207 | detail::EnableBitmask<Enum>& operator^=(Enum& X, Enum Y) | ||
1208 | { | ||
1209 | X = X ^ Y; | ||
1210 | return X; | ||
1211 | } | ||
1212 | |||
1213 | #ifdef GHC_EXPAND_IMPL | ||
1214 | |||
1215 | namespace detail { | ||
1216 | |||
1217 | GHC_INLINE bool in_range(uint32_t c, uint32_t lo, uint32_t hi) | ||
1218 | { | ||
1219 | return (static_cast<uint32_t>(c - lo) < (hi - lo + 1)); | ||
1220 | } | ||
1221 | |||
1222 | GHC_INLINE bool is_surrogate(uint32_t c) | ||
1223 | { | ||
1224 | return in_range(c, 0xd800, 0xdfff); | ||
1225 | } | ||
1226 | |||
1227 | GHC_INLINE bool is_high_surrogate(uint32_t c) | ||
1228 | { | ||
1229 | return (c & 0xfffffc00) == 0xd800; | ||
1230 | } | ||
1231 | |||
1232 | GHC_INLINE bool is_low_surrogate(uint32_t c) | ||
1233 | { | ||
1234 | return (c & 0xfffffc00) == 0xdc00; | ||
1235 | } | ||
1236 | |||
1237 | GHC_INLINE void appendUTF8(std::string& str, uint32_t unicode) | ||
1238 | { | ||
1239 | if (unicode <= 0x7f) { | ||
1240 | str.push_back(static_cast<char>(unicode)); | ||
1241 | } | ||
1242 | else if (unicode >= 0x80 && unicode <= 0x7ff) { | ||
1243 | str.push_back(static_cast<char>((unicode >> 6) + 192)); | ||
1244 | str.push_back(static_cast<char>((unicode & 0x3f) + 128)); | ||
1245 | } | ||
1246 | else if ((unicode >= 0x800 && unicode <= 0xd7ff) || (unicode >= 0xe000 && unicode <= 0xffff)) { | ||
1247 | str.push_back(static_cast<char>((unicode >> 12) + 224)); | ||
1248 | str.push_back(static_cast<char>(((unicode & 0xfff) >> 6) + 128)); | ||
1249 | str.push_back(static_cast<char>((unicode & 0x3f) + 128)); | ||
1250 | } | ||
1251 | else if (unicode >= 0x10000 && unicode <= 0x10ffff) { | ||
1252 | str.push_back(static_cast<char>((unicode >> 18) + 240)); | ||
1253 | str.push_back(static_cast<char>(((unicode & 0x3ffff) >> 12) + 128)); | ||
1254 | str.push_back(static_cast<char>(((unicode & 0xfff) >> 6) + 128)); | ||
1255 | str.push_back(static_cast<char>((unicode & 0x3f) + 128)); | ||
1256 | } | ||
1257 | else { | ||
1258 | #ifdef GHC_RAISE_UNICODE_ERRORS | ||
1259 | throw filesystem_error("Illegal code point for unicode character.", str, std::make_error_code(std::errc::illegal_byte_sequence)); | ||
1260 | #else | ||
1261 | appendUTF8(str, 0xfffd); | ||
1262 | #endif | ||
1263 | } | ||
1264 | } | ||
1265 | |||
1266 | // Thanks to Bjoern Hoehrmann (https://bjoern.hoehrmann.de/utf-8/decoder/dfa/) | ||
1267 | // and Taylor R Campbell for the ideas to this DFA approach of UTF-8 decoding; | ||
1268 | // Generating debugging and shrinking my own DFA from scratch was a day of fun! | ||
1269 | GHC_INLINE unsigned consumeUtf8Fragment(const unsigned state, const uint8_t fragment, uint32_t& codepoint) | ||
1270 | { | ||
1271 | static const uint32_t utf8_state_info[] = { | ||
1272 | // encoded states | ||
1273 | 0x11111111u, 0x11111111u, 0x77777777u, 0x77777777u, 0x88888888u, 0x88888888u, 0x88888888u, 0x88888888u, 0x22222299u, 0x22222222u, 0x22222222u, 0x22222222u, 0x3333333au, 0x33433333u, 0x9995666bu, 0x99999999u, | ||
1274 | 0x88888880u, 0x22818108u, 0x88888881u, 0x88888882u, 0x88888884u, 0x88888887u, 0x88888886u, 0x82218108u, 0x82281108u, 0x88888888u, 0x88888883u, 0x88888885u, 0u, 0u, 0u, 0u, | ||
1275 | }; | ||
1276 | uint8_t category = fragment < 128 ? 0 : (utf8_state_info[(fragment >> 3) & 0xf] >> ((fragment & 7) << 2)) & 0xf; | ||
1277 | codepoint = (state ? (codepoint << 6) | (fragment & 0x3fu) : (0xffu >> category) & fragment); | ||
1278 | return state == S_RJCT ? static_cast<unsigned>(S_RJCT) : static_cast<unsigned>((utf8_state_info[category + 16] >> (state << 2)) & 0xf); | ||
1279 | } | ||
1280 | |||
1281 | GHC_INLINE bool validUtf8(const std::string& utf8String) | ||
1282 | { | ||
1283 | std::string::const_iterator iter = utf8String.begin(); | ||
1284 | unsigned utf8_state = S_STRT; | ||
1285 | std::uint32_t codepoint = 0; | ||
1286 | while (iter < utf8String.end()) { | ||
1287 | if ((utf8_state = consumeUtf8Fragment(utf8_state, static_cast<uint8_t>(*iter++), codepoint)) == S_RJCT) { | ||
1288 | return false; | ||
1289 | } | ||
1290 | } | ||
1291 | if (utf8_state) { | ||
1292 | return false; | ||
1293 | } | ||
1294 | return true; | ||
1295 | } | ||
1296 | |||
1297 | } // namespace detail | ||
1298 | |||
1299 | #endif | ||
1300 | |||
1301 | namespace detail { | ||
1302 | |||
1303 | template <class StringType, typename std::enable_if<(sizeof(typename StringType::value_type) == 1)>::type* = nullptr> | ||
1304 | inline StringType fromUtf8(const std::string& utf8String, const typename StringType::allocator_type& alloc = typename StringType::allocator_type()) | ||
1305 | { | ||
1306 | return StringType(utf8String.begin(), utf8String.end(), alloc); | ||
1307 | } | ||
1308 | |||
1309 | template <class StringType, typename std::enable_if<(sizeof(typename StringType::value_type) == 2)>::type* = nullptr> | ||
1310 | inline StringType fromUtf8(const std::string& utf8String, const typename StringType::allocator_type& alloc = typename StringType::allocator_type()) | ||
1311 | { | ||
1312 | StringType result(alloc); | ||
1313 | result.reserve(utf8String.length()); | ||
1314 | std::string::const_iterator iter = utf8String.begin(); | ||
1315 | unsigned utf8_state = S_STRT; | ||
1316 | std::uint32_t codepoint = 0; | ||
1317 | while (iter < utf8String.end()) { | ||
1318 | if ((utf8_state = consumeUtf8Fragment(utf8_state, static_cast<uint8_t>(*iter++), codepoint)) == S_STRT) { | ||
1319 | if (codepoint <= 0xffff) { | ||
1320 | result += static_cast<typename StringType::value_type>(codepoint); | ||
1321 | } | ||
1322 | else { | ||
1323 | codepoint -= 0x10000; | ||
1324 | result += static_cast<typename StringType::value_type>((codepoint >> 10) + 0xd800); | ||
1325 | result += static_cast<typename StringType::value_type>((codepoint & 0x3ff) + 0xdc00); | ||
1326 | } | ||
1327 | codepoint = 0; | ||
1328 | } | ||
1329 | else if (utf8_state == S_RJCT) { | ||
1330 | #ifdef GHC_RAISE_UNICODE_ERRORS | ||
1331 | throw filesystem_error("Illegal byte sequence for unicode character.", utf8String, std::make_error_code(std::errc::illegal_byte_sequence)); | ||
1332 | #else | ||
1333 | result += static_cast<typename StringType::value_type>(0xfffd); | ||
1334 | utf8_state = S_STRT; | ||
1335 | codepoint = 0; | ||
1336 | #endif | ||
1337 | } | ||
1338 | } | ||
1339 | if (utf8_state) { | ||
1340 | #ifdef GHC_RAISE_UNICODE_ERRORS | ||
1341 | throw filesystem_error("Illegal byte sequence for unicode character.", utf8String, std::make_error_code(std::errc::illegal_byte_sequence)); | ||
1342 | #else | ||
1343 | result += static_cast<typename StringType::value_type>(0xfffd); | ||
1344 | #endif | ||
1345 | } | ||
1346 | return result; | ||
1347 | } | ||
1348 | |||
1349 | template <class StringType, typename std::enable_if<(sizeof(typename StringType::value_type) == 4)>::type* = nullptr> | ||
1350 | inline StringType fromUtf8(const std::string& utf8String, const typename StringType::allocator_type& alloc = typename StringType::allocator_type()) | ||
1351 | { | ||
1352 | StringType result(alloc); | ||
1353 | result.reserve(utf8String.length()); | ||
1354 | std::string::const_iterator iter = utf8String.begin(); | ||
1355 | unsigned utf8_state = S_STRT; | ||
1356 | std::uint32_t codepoint = 0; | ||
1357 | while (iter < utf8String.end()) { | ||
1358 | if ((utf8_state = consumeUtf8Fragment(utf8_state, static_cast<uint8_t>(*iter++), codepoint)) == S_STRT) { | ||
1359 | result += static_cast<typename StringType::value_type>(codepoint); | ||
1360 | codepoint = 0; | ||
1361 | } | ||
1362 | else if (utf8_state == S_RJCT) { | ||
1363 | #ifdef GHC_RAISE_UNICODE_ERRORS | ||
1364 | throw filesystem_error("Illegal byte sequence for unicode character.", utf8String, std::make_error_code(std::errc::illegal_byte_sequence)); | ||
1365 | #else | ||
1366 | result += static_cast<typename StringType::value_type>(0xfffd); | ||
1367 | utf8_state = S_STRT; | ||
1368 | codepoint = 0; | ||
1369 | #endif | ||
1370 | } | ||
1371 | } | ||
1372 | if (utf8_state) { | ||
1373 | #ifdef GHC_RAISE_UNICODE_ERRORS | ||
1374 | throw filesystem_error("Illegal byte sequence for unicode character.", utf8String, std::make_error_code(std::errc::illegal_byte_sequence)); | ||
1375 | #else | ||
1376 | result += static_cast<typename StringType::value_type>(0xfffd); | ||
1377 | #endif | ||
1378 | } | ||
1379 | return result; | ||
1380 | } | ||
1381 | |||
1382 | template <typename charT, typename traits, typename Alloc, typename std::enable_if<(sizeof(charT) == 1), int>::type size = 1> | ||
1383 | inline std::string toUtf8(const std::basic_string<charT, traits, Alloc>& unicodeString) | ||
1384 | { | ||
1385 | return std::string(unicodeString.begin(), unicodeString.end()); | ||
1386 | } | ||
1387 | |||
1388 | template <typename charT, typename traits, typename Alloc, typename std::enable_if<(sizeof(charT) == 2), int>::type size = 2> | ||
1389 | inline std::string toUtf8(const std::basic_string<charT, traits, Alloc>& unicodeString) | ||
1390 | { | ||
1391 | std::string result; | ||
1392 | for (auto iter = unicodeString.begin(); iter != unicodeString.end(); ++iter) { | ||
1393 | char32_t c = *iter; | ||
1394 | if (is_surrogate(c)) { | ||
1395 | ++iter; | ||
1396 | if (iter != unicodeString.end() && is_high_surrogate(c) && is_low_surrogate(*iter)) { | ||
1397 | appendUTF8(result, (char32_t(c) << 10) + *iter - 0x35fdc00); | ||
1398 | } | ||
1399 | else { | ||
1400 | #ifdef GHC_RAISE_UNICODE_ERRORS | ||
1401 | throw filesystem_error("Illegal code point for unicode character.", result, std::make_error_code(std::errc::illegal_byte_sequence)); | ||
1402 | #else | ||
1403 | appendUTF8(result, 0xfffd); | ||
1404 | if(iter == unicodeString.end()) { | ||
1405 | break; | ||
1406 | } | ||
1407 | #endif | ||
1408 | } | ||
1409 | } | ||
1410 | else { | ||
1411 | appendUTF8(result, c); | ||
1412 | } | ||
1413 | } | ||
1414 | return result; | ||
1415 | } | ||
1416 | |||
1417 | template <typename charT, typename traits, typename Alloc, typename std::enable_if<(sizeof(charT) == 4), int>::type size = 4> | ||
1418 | inline std::string toUtf8(const std::basic_string<charT, traits, Alloc>& unicodeString) | ||
1419 | { | ||
1420 | std::string result; | ||
1421 | for (auto c : unicodeString) { | ||
1422 | appendUTF8(result, static_cast<uint32_t>(c)); | ||
1423 | } | ||
1424 | return result; | ||
1425 | } | ||
1426 | |||
1427 | template <typename charT> | ||
1428 | inline std::string toUtf8(const charT* unicodeString) | ||
1429 | { | ||
1430 | return toUtf8(std::basic_string<charT, std::char_traits<charT>>(unicodeString)); | ||
1431 | } | ||
1432 | |||
1433 | } // namespace detail | ||
1434 | |||
1435 | #ifdef GHC_EXPAND_IMPL | ||
1436 | |||
1437 | namespace detail { | ||
1438 | |||
1439 | GHC_INLINE bool startsWith(const std::string& what, const std::string& with) | ||
1440 | { | ||
1441 | return with.length() <= what.length() && equal(with.begin(), with.end(), what.begin()); | ||
1442 | } | ||
1443 | |||
1444 | } // namespace detail | ||
1445 | |||
1446 | GHC_INLINE void path::postprocess_path_with_format(path::impl_string_type& p, path::format fmt) | ||
1447 | { | ||
1448 | #ifdef GHC_RAISE_UNICODE_ERRORS | ||
1449 | if(!detail::validUtf8(p)) { | ||
1450 | path t; | ||
1451 | t._path = p; | ||
1452 | throw filesystem_error("Illegal byte sequence for unicode character.", t, std::make_error_code(std::errc::illegal_byte_sequence)); | ||
1453 | } | ||
1454 | #endif | ||
1455 | switch (fmt) { | ||
1456 | #ifndef GHC_OS_WINDOWS | ||
1457 | case path::auto_format: | ||
1458 | case path::native_format: | ||
1459 | #endif | ||
1460 | case path::generic_format: | ||
1461 | // nothing to do | ||
1462 | break; | ||
1463 | #ifdef GHC_OS_WINDOWS | ||
1464 | case path::auto_format: | ||
1465 | case path::native_format: | ||
1466 | if (detail::startsWith(p, std::string("\\\\?\\"))) { | ||
1467 | // remove Windows long filename marker | ||
1468 | p.erase(0, 4); | ||
1469 | if (detail::startsWith(p, std::string("UNC\\"))) { | ||
1470 | p.erase(0, 2); | ||
1471 | p[0] = '\\'; | ||
1472 | } | ||
1473 | } | ||
1474 | for (auto& c : p) { | ||
1475 | if (c == '\\') { | ||
1476 | c = '/'; | ||
1477 | } | ||
1478 | } | ||
1479 | break; | ||
1480 | #endif | ||
1481 | } | ||
1482 | if (p.length() > 2 && p[0] == '/' && p[1] == '/' && p[2] != '/') { | ||
1483 | std::string::iterator new_end = std::unique(p.begin() + 2, p.end(), [](path::value_type lhs, path::value_type rhs) { return lhs == rhs && lhs == '/'; }); | ||
1484 | p.erase(new_end, p.end()); | ||
1485 | } | ||
1486 | else { | ||
1487 | std::string::iterator new_end = std::unique(p.begin(), p.end(), [](path::value_type lhs, path::value_type rhs) { return lhs == rhs && lhs == '/'; }); | ||
1488 | p.erase(new_end, p.end()); | ||
1489 | } | ||
1490 | } | ||
1491 | |||
1492 | #endif // GHC_EXPAND_IMPL | ||
1493 | |||
1494 | template <class Source, typename> | ||
1495 | inline path::path(const Source& source, format fmt) | ||
1496 | : _path(detail::toUtf8(source)) | ||
1497 | { | ||
1498 | postprocess_path_with_format(_path, fmt); | ||
1499 | } | ||
1500 | template <> | ||
1501 | inline path::path(const std::wstring& source, format fmt) | ||
1502 | { | ||
1503 | _path = detail::toUtf8(source); | ||
1504 | postprocess_path_with_format(_path, fmt); | ||
1505 | } | ||
1506 | template <> | ||
1507 | inline path::path(const std::u16string& source, format fmt) | ||
1508 | { | ||
1509 | _path = detail::toUtf8(source); | ||
1510 | postprocess_path_with_format(_path, fmt); | ||
1511 | } | ||
1512 | template <> | ||
1513 | inline path::path(const std::u32string& source, format fmt) | ||
1514 | { | ||
1515 | _path = detail::toUtf8(source); | ||
1516 | postprocess_path_with_format(_path, fmt); | ||
1517 | } | ||
1518 | |||
1519 | #ifdef __cpp_lib_string_view | ||
1520 | template <> | ||
1521 | inline path::path(const std::string_view& source, format fmt) | ||
1522 | { | ||
1523 | _path = detail::toUtf8(std::string(source)); | ||
1524 | postprocess_path_with_format(_path, fmt); | ||
1525 | } | ||
1526 | #endif | ||
1527 | |||
1528 | template <class Source, typename> | ||
1529 | inline path u8path(const Source& source) | ||
1530 | { | ||
1531 | return path(source); | ||
1532 | } | ||
1533 | template <class InputIterator> | ||
1534 | inline path u8path(InputIterator first, InputIterator last) | ||
1535 | { | ||
1536 | return path(first, last); | ||
1537 | } | ||
1538 | |||
1539 | template <class InputIterator> | ||
1540 | inline path::path(InputIterator first, InputIterator last, format fmt) | ||
1541 | : path(std::basic_string<typename std::iterator_traits<InputIterator>::value_type>(first, last), fmt) | ||
1542 | { | ||
1543 | // delegated | ||
1544 | } | ||
1545 | |||
1546 | #ifdef GHC_EXPAND_IMPL | ||
1547 | |||
1548 | namespace detail { | ||
1549 | |||
1550 | GHC_INLINE bool equals_simple_insensitive(const char* str1, const char* str2) | ||
1551 | { | ||
1552 | #ifdef GHC_OS_WINDOWS | ||
1553 | #ifdef __GNUC__ | ||
1554 | while (::tolower((unsigned char)*str1) == ::tolower((unsigned char)*str2++)) { | ||
1555 | if (*str1++ == 0) | ||
1556 | return true; | ||
1557 | } | ||
1558 | return false; | ||
1559 | #else | ||
1560 | return 0 == ::_stricmp(str1, str2); | ||
1561 | #endif | ||
1562 | #else | ||
1563 | return 0 == ::strcasecmp(str1, str2); | ||
1564 | #endif | ||
1565 | } | ||
1566 | |||
1567 | GHC_INLINE const char* strerror_adapter(char* gnu, char*) | ||
1568 | { | ||
1569 | return gnu; | ||
1570 | } | ||
1571 | |||
1572 | GHC_INLINE const char* strerror_adapter(int posix, char* buffer) | ||
1573 | { | ||
1574 | if(posix) { | ||
1575 | return "Error in strerror_r!"; | ||
1576 | } | ||
1577 | return buffer; | ||
1578 | } | ||
1579 | |||
1580 | template <typename ErrorNumber> | ||
1581 | GHC_INLINE std::string systemErrorText(ErrorNumber code = 0) | ||
1582 | { | ||
1583 | #if defined(GHC_OS_WINDOWS) | ||
1584 | LPVOID msgBuf; | ||
1585 | DWORD dw = code ? static_cast<DWORD>(code) : ::GetLastError(); | ||
1586 | FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&msgBuf, 0, NULL); | ||
1587 | std::string msg = toUtf8(std::wstring((LPWSTR)msgBuf)); | ||
1588 | LocalFree(msgBuf); | ||
1589 | return msg; | ||
1590 | #else | ||
1591 | char buffer[512]; | ||
1592 | return strerror_adapter(strerror_r(code ? code : errno, buffer, sizeof(buffer)), buffer); | ||
1593 | #endif | ||
1594 | } | ||
1595 | |||
1596 | #ifdef GHC_OS_WINDOWS | ||
1597 | using CreateSymbolicLinkW_fp = BOOLEAN(WINAPI*)(LPCWSTR, LPCWSTR, DWORD); | ||
1598 | using CreateHardLinkW_fp = BOOLEAN(WINAPI*)(LPCWSTR, LPCWSTR, LPSECURITY_ATTRIBUTES); | ||
1599 | |||
1600 | GHC_INLINE void create_symlink(const path& target_name, const path& new_symlink, bool to_directory, std::error_code& ec) | ||
1601 | { | ||
1602 | std::error_code tec; | ||
1603 | auto fs = status(target_name, tec); | ||
1604 | if ((fs.type() == file_type::directory && !to_directory) || (fs.type() == file_type::regular && to_directory)) { | ||
1605 | ec = detail::make_error_code(detail::portable_error::not_supported); | ||
1606 | return; | ||
1607 | } | ||
1608 | #if defined(__GNUC__) && __GNUC__ >= 8 | ||
1609 | #pragma GCC diagnostic push | ||
1610 | #pragma GCC diagnostic ignored "-Wcast-function-type" | ||
1611 | #endif | ||
1612 | static CreateSymbolicLinkW_fp api_call = reinterpret_cast<CreateSymbolicLinkW_fp>(GetProcAddress(GetModuleHandleW(L"kernel32.dll"), "CreateSymbolicLinkW")); | ||
1613 | #if defined(__GNUC__) && __GNUC__ >= 8 | ||
1614 | #pragma GCC diagnostic pop | ||
1615 | #endif | ||
1616 | if (api_call) { | ||
1617 | if (api_call(detail::fromUtf8<std::wstring>(new_symlink.u8string()).c_str(), detail::fromUtf8<std::wstring>(target_name.u8string()).c_str(), to_directory ? 1 : 0) == 0) { | ||
1618 | auto result = ::GetLastError(); | ||
1619 | if (result == ERROR_PRIVILEGE_NOT_HELD && api_call(detail::fromUtf8<std::wstring>(new_symlink.u8string()).c_str(), detail::fromUtf8<std::wstring>(target_name.u8string()).c_str(), to_directory ? 3 : 2) != 0) { | ||
1620 | return; | ||
1621 | } | ||
1622 | ec = detail::make_system_error(result); | ||
1623 | } | ||
1624 | } | ||
1625 | else { | ||
1626 | ec = detail::make_system_error(ERROR_NOT_SUPPORTED); | ||
1627 | } | ||
1628 | } | ||
1629 | |||
1630 | GHC_INLINE void create_hardlink(const path& target_name, const path& new_hardlink, std::error_code& ec) | ||
1631 | { | ||
1632 | #if defined(__GNUC__) && __GNUC__ >= 8 | ||
1633 | #pragma GCC diagnostic push | ||
1634 | #pragma GCC diagnostic ignored "-Wcast-function-type" | ||
1635 | #endif | ||
1636 | static CreateHardLinkW_fp api_call = reinterpret_cast<CreateHardLinkW_fp>(GetProcAddress(GetModuleHandleW(L"kernel32.dll"), "CreateHardLinkW")); | ||
1637 | #if defined(__GNUC__) && __GNUC__ >= 8 | ||
1638 | #pragma GCC diagnostic pop | ||
1639 | #endif | ||
1640 | if (api_call) { | ||
1641 | if (api_call(detail::fromUtf8<std::wstring>(new_hardlink.u8string()).c_str(), detail::fromUtf8<std::wstring>(target_name.u8string()).c_str(), NULL) == 0) { | ||
1642 | ec = detail::make_system_error(); | ||
1643 | } | ||
1644 | } | ||
1645 | else { | ||
1646 | ec = detail::make_system_error(ERROR_NOT_SUPPORTED); | ||
1647 | } | ||
1648 | } | ||
1649 | #else | ||
1650 | GHC_INLINE void create_symlink(const path& target_name, const path& new_symlink, bool, std::error_code& ec) | ||
1651 | { | ||
1652 | if (::symlink(target_name.c_str(), new_symlink.c_str()) != 0) { | ||
1653 | ec = detail::make_system_error(); | ||
1654 | } | ||
1655 | } | ||
1656 | |||
1657 | GHC_INLINE void create_hardlink(const path& target_name, const path& new_hardlink, std::error_code& ec) | ||
1658 | { | ||
1659 | if (::link(target_name.c_str(), new_hardlink.c_str()) != 0) { | ||
1660 | ec = detail::make_system_error(); | ||
1661 | } | ||
1662 | } | ||
1663 | #endif | ||
1664 | |||
1665 | template <typename T> | ||
1666 | GHC_INLINE file_status file_status_from_st_mode(T mode) | ||
1667 | { | ||
1668 | #ifdef GHC_OS_WINDOWS | ||
1669 | file_type ft = file_type::unknown; | ||
1670 | if ((mode & _S_IFDIR) == _S_IFDIR) { | ||
1671 | ft = file_type::directory; | ||
1672 | } | ||
1673 | else if ((mode & _S_IFREG) == _S_IFREG) { | ||
1674 | ft = file_type::regular; | ||
1675 | } | ||
1676 | else if ((mode & _S_IFCHR) == _S_IFCHR) { | ||
1677 | ft = file_type::character; | ||
1678 | } | ||
1679 | perms prms = static_cast<perms>(mode & 0xfff); | ||
1680 | return file_status(ft, prms); | ||
1681 | #else | ||
1682 | file_type ft = file_type::unknown; | ||
1683 | if (S_ISDIR(mode)) { | ||
1684 | ft = file_type::directory; | ||
1685 | } | ||
1686 | else if (S_ISREG(mode)) { | ||
1687 | ft = file_type::regular; | ||
1688 | } | ||
1689 | else if (S_ISCHR(mode)) { | ||
1690 | ft = file_type::character; | ||
1691 | } | ||
1692 | else if (S_ISBLK(mode)) { | ||
1693 | ft = file_type::block; | ||
1694 | } | ||
1695 | else if (S_ISFIFO(mode)) { | ||
1696 | ft = file_type::fifo; | ||
1697 | } | ||
1698 | else if (S_ISLNK(mode)) { | ||
1699 | ft = file_type::symlink; | ||
1700 | } | ||
1701 | else if (S_ISSOCK(mode)) { | ||
1702 | ft = file_type::socket; | ||
1703 | } | ||
1704 | perms prms = static_cast<perms>(mode & 0xfff); | ||
1705 | return file_status(ft, prms); | ||
1706 | #endif | ||
1707 | } | ||
1708 | |||
1709 | GHC_INLINE path resolveSymlink(const path& p, std::error_code& ec) | ||
1710 | { | ||
1711 | #ifdef GHC_OS_WINDOWS | ||
1712 | #ifndef REPARSE_DATA_BUFFER_HEADER_SIZE | ||
1713 | typedef struct _REPARSE_DATA_BUFFER | ||
1714 | { | ||
1715 | ULONG ReparseTag; | ||
1716 | USHORT ReparseDataLength; | ||
1717 | USHORT Reserved; | ||
1718 | union | ||
1719 | { | ||
1720 | struct | ||
1721 | { | ||
1722 | USHORT SubstituteNameOffset; | ||
1723 | USHORT SubstituteNameLength; | ||
1724 | USHORT PrintNameOffset; | ||
1725 | USHORT PrintNameLength; | ||
1726 | ULONG Flags; | ||
1727 | WCHAR PathBuffer[1]; | ||
1728 | } SymbolicLinkReparseBuffer; | ||
1729 | struct | ||
1730 | { | ||
1731 | USHORT SubstituteNameOffset; | ||
1732 | USHORT SubstituteNameLength; | ||
1733 | USHORT PrintNameOffset; | ||
1734 | USHORT PrintNameLength; | ||
1735 | WCHAR PathBuffer[1]; | ||
1736 | } MountPointReparseBuffer; | ||
1737 | struct | ||
1738 | { | ||
1739 | UCHAR DataBuffer[1]; | ||
1740 | } GenericReparseBuffer; | ||
1741 | } DUMMYUNIONNAME; | ||
1742 | } REPARSE_DATA_BUFFER; | ||
1743 | #ifndef MAXIMUM_REPARSE_DATA_BUFFER_SIZE | ||
1744 | #define MAXIMUM_REPARSE_DATA_BUFFER_SIZE (16 * 1024) | ||
1745 | #endif | ||
1746 | #endif | ||
1747 | |||
1748 | std::shared_ptr<void> file(CreateFileW(p.wstring().c_str(), 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 0, OPEN_EXISTING, FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, 0), CloseHandle); | ||
1749 | if (file.get() == INVALID_HANDLE_VALUE) { | ||
1750 | ec = detail::make_system_error(); | ||
1751 | return path(); | ||
1752 | } | ||
1753 | |||
1754 | std::shared_ptr<REPARSE_DATA_BUFFER> reparseData((REPARSE_DATA_BUFFER*)std::calloc(1, MAXIMUM_REPARSE_DATA_BUFFER_SIZE), std::free); | ||
1755 | ULONG bufferUsed; | ||
1756 | path result; | ||
1757 | if (DeviceIoControl(file.get(), FSCTL_GET_REPARSE_POINT, 0, 0, reparseData.get(), MAXIMUM_REPARSE_DATA_BUFFER_SIZE, &bufferUsed, 0)) { | ||
1758 | if (IsReparseTagMicrosoft(reparseData->ReparseTag)) { | ||
1759 | switch (reparseData->ReparseTag) { | ||
1760 | case IO_REPARSE_TAG_SYMLINK: | ||
1761 | result = std::wstring(&reparseData->SymbolicLinkReparseBuffer.PathBuffer[reparseData->SymbolicLinkReparseBuffer.PrintNameOffset / sizeof(WCHAR)], reparseData->SymbolicLinkReparseBuffer.PrintNameLength / sizeof(WCHAR)); | ||
1762 | break; | ||
1763 | case IO_REPARSE_TAG_MOUNT_POINT: | ||
1764 | result = std::wstring(&reparseData->MountPointReparseBuffer.PathBuffer[reparseData->MountPointReparseBuffer.PrintNameOffset / sizeof(WCHAR)], reparseData->MountPointReparseBuffer.PrintNameLength / sizeof(WCHAR)); | ||
1765 | break; | ||
1766 | default: | ||
1767 | break; | ||
1768 | } | ||
1769 | } | ||
1770 | } | ||
1771 | else { | ||
1772 | ec = detail::make_system_error(); | ||
1773 | } | ||
1774 | return result; | ||
1775 | #else | ||
1776 | size_t bufferSize = 256; | ||
1777 | while (true) { | ||
1778 | std::vector<char> buffer(bufferSize, static_cast<char>(0)); | ||
1779 | auto rc = ::readlink(p.c_str(), buffer.data(), buffer.size()); | ||
1780 | if (rc < 0) { | ||
1781 | ec = detail::make_system_error(); | ||
1782 | return path(); | ||
1783 | } | ||
1784 | else if (rc < static_cast<int>(bufferSize)) { | ||
1785 | return path(std::string(buffer.data(), static_cast<std::string::size_type>(rc))); | ||
1786 | } | ||
1787 | bufferSize *= 2; | ||
1788 | } | ||
1789 | return path(); | ||
1790 | #endif | ||
1791 | } | ||
1792 | |||
1793 | #ifdef GHC_OS_WINDOWS | ||
1794 | GHC_INLINE time_t timeFromFILETIME(const FILETIME& ft) | ||
1795 | { | ||
1796 | ULARGE_INTEGER ull; | ||
1797 | ull.LowPart = ft.dwLowDateTime; | ||
1798 | ull.HighPart = ft.dwHighDateTime; | ||
1799 | return static_cast<time_t>(ull.QuadPart / 10000000ULL - 11644473600ULL); | ||
1800 | } | ||
1801 | |||
1802 | GHC_INLINE void timeToFILETIME(time_t t, FILETIME& ft) | ||
1803 | { | ||
1804 | LONGLONG ll; | ||
1805 | ll = Int32x32To64(t, 10000000) + 116444736000000000; | ||
1806 | ft.dwLowDateTime = static_cast<DWORD>(ll); | ||
1807 | ft.dwHighDateTime = static_cast<DWORD>(ll >> 32); | ||
1808 | } | ||
1809 | |||
1810 | template <typename INFO> | ||
1811 | GHC_INLINE uintmax_t hard_links_from_INFO(const INFO* info) | ||
1812 | { | ||
1813 | return static_cast<uintmax_t>(-1); | ||
1814 | } | ||
1815 | |||
1816 | template <> | ||
1817 | GHC_INLINE uintmax_t hard_links_from_INFO<BY_HANDLE_FILE_INFORMATION>(const BY_HANDLE_FILE_INFORMATION* info) | ||
1818 | { | ||
1819 | return info->nNumberOfLinks; | ||
1820 | } | ||
1821 | |||
1822 | template <typename INFO> | ||
1823 | GHC_INLINE file_status status_from_INFO(const path& p, const INFO* info, std::error_code&, uintmax_t* sz = nullptr, time_t* lwt = nullptr) noexcept | ||
1824 | { | ||
1825 | file_type ft = file_type::unknown; | ||
1826 | if ((info->dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) { | ||
1827 | ft = file_type::symlink; | ||
1828 | } | ||
1829 | else { | ||
1830 | if ((info->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { | ||
1831 | ft = file_type::directory; | ||
1832 | } | ||
1833 | else { | ||
1834 | ft = file_type::regular; | ||
1835 | } | ||
1836 | } | ||
1837 | perms prms = perms::owner_read | perms::group_read | perms::others_read; | ||
1838 | if (!(info->dwFileAttributes & FILE_ATTRIBUTE_READONLY)) { | ||
1839 | prms = prms | perms::owner_write | perms::group_write | perms::others_write; | ||
1840 | } | ||
1841 | std::string ext = p.extension().generic_string(); | ||
1842 | if (equals_simple_insensitive(ext.c_str(), ".exe") || equals_simple_insensitive(ext.c_str(), ".cmd") || equals_simple_insensitive(ext.c_str(), ".bat") || equals_simple_insensitive(ext.c_str(), ".com")) { | ||
1843 | prms = prms | perms::owner_exec | perms::group_exec | perms::others_exec; | ||
1844 | } | ||
1845 | if (sz) { | ||
1846 | *sz = static_cast<uintmax_t>(info->nFileSizeHigh) << (sizeof(info->nFileSizeHigh) * 8) | info->nFileSizeLow; | ||
1847 | } | ||
1848 | if (lwt) { | ||
1849 | *lwt = detail::timeFromFILETIME(info->ftLastWriteTime); | ||
1850 | } | ||
1851 | return file_status(ft, prms); | ||
1852 | } | ||
1853 | |||
1854 | #endif | ||
1855 | |||
1856 | GHC_INLINE bool is_not_found_error(std::error_code& ec) | ||
1857 | { | ||
1858 | #ifdef GHC_OS_WINDOWS | ||
1859 | return ec.value() == ERROR_FILE_NOT_FOUND || ec.value() == ERROR_PATH_NOT_FOUND || ec.value() == ERROR_INVALID_NAME; | ||
1860 | #else | ||
1861 | return ec.value() == ENOENT || ec.value() == ENOTDIR; | ||
1862 | #endif | ||
1863 | } | ||
1864 | |||
1865 | GHC_INLINE file_status symlink_status_ex(const path& p, std::error_code& ec, uintmax_t* sz = nullptr, uintmax_t* nhl = nullptr, time_t* lwt = nullptr) noexcept | ||
1866 | { | ||
1867 | #ifdef GHC_OS_WINDOWS | ||
1868 | file_status fs; | ||
1869 | WIN32_FILE_ATTRIBUTE_DATA attr; | ||
1870 | if (!GetFileAttributesExW(detail::fromUtf8<std::wstring>(p.u8string()).c_str(), GetFileExInfoStandard, &attr)) { | ||
1871 | ec = detail::make_system_error(); | ||
1872 | } | ||
1873 | else { | ||
1874 | ec.clear(); | ||
1875 | fs = detail::status_from_INFO(p, &attr, ec, sz, lwt); | ||
1876 | if (nhl) { | ||
1877 | *nhl = 0; | ||
1878 | } | ||
1879 | if (attr.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { | ||
1880 | fs.type(file_type::symlink); | ||
1881 | } | ||
1882 | } | ||
1883 | if (detail::is_not_found_error(ec)) { | ||
1884 | return file_status(file_type::not_found); | ||
1885 | } | ||
1886 | return ec ? file_status(file_type::none) : fs; | ||
1887 | #else | ||
1888 | (void)sz; | ||
1889 | (void)nhl; | ||
1890 | (void)lwt; | ||
1891 | struct ::stat fs; | ||
1892 | auto result = ::lstat(p.c_str(), &fs); | ||
1893 | if (result == 0) { | ||
1894 | ec.clear(); | ||
1895 | file_status f_s = detail::file_status_from_st_mode(fs.st_mode); | ||
1896 | return f_s; | ||
1897 | } | ||
1898 | ec = detail::make_system_error(); | ||
1899 | if (detail::is_not_found_error(ec)) { | ||
1900 | return file_status(file_type::not_found, perms::unknown); | ||
1901 | } | ||
1902 | return file_status(file_type::none); | ||
1903 | #endif | ||
1904 | } | ||
1905 | |||
1906 | GHC_INLINE file_status status_ex(const path& p, std::error_code& ec, file_status* sls = nullptr, uintmax_t* sz = nullptr, uintmax_t* nhl = nullptr, time_t* lwt = nullptr, int recurse_count = 0) noexcept | ||
1907 | { | ||
1908 | ec.clear(); | ||
1909 | #ifdef GHC_OS_WINDOWS | ||
1910 | if (recurse_count > 16) { | ||
1911 | ec = detail::make_system_error(0x2A9 /*ERROR_STOPPED_ON_SYMLINK*/); | ||
1912 | return file_status(file_type::unknown); | ||
1913 | } | ||
1914 | WIN32_FILE_ATTRIBUTE_DATA attr; | ||
1915 | if (!::GetFileAttributesExW(p.wstring().c_str(), GetFileExInfoStandard, &attr)) { | ||
1916 | ec = detail::make_system_error(); | ||
1917 | } | ||
1918 | else if (attr.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { | ||
1919 | path target = resolveSymlink(p, ec); | ||
1920 | file_status result; | ||
1921 | if (!ec && !target.empty()) { | ||
1922 | if (sls) { | ||
1923 | *sls = status_from_INFO(p, &attr, ec); | ||
1924 | } | ||
1925 | return detail::status_ex(target, ec, nullptr, sz, nhl, lwt, recurse_count + 1); | ||
1926 | } | ||
1927 | return file_status(file_type::unknown); | ||
1928 | } | ||
1929 | if (ec) { | ||
1930 | if (detail::is_not_found_error(ec)) { | ||
1931 | return file_status(file_type::not_found); | ||
1932 | } | ||
1933 | return file_status(file_type::none); | ||
1934 | } | ||
1935 | if (nhl) { | ||
1936 | *nhl = 0; | ||
1937 | } | ||
1938 | return detail::status_from_INFO(p, &attr, ec, sz, lwt); | ||
1939 | #else | ||
1940 | (void)recurse_count; | ||
1941 | struct ::stat st; | ||
1942 | auto result = ::lstat(p.c_str(), &st); | ||
1943 | if (result == 0) { | ||
1944 | ec.clear(); | ||
1945 | file_status fs = detail::file_status_from_st_mode(st.st_mode); | ||
1946 | if (fs.type() == file_type::symlink) { | ||
1947 | result = ::stat(p.c_str(), &st); | ||
1948 | if (result == 0) { | ||
1949 | if (sls) { | ||
1950 | *sls = fs; | ||
1951 | } | ||
1952 | fs = detail::file_status_from_st_mode(st.st_mode); | ||
1953 | } | ||
1954 | } | ||
1955 | if (sz) { | ||
1956 | *sz = static_cast<uintmax_t>(st.st_size); | ||
1957 | } | ||
1958 | if (nhl) { | ||
1959 | *nhl = st.st_nlink; | ||
1960 | } | ||
1961 | if (lwt) { | ||
1962 | *lwt = st.st_mtime; | ||
1963 | } | ||
1964 | return fs; | ||
1965 | } | ||
1966 | else { | ||
1967 | ec = detail::make_system_error(); | ||
1968 | if (detail::is_not_found_error(ec)) { | ||
1969 | return file_status(file_type::not_found, perms::unknown); | ||
1970 | } | ||
1971 | return file_status(file_type::none); | ||
1972 | } | ||
1973 | #endif | ||
1974 | } | ||
1975 | |||
1976 | } // namespace detail | ||
1977 | |||
1978 | GHC_INLINE u8arguments::u8arguments(int& argc, char**& argv) | ||
1979 | : _argc(argc) | ||
1980 | , _argv(argv) | ||
1981 | , _refargc(argc) | ||
1982 | , _refargv(argv) | ||
1983 | , _isvalid(false) | ||
1984 | { | ||
1985 | #ifdef GHC_OS_WINDOWS | ||
1986 | LPWSTR* p; | ||
1987 | p = ::CommandLineToArgvW(::GetCommandLineW(), &argc); | ||
1988 | _args.reserve(static_cast<size_t>(argc)); | ||
1989 | _argp.reserve(static_cast<size_t>(argc)); | ||
1990 | for (size_t i = 0; i < static_cast<size_t>(argc); ++i) { | ||
1991 | _args.push_back(detail::toUtf8(std::wstring(p[i]))); | ||
1992 | _argp.push_back((char*)_args[i].data()); | ||
1993 | } | ||
1994 | argv = _argp.data(); | ||
1995 | ::LocalFree(p); | ||
1996 | _isvalid = true; | ||
1997 | #else | ||
1998 | std::setlocale(LC_ALL, ""); | ||
1999 | #if defined(__ANDROID__) && __ANDROID_API__ < 26 | ||
2000 | _isvalid = true; | ||
2001 | #else | ||
2002 | if (detail::equals_simple_insensitive(::nl_langinfo(CODESET), "UTF-8")) { | ||
2003 | _isvalid = true; | ||
2004 | } | ||
2005 | #endif | ||
2006 | #endif | ||
2007 | } | ||
2008 | |||
2009 | //----------------------------------------------------------------------------- | ||
2010 | // 30.10.8.4.1 constructors and destructor | ||
2011 | |||
2012 | GHC_INLINE path::path() noexcept {} | ||
2013 | |||
2014 | GHC_INLINE path::path(const path& p) | ||
2015 | : _path(p._path) | ||
2016 | { | ||
2017 | } | ||
2018 | |||
2019 | GHC_INLINE path::path(path&& p) noexcept | ||
2020 | : _path(std::move(p._path)) | ||
2021 | { | ||
2022 | } | ||
2023 | |||
2024 | GHC_INLINE path::path(string_type&& source, format fmt) | ||
2025 | #ifdef GHC_USE_WCHAR_T | ||
2026 | : _path(detail::toUtf8(source)) | ||
2027 | #else | ||
2028 | : _path(std::move(source)) | ||
2029 | #endif | ||
2030 | { | ||
2031 | postprocess_path_with_format(_path, fmt); | ||
2032 | } | ||
2033 | |||
2034 | #endif // GHC_EXPAND_IMPL | ||
2035 | |||
2036 | template <class Source, typename> | ||
2037 | inline path::path(const Source& source, const std::locale& loc, format fmt) | ||
2038 | : path(source, fmt) | ||
2039 | { | ||
2040 | std::string locName = loc.name(); | ||
2041 | if (!(locName.length() >= 5 && (locName.substr(locName.length() - 5) == "UTF-8" || locName.substr(locName.length() - 5) == "utf-8"))) { | ||
2042 | throw filesystem_error("This implementation only supports UTF-8 locales!", path(_path), detail::make_error_code(detail::portable_error::not_supported)); | ||
2043 | } | ||
2044 | } | ||
2045 | |||
2046 | template <class InputIterator> | ||
2047 | inline path::path(InputIterator first, InputIterator last, const std::locale& loc, format fmt) | ||
2048 | : path(std::basic_string<typename std::iterator_traits<InputIterator>::value_type>(first, last), fmt) | ||
2049 | { | ||
2050 | std::string locName = loc.name(); | ||
2051 | if (!(locName.length() >= 5 && (locName.substr(locName.length() - 5) == "UTF-8" || locName.substr(locName.length() - 5) == "utf-8"))) { | ||
2052 | throw filesystem_error("This implementation only supports UTF-8 locales!", path(_path), detail::make_error_code(detail::portable_error::not_supported)); | ||
2053 | } | ||
2054 | } | ||
2055 | |||
2056 | #ifdef GHC_EXPAND_IMPL | ||
2057 | |||
2058 | GHC_INLINE path::~path() {} | ||
2059 | |||
2060 | //----------------------------------------------------------------------------- | ||
2061 | // 30.10.8.4.2 assignments | ||
2062 | |||
2063 | GHC_INLINE path& path::operator=(const path& p) | ||
2064 | { | ||
2065 | _path = p._path; | ||
2066 | return *this; | ||
2067 | } | ||
2068 | |||
2069 | GHC_INLINE path& path::operator=(path&& p) noexcept | ||
2070 | { | ||
2071 | _path = std::move(p._path); | ||
2072 | return *this; | ||
2073 | } | ||
2074 | |||
2075 | GHC_INLINE path& path::operator=(path::string_type&& source) | ||
2076 | { | ||
2077 | return assign(source); | ||
2078 | } | ||
2079 | |||
2080 | GHC_INLINE path& path::assign(path::string_type&& source) | ||
2081 | { | ||
2082 | #ifdef GHC_USE_WCHAR_T | ||
2083 | _path = detail::toUtf8(source); | ||
2084 | #else | ||
2085 | _path = std::move(source); | ||
2086 | #endif | ||
2087 | postprocess_path_with_format(_path, native_format); | ||
2088 | return *this; | ||
2089 | } | ||
2090 | |||
2091 | #endif // GHC_EXPAND_IMPL | ||
2092 | |||
2093 | template <class Source> | ||
2094 | inline path& path::operator=(const Source& source) | ||
2095 | { | ||
2096 | return assign(source); | ||
2097 | } | ||
2098 | |||
2099 | template <class Source> | ||
2100 | inline path& path::assign(const Source& source) | ||
2101 | { | ||
2102 | _path.assign(detail::toUtf8(source)); | ||
2103 | postprocess_path_with_format(_path, native_format); | ||
2104 | return *this; | ||
2105 | } | ||
2106 | |||
2107 | template <> | ||
2108 | inline path& path::assign<path>(const path& source) | ||
2109 | { | ||
2110 | _path = source._path; | ||
2111 | return *this; | ||
2112 | } | ||
2113 | |||
2114 | template <class InputIterator> | ||
2115 | inline path& path::assign(InputIterator first, InputIterator last) | ||
2116 | { | ||
2117 | _path.assign(first, last); | ||
2118 | postprocess_path_with_format(_path, native_format); | ||
2119 | return *this; | ||
2120 | } | ||
2121 | |||
2122 | #ifdef GHC_EXPAND_IMPL | ||
2123 | |||
2124 | //----------------------------------------------------------------------------- | ||
2125 | // 30.10.8.4.3 appends | ||
2126 | |||
2127 | GHC_INLINE path& path::operator/=(const path& p) | ||
2128 | { | ||
2129 | if (p.empty()) { | ||
2130 | // was: if ((!has_root_directory() && is_absolute()) || has_filename()) | ||
2131 | if (!_path.empty() && _path[_path.length() - 1] != '/' && _path[_path.length() - 1] != ':') { | ||
2132 | _path += '/'; | ||
2133 | } | ||
2134 | return *this; | ||
2135 | } | ||
2136 | if ((p.is_absolute() && (_path != root_name() || p._path != "/")) || (p.has_root_name() && p.root_name() != root_name())) { | ||
2137 | assign(p); | ||
2138 | return *this; | ||
2139 | } | ||
2140 | if (p.has_root_directory()) { | ||
2141 | assign(root_name()); | ||
2142 | } | ||
2143 | else if ((!has_root_directory() && is_absolute()) || has_filename()) { | ||
2144 | _path += '/'; | ||
2145 | } | ||
2146 | auto iter = p.begin(); | ||
2147 | bool first = true; | ||
2148 | if (p.has_root_name()) { | ||
2149 | ++iter; | ||
2150 | } | ||
2151 | while (iter != p.end()) { | ||
2152 | if (!first && !(!_path.empty() && _path[_path.length() - 1] == '/')) { | ||
2153 | _path += '/'; | ||
2154 | } | ||
2155 | first = false; | ||
2156 | _path += (*iter++).generic_string(); | ||
2157 | } | ||
2158 | return *this; | ||
2159 | } | ||
2160 | |||
2161 | GHC_INLINE void path::append_name(const char* name) | ||
2162 | { | ||
2163 | if (_path.empty()) { | ||
2164 | this->operator/=(path(name)); | ||
2165 | } | ||
2166 | else { | ||
2167 | if (_path.back() != path::generic_separator) { | ||
2168 | _path.push_back(path::generic_separator); | ||
2169 | } | ||
2170 | _path += name; | ||
2171 | } | ||
2172 | } | ||
2173 | |||
2174 | #endif // GHC_EXPAND_IMPL | ||
2175 | |||
2176 | template <class Source> | ||
2177 | inline path& path::operator/=(const Source& source) | ||
2178 | { | ||
2179 | return append(source); | ||
2180 | } | ||
2181 | |||
2182 | template <class Source> | ||
2183 | inline path& path::append(const Source& source) | ||
2184 | { | ||
2185 | return this->operator/=(path(detail::toUtf8(source))); | ||
2186 | } | ||
2187 | |||
2188 | template <> | ||
2189 | inline path& path::append<path>(const path& p) | ||
2190 | { | ||
2191 | return this->operator/=(p); | ||
2192 | } | ||
2193 | |||
2194 | template <class InputIterator> | ||
2195 | inline path& path::append(InputIterator first, InputIterator last) | ||
2196 | { | ||
2197 | std::basic_string<typename std::iterator_traits<InputIterator>::value_type> part(first, last); | ||
2198 | return append(part); | ||
2199 | } | ||
2200 | |||
2201 | #ifdef GHC_EXPAND_IMPL | ||
2202 | |||
2203 | //----------------------------------------------------------------------------- | ||
2204 | // 30.10.8.4.4 concatenation | ||
2205 | |||
2206 | GHC_INLINE path& path::operator+=(const path& x) | ||
2207 | { | ||
2208 | return concat(x._path); | ||
2209 | } | ||
2210 | |||
2211 | GHC_INLINE path& path::operator+=(const string_type& x) | ||
2212 | { | ||
2213 | return concat(x); | ||
2214 | } | ||
2215 | |||
2216 | #ifdef __cpp_lib_string_view | ||
2217 | GHC_INLINE path& path::operator+=(std::basic_string_view<value_type> x) | ||
2218 | { | ||
2219 | return concat(x); | ||
2220 | } | ||
2221 | #endif | ||
2222 | |||
2223 | GHC_INLINE path& path::operator+=(const value_type* x) | ||
2224 | { | ||
2225 | return concat(string_type(x)); | ||
2226 | } | ||
2227 | |||
2228 | GHC_INLINE path& path::operator+=(value_type x) | ||
2229 | { | ||
2230 | #ifdef GHC_OS_WINDOWS | ||
2231 | if (x == '\\') { | ||
2232 | x = generic_separator; | ||
2233 | } | ||
2234 | #endif | ||
2235 | if (_path.empty() || _path.back() != generic_separator) { | ||
2236 | #ifdef GHC_USE_WCHAR_T | ||
2237 | _path += detail::toUtf8(string_type(1, x)); | ||
2238 | #else | ||
2239 | _path += x; | ||
2240 | #endif | ||
2241 | } | ||
2242 | return *this; | ||
2243 | } | ||
2244 | |||
2245 | #endif // GHC_EXPAND_IMPL | ||
2246 | |||
2247 | template <class Source> | ||
2248 | inline path::path_from_string<Source>& path::operator+=(const Source& x) | ||
2249 | { | ||
2250 | return concat(x); | ||
2251 | } | ||
2252 | |||
2253 | template <class EcharT> | ||
2254 | inline path::path_type_EcharT<EcharT>& path::operator+=(EcharT x) | ||
2255 | { | ||
2256 | std::basic_string<EcharT> part(1, x); | ||
2257 | concat(detail::toUtf8(part)); | ||
2258 | return *this; | ||
2259 | } | ||
2260 | |||
2261 | template <class Source> | ||
2262 | inline path& path::concat(const Source& x) | ||
2263 | { | ||
2264 | path p(x); | ||
2265 | postprocess_path_with_format(p._path, native_format); | ||
2266 | _path += p._path; | ||
2267 | return *this; | ||
2268 | } | ||
2269 | template <class InputIterator> | ||
2270 | inline path& path::concat(InputIterator first, InputIterator last) | ||
2271 | { | ||
2272 | _path.append(first, last); | ||
2273 | postprocess_path_with_format(_path, native_format); | ||
2274 | return *this; | ||
2275 | } | ||
2276 | |||
2277 | #ifdef GHC_EXPAND_IMPL | ||
2278 | |||
2279 | //----------------------------------------------------------------------------- | ||
2280 | // 30.10.8.4.5 modifiers | ||
2281 | GHC_INLINE void path::clear() noexcept | ||
2282 | { | ||
2283 | _path.clear(); | ||
2284 | } | ||
2285 | |||
2286 | GHC_INLINE path& path::make_preferred() | ||
2287 | { | ||
2288 | // as this filesystem implementation only uses generic_format | ||
2289 | // internally, this must be a no-op | ||
2290 | return *this; | ||
2291 | } | ||
2292 | |||
2293 | GHC_INLINE path& path::remove_filename() | ||
2294 | { | ||
2295 | if (has_filename()) { | ||
2296 | _path.erase(_path.size() - filename()._path.size()); | ||
2297 | } | ||
2298 | return *this; | ||
2299 | } | ||
2300 | |||
2301 | GHC_INLINE path& path::replace_filename(const path& replacement) | ||
2302 | { | ||
2303 | remove_filename(); | ||
2304 | return append(replacement); | ||
2305 | } | ||
2306 | |||
2307 | GHC_INLINE path& path::replace_extension(const path& replacement) | ||
2308 | { | ||
2309 | if (has_extension()) { | ||
2310 | _path.erase(_path.size() - extension()._path.size()); | ||
2311 | } | ||
2312 | if (!replacement.empty() && replacement._path[0] != '.') { | ||
2313 | _path += '.'; | ||
2314 | } | ||
2315 | return concat(replacement); | ||
2316 | } | ||
2317 | |||
2318 | GHC_INLINE void path::swap(path& rhs) noexcept | ||
2319 | { | ||
2320 | _path.swap(rhs._path); | ||
2321 | } | ||
2322 | |||
2323 | //----------------------------------------------------------------------------- | ||
2324 | // 30.10.8.4.6, native format observers | ||
2325 | #ifdef GHC_OS_WINDOWS | ||
2326 | GHC_INLINE path::impl_string_type path::native_impl() const | ||
2327 | { | ||
2328 | impl_string_type result; | ||
2329 | if (is_absolute() && _path.length() > MAX_PATH - 10) { | ||
2330 | // expand long Windows filenames with marker | ||
2331 | if (has_root_name() && _path[0] == '/') { | ||
2332 | result = "\\\\?\\UNC" + _path.substr(1); | ||
2333 | } | ||
2334 | else { | ||
2335 | result = "\\\\?\\" + _path; | ||
2336 | } | ||
2337 | } | ||
2338 | else { | ||
2339 | result = _path; | ||
2340 | } | ||
2341 | /*if (has_root_name() && root_name()._path[0] == '/') { | ||
2342 | return _path; | ||
2343 | }*/ | ||
2344 | for (auto& c : result) { | ||
2345 | if (c == '/') { | ||
2346 | c = '\\'; | ||
2347 | } | ||
2348 | } | ||
2349 | return result; | ||
2350 | } | ||
2351 | #else | ||
2352 | GHC_INLINE const path::impl_string_type& path::native_impl() const | ||
2353 | { | ||
2354 | return _path; | ||
2355 | } | ||
2356 | #endif | ||
2357 | |||
2358 | GHC_INLINE const path::string_type& path::native() const | ||
2359 | { | ||
2360 | #ifdef GHC_OS_WINDOWS | ||
2361 | #ifdef GHC_USE_WCHAR_T | ||
2362 | _native_cache = detail::fromUtf8<string_type>(native_impl()); | ||
2363 | #else | ||
2364 | _native_cache = native_impl(); | ||
2365 | #endif | ||
2366 | return _native_cache; | ||
2367 | #else | ||
2368 | return _path; | ||
2369 | #endif | ||
2370 | } | ||
2371 | |||
2372 | GHC_INLINE const path::value_type* path::c_str() const | ||
2373 | { | ||
2374 | return native().c_str(); | ||
2375 | } | ||
2376 | |||
2377 | GHC_INLINE path::operator path::string_type() const | ||
2378 | { | ||
2379 | return native(); | ||
2380 | } | ||
2381 | |||
2382 | #endif // GHC_EXPAND_IMPL | ||
2383 | |||
2384 | template <class EcharT, class traits, class Allocator> | ||
2385 | inline std::basic_string<EcharT, traits, Allocator> path::string(const Allocator& a) const | ||
2386 | { | ||
2387 | return detail::fromUtf8<std::basic_string<EcharT, traits, Allocator>>(native_impl(), a); | ||
2388 | } | ||
2389 | |||
2390 | #ifdef GHC_EXPAND_IMPL | ||
2391 | |||
2392 | GHC_INLINE std::string path::string() const | ||
2393 | { | ||
2394 | return native_impl(); | ||
2395 | } | ||
2396 | |||
2397 | GHC_INLINE std::wstring path::wstring() const | ||
2398 | { | ||
2399 | #ifdef GHC_USE_WCHAR_T | ||
2400 | return native(); | ||
2401 | #else | ||
2402 | return detail::fromUtf8<std::wstring>(native()); | ||
2403 | #endif | ||
2404 | } | ||
2405 | |||
2406 | GHC_INLINE std::string path::u8string() const | ||
2407 | { | ||
2408 | return native_impl(); | ||
2409 | } | ||
2410 | |||
2411 | GHC_INLINE std::u16string path::u16string() const | ||
2412 | { | ||
2413 | return detail::fromUtf8<std::u16string>(native_impl()); | ||
2414 | } | ||
2415 | |||
2416 | GHC_INLINE std::u32string path::u32string() const | ||
2417 | { | ||
2418 | return detail::fromUtf8<std::u32string>(native_impl()); | ||
2419 | } | ||
2420 | |||
2421 | #endif // GHC_EXPAND_IMPL | ||
2422 | |||
2423 | //----------------------------------------------------------------------------- | ||
2424 | // 30.10.8.4.7, generic format observers | ||
2425 | template <class EcharT, class traits, class Allocator> | ||
2426 | inline std::basic_string<EcharT, traits, Allocator> path::generic_string(const Allocator& a) const | ||
2427 | { | ||
2428 | return detail::fromUtf8<std::basic_string<EcharT, traits, Allocator>>(_path, a); | ||
2429 | } | ||
2430 | |||
2431 | #ifdef GHC_EXPAND_IMPL | ||
2432 | |||
2433 | GHC_INLINE const std::string& path::generic_string() const | ||
2434 | { | ||
2435 | return _path; | ||
2436 | } | ||
2437 | |||
2438 | GHC_INLINE std::wstring path::generic_wstring() const | ||
2439 | { | ||
2440 | return detail::fromUtf8<std::wstring>(_path); | ||
2441 | } | ||
2442 | |||
2443 | GHC_INLINE std::string path::generic_u8string() const | ||
2444 | { | ||
2445 | return _path; | ||
2446 | } | ||
2447 | |||
2448 | GHC_INLINE std::u16string path::generic_u16string() const | ||
2449 | { | ||
2450 | return detail::fromUtf8<std::u16string>(_path); | ||
2451 | } | ||
2452 | |||
2453 | GHC_INLINE std::u32string path::generic_u32string() const | ||
2454 | { | ||
2455 | return detail::fromUtf8<std::u32string>(_path); | ||
2456 | } | ||
2457 | |||
2458 | //----------------------------------------------------------------------------- | ||
2459 | // 30.10.8.4.8, compare | ||
2460 | GHC_INLINE int path::compare(const path& p) const noexcept | ||
2461 | { | ||
2462 | return native().compare(p.native()); | ||
2463 | } | ||
2464 | |||
2465 | GHC_INLINE int path::compare(const string_type& s) const | ||
2466 | { | ||
2467 | return native().compare(path(s).native()); | ||
2468 | } | ||
2469 | |||
2470 | #ifdef __cpp_lib_string_view | ||
2471 | GHC_INLINE int path::compare(std::basic_string_view<value_type> s) const | ||
2472 | { | ||
2473 | return native().compare(path(s).native()); | ||
2474 | } | ||
2475 | #endif | ||
2476 | |||
2477 | GHC_INLINE int path::compare(const value_type* s) const | ||
2478 | { | ||
2479 | return native().compare(path(s).native()); | ||
2480 | } | ||
2481 | |||
2482 | //----------------------------------------------------------------------------- | ||
2483 | // 30.10.8.4.9, decomposition | ||
2484 | GHC_INLINE path path::root_name() const | ||
2485 | { | ||
2486 | #ifdef GHC_OS_WINDOWS | ||
2487 | if (_path.length() >= 2 && std::toupper(static_cast<unsigned char>(_path[0])) >= 'A' && std::toupper(static_cast<unsigned char>(_path[0])) <= 'Z' && _path[1] == ':') { | ||
2488 | return path(_path.substr(0, 2)); | ||
2489 | } | ||
2490 | #endif | ||
2491 | if (_path.length() > 2 && _path[0] == '/' && _path[1] == '/' && _path[2] != '/' && std::isprint(_path[2])) { | ||
2492 | impl_string_type::size_type pos = _path.find_first_of("/\\", 3); | ||
2493 | if (pos == impl_string_type::npos) { | ||
2494 | return path(_path); | ||
2495 | } | ||
2496 | else { | ||
2497 | return path(_path.substr(0, pos)); | ||
2498 | } | ||
2499 | } | ||
2500 | return path(); | ||
2501 | } | ||
2502 | |||
2503 | GHC_INLINE path path::root_directory() const | ||
2504 | { | ||
2505 | path root = root_name(); | ||
2506 | if (_path.length() > root._path.length() && _path[root._path.length()] == '/') { | ||
2507 | return path("/"); | ||
2508 | } | ||
2509 | return path(); | ||
2510 | } | ||
2511 | |||
2512 | GHC_INLINE path path::root_path() const | ||
2513 | { | ||
2514 | return root_name().generic_string() + root_directory().generic_string(); | ||
2515 | } | ||
2516 | |||
2517 | GHC_INLINE path path::relative_path() const | ||
2518 | { | ||
2519 | std::string root = root_path()._path; | ||
2520 | return path(_path.substr((std::min)(root.length(), _path.length())), generic_format); | ||
2521 | } | ||
2522 | |||
2523 | GHC_INLINE path path::parent_path() const | ||
2524 | { | ||
2525 | if (has_relative_path()) { | ||
2526 | if (empty() || begin() == --end()) { | ||
2527 | return path(); | ||
2528 | } | ||
2529 | else { | ||
2530 | path pp; | ||
2531 | for (string_type s : input_iterator_range<iterator>(begin(), --end())) { | ||
2532 | if (s == "/") { | ||
2533 | // don't use append to join a path- | ||
2534 | pp += s; | ||
2535 | } | ||
2536 | else { | ||
2537 | pp /= s; | ||
2538 | } | ||
2539 | } | ||
2540 | return pp; | ||
2541 | } | ||
2542 | } | ||
2543 | else { | ||
2544 | return *this; | ||
2545 | } | ||
2546 | } | ||
2547 | |||
2548 | GHC_INLINE path path::filename() const | ||
2549 | { | ||
2550 | return relative_path().empty() ? path() : path(*--end()); | ||
2551 | } | ||
2552 | |||
2553 | GHC_INLINE path path::stem() const | ||
2554 | { | ||
2555 | impl_string_type fn = filename().string(); | ||
2556 | if (fn != "." && fn != "..") { | ||
2557 | impl_string_type::size_type n = fn.rfind('.'); | ||
2558 | if (n != impl_string_type::npos && n != 0) { | ||
2559 | return path{fn.substr(0, n)}; | ||
2560 | } | ||
2561 | } | ||
2562 | return path{fn}; | ||
2563 | } | ||
2564 | |||
2565 | GHC_INLINE path path::extension() const | ||
2566 | { | ||
2567 | impl_string_type fn = filename().string(); | ||
2568 | impl_string_type::size_type pos = fn.find_last_of('.'); | ||
2569 | if (pos == std::string::npos || pos == 0) { | ||
2570 | return ""; | ||
2571 | } | ||
2572 | return fn.substr(pos); | ||
2573 | } | ||
2574 | |||
2575 | //----------------------------------------------------------------------------- | ||
2576 | // 30.10.8.4.10, query | ||
2577 | GHC_INLINE bool path::empty() const noexcept | ||
2578 | { | ||
2579 | return _path.empty(); | ||
2580 | } | ||
2581 | |||
2582 | GHC_INLINE bool path::has_root_name() const | ||
2583 | { | ||
2584 | return !root_name().empty(); | ||
2585 | } | ||
2586 | |||
2587 | GHC_INLINE bool path::has_root_directory() const | ||
2588 | { | ||
2589 | return !root_directory().empty(); | ||
2590 | } | ||
2591 | |||
2592 | GHC_INLINE bool path::has_root_path() const | ||
2593 | { | ||
2594 | return !root_path().empty(); | ||
2595 | } | ||
2596 | |||
2597 | GHC_INLINE bool path::has_relative_path() const | ||
2598 | { | ||
2599 | return !relative_path().empty(); | ||
2600 | } | ||
2601 | |||
2602 | GHC_INLINE bool path::has_parent_path() const | ||
2603 | { | ||
2604 | return !parent_path().empty(); | ||
2605 | } | ||
2606 | |||
2607 | GHC_INLINE bool path::has_filename() const | ||
2608 | { | ||
2609 | return !filename().empty(); | ||
2610 | } | ||
2611 | |||
2612 | GHC_INLINE bool path::has_stem() const | ||
2613 | { | ||
2614 | return !stem().empty(); | ||
2615 | } | ||
2616 | |||
2617 | GHC_INLINE bool path::has_extension() const | ||
2618 | { | ||
2619 | return !extension().empty(); | ||
2620 | } | ||
2621 | |||
2622 | GHC_INLINE bool path::is_absolute() const | ||
2623 | { | ||
2624 | #ifdef GHC_OS_WINDOWS | ||
2625 | return has_root_name() && has_root_directory(); | ||
2626 | #else | ||
2627 | return has_root_directory(); | ||
2628 | #endif | ||
2629 | } | ||
2630 | |||
2631 | GHC_INLINE bool path::is_relative() const | ||
2632 | { | ||
2633 | return !is_absolute(); | ||
2634 | } | ||
2635 | |||
2636 | //----------------------------------------------------------------------------- | ||
2637 | // 30.10.8.4.11, generation | ||
2638 | GHC_INLINE path path::lexically_normal() const | ||
2639 | { | ||
2640 | path dest; | ||
2641 | bool lastDotDot = false; | ||
2642 | for (string_type s : *this) { | ||
2643 | if (s == ".") { | ||
2644 | dest /= ""; | ||
2645 | continue; | ||
2646 | } | ||
2647 | else if (s == ".." && !dest.empty()) { | ||
2648 | auto root = root_path(); | ||
2649 | if (dest == root) { | ||
2650 | continue; | ||
2651 | } | ||
2652 | else if (*(--dest.end()) != "..") { | ||
2653 | if (dest._path.back() == generic_separator) { | ||
2654 | dest._path.pop_back(); | ||
2655 | } | ||
2656 | dest.remove_filename(); | ||
2657 | continue; | ||
2658 | } | ||
2659 | } | ||
2660 | if (!(s.empty() && lastDotDot)) { | ||
2661 | dest /= s; | ||
2662 | } | ||
2663 | lastDotDot = s == ".."; | ||
2664 | } | ||
2665 | if (dest.empty()) { | ||
2666 | dest = "."; | ||
2667 | } | ||
2668 | return dest; | ||
2669 | } | ||
2670 | |||
2671 | GHC_INLINE path path::lexically_relative(const path& base) const | ||
2672 | { | ||
2673 | if (root_name() != base.root_name() || is_absolute() != base.is_absolute() || (!has_root_directory() && base.has_root_directory())) { | ||
2674 | return path(); | ||
2675 | } | ||
2676 | const_iterator a = begin(), b = base.begin(); | ||
2677 | while (a != end() && b != base.end() && *a == *b) { | ||
2678 | ++a; | ||
2679 | ++b; | ||
2680 | } | ||
2681 | if (a == end() && b == base.end()) { | ||
2682 | return path("."); | ||
2683 | } | ||
2684 | int count = 0; | ||
2685 | for (const auto& element : input_iterator_range<const_iterator>(b, base.end())) { | ||
2686 | if (element != "." && element != "..") { | ||
2687 | ++count; | ||
2688 | } | ||
2689 | else if (element == "..") { | ||
2690 | --count; | ||
2691 | } | ||
2692 | } | ||
2693 | if (count < 0) { | ||
2694 | return path(); | ||
2695 | } | ||
2696 | path result; | ||
2697 | for (int i = 0; i < count; ++i) { | ||
2698 | result /= ".."; | ||
2699 | } | ||
2700 | for (const auto& element : input_iterator_range<const_iterator>(a, end())) { | ||
2701 | result /= element; | ||
2702 | } | ||
2703 | return result; | ||
2704 | } | ||
2705 | |||
2706 | GHC_INLINE path path::lexically_proximate(const path& base) const | ||
2707 | { | ||
2708 | path result = lexically_relative(base); | ||
2709 | return result.empty() ? *this : result; | ||
2710 | } | ||
2711 | |||
2712 | //----------------------------------------------------------------------------- | ||
2713 | // 30.10.8.5, iterators | ||
2714 | GHC_INLINE path::iterator::iterator() {} | ||
2715 | |||
2716 | GHC_INLINE path::iterator::iterator(const path::impl_string_type::const_iterator& first, const path::impl_string_type::const_iterator& last, const path::impl_string_type::const_iterator& pos) | ||
2717 | : _first(first) | ||
2718 | , _last(last) | ||
2719 | , _iter(pos) | ||
2720 | { | ||
2721 | updateCurrent(); | ||
2722 | // find the position of a potential root directory slash | ||
2723 | #ifdef GHC_OS_WINDOWS | ||
2724 | if (_last - _first >= 3 && std::toupper(static_cast<unsigned char>(*first)) >= 'A' && std::toupper(static_cast<unsigned char>(*first)) <= 'Z' && *(first + 1) == ':' && *(first + 2) == '/') { | ||
2725 | _root = _first + 2; | ||
2726 | } | ||
2727 | else | ||
2728 | #endif | ||
2729 | { | ||
2730 | if (_first != _last && *_first == '/') { | ||
2731 | if (_last - _first >= 2 && *(_first + 1) == '/' && !(_last - _first >= 3 && *(_first + 2) == '/')) { | ||
2732 | _root = increment(_first); | ||
2733 | } | ||
2734 | else { | ||
2735 | _root = _first; | ||
2736 | } | ||
2737 | } | ||
2738 | else { | ||
2739 | _root = _last; | ||
2740 | } | ||
2741 | } | ||
2742 | } | ||
2743 | |||
2744 | GHC_INLINE path::impl_string_type::const_iterator path::iterator::increment(const path::impl_string_type::const_iterator& pos) const | ||
2745 | { | ||
2746 | path::impl_string_type::const_iterator i = pos; | ||
2747 | bool fromStart = i == _first; | ||
2748 | if (i != _last) { | ||
2749 | // we can only sit on a slash if it is a network name or a root | ||
2750 | if (*i++ == '/') { | ||
2751 | if (i != _last && *i == '/') { | ||
2752 | if (fromStart && !(i + 1 != _last && *(i + 1) == '/')) { | ||
2753 | // leadind double slashes detected, treat this and the | ||
2754 | // following until a slash as one unit | ||
2755 | i = std::find(++i, _last, '/'); | ||
2756 | } | ||
2757 | else { | ||
2758 | // skip redundant slashes | ||
2759 | while (i != _last && *i == '/') { | ||
2760 | ++i; | ||
2761 | } | ||
2762 | } | ||
2763 | } | ||
2764 | } | ||
2765 | else { | ||
2766 | if (fromStart && i != _last && *i == ':') { | ||
2767 | ++i; | ||
2768 | } | ||
2769 | else { | ||
2770 | i = std::find(i, _last, '/'); | ||
2771 | } | ||
2772 | } | ||
2773 | } | ||
2774 | return i; | ||
2775 | } | ||
2776 | |||
2777 | GHC_INLINE path::impl_string_type::const_iterator path::iterator::decrement(const path::impl_string_type::const_iterator& pos) const | ||
2778 | { | ||
2779 | path::impl_string_type::const_iterator i = pos; | ||
2780 | if (i != _first) { | ||
2781 | --i; | ||
2782 | // if this is now the root slash or the trailing slash, we are done, | ||
2783 | // else check for network name | ||
2784 | if (i != _root && (pos != _last || *i != '/')) { | ||
2785 | #ifdef GHC_OS_WINDOWS | ||
2786 | static const std::string seps = "/:"; | ||
2787 | i = std::find_first_of(std::reverse_iterator<path::impl_string_type::const_iterator>(i), std::reverse_iterator<path::impl_string_type::const_iterator>(_first), seps.begin(), seps.end()).base(); | ||
2788 | if (i > _first && *i == ':') { | ||
2789 | i++; | ||
2790 | } | ||
2791 | #else | ||
2792 | i = std::find(std::reverse_iterator<path::impl_string_type::const_iterator>(i), std::reverse_iterator<path::impl_string_type::const_iterator>(_first), '/').base(); | ||
2793 | #endif | ||
2794 | // Now we have to check if this is a network name | ||
2795 | if (i - _first == 2 && *_first == '/' && *(_first + 1) == '/') { | ||
2796 | i -= 2; | ||
2797 | } | ||
2798 | } | ||
2799 | } | ||
2800 | return i; | ||
2801 | } | ||
2802 | |||
2803 | GHC_INLINE void path::iterator::updateCurrent() | ||
2804 | { | ||
2805 | if (_iter != _first && _iter != _last && (*_iter == '/' && _iter != _root) && (_iter + 1 == _last)) { | ||
2806 | _current = ""; | ||
2807 | } | ||
2808 | else { | ||
2809 | _current.assign(_iter, increment(_iter)); | ||
2810 | if (_current.generic_string().size() > 1 && _current.generic_string()[0] == '/' && _current.generic_string()[_current.generic_string().size() - 1] == '/') { | ||
2811 | // shrink successive slashes to one | ||
2812 | _current = "/"; | ||
2813 | } | ||
2814 | } | ||
2815 | } | ||
2816 | |||
2817 | GHC_INLINE path::iterator& path::iterator::operator++() | ||
2818 | { | ||
2819 | _iter = increment(_iter); | ||
2820 | while (_iter != _last && // we didn't reach the end | ||
2821 | _iter != _root && // this is not a root position | ||
2822 | *_iter == '/' && // we are on a slash | ||
2823 | (_iter + 1) != _last // the slash is not the last char | ||
2824 | ) { | ||
2825 | ++_iter; | ||
2826 | } | ||
2827 | updateCurrent(); | ||
2828 | return *this; | ||
2829 | } | ||
2830 | |||
2831 | GHC_INLINE path::iterator path::iterator::operator++(int) | ||
2832 | { | ||
2833 | path::iterator i{*this}; | ||
2834 | ++(*this); | ||
2835 | return i; | ||
2836 | } | ||
2837 | |||
2838 | GHC_INLINE path::iterator& path::iterator::operator--() | ||
2839 | { | ||
2840 | _iter = decrement(_iter); | ||
2841 | updateCurrent(); | ||
2842 | return *this; | ||
2843 | } | ||
2844 | |||
2845 | GHC_INLINE path::iterator path::iterator::operator--(int) | ||
2846 | { | ||
2847 | auto i = *this; | ||
2848 | --(*this); | ||
2849 | return i; | ||
2850 | } | ||
2851 | |||
2852 | GHC_INLINE bool path::iterator::operator==(const path::iterator& other) const | ||
2853 | { | ||
2854 | return _iter == other._iter; | ||
2855 | } | ||
2856 | |||
2857 | GHC_INLINE bool path::iterator::operator!=(const path::iterator& other) const | ||
2858 | { | ||
2859 | return _iter != other._iter; | ||
2860 | } | ||
2861 | |||
2862 | GHC_INLINE path::iterator::reference path::iterator::operator*() const | ||
2863 | { | ||
2864 | return _current; | ||
2865 | } | ||
2866 | |||
2867 | GHC_INLINE path::iterator::pointer path::iterator::operator->() const | ||
2868 | { | ||
2869 | return &_current; | ||
2870 | } | ||
2871 | |||
2872 | GHC_INLINE path::iterator path::begin() const | ||
2873 | { | ||
2874 | return iterator(_path.begin(), _path.end(), _path.begin()); | ||
2875 | } | ||
2876 | |||
2877 | GHC_INLINE path::iterator path::end() const | ||
2878 | { | ||
2879 | return iterator(_path.begin(), _path.end(), _path.end()); | ||
2880 | } | ||
2881 | |||
2882 | //----------------------------------------------------------------------------- | ||
2883 | // 30.10.8.6, path non-member functions | ||
2884 | GHC_INLINE void swap(path& lhs, path& rhs) noexcept | ||
2885 | { | ||
2886 | swap(lhs._path, rhs._path); | ||
2887 | } | ||
2888 | |||
2889 | GHC_INLINE size_t hash_value(const path& p) noexcept | ||
2890 | { | ||
2891 | return std::hash<std::string>()(p.generic_string()); | ||
2892 | } | ||
2893 | |||
2894 | GHC_INLINE bool operator==(const path& lhs, const path& rhs) noexcept | ||
2895 | { | ||
2896 | return lhs.generic_string() == rhs.generic_string(); | ||
2897 | } | ||
2898 | |||
2899 | GHC_INLINE bool operator!=(const path& lhs, const path& rhs) noexcept | ||
2900 | { | ||
2901 | return lhs.generic_string() != rhs.generic_string(); | ||
2902 | } | ||
2903 | |||
2904 | GHC_INLINE bool operator<(const path& lhs, const path& rhs) noexcept | ||
2905 | { | ||
2906 | return lhs.generic_string() < rhs.generic_string(); | ||
2907 | } | ||
2908 | |||
2909 | GHC_INLINE bool operator<=(const path& lhs, const path& rhs) noexcept | ||
2910 | { | ||
2911 | return lhs.generic_string() <= rhs.generic_string(); | ||
2912 | } | ||
2913 | |||
2914 | GHC_INLINE bool operator>(const path& lhs, const path& rhs) noexcept | ||
2915 | { | ||
2916 | return lhs.generic_string() > rhs.generic_string(); | ||
2917 | } | ||
2918 | |||
2919 | GHC_INLINE bool operator>=(const path& lhs, const path& rhs) noexcept | ||
2920 | { | ||
2921 | return lhs.generic_string() >= rhs.generic_string(); | ||
2922 | } | ||
2923 | |||
2924 | GHC_INLINE path operator/(const path& lhs, const path& rhs) | ||
2925 | { | ||
2926 | path result(lhs); | ||
2927 | result /= rhs; | ||
2928 | return result; | ||
2929 | } | ||
2930 | |||
2931 | #endif // GHC_EXPAND_IMPL | ||
2932 | |||
2933 | //----------------------------------------------------------------------------- | ||
2934 | // 30.10.8.6.1 path inserter and extractor | ||
2935 | template <class charT, class traits> | ||
2936 | inline std::basic_ostream<charT, traits>& operator<<(std::basic_ostream<charT, traits>& os, const path& p) | ||
2937 | { | ||
2938 | os << "\""; | ||
2939 | auto ps = p.string<charT, traits>(); | ||
2940 | for (auto c : ps) { | ||
2941 | if (c == '"' || c == '\\') { | ||
2942 | os << '\\'; | ||
2943 | } | ||
2944 | os << c; | ||
2945 | } | ||
2946 | os << "\""; | ||
2947 | return os; | ||
2948 | } | ||
2949 | |||
2950 | template <class charT, class traits> | ||
2951 | inline std::basic_istream<charT, traits>& operator>>(std::basic_istream<charT, traits>& is, path& p) | ||
2952 | { | ||
2953 | std::basic_string<charT, traits> tmp; | ||
2954 | charT c; | ||
2955 | is >> c; | ||
2956 | if (c == '"') { | ||
2957 | auto sf = is.flags(); | ||
2958 | is >> std::noskipws; | ||
2959 | while (is) { | ||
2960 | auto c2 = is.get(); | ||
2961 | if (is) { | ||
2962 | if (c2 == '\\') { | ||
2963 | c2 = is.get(); | ||
2964 | if (is) { | ||
2965 | tmp += static_cast<charT>(c2); | ||
2966 | } | ||
2967 | } | ||
2968 | else if (c2 == '"') { | ||
2969 | break; | ||
2970 | } | ||
2971 | else { | ||
2972 | tmp += static_cast<charT>(c2); | ||
2973 | } | ||
2974 | } | ||
2975 | } | ||
2976 | if ((sf & std::ios_base::skipws) == std::ios_base::skipws) { | ||
2977 | is >> std::skipws; | ||
2978 | } | ||
2979 | p = path(tmp); | ||
2980 | } | ||
2981 | else { | ||
2982 | is >> tmp; | ||
2983 | p = path(static_cast<charT>(c) + tmp); | ||
2984 | } | ||
2985 | return is; | ||
2986 | } | ||
2987 | |||
2988 | #ifdef GHC_EXPAND_IMPL | ||
2989 | |||
2990 | //----------------------------------------------------------------------------- | ||
2991 | // 30.10.9 Class filesystem_error | ||
2992 | GHC_INLINE filesystem_error::filesystem_error(const std::string& what_arg, std::error_code ec) | ||
2993 | : std::system_error(ec, what_arg) | ||
2994 | , _what_arg(what_arg) | ||
2995 | , _ec(ec) | ||
2996 | { | ||
2997 | } | ||
2998 | |||
2999 | GHC_INLINE filesystem_error::filesystem_error(const std::string& what_arg, const path& p1, std::error_code ec) | ||
3000 | : std::system_error(ec, what_arg) | ||
3001 | , _what_arg(what_arg) | ||
3002 | , _ec(ec) | ||
3003 | , _p1(p1) | ||
3004 | { | ||
3005 | if (!_p1.empty()) { | ||
3006 | _what_arg += ": '" + _p1.u8string() + "'"; | ||
3007 | } | ||
3008 | } | ||
3009 | |||
3010 | GHC_INLINE filesystem_error::filesystem_error(const std::string& what_arg, const path& p1, const path& p2, std::error_code ec) | ||
3011 | : std::system_error(ec, what_arg) | ||
3012 | , _what_arg(what_arg) | ||
3013 | , _ec(ec) | ||
3014 | , _p1(p1) | ||
3015 | , _p2(p2) | ||
3016 | { | ||
3017 | if (!_p1.empty()) { | ||
3018 | _what_arg += ": '" + _p1.u8string() + "'"; | ||
3019 | } | ||
3020 | if (!_p2.empty()) { | ||
3021 | _what_arg += ", '" + _p2.u8string() + "'"; | ||
3022 | } | ||
3023 | } | ||
3024 | |||
3025 | GHC_INLINE const path& filesystem_error::path1() const noexcept | ||
3026 | { | ||
3027 | return _p1; | ||
3028 | } | ||
3029 | |||
3030 | GHC_INLINE const path& filesystem_error::path2() const noexcept | ||
3031 | { | ||
3032 | return _p2; | ||
3033 | } | ||
3034 | |||
3035 | GHC_INLINE const char* filesystem_error::what() const noexcept | ||
3036 | { | ||
3037 | return _what_arg.c_str(); | ||
3038 | } | ||
3039 | |||
3040 | //----------------------------------------------------------------------------- | ||
3041 | // 30.10.15, filesystem operations | ||
3042 | GHC_INLINE path absolute(const path& p) | ||
3043 | { | ||
3044 | std::error_code ec; | ||
3045 | path result = absolute(p, ec); | ||
3046 | if (ec) { | ||
3047 | throw filesystem_error(detail::systemErrorText(ec.value()), p, ec); | ||
3048 | } | ||
3049 | return result; | ||
3050 | } | ||
3051 | |||
3052 | GHC_INLINE path absolute(const path& p, std::error_code& ec) | ||
3053 | { | ||
3054 | ec.clear(); | ||
3055 | #ifdef GHC_OS_WINDOWS | ||
3056 | if (p.empty()) { | ||
3057 | return absolute(current_path(ec), ec) / ""; | ||
3058 | } | ||
3059 | ULONG size = ::GetFullPathNameW(p.wstring().c_str(), 0, 0, 0); | ||
3060 | if (size) { | ||
3061 | std::vector<wchar_t> buf(size, 0); | ||
3062 | ULONG s2 = GetFullPathNameW(p.wstring().c_str(), size, buf.data(), nullptr); | ||
3063 | if (s2 && s2 < size) { | ||
3064 | path result = path(std::wstring(buf.data(), s2)); | ||
3065 | if (p.filename() == ".") { | ||
3066 | result /= "."; | ||
3067 | } | ||
3068 | return result; | ||
3069 | } | ||
3070 | } | ||
3071 | ec = detail::make_system_error(); | ||
3072 | return path(); | ||
3073 | #else | ||
3074 | path base = current_path(ec); | ||
3075 | if (!ec) { | ||
3076 | if (p.empty()) { | ||
3077 | return base / p; | ||
3078 | } | ||
3079 | if (p.has_root_name()) { | ||
3080 | if (p.has_root_directory()) { | ||
3081 | return p; | ||
3082 | } | ||
3083 | else { | ||
3084 | return p.root_name() / base.root_directory() / base.relative_path() / p.relative_path(); | ||
3085 | } | ||
3086 | } | ||
3087 | else { | ||
3088 | if (p.has_root_directory()) { | ||
3089 | return base.root_name() / p; | ||
3090 | } | ||
3091 | else { | ||
3092 | return base / p; | ||
3093 | } | ||
3094 | } | ||
3095 | } | ||
3096 | ec = detail::make_system_error(); | ||
3097 | return path(); | ||
3098 | #endif | ||
3099 | } | ||
3100 | |||
3101 | GHC_INLINE path canonical(const path& p) | ||
3102 | { | ||
3103 | std::error_code ec; | ||
3104 | auto result = canonical(p, ec); | ||
3105 | if (ec) { | ||
3106 | throw filesystem_error(detail::systemErrorText(ec.value()), p, ec); | ||
3107 | } | ||
3108 | return result; | ||
3109 | } | ||
3110 | |||
3111 | GHC_INLINE path canonical(const path& p, std::error_code& ec) | ||
3112 | { | ||
3113 | if (p.empty()) { | ||
3114 | ec = detail::make_error_code(detail::portable_error::not_found); | ||
3115 | return path(); | ||
3116 | } | ||
3117 | path work = p.is_absolute() ? p : absolute(p, ec); | ||
3118 | path root = work.root_path(); | ||
3119 | path result; | ||
3120 | |||
3121 | auto fs = status(work, ec); | ||
3122 | if (ec) { | ||
3123 | return path(); | ||
3124 | } | ||
3125 | if (fs.type() == file_type::not_found) { | ||
3126 | ec = detail::make_error_code(detail::portable_error::not_found); | ||
3127 | return path(); | ||
3128 | } | ||
3129 | bool redo; | ||
3130 | do { | ||
3131 | redo = false; | ||
3132 | result.clear(); | ||
3133 | for (auto pe : work) { | ||
3134 | if (pe.empty() || pe == ".") { | ||
3135 | continue; | ||
3136 | } | ||
3137 | else if (pe == "..") { | ||
3138 | result = result.parent_path(); | ||
3139 | continue; | ||
3140 | } | ||
3141 | else if ((result / pe).string().length() <= root.string().length()) { | ||
3142 | result /= pe; | ||
3143 | continue; | ||
3144 | } | ||
3145 | auto sls = symlink_status(result / pe, ec); | ||
3146 | if (ec) { | ||
3147 | return path(); | ||
3148 | } | ||
3149 | if (is_symlink(sls)) { | ||
3150 | redo = true; | ||
3151 | auto target = read_symlink(result / pe, ec); | ||
3152 | if (ec) { | ||
3153 | return path(); | ||
3154 | } | ||
3155 | if (target.is_absolute()) { | ||
3156 | result = target; | ||
3157 | continue; | ||
3158 | } | ||
3159 | else { | ||
3160 | result /= target; | ||
3161 | continue; | ||
3162 | } | ||
3163 | } | ||
3164 | else { | ||
3165 | result /= pe; | ||
3166 | } | ||
3167 | } | ||
3168 | work = result; | ||
3169 | } while (redo); | ||
3170 | ec.clear(); | ||
3171 | return result; | ||
3172 | } | ||
3173 | |||
3174 | GHC_INLINE void copy(const path& from, const path& to) | ||
3175 | { | ||
3176 | copy(from, to, copy_options::none); | ||
3177 | } | ||
3178 | |||
3179 | GHC_INLINE void copy(const path& from, const path& to, std::error_code& ec) noexcept | ||
3180 | { | ||
3181 | copy(from, to, copy_options::none, ec); | ||
3182 | } | ||
3183 | |||
3184 | GHC_INLINE void copy(const path& from, const path& to, copy_options options) | ||
3185 | { | ||
3186 | std::error_code ec; | ||
3187 | copy(from, to, options, ec); | ||
3188 | if (ec) { | ||
3189 | throw filesystem_error(detail::systemErrorText(ec.value()), from, to, ec); | ||
3190 | } | ||
3191 | } | ||
3192 | |||
3193 | GHC_INLINE void copy(const path& from, const path& to, copy_options options, std::error_code& ec) noexcept | ||
3194 | { | ||
3195 | std::error_code tec; | ||
3196 | file_status fs_from, fs_to; | ||
3197 | ec.clear(); | ||
3198 | if ((options & (copy_options::skip_symlinks | copy_options::copy_symlinks | copy_options::create_symlinks)) != copy_options::none) { | ||
3199 | fs_from = symlink_status(from, ec); | ||
3200 | } | ||
3201 | else { | ||
3202 | fs_from = status(from, ec); | ||
3203 | } | ||
3204 | if (!exists(fs_from)) { | ||
3205 | if (!ec) { | ||
3206 | ec = detail::make_error_code(detail::portable_error::not_found); | ||
3207 | } | ||
3208 | return; | ||
3209 | } | ||
3210 | if ((options & (copy_options::skip_symlinks | copy_options::create_symlinks)) != copy_options::none) { | ||
3211 | fs_to = symlink_status(to, tec); | ||
3212 | } | ||
3213 | else { | ||
3214 | fs_to = status(to, tec); | ||
3215 | } | ||
3216 | if (is_other(fs_from) || is_other(fs_to) || (is_directory(fs_from) && is_regular_file(fs_to)) || (exists(fs_to) && equivalent(from, to, ec))) { | ||
3217 | ec = detail::make_error_code(detail::portable_error::invalid_argument); | ||
3218 | } | ||
3219 | else if (is_symlink(fs_from)) { | ||
3220 | if ((options & copy_options::skip_symlinks) == copy_options::none) { | ||
3221 | if (!exists(fs_to) && (options & copy_options::copy_symlinks) != copy_options::none) { | ||
3222 | copy_symlink(from, to, ec); | ||
3223 | } | ||
3224 | else { | ||
3225 | ec = detail::make_error_code(detail::portable_error::invalid_argument); | ||
3226 | } | ||
3227 | } | ||
3228 | } | ||
3229 | else if (is_regular_file(fs_from)) { | ||
3230 | if ((options & copy_options::directories_only) == copy_options::none) { | ||
3231 | if ((options & copy_options::create_symlinks) != copy_options::none) { | ||
3232 | create_symlink(from.is_absolute() ? from : canonical(from, ec), to, ec); | ||
3233 | } | ||
3234 | else if ((options & copy_options::create_hard_links) != copy_options::none) { | ||
3235 | create_hard_link(from, to, ec); | ||
3236 | } | ||
3237 | else if (is_directory(fs_to)) { | ||
3238 | copy_file(from, to / from.filename(), options, ec); | ||
3239 | } | ||
3240 | else { | ||
3241 | copy_file(from, to, options, ec); | ||
3242 | } | ||
3243 | } | ||
3244 | } | ||
3245 | #ifdef LWG_2682_BEHAVIOUR | ||
3246 | else if (is_directory(fs_from) && (options & copy_options::create_symlinks) != copy_options::none) { | ||
3247 | ec = detail::make_error_code(detail::portable_error::is_a_directory); | ||
3248 | } | ||
3249 | #endif | ||
3250 | else if (is_directory(fs_from) && (options == copy_options::none || (options & copy_options::recursive) != copy_options::none)) { | ||
3251 | if (!exists(fs_to)) { | ||
3252 | create_directory(to, from, ec); | ||
3253 | if (ec) { | ||
3254 | return; | ||
3255 | } | ||
3256 | } | ||
3257 | for (auto iter = directory_iterator(from, ec); iter != directory_iterator(); iter.increment(ec)) { | ||
3258 | if (!ec) { | ||
3259 | copy(iter->path(), to / iter->path().filename(), options | static_cast<copy_options>(0x8000), ec); | ||
3260 | } | ||
3261 | if (ec) { | ||
3262 | return; | ||
3263 | } | ||
3264 | } | ||
3265 | } | ||
3266 | return; | ||
3267 | } | ||
3268 | |||
3269 | GHC_INLINE bool copy_file(const path& from, const path& to) | ||
3270 | { | ||
3271 | return copy_file(from, to, copy_options::none); | ||
3272 | } | ||
3273 | |||
3274 | GHC_INLINE bool copy_file(const path& from, const path& to, std::error_code& ec) noexcept | ||
3275 | { | ||
3276 | return copy_file(from, to, copy_options::none, ec); | ||
3277 | } | ||
3278 | |||
3279 | GHC_INLINE bool copy_file(const path& from, const path& to, copy_options option) | ||
3280 | { | ||
3281 | std::error_code ec; | ||
3282 | auto result = copy_file(from, to, option, ec); | ||
3283 | if (ec) { | ||
3284 | throw filesystem_error(detail::systemErrorText(ec.value()), from, to, ec); | ||
3285 | } | ||
3286 | return result; | ||
3287 | } | ||
3288 | |||
3289 | GHC_INLINE bool copy_file(const path& from, const path& to, copy_options options, std::error_code& ec) noexcept | ||
3290 | { | ||
3291 | std::error_code tecf, tect; | ||
3292 | auto sf = status(from, tecf); | ||
3293 | auto st = status(to, tect); | ||
3294 | bool overwrite = false; | ||
3295 | ec.clear(); | ||
3296 | if (!is_regular_file(sf)) { | ||
3297 | ec = tecf; | ||
3298 | return false; | ||
3299 | } | ||
3300 | if (exists(st) && (!is_regular_file(st) || equivalent(from, to, ec) || (options & (copy_options::skip_existing | copy_options::overwrite_existing | copy_options::update_existing)) == copy_options::none)) { | ||
3301 | ec = tect ? tect : detail::make_error_code(detail::portable_error::exists); | ||
3302 | return false; | ||
3303 | } | ||
3304 | if (exists(st)) { | ||
3305 | if ((options & copy_options::update_existing) == copy_options::update_existing) { | ||
3306 | auto from_time = last_write_time(from, ec); | ||
3307 | if (ec) { | ||
3308 | ec = detail::make_system_error(); | ||
3309 | return false; | ||
3310 | } | ||
3311 | auto to_time = last_write_time(to, ec); | ||
3312 | if (ec) { | ||
3313 | ec = detail::make_system_error(); | ||
3314 | return false; | ||
3315 | } | ||
3316 | if (from_time <= to_time) { | ||
3317 | return false; | ||
3318 | } | ||
3319 | } | ||
3320 | overwrite = true; | ||
3321 | } | ||
3322 | #ifdef GHC_OS_WINDOWS | ||
3323 | if (!::CopyFileW(detail::fromUtf8<std::wstring>(from.u8string()).c_str(), detail::fromUtf8<std::wstring>(to.u8string()).c_str(), !overwrite)) { | ||
3324 | ec = detail::make_system_error(); | ||
3325 | return false; | ||
3326 | } | ||
3327 | return true; | ||
3328 | #else | ||
3329 | std::vector<char> buffer(16384, '\0'); | ||
3330 | int in = -1, out = -1; | ||
3331 | if ((in = ::open(from.c_str(), O_RDONLY)) < 0) { | ||
3332 | ec = detail::make_system_error(); | ||
3333 | return false; | ||
3334 | } | ||
3335 | std::shared_ptr<void> guard_in(nullptr, [in](void*) { ::close(in); }); | ||
3336 | int mode = O_CREAT | O_WRONLY | O_TRUNC; | ||
3337 | if (!overwrite) { | ||
3338 | mode |= O_EXCL; | ||
3339 | } | ||
3340 | if ((out = ::open(to.c_str(), mode, static_cast<int>(sf.permissions() & perms::all))) < 0) { | ||
3341 | ec = detail::make_system_error(); | ||
3342 | return false; | ||
3343 | } | ||
3344 | std::shared_ptr<void> guard_out(nullptr, [out](void*) { ::close(out); }); | ||
3345 | ssize_t br, bw; | ||
3346 | while ((br = ::read(in, buffer.data(), buffer.size())) > 0) { | ||
3347 | ssize_t offset = 0; | ||
3348 | do { | ||
3349 | if ((bw = ::write(out, buffer.data() + offset, static_cast<size_t>(br))) > 0) { | ||
3350 | br -= bw; | ||
3351 | offset += bw; | ||
3352 | } | ||
3353 | else if (bw < 0) { | ||
3354 | ec = detail::make_system_error(); | ||
3355 | return false; | ||
3356 | } | ||
3357 | } while (br); | ||
3358 | } | ||
3359 | return true; | ||
3360 | #endif | ||
3361 | } | ||
3362 | |||
3363 | GHC_INLINE void copy_symlink(const path& existing_symlink, const path& new_symlink) | ||
3364 | { | ||
3365 | std::error_code ec; | ||
3366 | copy_symlink(existing_symlink, new_symlink, ec); | ||
3367 | if (ec) { | ||
3368 | throw filesystem_error(detail::systemErrorText(ec.value()), existing_symlink, new_symlink, ec); | ||
3369 | } | ||
3370 | } | ||
3371 | |||
3372 | GHC_INLINE void copy_symlink(const path& existing_symlink, const path& new_symlink, std::error_code& ec) noexcept | ||
3373 | { | ||
3374 | ec.clear(); | ||
3375 | auto to = read_symlink(existing_symlink, ec); | ||
3376 | if (!ec) { | ||
3377 | if (exists(to, ec) && is_directory(to, ec)) { | ||
3378 | create_directory_symlink(to, new_symlink, ec); | ||
3379 | } | ||
3380 | else { | ||
3381 | create_symlink(to, new_symlink, ec); | ||
3382 | } | ||
3383 | } | ||
3384 | } | ||
3385 | |||
3386 | GHC_INLINE bool create_directories(const path& p) | ||
3387 | { | ||
3388 | std::error_code ec; | ||
3389 | auto result = create_directories(p, ec); | ||
3390 | if (ec) { | ||
3391 | throw filesystem_error(detail::systemErrorText(ec.value()), p, ec); | ||
3392 | } | ||
3393 | return result; | ||
3394 | } | ||
3395 | |||
3396 | GHC_INLINE bool create_directories(const path& p, std::error_code& ec) noexcept | ||
3397 | { | ||
3398 | path current; | ||
3399 | ec.clear(); | ||
3400 | bool didCreate = false; | ||
3401 | for (path::string_type part : p) { | ||
3402 | current /= part; | ||
3403 | if (current != p.root_name() && current != p.root_path()) { | ||
3404 | std::error_code tec; | ||
3405 | auto fs = status(current, tec); | ||
3406 | if (tec && fs.type() != file_type::not_found) { | ||
3407 | ec = tec; | ||
3408 | return false; | ||
3409 | } | ||
3410 | if (!exists(fs)) { | ||
3411 | create_directory(current, ec); | ||
3412 | if (ec) { | ||
3413 | std::error_code tmp_ec; | ||
3414 | if (is_directory(current, tmp_ec)) { | ||
3415 | ec.clear(); | ||
3416 | } else { | ||
3417 | return false; | ||
3418 | } | ||
3419 | } | ||
3420 | didCreate = true; | ||
3421 | } | ||
3422 | #ifndef LWG_2935_BEHAVIOUR | ||
3423 | else if (!is_directory(fs)) { | ||
3424 | ec = detail::make_error_code(detail::portable_error::exists); | ||
3425 | return false; | ||
3426 | } | ||
3427 | #endif | ||
3428 | } | ||
3429 | } | ||
3430 | return didCreate; | ||
3431 | } | ||
3432 | |||
3433 | GHC_INLINE bool create_directory(const path& p) | ||
3434 | { | ||
3435 | std::error_code ec; | ||
3436 | auto result = create_directory(p, path(), ec); | ||
3437 | if (ec) { | ||
3438 | throw filesystem_error(detail::systemErrorText(ec.value()), p, ec); | ||
3439 | } | ||
3440 | return result; | ||
3441 | } | ||
3442 | |||
3443 | GHC_INLINE bool create_directory(const path& p, std::error_code& ec) noexcept | ||
3444 | { | ||
3445 | return create_directory(p, path(), ec); | ||
3446 | } | ||
3447 | |||
3448 | GHC_INLINE bool create_directory(const path& p, const path& attributes) | ||
3449 | { | ||
3450 | std::error_code ec; | ||
3451 | auto result = create_directory(p, attributes, ec); | ||
3452 | if (ec) { | ||
3453 | throw filesystem_error(detail::systemErrorText(ec.value()), p, ec); | ||
3454 | } | ||
3455 | return result; | ||
3456 | } | ||
3457 | |||
3458 | GHC_INLINE bool create_directory(const path& p, const path& attributes, std::error_code& ec) noexcept | ||
3459 | { | ||
3460 | std::error_code tec; | ||
3461 | ec.clear(); | ||
3462 | auto fs = status(p, tec); | ||
3463 | #ifdef LWG_2935_BEHAVIOUR | ||
3464 | if (status_known(fs) && exists(fs)) { | ||
3465 | return false; | ||
3466 | } | ||
3467 | #else | ||
3468 | if (status_known(fs) && exists(fs) && is_directory(fs)) { | ||
3469 | return false; | ||
3470 | } | ||
3471 | #endif | ||
3472 | #ifdef GHC_OS_WINDOWS | ||
3473 | if (!attributes.empty()) { | ||
3474 | if (!::CreateDirectoryExW(detail::fromUtf8<std::wstring>(attributes.u8string()).c_str(), detail::fromUtf8<std::wstring>(p.u8string()).c_str(), NULL)) { | ||
3475 | ec = detail::make_system_error(); | ||
3476 | return false; | ||
3477 | } | ||
3478 | } | ||
3479 | else if (!::CreateDirectoryW(detail::fromUtf8<std::wstring>(p.u8string()).c_str(), NULL)) { | ||
3480 | ec = detail::make_system_error(); | ||
3481 | return false; | ||
3482 | } | ||
3483 | #else | ||
3484 | ::mode_t attribs = static_cast<mode_t>(perms::all); | ||
3485 | if (!attributes.empty()) { | ||
3486 | struct ::stat fileStat; | ||
3487 | if (::stat(attributes.c_str(), &fileStat) != 0) { | ||
3488 | ec = detail::make_system_error(); | ||
3489 | return false; | ||
3490 | } | ||
3491 | attribs = fileStat.st_mode; | ||
3492 | } | ||
3493 | if (::mkdir(p.c_str(), attribs) != 0) { | ||
3494 | ec = detail::make_system_error(); | ||
3495 | return false; | ||
3496 | } | ||
3497 | #endif | ||
3498 | return true; | ||
3499 | } | ||
3500 | |||
3501 | GHC_INLINE void create_directory_symlink(const path& to, const path& new_symlink) | ||
3502 | { | ||
3503 | std::error_code ec; | ||
3504 | create_directory_symlink(to, new_symlink, ec); | ||
3505 | if (ec) { | ||
3506 | throw filesystem_error(detail::systemErrorText(ec.value()), to, new_symlink, ec); | ||
3507 | } | ||
3508 | } | ||
3509 | |||
3510 | GHC_INLINE void create_directory_symlink(const path& to, const path& new_symlink, std::error_code& ec) noexcept | ||
3511 | { | ||
3512 | detail::create_symlink(to, new_symlink, true, ec); | ||
3513 | } | ||
3514 | |||
3515 | GHC_INLINE void create_hard_link(const path& to, const path& new_hard_link) | ||
3516 | { | ||
3517 | std::error_code ec; | ||
3518 | create_hard_link(to, new_hard_link, ec); | ||
3519 | if (ec) { | ||
3520 | throw filesystem_error(detail::systemErrorText(ec.value()), to, new_hard_link, ec); | ||
3521 | } | ||
3522 | } | ||
3523 | |||
3524 | GHC_INLINE void create_hard_link(const path& to, const path& new_hard_link, std::error_code& ec) noexcept | ||
3525 | { | ||
3526 | detail::create_hardlink(to, new_hard_link, ec); | ||
3527 | } | ||
3528 | |||
3529 | GHC_INLINE void create_symlink(const path& to, const path& new_symlink) | ||
3530 | { | ||
3531 | std::error_code ec; | ||
3532 | create_symlink(to, new_symlink, ec); | ||
3533 | if (ec) { | ||
3534 | throw filesystem_error(detail::systemErrorText(ec.value()), to, new_symlink, ec); | ||
3535 | } | ||
3536 | } | ||
3537 | |||
3538 | GHC_INLINE void create_symlink(const path& to, const path& new_symlink, std::error_code& ec) noexcept | ||
3539 | { | ||
3540 | detail::create_symlink(to, new_symlink, false, ec); | ||
3541 | } | ||
3542 | |||
3543 | GHC_INLINE path current_path() | ||
3544 | { | ||
3545 | std::error_code ec; | ||
3546 | auto result = current_path(ec); | ||
3547 | if (ec) { | ||
3548 | throw filesystem_error(detail::systemErrorText(ec.value()), ec); | ||
3549 | } | ||
3550 | return result; | ||
3551 | } | ||
3552 | |||
3553 | GHC_INLINE path current_path(std::error_code& ec) | ||
3554 | { | ||
3555 | ec.clear(); | ||
3556 | #ifdef GHC_OS_WINDOWS | ||
3557 | DWORD pathlen = ::GetCurrentDirectoryW(0, 0); | ||
3558 | std::unique_ptr<wchar_t[]> buffer(new wchar_t[size_t(pathlen) + 1]); | ||
3559 | if (::GetCurrentDirectoryW(pathlen, buffer.get()) == 0) { | ||
3560 | ec = detail::make_system_error(); | ||
3561 | return path(); | ||
3562 | } | ||
3563 | return path(std::wstring(buffer.get()), path::native_format); | ||
3564 | #else | ||
3565 | size_t pathlen = static_cast<size_t>(std::max(int(::pathconf(".", _PC_PATH_MAX)), int(PATH_MAX))); | ||
3566 | std::unique_ptr<char[]> buffer(new char[pathlen + 1]); | ||
3567 | if (::getcwd(buffer.get(), pathlen) == nullptr) { | ||
3568 | ec = detail::make_system_error(); | ||
3569 | return path(); | ||
3570 | } | ||
3571 | return path(buffer.get()); | ||
3572 | #endif | ||
3573 | } | ||
3574 | |||
3575 | GHC_INLINE void current_path(const path& p) | ||
3576 | { | ||
3577 | std::error_code ec; | ||
3578 | current_path(p, ec); | ||
3579 | if (ec) { | ||
3580 | throw filesystem_error(detail::systemErrorText(ec.value()), p, ec); | ||
3581 | } | ||
3582 | } | ||
3583 | |||
3584 | GHC_INLINE void current_path(const path& p, std::error_code& ec) noexcept | ||
3585 | { | ||
3586 | ec.clear(); | ||
3587 | #ifdef GHC_OS_WINDOWS | ||
3588 | if (!::SetCurrentDirectoryW(detail::fromUtf8<std::wstring>(p.u8string()).c_str())) { | ||
3589 | ec = detail::make_system_error(); | ||
3590 | } | ||
3591 | #else | ||
3592 | if (::chdir(p.string().c_str()) == -1) { | ||
3593 | ec = detail::make_system_error(); | ||
3594 | } | ||
3595 | #endif | ||
3596 | } | ||
3597 | |||
3598 | GHC_INLINE bool exists(file_status s) noexcept | ||
3599 | { | ||
3600 | return status_known(s) && s.type() != file_type::not_found; | ||
3601 | } | ||
3602 | |||
3603 | GHC_INLINE bool exists(const path& p) | ||
3604 | { | ||
3605 | return exists(status(p)); | ||
3606 | } | ||
3607 | |||
3608 | GHC_INLINE bool exists(const path& p, std::error_code& ec) noexcept | ||
3609 | { | ||
3610 | file_status s = status(p, ec); | ||
3611 | if (status_known(s)) { | ||
3612 | ec.clear(); | ||
3613 | } | ||
3614 | return exists(s); | ||
3615 | } | ||
3616 | |||
3617 | GHC_INLINE bool equivalent(const path& p1, const path& p2) | ||
3618 | { | ||
3619 | std::error_code ec; | ||
3620 | bool result = equivalent(p1, p2, ec); | ||
3621 | if (ec) { | ||
3622 | throw filesystem_error(detail::systemErrorText(ec.value()), p1, p2, ec); | ||
3623 | } | ||
3624 | return result; | ||
3625 | } | ||
3626 | |||
3627 | GHC_INLINE bool equivalent(const path& p1, const path& p2, std::error_code& ec) noexcept | ||
3628 | { | ||
3629 | ec.clear(); | ||
3630 | #ifdef GHC_OS_WINDOWS | ||
3631 | std::shared_ptr<void> file1(::CreateFileW(p1.wstring().c_str(), 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0), CloseHandle); | ||
3632 | auto e1 = ::GetLastError(); | ||
3633 | std::shared_ptr<void> file2(::CreateFileW(p2.wstring().c_str(), 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0), CloseHandle); | ||
3634 | if (file1.get() == INVALID_HANDLE_VALUE || file2.get() == INVALID_HANDLE_VALUE) { | ||
3635 | #ifdef LWG_2937_BEHAVIOUR | ||
3636 | ec = detail::make_system_error(e1 ? e1 : ::GetLastError()); | ||
3637 | #else | ||
3638 | if (file1 == file2) { | ||
3639 | ec = detail::make_system_error(e1 ? e1 : ::GetLastError()); | ||
3640 | } | ||
3641 | #endif | ||
3642 | return false; | ||
3643 | } | ||
3644 | BY_HANDLE_FILE_INFORMATION inf1, inf2; | ||
3645 | if (!::GetFileInformationByHandle(file1.get(), &inf1)) { | ||
3646 | ec = detail::make_system_error(); | ||
3647 | return false; | ||
3648 | } | ||
3649 | if (!::GetFileInformationByHandle(file2.get(), &inf2)) { | ||
3650 | ec = detail::make_system_error(); | ||
3651 | return false; | ||
3652 | } | ||
3653 | return inf1.ftLastWriteTime.dwLowDateTime == inf2.ftLastWriteTime.dwLowDateTime && inf1.ftLastWriteTime.dwHighDateTime == inf2.ftLastWriteTime.dwHighDateTime && inf1.nFileIndexHigh == inf2.nFileIndexHigh && inf1.nFileIndexLow == inf2.nFileIndexLow && | ||
3654 | inf1.nFileSizeHigh == inf2.nFileSizeHigh && inf1.nFileSizeLow == inf2.nFileSizeLow && inf1.dwVolumeSerialNumber == inf2.dwVolumeSerialNumber; | ||
3655 | #else | ||
3656 | struct ::stat s1, s2; | ||
3657 | auto rc1 = ::stat(p1.c_str(), &s1); | ||
3658 | auto e1 = errno; | ||
3659 | auto rc2 = ::stat(p2.c_str(), &s2); | ||
3660 | if (rc1 || rc2) { | ||
3661 | #ifdef LWG_2937_BEHAVIOUR | ||
3662 | ec = detail::make_system_error(e1 ? e1 : errno); | ||
3663 | #else | ||
3664 | if (rc1 && rc2) { | ||
3665 | ec = detail::make_system_error(e1 ? e1 : errno); | ||
3666 | } | ||
3667 | #endif | ||
3668 | return false; | ||
3669 | } | ||
3670 | return s1.st_dev == s2.st_dev && s1.st_ino == s2.st_ino && s1.st_size == s2.st_size && s1.st_mtime == s2.st_mtime; | ||
3671 | #endif | ||
3672 | } | ||
3673 | |||
3674 | GHC_INLINE uintmax_t file_size(const path& p) | ||
3675 | { | ||
3676 | std::error_code ec; | ||
3677 | auto result = file_size(p, ec); | ||
3678 | if (ec) { | ||
3679 | throw filesystem_error(detail::systemErrorText(ec.value()), p, ec); | ||
3680 | } | ||
3681 | return result; | ||
3682 | } | ||
3683 | |||
3684 | GHC_INLINE uintmax_t file_size(const path& p, std::error_code& ec) noexcept | ||
3685 | { | ||
3686 | ec.clear(); | ||
3687 | #ifdef GHC_OS_WINDOWS | ||
3688 | WIN32_FILE_ATTRIBUTE_DATA attr; | ||
3689 | if (!GetFileAttributesExW(detail::fromUtf8<std::wstring>(p.u8string()).c_str(), GetFileExInfoStandard, &attr)) { | ||
3690 | ec = detail::make_system_error(); | ||
3691 | return static_cast<uintmax_t>(-1); | ||
3692 | } | ||
3693 | return static_cast<uintmax_t>(attr.nFileSizeHigh) << (sizeof(attr.nFileSizeHigh) * 8) | attr.nFileSizeLow; | ||
3694 | #else | ||
3695 | struct ::stat fileStat; | ||
3696 | if (::stat(p.c_str(), &fileStat) == -1) { | ||
3697 | ec = detail::make_system_error(); | ||
3698 | return static_cast<uintmax_t>(-1); | ||
3699 | } | ||
3700 | return static_cast<uintmax_t>(fileStat.st_size); | ||
3701 | #endif | ||
3702 | } | ||
3703 | |||
3704 | GHC_INLINE uintmax_t hard_link_count(const path& p) | ||
3705 | { | ||
3706 | std::error_code ec; | ||
3707 | auto result = hard_link_count(p, ec); | ||
3708 | if (ec) { | ||
3709 | throw filesystem_error(detail::systemErrorText(ec.value()), p, ec); | ||
3710 | } | ||
3711 | return result; | ||
3712 | } | ||
3713 | |||
3714 | GHC_INLINE uintmax_t hard_link_count(const path& p, std::error_code& ec) noexcept | ||
3715 | { | ||
3716 | ec.clear(); | ||
3717 | #ifdef GHC_OS_WINDOWS | ||
3718 | uintmax_t result = static_cast<uintmax_t>(-1); | ||
3719 | std::shared_ptr<void> file(::CreateFileW(p.wstring().c_str(), 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0), CloseHandle); | ||
3720 | BY_HANDLE_FILE_INFORMATION inf; | ||
3721 | if (file.get() == INVALID_HANDLE_VALUE) { | ||
3722 | ec = detail::make_system_error(); | ||
3723 | } | ||
3724 | else { | ||
3725 | if (!::GetFileInformationByHandle(file.get(), &inf)) { | ||
3726 | ec = detail::make_system_error(); | ||
3727 | } | ||
3728 | else { | ||
3729 | result = inf.nNumberOfLinks; | ||
3730 | } | ||
3731 | } | ||
3732 | return result; | ||
3733 | #else | ||
3734 | uintmax_t result = 0; | ||
3735 | file_status fs = detail::status_ex(p, ec, nullptr, nullptr, &result, nullptr); | ||
3736 | if (fs.type() == file_type::not_found) { | ||
3737 | ec = detail::make_error_code(detail::portable_error::not_found); | ||
3738 | } | ||
3739 | return ec ? static_cast<uintmax_t>(-1) : result; | ||
3740 | #endif | ||
3741 | } | ||
3742 | |||
3743 | GHC_INLINE bool is_block_file(file_status s) noexcept | ||
3744 | { | ||
3745 | return s.type() == file_type::block; | ||
3746 | } | ||
3747 | |||
3748 | GHC_INLINE bool is_block_file(const path& p) | ||
3749 | { | ||
3750 | return is_block_file(status(p)); | ||
3751 | } | ||
3752 | |||
3753 | GHC_INLINE bool is_block_file(const path& p, std::error_code& ec) noexcept | ||
3754 | { | ||
3755 | return is_block_file(status(p, ec)); | ||
3756 | } | ||
3757 | |||
3758 | GHC_INLINE bool is_character_file(file_status s) noexcept | ||
3759 | { | ||
3760 | return s.type() == file_type::character; | ||
3761 | } | ||
3762 | |||
3763 | GHC_INLINE bool is_character_file(const path& p) | ||
3764 | { | ||
3765 | return is_character_file(status(p)); | ||
3766 | } | ||
3767 | |||
3768 | GHC_INLINE bool is_character_file(const path& p, std::error_code& ec) noexcept | ||
3769 | { | ||
3770 | return is_character_file(status(p, ec)); | ||
3771 | } | ||
3772 | |||
3773 | GHC_INLINE bool is_directory(file_status s) noexcept | ||
3774 | { | ||
3775 | return s.type() == file_type::directory; | ||
3776 | } | ||
3777 | |||
3778 | GHC_INLINE bool is_directory(const path& p) | ||
3779 | { | ||
3780 | return is_directory(status(p)); | ||
3781 | } | ||
3782 | |||
3783 | GHC_INLINE bool is_directory(const path& p, std::error_code& ec) noexcept | ||
3784 | { | ||
3785 | return is_directory(status(p, ec)); | ||
3786 | } | ||
3787 | |||
3788 | GHC_INLINE bool is_empty(const path& p) | ||
3789 | { | ||
3790 | if (is_directory(p)) { | ||
3791 | return directory_iterator(p) == directory_iterator(); | ||
3792 | } | ||
3793 | else { | ||
3794 | return file_size(p) == 0; | ||
3795 | } | ||
3796 | } | ||
3797 | |||
3798 | GHC_INLINE bool is_empty(const path& p, std::error_code& ec) noexcept | ||
3799 | { | ||
3800 | auto fs = status(p, ec); | ||
3801 | if (ec) { | ||
3802 | return false; | ||
3803 | } | ||
3804 | if (is_directory(fs)) { | ||
3805 | directory_iterator iter(p, ec); | ||
3806 | if (ec) { | ||
3807 | return false; | ||
3808 | } | ||
3809 | return iter == directory_iterator(); | ||
3810 | } | ||
3811 | else { | ||
3812 | auto sz = file_size(p, ec); | ||
3813 | if (ec) { | ||
3814 | return false; | ||
3815 | } | ||
3816 | return sz == 0; | ||
3817 | } | ||
3818 | } | ||
3819 | |||
3820 | GHC_INLINE bool is_fifo(file_status s) noexcept | ||
3821 | { | ||
3822 | return s.type() == file_type::fifo; | ||
3823 | } | ||
3824 | |||
3825 | GHC_INLINE bool is_fifo(const path& p) | ||
3826 | { | ||
3827 | return is_fifo(status(p)); | ||
3828 | } | ||
3829 | |||
3830 | GHC_INLINE bool is_fifo(const path& p, std::error_code& ec) noexcept | ||
3831 | { | ||
3832 | return is_fifo(status(p, ec)); | ||
3833 | } | ||
3834 | |||
3835 | GHC_INLINE bool is_other(file_status s) noexcept | ||
3836 | { | ||
3837 | return exists(s) && !is_regular_file(s) && !is_directory(s) && !is_symlink(s); | ||
3838 | } | ||
3839 | |||
3840 | GHC_INLINE bool is_other(const path& p) | ||
3841 | { | ||
3842 | return is_other(status(p)); | ||
3843 | } | ||
3844 | |||
3845 | GHC_INLINE bool is_other(const path& p, std::error_code& ec) noexcept | ||
3846 | { | ||
3847 | return is_other(status(p, ec)); | ||
3848 | } | ||
3849 | |||
3850 | GHC_INLINE bool is_regular_file(file_status s) noexcept | ||
3851 | { | ||
3852 | return s.type() == file_type::regular; | ||
3853 | } | ||
3854 | |||
3855 | GHC_INLINE bool is_regular_file(const path& p) | ||
3856 | { | ||
3857 | return is_regular_file(status(p)); | ||
3858 | } | ||
3859 | |||
3860 | GHC_INLINE bool is_regular_file(const path& p, std::error_code& ec) noexcept | ||
3861 | { | ||
3862 | return is_regular_file(status(p, ec)); | ||
3863 | } | ||
3864 | |||
3865 | GHC_INLINE bool is_socket(file_status s) noexcept | ||
3866 | { | ||
3867 | return s.type() == file_type::socket; | ||
3868 | } | ||
3869 | |||
3870 | GHC_INLINE bool is_socket(const path& p) | ||
3871 | { | ||
3872 | return is_socket(status(p)); | ||
3873 | } | ||
3874 | |||
3875 | GHC_INLINE bool is_socket(const path& p, std::error_code& ec) noexcept | ||
3876 | { | ||
3877 | return is_socket(status(p, ec)); | ||
3878 | } | ||
3879 | |||
3880 | GHC_INLINE bool is_symlink(file_status s) noexcept | ||
3881 | { | ||
3882 | return s.type() == file_type::symlink; | ||
3883 | } | ||
3884 | |||
3885 | GHC_INLINE bool is_symlink(const path& p) | ||
3886 | { | ||
3887 | return is_symlink(symlink_status(p)); | ||
3888 | } | ||
3889 | |||
3890 | GHC_INLINE bool is_symlink(const path& p, std::error_code& ec) noexcept | ||
3891 | { | ||
3892 | return is_symlink(symlink_status(p, ec)); | ||
3893 | } | ||
3894 | |||
3895 | GHC_INLINE file_time_type last_write_time(const path& p) | ||
3896 | { | ||
3897 | std::error_code ec; | ||
3898 | auto result = last_write_time(p, ec); | ||
3899 | if (ec) { | ||
3900 | throw filesystem_error(detail::systemErrorText(ec.value()), p, ec); | ||
3901 | } | ||
3902 | return result; | ||
3903 | } | ||
3904 | |||
3905 | GHC_INLINE file_time_type last_write_time(const path& p, std::error_code& ec) noexcept | ||
3906 | { | ||
3907 | time_t result = 0; | ||
3908 | ec.clear(); | ||
3909 | file_status fs = detail::status_ex(p, ec, nullptr, nullptr, nullptr, &result); | ||
3910 | return ec ? (file_time_type::min)() : std::chrono::system_clock::from_time_t(result); | ||
3911 | } | ||
3912 | |||
3913 | GHC_INLINE void last_write_time(const path& p, file_time_type new_time) | ||
3914 | { | ||
3915 | std::error_code ec; | ||
3916 | last_write_time(p, new_time, ec); | ||
3917 | if (ec) { | ||
3918 | throw filesystem_error(detail::systemErrorText(ec.value()), p, ec); | ||
3919 | } | ||
3920 | } | ||
3921 | |||
3922 | GHC_INLINE void last_write_time(const path& p, file_time_type new_time, std::error_code& ec) noexcept | ||
3923 | { | ||
3924 | ec.clear(); | ||
3925 | auto d = new_time.time_since_epoch(); | ||
3926 | #ifdef GHC_OS_WINDOWS | ||
3927 | std::shared_ptr<void> file(::CreateFileW(p.wstring().c_str(), FILE_WRITE_ATTRIBUTES, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL), ::CloseHandle); | ||
3928 | FILETIME ft; | ||
3929 | auto tt = std::chrono::duration_cast<std::chrono::microseconds>(d).count() * 10 + 116444736000000000; | ||
3930 | ft.dwLowDateTime = static_cast<DWORD>(tt); | ||
3931 | ft.dwHighDateTime = static_cast<DWORD>(tt >> 32); | ||
3932 | if (!::SetFileTime(file.get(), 0, 0, &ft)) { | ||
3933 | ec = detail::make_system_error(); | ||
3934 | } | ||
3935 | #elif defined(GHC_OS_MACOS) | ||
3936 | #ifdef __MAC_OS_X_VERSION_MIN_REQUIRED | ||
3937 | #if __MAC_OS_X_VERSION_MIN_REQUIRED < 101300 | ||
3938 | struct ::stat fs; | ||
3939 | if (::stat(p.c_str(), &fs) == 0) { | ||
3940 | struct ::timeval tv[2]; | ||
3941 | tv[0].tv_sec = fs.st_atimespec.tv_sec; | ||
3942 | tv[0].tv_usec = static_cast<int>(fs.st_atimespec.tv_nsec / 1000); | ||
3943 | tv[1].tv_sec = std::chrono::duration_cast<std::chrono::seconds>(d).count(); | ||
3944 | tv[1].tv_usec = static_cast<int>(std::chrono::duration_cast<std::chrono::microseconds>(d).count() % 1000000); | ||
3945 | if (::utimes(p.c_str(), tv) == 0) { | ||
3946 | return; | ||
3947 | } | ||
3948 | } | ||
3949 | ec = detail::make_system_error(); | ||
3950 | return; | ||
3951 | #else | ||
3952 | struct ::timespec times[2]; | ||
3953 | times[0].tv_sec = 0; | ||
3954 | times[0].tv_nsec = UTIME_OMIT; | ||
3955 | times[1].tv_sec = std::chrono::duration_cast<std::chrono::seconds>(d).count(); | ||
3956 | times[1].tv_nsec = std::chrono::duration_cast<std::chrono::nanoseconds>(d).count() % 1000000000; | ||
3957 | if (::utimensat(AT_FDCWD, p.c_str(), times, AT_SYMLINK_NOFOLLOW) != 0) { | ||
3958 | ec = detail::make_system_error(); | ||
3959 | } | ||
3960 | return; | ||
3961 | #endif | ||
3962 | #endif | ||
3963 | #else | ||
3964 | struct ::timespec times[2]; | ||
3965 | times[0].tv_sec = 0; | ||
3966 | times[0].tv_nsec = UTIME_OMIT; | ||
3967 | times[1].tv_sec = static_cast<decltype(times[1].tv_sec)>(std::chrono::duration_cast<std::chrono::seconds>(d).count()); | ||
3968 | times[1].tv_nsec = static_cast<decltype(times[1].tv_nsec)>(std::chrono::duration_cast<std::chrono::nanoseconds>(d).count() % 1000000000); | ||
3969 | if (::utimensat(AT_FDCWD, p.c_str(), times, AT_SYMLINK_NOFOLLOW) != 0) { | ||
3970 | ec = detail::make_system_error(); | ||
3971 | } | ||
3972 | return; | ||
3973 | #endif | ||
3974 | } | ||
3975 | |||
3976 | GHC_INLINE void permissions(const path& p, perms prms, perm_options opts) | ||
3977 | { | ||
3978 | std::error_code ec; | ||
3979 | permissions(p, prms, opts, ec); | ||
3980 | if (ec) { | ||
3981 | throw filesystem_error(detail::systemErrorText(ec.value()), p, ec); | ||
3982 | } | ||
3983 | } | ||
3984 | |||
3985 | GHC_INLINE void permissions(const path& p, perms prms, std::error_code& ec) noexcept | ||
3986 | { | ||
3987 | permissions(p, prms, perm_options::replace, ec); | ||
3988 | } | ||
3989 | |||
3990 | GHC_INLINE void permissions(const path& p, perms prms, perm_options opts, std::error_code& ec) | ||
3991 | { | ||
3992 | if (static_cast<int>(opts & (perm_options::replace | perm_options::add | perm_options::remove)) == 0) { | ||
3993 | ec = detail::make_error_code(detail::portable_error::invalid_argument); | ||
3994 | return; | ||
3995 | } | ||
3996 | auto fs = symlink_status(p, ec); | ||
3997 | if ((opts & perm_options::replace) != perm_options::replace) { | ||
3998 | if ((opts & perm_options::add) == perm_options::add) { | ||
3999 | prms = fs.permissions() | prms; | ||
4000 | } | ||
4001 | else { | ||
4002 | prms = fs.permissions() & ~prms; | ||
4003 | } | ||
4004 | } | ||
4005 | #ifdef GHC_OS_WINDOWS | ||
4006 | #ifdef __GNUC__ | ||
4007 | auto oldAttr = GetFileAttributesW(p.wstring().c_str()); | ||
4008 | if (oldAttr != INVALID_FILE_ATTRIBUTES) { | ||
4009 | DWORD newAttr = ((prms & perms::owner_write) == perms::owner_write) ? oldAttr & ~(static_cast<DWORD>(FILE_ATTRIBUTE_READONLY)) : oldAttr | FILE_ATTRIBUTE_READONLY; | ||
4010 | if (oldAttr == newAttr || SetFileAttributesW(p.wstring().c_str(), newAttr)) { | ||
4011 | return; | ||
4012 | } | ||
4013 | } | ||
4014 | ec = detail::make_system_error(); | ||
4015 | #else | ||
4016 | int mode = 0; | ||
4017 | if ((prms & perms::owner_read) == perms::owner_read) { | ||
4018 | mode |= _S_IREAD; | ||
4019 | } | ||
4020 | if ((prms & perms::owner_write) == perms::owner_write) { | ||
4021 | mode |= _S_IWRITE; | ||
4022 | } | ||
4023 | if (::_wchmod(p.wstring().c_str(), mode) != 0) { | ||
4024 | ec = detail::make_system_error(); | ||
4025 | } | ||
4026 | #endif | ||
4027 | #else | ||
4028 | if ((opts & perm_options::nofollow) != perm_options::nofollow) { | ||
4029 | if (::chmod(p.c_str(), static_cast<mode_t>(prms)) != 0) { | ||
4030 | ec = detail::make_system_error(); | ||
4031 | } | ||
4032 | } | ||
4033 | #endif | ||
4034 | } | ||
4035 | |||
4036 | GHC_INLINE path proximate(const path& p, std::error_code& ec) | ||
4037 | { | ||
4038 | return proximate(p, current_path(), ec); | ||
4039 | } | ||
4040 | |||
4041 | GHC_INLINE path proximate(const path& p, const path& base) | ||
4042 | { | ||
4043 | return weakly_canonical(p).lexically_proximate(weakly_canonical(base)); | ||
4044 | } | ||
4045 | |||
4046 | GHC_INLINE path proximate(const path& p, const path& base, std::error_code& ec) | ||
4047 | { | ||
4048 | return weakly_canonical(p, ec).lexically_proximate(weakly_canonical(base, ec)); | ||
4049 | } | ||
4050 | |||
4051 | GHC_INLINE path read_symlink(const path& p) | ||
4052 | { | ||
4053 | std::error_code ec; | ||
4054 | auto result = read_symlink(p, ec); | ||
4055 | if (ec) { | ||
4056 | throw filesystem_error(detail::systemErrorText(ec.value()), p, ec); | ||
4057 | } | ||
4058 | return result; | ||
4059 | } | ||
4060 | |||
4061 | GHC_INLINE path read_symlink(const path& p, std::error_code& ec) | ||
4062 | { | ||
4063 | file_status fs = symlink_status(p, ec); | ||
4064 | if (fs.type() != file_type::symlink) { | ||
4065 | ec = detail::make_error_code(detail::portable_error::invalid_argument); | ||
4066 | return path(); | ||
4067 | } | ||
4068 | auto result = detail::resolveSymlink(p, ec); | ||
4069 | return ec ? path() : result; | ||
4070 | } | ||
4071 | |||
4072 | GHC_INLINE path relative(const path& p, std::error_code& ec) | ||
4073 | { | ||
4074 | return relative(p, current_path(ec), ec); | ||
4075 | } | ||
4076 | |||
4077 | GHC_INLINE path relative(const path& p, const path& base) | ||
4078 | { | ||
4079 | return weakly_canonical(p).lexically_relative(weakly_canonical(base)); | ||
4080 | } | ||
4081 | |||
4082 | GHC_INLINE path relative(const path& p, const path& base, std::error_code& ec) | ||
4083 | { | ||
4084 | return weakly_canonical(p, ec).lexically_relative(weakly_canonical(base, ec)); | ||
4085 | } | ||
4086 | |||
4087 | GHC_INLINE bool remove(const path& p) | ||
4088 | { | ||
4089 | std::error_code ec; | ||
4090 | auto result = remove(p, ec); | ||
4091 | if (ec) { | ||
4092 | throw filesystem_error(detail::systemErrorText(ec.value()), p, ec); | ||
4093 | } | ||
4094 | return result; | ||
4095 | } | ||
4096 | |||
4097 | GHC_INLINE bool remove(const path& p, std::error_code& ec) noexcept | ||
4098 | { | ||
4099 | ec.clear(); | ||
4100 | #ifdef GHC_OS_WINDOWS | ||
4101 | std::wstring np = detail::fromUtf8<std::wstring>(p.u8string()); | ||
4102 | DWORD attr = GetFileAttributesW(np.c_str()); | ||
4103 | if (attr == INVALID_FILE_ATTRIBUTES) { | ||
4104 | auto error = ::GetLastError(); | ||
4105 | if (error == ERROR_FILE_NOT_FOUND || error == ERROR_PATH_NOT_FOUND) { | ||
4106 | return false; | ||
4107 | } | ||
4108 | ec = detail::make_system_error(error); | ||
4109 | } | ||
4110 | if (!ec) { | ||
4111 | if (attr & FILE_ATTRIBUTE_DIRECTORY) { | ||
4112 | if (!RemoveDirectoryW(np.c_str())) { | ||
4113 | ec = detail::make_system_error(); | ||
4114 | } | ||
4115 | } | ||
4116 | else { | ||
4117 | if (!DeleteFileW(np.c_str())) { | ||
4118 | ec = detail::make_system_error(); | ||
4119 | } | ||
4120 | } | ||
4121 | } | ||
4122 | #else | ||
4123 | if (::remove(p.c_str()) == -1) { | ||
4124 | auto error = errno; | ||
4125 | if (error == ENOENT) { | ||
4126 | return false; | ||
4127 | } | ||
4128 | ec = detail::make_system_error(); | ||
4129 | } | ||
4130 | #endif | ||
4131 | return ec ? false : true; | ||
4132 | } | ||
4133 | |||
4134 | GHC_INLINE uintmax_t remove_all(const path& p) | ||
4135 | { | ||
4136 | std::error_code ec; | ||
4137 | auto result = remove_all(p, ec); | ||
4138 | if (ec) { | ||
4139 | throw filesystem_error(detail::systemErrorText(ec.value()), p, ec); | ||
4140 | } | ||
4141 | return result; | ||
4142 | } | ||
4143 | |||
4144 | GHC_INLINE uintmax_t remove_all(const path& p, std::error_code& ec) noexcept | ||
4145 | { | ||
4146 | ec.clear(); | ||
4147 | uintmax_t count = 0; | ||
4148 | if (p == "/") { | ||
4149 | ec = detail::make_error_code(detail::portable_error::not_supported); | ||
4150 | return static_cast<uintmax_t>(-1); | ||
4151 | } | ||
4152 | std::error_code tec; | ||
4153 | auto fs = status(p, tec); | ||
4154 | if (exists(fs) && is_directory(fs)) { | ||
4155 | for (auto iter = directory_iterator(p, ec); iter != directory_iterator(); iter.increment(ec)) { | ||
4156 | if (ec) { | ||
4157 | break; | ||
4158 | } | ||
4159 | if (!iter->is_symlink() && iter->is_directory()) { | ||
4160 | count += remove_all(iter->path(), ec); | ||
4161 | if (ec) { | ||
4162 | return static_cast<uintmax_t>(-1); | ||
4163 | } | ||
4164 | } | ||
4165 | else { | ||
4166 | remove(iter->path(), ec); | ||
4167 | if (ec) { | ||
4168 | return static_cast<uintmax_t>(-1); | ||
4169 | } | ||
4170 | ++count; | ||
4171 | } | ||
4172 | } | ||
4173 | } | ||
4174 | if (!ec) { | ||
4175 | if (remove(p, ec)) { | ||
4176 | ++count; | ||
4177 | } | ||
4178 | } | ||
4179 | if (ec) { | ||
4180 | return static_cast<uintmax_t>(-1); | ||
4181 | } | ||
4182 | return count; | ||
4183 | } | ||
4184 | |||
4185 | GHC_INLINE void rename(const path& from, const path& to) | ||
4186 | { | ||
4187 | std::error_code ec; | ||
4188 | rename(from, to, ec); | ||
4189 | if (ec) { | ||
4190 | throw filesystem_error(detail::systemErrorText(ec.value()), from, to, ec); | ||
4191 | } | ||
4192 | } | ||
4193 | |||
4194 | GHC_INLINE void rename(const path& from, const path& to, std::error_code& ec) noexcept | ||
4195 | { | ||
4196 | ec.clear(); | ||
4197 | #ifdef GHC_OS_WINDOWS | ||
4198 | if (from != to) { | ||
4199 | if (!MoveFileExW(detail::fromUtf8<std::wstring>(from.u8string()).c_str(), detail::fromUtf8<std::wstring>(to.u8string()).c_str(), (DWORD)MOVEFILE_REPLACE_EXISTING)) { | ||
4200 | ec = detail::make_system_error(); | ||
4201 | } | ||
4202 | } | ||
4203 | #else | ||
4204 | if (from != to) { | ||
4205 | if (::rename(from.c_str(), to.c_str()) != 0) { | ||
4206 | ec = detail::make_system_error(); | ||
4207 | } | ||
4208 | } | ||
4209 | #endif | ||
4210 | } | ||
4211 | |||
4212 | GHC_INLINE void resize_file(const path& p, uintmax_t size) | ||
4213 | { | ||
4214 | std::error_code ec; | ||
4215 | resize_file(p, size, ec); | ||
4216 | if (ec) { | ||
4217 | throw filesystem_error(detail::systemErrorText(ec.value()), p, ec); | ||
4218 | } | ||
4219 | } | ||
4220 | |||
4221 | GHC_INLINE void resize_file(const path& p, uintmax_t size, std::error_code& ec) noexcept | ||
4222 | { | ||
4223 | ec.clear(); | ||
4224 | #ifdef GHC_OS_WINDOWS | ||
4225 | LARGE_INTEGER lisize; | ||
4226 | lisize.QuadPart = static_cast<LONGLONG>(size); | ||
4227 | if(lisize.QuadPart < 0) { | ||
4228 | ec = detail::make_system_error(ERROR_FILE_TOO_LARGE); | ||
4229 | return; | ||
4230 | } | ||
4231 | std::shared_ptr<void> file(CreateFileW(detail::fromUtf8<std::wstring>(p.u8string()).c_str(), GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL), CloseHandle); | ||
4232 | if (file.get() == INVALID_HANDLE_VALUE) { | ||
4233 | ec = detail::make_system_error(); | ||
4234 | } | ||
4235 | else if (SetFilePointerEx(file.get(), lisize, NULL, FILE_BEGIN) == 0 || SetEndOfFile(file.get()) == 0) { | ||
4236 | ec = detail::make_system_error(); | ||
4237 | } | ||
4238 | #else | ||
4239 | if (::truncate(p.c_str(), static_cast<off_t>(size)) != 0) { | ||
4240 | ec = detail::make_system_error(); | ||
4241 | } | ||
4242 | #endif | ||
4243 | } | ||
4244 | |||
4245 | GHC_INLINE space_info space(const path& p) | ||
4246 | { | ||
4247 | std::error_code ec; | ||
4248 | auto result = space(p, ec); | ||
4249 | if (ec) { | ||
4250 | throw filesystem_error(detail::systemErrorText(ec.value()), p, ec); | ||
4251 | } | ||
4252 | return result; | ||
4253 | } | ||
4254 | |||
4255 | GHC_INLINE space_info space(const path& p, std::error_code& ec) noexcept | ||
4256 | { | ||
4257 | ec.clear(); | ||
4258 | #ifdef GHC_OS_WINDOWS | ||
4259 | ULARGE_INTEGER freeBytesAvailableToCaller = {0, 0}; | ||
4260 | ULARGE_INTEGER totalNumberOfBytes = {0, 0}; | ||
4261 | ULARGE_INTEGER totalNumberOfFreeBytes = {0, 0}; | ||
4262 | if (!GetDiskFreeSpaceExW(detail::fromUtf8<std::wstring>(p.u8string()).c_str(), &freeBytesAvailableToCaller, &totalNumberOfBytes, &totalNumberOfFreeBytes)) { | ||
4263 | ec = detail::make_system_error(); | ||
4264 | return {static_cast<uintmax_t>(-1), static_cast<uintmax_t>(-1), static_cast<uintmax_t>(-1)}; | ||
4265 | } | ||
4266 | return {static_cast<uintmax_t>(totalNumberOfBytes.QuadPart), static_cast<uintmax_t>(totalNumberOfFreeBytes.QuadPart), static_cast<uintmax_t>(freeBytesAvailableToCaller.QuadPart)}; | ||
4267 | #elif !defined(__ANDROID__) || __ANDROID_API__ >= 19 | ||
4268 | struct ::statvfs sfs; | ||
4269 | if (::statvfs(p.c_str(), &sfs) != 0) { | ||
4270 | ec = detail::make_system_error(); | ||
4271 | return {static_cast<uintmax_t>(-1), static_cast<uintmax_t>(-1), static_cast<uintmax_t>(-1)}; | ||
4272 | } | ||
4273 | return {static_cast<uintmax_t>(sfs.f_blocks * sfs.f_frsize), static_cast<uintmax_t>(sfs.f_bfree * sfs.f_frsize), static_cast<uintmax_t>(sfs.f_bavail * sfs.f_frsize)}; | ||
4274 | #else | ||
4275 | (void)p; | ||
4276 | ec = detail::make_error_code(detail::portable_error::not_supported); | ||
4277 | return {static_cast<uintmax_t>(-1), static_cast<uintmax_t>(-1), static_cast<uintmax_t>(-1)}; | ||
4278 | #endif | ||
4279 | } | ||
4280 | |||
4281 | GHC_INLINE file_status status(const path& p) | ||
4282 | { | ||
4283 | std::error_code ec; | ||
4284 | auto result = status(p, ec); | ||
4285 | if (result.type() == file_type::none) { | ||
4286 | throw filesystem_error(detail::systemErrorText(ec.value()), p, ec); | ||
4287 | } | ||
4288 | return result; | ||
4289 | } | ||
4290 | |||
4291 | GHC_INLINE file_status status(const path& p, std::error_code& ec) noexcept | ||
4292 | { | ||
4293 | return detail::status_ex(p, ec); | ||
4294 | } | ||
4295 | |||
4296 | GHC_INLINE bool status_known(file_status s) noexcept | ||
4297 | { | ||
4298 | return s.type() != file_type::none; | ||
4299 | } | ||
4300 | |||
4301 | GHC_INLINE file_status symlink_status(const path& p) | ||
4302 | { | ||
4303 | std::error_code ec; | ||
4304 | auto result = symlink_status(p, ec); | ||
4305 | if (result.type() == file_type::none) { | ||
4306 | throw filesystem_error(detail::systemErrorText(ec.value()), ec); | ||
4307 | } | ||
4308 | return result; | ||
4309 | } | ||
4310 | |||
4311 | GHC_INLINE file_status symlink_status(const path& p, std::error_code& ec) noexcept | ||
4312 | { | ||
4313 | return detail::symlink_status_ex(p, ec); | ||
4314 | } | ||
4315 | |||
4316 | GHC_INLINE path temp_directory_path() | ||
4317 | { | ||
4318 | std::error_code ec; | ||
4319 | path result = temp_directory_path(ec); | ||
4320 | if (ec) { | ||
4321 | throw filesystem_error(detail::systemErrorText(ec.value()), ec); | ||
4322 | } | ||
4323 | return result; | ||
4324 | } | ||
4325 | |||
4326 | GHC_INLINE path temp_directory_path(std::error_code& ec) noexcept | ||
4327 | { | ||
4328 | ec.clear(); | ||
4329 | #ifdef GHC_OS_WINDOWS | ||
4330 | wchar_t buffer[512]; | ||
4331 | auto rc = GetTempPathW(511, buffer); | ||
4332 | if (!rc || rc > 511) { | ||
4333 | ec = detail::make_system_error(); | ||
4334 | return path(); | ||
4335 | } | ||
4336 | return path(std::wstring(buffer)); | ||
4337 | #else | ||
4338 | static const char* temp_vars[] = {"TMPDIR", "TMP", "TEMP", "TEMPDIR", nullptr}; | ||
4339 | const char* temp_path = nullptr; | ||
4340 | for (auto temp_name = temp_vars; *temp_name != nullptr; ++temp_name) { | ||
4341 | temp_path = std::getenv(*temp_name); | ||
4342 | if (temp_path) { | ||
4343 | return path(temp_path); | ||
4344 | } | ||
4345 | } | ||
4346 | return path("/tmp"); | ||
4347 | #endif | ||
4348 | } | ||
4349 | |||
4350 | GHC_INLINE path weakly_canonical(const path& p) | ||
4351 | { | ||
4352 | std::error_code ec; | ||
4353 | auto result = weakly_canonical(p, ec); | ||
4354 | if (ec) { | ||
4355 | throw filesystem_error(detail::systemErrorText(ec.value()), p, ec); | ||
4356 | } | ||
4357 | return result; | ||
4358 | } | ||
4359 | |||
4360 | GHC_INLINE path weakly_canonical(const path& p, std::error_code& ec) noexcept | ||
4361 | { | ||
4362 | path result; | ||
4363 | ec.clear(); | ||
4364 | bool scan = true; | ||
4365 | for (auto pe : p) { | ||
4366 | if (scan) { | ||
4367 | std::error_code tec; | ||
4368 | if (exists(result / pe, tec)) { | ||
4369 | result /= pe; | ||
4370 | } | ||
4371 | else { | ||
4372 | if (ec) { | ||
4373 | return path(); | ||
4374 | } | ||
4375 | scan = false; | ||
4376 | if (!result.empty()) { | ||
4377 | result = canonical(result, ec) / pe; | ||
4378 | if (ec) { | ||
4379 | break; | ||
4380 | } | ||
4381 | } | ||
4382 | else { | ||
4383 | result /= pe; | ||
4384 | } | ||
4385 | } | ||
4386 | } | ||
4387 | else { | ||
4388 | result /= pe; | ||
4389 | } | ||
4390 | } | ||
4391 | if (scan) { | ||
4392 | if (!result.empty()) { | ||
4393 | result = canonical(result, ec); | ||
4394 | } | ||
4395 | } | ||
4396 | return ec ? path() : result.lexically_normal(); | ||
4397 | } | ||
4398 | |||
4399 | //----------------------------------------------------------------------------- | ||
4400 | // 30.10.11 class file_status | ||
4401 | // 30.10.11.1 constructors and destructor | ||
4402 | GHC_INLINE file_status::file_status() noexcept | ||
4403 | : file_status(file_type::none) | ||
4404 | { | ||
4405 | } | ||
4406 | |||
4407 | GHC_INLINE file_status::file_status(file_type ft, perms prms) noexcept | ||
4408 | : _type(ft) | ||
4409 | , _perms(prms) | ||
4410 | { | ||
4411 | } | ||
4412 | |||
4413 | GHC_INLINE file_status::file_status(const file_status& other) noexcept | ||
4414 | : _type(other._type) | ||
4415 | , _perms(other._perms) | ||
4416 | { | ||
4417 | } | ||
4418 | |||
4419 | GHC_INLINE file_status::file_status(file_status&& other) noexcept | ||
4420 | : _type(other._type) | ||
4421 | , _perms(other._perms) | ||
4422 | { | ||
4423 | } | ||
4424 | |||
4425 | GHC_INLINE file_status::~file_status() {} | ||
4426 | |||
4427 | // assignments: | ||
4428 | GHC_INLINE file_status& file_status::operator=(const file_status& rhs) noexcept | ||
4429 | { | ||
4430 | _type = rhs._type; | ||
4431 | _perms = rhs._perms; | ||
4432 | return *this; | ||
4433 | } | ||
4434 | |||
4435 | GHC_INLINE file_status& file_status::operator=(file_status&& rhs) noexcept | ||
4436 | { | ||
4437 | _type = rhs._type; | ||
4438 | _perms = rhs._perms; | ||
4439 | return *this; | ||
4440 | } | ||
4441 | |||
4442 | // 30.10.11.3 modifiers | ||
4443 | GHC_INLINE void file_status::type(file_type ft) noexcept | ||
4444 | { | ||
4445 | _type = ft; | ||
4446 | } | ||
4447 | |||
4448 | GHC_INLINE void file_status::permissions(perms prms) noexcept | ||
4449 | { | ||
4450 | _perms = prms; | ||
4451 | } | ||
4452 | |||
4453 | // 30.10.11.2 observers | ||
4454 | GHC_INLINE file_type file_status::type() const noexcept | ||
4455 | { | ||
4456 | return _type; | ||
4457 | } | ||
4458 | |||
4459 | GHC_INLINE perms file_status::permissions() const noexcept | ||
4460 | { | ||
4461 | return _perms; | ||
4462 | } | ||
4463 | |||
4464 | //----------------------------------------------------------------------------- | ||
4465 | // 30.10.12 class directory_entry | ||
4466 | // 30.10.12.1 constructors and destructor | ||
4467 | // directory_entry::directory_entry() noexcept = default; | ||
4468 | // directory_entry::directory_entry(const directory_entry&) = default; | ||
4469 | // directory_entry::directory_entry(directory_entry&&) noexcept = default; | ||
4470 | GHC_INLINE directory_entry::directory_entry(const filesystem::path& p) | ||
4471 | : _path(p) | ||
4472 | , _file_size(0) | ||
4473 | #ifndef GHC_OS_WINDOWS | ||
4474 | , _hard_link_count(0) | ||
4475 | #endif | ||
4476 | , _last_write_time(0) | ||
4477 | { | ||
4478 | refresh(); | ||
4479 | } | ||
4480 | |||
4481 | GHC_INLINE directory_entry::directory_entry(const filesystem::path& p, std::error_code& ec) | ||
4482 | : _path(p) | ||
4483 | , _file_size(0) | ||
4484 | #ifndef GHC_OS_WINDOWS | ||
4485 | , _hard_link_count(0) | ||
4486 | #endif | ||
4487 | , _last_write_time(0) | ||
4488 | { | ||
4489 | refresh(ec); | ||
4490 | } | ||
4491 | |||
4492 | GHC_INLINE directory_entry::~directory_entry() {} | ||
4493 | |||
4494 | // assignments: | ||
4495 | // directory_entry& directory_entry::operator=(const directory_entry&) = default; | ||
4496 | // directory_entry& directory_entry::operator=(directory_entry&&) noexcept = default; | ||
4497 | |||
4498 | // 30.10.12.2 directory_entry modifiers | ||
4499 | GHC_INLINE void directory_entry::assign(const filesystem::path& p) | ||
4500 | { | ||
4501 | _path = p; | ||
4502 | refresh(); | ||
4503 | } | ||
4504 | |||
4505 | GHC_INLINE void directory_entry::assign(const filesystem::path& p, std::error_code& ec) | ||
4506 | { | ||
4507 | _path = p; | ||
4508 | refresh(ec); | ||
4509 | } | ||
4510 | |||
4511 | GHC_INLINE void directory_entry::replace_filename(const filesystem::path& p) | ||
4512 | { | ||
4513 | _path.replace_filename(p); | ||
4514 | refresh(); | ||
4515 | } | ||
4516 | |||
4517 | GHC_INLINE void directory_entry::replace_filename(const filesystem::path& p, std::error_code& ec) | ||
4518 | { | ||
4519 | _path.replace_filename(p); | ||
4520 | refresh(ec); | ||
4521 | } | ||
4522 | |||
4523 | GHC_INLINE void directory_entry::refresh() | ||
4524 | { | ||
4525 | std::error_code ec; | ||
4526 | refresh(ec); | ||
4527 | if (ec) { | ||
4528 | throw filesystem_error(detail::systemErrorText(ec.value()), _path, ec); | ||
4529 | } | ||
4530 | } | ||
4531 | |||
4532 | GHC_INLINE void directory_entry::refresh(std::error_code& ec) noexcept | ||
4533 | { | ||
4534 | #ifdef GHC_OS_WINDOWS | ||
4535 | _status = detail::status_ex(_path, ec, &_symlink_status, &_file_size, nullptr, &_last_write_time); | ||
4536 | #else | ||
4537 | _status = detail::status_ex(_path, ec, &_symlink_status, &_file_size, &_hard_link_count, &_last_write_time); | ||
4538 | #endif | ||
4539 | } | ||
4540 | |||
4541 | // 30.10.12.3 directory_entry observers | ||
4542 | GHC_INLINE const filesystem::path& directory_entry::path() const noexcept | ||
4543 | { | ||
4544 | return _path; | ||
4545 | } | ||
4546 | |||
4547 | GHC_INLINE directory_entry::operator const filesystem::path&() const noexcept | ||
4548 | { | ||
4549 | return _path; | ||
4550 | } | ||
4551 | |||
4552 | GHC_INLINE bool directory_entry::exists() const | ||
4553 | { | ||
4554 | return filesystem::exists(status()); | ||
4555 | } | ||
4556 | |||
4557 | GHC_INLINE bool directory_entry::exists(std::error_code& ec) const noexcept | ||
4558 | { | ||
4559 | return filesystem::exists(status(ec)); | ||
4560 | } | ||
4561 | |||
4562 | GHC_INLINE bool directory_entry::is_block_file() const | ||
4563 | { | ||
4564 | return filesystem::is_block_file(status()); | ||
4565 | } | ||
4566 | GHC_INLINE bool directory_entry::is_block_file(std::error_code& ec) const noexcept | ||
4567 | { | ||
4568 | return filesystem::is_block_file(status(ec)); | ||
4569 | } | ||
4570 | |||
4571 | GHC_INLINE bool directory_entry::is_character_file() const | ||
4572 | { | ||
4573 | return filesystem::is_character_file(status()); | ||
4574 | } | ||
4575 | |||
4576 | GHC_INLINE bool directory_entry::is_character_file(std::error_code& ec) const noexcept | ||
4577 | { | ||
4578 | return filesystem::is_character_file(status(ec)); | ||
4579 | } | ||
4580 | |||
4581 | GHC_INLINE bool directory_entry::is_directory() const | ||
4582 | { | ||
4583 | return filesystem::is_directory(status()); | ||
4584 | } | ||
4585 | |||
4586 | GHC_INLINE bool directory_entry::is_directory(std::error_code& ec) const noexcept | ||
4587 | { | ||
4588 | return filesystem::is_directory(status(ec)); | ||
4589 | } | ||
4590 | |||
4591 | GHC_INLINE bool directory_entry::is_fifo() const | ||
4592 | { | ||
4593 | return filesystem::is_fifo(status()); | ||
4594 | } | ||
4595 | |||
4596 | GHC_INLINE bool directory_entry::is_fifo(std::error_code& ec) const noexcept | ||
4597 | { | ||
4598 | return filesystem::is_fifo(status(ec)); | ||
4599 | } | ||
4600 | |||
4601 | GHC_INLINE bool directory_entry::is_other() const | ||
4602 | { | ||
4603 | return filesystem::is_other(status()); | ||
4604 | } | ||
4605 | |||
4606 | GHC_INLINE bool directory_entry::is_other(std::error_code& ec) const noexcept | ||
4607 | { | ||
4608 | return filesystem::is_other(status(ec)); | ||
4609 | } | ||
4610 | |||
4611 | GHC_INLINE bool directory_entry::is_regular_file() const | ||
4612 | { | ||
4613 | return filesystem::is_regular_file(status()); | ||
4614 | } | ||
4615 | |||
4616 | GHC_INLINE bool directory_entry::is_regular_file(std::error_code& ec) const noexcept | ||
4617 | { | ||
4618 | return filesystem::is_regular_file(status(ec)); | ||
4619 | } | ||
4620 | |||
4621 | GHC_INLINE bool directory_entry::is_socket() const | ||
4622 | { | ||
4623 | return filesystem::is_socket(status()); | ||
4624 | } | ||
4625 | |||
4626 | GHC_INLINE bool directory_entry::is_socket(std::error_code& ec) const noexcept | ||
4627 | { | ||
4628 | return filesystem::is_socket(status(ec)); | ||
4629 | } | ||
4630 | |||
4631 | GHC_INLINE bool directory_entry::is_symlink() const | ||
4632 | { | ||
4633 | return filesystem::is_symlink(symlink_status()); | ||
4634 | } | ||
4635 | |||
4636 | GHC_INLINE bool directory_entry::is_symlink(std::error_code& ec) const noexcept | ||
4637 | { | ||
4638 | return filesystem::is_symlink(symlink_status(ec)); | ||
4639 | } | ||
4640 | |||
4641 | GHC_INLINE uintmax_t directory_entry::file_size() const | ||
4642 | { | ||
4643 | if (_status.type() != file_type::none) { | ||
4644 | return _file_size; | ||
4645 | } | ||
4646 | return filesystem::file_size(path()); | ||
4647 | } | ||
4648 | |||
4649 | GHC_INLINE uintmax_t directory_entry::file_size(std::error_code& ec) const noexcept | ||
4650 | { | ||
4651 | if (_status.type() != file_type::none) { | ||
4652 | ec.clear(); | ||
4653 | return _file_size; | ||
4654 | } | ||
4655 | return filesystem::file_size(path(), ec); | ||
4656 | } | ||
4657 | |||
4658 | GHC_INLINE uintmax_t directory_entry::hard_link_count() const | ||
4659 | { | ||
4660 | #ifndef GHC_OS_WINDOWS | ||
4661 | if (_status.type() != file_type::none) { | ||
4662 | return _hard_link_count; | ||
4663 | } | ||
4664 | #endif | ||
4665 | return filesystem::hard_link_count(path()); | ||
4666 | } | ||
4667 | |||
4668 | GHC_INLINE uintmax_t directory_entry::hard_link_count(std::error_code& ec) const noexcept | ||
4669 | { | ||
4670 | #ifndef GHC_OS_WINDOWS | ||
4671 | if (_status.type() != file_type::none) { | ||
4672 | ec.clear(); | ||
4673 | return _hard_link_count; | ||
4674 | } | ||
4675 | #endif | ||
4676 | return filesystem::hard_link_count(path(), ec); | ||
4677 | } | ||
4678 | |||
4679 | GHC_INLINE file_time_type directory_entry::last_write_time() const | ||
4680 | { | ||
4681 | if (_status.type() != file_type::none) { | ||
4682 | return std::chrono::system_clock::from_time_t(_last_write_time); | ||
4683 | } | ||
4684 | return filesystem::last_write_time(path()); | ||
4685 | } | ||
4686 | |||
4687 | GHC_INLINE file_time_type directory_entry::last_write_time(std::error_code& ec) const noexcept | ||
4688 | { | ||
4689 | if (_status.type() != file_type::none) { | ||
4690 | ec.clear(); | ||
4691 | return std::chrono::system_clock::from_time_t(_last_write_time); | ||
4692 | } | ||
4693 | return filesystem::last_write_time(path(), ec); | ||
4694 | } | ||
4695 | |||
4696 | GHC_INLINE file_status directory_entry::status() const | ||
4697 | { | ||
4698 | if (_status.type() != file_type::none) { | ||
4699 | return _status; | ||
4700 | } | ||
4701 | return filesystem::status(path()); | ||
4702 | } | ||
4703 | |||
4704 | GHC_INLINE file_status directory_entry::status(std::error_code& ec) const noexcept | ||
4705 | { | ||
4706 | if (_status.type() != file_type::none) { | ||
4707 | ec.clear(); | ||
4708 | return _status; | ||
4709 | } | ||
4710 | return filesystem::status(path(), ec); | ||
4711 | } | ||
4712 | |||
4713 | GHC_INLINE file_status directory_entry::symlink_status() const | ||
4714 | { | ||
4715 | if (_symlink_status.type() != file_type::none) { | ||
4716 | return _symlink_status; | ||
4717 | } | ||
4718 | return filesystem::symlink_status(path()); | ||
4719 | } | ||
4720 | |||
4721 | GHC_INLINE file_status directory_entry::symlink_status(std::error_code& ec) const noexcept | ||
4722 | { | ||
4723 | if (_symlink_status.type() != file_type::none) { | ||
4724 | ec.clear(); | ||
4725 | return _symlink_status; | ||
4726 | } | ||
4727 | return filesystem::symlink_status(path(), ec); | ||
4728 | } | ||
4729 | |||
4730 | GHC_INLINE bool directory_entry::operator<(const directory_entry& rhs) const noexcept | ||
4731 | { | ||
4732 | return _path < rhs._path; | ||
4733 | } | ||
4734 | |||
4735 | GHC_INLINE bool directory_entry::operator==(const directory_entry& rhs) const noexcept | ||
4736 | { | ||
4737 | return _path == rhs._path; | ||
4738 | } | ||
4739 | |||
4740 | GHC_INLINE bool directory_entry::operator!=(const directory_entry& rhs) const noexcept | ||
4741 | { | ||
4742 | return _path != rhs._path; | ||
4743 | } | ||
4744 | |||
4745 | GHC_INLINE bool directory_entry::operator<=(const directory_entry& rhs) const noexcept | ||
4746 | { | ||
4747 | return _path <= rhs._path; | ||
4748 | } | ||
4749 | |||
4750 | GHC_INLINE bool directory_entry::operator>(const directory_entry& rhs) const noexcept | ||
4751 | { | ||
4752 | return _path > rhs._path; | ||
4753 | } | ||
4754 | |||
4755 | GHC_INLINE bool directory_entry::operator>=(const directory_entry& rhs) const noexcept | ||
4756 | { | ||
4757 | return _path >= rhs._path; | ||
4758 | } | ||
4759 | |||
4760 | //----------------------------------------------------------------------------- | ||
4761 | // 30.10.13 class directory_iterator | ||
4762 | |||
4763 | #ifdef GHC_OS_WINDOWS | ||
4764 | class directory_iterator::impl | ||
4765 | { | ||
4766 | public: | ||
4767 | impl(const path& p, directory_options options) | ||
4768 | : _base(p) | ||
4769 | , _options(options) | ||
4770 | , _dirHandle(INVALID_HANDLE_VALUE) | ||
4771 | { | ||
4772 | if (!_base.empty()) { | ||
4773 | ZeroMemory(&_findData, sizeof(WIN32_FIND_DATAW)); | ||
4774 | if ((_dirHandle = FindFirstFileW(detail::fromUtf8<std::wstring>((_base / "*").u8string()).c_str(), &_findData)) != INVALID_HANDLE_VALUE) { | ||
4775 | if (std::wstring(_findData.cFileName) == L"." || std::wstring(_findData.cFileName) == L"..") { | ||
4776 | increment(_ec); | ||
4777 | } | ||
4778 | else { | ||
4779 | _current = _base / std::wstring(_findData.cFileName); | ||
4780 | copyToDirEntry(_ec); | ||
4781 | } | ||
4782 | } | ||
4783 | else { | ||
4784 | auto error = ::GetLastError(); | ||
4785 | _base = filesystem::path(); | ||
4786 | if (error != ERROR_ACCESS_DENIED || (options & directory_options::skip_permission_denied) == directory_options::none) { | ||
4787 | _ec = detail::make_system_error(); | ||
4788 | } | ||
4789 | } | ||
4790 | } | ||
4791 | } | ||
4792 | impl(const impl& other) = delete; | ||
4793 | ~impl() | ||
4794 | { | ||
4795 | if (_dirHandle != INVALID_HANDLE_VALUE) { | ||
4796 | FindClose(_dirHandle); | ||
4797 | _dirHandle = INVALID_HANDLE_VALUE; | ||
4798 | } | ||
4799 | } | ||
4800 | void increment(std::error_code& ec) | ||
4801 | { | ||
4802 | if (_dirHandle != INVALID_HANDLE_VALUE) { | ||
4803 | do { | ||
4804 | if (FindNextFileW(_dirHandle, &_findData)) { | ||
4805 | _current = _base; | ||
4806 | try { | ||
4807 | _current.append_name(detail::toUtf8(_findData.cFileName).c_str()); | ||
4808 | } | ||
4809 | catch(filesystem_error& fe) { | ||
4810 | ec = fe.code(); | ||
4811 | return; | ||
4812 | } | ||
4813 | copyToDirEntry(ec); | ||
4814 | } | ||
4815 | else { | ||
4816 | auto err = ::GetLastError(); | ||
4817 | if(err != ERROR_NO_MORE_FILES) { | ||
4818 | _ec = ec = detail::make_system_error(err); | ||
4819 | } | ||
4820 | FindClose(_dirHandle); | ||
4821 | _dirHandle = INVALID_HANDLE_VALUE; | ||
4822 | _current = filesystem::path(); | ||
4823 | break; | ||
4824 | } | ||
4825 | } while (std::wstring(_findData.cFileName) == L"." || std::wstring(_findData.cFileName) == L".."); | ||
4826 | } | ||
4827 | else { | ||
4828 | ec = _ec; | ||
4829 | } | ||
4830 | } | ||
4831 | void copyToDirEntry(std::error_code& ec) | ||
4832 | { | ||
4833 | _dir_entry._path = _current; | ||
4834 | if (_findData.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { | ||
4835 | _dir_entry._status = detail::status_ex(_current, ec, &_dir_entry._symlink_status, &_dir_entry._file_size, nullptr, &_dir_entry._last_write_time); | ||
4836 | } | ||
4837 | else { | ||
4838 | _dir_entry._status = detail::status_from_INFO(_current, &_findData, ec, &_dir_entry._file_size, &_dir_entry._last_write_time); | ||
4839 | _dir_entry._symlink_status = _dir_entry._status; | ||
4840 | } | ||
4841 | if (ec) { | ||
4842 | if (_dir_entry._status.type() != file_type::none && _dir_entry._symlink_status.type() != file_type::none) { | ||
4843 | ec.clear(); | ||
4844 | } | ||
4845 | else { | ||
4846 | _dir_entry._file_size = static_cast<uintmax_t>(-1); | ||
4847 | _dir_entry._last_write_time = 0; | ||
4848 | } | ||
4849 | } | ||
4850 | } | ||
4851 | path _base; | ||
4852 | directory_options _options; | ||
4853 | WIN32_FIND_DATAW _findData; | ||
4854 | HANDLE _dirHandle; | ||
4855 | path _current; | ||
4856 | directory_entry _dir_entry; | ||
4857 | std::error_code _ec; | ||
4858 | }; | ||
4859 | #else | ||
4860 | // POSIX implementation | ||
4861 | class directory_iterator::impl | ||
4862 | { | ||
4863 | public: | ||
4864 | impl(const path& path, directory_options options) | ||
4865 | : _base(path) | ||
4866 | , _options(options) | ||
4867 | , _dir(nullptr) | ||
4868 | , _entry(nullptr) | ||
4869 | { | ||
4870 | if (!path.empty()) { | ||
4871 | _dir = ::opendir(path.native().c_str()); | ||
4872 | } | ||
4873 | if (!path.empty()) { | ||
4874 | if (!_dir) { | ||
4875 | auto error = errno; | ||
4876 | _base = filesystem::path(); | ||
4877 | if (error != EACCES || (options & directory_options::skip_permission_denied) == directory_options::none) { | ||
4878 | _ec = detail::make_system_error(); | ||
4879 | } | ||
4880 | } | ||
4881 | else { | ||
4882 | increment(_ec); | ||
4883 | } | ||
4884 | } | ||
4885 | } | ||
4886 | impl(const impl& other) = delete; | ||
4887 | ~impl() | ||
4888 | { | ||
4889 | if (_dir) { | ||
4890 | ::closedir(_dir); | ||
4891 | } | ||
4892 | } | ||
4893 | void increment(std::error_code& ec) | ||
4894 | { | ||
4895 | if (_dir) { | ||
4896 | do { | ||
4897 | errno = 0; | ||
4898 | _entry = readdir(_dir); | ||
4899 | if (_entry) { | ||
4900 | _current = _base; | ||
4901 | _current.append_name(_entry->d_name); | ||
4902 | _dir_entry = directory_entry(_current, ec); | ||
4903 | } | ||
4904 | else { | ||
4905 | ::closedir(_dir); | ||
4906 | _dir = nullptr; | ||
4907 | _current = path(); | ||
4908 | if (errno) { | ||
4909 | ec = detail::make_system_error(); | ||
4910 | } | ||
4911 | break; | ||
4912 | } | ||
4913 | } while (std::strcmp(_entry->d_name, ".") == 0 || std::strcmp(_entry->d_name, "..") == 0); | ||
4914 | } | ||
4915 | } | ||
4916 | path _base; | ||
4917 | directory_options _options; | ||
4918 | path _current; | ||
4919 | DIR* _dir; | ||
4920 | struct ::dirent* _entry; | ||
4921 | directory_entry _dir_entry; | ||
4922 | std::error_code _ec; | ||
4923 | }; | ||
4924 | #endif | ||
4925 | |||
4926 | // 30.10.13.1 member functions | ||
4927 | GHC_INLINE directory_iterator::directory_iterator() noexcept | ||
4928 | : _impl(new impl(path(), directory_options::none)) | ||
4929 | { | ||
4930 | } | ||
4931 | |||
4932 | GHC_INLINE directory_iterator::directory_iterator(const path& p) | ||
4933 | : _impl(new impl(p, directory_options::none)) | ||
4934 | { | ||
4935 | if (_impl->_ec) { | ||
4936 | throw filesystem_error(detail::systemErrorText(_impl->_ec.value()), p, _impl->_ec); | ||
4937 | } | ||
4938 | _impl->_ec.clear(); | ||
4939 | } | ||
4940 | |||
4941 | GHC_INLINE directory_iterator::directory_iterator(const path& p, directory_options options) | ||
4942 | : _impl(new impl(p, options)) | ||
4943 | { | ||
4944 | if (_impl->_ec) { | ||
4945 | throw filesystem_error(detail::systemErrorText(_impl->_ec.value()), p, _impl->_ec); | ||
4946 | } | ||
4947 | } | ||
4948 | |||
4949 | GHC_INLINE directory_iterator::directory_iterator(const path& p, std::error_code& ec) noexcept | ||
4950 | : _impl(new impl(p, directory_options::none)) | ||
4951 | { | ||
4952 | if (_impl->_ec) { | ||
4953 | ec = _impl->_ec; | ||
4954 | } | ||
4955 | } | ||
4956 | |||
4957 | GHC_INLINE directory_iterator::directory_iterator(const path& p, directory_options options, std::error_code& ec) noexcept | ||
4958 | : _impl(new impl(p, options)) | ||
4959 | { | ||
4960 | if (_impl->_ec) { | ||
4961 | ec = _impl->_ec; | ||
4962 | } | ||
4963 | } | ||
4964 | |||
4965 | GHC_INLINE directory_iterator::directory_iterator(const directory_iterator& rhs) | ||
4966 | : _impl(rhs._impl) | ||
4967 | { | ||
4968 | } | ||
4969 | |||
4970 | GHC_INLINE directory_iterator::directory_iterator(directory_iterator&& rhs) noexcept | ||
4971 | : _impl(std::move(rhs._impl)) | ||
4972 | { | ||
4973 | } | ||
4974 | |||
4975 | GHC_INLINE directory_iterator::~directory_iterator() {} | ||
4976 | |||
4977 | GHC_INLINE directory_iterator& directory_iterator::operator=(const directory_iterator& rhs) | ||
4978 | { | ||
4979 | _impl = rhs._impl; | ||
4980 | return *this; | ||
4981 | } | ||
4982 | |||
4983 | GHC_INLINE directory_iterator& directory_iterator::operator=(directory_iterator&& rhs) noexcept | ||
4984 | { | ||
4985 | _impl = std::move(rhs._impl); | ||
4986 | return *this; | ||
4987 | } | ||
4988 | |||
4989 | GHC_INLINE const directory_entry& directory_iterator::operator*() const | ||
4990 | { | ||
4991 | return _impl->_dir_entry; | ||
4992 | } | ||
4993 | |||
4994 | GHC_INLINE const directory_entry* directory_iterator::operator->() const | ||
4995 | { | ||
4996 | return &_impl->_dir_entry; | ||
4997 | } | ||
4998 | |||
4999 | GHC_INLINE directory_iterator& directory_iterator::operator++() | ||
5000 | { | ||
5001 | std::error_code ec; | ||
5002 | _impl->increment(ec); | ||
5003 | if (ec) { | ||
5004 | throw filesystem_error(detail::systemErrorText(ec.value()), _impl->_current, ec); | ||
5005 | } | ||
5006 | return *this; | ||
5007 | } | ||
5008 | |||
5009 | GHC_INLINE directory_iterator& directory_iterator::increment(std::error_code& ec) noexcept | ||
5010 | { | ||
5011 | _impl->increment(ec); | ||
5012 | return *this; | ||
5013 | } | ||
5014 | |||
5015 | GHC_INLINE bool directory_iterator::operator==(const directory_iterator& rhs) const | ||
5016 | { | ||
5017 | return _impl->_current == rhs._impl->_current; | ||
5018 | } | ||
5019 | |||
5020 | GHC_INLINE bool directory_iterator::operator!=(const directory_iterator& rhs) const | ||
5021 | { | ||
5022 | return _impl->_current != rhs._impl->_current; | ||
5023 | } | ||
5024 | |||
5025 | // 30.10.13.2 directory_iterator non-member functions | ||
5026 | |||
5027 | GHC_INLINE directory_iterator begin(directory_iterator iter) noexcept | ||
5028 | { | ||
5029 | return iter; | ||
5030 | } | ||
5031 | |||
5032 | GHC_INLINE directory_iterator end(const directory_iterator&) noexcept | ||
5033 | { | ||
5034 | return directory_iterator(); | ||
5035 | } | ||
5036 | |||
5037 | //----------------------------------------------------------------------------- | ||
5038 | // 30.10.14 class recursive_directory_iterator | ||
5039 | |||
5040 | GHC_INLINE recursive_directory_iterator::recursive_directory_iterator() noexcept | ||
5041 | : _impl(new recursive_directory_iterator_impl(directory_options::none, true)) | ||
5042 | { | ||
5043 | _impl->_dir_iter_stack.push(directory_iterator()); | ||
5044 | } | ||
5045 | |||
5046 | GHC_INLINE recursive_directory_iterator::recursive_directory_iterator(const path& p) | ||
5047 | : _impl(new recursive_directory_iterator_impl(directory_options::none, true)) | ||
5048 | { | ||
5049 | _impl->_dir_iter_stack.push(directory_iterator(p)); | ||
5050 | } | ||
5051 | |||
5052 | GHC_INLINE recursive_directory_iterator::recursive_directory_iterator(const path& p, directory_options options) | ||
5053 | : _impl(new recursive_directory_iterator_impl(options, true)) | ||
5054 | { | ||
5055 | _impl->_dir_iter_stack.push(directory_iterator(p, options)); | ||
5056 | } | ||
5057 | |||
5058 | GHC_INLINE recursive_directory_iterator::recursive_directory_iterator(const path& p, directory_options options, std::error_code& ec) noexcept | ||
5059 | : _impl(new recursive_directory_iterator_impl(options, true)) | ||
5060 | { | ||
5061 | _impl->_dir_iter_stack.push(directory_iterator(p, options, ec)); | ||
5062 | } | ||
5063 | |||
5064 | GHC_INLINE recursive_directory_iterator::recursive_directory_iterator(const path& p, std::error_code& ec) noexcept | ||
5065 | : _impl(new recursive_directory_iterator_impl(directory_options::none, true)) | ||
5066 | { | ||
5067 | _impl->_dir_iter_stack.push(directory_iterator(p, ec)); | ||
5068 | } | ||
5069 | |||
5070 | GHC_INLINE recursive_directory_iterator::recursive_directory_iterator(const recursive_directory_iterator& rhs) | ||
5071 | : _impl(rhs._impl) | ||
5072 | { | ||
5073 | } | ||
5074 | |||
5075 | GHC_INLINE recursive_directory_iterator::recursive_directory_iterator(recursive_directory_iterator&& rhs) noexcept | ||
5076 | : _impl(std::move(rhs._impl)) | ||
5077 | { | ||
5078 | } | ||
5079 | |||
5080 | GHC_INLINE recursive_directory_iterator::~recursive_directory_iterator() {} | ||
5081 | |||
5082 | // 30.10.14.1 observers | ||
5083 | GHC_INLINE directory_options recursive_directory_iterator::options() const | ||
5084 | { | ||
5085 | return _impl->_options; | ||
5086 | } | ||
5087 | |||
5088 | GHC_INLINE int recursive_directory_iterator::depth() const | ||
5089 | { | ||
5090 | return static_cast<int>(_impl->_dir_iter_stack.size() - 1); | ||
5091 | } | ||
5092 | |||
5093 | GHC_INLINE bool recursive_directory_iterator::recursion_pending() const | ||
5094 | { | ||
5095 | return _impl->_recursion_pending; | ||
5096 | } | ||
5097 | |||
5098 | GHC_INLINE const directory_entry& recursive_directory_iterator::operator*() const | ||
5099 | { | ||
5100 | return *(_impl->_dir_iter_stack.top()); | ||
5101 | } | ||
5102 | |||
5103 | GHC_INLINE const directory_entry* recursive_directory_iterator::operator->() const | ||
5104 | { | ||
5105 | return &(*(_impl->_dir_iter_stack.top())); | ||
5106 | } | ||
5107 | |||
5108 | // 30.10.14.1 modifiers recursive_directory_iterator& | ||
5109 | GHC_INLINE recursive_directory_iterator& recursive_directory_iterator::operator=(const recursive_directory_iterator& rhs) | ||
5110 | { | ||
5111 | _impl = rhs._impl; | ||
5112 | return *this; | ||
5113 | } | ||
5114 | |||
5115 | GHC_INLINE recursive_directory_iterator& recursive_directory_iterator::operator=(recursive_directory_iterator&& rhs) noexcept | ||
5116 | { | ||
5117 | _impl = std::move(rhs._impl); | ||
5118 | return *this; | ||
5119 | } | ||
5120 | |||
5121 | GHC_INLINE recursive_directory_iterator& recursive_directory_iterator::operator++() | ||
5122 | { | ||
5123 | std::error_code ec; | ||
5124 | increment(ec); | ||
5125 | if (ec) { | ||
5126 | throw filesystem_error(detail::systemErrorText(ec.value()), _impl->_dir_iter_stack.empty() ? path() : _impl->_dir_iter_stack.top()->path(), ec); | ||
5127 | } | ||
5128 | return *this; | ||
5129 | } | ||
5130 | |||
5131 | GHC_INLINE recursive_directory_iterator& recursive_directory_iterator::increment(std::error_code& ec) noexcept | ||
5132 | { | ||
5133 | if (recursion_pending() && is_directory((*this)->status()) && (!is_symlink((*this)->symlink_status()) || (options() & directory_options::follow_directory_symlink) != directory_options::none)) { | ||
5134 | _impl->_dir_iter_stack.push(directory_iterator((*this)->path(), _impl->_options, ec)); | ||
5135 | } | ||
5136 | else { | ||
5137 | _impl->_dir_iter_stack.top().increment(ec); | ||
5138 | } | ||
5139 | if (!ec) { | ||
5140 | while (depth() && _impl->_dir_iter_stack.top() == directory_iterator()) { | ||
5141 | _impl->_dir_iter_stack.pop(); | ||
5142 | _impl->_dir_iter_stack.top().increment(ec); | ||
5143 | } | ||
5144 | } | ||
5145 | else if (!_impl->_dir_iter_stack.empty()) { | ||
5146 | _impl->_dir_iter_stack.pop(); | ||
5147 | } | ||
5148 | _impl->_recursion_pending = true; | ||
5149 | return *this; | ||
5150 | } | ||
5151 | |||
5152 | GHC_INLINE void recursive_directory_iterator::pop() | ||
5153 | { | ||
5154 | std::error_code ec; | ||
5155 | pop(ec); | ||
5156 | if (ec) { | ||
5157 | throw filesystem_error(detail::systemErrorText(ec.value()), _impl->_dir_iter_stack.empty() ? path() : _impl->_dir_iter_stack.top()->path(), ec); | ||
5158 | } | ||
5159 | } | ||
5160 | |||
5161 | GHC_INLINE void recursive_directory_iterator::pop(std::error_code& ec) | ||
5162 | { | ||
5163 | if (depth() == 0) { | ||
5164 | *this = recursive_directory_iterator(); | ||
5165 | } | ||
5166 | else { | ||
5167 | do { | ||
5168 | _impl->_dir_iter_stack.pop(); | ||
5169 | _impl->_dir_iter_stack.top().increment(ec); | ||
5170 | } while (depth() && _impl->_dir_iter_stack.top() == directory_iterator()); | ||
5171 | } | ||
5172 | } | ||
5173 | |||
5174 | GHC_INLINE void recursive_directory_iterator::disable_recursion_pending() | ||
5175 | { | ||
5176 | _impl->_recursion_pending = false; | ||
5177 | } | ||
5178 | |||
5179 | // other members as required by 27.2.3, input iterators | ||
5180 | GHC_INLINE bool recursive_directory_iterator::operator==(const recursive_directory_iterator& rhs) const | ||
5181 | { | ||
5182 | return _impl->_dir_iter_stack.top() == rhs._impl->_dir_iter_stack.top(); | ||
5183 | } | ||
5184 | |||
5185 | GHC_INLINE bool recursive_directory_iterator::operator!=(const recursive_directory_iterator& rhs) const | ||
5186 | { | ||
5187 | return _impl->_dir_iter_stack.top() != rhs._impl->_dir_iter_stack.top(); | ||
5188 | } | ||
5189 | |||
5190 | // 30.10.14.2 directory_iterator non-member functions | ||
5191 | GHC_INLINE recursive_directory_iterator begin(recursive_directory_iterator iter) noexcept | ||
5192 | { | ||
5193 | return iter; | ||
5194 | } | ||
5195 | |||
5196 | GHC_INLINE recursive_directory_iterator end(const recursive_directory_iterator&) noexcept | ||
5197 | { | ||
5198 | return recursive_directory_iterator(); | ||
5199 | } | ||
5200 | |||
5201 | #endif // GHC_EXPAND_IMPL | ||
5202 | |||
5203 | } // namespace filesystem | ||
5204 | } // namespace ghc | ||
5205 | |||
5206 | // cleanup some macros | ||
5207 | #undef GHC_INLINE | ||
5208 | #undef GHC_EXPAND_IMPL | ||
5209 | |||
5210 | #endif // GHC_FILESYSTEM_H | ||
diff --git a/src/ghc/fs_std.hpp b/src/ghc/fs_std.hpp deleted file mode 100644 index d8e03b8..0000000 --- a/src/ghc/fs_std.hpp +++ /dev/null | |||
@@ -1,56 +0,0 @@ | |||
1 | //--------------------------------------------------------------------------------------- | ||
2 | // | ||
3 | // ghc::filesystem - A C++17-like filesystem implementation for C++11/C++14 | ||
4 | // | ||
5 | //--------------------------------------------------------------------------------------- | ||
6 | // | ||
7 | // Copyright (c) 2018, Steffen Schümann <s.schuemann@pobox.com> | ||
8 | // | ||
9 | // Permission is hereby granted, free of charge, to any person obtaining a copy | ||
10 | // of this software and associated documentation files (the "Software"), to deal | ||
11 | // in the Software without restriction, including without limitation the rights | ||
12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
13 | // copies of the Software, and to permit persons to whom the Software is | ||
14 | // furnished to do so, subject to the following conditions: | ||
15 | // | ||
16 | // The above copyright notice and this permission notice shall be included in all | ||
17 | // copies or substantial portions of the Software. | ||
18 | // | ||
19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
25 | // SOFTWARE. | ||
26 | // | ||
27 | //--------------------------------------------------------------------------------------- | ||
28 | // fs_std.hpp - The dynamic switching header that includes std::filesystem if detected | ||
29 | // or ghc::filesystem if not, and makes the resulting API available in the | ||
30 | // namespace fs. | ||
31 | //--------------------------------------------------------------------------------------- | ||
32 | #ifndef GHC_FILESYSTEM_STD_H | ||
33 | #if defined(__cplusplus) && __cplusplus >= 201703L && defined(__has_include) && (!defined(__GNUC__) || __GNUC__ >= 9) | ||
34 | #if __has_include(<filesystem>) | ||
35 | #define GHC_USE_STD_FS | ||
36 | #include <filesystem> | ||
37 | namespace fs { | ||
38 | using namespace std::filesystem; | ||
39 | using ifstream = std::ifstream; | ||
40 | using ofstream = std::ofstream; | ||
41 | using fstream = std::fstream; | ||
42 | } | ||
43 | #endif | ||
44 | #endif | ||
45 | #ifndef GHC_USE_STD_FS | ||
46 | #define GHC_WIN_WSTRING_STRING_TYPE | ||
47 | #include "ghc/filesystem.hpp" | ||
48 | namespace fs { | ||
49 | using namespace ghc::filesystem; | ||
50 | using ifstream = ghc::filesystem::ifstream; | ||
51 | using ofstream = ghc::filesystem::ofstream; | ||
52 | using fstream = ghc::filesystem::fstream; | ||
53 | } | ||
54 | #endif | ||
55 | #endif // GHC_FILESYSTEM_STD_H | ||
56 | |||