STL/stl/inc/experimental/filesystem

2698 строки
91 KiB
C++

// filesystem experimental header
// Copyright (c) Microsoft Corporation.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#ifndef _EXPERIMENTAL_FILESYSTEM_
#define _EXPERIMENTAL_FILESYSTEM_
#include <yvals_core.h>
#if _STL_COMPILER_PREPROCESSOR
#include <__msvc_chrono.hpp> // for chrono::time_point
#include <algorithm> // for replace
#include <codecvt> // for codecvt_utf8_*
#include <list> // for recursive_directory_iterator stack
#include <locale> // for wstring_convert
#include <memory> // for shared_ptr
#include <vector> // for canonical's .. handling
#pragma pack(push, _CRT_PACKING)
#pragma warning(push, _STL_WARNING_LEVEL)
#pragma warning(disable : _STL_DISABLED_WARNINGS)
_STL_DISABLE_CLANG_WARNINGS
#pragma push_macro("new")
#undef new
#ifndef _SILENCE_EXPERIMENTAL_FILESYSTEM_DEPRECATION_WARNING
#error The <experimental/filesystem> header providing std::experimental::filesystem is deprecated by Microsoft \
and will be REMOVED. It is superseded by the C++17 <filesystem> header providing std::filesystem. \
You can define _SILENCE_EXPERIMENTAL_FILESYSTEM_DEPRECATION_WARNING to suppress this error.
#endif // !defined(_SILENCE_EXPERIMENTAL_FILESYSTEM_DEPRECATION_WARNING)
#pragma warning(disable : 4365) // conversion from 'type_1' to 'type_2', signed/unsigned mismatch (/Wall)
#ifndef _FS_DLL
#define _FS_DLL extern "C" _CRTIMP2_PURE
#endif // !defined(_FS_DLL)
#define _MAX_FILESYS_NAME 260 // longest Windows or Posix filename + 1
#define _FS_BEGIN \
_STD_BEGIN \
namespace experimental { \
namespace filesystem { \
inline namespace v1 {
#define _FS_END \
} \
} \
} \
_STD_END
#define _FSPFX _STD experimental::filesystem::v1::
_FS_BEGIN
using _Pchar = wchar_t; // UTF16
#define _FS_ISSEP(x) ((x) == L'/' || (x) == L'\\')
#define _FS_PREF L'\\'
#define _FS_COLON L':'
#define _FS_PERIOD L'.'
#define _FS_SLASH L'/'
#define _FS_BSLASH L'\\'
struct _Char8_t; // flag for UTF8
enum class file_type { // names for file types
not_found = -1,
none,
regular,
directory,
symlink,
block,
character,
fifo,
socket,
unknown
};
enum class copy_options { // names for copy options
none = 0,
skip_existing = 1,
overwrite_existing = 2,
update_existing = 4,
recursive = 8,
copy_symlinks = 16,
skip_symlinks = 32,
directories_only = 64,
create_symlinks = 128,
create_hard_links = 256,
_Unspecified_recursion_prevention_tag = 512
};
_BITMASK_OPS(_EMPTY_ARGUMENT, copy_options)
enum class directory_options { // names for directory options
none = 0,
follow_directory_symlink
};
enum class perms { // names for permissions
none = 0,
owner_read = 0400, // S_IRUSR
owner_write = 0200, // S_IWUSR
owner_exec = 0100, // S_IXUSR
owner_all = 0700, // S_IRWXU
group_read = 040, // S_IRGRP
group_write = 020, // S_IWGRP
group_exec = 010, // S_IXGRP
group_all = 070, // S_IRWXG
others_read = 04, // S_IROTH
others_write = 02, // S_IWOTH
others_exec = 01, // S_IXOTH
others_all = 07, // S_IRWXO
all = 0777,
set_uid = 04000, // S_ISUID
set_gid = 02000, // S_ISGID
sticky_bit = 01000, // S_ISVTX
mask = 07777,
unknown = 0xFFFF,
add_perms = 0x10000,
remove_perms = 0x20000,
resolve_symlinks = 0x40000
};
_BITMASK_OPS(_EMPTY_ARGUMENT, perms)
class file_status { // stores file status
public:
explicit file_status(file_type _Ftype = file_type::none, perms _Prms = perms::unknown) noexcept
: _Myftype(_Ftype), _Myperms(_Prms) {}
file_status(const file_status&) noexcept = default;
file_status& operator=(const file_status&) noexcept = default;
file_status(file_status&&) = default;
file_status& operator=(file_status&&) = default;
_NODISCARD file_type type() const noexcept {
return _Myftype;
}
_NODISCARD perms permissions() const noexcept {
return _Myperms;
}
void type(file_type _Ftype) noexcept {
_Myftype = _Ftype;
}
void permissions(perms _Prms) noexcept {
_Myperms = _Prms;
}
private:
file_type _Myftype;
perms _Myperms;
};
struct space_info { // space information for a file
uintmax_t capacity;
uintmax_t free;
uintmax_t available;
};
// wide filenames
_FS_DLL void* __CLRCALL_PURE_OR_CDECL _Open_dir(
wchar_t (&)[_MAX_FILESYS_NAME], const wchar_t*, int&, file_type&) noexcept;
_FS_DLL wchar_t* __CLRCALL_PURE_OR_CDECL _Read_dir(wchar_t (&)[_MAX_FILESYS_NAME], void*, file_type&) noexcept;
_FS_DLL void __CLRCALL_PURE_OR_CDECL _Close_dir(void*) noexcept;
_FS_DLL bool __CLRCALL_PURE_OR_CDECL _Current_get(wchar_t (&)[_MAX_FILESYS_NAME]) noexcept;
_FS_DLL bool __CLRCALL_PURE_OR_CDECL _Current_set(const wchar_t*) noexcept;
_FS_DLL wchar_t* __CLRCALL_PURE_OR_CDECL _Symlink_get(wchar_t (&)[_MAX_FILESYS_NAME], const wchar_t*) noexcept;
_FS_DLL wchar_t* __CLRCALL_PURE_OR_CDECL _Temp_get(wchar_t (&)[_MAX_FILESYS_NAME]) noexcept;
_FS_DLL int __CLRCALL_PURE_OR_CDECL _Make_dir(const wchar_t*, const wchar_t*) noexcept;
_FS_DLL bool __CLRCALL_PURE_OR_CDECL _Remove_dir(const wchar_t*) noexcept;
_FS_DLL file_type __CLRCALL_PURE_OR_CDECL _Stat(const wchar_t*, perms*) noexcept;
_FS_DLL file_type __CLRCALL_PURE_OR_CDECL _Lstat(const wchar_t*, perms*) noexcept;
_FS_DLL uintmax_t __CLRCALL_PURE_OR_CDECL _File_size(const wchar_t*) noexcept;
_FS_DLL uintmax_t __CLRCALL_PURE_OR_CDECL _Hard_links(const wchar_t*) noexcept;
_FS_DLL int64_t __CLRCALL_PURE_OR_CDECL _Last_write_time(const wchar_t*) noexcept;
_FS_DLL int __CLRCALL_PURE_OR_CDECL _Set_last_write_time(const wchar_t*, int64_t) noexcept;
_FS_DLL space_info __CLRCALL_PURE_OR_CDECL _Statvfs(const wchar_t*) noexcept;
_FS_DLL int __CLRCALL_PURE_OR_CDECL _Equivalent(const wchar_t*, const wchar_t*) noexcept;
_FS_DLL int __CLRCALL_PURE_OR_CDECL _Link(const wchar_t*, const wchar_t*) noexcept;
_FS_DLL int __CLRCALL_PURE_OR_CDECL _Symlink(const wchar_t*, const wchar_t*) noexcept;
_FS_DLL int __CLRCALL_PURE_OR_CDECL _Rename(const wchar_t*, const wchar_t*) noexcept;
_FS_DLL int __CLRCALL_PURE_OR_CDECL _Resize(const wchar_t*, uintmax_t) noexcept;
_FS_DLL int __CLRCALL_PURE_OR_CDECL _Unlink(const wchar_t*) noexcept;
_FS_DLL int __CLRCALL_PURE_OR_CDECL _Copy_file(const wchar_t*, const wchar_t*) noexcept;
_FS_DLL int __CLRCALL_PURE_OR_CDECL _Chmod(const wchar_t*, perms) noexcept;
template <class _Inchar, class _Outchar, class _Outtraits = char_traits<_Outchar>,
class _Outalloc = allocator<_Outchar>>
struct _Path_cvt { // converts among {char, wchar_t, UTF8, char16_t, char32_t} paths
using _Outstr = basic_string<_Outchar, _Outtraits, _Outalloc>;
static _Outstr&& _Cvt(_Outstr& _Str, const _Inchar* _First, size_t _Size,
_Unused_parameter = {}) { // convert _Inchar sequence to _Outchar one-to-one
for (; 0 < _Size; --_Size, ++_First) {
_Str.push_back(static_cast<_Outchar>(*_First));
}
return _STD move(_Str);
}
};
template <class _Outchar, class _Outtraits, class _Outalloc>
struct _Path_cvt<_Outchar, _Outchar, _Outtraits,
_Outalloc> { // converts among {char, wchar_t, UTF8, char16_t, char32_t} paths
using _Outstr = basic_string<_Outchar, _Outtraits, _Outalloc>;
static _Outstr&& _Cvt(_Outstr& _Str, const _Outchar* _First, size_t _Size,
_Unused_parameter = {}) { // copy _Outchar sequence to _Outchar one-to-one
return _STD move(_Str.append(_First, _First + _Size));
}
};
_STL_DISABLE_DEPRECATED_WARNING
template <class _Outtraits, class _Outalloc>
struct _Path_cvt<char, char16_t, _Outtraits,
_Outalloc> { // converts among {char, wchar_t, UTF8, char16_t, char32_t} paths
using _Inchar = char;
using _Outchar = char16_t;
using _Outstr = basic_string<_Outchar, _Outtraits, _Outalloc>;
static _Outstr&& _Cvt(_Outstr& _Str, const _Inchar* _First, size_t _Size,
_Unused_parameter = {}) { // convert char sequence to char16_t string
wstring_convert<codecvt_utf8_utf16<_Outchar>, _Outchar> _Wcvt;
return _STD move(_Str.append(_Wcvt.from_bytes(_First, _First + _Size)));
}
};
template <class _Outtraits, class _Outalloc>
struct _Path_cvt<char16_t, char, _Outtraits,
_Outalloc> { // converts among {char, wchar_t, UTF8, char16_t, char32_t} paths
using _Inchar = char16_t;
using _Outchar = char;
using _Outstr = basic_string<_Outchar, _Outtraits, _Outalloc>;
static _Outstr&& _Cvt(_Outstr& _Str, const _Inchar* _First, size_t _Size,
_Unused_parameter = {}) { // convert char16_t sequence to char string
wstring_convert<codecvt_utf8_utf16<_Inchar>, _Inchar> _Wcvt;
return _STD move(_Str.append(_Wcvt.to_bytes(_First, _First + _Size)));
}
};
template <class _Outtraits, class _Outalloc>
struct _Path_cvt<char, char32_t, _Outtraits,
_Outalloc> { // converts among {char, wchar_t, UTF8, char16_t, char32_t} paths
using _Inchar = char;
using _Outchar = char32_t;
using _Outstr = basic_string<_Outchar, _Outtraits, _Outalloc>;
static _Outstr&& _Cvt(_Outstr& _Str, const _Inchar* _First, size_t _Size,
_Unused_parameter = {}) { // convert char sequence to char32_t string
wstring_convert<codecvt_utf8<_Outchar>, _Outchar> _Wcvt;
return _STD move(_Str.append(_Wcvt.from_bytes(_First, _First + _Size)));
}
};
template <class _Outtraits, class _Outalloc>
struct _Path_cvt<char32_t, char, _Outtraits,
_Outalloc> { // converts among {char, wchar_t, UTF8, char16_t, char32_t} paths
using _Inchar = char32_t;
using _Outchar = char;
using _Outstr = basic_string<_Outchar, _Outtraits, _Outalloc>;
static _Outstr&& _Cvt(_Outstr& _Str, const _Inchar* _First, size_t _Size,
_Unused_parameter = {}) { // convert char32_t sequence to char string
wstring_convert<codecvt_utf8<_Inchar>, _Inchar> _Wcvt;
return _STD move(_Str.append(_Wcvt.to_bytes(_First, _First + _Size)));
}
};
_FS_DLL int __CLRCALL_PURE_OR_CDECL _To_byte(const wchar_t*, char*) noexcept;
_FS_DLL int __CLRCALL_PURE_OR_CDECL _To_wide(const char*, wchar_t*) noexcept;
template <class _Outtraits, class _Outalloc>
struct _Path_cvt<char, wchar_t, _Outtraits,
_Outalloc> { // converts among {char, wchar_t, UTF8, char16_t, char32_t} paths
using _Inchar = char;
using _Outchar = wchar_t;
using _Outstr = basic_string<_Outchar, _Outtraits, _Outalloc>;
static _Outstr&& _Cvt(_Outstr& _Str, const _Inchar* _First,
size_t) { // convert char sequence to wchar_t string -- Windows
_Outchar _Fname_wide[_MAX_FILESYS_NAME];
if (_To_wide(_First, _Fname_wide) == 0) {
_Xinvalid_argument("invalid char filename argument");
}
return _STD move(_Str.append(_Fname_wide));
}
static _Outstr&& _Cvt(_Outstr& _Str, const _Inchar* _First, size_t _Size,
const locale& _Loc) { // convert char sequence to wchar_t string, locale -- Windows
using _Mycvt = codecvt<_Outchar, _Inchar, _Mbstatet>;
wstring_convert<_Mycvt> _Wcvt(&_STD use_facet<_Mycvt>(_Loc));
return _STD move(_Str.append(_Wcvt.from_bytes(_First, _First + _Size)));
}
};
template <class _Outtraits, class _Outalloc>
struct _Path_cvt<wchar_t, char, _Outtraits,
_Outalloc> { // converts among {char, wchar_t, UTF8, char16_t, char32_t} paths
using _Inchar = wchar_t;
using _Outchar = char;
using _Outstr = basic_string<_Outchar, _Outtraits, _Outalloc>;
static _Outstr&& _Cvt(_Outstr& _Str, const _Inchar* _First,
size_t) { // convert wchar_t sequence to char string -- Windows
_Outchar _Fname_byte[_MAX_FILESYS_NAME];
if (_To_byte(_First, _Fname_byte) == 0) {
_Xinvalid_argument("invalid wchar_t filename argument");
}
return _STD move(_Str.append(_Fname_byte));
}
static _Outstr&& _Cvt(_Outstr& _Str, const _Inchar* _First, size_t _Size,
const locale& _Loc) { // convert wchar_t sequence to char string, locale -- Windows
using _Mycvt = codecvt<_Inchar, _Outchar, _Mbstatet>;
wstring_convert<_Mycvt> _Wcvt(&_STD use_facet<_Mycvt>(_Loc));
return _STD move(_Str.append(_Wcvt.to_bytes(_First, _First + _Size)));
}
};
template <>
struct _Path_cvt<char, _Char8_t, char_traits<char>,
allocator<char>> { // converts among {char, wchar_t, UTF8, char16_t, char32_t} paths
using _Inchar = char;
using _Outchar = char;
using _Outtraits = char_traits<_Outchar>;
using _Outalloc = allocator<_Outchar>;
using _Outstr = basic_string<_Outchar, _Outtraits, _Outalloc>;
static _Outstr&& _Cvt(_Outstr& _Str, const _Inchar* _First, size_t,
_Unused_parameter = {}) { // convert char sequence to UTF8 string -- Windows
wchar_t _Fname_wide[_MAX_FILESYS_NAME];
if (_To_wide(_First, _Fname_wide) == 0) {
_Xinvalid_argument("invalid char filename argument");
}
wstring_convert<codecvt_utf8<wchar_t>, wchar_t> _Wcvt;
wchar_t* _Last1 = _Fname_wide;
while (*_Last1 != L'\0') {
++_Last1;
}
return _STD move(_Str.append(_Wcvt.to_bytes(_Fname_wide, _Last1)));
}
};
template <class _Outtraits, class _Outalloc>
struct _Path_cvt<_Char8_t, char, _Outtraits,
_Outalloc> { // converts among {char, wchar_t, UTF8, char16_t, char32_t} paths
using _Inchar = char;
using _Outchar = char;
using _Outstr = basic_string<_Outchar, _Outtraits, _Outalloc>;
static _Outstr&& _Cvt(_Outstr& _Str, const _Inchar* _First, size_t _Size,
_Unused_parameter = {}) { // convert UTF8 sequence to char string -- Windows
wstring_convert<codecvt_utf8_utf16<wchar_t>, wchar_t> _Wcvt;
wstring _Str0(_Wcvt.from_bytes(_First, _First + _Size));
_Outchar _Fname_byte[_MAX_FILESYS_NAME];
if (_To_byte(_Str0.c_str(), _Fname_byte) == 0) {
_Xinvalid_argument("invalid UTF8 filename argument");
}
return _STD move(_Str.append(_Fname_byte));
}
};
template <>
struct _Path_cvt<wchar_t, _Char8_t, char_traits<char>,
allocator<char>> { // converts among {char, wchar_t, UTF8, char16_t, char32_t} paths
using _Inchar = wchar_t;
using _Outchar = char;
using _Outtraits = char_traits<_Outchar>;
using _Outalloc = allocator<_Outchar>;
using _Outstr = basic_string<_Outchar, _Outtraits, _Outalloc>;
static _Outstr&& _Cvt(_Outstr& _Str, const _Inchar* _First, size_t _Size,
_Unused_parameter = {}) { // convert wchar_t sequence to UTF8 string -- Windows
wstring_convert<codecvt_utf8<_Inchar>, _Inchar> _Wcvt;
return _STD move(_Str.append(_Wcvt.to_bytes(_First, _First + _Size)));
}
};
template <class _Outtraits, class _Outalloc>
struct _Path_cvt<_Char8_t, wchar_t, _Outtraits,
_Outalloc> { // converts among {char, wchar_t, UTF8, char16_t, char32_t} paths
using _Inchar = char;
using _Outchar = wchar_t;
using _Outstr = basic_string<_Outchar, _Outtraits, _Outalloc>;
static _Outstr&& _Cvt(_Outstr& _Str, const _Inchar* _First, size_t _Size,
_Unused_parameter = {}) { // convert UTF8 sequence to wchar_t string -- Windows
wstring_convert<codecvt_utf8<_Outchar>, _Outchar> _Wcvt;
return _STD move(_Str.append(_Wcvt.from_bytes(_First, _First + _Size)));
}
};
// struct _Path_cvt<wchar_t, char16_t, _Outtraits, _Outalloc> Windows (copy)
// struct _Path_cvt<char16_t, wchar_t, _Outtraits, _Outalloc> Windows (copy)
template <class _Outtraits, class _Outalloc>
struct _Path_cvt<wchar_t, char32_t, _Outtraits,
_Outalloc> { // converts among {char, wchar_t, UTF8, char16_t, char32_t} paths
using _Inchar = wchar_t;
using _Outchar = char32_t;
using _Outstr = basic_string<_Outchar, _Outtraits, _Outalloc>;
static _Outstr&& _Cvt(_Outstr& _Str, const _Inchar* _First, size_t _Size,
_Unused_parameter = {}) { // convert wchar_t sequence to char32_t string -- Windows
wstring_convert<codecvt_utf8_utf16<_Inchar>, _Inchar> _Wcvt0;
_STD string _Str0(_Wcvt0.to_bytes(_First, _First + _Size));
wstring_convert<codecvt_utf8<_Outchar>, _Outchar> _Wcvt;
return _STD move(_Str.append(_Wcvt.from_bytes(_Str0)));
}
};
template <class _Outtraits, class _Outalloc>
struct _Path_cvt<char32_t, wchar_t, _Outtraits,
_Outalloc> { // converts among {char, wchar_t, UTF8, char16_t, char32_t} paths
using _Inchar = char32_t;
using _Outchar = wchar_t;
using _Outstr = basic_string<_Outchar, _Outtraits, _Outalloc>;
static _Outstr&& _Cvt(_Outstr& _Str, const _Inchar* _First, size_t _Size,
_Unused_parameter = {}) { // convert char32_t sequence to wchar_t string -- Windows
wstring_convert<codecvt_utf8<_Inchar>, _Inchar> _Wcvt0;
_STD string _Str0(_Wcvt0.to_bytes(_First, _First + _Size));
wstring_convert<codecvt_utf8_utf16<_Outchar>, _Outchar> _Wcvt;
return _STD move(_Str.append(_Wcvt.from_bytes(_Str0)));
}
};
_STL_RESTORE_DEPRECATED_WARNING
class path;
path operator/(const path&, const path&);
path _Absolute(const path&, const path&, error_code&);
// path absolute(const path&, const path& = current_path());
void _Canonicalize_string_only(path&, const path&);
// path canonical(const path&, const path& _Base = current_path());
path canonical(const path&, error_code&);
path canonical(const path&, const path&, error_code&);
void copy(const path&, const path&);
void copy(const path&, const path&, error_code&) noexcept;
void copy(const path&, const path&, copy_options);
void copy(const path&, const path&, copy_options, error_code&) noexcept;
bool copy_file(const path&, const path&, copy_options = copy_options::none);
bool copy_file(const path&, const path&, error_code&) noexcept;
bool copy_file(const path&, const path&, copy_options, error_code&) noexcept;
void copy_symlink(const path&, const path&);
void copy_symlink(const path&, const path&, error_code&) noexcept;
bool create_directories(const path&);
bool create_directories(const path&, error_code&) noexcept;
bool create_directory(const path&);
bool create_directory(const path&, error_code&) noexcept;
bool create_directory(const path&, const path&);
bool create_directory(const path&, const path&, error_code&) noexcept;
void create_directory_symlink(const path&, const path&);
void create_directory_symlink(const path&, const path&, error_code&) noexcept;
void create_hard_link(const path&, const path&);
void create_hard_link(const path&, const path&, error_code&) noexcept;
void create_symlink(const path&, const path&);
void create_symlink(const path&, const path&, error_code&) noexcept;
path current_path();
path current_path(error_code&);
void current_path(const path&);
void current_path(const path&, error_code&) noexcept;
bool equivalent(const path&, const path&);
bool equivalent(const path&, const path&, error_code&) noexcept;
bool exists(file_status) noexcept;
bool exists(const path&);
bool exists(const path&, error_code&) noexcept;
uintmax_t file_size(const path&);
uintmax_t file_size(const path&, error_code&) noexcept;
uintmax_t hard_link_count(const path&);
uintmax_t hard_link_count(const path&, error_code&) noexcept;
bool is_block_file(file_status) noexcept;
bool is_block_file(const path&);
bool is_block_file(const path&, error_code&) noexcept;
bool is_character_file(file_status) noexcept;
bool is_character_file(const path&);
bool is_character_file(const path&, error_code&) noexcept;
bool is_directory(file_status) noexcept;
bool is_directory(const path&);
bool is_directory(const path&, error_code&) noexcept;
bool is_empty(const path&);
bool is_empty(const path&, error_code&) noexcept;
bool is_fifo(file_status) noexcept;
bool is_fifo(const path&);
bool is_fifo(const path&, error_code&) noexcept;
bool is_other(file_status) noexcept;
bool is_other(const path&);
bool is_other(const path&, error_code&) noexcept;
bool is_regular_file(file_status) noexcept;
bool is_regular_file(const path&);
bool is_regular_file(const path&, error_code&) noexcept;
bool is_socket(file_status) noexcept;
bool is_socket(const path&);
bool is_socket(const path&, error_code&) noexcept;
bool is_symlink(file_status) noexcept;
bool is_symlink(const path&);
bool is_symlink(const path&, error_code&) noexcept;
using file_time_type = chrono::system_clock::time_point;
file_time_type last_write_time(const path&, error_code&) noexcept;
file_time_type last_write_time(const path&);
void last_write_time(const path&, file_time_type, error_code&) noexcept;
void last_write_time(const path&, file_time_type);
void permissions(const path&, perms);
void permissions(const path&, perms, error_code&);
path read_symlink(const path&);
path read_symlink(const path&, error_code&);
bool remove(const path&);
bool remove(const path&, error_code&) noexcept;
uintmax_t remove_all(const path&);
uintmax_t remove_all(const path&, error_code&) noexcept;
void rename(const path&, const path&);
void rename(const path&, const path&, error_code&) noexcept;
void resize_file(const path&, uintmax_t);
void resize_file(const path&, uintmax_t, error_code&) noexcept;
space_info space(const path&);
space_info space(const path&, error_code&) noexcept;
file_status status(const path&);
file_status status(const path&, error_code&) noexcept;
bool status_known(file_status) noexcept;
file_status symlink_status(const path&);
file_status symlink_status(const path&, error_code&) noexcept;
path system_complete(const path&);
path system_complete(const path&, error_code&);
path temp_directory_path();
path temp_directory_path(error_code&);
template <class _Path_type>
class _Path_iterator {
public:
using path_type = _Path_type;
using string_type = typename _Path_type::string_type;
using iterator_category = bidirectional_iterator_tag;
using value_type = path_type;
using difference_type = ptrdiff_t;
using pointer = const value_type*;
using reference = const value_type&;
_Path_iterator() : _Myptr(nullptr), _Myoff(0) {}
_Path_iterator(const path_type& _Path, size_t _Off) : _Myptr(&_Path), _Myoff(_Off) {
_Getval();
}
_Path_iterator(const _Path_iterator& _Right)
: _Myptr(_Right._Myptr), _Myelem(_Right._Myelem), _Myoff(_Right._Myoff) {}
_Path_iterator& operator=(const _Path_iterator& _Right) {
_Myptr = _Right._Myptr;
_Myelem = _Right._Myelem;
_Myoff = _Right._Myoff;
return *this;
}
_Path_iterator(_Path_iterator&& _Right) noexcept
: _Myptr(_Right._Myptr), _Myelem(_STD move(_Right._Myelem)), _Myoff(_Right._Myoff) {}
_Path_iterator& operator=(_Path_iterator&& _Right) noexcept {
_Myptr = _Right._Myptr;
_Myelem = _STD move(_Right._Myelem);
_Myoff = _Right._Myoff;
return *this;
}
_NODISCARD reference operator*() const {
return _Myelem;
}
_NODISCARD pointer operator->() const {
return pointer_traits<pointer>::pointer_to(**this);
}
_Path_iterator& operator++() {
#if _ITERATOR_DEBUG_LEVEL != 0
_STL_VERIFY(_Myptr && _Myoff < _Myptr->_Mystr.size(), "path::iterator is not incrementable");
#endif // _ITERATOR_DEBUG_LEVEL != 0
const size_t _Pend = _Myptr->_Prefix_end();
const size_t _Size = _Myptr->_Mystr.size();
if (_Myoff < _Pend) {
_Myoff = _Pend; // point past "x:"
} else if (_Myoff == _Pend && _Pend < _Size
&& _FS_ISSEP(_Myptr->_Mystr[_Pend])) { // point past root "/" and following slashes
for (++_Myoff; _Myoff < _Size; ++_Myoff) {
if (!_FS_ISSEP(_Myptr->_Mystr[_Myoff])) {
break;
}
}
} else { // point past slashes followed by stuff
for (; _Myoff < _Size; ++_Myoff) {
if (!_FS_ISSEP(_Myptr->_Mystr[_Myoff])) {
break;
}
}
for (; _Myoff < _Size; ++_Myoff) {
if (_FS_ISSEP(_Myptr->_Mystr[_Myoff])) {
break;
}
}
}
_Getval();
return *this;
}
_Path_iterator operator++(int) {
_Path_iterator _Tmp = *this;
++*this;
return _Tmp;
}
_Path_iterator& operator--() {
#if _ITERATOR_DEBUG_LEVEL != 0
_STL_VERIFY(_Myptr && _Myoff != 0, "path::iterator is not decrementable");
#endif // _ITERATOR_DEBUG_LEVEL != 0
const size_t _Myoff_sav = _Myoff;
size_t _Off_back = 0;
_Myoff = 0;
do { // scan down to previous
_Off_back = _Myoff;
++*this;
} while (_Myoff < _Myoff_sav);
_Myoff = _Off_back;
_Getval();
return *this;
}
_Path_iterator operator--(int) {
_Path_iterator _Tmp = *this;
--*this;
return _Tmp;
}
_NODISCARD bool operator==(const _Path_iterator& _Right) const {
return _Myptr == _Right._Myptr && _Myoff == _Right._Myoff;
}
_NODISCARD bool operator!=(const _Path_iterator& _Right) const {
return !(*this == _Right);
}
private:
void _Getval() { // determine _Myelem
string_type _Str;
const size_t _Pend = _Myptr->_Prefix_end();
const size_t _Size = _Myptr->_Mystr.size();
if (_Size > _Myoff) {
if (_Myoff < _Pend) {
_Str = _Myptr->_Mystr.substr(0, _Pend); // get "x:"
} else if (_Myoff == _Pend && _Pend < _Size && _FS_ISSEP(_Myptr->_Mystr[_Pend])) {
_Str = _FS_PREF; // get "/"
} else { // determine next field as slashes followed by stuff
size_t _Nslash = 0;
size_t _Nstuff = 0;
for (; _Myoff + _Nslash < _Size; ++_Nslash) {
if (!_FS_ISSEP(_Myptr->_Mystr[_Myoff + _Nslash])) {
break;
}
}
for (; _Myoff + _Nslash + _Nstuff < _Size; ++_Nstuff) {
if (_FS_ISSEP(_Myptr->_Mystr[_Myoff + _Nslash + _Nstuff])) {
break;
}
}
if (0 < _Nstuff) {
_Str = _Myptr->_Mystr.substr(_Myoff + _Nslash, _Nstuff); // get "stuff"
} else if (0 < _Nslash) {
_Str = _FS_PERIOD; // get "."
}
}
}
_Myelem = _Str;
}
const path_type* _Myptr; // pointer to full path
path_type _Myelem; // current element subpath
size_t _Myoff; // current offset in full path
};
class path { // stores a pathname
public:
using value_type = _Pchar;
using string_type = basic_string<value_type>;
static constexpr value_type preferred_separator = _FS_PREF;
path() {}
path(const path& _Right) : _Mystr(_Right._Mystr) {}
template <class _InIt, enable_if_t<_Is_iterator_v<_InIt>, int> = 0>
path(_InIt _First, _InIt _Last) {
using _Valty = _Iter_value_t<_InIt>;
basic_string<_Valty> _Str(_First, _Last);
string_type _Str_out;
*this /= _Path_cvt<_Valty, value_type>::_Cvt(_Str_out, _Str.c_str(), _Str.size());
}
template <class _InIt, enable_if_t<conjunction_v<negation<is_same<_InIt, path>>, _Is_iterator<_InIt>>, int> = 0>
path(_InIt _First) {
using _Valty = _Iter_value_t<_InIt>;
basic_string<_Valty> _Str;
for (; *_First != _Valty(0); ++_First) {
_Str += *_First;
}
string_type _Str_out;
*this /= _Path_cvt<_Valty, value_type>::_Cvt(_Str_out, _Str.c_str(), _Str.size());
}
template <class _Elem, class _Traits, class _Alloc>
path(const basic_string<_Elem, _Traits, _Alloc>& _Str) {
string_type _Str_out;
*this /= _Path_cvt<_Elem, value_type>::_Cvt(_Str_out, _Str.c_str(), _Str.size());
}
template <class _InIt, enable_if_t<_Is_iterator_v<_InIt>, int> = 0>
path(_InIt _First, _InIt _Last, const locale& _Loc) {
using _Valty = _Iter_value_t<_InIt>;
basic_string<_Valty> _Str(_First, _Last);
string_type _Str_out;
*this /= _Path_cvt<_Valty, value_type>::_Cvt(_Str_out, _Str.c_str(), _Str.size(), _Loc);
}
template <class _InIt, enable_if_t<_Is_iterator_v<_InIt>, int> = 0>
path(_InIt _First, const locale& _Loc) {
using _Valty = _Iter_value_t<_InIt>;
basic_string<_Valty> _Str;
for (; *_First != _Valty(0); ++_First) {
_Str += *_First;
}
string_type _Str_out;
*this /= _Path_cvt<_Valty, value_type>::_Cvt(_Str_out, _Str.c_str(), _Str.size(), _Loc);
}
template <class _Elem, class _Traits, class _Alloc>
path(const basic_string<_Elem, _Traits, _Alloc>& _Str, const locale& _Loc) {
string_type _Str_out;
*this /= _Path_cvt<_Elem, value_type>::_Cvt(_Str_out, _Str.c_str(), _Str.size(), _Loc);
}
path(path&& _Right) noexcept : _Mystr(_STD move(_Right._Mystr)) {}
path& operator=(path&& _Right) noexcept {
_Mystr = _STD move(_Right._Mystr);
return *this;
}
~path() noexcept {}
path& operator=(const path& _Right) {
_Mystr = _Right._Mystr;
return *this;
}
template <class _InIt>
path& operator=(_InIt _First) {
return *this = path{_First};
}
template <class _Elem, class _Traits, class _Alloc>
path& operator=(const basic_string<_Elem, _Traits, _Alloc>& _Str) {
return *this = path{_Str};
}
template <class _InIt>
path& assign(_InIt _First, _InIt _Last) {
return *this = path{_First, _Last};
}
template <class _InIt>
path& assign(_InIt _First) {
return *this = path{_First};
}
template <class _Elem, class _Traits, class _Alloc>
path& assign(const basic_string<_Elem, _Traits, _Alloc>& _Str) {
return *this = path{_Str};
}
path& operator/=(const path& _Path) { // append copy
return append(_Path._Mystr);
}
template <class _InIt>
path& operator/=(_InIt _First) { // append NTCTS, given iterator
return append(path{_First}._Mystr);
}
template <class _Elem, class _Traits, class _Alloc>
path& operator/=(const basic_string<_Elem, _Traits, _Alloc>& _Str) { // append arbitrary source string
return append(_Str);
}
template <class _InIt>
path& append(_InIt _First, _InIt _Last) { // append NTCTS
return append(path{_First, _Last}._Mystr);
}
template <class _InIt>
path& append(_InIt _First) { // append NTCTS
return append(path{_First}._Mystr);
}
template <class _Elem, class _Traits, class _Alloc>
path& append(const basic_string<_Elem, _Traits, _Alloc>& _Str0) { // append arbitrary source string
string_type _Str(_Str0.size(), L'\0');
// convert _Elem and '/' to '\'
_STD transform(_Str0.begin(), _Str0.end(), _Str.begin(), [](const _Elem _Ch) _STATIC_CALL_OPERATOR {
auto _Wch = static_cast<wchar_t>(_Ch);
if (_Wch == _FS_SLASH) {
_Wch = _FS_PREF;
}
return _Wch;
});
if (0 < _Mystr.size() && 0 < _Str.size() && _Mystr.back() != _FS_COLON && !_FS_ISSEP(_Mystr.back())
&& !_FS_ISSEP(_Str[0])) {
_Mystr.push_back(_FS_PREF); // add needed separator
}
_Mystr.append(_Str);
return *this;
}
path& operator+=(const path& _Path) { // concatenate copy
return concat(_Path._Mystr);
}
template <class _Ty>
path& operator+=(_Ty _Val) { // concatenate NTCTS, given iterator/element
return concat(_Val);
}
template <class _Elem, class _Traits, class _Alloc>
path& operator+=(const basic_string<_Elem, _Traits, _Alloc>& _Str) { // concatenate arbitrary source string
return concat(_Str);
}
template <class _Elem>
path& operator+=(const _Elem* _Ptr) { // concatenate arbitrary NTCTS
return concat(basic_string<_Elem>(_Ptr));
}
template <class _InIt>
path& concat(_InIt _First, _InIt _Last) { // concatenate NTCTS
return concat(path{_First, _Last}._Mystr);
}
template <class _Elem>
path& concat(const _Elem* _Ptr) { // concatenate arbitrary NTCTS
return concat(basic_string<_Elem>(_Ptr));
}
template <class _InIt, enable_if_t<_Is_iterator_v<_InIt>, int> = 0>
path& concat(_InIt _First) { // concatenate NTCTS
return concat(path{_First}._Mystr);
}
template <class _Elem, enable_if_t<!_Is_iterator_v<_Elem>, int> = 0>
path& concat(_Elem _Val) { // concatenate element
return concat(path{basic_string<_Elem>(1, _Val)}._Mystr);
}
template <class _Elem, class _Traits, class _Alloc>
path& concat(const basic_string<_Elem, _Traits, _Alloc>& _Str) { // concatenate arbitrary source string
for (const auto& _Ch : _Str) {
_Mystr.push_back(static_cast<wchar_t>(_Ch));
}
return *this;
}
void clear() noexcept { // clear the stored string
_Mystr.clear();
}
path& make_preferred() { // convert any '/' to '\'
_STD replace(_Mystr.begin(), _Mystr.end(), _FS_SLASH, _FS_BSLASH);
return *this;
}
path& remove_filename() { // remove filename (leaf)
if (!empty() && begin() != --end()) { // leaf to remove, back up over it
const size_t _Rend = _Root_end();
size_t _Idx = _Mystr.size();
for (; _Rend < _Idx; --_Idx) {
if (_FS_ISSEP(_Mystr[_Idx - 1])) {
break; // back up over stuff at end
}
}
for (; _Rend < _Idx; --_Idx) {
if (!_FS_ISSEP(_Mystr[_Idx - 1])) {
break; // back up over trailing non-root slashes
}
}
_Mystr.erase(_Idx);
}
return *this;
}
path& replace_filename(const path& _Path) { // replace filename
remove_filename();
*this /= _Path;
return *this;
}
path& replace_extension(const path& _Newext = {}) { // replace extension with _Newext
if (_Newext.empty() || _Newext.c_str()[0] == _FS_PERIOD) {
*this = parent_path() / path{stem().native() + _Newext.native()};
} else {
*this = parent_path() / path{stem().native() + _FS_PERIOD + _Newext.native()};
}
return *this;
}
void swap(path& _Right) noexcept {
_Mystr.swap(_Right._Mystr);
}
_NODISCARD const string_type& native() const noexcept {
return _Mystr;
}
_NODISCARD _Ret_z_ const value_type* c_str() const noexcept {
return _Mystr.c_str();
}
operator string_type() const {
return _Mystr;
}
template <class _Elem, class _Traits = char_traits<_Elem>, class _Alloc = allocator<_Elem>>
_NODISCARD basic_string<_Elem, _Traits, _Alloc> string(
const _Alloc& _Al = _Alloc()) const { // return path as basic_string<_Elem, _Traits, _Alloc>
basic_string<_Elem, _Traits, _Alloc> _Str(_Al);
return _Path_cvt<value_type, _Elem>::_Cvt(_Str, _Mystr.c_str(), _Mystr.size());
}
_NODISCARD _STD string string() const { // return path as basic_string<char> native
_STD string _Str;
return _Path_cvt<value_type, char>::_Cvt(_Str, _Mystr.c_str(), _Mystr.size());
}
_NODISCARD _STD wstring wstring() const { // return path as basic_string<wchar_t> native
_STD wstring _Str;
return _Path_cvt<value_type, wchar_t>::_Cvt(_Str, _Mystr.c_str(), _Mystr.size());
}
_NODISCARD _STD string u8string() const { // return path as basic_string<char> UTF8
_STD string _Str;
return _Path_cvt<value_type, _Char8_t, char_traits<char>, allocator<char>>::_Cvt(
_Str, _Mystr.c_str(), _Mystr.size());
}
_NODISCARD _STD u16string u16string() const { // return path as basic_string<char16_t> UTF16
_STD u16string _Str;
return _Path_cvt<value_type, char16_t>::_Cvt(_Str, _Mystr.c_str(), _Mystr.size());
}
_STD u32string u32string() const = delete;
string_type _Make_generic() const { // copy and convert any '\' to '/'
string_type _Str = _Mystr;
_STD replace(_Str.begin(), _Str.end(), _FS_BSLASH, _FS_SLASH);
return _Str;
}
template <class _Elem, class _Traits = char_traits<_Elem>, class _Alloc = allocator<_Elem>>
_NODISCARD basic_string<_Elem, _Traits, _Alloc> generic_string(
const _Alloc& _Al = _Alloc()) const { // return path as basic_string<_Elem, _Traits, _Alloc>
basic_string<_Elem, _Traits, _Alloc> _Str(_Al);
const string_type _Genstr = _Make_generic();
return _Path_cvt<value_type, _Elem>::_Cvt(_Str, _Genstr.c_str(), _Genstr.size());
}
_NODISCARD _STD string generic_string() const { // return path as basic_string<char> native
_STD string _Str;
const string_type _Genstr = _Make_generic();
return _Path_cvt<value_type, char>::_Cvt(_Str, _Genstr.c_str(), _Genstr.size());
}
_NODISCARD _STD wstring generic_wstring() const { // return path as basic_string<wchar_t> native
_STD wstring _Str;
const string_type _Genstr = _Make_generic();
return _Path_cvt<value_type, wchar_t>::_Cvt(_Str, _Genstr.c_str(), _Genstr.size());
}
_NODISCARD _STD string generic_u8string() const { // return path as basic_string<char> UTF8
_STD string _Str;
const string_type _Genstr = _Make_generic();
return _Path_cvt<value_type, _Char8_t, char_traits<char>, allocator<char>>::_Cvt(
_Str, _Genstr.c_str(), _Genstr.size());
}
_NODISCARD _STD u16string generic_u16string() const { // return path as basic_string<char16_t> UTF16
_STD u16string _Str;
const string_type _Genstr = _Make_generic();
return _Path_cvt<value_type, char16_t>::_Cvt(_Str, _Genstr.c_str(), _Genstr.size());
}
_STD u32string generic_u32string() const = delete;
_NODISCARD int compare(const path& _Path) const noexcept { // compare native() to _Path.native()
return _Mystr.compare(_Path._Mystr);
}
_NODISCARD int compare(const string_type& _Str) const { // compare native() to string
return _Mystr.compare(_Str);
}
_NODISCARD int compare(const value_type* _Ptr) const { // compare native() to NTCS
return _Mystr.compare(_Ptr);
}
_NODISCARD path root_name() const {
return path{_Mystr.substr(0, _Prefix_end())};
}
_NODISCARD path root_directory() const {
const size_t _Idx = _Prefix_end();
if (_Idx < _Mystr.size() && _FS_ISSEP(_Mystr[_Idx])) {
return path{string_type(1, _FS_PREF)};
} else {
return {};
}
}
_NODISCARD path root_path() const {
return path{_Mystr.c_str(), _Mystr.c_str() + _Root_end()};
}
_NODISCARD path relative_path() const {
size_t _Idx = _Root_end();
while (_Idx < _Mystr.size() && _FS_ISSEP(_Mystr[_Idx])) {
++_Idx; // skip extra '/' after root
}
return path{_Mystr.substr(_Idx)};
}
_NODISCARD path parent_path() const {
path _Ans;
if (!empty()) { // append all but last element
iterator _End = --end();
for (iterator _Next = begin(); _Next != _End; ++_Next) {
_Ans /= *_Next;
}
}
return _Ans;
}
_NODISCARD path filename() const {
return empty() ? path{} : path{*--end()};
}
_NODISCARD path stem() const { // pick off stem (basename) in filename (leaf) before dot
string_type _Str0 = filename().native();
string_type _Str1 = extension().native();
_Str0.resize(_Str0.size() - _Str1.size());
return path{_Str0};
}
_NODISCARD path extension() const { // pick off .extension in filename (leaf), including dot
string_type _Str = filename().native();
const size_t _Idx = _Str.rfind(_FS_PERIOD);
return _Idx == string_type::npos // no .
|| _Str.size() == 1 // only .
|| (_Str.size() == 2 && _Str[0] == _FS_PERIOD && _Str[1] == _FS_PERIOD) // only ..
? path{}
: path{_Str.substr(_Idx)};
}
_NODISCARD bool empty() const noexcept {
return _Mystr.empty();
}
_NODISCARD bool has_root_name() const {
return !root_name().empty();
}
_NODISCARD bool has_root_directory() const {
return !root_directory().empty();
}
_NODISCARD bool has_root_path() const {
return !root_path().empty();
}
_NODISCARD bool has_relative_path() const {
return !relative_path().empty();
}
_NODISCARD bool has_parent_path() const {
return !parent_path().empty();
}
_NODISCARD bool has_filename() const {
return !filename().empty();
}
_NODISCARD bool has_stem() const {
return !stem().empty();
}
_NODISCARD bool has_extension() const {
return !extension().empty();
}
_NODISCARD bool is_absolute() const {
return has_root_name() && has_root_directory();
}
_NODISCARD bool is_relative() const {
return !is_absolute();
}
using iterator = _Path_iterator<path>;
using const_iterator = iterator;
_NODISCARD iterator begin() const {
return iterator(*this, 0);
}
_NODISCARD iterator end() const {
return iterator(*this, _Mystr.size());
}
size_t _Prefix_end() const {
if (2 < _Mystr.size() && _FS_ISSEP(_Mystr[0]) && _FS_ISSEP(_Mystr[1])
&& !_FS_ISSEP(_Mystr[2])) { // network name, pick off \\name
size_t _Idx = 3;
while (_Idx < _Mystr.size() && !_FS_ISSEP(_Mystr[_Idx])) {
++_Idx;
}
return _Idx;
} else { // no network name, pick off drive:
size_t _Idx = _Mystr.find(_FS_COLON, 0);
if (_Idx == _Mystr.npos) {
_Idx = 0;
} else {
++_Idx;
}
return _Idx;
}
}
size_t _Root_end() const {
size_t _Idx = _Prefix_end();
if (_Idx < _Mystr.size() && _FS_ISSEP(_Mystr[_Idx])) {
++_Idx;
}
return _Idx;
}
string_type _Mystr;
};
inline void swap(path& _Left, path& _Right) noexcept {
_Left.swap(_Right);
}
_NODISCARD inline size_t hash_value(const path& _Path) noexcept {
return hash<path::string_type>()(_Path.native());
}
_NODISCARD inline bool operator==(const path& _Left, const path& _Right) noexcept {
return _Left.native() == _Right.native();
}
_NODISCARD inline bool operator!=(const path& _Left, const path& _Right) noexcept {
return !(_Left == _Right);
}
_NODISCARD inline bool operator<(const path& _Left, const path& _Right) noexcept {
return _Left.native() < _Right.native();
}
_NODISCARD inline bool operator<=(const path& _Left, const path& _Right) noexcept {
return !(_Right < _Left);
}
_NODISCARD inline bool operator>(const path& _Left, const path& _Right) noexcept {
return _Right < _Left;
}
_NODISCARD inline bool operator>=(const path& _Left, const path& _Right) noexcept {
return !(_Left < _Right);
}
_NODISCARD inline path operator/(const path& _Left, const path& _Right) { // concatenate paths
path _Ans = _Left;
_Ans /= _Right;
return _Ans;
}
template <class _Elem, class _Traits>
basic_ostream<_Elem, _Traits>& operator<<(basic_ostream<_Elem, _Traits>& _Ostr, const path& _Path) { // insert a path
return _Ostr << _Path.string<_Elem, _Traits, allocator<_Elem>>();
}
template <class _Elem, class _Traits>
basic_istream<_Elem, _Traits>& operator>>(basic_istream<_Elem, _Traits>& _Istr, path& _Path) { // extract a path
basic_string<_Elem, _Traits> _Str;
_Istr >> _Str;
_Path = _Str;
return _Istr;
}
template <class _InIt, enable_if_t<_Is_iterator_v<_InIt>, int> = 0>
_NODISCARD path u8path(_InIt _First, _InIt _Last) { // make path from [_First, _Last) UTF8, given iterators
string _Str(_First, _Last);
path::string_type _Str_out;
return path{_Path_cvt<_Char8_t, _Pchar>::_Cvt(_Str_out, _Str.c_str(), _Str.size())};
}
template <class _InIt, enable_if_t<_Is_iterator_v<_InIt>, int> = 0>
_NODISCARD path u8path(_InIt _First) { // make path from NTBS UTF8, given iterator
string _Str;
for (; *_First != '\0'; ++_First) {
_Str += *_First;
}
path::string_type _Str_out;
return path{_Path_cvt<_Char8_t, _Pchar>::_Cvt(_Str_out, _Str.c_str(), _Str.size())};
}
template <class _Traits, class _Alloc>
_NODISCARD path u8path(const basic_string<char, _Traits, _Alloc>& _Str) { // make path from arbitrary char string UTF8
path::string_type _Str_out;
return path{_Path_cvt<_Char8_t, _Pchar>::_Cvt(_Str_out, _Str.c_str(), _Str.size())};
}
class filesystem_error : public system_error { // base of all filesystem-error exceptions
public:
explicit filesystem_error(
const string& _Message, error_code _Errcode = make_error_code(errc::operation_not_permitted))
: system_error(_Errcode, _Message) {}
filesystem_error(const string& _Message, const path& _Path1, error_code _Errcode)
: system_error(_Errcode, _Message), _Mypval1(_Path1) {}
filesystem_error(const string& _Message, const path& _Path1, const path& _Path2, error_code _Errcode)
: system_error(_Errcode, _Message), _Mypval1(_Path1), _Mypval2(_Path2) {}
__CLR_OR_THIS_CALL ~filesystem_error() noexcept override {}
filesystem_error(filesystem_error&& _Right) noexcept
: system_error(_Right.code(), _Right.what()), _Mypval1(_STD move(_Right._Mypval1)),
_Mypval2(_STD move(_Right._Mypval2)) {}
filesystem_error& operator=(filesystem_error&& _Right) noexcept {
static_cast<system_error&>(*this) = _Right;
_Mypval1 = _STD move(_Right._Mypval1);
_Mypval2 = _STD move(_Right._Mypval2);
return *this;
}
_NODISCARD const path& path1() const noexcept {
return _Mypval1;
}
_NODISCARD const path& path2() const noexcept {
return _Mypval2;
}
filesystem_error(const filesystem_error&) = default;
filesystem_error& operator=(const filesystem_error&) = default;
private:
path _Mypval1;
path _Mypval2;
#if !_HAS_EXCEPTIONS
protected:
__CLR_OR_THIS_CALL void _Doraise() const override { // perform class-specific exception handling
_RAISE(*this);
}
#endif // !_HAS_EXCEPTIONS
};
[[noreturn]] inline void _Throw_filesystem_error(const char* const _Message) {
_THROW(filesystem_error{_Message}); // centralize construction of temporary string
}
class directory_entry { // represents a directory entry
public:
using string_type = _FSPFX path::string_type;
directory_entry() : _Mystat(), _Mysymstat() {}
directory_entry(const directory_entry&) = default;
directory_entry& operator=(const directory_entry&) = default;
directory_entry(directory_entry&&) = default;
directory_entry& operator=(directory_entry&&) = default;
explicit directory_entry(
const _FSPFX path& _Path, file_status _Statarg = file_status{}, file_status _Symstatarg = file_status{})
: _Mypval(_Path), _Mystat(_Statarg), _Mysymstat(_Symstatarg) {}
void assign(
const _FSPFX path& _Path, file_status _Statarg = file_status{}, file_status _Symstatarg = file_status{}) {
_Mypval = _Path;
_Mystat = _Statarg;
_Mysymstat = _Symstatarg;
}
void replace_filename(const _FSPFX path& _Path, file_status _Statarg = file_status{},
file_status _Symstatarg = file_status{}) { // replace filename and assign status
_Mypval = _Mypval.parent_path() / _Path;
_Mystat = _Statarg;
_Mysymstat = _Symstatarg;
}
operator const _FSPFX path&() const noexcept {
return _Mypval;
}
_NODISCARD const _FSPFX path& path() const noexcept {
return _Mypval;
}
_NODISCARD file_status status() const {
error_code _Code;
return status(_Code);
}
_NODISCARD file_status status(error_code& _Code) const noexcept {
_Code.clear();
if (!status_known(_Mystat)) {
if (status_known(_Mysymstat) && !is_symlink(_Mysymstat)) {
_Mystat = _Mysymstat;
} else {
_Mystat = _FSPFX status(_Mypval, _Code);
}
}
return _Mystat;
}
_NODISCARD file_status symlink_status() const {
error_code _Code;
return symlink_status(_Code);
}
_NODISCARD file_status symlink_status(error_code& _Code) const noexcept {
_Code.clear();
if (!status_known(_Mysymstat)) {
_Mysymstat = _FSPFX symlink_status(_Mypval, _Code);
}
return _Mysymstat;
}
_NODISCARD bool operator==(const directory_entry& _Right) const noexcept {
return _Mypval == _Right._Mypval;
}
_NODISCARD bool operator!=(const directory_entry& _Right) const noexcept {
return !(*this == _Right);
}
_NODISCARD bool operator<(const directory_entry& _Right) const noexcept {
return _Mypval < _Right._Mypval;
}
_NODISCARD bool operator>(const directory_entry& _Right) const noexcept {
return _Right < *this;
}
_NODISCARD bool operator<=(const directory_entry& _Right) const noexcept {
return !(_Right < *this);
}
_NODISCARD bool operator>=(const directory_entry& _Right) const noexcept {
return !(*this < _Right);
}
private:
_FSPFX path _Mypval;
mutable file_status _Mystat;
mutable file_status _Mysymstat;
};
template <class _Prefix_directory>
class _Directory_iterator {
public:
using string_type = path::string_type;
using iterator_category = input_iterator_tag;
using value_type = directory_entry;
using difference_type = ptrdiff_t;
using pointer = const value_type*;
using reference = const value_type&;
_Directory_iterator() noexcept : _Mypdir(new void*(nullptr), &_Delptr) {}
explicit _Directory_iterator(const path& _Path) : _Mypdir(new void*(nullptr), &_Delptr), _Mydirpath(_Path) {
typename string_type::value_type _Dest[_MAX_FILESYS_NAME];
int _Errno = 0;
file_type _Ftype;
*_Mypdir = _Open_dir(_Dest, _Path.c_str(), _Errno, _Ftype);
if (*_Mypdir) {
_Form_name(_Dest, _Ftype);
}
}
_Directory_iterator(const path& _Path, error_code& _Code) noexcept
: _Mypdir(new void*(nullptr), &_Delptr), _Mydirpath(_Path) {
typename string_type::value_type _Dest[_MAX_FILESYS_NAME];
int _Errno = 0;
file_type _Ftype;
*_Mypdir = _Open_dir(_Dest, _Path.c_str(), _Errno, _Ftype);
if (*_Mypdir) {
_Form_name(_Dest, _Ftype);
}
_Code = error_code(_Errno, _STD system_category());
}
_Directory_iterator(const _Directory_iterator&) = default;
_Directory_iterator& operator=(const _Directory_iterator&) = default;
_Directory_iterator(_Directory_iterator&&) = default;
_Directory_iterator& operator=(_Directory_iterator&&) = default;
_NODISCARD const value_type& operator*() const {
#if _ITERATOR_DEBUG_LEVEL != 0
_STL_VERIFY(*_Mypdir, "directory_iterator is not dereferenceable");
#endif // _ITERATOR_DEBUG_LEVEL != 0
return _Myentry;
}
_NODISCARD pointer operator->() const {
return pointer_traits<pointer>::pointer_to(**this);
}
_Directory_iterator& operator++() {
#if _ITERATOR_DEBUG_LEVEL != 0
_STL_VERIFY(*_Mypdir, "directory_iterator is not incrementable");
#endif // _ITERATOR_DEBUG_LEVEL != 0
_Get();
return *this;
}
_Directory_iterator& increment(error_code& _Code) noexcept {
_Code.clear();
if (_Mypdir && *_Mypdir) {
_Get();
} else {
_Code = make_error_code(errc::operation_not_permitted);
}
return *this;
}
_Directory_iterator operator++(int) {
_Directory_iterator _Tmp = *this;
++*this;
return _Tmp;
}
bool _Equal(const _Directory_iterator& _Right) const {
if (_Mypdir.get() && _Right._Mypdir.get()) {
return *_Mypdir == *_Right._Mypdir;
}
return !_Mypdir.get() && !_Right._Mypdir.get();
}
private:
static void _Delptr(void** _Ptr) { // close directory and delete pointer
if (_Ptr && *_Ptr) {
_Close_dir(*_Ptr);
}
delete _Ptr;
}
void _Get() { // peek at next input element
if (*_Mypdir) { // read a directory entry
typename string_type::value_type _Dest[_MAX_FILESYS_NAME];
file_type _Ftype;
if (_Read_dir(_Dest, *_Mypdir, _Ftype)[0] == 0) { // end of directory, close it
_Close_dir(*_Mypdir);
*_Mypdir = nullptr; // end of directory
} else {
_Form_name(_Dest, _Ftype);
}
}
}
void _Form_name(typename string_type::value_type* _Filename, file_type _Ftype) {
if constexpr (_Prefix_directory::value) {
// set entry to _Mydirpath/_Filename
_Myentry.assign(_Mydirpath / path{_Filename}, file_status{_Ftype});
} else {
// set entry to _Filename
_Myentry.assign(path{_Filename}, file_status{_Ftype});
}
}
shared_ptr<void*> _Mypdir;
path _Mydirpath;
value_type _Myentry;
};
template <class _Prefix_directory>
_NODISCARD bool operator==(
const _Directory_iterator<_Prefix_directory>& _Left, const _Directory_iterator<_Prefix_directory>& _Right) {
return _Left._Equal(_Right);
}
template <class _Prefix_directory>
_NODISCARD bool operator!=(
const _Directory_iterator<_Prefix_directory>& _Left, const _Directory_iterator<_Prefix_directory>& _Right) {
return !(_Left == _Right);
}
using directory_iterator = _Directory_iterator<true_type>;
_NODISCARD inline const directory_iterator& begin(const directory_iterator& _Iter) noexcept {
return _Iter;
}
_NODISCARD inline directory_iterator end(const directory_iterator&) noexcept {
return {};
}
class recursive_directory_iterator {
public:
using _Myiter = _Directory_iterator<false_type>;
using _Mypair = pair<_Myiter, path>;
using string_type = path::string_type;
using char_type = string_type::value_type;
using iterator_category = input_iterator_tag;
using value_type = directory_entry;
using difference_type = ptrdiff_t;
using pointer = const value_type*;
using reference = const value_type&;
recursive_directory_iterator() noexcept
: _Mylist(1, _Mypair()), _Myentry(), _No_push(false), _Options(directory_options::none) {}
explicit recursive_directory_iterator(const path& _Path, directory_options _Opts = directory_options::none)
: _Mylist(1, _Mypair(_Myiter(_Path), _Path)), _Myentry(), _No_push(false), _Options(_Opts) {
_Get();
}
recursive_directory_iterator(const path& _Path, directory_options _Opts, error_code& _Code) noexcept
: _Mylist(1, _Mypair(_Myiter(_Path), _Path)), _Myentry(), _No_push(false), _Options(_Opts) {
_Code.clear();
_Get();
}
recursive_directory_iterator(const path& _Path, error_code& _Code) noexcept
: _Mylist(1, _Mypair(_Myiter(_Path), _Path)), _Myentry(), _No_push(false), _Options(directory_options::none) {
_Code.clear();
_Get();
}
recursive_directory_iterator(const recursive_directory_iterator&) = default;
recursive_directory_iterator& operator=(const recursive_directory_iterator&) = default;
recursive_directory_iterator(recursive_directory_iterator&&) = default;
recursive_directory_iterator& operator=(recursive_directory_iterator&&) = default;
_NODISCARD directory_options options() const {
return _Options;
}
_NODISCARD int depth() const {
return static_cast<int>(_Mylist.size()) - 1;
}
_NODISCARD bool recursion_pending() const {
return !_No_push;
}
void pop() { // pop a level
if (_Mylist.size() > 1) {
_Mylist.pop_front(); // something to pop, do it
}
}
void disable_recursion_pending() { // disable directory recursion
_No_push = true;
}
_NODISCARD const value_type& operator*() const {
#if _ITERATOR_DEBUG_LEVEL != 0
_STL_VERIFY(_Mylist.front().first != _Myiter(), "recursive_directory_iterator is not dereferenceable");
#endif // _ITERATOR_DEBUG_LEVEL != 0
return _Myentry;
}
_NODISCARD pointer operator->() const {
return pointer_traits<pointer>::pointer_to(**this);
}
recursive_directory_iterator& operator++() {
#if _ITERATOR_DEBUG_LEVEL != 0
_STL_VERIFY(_Mylist.front().first != _Myiter(), "recursive_directory_iterator is not incrementable");
#endif // _ITERATOR_DEBUG_LEVEL != 0
if (_No_push || !is_directory(_Mylist.front().first->status())
|| (_Options != directory_options::follow_directory_symlink
&& is_symlink(_Mylist.front().first->status()))) {
_No_push = false;
++_Mylist.front().first;
} else { // push down a subdirectory
path _Newpath = _Mylist.front().second / _Mylist.front().first->path();
++_Mylist.front().first;
_Mylist.emplace_front(_Myiter(_Newpath), _Newpath);
}
while (1 < _Mylist.size() && _Mylist.front().first == _Myiter()) {
pop();
}
_Get();
return *this;
}
recursive_directory_iterator& increment(error_code& _Code) noexcept {
_Code.clear();
if (_Mylist.front().first == _Myiter()) {
_Code = make_error_code(errc::operation_not_permitted);
} else {
++*this;
}
return *this;
}
recursive_directory_iterator operator++(int) {
recursive_directory_iterator _Tmp = *this;
++*this;
return _Tmp;
}
bool _Equal(const recursive_directory_iterator& _Right) const {
return _Mylist.front().first == _Right._Mylist.front().first;
}
void _Get() { // prime _Myentry for future gets
if (_Mylist.front().first != _Myiter()) { // item present, get it
value_type _Dentry = *_Mylist.front().first;
_Myentry.assign(_Mylist.front().second / _Dentry.path(), _Dentry.status(), _Dentry.symlink_status());
}
}
private:
list<_Mypair> _Mylist;
value_type _Myentry;
bool _No_push;
directory_options _Options;
};
_NODISCARD inline bool operator==(
const recursive_directory_iterator& _Left, const recursive_directory_iterator& _Right) {
return _Left._Equal(_Right);
}
_NODISCARD inline bool operator!=(
const recursive_directory_iterator& _Left, const recursive_directory_iterator& _Right) {
return !(_Left == _Right);
}
_NODISCARD inline const recursive_directory_iterator& begin(const recursive_directory_iterator& _Iter) noexcept {
return _Iter;
}
_NODISCARD inline recursive_directory_iterator end(const recursive_directory_iterator&) noexcept {
return {};
}
inline path _Absolute(const path& _Path, const path& _Base,
error_code& _Code) { // make absolute path from _Path and directory _Base; errors in _Code
_Code.clear();
const bool _Path_has_root_name = _Path.has_root_name();
const bool _Path_has_root_directory = _Path.has_root_directory();
if (_Path_has_root_name && _Path_has_root_directory) {
return _Path; // fine as is
}
path _Current = current_path(_Code);
if (_Code) {
return {};
}
path _Abs_base = _Absolute(_Base, _Current, _Code);
if (_Code) {
return {};
}
if (_Path_has_root_name) { // insert _Base
return _Path.root_name() / _Abs_base.root_directory() / _Abs_base.relative_path() / _Path.relative_path();
} else if (_Path_has_root_directory) {
return _Abs_base.root_name() / _Path; // prepend root name of base
} else {
return _Abs_base / _Path; // prepend absolute name of base
}
}
_NODISCARD inline path absolute(const path& _Path,
const path& _Base = current_path()) { // make absolute path from _Path and directory _Base
error_code _Code;
path _Result = _Absolute(_Path, _Base, _Code);
if (_Code) {
_Throw_filesystem_error("absolute(p1, p2): current_path() couldn't get current working directory");
}
return _Result;
}
inline void _Canonicalize_string_only(
path& _Canon_path, const path& _Abs_path) { // transform absolute path _Abs_path, removing .s, and ..s,
// using string manipulations (rather than platform support)
vector<path> _Components;
path::const_iterator _Abs_path_next = _Abs_path.begin();
const path::const_iterator _Abs_path_end = _Abs_path.end();
// This is safe because we have already made the path absolute
_Canon_path /= *_Abs_path_next; // root_name
++_Abs_path_next;
_Canon_path /= *_Abs_path_next; // root_directory
++_Abs_path_next;
for (; _Abs_path_next != _Abs_path_end; ++_Abs_path_next) {
const auto _Cstr = _Abs_path_next->c_str();
if (_Cstr[0] == _FS_PERIOD) {
if (_Cstr[1] == static_cast<path::value_type>(0)) {
continue; // consume "."
} else if (_Cstr[1] == _FS_PERIOD && _Cstr[2] == static_cast<path::value_type>(0)) {
// If no parent is found to remove with .., ignore ..
// (that is, C:\..\..\..\Meow canonicalizes to C:\Meow)
if (!_Components.empty()) {
_Components.pop_back();
}
continue; // consume ".."
}
}
_Components.push_back(*_Abs_path_next);
}
for (const auto& _Component : _Components) {
_Canon_path /= _Component;
}
}
_NODISCARD inline path canonical(const path& _Path,
const path& _Base = current_path()) { // make absolute path from _Path, _Base with no ., .., or symlink
error_code _Code;
path _Ans = canonical(_Path, _Base, _Code);
if (_Code) {
_Throw_filesystem_error("canonical(p1, p2): invalid arguments");
}
return _Ans;
}
_NODISCARD inline path canonical(const path& _Path,
error_code& _Code) { // make absolute path from _Path with no ., .., or symlink
path _Current = current_path(_Code);
if (_Code) {
return {};
}
return canonical(_Path, _Current, _Code);
}
_NODISCARD inline path canonical(const path& _Path, const path& _Base,
error_code& _Code) { // make absolute path from _Path, _Base with no ".", "..", symlink
_Code.clear();
path _Canon_path; // NRVO this variable
path _Abs_path = _Absolute(_Path, _Base, _Code);
if (_Code) {
return _Canon_path;
}
if (_Abs_path.native().size() >= _MAX_FILESYS_NAME) {
_Code = make_error_code(errc::filename_too_long);
return _Canon_path;
}
_Canonicalize_string_only(_Canon_path, _Abs_path);
return _Canon_path;
}
inline bool _Copy_options_indicate_recursive_copy(
copy_options _Opts) { // Checks a copy_options for whether copy should call itself recursively
if (_Opts == copy_options::none) {
// This supports "copying a directory" as copying the directory and
// files therein but not subdirectories.
return true;
}
if ((_Opts & copy_options::recursive) != copy_options::none) {
return true;
}
return false;
}
inline void copy(const path& _Oldpval, const path& _Newpval) { // copy _Oldpval to _Newpval, general
error_code _Code;
copy(_Oldpval, _Newpval, copy_options::none, _Code);
if (_Code) {
_Throw_filesystem_error("copy(p1, p2): invalid arguments");
}
}
inline void copy(const path& _Oldpval, const path& _Newpval,
error_code& _Code) noexcept { // copy _Oldpval to _Newpval, general
copy(_Oldpval, _Newpval, copy_options::none, _Code);
}
inline void copy(const path& _Oldpval, const path& _Newpval,
copy_options _Opts) { // copy _Oldpval to _Newpval, general
error_code _Code;
copy(_Oldpval, _Newpval, _Opts, _Code);
if (_Code) {
_Throw_filesystem_error("copy(p1, p2, options): invalid arguments");
}
}
inline void copy(const path& _Oldpval, const path& _Newpval, copy_options _Opts,
error_code& _Code) noexcept { // copy _Oldpval to _Newpval, general
file_status _Oldstat;
file_status _Newstat;
error_code _Code2;
_Code.clear();
if ((_Opts & copy_options::create_symlinks) != copy_options::none
|| (_Opts & copy_options::skip_symlinks) != copy_options::none) { // get symlink status
_Oldstat = symlink_status(_Oldpval);
_Newstat = symlink_status(_Newpval);
} else { // get file status
_Oldstat = status(_Oldpval);
_Newstat = status(_Newpval);
}
if (!exists(_Oldstat) || equivalent(_Oldpval, _Newpval, _Code2) || is_other(_Oldstat) || is_other(_Newstat)
|| (is_directory(_Oldstat) && is_regular_file(_Newstat))) {
_Code = make_error_code(errc::operation_not_permitted);
} else if (is_symlink(_Oldstat)) {
if ((_Opts & copy_options::skip_symlinks) == copy_options::none) {
if (exists(_Newstat) || (_Opts & copy_options::copy_symlinks) == copy_options::none) {
_Code = make_error_code(errc::operation_not_permitted);
} else {
copy_symlink(_Oldpval, _Newpval, _Code);
}
}
} else if (is_regular_file(_Oldstat)) {
if ((_Opts & copy_options::directories_only) == copy_options::none) {
if ((_Opts & copy_options::create_symlinks) != copy_options::none) {
create_symlink(_Oldpval, _Newpval, _Code);
} else if ((_Opts & copy_options::create_hard_links) != copy_options::none) {
create_hard_link(_Oldpval, _Newpval, _Code);
} else if (is_directory(_Newstat)) {
copy_file(_Oldpval, _Newpval / _Oldpval.filename(), _Opts, _Code);
} else {
copy_file(_Oldpval, _Newpval, _Opts, _Code);
}
}
} else if (is_directory(_Oldstat) && _Copy_options_indicate_recursive_copy(_Opts)) { // copy directory recursively
if (!exists(_Newpval) && !create_directory(_Newpval, _Code) && !_Code) {
_Code = make_error_code(errc::operation_not_permitted);
}
for (directory_iterator _Next(_Oldpval), _End; !_Code && _Next != _End; ++_Next) {
copy(_Next->path(), _Newpval / _Next->path().filename(),
_Opts | copy_options::_Unspecified_recursion_prevention_tag, _Code);
}
}
}
inline bool copy_file(const path& _Oldpval, const path& _Newpval,
copy_options _Opt /* = copy_options::none */) { // copy _Oldpval to _Newpval
error_code _Code;
const bool _Ans = copy_file(_Oldpval, _Newpval, _Opt, _Code);
if (_Code) {
_Throw_filesystem_error("copy_file(p1, p2, options): invalid arguments");
}
return _Ans;
}
inline bool copy_file(const path& _Oldpval, const path& _Newpval,
error_code& _Code) noexcept { // copy _Oldpval to _Newpval
return copy_file(_Oldpval, _Newpval, copy_options::none, _Code);
}
inline bool copy_file(const path& _Oldpval, const path& _Newpval, copy_options _Opt,
error_code& _Code) noexcept { // copy _Oldpval to _Newpval
_Opt &= (copy_options::skip_existing | copy_options::overwrite_existing | copy_options::update_existing);
const bool _Exists = exists(_Newpval);
file_time_type _Oldtime;
file_time_type _Newtime;
_Code.clear();
if (_Exists && (_Opt == copy_options::none || equivalent(_Oldpval, _Newpval, _Code))) {
_Code = make_error_code(errc::file_exists);
return false;
}
if (_Code) { // equivalent() failed, report error
return false;
}
if (!_Exists || (_Opt & copy_options::overwrite_existing) != copy_options::none
|| ((_Opt & copy_options::update_existing) != copy_options::none
&& ((void) (_Oldtime = last_write_time(_Oldpval, _Code)), !_Code)
&& ((void) (_Newtime = last_write_time(_Newpval, _Code)), !_Code)
&& _Newtime < _Oldtime)) { // ok to overwrite, if necessary
if (_Copy_file(_Oldpval.c_str(), _Newpval.c_str()) == 0) {
return true;
}
_Code = make_error_code(errc::operation_not_permitted);
}
return false;
}
inline void copy_symlink(const path& _Oldpval, const path& _Newpval) { // copy symlink, file or directory
error_code _Code;
copy_symlink(_Oldpval, _Newpval, _Code);
if (_Code) {
_Throw_filesystem_error("copy_symlink(p1, p2): invalid arguments");
}
}
inline void copy_symlink(const path& _Oldpval, const path& _Newpval,
error_code& _Code) noexcept { // copy symlink, file or directory
if (is_directory(_Oldpval)) {
create_directory_symlink(_Oldpval, _Newpval, _Code);
} else {
create_symlink(_Oldpval, _Newpval, _Code);
}
}
inline bool create_directories(const path& _Path) { // create directories chain
error_code _Code;
const bool _Ans = create_directories(_Path, _Code);
if (_Code) {
_Throw_filesystem_error("create_directories(p): invalid argument");
}
return _Ans;
}
inline bool create_directories(const path& _Path,
error_code& _Code) noexcept { // create directory chain
_Code.clear();
if (_Path.empty()) {
return false;
} else if (!exists(_Path)) { // recursively create parent directories, then current
create_directories(_Path.parent_path(), _Code);
if (_Code) {
return false; // report error
}
create_directory(_Path, _Code);
if (_Code) {
return false; // report error
}
return true;
} else if (is_directory(_Path)) {
return false; // directory already there
} else { // report bad argument
_Code = make_error_code(errc::operation_not_permitted);
return false;
}
}
inline bool create_directory(const path& _Path) { // create a directory
error_code _Code;
const bool _Ans = create_directory(_Path, _Code);
if (_Code) {
_Throw_filesystem_error("create_directory(p): invalid argument");
}
return _Ans;
}
inline bool create_directory(const path& _Path,
error_code& _Code) noexcept { // create a directory
const int _Ans = _Make_dir(_Path.c_str(), nullptr);
_Code.clear();
if (_Ans < 0) {
_Code = make_error_code(errc::operation_not_permitted);
}
return 0 < _Ans;
}
inline bool create_directory(const path& _Path, const path& _Attrs) { // create a directory, copying attributes
error_code _Code;
const bool _Ans = create_directory(_Path, _Attrs, _Code);
if (_Code) {
_Throw_filesystem_error("create_directory(p1, p2): invalid arguments");
}
return _Ans;
}
inline bool create_directory(const path& _Path, const path& _Attrs,
error_code& _Code) noexcept { // create a directory, copying attributes
const int _Ans = _Make_dir(_Path.c_str(), _Attrs.c_str());
_Code.clear();
if (_Ans < 0) {
_Code = make_error_code(errc::operation_not_permitted);
}
return 0 < _Ans;
}
inline void create_directory_symlink(const path& _Oldpval,
const path& _Newpval) { // symlink directory _Newpval to _Oldpval
error_code _Code;
create_directory_symlink(_Oldpval, _Newpval, _Code);
if (_Code) {
_Throw_filesystem_error("create_directory_symlink(p1, p2): invalid arguments");
}
}
inline void create_directory_symlink(const path& _Oldpval, const path& _Newpval,
error_code& _Code) noexcept { // symlink directory_Newpval to _Oldpval (NB: SAME AS FILE)
const int _Ans = _Symlink(_Oldpval.c_str(), _Newpval.c_str());
_Code.clear();
if (_Ans != 0) {
_Code = error_code(_Ans, _STD system_category());
}
}
inline void create_hard_link(const path& _Oldpval, const path& _Newpval) { // hard link _Newpval to _Oldpval
error_code _Code;
create_hard_link(_Oldpval, _Newpval, _Code);
if (_Code) {
_Throw_filesystem_error("create_hard_link(p1, p2): invalid arguments");
}
}
inline void create_hard_link(const path& _Oldpval, const path& _Newpval,
error_code& _Code) noexcept { // hard link _Newpval to _Oldpval
const int _Ans = _Link(_Oldpval.c_str(), _Newpval.c_str());
_Code.clear();
if (_Ans != 0) {
_Code = error_code(_Ans, _STD system_category());
}
}
inline void create_symlink(const path& _Oldpval, const path& _Newpval) { // symlink _Newpval to _Oldpval
error_code _Code;
create_symlink(_Oldpval, _Newpval, _Code);
if (_Code) {
_Throw_filesystem_error("create_symlink(p1, p2): invalid arguments");
}
}
inline void create_symlink(const path& _Oldpval, const path& _Newpval,
error_code& _Code) noexcept { // symlink _Newpval to _Oldpval
const int _Ans = _Symlink(_Oldpval.c_str(), _Newpval.c_str());
_Code.clear();
if (_Ans != 0) {
_Code = error_code(_Ans, _STD system_category());
}
}
_NODISCARD inline path current_path() {
error_code _Code;
path _Ans = current_path(_Code);
if (_Code) {
_Throw_filesystem_error("current_path(): can't get current working directory");
}
return _Ans;
}
_NODISCARD inline path current_path(error_code& _Code) {
_Code.clear();
_Pchar _Dest[_MAX_FILESYS_NAME];
if (!_Current_get(_Dest)) { // report error
_Code = make_error_code(errc::operation_not_permitted);
return {};
}
return path{_Dest};
}
inline void current_path(const path& _Path) { // set current working directory
if (!_Current_set(_Path.c_str())) {
_Throw_filesystem_error("current_path(p): invalid argument");
}
}
inline void current_path(const path& _Path,
error_code& _Code) noexcept { // set current working directory
_Code.clear();
if (!_Current_set(_Path.c_str())) {
_Code = make_error_code(errc::no_such_file_or_directory);
}
}
_NODISCARD inline bool equivalent(const path& _Path1, const path& _Path2) {
error_code _Code;
const int _Ans = equivalent(_Path1, _Path2, _Code);
if (_Code) {
_Throw_filesystem_error("equivalent(p1, p2): invalid arguments");
}
return 0 < _Ans;
}
_NODISCARD inline bool equivalent(const path& _Path1, const path& _Path2, error_code& _Code) noexcept {
const int _Ans = _Equivalent(_Path1.c_str(), _Path2.c_str());
_Code.clear();
if (_Ans < 0) {
_Code = make_error_code(errc::operation_not_permitted);
}
return 0 < _Ans;
}
_NODISCARD inline bool exists(file_status _Stat) noexcept {
return status_known(_Stat) && _Stat.type() != file_type::not_found;
}
_NODISCARD inline bool exists(const path& _Path) {
return exists(status(_Path));
}
_NODISCARD inline bool exists(const path& _Path, error_code& _Code) noexcept {
_Code.clear();
return exists(status(_Path));
}
_NODISCARD inline uintmax_t file_size(const path& _Path) {
error_code _Code;
const uintmax_t _Ans = file_size(_Path, _Code);
if (_Code) {
_Throw_filesystem_error("file_size(p): invalid argument");
}
return _Ans;
}
_NODISCARD inline uintmax_t file_size(const path& _Path, error_code& _Code) noexcept {
uintmax_t _Ans = static_cast<uintmax_t>(-1);
const file_status _Stat = status(_Path);
_Code.clear();
if (exists(_Stat) && is_regular_file(_Stat)) {
_Ans = _File_size(_Path.c_str());
}
if (_Ans == static_cast<uintmax_t>(-1)) {
_Code = make_error_code(errc::operation_not_permitted);
}
return _Ans;
}
_NODISCARD inline uintmax_t hard_link_count(const path& _Path) {
error_code _Code;
const uintmax_t _Ans = hard_link_count(_Path, _Code);
if (_Code) {
_Throw_filesystem_error("hard_link_count(p): invalid argument");
}
return _Ans;
}
_NODISCARD inline uintmax_t hard_link_count(const path& _Path, error_code& _Code) noexcept {
_Code.clear();
const uintmax_t _Ans = _Hard_links(_Path.c_str());
if (_Ans == static_cast<uintmax_t>(-1)) {
_Code = make_error_code(errc::operation_not_permitted);
}
return _Ans;
}
_NODISCARD inline bool is_block_file(file_status _Stat) noexcept {
return _Stat.type() == file_type::block;
}
_NODISCARD inline bool is_block_file(const path& _Path) {
return is_block_file(status(_Path));
}
_NODISCARD inline bool is_block_file(const path& _Path, error_code& _Code) noexcept {
return is_block_file(status(_Path, _Code));
}
_NODISCARD inline bool is_character_file(file_status _Stat) noexcept {
return _Stat.type() == file_type::character;
}
_NODISCARD inline bool is_character_file(const path& _Path) {
return is_character_file(status(_Path));
}
_NODISCARD inline bool is_character_file(const path& _Path, error_code& _Code) noexcept {
return is_character_file(status(_Path, _Code));
}
_NODISCARD inline bool is_directory(file_status _Stat) noexcept {
return _Stat.type() == file_type::directory;
}
_NODISCARD inline bool is_directory(const path& _Path) {
return is_directory(status(_Path));
}
_NODISCARD inline bool is_directory(const path& _Path, error_code& _Code) noexcept {
return is_directory(status(_Path, _Code));
}
_NODISCARD inline bool is_empty(const path& _Path) {
error_code _Code;
const bool _Ans = _FSPFX is_empty(_Path, _Code);
if (_Code) {
_Throw_filesystem_error("is_empty(p): invalid argument");
}
return _Ans;
}
_NODISCARD inline bool is_empty(const path& _Path, error_code& _Code) noexcept {
const file_status _Stat = status(_Path);
_Code.clear();
if (is_directory(_Stat)) {
return directory_iterator(_Path) == directory_iterator();
} else {
return file_size(_Path, _Code) == 0;
}
}
_NODISCARD inline bool is_fifo(file_status _Stat) noexcept {
return _Stat.type() == file_type::fifo;
}
_NODISCARD inline bool is_fifo(const path& _Path) {
return is_fifo(status(_Path));
}
_NODISCARD inline bool is_fifo(const path& _Path, error_code& _Code) noexcept {
return is_fifo(status(_Path, _Code));
}
_NODISCARD inline bool is_other(file_status _Stat) noexcept {
return exists(_Stat) && !is_regular_file(_Stat) && !is_directory(_Stat) && !is_symlink(_Stat);
}
_NODISCARD inline bool is_other(const path& _Path) {
return is_other(status(_Path));
}
_NODISCARD inline bool is_other(const path& _Path, error_code& _Code) noexcept {
return is_other(status(_Path, _Code));
}
_NODISCARD inline bool is_regular_file(file_status _Stat) noexcept {
return _Stat.type() == file_type::regular;
}
_NODISCARD inline bool is_regular_file(const path& _Path) {
return is_regular_file(status(_Path));
}
_NODISCARD inline bool is_regular_file(const path& _Path, error_code& _Code) noexcept {
return is_regular_file(status(_Path, _Code));
}
_NODISCARD inline bool is_socket(file_status _Stat) noexcept {
return _Stat.type() == file_type::socket;
}
_NODISCARD inline bool is_socket(const path& _Path) {
return is_socket(status(_Path));
}
_NODISCARD inline bool is_socket(const path& _Path, error_code& _Code) noexcept {
return is_socket(status(_Path, _Code));
}
_NODISCARD inline bool is_symlink(file_status _Stat) noexcept {
return _Stat.type() == file_type::symlink;
}
_NODISCARD inline bool is_symlink(const path& _Path) {
return is_symlink(status(_Path));
}
_NODISCARD inline bool is_symlink(const path& _Path, error_code& _Code) noexcept {
return is_symlink(status(_Path, _Code));
}
_NODISCARD inline file_time_type last_write_time(const path& _Path) {
error_code _Code;
file_time_type _Ans = last_write_time(_Path, _Code);
if (_Code) {
_Throw_filesystem_error("last_write_time(p): invalid argument");
}
return _Ans;
}
_NODISCARD inline file_time_type last_write_time(const path& _Path, error_code& _Code) noexcept {
const int64_t _Ticks = _Last_write_time(_Path.c_str());
_Code.clear();
if (_Ticks == -1) { // report error
_Code = make_error_code(errc::operation_not_permitted);
return (file_time_type::min)();
}
return file_time_type(chrono::system_clock::duration(_Ticks));
}
inline void last_write_time(const path& _Path, file_time_type _Newtime) { // set last write time
error_code _Code;
last_write_time(_Path, _Newtime, _Code);
if (_Code) {
_Throw_filesystem_error("last_write_time(p, new_time): invalid arguments");
}
}
inline void last_write_time(const path& _Path, file_time_type _Newtime,
error_code& _Code) noexcept { // set last write time
_Code.clear();
if (_Set_last_write_time(_Path.c_str(), _Newtime.time_since_epoch().count()) == 0) {
_Code = make_error_code(errc::operation_not_permitted);
}
}
inline void permissions(const path& _Path, perms _Mask) { // set access permissions
error_code _Code;
permissions(_Path, _Mask, _Code);
if (_Code) {
_Throw_filesystem_error("permissions(p, prms): can't set permissions");
}
}
inline void permissions(const path& _Path, perms _Mask,
error_code& _Code) { // set access permissions
const perms _Todo = _Mask;
_Mask = _Mask & perms::mask;
bool _Ok = true;
_Code.clear();
if ((_Todo & perms::add_perms) == perms::none) {
if ((_Todo & perms::remove_perms) != perms::none) {
_Mask = status(_Path).permissions() & ~_Mask;
}
} else {
if ((_Todo & perms::remove_perms) == perms::none) {
_Mask = _Mask | status(_Path).permissions();
} else {
_Ok = false;
}
}
if (!_Ok || _Chmod(_Path.c_str(), _Mask) != 0) {
_Code = make_error_code(errc::operation_not_permitted);
}
}
_NODISCARD inline path read_symlink(const path& _Path) { // read symbolic link
error_code _Code;
path _Sympath = read_symlink(_Path, _Code);
if (_Code) {
_Throw_filesystem_error("read_symlink(p): can't read symbolic link");
}
return _Sympath;
}
_NODISCARD inline path read_symlink(const path& _Path,
error_code& _Code) { // read symbolic link
_Code.clear();
if (!is_symlink(_Path)) { // report error
_Code = make_error_code(errc::no_such_file_or_directory);
return {};
}
_Pchar _Dest[_MAX_FILESYS_NAME];
return path{_Symlink_get(_Dest, _Path.c_str())};
}
inline bool remove(const path& _Path) { // remove a file
error_code _Code;
const bool _Ans = remove(_Path, _Code);
if (_Code) {
_Throw_filesystem_error("remove(p): invalid argument");
}
return _Ans;
}
inline bool remove(const path& _Path,
error_code& _Code) noexcept { // remove a file
_Code.clear();
if (!exists(symlink_status(_Path))) {
return false;
} else if (is_directory(_Path, _Code)) {
if (_Remove_dir(_Path.c_str())) {
return true;
} else { // couldn't remove emptied directory, report it
_Code = make_error_code(errc::operation_not_permitted);
return false;
}
} else { // file exists, try to remove it
const bool _Ans = _Unlink(_Path.c_str()) == 0;
if (!_Ans) {
_Code = make_error_code(errc::operation_not_permitted);
}
return _Ans;
}
}
inline bool _Remove_all(const path& _Path, uintmax_t& _Ans,
error_code& _Code) noexcept { // recursively remove a file or directory, count removed files
_Code.clear();
if (is_directory(_Path)) { // empty and remove a directory
using _Myit = _Directory_iterator<false_type>;
_Myit _Last;
for (;;) { // remove a directory entry
_Myit _First(_Path);
if (_First == _Last) {
break;
}
if (!_Remove_all(_Path / _First->path(), _Ans, _Code)) {
return false;
}
}
if (_Remove_dir(_Path.c_str())) {
return true;
} else { // couldn't remove emptied directory, report it
_Code = make_error_code(errc::operation_not_permitted);
return false;
}
} else if (!remove(_Path, _Code)) {
return false;
} else { // file remove succeeded, count it
++_Ans;
return true;
}
}
inline uintmax_t remove_all(const path& _Path) { // recursively remove a directory
error_code _Code;
const uintmax_t _Ans = remove_all(_Path, _Code);
if (_Code) {
_Throw_filesystem_error("remove_all(p): invalid argument");
}
return _Ans;
}
inline uintmax_t remove_all(const path& _Path,
error_code& _Code) noexcept { // recursively remove a directory
uintmax_t _Ans = 0;
_Remove_all(_Path, _Ans, _Code);
if (_Code) {
return static_cast<uintmax_t>(-1);
}
return _Ans;
}
inline void rename(const path& _Oldpval, const path& _Newpval) { // rename _Oldpval as _Newpval
error_code _Code;
rename(_Oldpval, _Newpval, _Code);
if (_Code) {
_Throw_filesystem_error("rename(p1, p2): invalid arguments");
}
}
inline void rename(const path& _Oldpval, const path& _Newpval,
error_code& _Code) noexcept { // rename _Oldpval as _Newpval
_Code.clear();
if (!exists(_Oldpval)) { // fail immediately without modifying the filesystem
_Code = make_error_code(errc::operation_not_permitted);
return;
}
if (exists(_Newpval)) { // both exist; there can be only one
if (equivalent(_Oldpval, _Newpval, _Code) || _Code) {
return; // successful no-op, or report equivalent() failure
}
if (!remove(_Newpval, _Code)) {
return; // report remove() failure
}
}
if (_Rename(_Oldpval.c_str(), _Newpval.c_str()) != 0) {
_Code = make_error_code(errc::operation_not_permitted);
}
}
inline void resize_file(const path& _Path, uintmax_t _Newsize) { // change file size
error_code _Code;
resize_file(_Path, _Newsize, _Code);
if (_Code) {
_Throw_filesystem_error("resize_file(p, n): invalid arguments");
}
}
inline void resize_file(const path& _Path, uintmax_t _Newsize,
error_code& _Code) noexcept { // change file size
const int _Errno = _Resize(_Path.c_str(), _Newsize);
_Code.clear();
if (_Errno != 0) {
_Code = error_code(_Errno, _STD system_category());
}
}
_NODISCARD inline space_info space(const path& _Path) {
return _Statvfs(_Path.c_str());
}
_NODISCARD inline space_info space(const path& _Path, error_code& _Code) noexcept {
_Code.clear();
return _Statvfs(_Path.c_str());
}
_NODISCARD inline file_status status(const path& _Path) {
error_code _Code;
return status(_Path, _Code);
}
_NODISCARD inline file_status status(const path& _Path, error_code& _Code) noexcept {
_Code.clear();
perms _Mode;
const file_type _Ftype = _Stat(_Path.c_str(), &_Mode);
return file_status{_Ftype, _Mode};
}
_NODISCARD inline bool status_known(file_status _Stat) noexcept {
return _Stat.type() != file_type::unknown;
}
_NODISCARD inline file_status symlink_status(const path& _Path) {
error_code _Code;
return symlink_status(_Path, _Code);
}
_NODISCARD inline file_status symlink_status(const path& _Path, error_code& _Code) noexcept {
perms _Mode;
const file_type _Ftype = _Lstat(_Path.c_str(), &_Mode);
_Code.clear();
return file_status{_Ftype, _Mode};
}
_NODISCARD inline path system_complete(const path& _Path) {
if (_Path.is_absolute()) {
return _Path;
}
path _Curpath = current_path();
if (!_Path.has_root_name() || _Path.root_name() == _Curpath.root_name()) {
return absolute(_Path);
}
current_path(_Path.root_name()); // switch to new device
path _Altpath = current_path(); // get its full current path
current_path(_Curpath); // revert to original current path
return _Altpath / _Path.relative_path();
}
_NODISCARD inline path system_complete(const path& _Path, error_code& _Code) {
_Code.clear();
path _Ans;
_TRY_BEGIN
_Ans = system_complete(_Path);
_CATCH_ALL
_Code = make_error_code(errc::operation_not_permitted);
return {};
_CATCH_END
return _Ans;
}
_NODISCARD inline path temp_directory_path() {
error_code _Code;
path _Ans = temp_directory_path(_Code);
if (_Code) {
_Throw_filesystem_error("temp_directory_path(): can't find temp directory");
}
return _Ans;
}
_NODISCARD inline path temp_directory_path(error_code& _Code) {
_Pchar _Dest[_MAX_FILESYS_NAME];
_Temp_get(_Dest);
path _Ans(_Dest);
_Code.clear();
if (!exists(_Ans) || !is_directory(_Ans)) { // report error
_Code = make_error_code(errc::no_such_file_or_directory);
return {};
}
return _Ans;
}
_FS_END
#pragma pop_macro("new")
_STL_RESTORE_CLANG_WARNINGS
#pragma warning(pop)
#pragma pack(pop)
#endif // _STL_COMPILER_PREPROCESSOR
#endif // _EXPERIMENTAL_FILESYSTEM_