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