diff --git a/README.md b/README.md index 432fd835a..3bb443c8c 100644 --- a/README.md +++ b/README.md @@ -9,38 +9,38 @@ Other versions of Boost are built only for arm architecture, they are using gcc To compile Boost for Android you may use one of the following NDKs: -| NDK / boost | 1.45 | 1.48 | 1.49 | 1.53 | 1.65 | 1.66 | 1.67 | 1.68 | 1.69 | 1.70 | 1.71 | 1.73 | 1.74 | 1.76 | 1.77 | 1.78 | 1.79 | 1.80 | 1.82 | -| ----------- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | -| r4 customized by [Dmitry Moskalchuk aka CrystaX](http://www.crystax.net/android/ndk.php). | x | | | | | | | | | | | | | | | | | | | -| r5 from the [official android repository](http://developer.android.com). | x | | | | | | | | | | | | | | | | | | | -| r5 customized by [CrystaX](http://www.crystax.net/android/ndk.php). | x | | | | | | | | | | | | | | | | | | | -| r7 customized by [CrystaX](http://www.crystax.net/android/ndk.php). | x | x | x | | | | | | | | | | | | | | | | | -| r8 from the [official android repository](http://developer.android.com). | x | x | x | | | | | | | | | | | | | | | | | -| r8b from the [official android repository](http://developer.android.com). | | x | x | | | | | | | | | | | | | | | | | -| r8c from the [official android repository](http://developer.android.com). | | | x | | | | | | | | | | | | | | | | | -| r8d from the [official android repository](http://developer.android.com). | | | x | x | | | | | | | | | | | | | | | | -| r8e from the [official android repository](http://developer.android.com). | | | x | x | | | | | | | | | | | | | | | | -| r10 from the [official android repository](http://developer.android.com). | | | x | x | | | | | | | | | | | | | | | | -| r16 from the [official android repository](http://developer.android.com). | | | | | x | x | x | x | | x | | | | | | | | | | -| r17b from the [official android repository](http://developer.android.com). | | | | | | | x | x | | x | | | | | | | | | | -| r18 from the [official android repository](http://developer.android.com). | | | | | | | | x | | | | | | | | | | | | -| r18b from the [official android repository](http://developer.android.com). | | | | | | | | x | x | x | | | | | | | | | | -| r19 from the [official android repository](http://developer.android.com). | | | | | | | | | x | x | x | x | x | | | | | | | -| r19b from the [official android repository](http://developer.android.com). | | | | | | | | | x | x | x | x | x | | | | | | | -| r19c from the [official android repository](http://developer.android.com). | | | | | | | | | x | x | x | x | x | | | | | | | -| r20 from the [official android repository](http://developer.android.com). | | | | | | | | | x | x | x | x | x | | | | | | | -| r20b from the [official android repository](http://developer.android.com). | | | | | | | | | x | x | x | x | x | | | | | | | -| r21 from the [official android repository](http://developer.android.com). | | | | | | | | | x | x | x | x | x | | | | | | | -| r21b from the [official android repository](http://developer.android.com). | | | | | | | | | x | x | x | x | x | | | | | | | -| r21c from the [official android repository](http://developer.android.com). | | | | | | | | | x | x | x | x | x | | | | | | | -| r21d from the [official android repository](http://developer.android.com). | | | | | | | | | x | x | x | x | x | | | | | | | -| r21e from the [official android repository](http://developer.android.com). | | | | | | | | | x | x | x | x | x | | | | | | | -| r23 from the [official android repository](http://developer.android.com). | | | | | | | | | | | | | x | x | x | x | x | x | x | -| r23b from the [official android repository](http://developer.android.com). | | | | | | | | | | | | | x | x | x | x | x | x | x | -| r25 from the [official android repository](http://developer.android.com). | | | | | | | | | | | | | x | x | x | x | x | x | x | -| r25b from the [official android repository](http://developer.android.com). | | | | | | | | | | | | | x | x | x | x | x | x | x | -| r25c from the [official android repository](http://developer.android.com). | | | | | | | | | | | | | x | x | x | x | x | x | x | -| r26 from the [official android repository](http://developer.android.com). | | | | | | | | | | | | | x | x | x | x | x | x | x | +| NDK / boost | 1.45 | 1.48 | 1.49 | 1.53 | 1.65 | 1.66 | 1.67 | 1.68 | 1.69 | 1.70 | 1.71 | 1.73 | 1.74 | 1.76 | 1.77 | 1.78 | 1.79 | 1.80 | 1.82 | 1.83 | +| ----------- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | +| r4 customized by [Dmitry Moskalchuk aka CrystaX](http://www.crystax.net/android/ndk.php). | x | | | | | | | | | | | | | | | | | | | | +| r5 from the [official android repository](http://developer.android.com). | x | | | | | | | | | | | | | | | | | | | | +| r5 customized by [CrystaX](http://www.crystax.net/android/ndk.php). | x | | | | | | | | | | | | | | | | | | | | +| r7 customized by [CrystaX](http://www.crystax.net/android/ndk.php). | x | x | x | | | | | | | | | | | | | | | | | | +| r8 from the [official android repository](http://developer.android.com). | x | x | x | | | | | | | | | | | | | | | | | | +| r8b from the [official android repository](http://developer.android.com). | | x | x | | | | | | | | | | | | | | | | | | +| r8c from the [official android repository](http://developer.android.com). | | | x | | | | | | | | | | | | | | | | | | +| r8d from the [official android repository](http://developer.android.com). | | | x | x | | | | | | | | | | | | | | | | | +| r8e from the [official android repository](http://developer.android.com). | | | x | x | | | | | | | | | | | | | | | | | +| r10 from the [official android repository](http://developer.android.com). | | | x | x | | | | | | | | | | | | | | | | | +| r16 from the [official android repository](http://developer.android.com). | | | | | x | x | x | x | | x | | | | | | | | | | | +| r17b from the [official android repository](http://developer.android.com). | | | | | | | x | x | | x | | | | | | | | | | | +| r18 from the [official android repository](http://developer.android.com). | | | | | | | | x | | | | | | | | | | | | | +| r18b from the [official android repository](http://developer.android.com). | | | | | | | | x | x | x | | | | | | | | | | | +| r19 from the [official android repository](http://developer.android.com). | | | | | | | | | x | x | x | x | x | | | | | | | | +| r19b from the [official android repository](http://developer.android.com). | | | | | | | | | x | x | x | x | x | | | | | | | | +| r19c from the [official android repository](http://developer.android.com). | | | | | | | | | x | x | x | x | x | | | | | | | | +| r20 from the [official android repository](http://developer.android.com). | | | | | | | | | x | x | x | x | x | | | | | | | | +| r20b from the [official android repository](http://developer.android.com). | | | | | | | | | x | x | x | x | x | | | | | | | | +| r21 from the [official android repository](http://developer.android.com). | | | | | | | | | x | x | x | x | x | | | | | | | | +| r21b from the [official android repository](http://developer.android.com). | | | | | | | | | x | x | x | x | x | | | | | | | | +| r21c from the [official android repository](http://developer.android.com). | | | | | | | | | x | x | x | x | x | | | | | | | | +| r21d from the [official android repository](http://developer.android.com). | | | | | | | | | x | x | x | x | x | | | | | | | | +| r21e from the [official android repository](http://developer.android.com). | | | | | | | | | x | x | x | x | x | | | | | | | | +| r23 from the [official android repository](http://developer.android.com). | | | | | | | | | | | | | x | x | x | x | x | x | x | x | +| r23b from the [official android repository](http://developer.android.com). | | | | | | | | | | | | | x | x | x | x | x | x | x | x | +| r25 from the [official android repository](http://developer.android.com). | | | | | | | | | | | | | x | x | x | x | x | x | x | x | +| r25b from the [official android repository](http://developer.android.com). | | | | | | | | | | | | | x | x | x | x | x | x | x | x | +| r25c from the [official android repository](http://developer.android.com). | | | | | | | | | | | | | x | x | x | x | x | x | x | x | +| r26 from the [official android repository](http://developer.android.com). | | | | | | | | | | | | | x | x | x | x | x | x | x | x | For NDK from r4 to r10, GCC with gnustl_static runtime library is used, only ARM architecture is supported. @@ -69,9 +69,9 @@ Windows: build-android.bat $(NDK_ROOT) ``` NOTE: Do not forget to replace backslash with slashes in $(NDK_ROOT). For example set $(NDK_ROOT) to D:/android-ndk-r8e instead of D:\android-ndk-r8e - + On windows you will need MSYS to be able to launch the corresponding bat files (http://www.mingw.org/wiki/MSYS). - + This command will download and build boost against the NDK specified and output the final headers and libs in the `build` folder. Make sure to provide an absolute path the the NDK folder! For more info about usage and available commands use `--help`. @@ -98,7 +98,7 @@ The projects is split into two main branches, the master and devel. The master b ## Troubleshooting -In case you encounter bunch of linker errors when building your app with boost, +In case you encounter bunch of linker errors when building your app with boost, this might help: ### Building from a 64 bit machine (Linux) @@ -112,7 +112,7 @@ To install them just use the following ### NDK 7 (CrystaX) -Add `-lgnustl_static` *AFTER* all boost libraries to the LOCAL_LDLIBS line in +Add `-lgnustl_static` *AFTER* all boost libraries to the LOCAL_LDLIBS line in Android.mk. Example: LOCAL_LDLIBS += lboost_system-gcc-md lboost_thread-gcc-md -lgnustl_static diff --git a/build-android.sh b/build-android.sh index b477a7f91..b929811e0 100755 --- a/build-android.sh +++ b/build-android.sh @@ -30,12 +30,16 @@ SCRIPTDIR="$(cd "$(dirname "$0")"; pwd)" # " # This extra quote fixes syntax hig # ----------------------- BOOST_VER1=1 -BOOST_VER2=82 +BOOST_VER2=83 BOOST_VER3=0 -register_option "--boost=" boost_version "Boost version to be used, one of {1.82.0 1.80.0 1.79.0 1.78.0 1.76.0 1.74.0, 1.73.0, 1.71.0, 1.70.0, 1.69.0, 1.68.0, 1.67.0, 1.66.0, 1.65.1, 1.55.0, 1.54.0, 1.53.0, 1.49.0, 1.48.0, 1.45.0}, default is 1.82.0." +register_option "--boost=" boost_version "Boost version to be used, one of {1.83.0 1.82.0 1.80.0 1.79.0 1.78.0 1.76.0 1.74.0, 1.73.0, 1.71.0, 1.70.0, 1.69.0, 1.68.0, 1.67.0, 1.66.0, 1.65.1, 1.55.0, 1.54.0, 1.53.0, 1.49.0, 1.48.0, 1.45.0}, default is 1.83.0." boost_version() { - if [ "$1" = "1.82.0" ]; then + if [ "$1" = "1.83.0" ]; then + BOOST_VER1=1 + BOOST_VER2=83 + BOOST_VER3=0 + elif [ "$1" = "1.82.0" ]; then BOOST_VER1=1 BOOST_VER2=82 BOOST_VER3=0 @@ -644,7 +648,7 @@ echo "Building boost for android for $ARCH" unset WITHOUT_LIBRARIES fi - { + { ./b2 -q \ -d+2 \ --ignore-site-config \ diff --git a/configs/user-config-ndk23-1_83_0-arm64-v8a.jam b/configs/user-config-ndk23-1_83_0-arm64-v8a.jam new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/configs/user-config-ndk23-1_83_0-arm64-v8a.jam @@ -0,0 +1 @@ + diff --git a/configs/user-config-ndk23-1_83_0-armeabi-v7a.jam b/configs/user-config-ndk23-1_83_0-armeabi-v7a.jam new file mode 100644 index 000000000..a5cfdf54d --- /dev/null +++ b/configs/user-config-ndk23-1_83_0-armeabi-v7a.jam @@ -0,0 +1 @@ +-mthumb diff --git a/configs/user-config-ndk23-1_83_0-common.jam b/configs/user-config-ndk23-1_83_0-common.jam new file mode 100644 index 000000000..edd81ea1a --- /dev/null +++ b/configs/user-config-ndk23-1_83_0-common.jam @@ -0,0 +1,22 @@ + +# -------------------------------------------------------------------- + +using clang : %ARCH% +: +$(AndroidCompiler_%ARCH%) +: +$(AndroidBinariesPath)/llvm-ar +$(AndroidBinariesPath)/llvm-ranlib +-fPIC +-ffunction-sections +-fdata-sections +-funwind-tables +-fstack-protector-strong +-no-canonical-prefixes +-Wformat +-Werror=format-security +-frtti +-fexceptions +-DNDEBUG +-g +-Oz diff --git a/configs/user-config-ndk23-1_83_0-x86.jam b/configs/user-config-ndk23-1_83_0-x86.jam new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/configs/user-config-ndk23-1_83_0-x86.jam @@ -0,0 +1 @@ + diff --git a/configs/user-config-ndk23-1_83_0-x86_64.jam b/configs/user-config-ndk23-1_83_0-x86_64.jam new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/configs/user-config-ndk23-1_83_0-x86_64.jam @@ -0,0 +1 @@ + diff --git a/configs/user-config-ndk23-1_83_0.jam b/configs/user-config-ndk23-1_83_0.jam new file mode 100644 index 000000000..483132946 --- /dev/null +++ b/configs/user-config-ndk23-1_83_0.jam @@ -0,0 +1,54 @@ +# Copyright 2003, 2005 Douglas Gregor +# Copyright 2004 John Maddock +# Copyright 2002, 2003, 2004, 2007 Vladimir Prus +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + +# This file is used to configure your Boost.Build installation. You can modify +# this file in place, or you can place it in a permanent location so that it +# does not get overwritten should you get a new version of Boost.Build. See: +# +# http://www.boost.org/boost-build2/doc/html/bbv2/overview/configuration.html +# +# for documentation about possible permanent locations. + +# This file specifies which toolsets (C++ compilers), libraries, and other +# tools are available. Often, you should be able to just uncomment existing +# example lines and adjust them to taste. The complete list of supported tools, +# and configuration instructions can be found at: +# +# http://boost.org/boost-build2/doc/html/bbv2/reference/tools.html +# + +# This file uses Jam language syntax to describe available tools. Mostly, +# there are 'using' lines, that contain the name of the used tools, and +# parameters to pass to those tools -- where paremeters are separated by +# semicolons. Important syntax notes: +# +# - Both ':' and ';' must be separated from other tokens by whitespace +# - The '\' symbol is a quote character, so when specifying Windows paths you +# should use '/' or '\\' instead. +# +# More details about the syntax can be found at: +# +# http://boost.org/boost-build2/doc/html/bbv2/advanced.html#bbv2.advanced.jam_language +# +# ------------------ +# Android configurations. +# ------------------ + +import os ; +local AndroidNDKRoot = [ os.environ AndroidNDKRoot ] ; +local AndroidBinariesPath = [ os.environ AndroidBinariesPath ] ; +local AndroidTargetVersion32 = [ os.environ AndroidTargetVersion32 ] ; +local AndroidTargetVersion64 = [ os.environ AndroidTargetVersion64 ] ; + +local AndroidCompiler_arm64v8a = $(AndroidBinariesPath)/aarch64-linux-android$(AndroidTargetVersion64)-clang++ ; +local AndroidCompiler_armeabiv7a = $(AndroidBinariesPath)/armv7a-linux-androideabi$(AndroidTargetVersion32)-clang++ ; +local AndroidCompiler_x86 = $(AndroidBinariesPath)/i686-linux-android$(AndroidTargetVersion32)-clang++ ; +local AndroidCompiler_x8664 = $(AndroidBinariesPath)/x86_64-linux-android$(AndroidTargetVersion64)-clang++ ; + +local AndroidBinaryPrefix_arm64v8a = $(AndroidBinariesPath)/aarch64-linux-android ; +local AndroidBinaryPrefix_armeabiv7a = $(AndroidBinariesPath)/arm-linux-androideabi ; +local AndroidBinaryPrefix_x86 = $(AndroidBinariesPath)/i686-linux-android ; +local AndroidBinaryPrefix_x8664 = $(AndroidBinariesPath)/x86_64-linux-android ; diff --git a/patches/boost-1_83_0/boost-1.83.0.patch b/patches/boost-1_83_0/boost-1.83.0.patch new file mode 100644 index 000000000..b14685c1f --- /dev/null +++ b/patches/boost-1_83_0/boost-1.83.0.patch @@ -0,0 +1,8633 @@ +diff -urN boost_1_83_0.orig/boost/asio/detail/config.hpp boost_1_83_0/boost/asio/detail/config.hpp +--- boost_1_83_0.orig/boost/asio/detail/config.hpp 2023-08-08 16:02:50.000000000 -0500 ++++ boost_1_83_0/boost/asio/detail/config.hpp 2023-12-20 19:37:21.249966924 -0600 +@@ -1305,7 +1305,11 @@ + # if (_LIBCPP_VERSION < 7000) + # if (__cplusplus >= 201402) + # if __has_include() +-# define BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW 1 ++# if __clang_major__ >= 7 ++# undef BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW ++# else ++# define BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW 1 ++# endif // __clang_major__ >= 7 + # endif // __has_include() + # endif // (__cplusplus >= 201402) + # endif // (_LIBCPP_VERSION < 7000) +diff -urN boost_1_83_0.orig/boost/asio/detail/config.hpp.orig boost_1_83_0/boost/asio/detail/config.hpp.orig +--- boost_1_83_0.orig/boost/asio/detail/config.hpp.orig 1969-12-31 18:00:00.000000000 -0600 ++++ boost_1_83_0/boost/asio/detail/config.hpp.orig 2023-12-20 19:37:21.249966924 -0600 +@@ -0,0 +1,2282 @@ ++// ++// detail/config.hpp ++// ~~~~~~~~~~~~~~~~~ ++// ++// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com) ++// ++// Distributed under the Boost Software License, Version 1.0. (See accompanying ++// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ++// ++ ++#ifndef BOOST_ASIO_DETAIL_CONFIG_HPP ++#define BOOST_ASIO_DETAIL_CONFIG_HPP ++ ++#if defined(BOOST_ASIO_STANDALONE) ++# define BOOST_ASIO_DISABLE_BOOST_ALIGN 1 ++# define BOOST_ASIO_DISABLE_BOOST_ARRAY 1 ++# define BOOST_ASIO_DISABLE_BOOST_ASSERT 1 ++# define BOOST_ASIO_DISABLE_BOOST_BIND 1 ++# define BOOST_ASIO_DISABLE_BOOST_CHRONO 1 ++# define BOOST_ASIO_DISABLE_BOOST_DATE_TIME 1 ++# define BOOST_ASIO_DISABLE_BOOST_LIMITS 1 ++# define BOOST_ASIO_DISABLE_BOOST_REGEX 1 ++# define BOOST_ASIO_DISABLE_BOOST_STATIC_CONSTANT 1 ++# define BOOST_ASIO_DISABLE_BOOST_THROW_EXCEPTION 1 ++# define BOOST_ASIO_DISABLE_BOOST_WORKAROUND 1 ++#else // defined(BOOST_ASIO_STANDALONE) ++// Boost.Config library is available. ++# include ++# include ++# define BOOST_ASIO_HAS_BOOST_CONFIG 1 ++#endif // defined(BOOST_ASIO_STANDALONE) ++ ++// Default to a header-only implementation. The user must specifically request ++// separate compilation by defining either BOOST_ASIO_SEPARATE_COMPILATION or ++// BOOST_ASIO_DYN_LINK (as a DLL/shared library implies separate compilation). ++#if !defined(BOOST_ASIO_HEADER_ONLY) ++# if !defined(BOOST_ASIO_SEPARATE_COMPILATION) ++# if !defined(BOOST_ASIO_DYN_LINK) ++# define BOOST_ASIO_HEADER_ONLY 1 ++# endif // !defined(BOOST_ASIO_DYN_LINK) ++# endif // !defined(BOOST_ASIO_SEPARATE_COMPILATION) ++#endif // !defined(BOOST_ASIO_HEADER_ONLY) ++ ++#if defined(BOOST_ASIO_HEADER_ONLY) ++# define BOOST_ASIO_DECL inline ++#else // defined(BOOST_ASIO_HEADER_ONLY) ++# if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__CODEGEARC__) ++// We need to import/export our code only if the user has specifically asked ++// for it by defining BOOST_ASIO_DYN_LINK. ++# if defined(BOOST_ASIO_DYN_LINK) ++// Export if this is our own source, otherwise import. ++# if defined(BOOST_ASIO_SOURCE) ++# define BOOST_ASIO_DECL __declspec(dllexport) ++# else // defined(BOOST_ASIO_SOURCE) ++# define BOOST_ASIO_DECL __declspec(dllimport) ++# endif // defined(BOOST_ASIO_SOURCE) ++# endif // defined(BOOST_ASIO_DYN_LINK) ++# endif // defined(_MSC_VER) || defined(__BORLANDC__) || defined(__CODEGEARC__) ++#endif // defined(BOOST_ASIO_HEADER_ONLY) ++ ++// If BOOST_ASIO_DECL isn't defined yet define it now. ++#if !defined(BOOST_ASIO_DECL) ++# define BOOST_ASIO_DECL ++#endif // !defined(BOOST_ASIO_DECL) ++ ++// Helper macro for documentation. ++#define BOOST_ASIO_UNSPECIFIED(e) e ++ ++// Microsoft Visual C++ detection. ++#if !defined(BOOST_ASIO_MSVC) ++# if defined(BOOST_ASIO_HAS_BOOST_CONFIG) && defined(BOOST_MSVC) ++# define BOOST_ASIO_MSVC BOOST_MSVC ++# elif defined(_MSC_VER) && (defined(__INTELLISENSE__) \ ++ || (!defined(__MWERKS__) && !defined(__EDG_VERSION__))) ++# define BOOST_ASIO_MSVC _MSC_VER ++# endif // defined(BOOST_ASIO_HAS_BOOST_CONFIG) && defined(BOOST_MSVC) ++#endif // !defined(BOOST_ASIO_MSVC) ++ ++// Clang / libc++ detection. ++#if defined(__clang__) ++# if (__cplusplus >= 201103) ++# if __has_include(<__config>) ++# include <__config> ++# if defined(_LIBCPP_VERSION) ++# define BOOST_ASIO_HAS_CLANG_LIBCXX 1 ++# endif // defined(_LIBCPP_VERSION) ++# endif // __has_include(<__config>) ++# endif // (__cplusplus >= 201103) ++#endif // defined(__clang__) ++ ++// Android platform detection. ++#if defined(__ANDROID__) ++# include ++#endif // defined(__ANDROID__) ++ ++// Support move construction and assignment on compilers known to allow it. ++#if !defined(BOOST_ASIO_HAS_MOVE) ++# if !defined(BOOST_ASIO_DISABLE_MOVE) ++# if defined(__clang__) ++# if __has_feature(__cxx_rvalue_references__) ++# define BOOST_ASIO_HAS_MOVE 1 ++# endif // __has_feature(__cxx_rvalue_references__) ++# elif defined(__GNUC__) ++# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4) ++# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) ++# define BOOST_ASIO_HAS_MOVE 1 ++# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) ++# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4) ++# endif // defined(__GNUC__) ++# if defined(BOOST_ASIO_MSVC) ++# if (_MSC_VER >= 1700) ++# define BOOST_ASIO_HAS_MOVE 1 ++# endif // (_MSC_VER >= 1700) ++# endif // defined(BOOST_ASIO_MSVC) ++# if defined(__INTEL_CXX11_MODE__) ++# if defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 1500) ++# define BOOST_ASIO_HAS_MOVE 1 ++# endif // defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 1500) ++# if defined(__ICL) && (__ICL >= 1500) ++# define BOOST_ASIO_HAS_MOVE 1 ++# endif // defined(__ICL) && (__ICL >= 1500) ++# endif // defined(__INTEL_CXX11_MODE__) ++# endif // !defined(BOOST_ASIO_DISABLE_MOVE) ++#endif // !defined(BOOST_ASIO_HAS_MOVE) ++ ++// If BOOST_ASIO_MOVE_CAST isn't defined, and move support is available, define ++// * BOOST_ASIO_MOVE_ARG, ++// * BOOST_ASIO_NONDEDUCED_MOVE_ARG, and ++// * BOOST_ASIO_MOVE_CAST ++// to take advantage of rvalue references and perfect forwarding. ++#if defined(BOOST_ASIO_HAS_MOVE) && !defined(BOOST_ASIO_MOVE_CAST) ++# define BOOST_ASIO_MOVE_ARG(type) type&& ++# define BOOST_ASIO_MOVE_ARG2(type1, type2) type1, type2&& ++# define BOOST_ASIO_NONDEDUCED_MOVE_ARG(type) type& ++# define BOOST_ASIO_MOVE_CAST(type) static_cast ++# define BOOST_ASIO_MOVE_CAST2(type1, type2) static_cast ++# define BOOST_ASIO_MOVE_OR_LVALUE(type) static_cast ++# define BOOST_ASIO_MOVE_OR_LVALUE_ARG(type) type&& ++# define BOOST_ASIO_MOVE_OR_LVALUE_TYPE(type) type ++#endif // defined(BOOST_ASIO_HAS_MOVE) && !defined(BOOST_ASIO_MOVE_CAST) ++ ++// If BOOST_ASIO_MOVE_CAST still isn't defined, default to a C++03-compatible ++// implementation. Note that older g++ and MSVC versions don't like it when you ++// pass a non-member function through a const reference, so for most compilers ++// we'll play it safe and stick with the old approach of passing the handler by ++// value. ++#if !defined(BOOST_ASIO_MOVE_CAST) ++# if defined(__GNUC__) ++# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 1)) || (__GNUC__ > 4) ++# define BOOST_ASIO_MOVE_ARG(type) const type& ++# else // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 1)) || (__GNUC__ > 4) ++# define BOOST_ASIO_MOVE_ARG(type) type ++# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 1)) || (__GNUC__ > 4) ++# elif defined(BOOST_ASIO_MSVC) ++# if (_MSC_VER >= 1400) ++# define BOOST_ASIO_MOVE_ARG(type) const type& ++# else // (_MSC_VER >= 1400) ++# define BOOST_ASIO_MOVE_ARG(type) type ++# endif // (_MSC_VER >= 1400) ++# else ++# define BOOST_ASIO_MOVE_ARG(type) type ++# endif ++# define BOOST_ASIO_NONDEDUCED_MOVE_ARG(type) const type& ++# define BOOST_ASIO_MOVE_CAST(type) static_cast ++# define BOOST_ASIO_MOVE_CAST2(type1, type2) static_cast ++# define BOOST_ASIO_MOVE_OR_LVALUE(type) ++# define BOOST_ASIO_MOVE_OR_LVALUE_ARG(type) type& ++# define BOOST_ASIO_MOVE_OR_LVALUE_TYPE(type) type& ++#endif // !defined(BOOST_ASIO_MOVE_CAST) ++ ++// Support variadic templates on compilers known to allow it. ++#if !defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) ++# if !defined(BOOST_ASIO_DISABLE_VARIADIC_TEMPLATES) ++# if defined(__clang__) ++# if __has_feature(__cxx_variadic_templates__) ++# define BOOST_ASIO_HAS_VARIADIC_TEMPLATES 1 ++# endif // __has_feature(__cxx_variadic_templates__) ++# elif defined(__GNUC__) ++# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4) ++# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) ++# define BOOST_ASIO_HAS_VARIADIC_TEMPLATES 1 ++# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) ++# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4) ++# endif // defined(__GNUC__) ++# if defined(BOOST_ASIO_MSVC) ++# if (_MSC_VER >= 1900) ++# define BOOST_ASIO_HAS_VARIADIC_TEMPLATES 1 ++# endif // (_MSC_VER >= 1900) ++# endif // defined(BOOST_ASIO_MSVC) ++# endif // !defined(BOOST_ASIO_DISABLE_VARIADIC_TEMPLATES) ++#endif // !defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) ++#if !defined(BOOST_ASIO_ELLIPSIS) ++# if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) ++# define BOOST_ASIO_ELLIPSIS ... ++# else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) ++# define BOOST_ASIO_ELLIPSIS ++# endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) ++#endif // !defined(BOOST_ASIO_ELLIPSIS) ++ ++// Support deleted functions on compilers known to allow it. ++#if !defined(BOOST_ASIO_DELETED) ++# if defined(__clang__) ++# if __has_feature(__cxx_deleted_functions__) ++# define BOOST_ASIO_DELETED = delete ++# endif // __has_feature(__cxx_deleted_functions__) ++# elif defined(__GNUC__) ++# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) ++# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) ++# define BOOST_ASIO_DELETED = delete ++# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) ++# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) ++# endif // defined(__GNUC__) ++# if defined(BOOST_ASIO_MSVC) ++# if (_MSC_VER >= 1900) ++# define BOOST_ASIO_DELETED = delete ++# endif // (_MSC_VER >= 1900) ++# endif // defined(BOOST_ASIO_MSVC) ++# if !defined(BOOST_ASIO_DELETED) ++# define BOOST_ASIO_DELETED ++# endif // !defined(BOOST_ASIO_DELETED) ++#endif // !defined(BOOST_ASIO_DELETED) ++ ++// Support constexpr on compilers known to allow it. ++#if !defined(BOOST_ASIO_HAS_CONSTEXPR) ++# if !defined(BOOST_ASIO_DISABLE_CONSTEXPR) ++# if defined(__clang__) ++# if __has_feature(__cxx_constexpr__) ++# define BOOST_ASIO_HAS_CONSTEXPR 1 ++# endif // __has_feature(__cxx_constexpr__) ++# elif defined(__GNUC__) ++# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4) ++# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) ++# define BOOST_ASIO_HAS_CONSTEXPR 1 ++# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) ++# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4) ++# endif // defined(__GNUC__) ++# if defined(BOOST_ASIO_MSVC) ++# if (_MSC_VER >= 1900) ++# define BOOST_ASIO_HAS_CONSTEXPR 1 ++# endif // (_MSC_VER >= 1900) ++# endif // defined(BOOST_ASIO_MSVC) ++# endif // !defined(BOOST_ASIO_DISABLE_CONSTEXPR) ++#endif // !defined(BOOST_ASIO_HAS_CONSTEXPR) ++#if !defined(BOOST_ASIO_CONSTEXPR) ++# if defined(BOOST_ASIO_HAS_CONSTEXPR) ++# define BOOST_ASIO_CONSTEXPR constexpr ++# else // defined(BOOST_ASIO_HAS_CONSTEXPR) ++# define BOOST_ASIO_CONSTEXPR ++# endif // defined(BOOST_ASIO_HAS_CONSTEXPR) ++#endif // !defined(BOOST_ASIO_CONSTEXPR) ++#if !defined(BOOST_ASIO_STATIC_CONSTEXPR) ++# if defined(BOOST_ASIO_HAS_CONSTEXPR) ++# define BOOST_ASIO_STATIC_CONSTEXPR(type, assignment) \ ++ static constexpr type assignment ++# else // defined(BOOST_ASIO_HAS_CONSTEXPR) ++# define BOOST_ASIO_STATIC_CONSTEXPR(type, assignment) \ ++ static const type assignment ++# endif // defined(BOOST_ASIO_HAS_CONSTEXPR) ++#endif // !defined(BOOST_ASIO_STATIC_CONSTEXPR) ++#if !defined(BOOST_ASIO_STATIC_CONSTEXPR_DEFAULT_INIT) ++# if defined(BOOST_ASIO_HAS_CONSTEXPR) ++# if defined(__GNUC__) ++# if (__GNUC__ >= 8) ++# define BOOST_ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(type, name) \ ++ static constexpr const type name{} ++# else // (__GNUC__ >= 8) ++# define BOOST_ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(type, name) \ ++ static const type name ++# endif // (__GNUC__ >= 8) ++# elif defined(BOOST_ASIO_MSVC) ++# define BOOST_ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(type, name) \ ++ static const type name ++# else // defined(BOOST_ASIO_MSVC) ++# define BOOST_ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(type, name) \ ++ static constexpr const type name{} ++# endif // defined(BOOST_ASIO_MSVC) ++# else // defined(BOOST_ASIO_HAS_CONSTEXPR) ++# define BOOST_ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(type, name) \ ++ static const type name ++# endif // defined(BOOST_ASIO_HAS_CONSTEXPR) ++#endif // !defined(BOOST_ASIO_STATIC_CONSTEXPR_DEFAULT_INIT) ++ ++// Support noexcept on compilers known to allow it. ++#if !defined(BOOST_ASIO_HAS_NOEXCEPT) ++# if !defined(BOOST_ASIO_DISABLE_NOEXCEPT) ++# if defined(BOOST_ASIO_HAS_BOOST_CONFIG) && (BOOST_VERSION >= 105300) ++# if !defined(BOOST_NO_NOEXCEPT) ++# define BOOST_ASIO_HAS_NOEXCEPT 1 ++# endif // !defined(BOOST_NO_NOEXCEPT) ++# define BOOST_ASIO_NOEXCEPT BOOST_NOEXCEPT ++# define BOOST_ASIO_NOEXCEPT_OR_NOTHROW BOOST_NOEXCEPT_OR_NOTHROW ++# define BOOST_ASIO_NOEXCEPT_IF(c) BOOST_NOEXCEPT_IF(c) ++# elif defined(__clang__) ++# if __has_feature(__cxx_noexcept__) ++# define BOOST_ASIO_HAS_NOEXCEPT 1 ++# endif // __has_feature(__cxx_noexcept__) ++# elif defined(__GNUC__) ++# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) ++# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) ++# define BOOST_ASIO_HAS_NOEXCEPT 1 ++# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) ++# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) ++# elif defined(BOOST_ASIO_MSVC) ++# if (_MSC_VER >= 1900) ++# define BOOST_ASIO_HAS_NOEXCEPT 1 ++# endif // (_MSC_VER >= 1900) ++# endif // defined(BOOST_ASIO_MSVC) ++# endif // !defined(BOOST_ASIO_DISABLE_NOEXCEPT) ++# if !defined(BOOST_ASIO_NOEXCEPT) ++# endif // !defined(BOOST_ASIO_NOEXCEPT) ++# if !defined(BOOST_ASIO_NOEXCEPT_OR_NOTHROW) ++# endif // !defined(BOOST_ASIO_NOEXCEPT_OR_NOTHROW) ++#endif // !defined(BOOST_ASIO_HAS_NOEXCEPT) ++#if !defined(BOOST_ASIO_NOEXCEPT) ++# if defined(BOOST_ASIO_HAS_NOEXCEPT) ++# define BOOST_ASIO_NOEXCEPT noexcept(true) ++# else // defined(BOOST_ASIO_HAS_NOEXCEPT) ++# define BOOST_ASIO_NOEXCEPT ++# endif // defined(BOOST_ASIO_HAS_NOEXCEPT) ++#endif // !defined(BOOST_ASIO_NOEXCEPT) ++#if !defined(BOOST_ASIO_NOEXCEPT_OR_NOTHROW) ++# if defined(BOOST_ASIO_HAS_NOEXCEPT) ++# define BOOST_ASIO_NOEXCEPT_OR_NOTHROW noexcept(true) ++# else // defined(BOOST_ASIO_HAS_NOEXCEPT) ++# define BOOST_ASIO_NOEXCEPT_OR_NOTHROW throw() ++# endif // defined(BOOST_ASIO_HAS_NOEXCEPT) ++#endif // !defined(BOOST_ASIO_NOEXCEPT_OR_NOTHROW) ++#if !defined(BOOST_ASIO_NOEXCEPT_IF) ++# if defined(BOOST_ASIO_HAS_NOEXCEPT) ++# define BOOST_ASIO_NOEXCEPT_IF(c) noexcept(c) ++# else // defined(BOOST_ASIO_HAS_NOEXCEPT) ++# define BOOST_ASIO_NOEXCEPT_IF(c) ++# endif // defined(BOOST_ASIO_HAS_NOEXCEPT) ++#endif // !defined(BOOST_ASIO_NOEXCEPT_IF) ++ ++// Support noexcept on function types on compilers known to allow it. ++#if !defined(BOOST_ASIO_HAS_NOEXCEPT_FUNCTION_TYPE) ++# if !defined(BOOST_ASIO_DISABLE_NOEXCEPT_FUNCTION_TYPE) ++# if defined(__clang__) ++# if (__cplusplus >= 202002) ++# define BOOST_ASIO_HAS_NOEXCEPT_FUNCTION_TYPE 1 ++# endif // (__cplusplus >= 202002) ++# elif defined(__GNUC__) ++# if (__cplusplus >= 202002) ++# define BOOST_ASIO_HAS_NOEXCEPT_FUNCTION_TYPE 1 ++# endif // (__cplusplus >= 202002) ++# elif defined(BOOST_ASIO_MSVC) ++# if (_MSC_VER >= 1900 && _MSVC_LANG >= 202002) ++# define BOOST_ASIO_HAS_NOEXCEPT_FUNCTION_TYPE 1 ++# endif // (_MSC_VER >= 1900 && _MSVC_LANG >= 202002) ++# endif // defined(BOOST_ASIO_MSVC) ++# endif // !defined(BOOST_ASIO_DISABLE_NOEXCEPT_FUNCTION_TYPE) ++#endif // !defined(BOOST_ASIO_HAS_NOEXCEPT_FUNCTION_TYPE) ++ ++// Support automatic type deduction on compilers known to support it. ++#if !defined(BOOST_ASIO_HAS_DECLTYPE) ++# if !defined(BOOST_ASIO_DISABLE_DECLTYPE) ++# if defined(__clang__) ++# if __has_feature(__cxx_decltype__) ++# define BOOST_ASIO_HAS_DECLTYPE 1 ++# endif // __has_feature(__cxx_decltype__) ++# elif defined(__GNUC__) ++# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4) ++# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) ++# define BOOST_ASIO_HAS_DECLTYPE 1 ++# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) ++# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4) ++# endif // defined(__GNUC__) ++# if defined(BOOST_ASIO_MSVC) ++# if (_MSC_VER >= 1800) ++# define BOOST_ASIO_HAS_DECLTYPE 1 ++# endif // (_MSC_VER >= 1800) ++# endif // defined(BOOST_ASIO_MSVC) ++# endif // !defined(BOOST_ASIO_DISABLE_DECLTYPE) ++#endif // !defined(BOOST_ASIO_HAS_DECLTYPE) ++#if defined(BOOST_ASIO_HAS_DECLTYPE) ++# define BOOST_ASIO_AUTO_RETURN_TYPE_PREFIX(t) auto ++# define BOOST_ASIO_AUTO_RETURN_TYPE_PREFIX2(t0, t1) auto ++# define BOOST_ASIO_AUTO_RETURN_TYPE_PREFIX3(t0, t1, t2) auto ++# define BOOST_ASIO_AUTO_RETURN_TYPE_SUFFIX(expr) -> decltype expr ++#else // defined(BOOST_ASIO_HAS_DECLTYPE) ++# define BOOST_ASIO_AUTO_RETURN_TYPE_PREFIX(t) t ++# define BOOST_ASIO_AUTO_RETURN_TYPE_PREFIX2(t0, t1) t0, t1 ++# define BOOST_ASIO_AUTO_RETURN_TYPE_PREFIX3(t0, t1, t2) t0, t1, t2 ++# define BOOST_ASIO_AUTO_RETURN_TYPE_SUFFIX(expr) ++#endif // defined(BOOST_ASIO_HAS_DECLTYPE) ++ ++// Support alias templates on compilers known to allow it. ++#if !defined(BOOST_ASIO_HAS_ALIAS_TEMPLATES) ++# if !defined(BOOST_ASIO_DISABLE_ALIAS_TEMPLATES) ++# if defined(__clang__) ++# if __has_feature(__cxx_alias_templates__) ++# define BOOST_ASIO_HAS_ALIAS_TEMPLATES 1 ++# endif // __has_feature(__cxx_alias_templates__) ++# elif defined(__GNUC__) ++# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) ++# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) ++# define BOOST_ASIO_HAS_ALIAS_TEMPLATES 1 ++# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) ++# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) ++# endif // defined(__GNUC__) ++# if defined(BOOST_ASIO_MSVC) ++# if (_MSC_VER >= 1900) ++# define BOOST_ASIO_HAS_ALIAS_TEMPLATES 1 ++# endif // (_MSC_VER >= 1900) ++# endif // defined(BOOST_ASIO_MSVC) ++# endif // !defined(BOOST_ASIO_DISABLE_ALIAS_TEMPLATES) ++#endif // !defined(BOOST_ASIO_HAS_ALIAS_TEMPLATES) ++ ++// Support return type deduction on compilers known to allow it. ++#if !defined(BOOST_ASIO_HAS_RETURN_TYPE_DEDUCTION) ++# if !defined(BOOST_ASIO_DISABLE_RETURN_TYPE_DEDUCTION) ++# if defined(__clang__) ++# if __has_feature(__cxx_return_type_deduction__) ++# define BOOST_ASIO_HAS_RETURN_TYPE_DEDUCTION 1 ++# endif // __has_feature(__cxx_return_type_deduction__) ++# elif (__cplusplus >= 201402) ++# define BOOST_ASIO_HAS_RETURN_TYPE_DEDUCTION 1 ++# elif defined(__cpp_return_type_deduction) ++# if (__cpp_return_type_deduction >= 201304) ++# define BOOST_ASIO_HAS_RETURN_TYPE_DEDUCTION 1 ++# endif // (__cpp_return_type_deduction >= 201304) ++# elif defined(BOOST_ASIO_MSVC) ++# if (_MSC_VER >= 1900 && _MSVC_LANG >= 201402) ++# define BOOST_ASIO_HAS_RETURN_TYPE_DEDUCTION 1 ++# endif // (_MSC_VER >= 1900 && _MSVC_LANG >= 201402) ++# endif // defined(BOOST_ASIO_MSVC) ++# endif // !defined(BOOST_ASIO_DISABLE_RETURN_TYPE_DEDUCTION) ++#endif // !defined(BOOST_ASIO_HAS_RETURN_TYPE_DEDUCTION) ++ ++// Support default function template arguments on compilers known to allow it. ++#if !defined(BOOST_ASIO_HAS_DEFAULT_FUNCTION_TEMPLATE_ARGUMENTS) ++# if !defined(BOOST_ASIO_DISABLE_DEFAULT_FUNCTION_TEMPLATE_ARGUMENTS) ++# if (__cplusplus >= 201103) ++# define BOOST_ASIO_HAS_DEFAULT_FUNCTION_TEMPLATE_ARGUMENTS 1 ++# elif defined(BOOST_ASIO_MSVC) ++# if (_MSC_VER >= 1900 && _MSVC_LANG >= 201103) ++# define BOOST_ASIO_HAS_DEFAULT_FUNCTION_TEMPLATE_ARGUMENTS 1 ++# endif // (_MSC_VER >= 1900 && _MSVC_LANG >= 201103) ++# endif // defined(BOOST_ASIO_MSVC) ++# endif // !defined(BOOST_ASIO_DISABLE_DEFAULT_FUNCTION_TEMPLATE_ARGUMENTS) ++#endif // !defined(BOOST_ASIO_HAS_DEFAULT_FUNCTION_TEMPLATE_ARGUMENTS) ++ ++// Support enum classes on compilers known to allow them. ++#if !defined(BOOST_ASIO_HAS_ENUM_CLASS) ++# if !defined(BOOST_ASIO_DISABLE_ENUM_CLASS) ++# if (__cplusplus >= 201103) ++# define BOOST_ASIO_HAS_ENUM_CLASS 1 ++# elif defined(BOOST_ASIO_MSVC) ++# if (_MSC_VER >= 1900 && _MSVC_LANG >= 201103) ++# define BOOST_ASIO_HAS_ENUM_CLASS 1 ++# endif // (_MSC_VER >= 1900 && _MSVC_LANG >= 201103) ++# endif // defined(BOOST_ASIO_MSVC) ++# endif // !defined(BOOST_ASIO_DISABLE_ENUM_CLASS) ++#endif // !defined(BOOST_ASIO_HAS_ENUM_CLASS) ++ ++// Support concepts on compilers known to allow them. ++#if !defined(BOOST_ASIO_HAS_CONCEPTS) ++# if !defined(BOOST_ASIO_DISABLE_CONCEPTS) ++# if defined(__cpp_concepts) ++# define BOOST_ASIO_HAS_CONCEPTS 1 ++# if (__cpp_concepts >= 201707) ++# define BOOST_ASIO_CONCEPT concept ++# else // (__cpp_concepts >= 201707) ++# define BOOST_ASIO_CONCEPT concept bool ++# endif // (__cpp_concepts >= 201707) ++# endif // defined(__cpp_concepts) ++# endif // !defined(BOOST_ASIO_DISABLE_CONCEPTS) ++#endif // !defined(BOOST_ASIO_HAS_CONCEPTS) ++ ++// Support concepts on compilers known to allow them. ++#if !defined(BOOST_ASIO_HAS_STD_CONCEPTS) ++# if !defined(BOOST_ASIO_DISABLE_STD_CONCEPTS) ++# if defined(BOOST_ASIO_HAS_CONCEPTS) ++# if (__cpp_lib_concepts >= 202002L) ++# define BOOST_ASIO_HAS_STD_CONCEPTS 1 ++# endif // (__cpp_concepts >= 202002L) ++# endif // defined(BOOST_ASIO_HAS_CONCEPTS) ++# endif // !defined(BOOST_ASIO_DISABLE_STD_CONCEPTS) ++#endif // !defined(BOOST_ASIO_HAS_STD_CONCEPTS) ++ ++// Support template variables on compilers known to allow it. ++#if !defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) ++# if !defined(BOOST_ASIO_DISABLE_VARIABLE_TEMPLATES) ++# if defined(__clang__) ++# if (__cplusplus >= 201402) ++# if __has_feature(__cxx_variable_templates__) ++# define BOOST_ASIO_HAS_VARIABLE_TEMPLATES 1 ++# endif // __has_feature(__cxx_variable_templates__) ++# endif // (__cplusplus >= 201402) ++# elif defined(__GNUC__) && !defined(__INTEL_COMPILER) ++# if (__GNUC__ >= 6) ++# if (__cplusplus >= 201402) ++# define BOOST_ASIO_HAS_VARIABLE_TEMPLATES 1 ++# endif // (__cplusplus >= 201402) ++# endif // (__GNUC__ >= 6) ++# endif // defined(__GNUC__) && !defined(__INTEL_COMPILER) ++# if defined(BOOST_ASIO_MSVC) ++# if (_MSC_VER >= 1901) ++# define BOOST_ASIO_HAS_VARIABLE_TEMPLATES 1 ++# endif // (_MSC_VER >= 1901) ++# endif // defined(BOOST_ASIO_MSVC) ++# endif // !defined(BOOST_ASIO_DISABLE_VARIABLE_TEMPLATES) ++#endif // !defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) ++ ++// Support SFINAEd template variables on compilers known to allow it. ++#if !defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) ++# if !defined(BOOST_ASIO_DISABLE_SFINAE_VARIABLE_TEMPLATES) ++# if defined(__clang__) ++# if (__cplusplus >= 201703) ++# if __has_feature(__cxx_variable_templates__) ++# define BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES 1 ++# endif // __has_feature(__cxx_variable_templates__) ++# endif // (__cplusplus >= 201703) ++# elif defined(__GNUC__) ++# if ((__GNUC__ == 8) && (__GNUC_MINOR__ >= 4)) || (__GNUC__ > 8) ++# if (__cplusplus >= 201402) ++# define BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES 1 ++# endif // (__cplusplus >= 201402) ++# endif // ((__GNUC__ == 8) && (__GNUC_MINOR__ >= 4)) || (__GNUC__ > 8) ++# endif // defined(__GNUC__) ++# if defined(BOOST_ASIO_MSVC) ++# if (_MSC_VER >= 1901) ++# define BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES 1 ++# endif // (_MSC_VER >= 1901) ++# endif // defined(BOOST_ASIO_MSVC) ++# endif // !defined(BOOST_ASIO_DISABLE_SFINAE_VARIABLE_TEMPLATES) ++#endif // !defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) ++ ++// Support SFINAE use of constant expressions on compilers known to allow it. ++#if !defined(BOOST_ASIO_HAS_CONSTANT_EXPRESSION_SFINAE) ++# if !defined(BOOST_ASIO_DISABLE_CONSTANT_EXPRESSION_SFINAE) ++# if defined(__clang__) ++# if (__cplusplus >= 201402) ++# define BOOST_ASIO_HAS_CONSTANT_EXPRESSION_SFINAE 1 ++# endif // (__cplusplus >= 201402) ++# elif defined(__GNUC__) && !defined(__INTEL_COMPILER) ++# if (__GNUC__ >= 7) ++# if (__cplusplus >= 201402) ++# define BOOST_ASIO_HAS_CONSTANT_EXPRESSION_SFINAE 1 ++# endif // (__cplusplus >= 201402) ++# endif // (__GNUC__ >= 7) ++# endif // defined(__GNUC__) && !defined(__INTEL_COMPILER) ++# if defined(BOOST_ASIO_MSVC) ++# if (_MSC_VER >= 1901) ++# define BOOST_ASIO_HAS_CONSTANT_EXPRESSION_SFINAE 1 ++# endif // (_MSC_VER >= 1901) ++# endif // defined(BOOST_ASIO_MSVC) ++# endif // !defined(BOOST_ASIO_DISABLE_CONSTANT_EXPRESSION_SFINAE) ++#endif // !defined(BOOST_ASIO_HAS_CONSTANT_EXPRESSION_SFINAE) ++ ++// Enable workarounds for lack of working expression SFINAE. ++#if !defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) ++# if !defined(BOOST_ASIO_DISABLE_WORKING_EXPRESSION_SFINAE) ++# if !defined(BOOST_ASIO_MSVC) && !defined(__INTEL_COMPILER) ++# if (__cplusplus >= 201103) ++# define BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE 1 ++# endif // (__cplusplus >= 201103) ++# elif defined(BOOST_ASIO_MSVC) && (_MSC_VER >= 1929) ++# if (_MSVC_LANG >= 202000) ++# define BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE 1 ++# endif // (_MSVC_LANG >= 202000) ++# endif // defined(BOOST_ASIO_MSVC) && (_MSC_VER >= 1929) ++# endif // !defined(BOOST_ASIO_DISABLE_WORKING_EXPRESSION_SFINAE) ++#endif // !defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) ++ ++// Support ref-qualified functions on compilers known to allow it. ++#if !defined(BOOST_ASIO_HAS_REF_QUALIFIED_FUNCTIONS) ++# if !defined(BOOST_ASIO_DISABLE_REF_QUALIFIED_FUNCTIONS) ++# if defined(__clang__) ++# if __has_feature(__cxx_reference_qualified_functions__) ++# define BOOST_ASIO_HAS_REF_QUALIFIED_FUNCTIONS 1 ++# endif // __has_feature(__cxx_reference_qualified_functions__) ++# elif defined(__GNUC__) ++# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 9)) || (__GNUC__ > 4) ++# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) ++# define BOOST_ASIO_HAS_REF_QUALIFIED_FUNCTIONS 1 ++# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) ++# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 9)) || (__GNUC__ > 4) ++# endif // defined(__GNUC__) ++# if defined(BOOST_ASIO_MSVC) ++# if (_MSC_VER >= 1900) ++# define BOOST_ASIO_HAS_REF_QUALIFIED_FUNCTIONS 1 ++# endif // (_MSC_VER >= 1900) ++# endif // defined(BOOST_ASIO_MSVC) ++# endif // !defined(BOOST_ASIO_DISABLE_REF_QUALIFIED_FUNCTIONS) ++#endif // !defined(BOOST_ASIO_HAS_REF_QUALIFIED_FUNCTIONS) ++#if defined(BOOST_ASIO_HAS_REF_QUALIFIED_FUNCTIONS) ++# if !defined(BOOST_ASIO_LVALUE_REF_QUAL) ++# define BOOST_ASIO_LVALUE_REF_QUAL & ++# endif // !defined(BOOST_ASIO_LVALUE_REF_QUAL) ++# if !defined(BOOST_ASIO_RVALUE_REF_QUAL) ++# define BOOST_ASIO_RVALUE_REF_QUAL && ++# endif // !defined(BOOST_ASIO_RVALUE_REF_QUAL) ++#else // defined(BOOST_ASIO_HAS_REF_QUALIFIED_FUNCTIONS) ++# if !defined(BOOST_ASIO_LVALUE_REF_QUAL) ++# define BOOST_ASIO_LVALUE_REF_QUAL ++# endif // !defined(BOOST_ASIO_LVALUE_REF_QUAL) ++# if !defined(BOOST_ASIO_RVALUE_REF_QUAL) ++# define BOOST_ASIO_RVALUE_REF_QUAL ++# endif // !defined(BOOST_ASIO_RVALUE_REF_QUAL) ++#endif // defined(BOOST_ASIO_HAS_REF_QUALIFIED_FUNCTIONS) ++ ++// Support for capturing parameter packs in lambdas. ++#if !defined(BOOST_ASIO_HAS_VARIADIC_LAMBDA_CAPTURES) ++# if !defined(BOOST_ASIO_DISABLE_VARIADIC_LAMBDA_CAPTURES) ++# if defined(__GNUC__) ++# if (__GNUC__ >= 6) ++# define BOOST_ASIO_HAS_VARIADIC_LAMBDA_CAPTURES 1 ++# endif // (__GNUC__ >= 6) ++# elif defined(BOOST_ASIO_MSVC) ++# if (_MSVC_LANG >= 201103) ++# define BOOST_ASIO_HAS_VARIADIC_LAMBDA_CAPTURES 1 ++# endif // (_MSC_LANG >= 201103) ++# else // defined(BOOST_ASIO_MSVC) ++# if (__cplusplus >= 201103) ++# define BOOST_ASIO_HAS_VARIADIC_LAMBDA_CAPTURES 1 ++# endif // (__cplusplus >= 201103) ++# endif // defined(BOOST_ASIO_MSVC) ++# endif // !defined(BOOST_ASIO_DISABLE_VARIADIC_LAMBDA_CAPTURES) ++#endif // !defined(BOOST_ASIO_HAS_VARIADIC_LAMBDA_CAPTURES) ++ ++// Support for the alignof operator. ++#if !defined(BOOST_ASIO_HAS_ALIGNOF) ++# if !defined(BOOST_ASIO_DISABLE_ALIGNOF) ++# if (__cplusplus >= 201103) ++# define BOOST_ASIO_HAS_ALIGNOF 1 ++# endif // (__cplusplus >= 201103) ++# endif // !defined(BOOST_ASIO_DISABLE_ALIGNOF) ++#endif // !defined(BOOST_ASIO_HAS_ALIGNOF) ++ ++#if defined(BOOST_ASIO_HAS_ALIGNOF) ++# define BOOST_ASIO_ALIGNOF(T) alignof(T) ++# if defined(__STDCPP_DEFAULT_NEW_ALIGNMENT__) ++# define BOOST_ASIO_DEFAULT_ALIGN __STDCPP_DEFAULT_NEW_ALIGNMENT__ ++# elif defined(__GNUC__) ++# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 9)) || (__GNUC__ > 4) ++# define BOOST_ASIO_DEFAULT_ALIGN alignof(std::max_align_t) ++# else // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 9)) || (__GNUC__ > 4) ++# define BOOST_ASIO_DEFAULT_ALIGN alignof(max_align_t) ++# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 9)) || (__GNUC__ > 4) ++# else // defined(__GNUC__) ++# define BOOST_ASIO_DEFAULT_ALIGN alignof(std::max_align_t) ++# endif // defined(__GNUC__) ++#else // defined(BOOST_ASIO_HAS_ALIGNOF) ++# define BOOST_ASIO_ALIGNOF(T) 1 ++# define BOOST_ASIO_DEFAULT_ALIGN 1 ++#endif // defined(BOOST_ASIO_HAS_ALIGNOF) ++ ++// Support for user-defined literals. ++#if !defined(BOOST_ASIO_HAS_USER_DEFINED_LITERALS) ++# if !defined(BOOST_ASIO_DISABLE_USER_DEFINED_LITERALS) ++# if (__cplusplus >= 201103) ++# define BOOST_ASIO_HAS_USER_DEFINED_LITERALS 1 ++# elif defined(BOOST_ASIO_MSVC) ++# if (_MSC_VER >= 1900 && _MSVC_LANG >= 201103) ++# define BOOST_ASIO_HAS_USER_DEFINED_LITERALS 1 ++# endif // (_MSC_VER >= 1900 && _MSVC_LANG >= 201103) ++# endif // defined(BOOST_ASIO_MSVC) ++# endif // !defined(BOOST_ASIO_DISABLE_USER_DEFINED_LITERALS) ++#endif // !defined(BOOST_ASIO_HAS_USER_DEFINED_LITERALS) ++ ++// Standard library support for aligned allocation. ++#if !defined(BOOST_ASIO_HAS_STD_ALIGNED_ALLOC) ++# if !defined(BOOST_ASIO_DISABLE_STD_ALIGNED_ALLOC) ++# if (__cplusplus >= 201703) ++# if defined(__clang__) ++# if defined(BOOST_ASIO_HAS_CLANG_LIBCXX) ++# if (_LIBCPP_STD_VER > 14) && defined(_LIBCPP_HAS_ALIGNED_ALLOC) \ ++ && !defined(_LIBCPP_MSVCRT) && !defined(__MINGW32__) ++# if defined(__APPLE__) ++# if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) ++# if (__MAC_OS_X_VERSION_MIN_REQUIRED >= 101500) ++# define BOOST_ASIO_HAS_STD_ALIGNED_ALLOC 1 ++# endif // (__MAC_OS_X_VERSION_MIN_REQUIRED >= 101500) ++# elif defined(__IPHONE_OS_VERSION_MIN_REQUIRED) ++# if (__IPHONE_OS_VERSION_MIN_REQUIRED >= 130000) ++# define BOOST_ASIO_HAS_STD_ALIGNED_ALLOC 1 ++# endif // (__IPHONE_OS_VERSION_MIN_REQUIRED >= 130000) ++# elif defined(__TV_OS_VERSION_MIN_REQUIRED) ++# if (__TV_OS_VERSION_MIN_REQUIRED >= 130000) ++# define BOOST_ASIO_HAS_STD_ALIGNED_ALLOC 1 ++# endif // (__TV_OS_VERSION_MIN_REQUIRED >= 130000) ++# elif defined(__WATCH_OS_VERSION_MIN_REQUIRED) ++# if (__WATCH_OS_VERSION_MIN_REQUIRED >= 60000) ++# define BOOST_ASIO_HAS_STD_ALIGNED_ALLOC 1 ++# endif // (__WATCH_OS_VERSION_MIN_REQUIRED >= 60000) ++# endif // defined(__WATCH_OS_X_VERSION_MIN_REQUIRED) ++# else // defined(__APPLE__) ++# define BOOST_ASIO_HAS_STD_ALIGNED_ALLOC 1 ++# endif // defined(__APPLE__) ++# endif // (_LIBCPP_STD_VER > 14) && defined(_LIBCPP_HAS_ALIGNED_ALLOC) ++ // && !defined(_LIBCPP_MSVCRT) && !defined(__MINGW32__) ++# elif defined(_GLIBCXX_HAVE_ALIGNED_ALLOC) ++# define BOOST_ASIO_HAS_STD_ALIGNED_ALLOC 1 ++# endif // defined(_GLIBCXX_HAVE_ALIGNED_ALLOC) ++# elif defined(__GNUC__) ++# if ((__GNUC__ == 7) && (__GNUC_MINOR__ >= 4)) || (__GNUC__ > 7) ++# if defined(_GLIBCXX_HAVE_ALIGNED_ALLOC) ++# define BOOST_ASIO_HAS_STD_ALIGNED_ALLOC 1 ++# endif // defined(_GLIBCXX_HAVE_ALIGNED_ALLOC) ++# endif // ((__GNUC__ == 7) && (__GNUC_MINOR__ >= 4)) || (__GNUC__ > 7) ++# endif // defined(__GNUC__) ++# endif // (__cplusplus >= 201703) ++# endif // !defined(BOOST_ASIO_DISABLE_STD_ALIGNED_ALLOC) ++#endif // !defined(BOOST_ASIO_HAS_STD_ALIGNED_ALLOC) ++ ++// Standard library support for std::align. ++#if !defined(BOOST_ASIO_HAS_STD_ALIGN) ++# if !defined(BOOST_ASIO_DISABLE_STD_ALIGN) ++# if defined(__clang__) ++# if defined(BOOST_ASIO_HAS_CLANG_LIBCXX) ++# define BOOST_ASIO_HAS_STD_ALIGN 1 ++# elif (__cplusplus >= 201103) ++# define BOOST_ASIO_HAS_STD_ALIGN 1 ++# endif // (__cplusplus >= 201103) ++# elif defined(__GNUC__) ++# if (__GNUC__ >= 6) ++# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) ++# define BOOST_ASIO_HAS_STD_ALIGN 1 ++# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) ++# endif // (__GNUC__ >= 6) ++# endif // defined(__GNUC__) ++# if defined(BOOST_ASIO_MSVC) ++# if (_MSC_VER >= 1700) ++# define BOOST_ASIO_HAS_STD_ALIGN 1 ++# endif // (_MSC_VER >= 1700) ++# endif // defined(BOOST_ASIO_MSVC) ++# endif // !defined(BOOST_ASIO_DISABLE_STD_ALIGN) ++#endif // !defined(BOOST_ASIO_HAS_STD_ALIGN) ++ ++// Standard library support for system errors. ++# if !defined(BOOST_ASIO_DISABLE_STD_SYSTEM_ERROR) ++# if defined(__clang__) ++# if defined(BOOST_ASIO_HAS_CLANG_LIBCXX) ++# define BOOST_ASIO_HAS_STD_SYSTEM_ERROR 1 ++# elif (__cplusplus >= 201103) ++# if __has_include() ++# define BOOST_ASIO_HAS_STD_SYSTEM_ERROR 1 ++# endif // __has_include() ++# endif // (__cplusplus >= 201103) ++# elif defined(__GNUC__) ++# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4) ++# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) ++# define BOOST_ASIO_HAS_STD_SYSTEM_ERROR 1 ++# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) ++# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4) ++# endif // defined(__GNUC__) ++# if defined(BOOST_ASIO_MSVC) ++# if (_MSC_VER >= 1700) ++# define BOOST_ASIO_HAS_STD_SYSTEM_ERROR 1 ++# endif // (_MSC_VER >= 1700) ++# endif // defined(BOOST_ASIO_MSVC) ++# endif // !defined(BOOST_ASIO_DISABLE_STD_SYSTEM_ERROR) ++ ++// Compliant C++11 compilers put noexcept specifiers on error_category members. ++#if !defined(BOOST_ASIO_ERROR_CATEGORY_NOEXCEPT) ++# if defined(BOOST_ASIO_HAS_BOOST_CONFIG) && (BOOST_VERSION >= 105300) ++# define BOOST_ASIO_ERROR_CATEGORY_NOEXCEPT BOOST_NOEXCEPT ++# elif defined(__clang__) ++# if __has_feature(__cxx_noexcept__) ++# define BOOST_ASIO_ERROR_CATEGORY_NOEXCEPT noexcept(true) ++# endif // __has_feature(__cxx_noexcept__) ++# elif defined(__GNUC__) ++# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) ++# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) ++# define BOOST_ASIO_ERROR_CATEGORY_NOEXCEPT noexcept(true) ++# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) ++# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) ++# elif defined(BOOST_ASIO_MSVC) ++# if (_MSC_VER >= 1900) ++# define BOOST_ASIO_ERROR_CATEGORY_NOEXCEPT noexcept(true) ++# endif // (_MSC_VER >= 1900) ++# endif // defined(BOOST_ASIO_MSVC) ++# if !defined(BOOST_ASIO_ERROR_CATEGORY_NOEXCEPT) ++# define BOOST_ASIO_ERROR_CATEGORY_NOEXCEPT ++# endif // !defined(BOOST_ASIO_ERROR_CATEGORY_NOEXCEPT) ++#endif // !defined(BOOST_ASIO_ERROR_CATEGORY_NOEXCEPT) ++ ++// Standard library support for arrays. ++#if !defined(BOOST_ASIO_HAS_STD_ARRAY) ++# if !defined(BOOST_ASIO_DISABLE_STD_ARRAY) ++# if defined(__clang__) ++# if defined(BOOST_ASIO_HAS_CLANG_LIBCXX) ++# define BOOST_ASIO_HAS_STD_ARRAY 1 ++# elif (__cplusplus >= 201103) ++# if __has_include() ++# define BOOST_ASIO_HAS_STD_ARRAY 1 ++# endif // __has_include() ++# endif // (__cplusplus >= 201103) ++# elif defined(__GNUC__) ++# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 4) ++# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) ++# define BOOST_ASIO_HAS_STD_ARRAY 1 ++# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) ++# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 4) ++# endif // defined(__GNUC__) ++# if defined(BOOST_ASIO_MSVC) ++# if (_MSC_VER >= 1600) ++# define BOOST_ASIO_HAS_STD_ARRAY 1 ++# endif // (_MSC_VER >= 1600) ++# endif // defined(BOOST_ASIO_MSVC) ++# endif // !defined(BOOST_ASIO_DISABLE_STD_ARRAY) ++#endif // !defined(BOOST_ASIO_HAS_STD_ARRAY) ++ ++// Standard library support for shared_ptr and weak_ptr. ++#if !defined(BOOST_ASIO_HAS_STD_SHARED_PTR) ++# if !defined(BOOST_ASIO_DISABLE_STD_SHARED_PTR) ++# if defined(__clang__) ++# if defined(BOOST_ASIO_HAS_CLANG_LIBCXX) ++# define BOOST_ASIO_HAS_STD_SHARED_PTR 1 ++# elif (__cplusplus >= 201103) ++# define BOOST_ASIO_HAS_STD_SHARED_PTR 1 ++# endif // (__cplusplus >= 201103) ++# elif defined(__GNUC__) ++# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 4) ++# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) ++# define BOOST_ASIO_HAS_STD_SHARED_PTR 1 ++# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) ++# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 4) ++# endif // defined(__GNUC__) ++# if defined(BOOST_ASIO_MSVC) ++# if (_MSC_VER >= 1600) ++# define BOOST_ASIO_HAS_STD_SHARED_PTR 1 ++# endif // (_MSC_VER >= 1600) ++# endif // defined(BOOST_ASIO_MSVC) ++# endif // !defined(BOOST_ASIO_DISABLE_STD_SHARED_PTR) ++#endif // !defined(BOOST_ASIO_HAS_STD_SHARED_PTR) ++ ++// Standard library support for allocator_arg_t. ++#if !defined(BOOST_ASIO_HAS_STD_ALLOCATOR_ARG) ++# if !defined(BOOST_ASIO_DISABLE_STD_ALLOCATOR_ARG) ++# if defined(__clang__) ++# if defined(BOOST_ASIO_HAS_CLANG_LIBCXX) ++# define BOOST_ASIO_HAS_STD_ALLOCATOR_ARG 1 ++# elif (__cplusplus >= 201103) ++# define BOOST_ASIO_HAS_STD_ALLOCATOR_ARG 1 ++# endif // (__cplusplus >= 201103) ++# elif defined(__GNUC__) ++# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4) ++# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) ++# define BOOST_ASIO_HAS_STD_ALLOCATOR_ARG 1 ++# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) ++# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4) ++# endif // defined(__GNUC__) ++# if defined(BOOST_ASIO_MSVC) ++# if (_MSC_VER >= 1600) ++# define BOOST_ASIO_HAS_STD_ALLOCATOR_ARG 1 ++# endif // (_MSC_VER >= 1600) ++# endif // defined(BOOST_ASIO_MSVC) ++# endif // !defined(BOOST_ASIO_DISABLE_STD_ALLOCATOR_ARG) ++#endif // !defined(BOOST_ASIO_HAS_STD_ALLOCATOR_ARG) ++ ++// Standard library support for atomic operations. ++#if !defined(BOOST_ASIO_HAS_STD_ATOMIC) ++# if !defined(BOOST_ASIO_DISABLE_STD_ATOMIC) ++# if defined(__clang__) ++# if defined(BOOST_ASIO_HAS_CLANG_LIBCXX) ++# define BOOST_ASIO_HAS_STD_ATOMIC 1 ++# elif (__cplusplus >= 201103) ++# if __has_include() ++# define BOOST_ASIO_HAS_STD_ATOMIC 1 ++# endif // __has_include() ++# elif defined(__apple_build_version__) && defined(_LIBCPP_VERSION) ++# if (__clang_major__ >= 10) ++# if __has_include() ++# define BOOST_ASIO_HAS_STD_ATOMIC 1 ++# endif // __has_include() ++# endif // (__clang_major__ >= 10) ++# endif // defined(__apple_build_version__) && defined(_LIBCPP_VERSION) ++# elif defined(__GNUC__) ++# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) ++# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) ++# define BOOST_ASIO_HAS_STD_ATOMIC 1 ++# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) ++# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) ++# endif // defined(__GNUC__) ++# if defined(BOOST_ASIO_MSVC) ++# if (_MSC_VER >= 1700) ++# define BOOST_ASIO_HAS_STD_ATOMIC 1 ++# endif // (_MSC_VER >= 1700) ++# endif // defined(BOOST_ASIO_MSVC) ++# endif // !defined(BOOST_ASIO_DISABLE_STD_ATOMIC) ++#endif // !defined(BOOST_ASIO_HAS_STD_ATOMIC) ++ ++// Standard library support for chrono. Some standard libraries (such as the ++// libstdc++ shipped with gcc 4.6) provide monotonic_clock as per early C++0x ++// drafts, rather than the eventually standardised name of steady_clock. ++#if !defined(BOOST_ASIO_HAS_STD_CHRONO) ++# if !defined(BOOST_ASIO_DISABLE_STD_CHRONO) ++# if defined(__clang__) ++# if defined(BOOST_ASIO_HAS_CLANG_LIBCXX) ++# define BOOST_ASIO_HAS_STD_CHRONO 1 ++# elif (__cplusplus >= 201103) ++# if __has_include() ++# define BOOST_ASIO_HAS_STD_CHRONO 1 ++# endif // __has_include() ++# endif // (__cplusplus >= 201103) ++# elif defined(__GNUC__) ++# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4) ++# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) ++# define BOOST_ASIO_HAS_STD_CHRONO 1 ++# if ((__GNUC__ == 4) && (__GNUC_MINOR__ == 6)) ++# define BOOST_ASIO_HAS_STD_CHRONO_MONOTONIC_CLOCK 1 ++# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ == 6)) ++# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) ++# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4) ++# endif // defined(__GNUC__) ++# if defined(BOOST_ASIO_MSVC) ++# if (_MSC_VER >= 1700) ++# define BOOST_ASIO_HAS_STD_CHRONO 1 ++# endif // (_MSC_VER >= 1700) ++# endif // defined(BOOST_ASIO_MSVC) ++# endif // !defined(BOOST_ASIO_DISABLE_STD_CHRONO) ++#endif // !defined(BOOST_ASIO_HAS_STD_CHRONO) ++ ++// Boost support for chrono. ++#if !defined(BOOST_ASIO_HAS_BOOST_CHRONO) ++# if !defined(BOOST_ASIO_DISABLE_BOOST_CHRONO) ++# if defined(BOOST_ASIO_HAS_BOOST_CONFIG) && (BOOST_VERSION >= 104700) ++# define BOOST_ASIO_HAS_BOOST_CHRONO 1 ++# endif // defined(BOOST_ASIO_HAS_BOOST_CONFIG) && (BOOST_VERSION >= 104700) ++# endif // !defined(BOOST_ASIO_DISABLE_BOOST_CHRONO) ++#endif // !defined(BOOST_ASIO_HAS_BOOST_CHRONO) ++ ++// Some form of chrono library is available. ++#if !defined(BOOST_ASIO_HAS_CHRONO) ++# if defined(BOOST_ASIO_HAS_STD_CHRONO) \ ++ || defined(BOOST_ASIO_HAS_BOOST_CHRONO) ++# define BOOST_ASIO_HAS_CHRONO 1 ++# endif // defined(BOOST_ASIO_HAS_STD_CHRONO) ++ // || defined(BOOST_ASIO_HAS_BOOST_CHRONO) ++#endif // !defined(BOOST_ASIO_HAS_CHRONO) ++ ++// Boost support for the DateTime library. ++#if !defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) ++# if !defined(BOOST_ASIO_DISABLE_BOOST_DATE_TIME) ++# define BOOST_ASIO_HAS_BOOST_DATE_TIME 1 ++# endif // !defined(BOOST_ASIO_DISABLE_BOOST_DATE_TIME) ++#endif // !defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) ++ ++// Boost support for the Coroutine library. ++#if !defined(BOOST_ASIO_HAS_BOOST_COROUTINE) ++# if !defined(BOOST_ASIO_DISABLE_BOOST_COROUTINE) ++# define BOOST_ASIO_HAS_BOOST_COROUTINE 1 ++# endif // !defined(BOOST_ASIO_DISABLE_BOOST_COROUTINE) ++#endif // !defined(BOOST_ASIO_HAS_BOOST_COROUTINE) ++ ++// Boost support for the Context library's fibers. ++#if !defined(BOOST_ASIO_HAS_BOOST_CONTEXT_FIBER) ++# if !defined(BOOST_ASIO_DISABLE_BOOST_CONTEXT_FIBER) ++# if defined(__clang__) ++# if (__cplusplus >= 201103) ++# define BOOST_ASIO_HAS_BOOST_CONTEXT_FIBER 1 ++# endif // (__cplusplus >= 201103) ++# elif defined(__GNUC__) ++# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4) ++# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) ++# define BOOST_ASIO_HAS_BOOST_CONTEXT_FIBER 1 ++# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) ++# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4) ++# endif // defined(__GNUC__) ++# if defined(BOOST_ASIO_MSVC) ++# if (_MSVC_LANG >= 201103) ++# define BOOST_ASIO_HAS_BOOST_CONTEXT_FIBER 1 ++# endif // (_MSC_LANG >= 201103) ++# endif // defined(BOOST_ASIO_MSVC) ++# endif // !defined(BOOST_ASIO_DISABLE_BOOST_CONTEXT_FIBER) ++#endif // !defined(BOOST_ASIO_HAS_BOOST_CONTEXT_FIBER) ++ ++// Standard library support for addressof. ++#if !defined(BOOST_ASIO_HAS_STD_ADDRESSOF) ++# if !defined(BOOST_ASIO_DISABLE_STD_ADDRESSOF) ++# if defined(__clang__) ++# if defined(BOOST_ASIO_HAS_CLANG_LIBCXX) ++# define BOOST_ASIO_HAS_STD_ADDRESSOF 1 ++# elif (__cplusplus >= 201103) ++# define BOOST_ASIO_HAS_STD_ADDRESSOF 1 ++# endif // (__cplusplus >= 201103) ++# elif defined(__GNUC__) ++# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4) ++# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) ++# define BOOST_ASIO_HAS_STD_ADDRESSOF 1 ++# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) ++# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4) ++# endif // defined(__GNUC__) ++# if defined(BOOST_ASIO_MSVC) ++# if (_MSC_VER >= 1700) ++# define BOOST_ASIO_HAS_STD_ADDRESSOF 1 ++# endif // (_MSC_VER >= 1700) ++# endif // defined(BOOST_ASIO_MSVC) ++# endif // !defined(BOOST_ASIO_DISABLE_STD_ADDRESSOF) ++#endif // !defined(BOOST_ASIO_HAS_STD_ADDRESSOF) ++ ++// Standard library support for the function class. ++#if !defined(BOOST_ASIO_HAS_STD_FUNCTION) ++# if !defined(BOOST_ASIO_DISABLE_STD_FUNCTION) ++# if defined(__clang__) ++# if defined(BOOST_ASIO_HAS_CLANG_LIBCXX) ++# define BOOST_ASIO_HAS_STD_FUNCTION 1 ++# elif (__cplusplus >= 201103) ++# define BOOST_ASIO_HAS_STD_FUNCTION 1 ++# endif // (__cplusplus >= 201103) ++# elif defined(__GNUC__) ++# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) ++# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) ++# define BOOST_ASIO_HAS_STD_FUNCTION 1 ++# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) ++# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) ++# endif // defined(__GNUC__) ++# if defined(BOOST_ASIO_MSVC) ++# if (_MSC_VER >= 1700) ++# define BOOST_ASIO_HAS_STD_FUNCTION 1 ++# endif // (_MSC_VER >= 1700) ++# endif // defined(BOOST_ASIO_MSVC) ++# endif // !defined(BOOST_ASIO_DISABLE_STD_FUNCTION) ++#endif // !defined(BOOST_ASIO_HAS_STD_FUNCTION) ++ ++// Standard library support for the reference_wrapper class. ++#if !defined(BOOST_ASIO_HAS_STD_REFERENCE_WRAPPER) ++# if !defined(BOOST_ASIO_DISABLE_STD_REFERENCE_WRAPPER) ++# if defined(__clang__) ++# if defined(BOOST_ASIO_HAS_CLANG_LIBCXX) ++# define BOOST_ASIO_HAS_STD_REFERENCE_WRAPPER 1 ++# elif (__cplusplus >= 201103) ++# define BOOST_ASIO_HAS_STD_REFERENCE_WRAPPER 1 ++# endif // (__cplusplus >= 201103) ++# elif defined(__GNUC__) ++# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) ++# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) ++# define BOOST_ASIO_HAS_STD_REFERENCE_WRAPPER 1 ++# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) ++# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) ++# endif // defined(__GNUC__) ++# if defined(BOOST_ASIO_MSVC) ++# if (_MSC_VER >= 1700) ++# define BOOST_ASIO_HAS_STD_REFERENCE_WRAPPER 1 ++# endif // (_MSC_VER >= 1700) ++# endif // defined(BOOST_ASIO_MSVC) ++# endif // !defined(BOOST_ASIO_DISABLE_STD_REFERENCE_WRAPPER) ++#endif // !defined(BOOST_ASIO_HAS_STD_REFERENCE_WRAPPER) ++ ++// Standard library support for type traits. ++#if !defined(BOOST_ASIO_HAS_STD_TYPE_TRAITS) ++# if !defined(BOOST_ASIO_DISABLE_STD_TYPE_TRAITS) ++# if defined(__clang__) ++# if defined(BOOST_ASIO_HAS_CLANG_LIBCXX) ++# define BOOST_ASIO_HAS_STD_TYPE_TRAITS 1 ++# elif (__cplusplus >= 201103) ++# if __has_include() ++# define BOOST_ASIO_HAS_STD_TYPE_TRAITS 1 ++# endif // __has_include() ++# endif // (__cplusplus >= 201103) ++# elif defined(__GNUC__) ++# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4) ++# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) ++# define BOOST_ASIO_HAS_STD_TYPE_TRAITS 1 ++# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) ++# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4) ++# endif // defined(__GNUC__) ++# if defined(BOOST_ASIO_MSVC) ++# if (_MSC_VER >= 1700) ++# define BOOST_ASIO_HAS_STD_TYPE_TRAITS 1 ++# endif // (_MSC_VER >= 1700) ++# endif // defined(BOOST_ASIO_MSVC) ++# endif // !defined(BOOST_ASIO_DISABLE_STD_TYPE_TRAITS) ++#endif // !defined(BOOST_ASIO_HAS_STD_TYPE_TRAITS) ++ ++// Standard library support for the nullptr_t type. ++#if !defined(BOOST_ASIO_HAS_NULLPTR) ++# if !defined(BOOST_ASIO_DISABLE_NULLPTR) ++# if defined(__clang__) ++# if __has_feature(__cxx_nullptr__) ++# define BOOST_ASIO_HAS_NULLPTR 1 ++# endif // __has_feature(__cxx_nullptr__) ++# elif defined(__GNUC__) ++# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4) ++# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) ++# define BOOST_ASIO_HAS_NULLPTR 1 ++# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) ++# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4) ++# endif // defined(__GNUC__) ++# if defined(BOOST_ASIO_MSVC) ++# if (_MSC_VER >= 1700) ++# define BOOST_ASIO_HAS_NULLPTR 1 ++# endif // (_MSC_VER >= 1700) ++# endif // defined(BOOST_ASIO_MSVC) ++# endif // !defined(BOOST_ASIO_DISABLE_NULLPTR) ++#endif // !defined(BOOST_ASIO_HAS_NULLPTR) ++ ++// Standard library support for the C++11 allocator additions. ++#if !defined(BOOST_ASIO_HAS_CXX11_ALLOCATORS) ++# if !defined(BOOST_ASIO_DISABLE_CXX11_ALLOCATORS) ++# if defined(__clang__) ++# if defined(BOOST_ASIO_HAS_CLANG_LIBCXX) ++# define BOOST_ASIO_HAS_CXX11_ALLOCATORS 1 ++# elif (__cplusplus >= 201103) ++# define BOOST_ASIO_HAS_CXX11_ALLOCATORS 1 ++# endif // (__cplusplus >= 201103) ++# elif defined(__GNUC__) ++# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) ++# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) ++# define BOOST_ASIO_HAS_CXX11_ALLOCATORS 1 ++# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) ++# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) ++# endif // defined(__GNUC__) ++# if defined(BOOST_ASIO_MSVC) ++# if (_MSC_VER >= 1800) ++# define BOOST_ASIO_HAS_CXX11_ALLOCATORS 1 ++# endif // (_MSC_VER >= 1800) ++# endif // defined(BOOST_ASIO_MSVC) ++# endif // !defined(BOOST_ASIO_DISABLE_CXX11_ALLOCATORS) ++#endif // !defined(BOOST_ASIO_HAS_CXX11_ALLOCATORS) ++ ++// Standard library support for the cstdint header. ++#if !defined(BOOST_ASIO_HAS_CSTDINT) ++# if !defined(BOOST_ASIO_DISABLE_CSTDINT) ++# if defined(__clang__) ++# if defined(BOOST_ASIO_HAS_CLANG_LIBCXX) ++# define BOOST_ASIO_HAS_CSTDINT 1 ++# elif (__cplusplus >= 201103) ++# define BOOST_ASIO_HAS_CSTDINT 1 ++# endif // (__cplusplus >= 201103) ++# elif defined(__GNUC__) ++# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) ++# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) ++# define BOOST_ASIO_HAS_CSTDINT 1 ++# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) ++# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) ++# endif // defined(__GNUC__) ++# if defined(BOOST_ASIO_MSVC) ++# if (_MSC_VER >= 1700) ++# define BOOST_ASIO_HAS_CSTDINT 1 ++# endif // (_MSC_VER >= 1700) ++# endif // defined(BOOST_ASIO_MSVC) ++# endif // !defined(BOOST_ASIO_DISABLE_CSTDINT) ++#endif // !defined(BOOST_ASIO_HAS_CSTDINT) ++ ++// Standard library support for the thread class. ++#if !defined(BOOST_ASIO_HAS_STD_THREAD) ++# if !defined(BOOST_ASIO_DISABLE_STD_THREAD) ++# if defined(__clang__) ++# if defined(BOOST_ASIO_HAS_CLANG_LIBCXX) ++# define BOOST_ASIO_HAS_STD_THREAD 1 ++# elif (__cplusplus >= 201103) ++# if __has_include() ++# define BOOST_ASIO_HAS_STD_THREAD 1 ++# endif // __has_include() ++# endif // (__cplusplus >= 201103) ++# elif defined(__GNUC__) ++# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) ++# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) ++# define BOOST_ASIO_HAS_STD_THREAD 1 ++# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) ++# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) ++# endif // defined(__GNUC__) ++# if defined(BOOST_ASIO_MSVC) ++# if (_MSC_VER >= 1700) ++# define BOOST_ASIO_HAS_STD_THREAD 1 ++# endif // (_MSC_VER >= 1700) ++# endif // defined(BOOST_ASIO_MSVC) ++# endif // !defined(BOOST_ASIO_DISABLE_STD_THREAD) ++#endif // !defined(BOOST_ASIO_HAS_STD_THREAD) ++ ++// Standard library support for the mutex and condition variable classes. ++#if !defined(BOOST_ASIO_HAS_STD_MUTEX_AND_CONDVAR) ++# if !defined(BOOST_ASIO_DISABLE_STD_MUTEX_AND_CONDVAR) ++# if defined(__clang__) ++# if defined(BOOST_ASIO_HAS_CLANG_LIBCXX) ++# define BOOST_ASIO_HAS_STD_MUTEX_AND_CONDVAR 1 ++# elif (__cplusplus >= 201103) ++# if __has_include() ++# define BOOST_ASIO_HAS_STD_MUTEX_AND_CONDVAR 1 ++# endif // __has_include() ++# endif // (__cplusplus >= 201103) ++# elif defined(__GNUC__) ++# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) ++# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) ++# define BOOST_ASIO_HAS_STD_MUTEX_AND_CONDVAR 1 ++# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) ++# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) ++# endif // defined(__GNUC__) ++# if defined(BOOST_ASIO_MSVC) ++# if (_MSC_VER >= 1700) ++# define BOOST_ASIO_HAS_STD_MUTEX_AND_CONDVAR 1 ++# endif // (_MSC_VER >= 1700) ++# endif // defined(BOOST_ASIO_MSVC) ++# endif // !defined(BOOST_ASIO_DISABLE_STD_MUTEX_AND_CONDVAR) ++#endif // !defined(BOOST_ASIO_HAS_STD_MUTEX_AND_CONDVAR) ++ ++// Standard library support for the call_once function. ++#if !defined(BOOST_ASIO_HAS_STD_CALL_ONCE) ++# if !defined(BOOST_ASIO_DISABLE_STD_CALL_ONCE) ++# if defined(__clang__) ++# if defined(BOOST_ASIO_HAS_CLANG_LIBCXX) ++# define BOOST_ASIO_HAS_STD_CALL_ONCE 1 ++# elif (__cplusplus >= 201103) ++# if __has_include() ++# define BOOST_ASIO_HAS_STD_CALL_ONCE 1 ++# endif // __has_include() ++# endif // (__cplusplus >= 201103) ++# elif defined(__GNUC__) ++# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) ++# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) ++# define BOOST_ASIO_HAS_STD_CALL_ONCE 1 ++# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) ++# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) ++# endif // defined(__GNUC__) ++# if defined(BOOST_ASIO_MSVC) ++# if (_MSC_VER >= 1700) ++# define BOOST_ASIO_HAS_STD_CALL_ONCE 1 ++# endif // (_MSC_VER >= 1700) ++# endif // defined(BOOST_ASIO_MSVC) ++# endif // !defined(BOOST_ASIO_DISABLE_STD_CALL_ONCE) ++#endif // !defined(BOOST_ASIO_HAS_STD_CALL_ONCE) ++ ++// Standard library support for futures. ++#if !defined(BOOST_ASIO_HAS_STD_FUTURE) ++# if !defined(BOOST_ASIO_DISABLE_STD_FUTURE) ++# if defined(__clang__) ++# if defined(BOOST_ASIO_HAS_CLANG_LIBCXX) ++# define BOOST_ASIO_HAS_STD_FUTURE 1 ++# elif (__cplusplus >= 201103) ++# if __has_include() ++# define BOOST_ASIO_HAS_STD_FUTURE 1 ++# endif // __has_include() ++# endif // (__cplusplus >= 201103) ++# elif defined(__GNUC__) ++# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) ++# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) ++# define BOOST_ASIO_HAS_STD_FUTURE 1 ++# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) ++# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) ++# endif // defined(__GNUC__) ++# if defined(BOOST_ASIO_MSVC) ++# if (_MSC_VER >= 1700) ++# define BOOST_ASIO_HAS_STD_FUTURE 1 ++# endif // (_MSC_VER >= 1700) ++# endif // defined(BOOST_ASIO_MSVC) ++# endif // !defined(BOOST_ASIO_DISABLE_STD_FUTURE) ++#endif // !defined(BOOST_ASIO_HAS_STD_FUTURE) ++ ++// Standard library support for std::tuple. ++#if !defined(BOOST_ASIO_HAS_STD_TUPLE) ++# if !defined(BOOST_ASIO_DISABLE_STD_TUPLE) ++# if defined(__clang__) ++# if defined(BOOST_ASIO_HAS_CLANG_LIBCXX) ++# define BOOST_ASIO_HAS_STD_TUPLE 1 ++# elif (__cplusplus >= 201103) ++# if __has_include() ++# define BOOST_ASIO_HAS_STD_TUPLE 1 ++# endif // __has_include() ++# endif // (__cplusplus >= 201103) ++# elif defined(__GNUC__) ++# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4) ++# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) ++# define BOOST_ASIO_HAS_STD_TUPLE 1 ++# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) ++# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4) ++# endif // defined(__GNUC__) ++# if defined(BOOST_ASIO_MSVC) ++# if (_MSC_VER >= 1700) ++# define BOOST_ASIO_HAS_STD_TUPLE 1 ++# endif // (_MSC_VER >= 1700) ++# endif // defined(BOOST_ASIO_MSVC) ++# endif // !defined(BOOST_ASIO_DISABLE_STD_TUPLE) ++#endif // !defined(BOOST_ASIO_HAS_STD_TUPLE) ++ ++// Standard library support for std::string_view. ++#if !defined(BOOST_ASIO_HAS_STD_STRING_VIEW) ++# if !defined(BOOST_ASIO_DISABLE_STD_STRING_VIEW) ++# if defined(__clang__) ++# if defined(BOOST_ASIO_HAS_CLANG_LIBCXX) ++# if (__cplusplus >= 201402) ++# if __has_include() ++# define BOOST_ASIO_HAS_STD_STRING_VIEW 1 ++# endif // __has_include() ++# endif // (__cplusplus >= 201402) ++# else // defined(BOOST_ASIO_HAS_CLANG_LIBCXX) ++# if (__cplusplus >= 201703) ++# if __has_include() ++# define BOOST_ASIO_HAS_STD_STRING_VIEW 1 ++# endif // __has_include() ++# endif // (__cplusplus >= 201703) ++# endif // defined(BOOST_ASIO_HAS_CLANG_LIBCXX) ++# elif defined(__GNUC__) ++# if (__GNUC__ >= 7) ++# if (__cplusplus >= 201703) ++# define BOOST_ASIO_HAS_STD_STRING_VIEW 1 ++# endif // (__cplusplus >= 201703) ++# endif // (__GNUC__ >= 7) ++# elif defined(BOOST_ASIO_MSVC) ++# if (_MSC_VER >= 1910 && _MSVC_LANG >= 201703) ++# define BOOST_ASIO_HAS_STD_STRING_VIEW 1 ++# endif // (_MSC_VER >= 1910 && _MSVC_LANG >= 201703) ++# endif // defined(BOOST_ASIO_MSVC) ++# endif // !defined(BOOST_ASIO_DISABLE_STD_STRING_VIEW) ++#endif // !defined(BOOST_ASIO_HAS_STD_STRING_VIEW) ++ ++// Standard library support for std::experimental::string_view. ++#if !defined(BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW) ++# if !defined(BOOST_ASIO_DISABLE_STD_EXPERIMENTAL_STRING_VIEW) ++# if defined(__clang__) ++# if defined(BOOST_ASIO_HAS_CLANG_LIBCXX) ++# if (_LIBCPP_VERSION < 7000) ++# if (__cplusplus >= 201402) ++# if __has_include() ++# define BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW 1 ++# endif // __has_include() ++# endif // (__cplusplus >= 201402) ++# endif // (_LIBCPP_VERSION < 7000) ++# else // defined(BOOST_ASIO_HAS_CLANG_LIBCXX) ++# if (__cplusplus >= 201402) ++# if __has_include() ++# define BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW 1 ++# endif // __has_include() ++# endif // (__cplusplus >= 201402) ++# endif // // defined(BOOST_ASIO_HAS_CLANG_LIBCXX) ++# elif defined(__GNUC__) ++# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 9)) || (__GNUC__ > 4) ++# if (__cplusplus >= 201402) ++# define BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW 1 ++# endif // (__cplusplus >= 201402) ++# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 9)) || (__GNUC__ > 4) ++# endif // defined(__GNUC__) ++# endif // !defined(BOOST_ASIO_DISABLE_STD_EXPERIMENTAL_STRING_VIEW) ++#endif // !defined(BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW) ++ ++// Standard library has a string_view that we can use. ++#if !defined(BOOST_ASIO_HAS_STRING_VIEW) ++# if !defined(BOOST_ASIO_DISABLE_STRING_VIEW) ++# if defined(BOOST_ASIO_HAS_STD_STRING_VIEW) ++# define BOOST_ASIO_HAS_STRING_VIEW 1 ++# elif defined(BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW) ++# define BOOST_ASIO_HAS_STRING_VIEW 1 ++# endif // defined(BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW) ++# endif // !defined(BOOST_ASIO_DISABLE_STRING_VIEW) ++#endif // !defined(BOOST_ASIO_HAS_STRING_VIEW) ++ ++// Standard library support for iostream move construction and assignment. ++#if !defined(BOOST_ASIO_HAS_STD_IOSTREAM_MOVE) ++# if !defined(BOOST_ASIO_DISABLE_STD_IOSTREAM_MOVE) ++# if defined(__clang__) ++# if (__cplusplus >= 201103) ++# define BOOST_ASIO_HAS_STD_IOSTREAM_MOVE 1 ++# endif // (__cplusplus >= 201103) ++# elif defined(__GNUC__) ++# if (__GNUC__ > 4) ++# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) ++# define BOOST_ASIO_HAS_STD_IOSTREAM_MOVE 1 ++# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) ++# endif // (__GNUC__ > 4) ++# elif defined(BOOST_ASIO_MSVC) ++# if (_MSC_VER >= 1700) ++# define BOOST_ASIO_HAS_STD_IOSTREAM_MOVE 1 ++# endif // (_MSC_VER >= 1700) ++# endif // defined(BOOST_ASIO_MSVC) ++# endif // !defined(BOOST_ASIO_DISABLE_STD_IOSTREAM_MOVE) ++#endif // !defined(BOOST_ASIO_HAS_STD_IOSTREAM_MOVE) ++ ++// Standard library has invoke_result (which supersedes result_of). ++#if !defined(BOOST_ASIO_HAS_STD_INVOKE_RESULT) ++# if !defined(BOOST_ASIO_DISABLE_STD_INVOKE_RESULT) ++# if defined(BOOST_ASIO_MSVC) ++# if (_MSC_VER >= 1911 && _MSVC_LANG >= 201703) ++# define BOOST_ASIO_HAS_STD_INVOKE_RESULT 1 ++# endif // (_MSC_VER >= 1911 && _MSVC_LANG >= 201703) ++# else // defined(BOOST_ASIO_MSVC) ++# if (__cplusplus >= 201703) ++# define BOOST_ASIO_HAS_STD_INVOKE_RESULT 1 ++# endif // (__cplusplus >= 201703) ++# endif // defined(BOOST_ASIO_MSVC) ++# endif // !defined(BOOST_ASIO_DISABLE_STD_INVOKE_RESULT) ++#endif // !defined(BOOST_ASIO_HAS_STD_INVOKE_RESULT) ++ ++// Standard library support for std::exception_ptr and std::current_exception. ++#if !defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR) ++# if !defined(BOOST_ASIO_DISABLE_STD_EXCEPTION_PTR) ++# if defined(__clang__) ++# if defined(BOOST_ASIO_HAS_CLANG_LIBCXX) ++# define BOOST_ASIO_HAS_STD_EXCEPTION_PTR 1 ++# elif (__cplusplus >= 201103) ++# define BOOST_ASIO_HAS_STD_EXCEPTION_PTR 1 ++# endif // (__cplusplus >= 201103) ++# elif defined(__GNUC__) ++# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) ++# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) ++# define BOOST_ASIO_HAS_STD_EXCEPTION_PTR 1 ++# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) ++# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) ++# endif // defined(__GNUC__) ++# if defined(BOOST_ASIO_MSVC) ++# if (_MSC_VER >= 1800) ++# define BOOST_ASIO_HAS_STD_EXCEPTION_PTR 1 ++# endif // (_MSC_VER >= 1800) ++# endif // defined(BOOST_ASIO_MSVC) ++# endif // !defined(BOOST_ASIO_DISABLE_STD_EXCEPTION_PTR) ++#endif // !defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR) ++ ++// Standard library support for std::nested_exception. ++#if !defined(BOOST_ASIO_HAS_STD_NESTED_EXCEPTION) ++# if !defined(BOOST_ASIO_DISABLE_STD_NESTED_EXCEPTION) ++# if defined(__clang__) ++# if defined(BOOST_ASIO_HAS_CLANG_LIBCXX) ++# define BOOST_ASIO_HAS_STD_NESTED_EXCEPTION 1 ++# elif (__cplusplus >= 201103) ++# define BOOST_ASIO_HAS_STD_NESTED_EXCEPTION 1 ++# endif // (__cplusplus >= 201103) ++# elif defined(__GNUC__) ++# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) ++# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) ++# define BOOST_ASIO_HAS_STD_NESTED_EXCEPTION 1 ++# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) ++# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) ++# endif // defined(__GNUC__) ++# if defined(BOOST_ASIO_MSVC) ++# if (_MSC_VER >= 1900) ++# define BOOST_ASIO_HAS_STD_NESTED_EXCEPTION 1 ++# endif // (_MSC_VER >= 1900) ++# endif // defined(BOOST_ASIO_MSVC) ++# endif // !defined(BOOST_ASIO_DISABLE_STD_NESTED_EXCEPTION) ++#endif // !defined(BOOST_ASIO_HAS_STD_NESTED_EXCEPTION) ++ ++// Standard library support for std::any. ++#if !defined(BOOST_ASIO_HAS_STD_ANY) ++# if !defined(BOOST_ASIO_DISABLE_STD_ANY) ++# if defined(__clang__) ++# if (__cplusplus >= 201703) ++# if __has_include() ++# define BOOST_ASIO_HAS_STD_ANY 1 ++# endif // __has_include() ++# endif // (__cplusplus >= 201703) ++# elif defined(__GNUC__) ++# if (__GNUC__ >= 7) ++# if (__cplusplus >= 201703) ++# define BOOST_ASIO_HAS_STD_ANY 1 ++# endif // (__cplusplus >= 201703) ++# endif // (__GNUC__ >= 7) ++# endif // defined(__GNUC__) ++# if defined(BOOST_ASIO_MSVC) ++# if (_MSC_VER >= 1910) && (_MSVC_LANG >= 201703) ++# define BOOST_ASIO_HAS_STD_ANY 1 ++# endif // (_MSC_VER >= 1910) && (_MSVC_LANG >= 201703) ++# endif // defined(BOOST_ASIO_MSVC) ++# endif // !defined(BOOST_ASIO_DISABLE_STD_ANY) ++#endif // !defined(BOOST_ASIO_HAS_STD_ANY) ++ ++// Standard library support for std::variant. ++#if !defined(BOOST_ASIO_HAS_STD_VARIANT) ++# if !defined(BOOST_ASIO_DISABLE_STD_VARIANT) ++# if defined(__clang__) ++# if (__cplusplus >= 201703) ++# if __has_include() ++# define BOOST_ASIO_HAS_STD_VARIANT 1 ++# endif // __has_include() ++# endif // (__cplusplus >= 201703) ++# elif defined(__GNUC__) ++# if (__GNUC__ >= 7) ++# if (__cplusplus >= 201703) ++# define BOOST_ASIO_HAS_STD_VARIANT 1 ++# endif // (__cplusplus >= 201703) ++# endif // (__GNUC__ >= 7) ++# endif // defined(__GNUC__) ++# if defined(BOOST_ASIO_MSVC) ++# if (_MSC_VER >= 1910) && (_MSVC_LANG >= 201703) ++# define BOOST_ASIO_HAS_STD_VARIANT 1 ++# endif // (_MSC_VER >= 1910) && (_MSVC_LANG >= 201703) ++# endif // defined(BOOST_ASIO_MSVC) ++# endif // !defined(BOOST_ASIO_DISABLE_STD_VARIANT) ++#endif // !defined(BOOST_ASIO_HAS_STD_VARIANT) ++ ++// Standard library support for std::source_location. ++#if !defined(BOOST_ASIO_HAS_STD_SOURCE_LOCATION) ++# if !defined(BOOST_ASIO_DISABLE_STD_SOURCE_LOCATION) ++// ... ++# endif // !defined(BOOST_ASIO_DISABLE_STD_SOURCE_LOCATION) ++#endif // !defined(BOOST_ASIO_HAS_STD_SOURCE_LOCATION) ++ ++// Standard library support for std::experimental::source_location. ++#if !defined(BOOST_ASIO_HAS_STD_EXPERIMENTAL_SOURCE_LOCATION) ++# if !defined(BOOST_ASIO_DISABLE_STD_EXPERIMENTAL_SOURCE_LOCATION) ++# if defined(__GNUC__) ++# if (__cplusplus >= 201709) ++# if __has_include() ++# define BOOST_ASIO_HAS_STD_EXPERIMENTAL_SOURCE_LOCATION 1 ++# endif // __has_include() ++# endif // (__cplusplus >= 201709) ++# endif // defined(__GNUC__) ++# endif // !defined(BOOST_ASIO_DISABLE_STD_EXPERIMENTAL_SOURCE_LOCATION) ++#endif // !defined(BOOST_ASIO_HAS_STD_EXPERIMENTAL_SOURCE_LOCATION) ++ ++// Standard library has a source_location that we can use. ++#if !defined(BOOST_ASIO_HAS_SOURCE_LOCATION) ++# if !defined(BOOST_ASIO_DISABLE_SOURCE_LOCATION) ++# if defined(BOOST_ASIO_HAS_STD_SOURCE_LOCATION) ++# define BOOST_ASIO_HAS_SOURCE_LOCATION 1 ++# elif defined(BOOST_ASIO_HAS_STD_EXPERIMENTAL_SOURCE_LOCATION) ++# define BOOST_ASIO_HAS_SOURCE_LOCATION 1 ++# endif // defined(BOOST_ASIO_HAS_STD_EXPERIMENTAL_SOURCE_LOCATION) ++# endif // !defined(BOOST_ASIO_DISABLE_SOURCE_LOCATION) ++#endif // !defined(BOOST_ASIO_HAS_SOURCE_LOCATION) ++ ++// Boost support for source_location and system errors. ++#if !defined(BOOST_ASIO_HAS_BOOST_SOURCE_LOCATION) ++# if !defined(BOOST_ASIO_DISABLE_BOOST_SOURCE_LOCATION) ++# if defined(BOOST_ASIO_HAS_BOOST_CONFIG) && (BOOST_VERSION >= 107900) ++# define BOOST_ASIO_HAS_BOOST_SOURCE_LOCATION 1 ++# endif // defined(BOOST_ASIO_HAS_BOOST_CONFIG) && (BOOST_VERSION >= 107900) ++# endif // !defined(BOOST_ASIO_DISABLE_BOOST_SOURCE_LOCATION) ++#endif // !defined(BOOST_ASIO_HAS_BOOST_SOURCE_LOCATION) ++ ++// Helper macros for working with Boost source locations. ++#if defined(BOOST_ASIO_HAS_BOOST_SOURCE_LOCATION) ++# define BOOST_ASIO_SOURCE_LOCATION_PARAM \ ++ , const boost::source_location& loc ++# define BOOST_ASIO_SOURCE_LOCATION_DEFAULTED_PARAM \ ++ , const boost::source_location& loc = BOOST_CURRENT_LOCATION ++# define BOOST_ASIO_SOURCE_LOCATION_ARG , loc ++#else // if defined(BOOST_ASIO_HAS_BOOST_SOURCE_LOCATION) ++# define BOOST_ASIO_SOURCE_LOCATION_PARAM ++# define BOOST_ASIO_SOURCE_LOCATION_DEFAULTED_PARAM ++# define BOOST_ASIO_SOURCE_LOCATION_ARG ++#endif // if defined(BOOST_ASIO_HAS_BOOST_SOURCE_LOCATION) ++ ++// Standard library support for std::index_sequence. ++#if !defined(BOOST_ASIO_HAS_STD_INDEX_SEQUENCE) ++# if !defined(BOOST_ASIO_DISABLE_STD_INDEX_SEQUENCE) ++# if defined(__clang__) ++# if (__cplusplus >= 201402) ++# define BOOST_ASIO_HAS_STD_INDEX_SEQUENCE 1 ++# endif // (__cplusplus >= 201402) ++# elif defined(__GNUC__) ++# if (__GNUC__ >= 7) ++# if (__cplusplus >= 201402) ++# define BOOST_ASIO_HAS_STD_INDEX_SEQUENCE 1 ++# endif // (__cplusplus >= 201402) ++# endif // (__GNUC__ >= 7) ++# endif // defined(__GNUC__) ++# if defined(BOOST_ASIO_MSVC) ++# if (_MSC_VER >= 1910) && (_MSVC_LANG >= 201402) ++# define BOOST_ASIO_HAS_STD_INDEX_SEQUENCE 1 ++# endif // (_MSC_VER >= 1910) && (_MSVC_LANG >= 201402) ++# endif // defined(BOOST_ASIO_MSVC) ++# endif // !defined(BOOST_ASIO_DISABLE_STD_INDEX_SEQUENCE) ++#endif // !defined(BOOST_ASIO_HAS_STD_INDEX_SEQUENCE) ++ ++// Windows App target. Windows but with a limited API. ++#if !defined(BOOST_ASIO_WINDOWS_APP) ++# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0603) ++# include ++# if (WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) \ ++ || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_TV_TITLE)) \ ++ && !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) ++# define BOOST_ASIO_WINDOWS_APP 1 ++# endif // WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) ++ // && !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) ++# endif // defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0603) ++#endif // !defined(BOOST_ASIO_WINDOWS_APP) ++ ++// Legacy WinRT target. Windows App is preferred. ++#if !defined(BOOST_ASIO_WINDOWS_RUNTIME) ++# if !defined(BOOST_ASIO_WINDOWS_APP) ++# if defined(__cplusplus_winrt) ++# include ++# if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) \ ++ && !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) ++# define BOOST_ASIO_WINDOWS_RUNTIME 1 ++# endif // WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) ++ // && !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) ++# endif // defined(__cplusplus_winrt) ++# endif // !defined(BOOST_ASIO_WINDOWS_APP) ++#endif // !defined(BOOST_ASIO_WINDOWS_RUNTIME) ++ ++// Windows target. Excludes WinRT but includes Windows App targets. ++#if !defined(BOOST_ASIO_WINDOWS) ++# if !defined(BOOST_ASIO_WINDOWS_RUNTIME) ++# if defined(BOOST_ASIO_HAS_BOOST_CONFIG) && defined(BOOST_WINDOWS) ++# define BOOST_ASIO_WINDOWS 1 ++# elif defined(WIN32) || defined(_WIN32) || defined(__WIN32__) ++# define BOOST_ASIO_WINDOWS 1 ++# elif defined(BOOST_ASIO_WINDOWS_APP) ++# define BOOST_ASIO_WINDOWS 1 ++# endif // defined(BOOST_ASIO_HAS_BOOST_CONFIG) && defined(BOOST_WINDOWS) ++# endif // !defined(BOOST_ASIO_WINDOWS_RUNTIME) ++#endif // !defined(BOOST_ASIO_WINDOWS) ++ ++// Windows: target OS version. ++#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) ++# if !defined(_WIN32_WINNT) && !defined(_WIN32_WINDOWS) ++# if defined(_MSC_VER) || (defined(__BORLANDC__) && !defined(__clang__)) ++# pragma message( \ ++ "Please define _WIN32_WINNT or _WIN32_WINDOWS appropriately. For example:\n"\ ++ "- add -D_WIN32_WINNT=0x0601 to the compiler command line; or\n"\ ++ "- add _WIN32_WINNT=0x0601 to your project's Preprocessor Definitions.\n"\ ++ "Assuming _WIN32_WINNT=0x0601 (i.e. Windows 7 target).") ++# else // defined(_MSC_VER) || (defined(__BORLANDC__) && !defined(__clang__)) ++# warning Please define _WIN32_WINNT or _WIN32_WINDOWS appropriately. ++# warning For example, add -D_WIN32_WINNT=0x0601 to the compiler command line. ++# warning Assuming _WIN32_WINNT=0x0601 (i.e. Windows 7 target). ++# endif // defined(_MSC_VER) || (defined(__BORLANDC__) && !defined(__clang__)) ++# define _WIN32_WINNT 0x0601 ++# endif // !defined(_WIN32_WINNT) && !defined(_WIN32_WINDOWS) ++# if defined(_MSC_VER) ++# if defined(_WIN32) && !defined(WIN32) ++# if !defined(_WINSOCK2API_) ++# define WIN32 // Needed for correct types in winsock2.h ++# else // !defined(_WINSOCK2API_) ++# error Please define the macro WIN32 in your compiler options ++# endif // !defined(_WINSOCK2API_) ++# endif // defined(_WIN32) && !defined(WIN32) ++# endif // defined(_MSC_VER) ++# if defined(__BORLANDC__) ++# if defined(__WIN32__) && !defined(WIN32) ++# if !defined(_WINSOCK2API_) ++# define WIN32 // Needed for correct types in winsock2.h ++# else // !defined(_WINSOCK2API_) ++# error Please define the macro WIN32 in your compiler options ++# endif // !defined(_WINSOCK2API_) ++# endif // defined(__WIN32__) && !defined(WIN32) ++# endif // defined(__BORLANDC__) ++# if defined(__CYGWIN__) ++# if !defined(__USE_W32_SOCKETS) ++# error You must add -D__USE_W32_SOCKETS to your compiler options. ++# endif // !defined(__USE_W32_SOCKETS) ++# endif // defined(__CYGWIN__) ++#endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) ++ ++// Windows: minimise header inclusion. ++#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) ++# if !defined(BOOST_ASIO_NO_WIN32_LEAN_AND_MEAN) ++# if !defined(WIN32_LEAN_AND_MEAN) ++# define WIN32_LEAN_AND_MEAN ++# endif // !defined(WIN32_LEAN_AND_MEAN) ++# endif // !defined(BOOST_ASIO_NO_WIN32_LEAN_AND_MEAN) ++#endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) ++ ++// Windows: suppress definition of "min" and "max" macros. ++#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) ++# if !defined(BOOST_ASIO_NO_NOMINMAX) ++# if !defined(NOMINMAX) ++# define NOMINMAX 1 ++# endif // !defined(NOMINMAX) ++# endif // !defined(BOOST_ASIO_NO_NOMINMAX) ++#endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) ++ ++// Windows: IO Completion Ports. ++#if !defined(BOOST_ASIO_HAS_IOCP) ++# if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) ++# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0400) ++# if !defined(UNDER_CE) && !defined(BOOST_ASIO_WINDOWS_APP) ++# if !defined(BOOST_ASIO_DISABLE_IOCP) ++# define BOOST_ASIO_HAS_IOCP 1 ++# endif // !defined(BOOST_ASIO_DISABLE_IOCP) ++# endif // !defined(UNDER_CE) && !defined(BOOST_ASIO_WINDOWS_APP) ++# endif // defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0400) ++# endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) ++#endif // !defined(BOOST_ASIO_HAS_IOCP) ++ ++// On POSIX (and POSIX-like) platforms we need to include unistd.h in order to ++// get access to the various platform feature macros, e.g. to be able to test ++// for threads support. ++#if !defined(BOOST_ASIO_HAS_UNISTD_H) ++# if !defined(BOOST_ASIO_HAS_BOOST_CONFIG) ++# if defined(unix) \ ++ || defined(__unix) \ ++ || defined(_XOPEN_SOURCE) \ ++ || defined(_POSIX_SOURCE) \ ++ || (defined(__MACH__) && defined(__APPLE__)) \ ++ || defined(__FreeBSD__) \ ++ || defined(__NetBSD__) \ ++ || defined(__OpenBSD__) \ ++ || defined(__linux__) \ ++ || defined(__HAIKU__) ++# define BOOST_ASIO_HAS_UNISTD_H 1 ++# endif ++# endif // !defined(BOOST_ASIO_HAS_BOOST_CONFIG) ++#endif // !defined(BOOST_ASIO_HAS_UNISTD_H) ++#if defined(BOOST_ASIO_HAS_UNISTD_H) ++# include ++#endif // defined(BOOST_ASIO_HAS_UNISTD_H) ++ ++// Linux: epoll, eventfd and timerfd. ++#if defined(__linux__) ++# include ++# if !defined(BOOST_ASIO_HAS_EPOLL) ++# if !defined(BOOST_ASIO_DISABLE_EPOLL) ++# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,45) ++# define BOOST_ASIO_HAS_EPOLL 1 ++# endif // LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,45) ++# endif // !defined(BOOST_ASIO_DISABLE_EPOLL) ++# endif // !defined(BOOST_ASIO_HAS_EPOLL) ++# if !defined(BOOST_ASIO_HAS_EVENTFD) ++# if !defined(BOOST_ASIO_DISABLE_EVENTFD) ++# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22) ++# define BOOST_ASIO_HAS_EVENTFD 1 ++# endif // LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22) ++# endif // !defined(BOOST_ASIO_DISABLE_EVENTFD) ++# endif // !defined(BOOST_ASIO_HAS_EVENTFD) ++# if !defined(BOOST_ASIO_HAS_TIMERFD) ++# if defined(BOOST_ASIO_HAS_EPOLL) ++# if (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 8) ++# define BOOST_ASIO_HAS_TIMERFD 1 ++# endif // (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 8) ++# endif // defined(BOOST_ASIO_HAS_EPOLL) ++# endif // !defined(BOOST_ASIO_HAS_TIMERFD) ++#endif // defined(__linux__) ++ ++// Linux: io_uring is used instead of epoll. ++#if !defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT) ++# if !defined(BOOST_ASIO_HAS_EPOLL) && defined(BOOST_ASIO_HAS_IO_URING) ++# define BOOST_ASIO_HAS_IO_URING_AS_DEFAULT 1 ++# endif // !defined(BOOST_ASIO_HAS_EPOLL) && defined(BOOST_ASIO_HAS_IO_URING) ++#endif // !defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT) ++ ++// Mac OS X, FreeBSD, NetBSD, OpenBSD: kqueue. ++#if (defined(__MACH__) && defined(__APPLE__)) \ ++ || defined(__FreeBSD__) \ ++ || defined(__NetBSD__) \ ++ || defined(__OpenBSD__) ++# if !defined(BOOST_ASIO_HAS_KQUEUE) ++# if !defined(BOOST_ASIO_DISABLE_KQUEUE) ++# define BOOST_ASIO_HAS_KQUEUE 1 ++# endif // !defined(BOOST_ASIO_DISABLE_KQUEUE) ++# endif // !defined(BOOST_ASIO_HAS_KQUEUE) ++#endif // (defined(__MACH__) && defined(__APPLE__)) ++ // || defined(__FreeBSD__) ++ // || defined(__NetBSD__) ++ // || defined(__OpenBSD__) ++ ++// Solaris: /dev/poll. ++#if defined(__sun) ++# if !defined(BOOST_ASIO_HAS_DEV_POLL) ++# if !defined(BOOST_ASIO_DISABLE_DEV_POLL) ++# define BOOST_ASIO_HAS_DEV_POLL 1 ++# endif // !defined(BOOST_ASIO_DISABLE_DEV_POLL) ++# endif // !defined(BOOST_ASIO_HAS_DEV_POLL) ++#endif // defined(__sun) ++ ++// Serial ports. ++#if !defined(BOOST_ASIO_HAS_SERIAL_PORT) ++# if defined(BOOST_ASIO_HAS_IOCP) \ ++ || !defined(BOOST_ASIO_WINDOWS) \ ++ && !defined(BOOST_ASIO_WINDOWS_RUNTIME) \ ++ && !defined(__CYGWIN__) ++# if !defined(__SYMBIAN32__) ++# if !defined(BOOST_ASIO_DISABLE_SERIAL_PORT) ++# define BOOST_ASIO_HAS_SERIAL_PORT 1 ++# endif // !defined(BOOST_ASIO_DISABLE_SERIAL_PORT) ++# endif // !defined(__SYMBIAN32__) ++# endif // defined(BOOST_ASIO_HAS_IOCP) ++ // || !defined(BOOST_ASIO_WINDOWS) ++ // && !defined(BOOST_ASIO_WINDOWS_RUNTIME) ++ // && !defined(__CYGWIN__) ++#endif // !defined(BOOST_ASIO_HAS_SERIAL_PORT) ++ ++// Windows: stream handles. ++#if !defined(BOOST_ASIO_HAS_WINDOWS_STREAM_HANDLE) ++# if !defined(BOOST_ASIO_DISABLE_WINDOWS_STREAM_HANDLE) ++# if defined(BOOST_ASIO_HAS_IOCP) ++# define BOOST_ASIO_HAS_WINDOWS_STREAM_HANDLE 1 ++# endif // defined(BOOST_ASIO_HAS_IOCP) ++# endif // !defined(BOOST_ASIO_DISABLE_WINDOWS_STREAM_HANDLE) ++#endif // !defined(BOOST_ASIO_HAS_WINDOWS_STREAM_HANDLE) ++ ++// Windows: random access handles. ++#if !defined(BOOST_ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) ++# if !defined(BOOST_ASIO_DISABLE_WINDOWS_RANDOM_ACCESS_HANDLE) ++# if defined(BOOST_ASIO_HAS_IOCP) ++# define BOOST_ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE 1 ++# endif // defined(BOOST_ASIO_HAS_IOCP) ++# endif // !defined(BOOST_ASIO_DISABLE_WINDOWS_RANDOM_ACCESS_HANDLE) ++#endif // !defined(BOOST_ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) ++ ++// Windows: object handles. ++#if !defined(BOOST_ASIO_HAS_WINDOWS_OBJECT_HANDLE) ++# if !defined(BOOST_ASIO_DISABLE_WINDOWS_OBJECT_HANDLE) ++# if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) ++# if !defined(UNDER_CE) && !defined(BOOST_ASIO_WINDOWS_APP) ++# define BOOST_ASIO_HAS_WINDOWS_OBJECT_HANDLE 1 ++# endif // !defined(UNDER_CE) && !defined(BOOST_ASIO_WINDOWS_APP) ++# endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) ++# endif // !defined(BOOST_ASIO_DISABLE_WINDOWS_OBJECT_HANDLE) ++#endif // !defined(BOOST_ASIO_HAS_WINDOWS_OBJECT_HANDLE) ++ ++// Windows: OVERLAPPED wrapper. ++#if !defined(BOOST_ASIO_HAS_WINDOWS_OVERLAPPED_PTR) ++# if !defined(BOOST_ASIO_DISABLE_WINDOWS_OVERLAPPED_PTR) ++# if defined(BOOST_ASIO_HAS_IOCP) ++# define BOOST_ASIO_HAS_WINDOWS_OVERLAPPED_PTR 1 ++# endif // defined(BOOST_ASIO_HAS_IOCP) ++# endif // !defined(BOOST_ASIO_DISABLE_WINDOWS_OVERLAPPED_PTR) ++#endif // !defined(BOOST_ASIO_HAS_WINDOWS_OVERLAPPED_PTR) ++ ++// POSIX: stream-oriented file descriptors. ++#if !defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR) ++# if !defined(BOOST_ASIO_DISABLE_POSIX_STREAM_DESCRIPTOR) ++# if !defined(BOOST_ASIO_WINDOWS) \ ++ && !defined(BOOST_ASIO_WINDOWS_RUNTIME) \ ++ && !defined(__CYGWIN__) ++# define BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR 1 ++# endif // !defined(BOOST_ASIO_WINDOWS) ++ // && !defined(BOOST_ASIO_WINDOWS_RUNTIME) ++ // && !defined(__CYGWIN__) ++# endif // !defined(BOOST_ASIO_DISABLE_POSIX_STREAM_DESCRIPTOR) ++#endif // !defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR) ++ ++// UNIX domain sockets. ++#if !defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) ++# if !defined(BOOST_ASIO_DISABLE_LOCAL_SOCKETS) ++# if !defined(BOOST_ASIO_WINDOWS_RUNTIME) ++# define BOOST_ASIO_HAS_LOCAL_SOCKETS 1 ++# endif // !defined(BOOST_ASIO_WINDOWS_RUNTIME) ++# endif // !defined(BOOST_ASIO_DISABLE_LOCAL_SOCKETS) ++#endif // !defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) ++ ++// Files. ++#if !defined(BOOST_ASIO_HAS_FILE) ++# if !defined(BOOST_ASIO_DISABLE_FILE) ++# if defined(BOOST_ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) ++# define BOOST_ASIO_HAS_FILE 1 ++# elif defined(BOOST_ASIO_HAS_IO_URING) ++# define BOOST_ASIO_HAS_FILE 1 ++# endif // defined(BOOST_ASIO_HAS_IO_URING) ++# endif // !defined(BOOST_ASIO_DISABLE_FILE) ++#endif // !defined(BOOST_ASIO_HAS_FILE) ++ ++// Pipes. ++#if !defined(BOOST_ASIO_HAS_PIPE) ++# if defined(BOOST_ASIO_HAS_IOCP) \ ++ || !defined(BOOST_ASIO_WINDOWS) \ ++ && !defined(BOOST_ASIO_WINDOWS_RUNTIME) \ ++ && !defined(__CYGWIN__) ++# if !defined(__SYMBIAN32__) ++# if !defined(BOOST_ASIO_DISABLE_PIPE) ++# define BOOST_ASIO_HAS_PIPE 1 ++# endif // !defined(BOOST_ASIO_DISABLE_PIPE) ++# endif // !defined(__SYMBIAN32__) ++# endif // defined(BOOST_ASIO_HAS_IOCP) ++ // || !defined(BOOST_ASIO_WINDOWS) ++ // && !defined(BOOST_ASIO_WINDOWS_RUNTIME) ++ // && !defined(__CYGWIN__) ++#endif // !defined(BOOST_ASIO_HAS_PIPE) ++ ++// Can use sigaction() instead of signal(). ++#if !defined(BOOST_ASIO_HAS_SIGACTION) ++# if !defined(BOOST_ASIO_DISABLE_SIGACTION) ++# if !defined(BOOST_ASIO_WINDOWS) \ ++ && !defined(BOOST_ASIO_WINDOWS_RUNTIME) \ ++ && !defined(__CYGWIN__) ++# define BOOST_ASIO_HAS_SIGACTION 1 ++# endif // !defined(BOOST_ASIO_WINDOWS) ++ // && !defined(BOOST_ASIO_WINDOWS_RUNTIME) ++ // && !defined(__CYGWIN__) ++# endif // !defined(BOOST_ASIO_DISABLE_SIGACTION) ++#endif // !defined(BOOST_ASIO_HAS_SIGACTION) ++ ++// Can use signal(). ++#if !defined(BOOST_ASIO_HAS_SIGNAL) ++# if !defined(BOOST_ASIO_DISABLE_SIGNAL) ++# if !defined(UNDER_CE) ++# define BOOST_ASIO_HAS_SIGNAL 1 ++# endif // !defined(UNDER_CE) ++# endif // !defined(BOOST_ASIO_DISABLE_SIGNAL) ++#endif // !defined(BOOST_ASIO_HAS_SIGNAL) ++ ++// Can use getaddrinfo() and getnameinfo(). ++#if !defined(BOOST_ASIO_HAS_GETADDRINFO) ++# if !defined(BOOST_ASIO_DISABLE_GETADDRINFO) ++# if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) ++# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501) ++# define BOOST_ASIO_HAS_GETADDRINFO 1 ++# elif defined(UNDER_CE) ++# define BOOST_ASIO_HAS_GETADDRINFO 1 ++# endif // defined(UNDER_CE) ++# elif defined(__MACH__) && defined(__APPLE__) ++# if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) ++# if (__MAC_OS_X_VERSION_MIN_REQUIRED >= 1050) ++# define BOOST_ASIO_HAS_GETADDRINFO 1 ++# endif // (__MAC_OS_X_VERSION_MIN_REQUIRED >= 1050) ++# else // defined(__MAC_OS_X_VERSION_MIN_REQUIRED) ++# define BOOST_ASIO_HAS_GETADDRINFO 1 ++# endif // defined(__MAC_OS_X_VERSION_MIN_REQUIRED) ++# else // defined(__MACH__) && defined(__APPLE__) ++# define BOOST_ASIO_HAS_GETADDRINFO 1 ++# endif // defined(__MACH__) && defined(__APPLE__) ++# endif // !defined(BOOST_ASIO_DISABLE_GETADDRINFO) ++#endif // !defined(BOOST_ASIO_HAS_GETADDRINFO) ++ ++// Whether standard iostreams are disabled. ++#if !defined(BOOST_ASIO_NO_IOSTREAM) ++# if defined(BOOST_ASIO_HAS_BOOST_CONFIG) && defined(BOOST_NO_IOSTREAM) ++# define BOOST_ASIO_NO_IOSTREAM 1 ++# endif // !defined(BOOST_NO_IOSTREAM) ++#endif // !defined(BOOST_ASIO_NO_IOSTREAM) ++ ++// Whether exception handling is disabled. ++#if !defined(BOOST_ASIO_NO_EXCEPTIONS) ++# if defined(BOOST_ASIO_HAS_BOOST_CONFIG) && defined(BOOST_NO_EXCEPTIONS) ++# define BOOST_ASIO_NO_EXCEPTIONS 1 ++# endif // !defined(BOOST_NO_EXCEPTIONS) ++#endif // !defined(BOOST_ASIO_NO_EXCEPTIONS) ++ ++// Whether the typeid operator is supported. ++#if !defined(BOOST_ASIO_NO_TYPEID) ++# if defined(BOOST_ASIO_HAS_BOOST_CONFIG) && defined(BOOST_NO_TYPEID) ++# define BOOST_ASIO_NO_TYPEID 1 ++# endif // !defined(BOOST_NO_TYPEID) ++#endif // !defined(BOOST_ASIO_NO_TYPEID) ++ ++// Threads. ++#if !defined(BOOST_ASIO_HAS_THREADS) ++# if !defined(BOOST_ASIO_DISABLE_THREADS) ++# if defined(BOOST_ASIO_HAS_BOOST_CONFIG) && defined(BOOST_HAS_THREADS) ++# define BOOST_ASIO_HAS_THREADS 1 ++# elif defined(__GNUC__) && !defined(__MINGW32__) \ ++ && !defined(linux) && !defined(__linux) && !defined(__linux__) ++# define BOOST_ASIO_HAS_THREADS 1 ++# elif defined(_MT) || defined(__MT__) ++# define BOOST_ASIO_HAS_THREADS 1 ++# elif defined(_REENTRANT) ++# define BOOST_ASIO_HAS_THREADS 1 ++# elif defined(__APPLE__) ++# define BOOST_ASIO_HAS_THREADS 1 ++# elif defined(__HAIKU__) ++# define BOOST_ASIO_HAS_THREADS 1 ++# elif defined(_POSIX_THREADS) && (_POSIX_THREADS + 0 >= 0) ++# define BOOST_ASIO_HAS_THREADS 1 ++# elif defined(_PTHREADS) ++# define BOOST_ASIO_HAS_THREADS 1 ++# endif // defined(BOOST_ASIO_HAS_BOOST_CONFIG) && defined(BOOST_HAS_THREADS) ++# endif // !defined(BOOST_ASIO_DISABLE_THREADS) ++#endif // !defined(BOOST_ASIO_HAS_THREADS) ++ ++// POSIX threads. ++#if !defined(BOOST_ASIO_HAS_PTHREADS) ++# if defined(BOOST_ASIO_HAS_THREADS) ++# if defined(BOOST_ASIO_HAS_BOOST_CONFIG) && defined(BOOST_HAS_PTHREADS) ++# define BOOST_ASIO_HAS_PTHREADS 1 ++# elif defined(_POSIX_THREADS) && (_POSIX_THREADS + 0 >= 0) ++# define BOOST_ASIO_HAS_PTHREADS 1 ++# elif defined(__HAIKU__) ++# define BOOST_ASIO_HAS_PTHREADS 1 ++# endif // defined(BOOST_ASIO_HAS_BOOST_CONFIG) && defined(BOOST_HAS_PTHREADS) ++# endif // defined(BOOST_ASIO_HAS_THREADS) ++#endif // !defined(BOOST_ASIO_HAS_PTHREADS) ++ ++// Helper to prevent macro expansion. ++#define BOOST_ASIO_PREVENT_MACRO_SUBSTITUTION ++ ++// Helper to define in-class constants. ++#if !defined(BOOST_ASIO_STATIC_CONSTANT) ++# if !defined(BOOST_ASIO_DISABLE_BOOST_STATIC_CONSTANT) ++# define BOOST_ASIO_STATIC_CONSTANT(type, assignment) \ ++ BOOST_STATIC_CONSTANT(type, assignment) ++# else // !defined(BOOST_ASIO_DISABLE_BOOST_STATIC_CONSTANT) ++# define BOOST_ASIO_STATIC_CONSTANT(type, assignment) \ ++ static const type assignment ++# endif // !defined(BOOST_ASIO_DISABLE_BOOST_STATIC_CONSTANT) ++#endif // !defined(BOOST_ASIO_STATIC_CONSTANT) ++ ++// Boost align library. ++#if !defined(BOOST_ASIO_HAS_BOOST_ALIGN) ++# if !defined(BOOST_ASIO_DISABLE_BOOST_ALIGN) ++# if defined(BOOST_ASIO_HAS_BOOST_CONFIG) && (BOOST_VERSION >= 105600) ++# define BOOST_ASIO_HAS_BOOST_ALIGN 1 ++# endif // defined(BOOST_ASIO_HAS_BOOST_CONFIG) && (BOOST_VERSION >= 105600) ++# endif // !defined(BOOST_ASIO_DISABLE_BOOST_ALIGN) ++#endif // !defined(BOOST_ASIO_HAS_BOOST_ALIGN) ++ ++// Boost array library. ++#if !defined(BOOST_ASIO_HAS_BOOST_ARRAY) ++# if !defined(BOOST_ASIO_DISABLE_BOOST_ARRAY) ++# define BOOST_ASIO_HAS_BOOST_ARRAY 1 ++# endif // !defined(BOOST_ASIO_DISABLE_BOOST_ARRAY) ++#endif // !defined(BOOST_ASIO_HAS_BOOST_ARRAY) ++ ++// Boost assert macro. ++#if !defined(BOOST_ASIO_HAS_BOOST_ASSERT) ++# if !defined(BOOST_ASIO_DISABLE_BOOST_ASSERT) ++# define BOOST_ASIO_HAS_BOOST_ASSERT 1 ++# endif // !defined(BOOST_ASIO_DISABLE_BOOST_ASSERT) ++#endif // !defined(BOOST_ASIO_HAS_BOOST_ASSERT) ++ ++// Boost limits header. ++#if !defined(BOOST_ASIO_HAS_BOOST_LIMITS) ++# if !defined(BOOST_ASIO_DISABLE_BOOST_LIMITS) ++# define BOOST_ASIO_HAS_BOOST_LIMITS 1 ++# endif // !defined(BOOST_ASIO_DISABLE_BOOST_LIMITS) ++#endif // !defined(BOOST_ASIO_HAS_BOOST_LIMITS) ++ ++// Boost throw_exception function. ++#if !defined(BOOST_ASIO_HAS_BOOST_THROW_EXCEPTION) ++# if !defined(BOOST_ASIO_DISABLE_BOOST_THROW_EXCEPTION) ++# define BOOST_ASIO_HAS_BOOST_THROW_EXCEPTION 1 ++# endif // !defined(BOOST_ASIO_DISABLE_BOOST_THROW_EXCEPTION) ++#endif // !defined(BOOST_ASIO_HAS_BOOST_THROW_EXCEPTION) ++ ++// Boost regex library. ++#if !defined(BOOST_ASIO_HAS_BOOST_REGEX) ++# if !defined(BOOST_ASIO_DISABLE_BOOST_REGEX) ++# define BOOST_ASIO_HAS_BOOST_REGEX 1 ++# endif // !defined(BOOST_ASIO_DISABLE_BOOST_REGEX) ++#endif // !defined(BOOST_ASIO_HAS_BOOST_REGEX) ++ ++// Boost bind function. ++#if !defined(BOOST_ASIO_HAS_BOOST_BIND) ++# if !defined(BOOST_ASIO_DISABLE_BOOST_BIND) ++# define BOOST_ASIO_HAS_BOOST_BIND 1 ++# endif // !defined(BOOST_ASIO_DISABLE_BOOST_BIND) ++#endif // !defined(BOOST_ASIO_HAS_BOOST_BIND) ++ ++// Boost's BOOST_WORKAROUND macro. ++#if !defined(BOOST_ASIO_HAS_BOOST_WORKAROUND) ++# if !defined(BOOST_ASIO_DISABLE_BOOST_WORKAROUND) ++# define BOOST_ASIO_HAS_BOOST_WORKAROUND 1 ++# endif // !defined(BOOST_ASIO_DISABLE_BOOST_WORKAROUND) ++#endif // !defined(BOOST_ASIO_HAS_BOOST_WORKAROUND) ++ ++// Microsoft Visual C++'s secure C runtime library. ++#if !defined(BOOST_ASIO_HAS_SECURE_RTL) ++# if !defined(BOOST_ASIO_DISABLE_SECURE_RTL) ++# if defined(BOOST_ASIO_MSVC) \ ++ && (BOOST_ASIO_MSVC >= 1400) \ ++ && !defined(UNDER_CE) ++# define BOOST_ASIO_HAS_SECURE_RTL 1 ++# endif // defined(BOOST_ASIO_MSVC) ++ // && (BOOST_ASIO_MSVC >= 1400) ++ // && !defined(UNDER_CE) ++# endif // !defined(BOOST_ASIO_DISABLE_SECURE_RTL) ++#endif // !defined(BOOST_ASIO_HAS_SECURE_RTL) ++ ++// Handler hooking. Disabled for ancient Borland C++ and gcc compilers. ++#if !defined(BOOST_ASIO_HAS_HANDLER_HOOKS) ++# if !defined(BOOST_ASIO_DISABLE_HANDLER_HOOKS) ++# if defined(__GNUC__) ++# if (__GNUC__ >= 3) ++# define BOOST_ASIO_HAS_HANDLER_HOOKS 1 ++# endif // (__GNUC__ >= 3) ++# elif !defined(__BORLANDC__) || defined(__clang__) ++# define BOOST_ASIO_HAS_HANDLER_HOOKS 1 ++# endif // !defined(__BORLANDC__) || defined(__clang__) ++# endif // !defined(BOOST_ASIO_DISABLE_HANDLER_HOOKS) ++#endif // !defined(BOOST_ASIO_HAS_HANDLER_HOOKS) ++ ++// Support for the __thread keyword extension. ++#if !defined(BOOST_ASIO_DISABLE_THREAD_KEYWORD_EXTENSION) ++# if defined(__linux__) ++# if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) ++# if ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3) ++# if !defined(__INTEL_COMPILER) && !defined(__ICL) \ ++ && !(defined(__clang__) && defined(__ANDROID__)) ++# define BOOST_ASIO_HAS_THREAD_KEYWORD_EXTENSION 1 ++# define BOOST_ASIO_THREAD_KEYWORD __thread ++# elif defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 1100) ++# define BOOST_ASIO_HAS_THREAD_KEYWORD_EXTENSION 1 ++# endif // defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 1100) ++ // && !(defined(__clang__) && defined(__ANDROID__)) ++# endif // ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3) ++# endif // defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) ++# endif // defined(__linux__) ++# if defined(BOOST_ASIO_MSVC) && defined(BOOST_ASIO_WINDOWS_RUNTIME) ++# if (_MSC_VER >= 1700) ++# define BOOST_ASIO_HAS_THREAD_KEYWORD_EXTENSION 1 ++# define BOOST_ASIO_THREAD_KEYWORD __declspec(thread) ++# endif // (_MSC_VER >= 1700) ++# endif // defined(BOOST_ASIO_MSVC) && defined(BOOST_ASIO_WINDOWS_RUNTIME) ++#endif // !defined(BOOST_ASIO_DISABLE_THREAD_KEYWORD_EXTENSION) ++#if !defined(BOOST_ASIO_THREAD_KEYWORD) ++# define BOOST_ASIO_THREAD_KEYWORD __thread ++#endif // !defined(BOOST_ASIO_THREAD_KEYWORD) ++ ++// Support for POSIX ssize_t typedef. ++#if !defined(BOOST_ASIO_DISABLE_SSIZE_T) ++# if defined(__linux__) \ ++ || (defined(__MACH__) && defined(__APPLE__)) ++# define BOOST_ASIO_HAS_SSIZE_T 1 ++# endif // defined(__linux__) ++ // || (defined(__MACH__) && defined(__APPLE__)) ++#endif // !defined(BOOST_ASIO_DISABLE_SSIZE_T) ++ ++// Helper macros to manage transition away from error_code return values. ++#if defined(BOOST_ASIO_NO_DEPRECATED) ++# define BOOST_ASIO_SYNC_OP_VOID void ++# define BOOST_ASIO_SYNC_OP_VOID_RETURN(e) return ++#else // defined(BOOST_ASIO_NO_DEPRECATED) ++# define BOOST_ASIO_SYNC_OP_VOID boost::system::error_code ++# define BOOST_ASIO_SYNC_OP_VOID_RETURN(e) return e ++#endif // defined(BOOST_ASIO_NO_DEPRECATED) ++ ++// Newer gcc, clang need special treatment to suppress unused typedef warnings. ++#if defined(__clang__) ++# if defined(__apple_build_version__) ++# if (__clang_major__ >= 7) ++# define BOOST_ASIO_UNUSED_TYPEDEF __attribute__((__unused__)) ++# endif // (__clang_major__ >= 7) ++# elif ((__clang_major__ == 3) && (__clang_minor__ >= 6)) \ ++ || (__clang_major__ > 3) ++# define BOOST_ASIO_UNUSED_TYPEDEF __attribute__((__unused__)) ++# endif // ((__clang_major__ == 3) && (__clang_minor__ >= 6)) ++ // || (__clang_major__ > 3) ++#elif defined(__GNUC__) ++# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4) ++# define BOOST_ASIO_UNUSED_TYPEDEF __attribute__((__unused__)) ++# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4) ++#endif // defined(__GNUC__) ++#if !defined(BOOST_ASIO_UNUSED_TYPEDEF) ++# define BOOST_ASIO_UNUSED_TYPEDEF ++#endif // !defined(BOOST_ASIO_UNUSED_TYPEDEF) ++ ++// Some versions of gcc generate spurious warnings about unused variables. ++#if defined(__GNUC__) ++# if (__GNUC__ >= 4) ++# define BOOST_ASIO_UNUSED_VARIABLE __attribute__((__unused__)) ++# endif // (__GNUC__ >= 4) ++#endif // defined(__GNUC__) ++#if !defined(BOOST_ASIO_UNUSED_VARIABLE) ++# define BOOST_ASIO_UNUSED_VARIABLE ++#endif // !defined(BOOST_ASIO_UNUSED_VARIABLE) ++ ++// Helper macro to tell the optimiser what may be assumed to be true. ++#if defined(BOOST_ASIO_MSVC) ++# define BOOST_ASIO_ASSUME(expr) __assume(expr) ++#elif defined(__clang__) ++# if __has_builtin(__builtin_assume) ++# define BOOST_ASIO_ASSUME(expr) __builtin_assume(expr) ++# endif // __has_builtin(__builtin_assume) ++#elif defined(__GNUC__) ++# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) ++# define BOOST_ASIO_ASSUME(expr) if (expr) {} else { __builtin_unreachable(); } ++# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) ++#endif // defined(__GNUC__) ++#if !defined(BOOST_ASIO_ASSUME) ++# define BOOST_ASIO_ASSUME(expr) (void)0 ++#endif // !defined(BOOST_ASIO_ASSUME) ++ ++// Support the co_await keyword on compilers known to allow it. ++#if !defined(BOOST_ASIO_HAS_CO_AWAIT) ++# if !defined(BOOST_ASIO_DISABLE_CO_AWAIT) ++# if defined(BOOST_ASIO_MSVC) ++# if (_MSC_VER >= 1928) && (_MSVC_LANG >= 201705) && !defined(__clang__) ++# define BOOST_ASIO_HAS_CO_AWAIT 1 ++# elif (_MSC_FULL_VER >= 190023506) ++# if defined(_RESUMABLE_FUNCTIONS_SUPPORTED) ++# define BOOST_ASIO_HAS_CO_AWAIT 1 ++# endif // defined(_RESUMABLE_FUNCTIONS_SUPPORTED) ++# endif // (_MSC_FULL_VER >= 190023506) ++# elif defined(__clang__) ++# if (__clang_major__ >= 14) ++# if (__cplusplus >= 202002) && (__cpp_impl_coroutine >= 201902) ++# if __has_include() ++# define BOOST_ASIO_HAS_CO_AWAIT 1 ++# endif // __has_include() ++# elif (__cplusplus >= 201703) && (__cpp_coroutines >= 201703) ++# if __has_include() ++# define BOOST_ASIO_HAS_CO_AWAIT 1 ++# endif // __has_include() ++# endif // (__cplusplus >= 201703) && (__cpp_coroutines >= 201703) ++# else // (__clang_major__ >= 14) ++# if (__cplusplus >= 201703) && (__cpp_coroutines >= 201703) ++# if __has_include() ++# define BOOST_ASIO_HAS_CO_AWAIT 1 ++# endif // __has_include() ++# endif // (__cplusplus >= 201703) && (__cpp_coroutines >= 201703) ++# endif // (__clang_major__ >= 14) ++# elif defined(__GNUC__) ++# if (__cplusplus >= 201709) && (__cpp_impl_coroutine >= 201902) ++# if __has_include() ++# define BOOST_ASIO_HAS_CO_AWAIT 1 ++# endif // __has_include() ++# endif // (__cplusplus >= 201709) && (__cpp_impl_coroutine >= 201902) ++# endif // defined(__GNUC__) ++# endif // !defined(BOOST_ASIO_DISABLE_CO_AWAIT) ++#endif // !defined(BOOST_ASIO_HAS_CO_AWAIT) ++ ++// Standard library support for coroutines. ++#if !defined(BOOST_ASIO_HAS_STD_COROUTINE) ++# if !defined(BOOST_ASIO_DISABLE_STD_COROUTINE) ++# if defined(BOOST_ASIO_MSVC) ++# if (_MSC_VER >= 1928) && (_MSVC_LANG >= 201705) ++# define BOOST_ASIO_HAS_STD_COROUTINE 1 ++# endif // (_MSC_VER >= 1928) && (_MSVC_LANG >= 201705) ++# elif defined(__clang__) ++# if (__clang_major__ >= 14) ++# if (__cplusplus >= 202002) && (__cpp_impl_coroutine >= 201902) ++# if __has_include() ++# define BOOST_ASIO_HAS_STD_COROUTINE 1 ++# endif // __has_include() ++# endif // (__cplusplus >= 202002) && (__cpp_impl_coroutine >= 201902) ++# endif // (__clang_major__ >= 14) ++# elif defined(__GNUC__) ++# if (__cplusplus >= 201709) && (__cpp_impl_coroutine >= 201902) ++# if __has_include() ++# define BOOST_ASIO_HAS_STD_COROUTINE 1 ++# endif // __has_include() ++# endif // (__cplusplus >= 201709) && (__cpp_impl_coroutine >= 201902) ++# endif // defined(__GNUC__) ++# endif // !defined(BOOST_ASIO_DISABLE_STD_COROUTINE) ++#endif // !defined(BOOST_ASIO_HAS_STD_COROUTINE) ++ ++// Compiler support for the the [[nodiscard]] attribute. ++#if !defined(BOOST_ASIO_NODISCARD) ++# if defined(__has_cpp_attribute) ++# if __has_cpp_attribute(nodiscard) ++# if (__cplusplus >= 201703) ++# define BOOST_ASIO_NODISCARD [[nodiscard]] ++# endif // (__cplusplus >= 201703) ++# endif // __has_cpp_attribute(nodiscard) ++# endif // defined(__has_cpp_attribute) ++#endif // !defined(BOOST_ASIO_NODISCARD) ++#if !defined(BOOST_ASIO_NODISCARD) ++# define BOOST_ASIO_NODISCARD ++#endif // !defined(BOOST_ASIO_NODISCARD) ++ ++// Kernel support for MSG_NOSIGNAL. ++#if !defined(BOOST_ASIO_HAS_MSG_NOSIGNAL) ++# if defined(__linux__) ++# define BOOST_ASIO_HAS_MSG_NOSIGNAL 1 ++# elif defined(_POSIX_VERSION) ++# if (_POSIX_VERSION >= 200809L) ++# define BOOST_ASIO_HAS_MSG_NOSIGNAL 1 ++# endif // _POSIX_VERSION >= 200809L ++# endif // defined(_POSIX_VERSION) ++#endif // !defined(BOOST_ASIO_HAS_MSG_NOSIGNAL) ++ ++// Standard library support for std::hash. ++#if !defined(BOOST_ASIO_HAS_STD_HASH) ++# if !defined(BOOST_ASIO_DISABLE_STD_HASH) ++# if defined(__clang__) ++# if defined(BOOST_ASIO_HAS_CLANG_LIBCXX) ++# define BOOST_ASIO_HAS_STD_HASH 1 ++# elif (__cplusplus >= 201103) ++# define BOOST_ASIO_HAS_STD_HASH 1 ++# endif // (__cplusplus >= 201103) ++# elif defined(__GNUC__) ++# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) ++# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) ++# define BOOST_ASIO_HAS_STD_HASH 1 ++# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) ++# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) ++# endif // defined(__GNUC__) ++# if defined(BOOST_ASIO_MSVC) ++# if (_MSC_VER >= 1700) ++# define BOOST_ASIO_HAS_STD_HASH 1 ++# endif // (_MSC_VER >= 1700) ++# endif // defined(BOOST_ASIO_MSVC) ++# endif // !defined(BOOST_ASIO_DISABLE_STD_HASH) ++#endif // !defined(BOOST_ASIO_HAS_STD_HASH) ++ ++// Standard library support for std::to_address. ++#if !defined(BOOST_ASIO_HAS_STD_TO_ADDRESS) ++# if !defined(BOOST_ASIO_DISABLE_STD_TO_ADDRESS) ++# if defined(__clang__) ++# if (__cplusplus >= 202002) ++# define BOOST_ASIO_HAS_STD_TO_ADDRESS 1 ++# endif // (__cplusplus >= 202002) ++# elif defined(__GNUC__) ++# if (__GNUC__ >= 8) ++# if (__cplusplus >= 202002) ++# define BOOST_ASIO_HAS_STD_TO_ADDRESS 1 ++# endif // (__cplusplus >= 202002) ++# endif // (__GNUC__ >= 8) ++# endif // defined(__GNUC__) ++# if defined(BOOST_ASIO_MSVC) ++# if (_MSC_VER >= 1922) && (_MSVC_LANG >= 202002) ++# define BOOST_ASIO_HAS_STD_TO_ADDRESS 1 ++# endif // (_MSC_VER >= 1922) && (_MSVC_LANG >= 202002) ++# endif // defined(BOOST_ASIO_MSVC) ++# endif // !defined(BOOST_ASIO_DISABLE_STD_TO_ADDRESS) ++#endif // !defined(BOOST_ASIO_HAS_STD_TO_ADDRESS) ++ ++// Standard library support for snprintf. ++#if !defined(BOOST_ASIO_HAS_SNPRINTF) ++# if !defined(BOOST_ASIO_DISABLE_SNPRINTF) ++# if defined(__apple_build_version__) ++# if (__clang_major__ >= 14) ++# define BOOST_ASIO_HAS_SNPRINTF 1 ++# endif // (__clang_major__ >= 14) ++# endif // defined(__apple_build_version__) ++# endif // !defined(BOOST_ASIO_DISABLE_SNPRINTF) ++#endif // !defined(BOOST_ASIO_HAS_SNPRINTF) ++ ++#endif // BOOST_ASIO_DETAIL_CONFIG_HPP +diff -urN boost_1_83_0.orig/boost/config/user.hpp boost_1_83_0/boost/config/user.hpp +--- boost_1_83_0.orig/boost/config/user.hpp 2023-08-08 16:02:50.000000000 -0500 ++++ boost_1_83_0/boost/config/user.hpp 2023-12-20 19:37:21.249966924 -0600 +@@ -13,6 +13,13 @@ + // configuration policy: + // + ++// Android defines ++// There is problem with std::atomic on android (and some other platforms). ++// See this link for more info: ++// https://issuetracker.google.com/issues/36964000 ++#define BOOST_ASIO_DISABLE_STD_ATOMIC 1 ++ ++ + // define this to locate a compiler config file: + // #define BOOST_COMPILER_CONFIG + +diff -urN boost_1_83_0.orig/libs/filesystem/src/operations.cpp boost_1_83_0/libs/filesystem/src/operations.cpp +--- boost_1_83_0.orig/libs/filesystem/src/operations.cpp 2023-08-08 16:02:51.000000000 -0500 ++++ boost_1_83_0/libs/filesystem/src/operations.cpp 2023-12-20 19:37:21.249966924 -0600 +@@ -75,6 +75,10 @@ + #endif + #include + ++#if defined(__ANDROID__) ++#define BOOST_FILESYSTEM_DISABLE_STATX 1 // statx syscall crashes the app on Android 10 because of seccomp error ++#endif ++ + #if defined(linux) || defined(__linux) || defined(__linux__) + + #include +@@ -223,6 +227,21 @@ + + #if defined(BOOST_POSIX_API) + ++#if defined(__ANDROID__) ++#define truncate libboost_truncate_wrapper ++// truncate() is present in Android libc only starting from ABI 21, so here's a simple wrapper ++static int libboost_truncate_wrapper(const char *path, off_t length) ++{ ++ int fd = open(path, O_WRONLY); ++ if (fd == -1) { ++ return -1; ++ } ++ int status = ftruncate(fd, length); ++ close(fd); ++ return status; ++} ++#endif ++ + #define BOOST_SET_CURRENT_DIRECTORY(P) (::chdir(P) == 0) + #define BOOST_MOVE_FILE(OLD, NEW) (::rename(OLD, NEW) == 0) + #define BOOST_RESIZE_FILE(P, SZ) (::truncate(P, SZ) == 0) +diff -urN boost_1_83_0.orig/libs/filesystem/src/operations.cpp.orig boost_1_83_0/libs/filesystem/src/operations.cpp.orig +--- boost_1_83_0.orig/libs/filesystem/src/operations.cpp.orig 1969-12-31 18:00:00.000000000 -0600 ++++ boost_1_83_0/libs/filesystem/src/operations.cpp.orig 2023-12-20 19:37:21.249966924 -0600 +@@ -0,0 +1,4604 @@ ++// operations.cpp --------------------------------------------------------------------// ++ ++// Copyright 2002-2009, 2014 Beman Dawes ++// Copyright 2001 Dietmar Kuehl ++// Copyright 2018-2022 Andrey Semashev ++ ++// Distributed under the Boost Software License, Version 1.0. ++// See http://www.boost.org/LICENSE_1_0.txt ++ ++// See library home page at http://www.boost.org/libs/filesystem ++ ++//--------------------------------------------------------------------------------------// ++ ++#include "platform_config.hpp" ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include // std::bad_alloc, std::nothrow ++#include ++#include ++#include ++#include // for malloc, free ++#include ++#include ++#include // for rename ++ ++// Default to POSIX under Emscripten ++// If BOOST_FILESYSTEM_EMSCRIPTEN_USE_WASI is set, use WASI instead ++#if defined(__wasm) && (!defined(__EMSCRIPTEN__) || defined(BOOST_FILESYSTEM_EMSCRIPTEN_USE_WASI)) ++#define BOOST_FILESYSTEM_USE_WASI ++#endif ++ ++#ifdef BOOST_POSIX_API ++ ++#include ++#include ++ ++#if defined(BOOST_FILESYSTEM_USE_WASI) ++// WASI does not have statfs or statvfs. ++#elif !defined(__APPLE__) && \ ++ (!defined(__OpenBSD__) || BOOST_OS_BSD_OPEN >= BOOST_VERSION_NUMBER(4, 4, 0)) && \ ++ !defined(__ANDROID__) && \ ++ !defined(__VXWORKS__) ++#include ++#define BOOST_STATVFS statvfs ++#define BOOST_STATVFS_F_FRSIZE vfs.f_frsize ++#else ++#ifdef __OpenBSD__ ++#include ++#elif defined(__ANDROID__) ++#include ++#endif ++#if !defined(__VXWORKS__) ++#include ++#endif ++#define BOOST_STATVFS statfs ++#define BOOST_STATVFS_F_FRSIZE static_cast< uintmax_t >(vfs.f_bsize) ++#endif // BOOST_STATVFS definition ++ ++#include ++#include ++#if !defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) ++#include ++#endif ++#include ++ ++#if defined(linux) || defined(__linux) || defined(__linux__) ++ ++#include ++#include ++#include ++#include ++#if !defined(BOOST_FILESYSTEM_DISABLE_SENDFILE) ++#include ++#define BOOST_FILESYSTEM_USE_SENDFILE ++#endif // !defined(BOOST_FILESYSTEM_DISABLE_SENDFILE) ++#if !defined(BOOST_FILESYSTEM_DISABLE_COPY_FILE_RANGE) && defined(__NR_copy_file_range) ++#define BOOST_FILESYSTEM_USE_COPY_FILE_RANGE ++#endif // !defined(BOOST_FILESYSTEM_DISABLE_COPY_FILE_RANGE) && defined(__NR_copy_file_range) ++#if !defined(BOOST_FILESYSTEM_DISABLE_STATX) && (defined(BOOST_FILESYSTEM_HAS_STATX) || defined(BOOST_FILESYSTEM_HAS_STATX_SYSCALL)) ++#if !defined(BOOST_FILESYSTEM_HAS_STATX) && defined(BOOST_FILESYSTEM_HAS_STATX_SYSCALL) ++#include ++#endif ++#define BOOST_FILESYSTEM_USE_STATX ++#endif // !defined(BOOST_FILESYSTEM_DISABLE_STATX) && (defined(BOOST_FILESYSTEM_HAS_STATX) || defined(BOOST_FILESYSTEM_HAS_STATX_SYSCALL)) ++ ++#if defined(__has_include) ++#if __has_include() ++// This header was introduced in Linux kernel 2.6.19 ++#include ++#endif ++#endif ++ ++// Some filesystem type magic constants are not defined in older kernel headers ++#ifndef PROC_SUPER_MAGIC ++#define PROC_SUPER_MAGIC 0x9fa0 ++#endif ++#ifndef SYSFS_MAGIC ++#define SYSFS_MAGIC 0x62656572 ++#endif ++#ifndef TRACEFS_MAGIC ++#define TRACEFS_MAGIC 0x74726163 ++#endif ++#ifndef DEBUGFS_MAGIC ++#define DEBUGFS_MAGIC 0x64626720 ++#endif ++ ++#endif // defined(linux) || defined(__linux) || defined(__linux__) ++ ++#if defined(POSIX_FADV_SEQUENTIAL) && (!defined(__ANDROID__) || __ANDROID_API__ >= 21) ++#define BOOST_FILESYSTEM_HAS_POSIX_FADVISE ++#endif ++ ++#if defined(BOOST_FILESYSTEM_HAS_STAT_ST_MTIM) ++#define BOOST_FILESYSTEM_STAT_ST_MTIMENSEC st_mtim.tv_nsec ++#elif defined(BOOST_FILESYSTEM_HAS_STAT_ST_MTIMESPEC) ++#define BOOST_FILESYSTEM_STAT_ST_MTIMENSEC st_mtimespec.tv_nsec ++#elif defined(BOOST_FILESYSTEM_HAS_STAT_ST_MTIMENSEC) ++#define BOOST_FILESYSTEM_STAT_ST_MTIMENSEC st_mtimensec ++#endif ++ ++#if defined(BOOST_FILESYSTEM_HAS_STAT_ST_BIRTHTIM) ++#define BOOST_FILESYSTEM_STAT_ST_BIRTHTIME st_birthtim.tv_sec ++#define BOOST_FILESYSTEM_STAT_ST_BIRTHTIMENSEC st_birthtim.tv_nsec ++#elif defined(BOOST_FILESYSTEM_HAS_STAT_ST_BIRTHTIMESPEC) ++#define BOOST_FILESYSTEM_STAT_ST_BIRTHTIME st_birthtimespec.tv_sec ++#define BOOST_FILESYSTEM_STAT_ST_BIRTHTIMENSEC st_birthtimespec.tv_nsec ++#elif defined(BOOST_FILESYSTEM_HAS_STAT_ST_BIRTHTIMENSEC) ++#define BOOST_FILESYSTEM_STAT_ST_BIRTHTIME st_birthtime ++#define BOOST_FILESYSTEM_STAT_ST_BIRTHTIMENSEC st_birthtimensec ++#endif ++ ++#include "posix_tools.hpp" ++ ++#else // BOOST_WINDOWS_API ++ ++#include // get_proc_address, GetModuleHandleW ++#include ++#include ++#include ++#include ++#if defined(__BORLANDC__) || defined(__MWERKS__) ++#if defined(BOOST_BORLANDC) ++using std::time_t; ++#endif ++#include ++#else ++#include ++#endif ++ ++#include "windows_tools.hpp" ++ ++#endif // BOOST_WINDOWS_API ++ ++#include "atomic_tools.hpp" ++#include "error_handling.hpp" ++#include "private_config.hpp" ++ ++#include // must be the last #include ++ ++namespace fs = boost::filesystem; ++using boost::filesystem::path; ++using boost::filesystem::filesystem_error; ++using boost::filesystem::perms; ++using boost::system::error_code; ++using boost::system::system_category; ++ ++#if defined(BOOST_POSIX_API) ++ ++// At least Mac OS X 10.6 and older doesn't support O_CLOEXEC ++#ifndef O_CLOEXEC ++#define O_CLOEXEC 0 ++#endif ++ ++#if defined(_POSIX_SYNCHRONIZED_IO) && _POSIX_SYNCHRONIZED_IO > 0 ++#define BOOST_FILESYSTEM_HAS_FDATASYNC ++#endif ++ ++#else // defined(BOOST_POSIX_API) ++ ++#ifndef MAXIMUM_REPARSE_DATA_BUFFER_SIZE ++#define MAXIMUM_REPARSE_DATA_BUFFER_SIZE (16 * 1024) ++#endif ++ ++#ifndef FSCTL_GET_REPARSE_POINT ++#define FSCTL_GET_REPARSE_POINT 0x900a8 ++#endif ++ ++#ifndef SYMLINK_FLAG_RELATIVE ++#define SYMLINK_FLAG_RELATIVE 1 ++#endif ++ ++// Fallback for MinGW/Cygwin ++#ifndef SYMBOLIC_LINK_FLAG_DIRECTORY ++#define SYMBOLIC_LINK_FLAG_DIRECTORY 0x1 ++#endif ++ ++#ifndef SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE ++#define SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE 0x2 ++#endif ++ ++#endif // defined(BOOST_POSIX_API) ++ ++// POSIX/Windows macros ----------------------------------------------------// ++ ++// Portions of the POSIX and Windows API's are very similar, except for name, ++// order of arguments, and meaning of zero/non-zero returns. The macros below ++// abstract away those differences. They follow Windows naming and order of ++// arguments, and return true to indicate no error occurred. [POSIX naming, ++// order of arguments, and meaning of return were followed initially, but ++// found to be less clear and cause more coding errors.] ++ ++#if defined(BOOST_POSIX_API) ++ ++#define BOOST_SET_CURRENT_DIRECTORY(P) (::chdir(P) == 0) ++#define BOOST_MOVE_FILE(OLD, NEW) (::rename(OLD, NEW) == 0) ++#define BOOST_RESIZE_FILE(P, SZ) (::truncate(P, SZ) == 0) ++ ++#else // BOOST_WINDOWS_API ++ ++#define BOOST_SET_CURRENT_DIRECTORY(P) (::SetCurrentDirectoryW(P) != 0) ++#define BOOST_MOVE_FILE(OLD, NEW) (::MoveFileExW(OLD, NEW, MOVEFILE_REPLACE_EXISTING | MOVEFILE_COPY_ALLOWED) != 0) ++#define BOOST_RESIZE_FILE(P, SZ) (resize_file_impl(P, SZ) != 0) ++ ++#endif ++ ++namespace boost { ++namespace filesystem { ++namespace detail { ++ ++#if defined(linux) || defined(__linux) || defined(__linux__) ++//! Initializes fill_random implementation pointer. Implemented in unique_path.cpp. ++void init_fill_random_impl(unsigned int major_ver, unsigned int minor_ver, unsigned int patch_ver); ++#endif // defined(linux) || defined(__linux) || defined(__linux__) ++ ++#if defined(BOOST_WINDOWS_API) && !defined(UNDER_CE) ++//! Initializes directory iterator implementation. Implemented in directory.cpp. ++void init_directory_iterator_impl() BOOST_NOEXCEPT; ++#endif // defined(BOOST_WINDOWS_API) && !defined(UNDER_CE) ++ ++//--------------------------------------------------------------------------------------// ++// // ++// helpers (all operating systems) // ++// // ++//--------------------------------------------------------------------------------------// ++ ++namespace { ++ ++// The number of retries remove_all should make if it detects that the directory it is about to enter has been replaced with a symlink or a regular file ++BOOST_CONSTEXPR_OR_CONST unsigned int remove_all_directory_replaced_retry_count = 5u; ++ ++#if defined(BOOST_POSIX_API) ++ ++// Size of a small buffer for a path that can be placed on stack, in character code units ++BOOST_CONSTEXPR_OR_CONST std::size_t small_path_size = 1024u; ++ ++// Absolute maximum path length, in character code units, that we're willing to accept from various system calls. ++// This value is arbitrary, it is supposed to be a hard limit to avoid memory exhaustion ++// in some of the algorithms below in case of some corrupted or maliciously broken filesystem. ++// A few examples of path size limits: ++// - Windows: 32767 UTF-16 code units or 260 bytes for legacy multibyte APIs. ++// - Linux: 4096 bytes ++// - IRIX, HP-UX, Mac OS, QNX, FreeBSD, OpenBSD: 1024 bytes ++// - GNU/Hurd: no hard limit ++BOOST_CONSTEXPR_OR_CONST std::size_t absolute_path_max = 32u * 1024u; ++ ++#endif // defined(BOOST_POSIX_API) ++ ++// Maximum number of resolved symlinks before we register a loop ++BOOST_CONSTEXPR_OR_CONST unsigned int symloop_max = ++#if defined(SYMLOOP_MAX) ++ SYMLOOP_MAX < 40 ? 40 : SYMLOOP_MAX ++#else ++ 40 ++#endif ++; ++ ++// general helpers -----------------------------------------------------------------// ++ ++bool is_empty_directory(path const& p, error_code* ec) ++{ ++ fs::directory_iterator itr; ++ detail::directory_iterator_construct(itr, p, static_cast< unsigned int >(directory_options::none), NULL, ec); ++ return itr == fs::directory_iterator(); ++} ++ ++bool not_found_error(int errval) BOOST_NOEXCEPT; // forward declaration ++ ++#ifdef BOOST_POSIX_API ++ ++//--------------------------------------------------------------------------------------// ++// // ++// POSIX-specific helpers // ++// // ++//--------------------------------------------------------------------------------------// ++ ++struct fd_wrapper ++{ ++ int fd; ++ ++ fd_wrapper() BOOST_NOEXCEPT : fd(-1) {} ++ explicit fd_wrapper(int fd) BOOST_NOEXCEPT : fd(fd) {} ++ ~fd_wrapper() BOOST_NOEXCEPT ++ { ++ if (fd >= 0) ++ close_fd(fd); ++ } ++ BOOST_DELETED_FUNCTION(fd_wrapper(fd_wrapper const&)) ++ BOOST_DELETED_FUNCTION(fd_wrapper& operator=(fd_wrapper const&)) ++}; ++ ++inline bool not_found_error(int errval) BOOST_NOEXCEPT ++{ ++ return errval == ENOENT || errval == ENOTDIR; ++} ++ ++#if defined(BOOST_FILESYSTEM_HAS_STATX) ++ ++//! A wrapper for statx libc function. Disable MSAN since at least on clang 10 it doesn't ++//! know which fields of struct statx are initialized by the syscall and misdetects errors. ++BOOST_FILESYSTEM_NO_SANITIZE_MEMORY ++BOOST_FORCEINLINE int invoke_statx(int dirfd, const char* path, int flags, unsigned int mask, struct ::statx* stx) ++{ ++ return ::statx(dirfd, path, flags, mask, stx); ++} ++ ++#elif defined(BOOST_FILESYSTEM_HAS_STATX_SYSCALL) ++ ++//! statx emulation through fstatat ++int statx_fstatat(int dirfd, const char* path, int flags, unsigned int mask, struct ::statx* stx) ++{ ++ struct ::stat st; ++ flags &= AT_EMPTY_PATH | AT_NO_AUTOMOUNT | AT_SYMLINK_NOFOLLOW; ++ int res = ::fstatat(dirfd, path, &st, flags); ++ if (BOOST_LIKELY(res == 0)) ++ { ++ std::memset(stx, 0, sizeof(*stx)); ++ stx->stx_mask = STATX_BASIC_STATS; ++ stx->stx_blksize = st.st_blksize; ++ stx->stx_nlink = st.st_nlink; ++ stx->stx_uid = st.st_uid; ++ stx->stx_gid = st.st_gid; ++ stx->stx_mode = st.st_mode; ++ stx->stx_ino = st.st_ino; ++ stx->stx_size = st.st_size; ++ stx->stx_blocks = st.st_blocks; ++ stx->stx_atime.tv_sec = st.st_atim.tv_sec; ++ stx->stx_atime.tv_nsec = st.st_atim.tv_nsec; ++ stx->stx_ctime.tv_sec = st.st_ctim.tv_sec; ++ stx->stx_ctime.tv_nsec = st.st_ctim.tv_nsec; ++ stx->stx_mtime.tv_sec = st.st_mtim.tv_sec; ++ stx->stx_mtime.tv_nsec = st.st_mtim.tv_nsec; ++ stx->stx_rdev_major = major(st.st_rdev); ++ stx->stx_rdev_minor = minor(st.st_rdev); ++ stx->stx_dev_major = major(st.st_dev); ++ stx->stx_dev_minor = minor(st.st_dev); ++ } ++ ++ return res; ++} ++ ++typedef int statx_t(int dirfd, const char* path, int flags, unsigned int mask, struct ::statx* stx); ++ ++//! Pointer to the actual implementation of the statx implementation ++statx_t* statx_ptr = &statx_fstatat; ++ ++inline int invoke_statx(int dirfd, const char* path, int flags, unsigned int mask, struct ::statx* stx) BOOST_NOEXCEPT ++{ ++ return filesystem::detail::atomic_load_relaxed(statx_ptr)(dirfd, path, flags, mask, stx); ++} ++ ++//! A wrapper for the statx syscall. Disable MSAN since at least on clang 10 it doesn't ++//! know which fields of struct statx are initialized by the syscall and misdetects errors. ++BOOST_FILESYSTEM_NO_SANITIZE_MEMORY ++int statx_syscall(int dirfd, const char* path, int flags, unsigned int mask, struct ::statx* stx) ++{ ++ int res = ::syscall(__NR_statx, dirfd, path, flags, mask, stx); ++ if (res < 0) ++ { ++ const int err = errno; ++ if (BOOST_UNLIKELY(err == ENOSYS)) ++ { ++ filesystem::detail::atomic_store_relaxed(statx_ptr, &statx_fstatat); ++ return statx_fstatat(dirfd, path, flags, mask, stx); ++ } ++ } ++ ++ return res; ++} ++ ++#endif // defined(BOOST_FILESYSTEM_HAS_STATX) ++ ++#if defined(linux) || defined(__linux) || defined(__linux__) ++ ++//! Initializes statx implementation pointer ++inline void init_statx_impl(unsigned int major_ver, unsigned int minor_ver, unsigned int patch_ver) ++{ ++#if !defined(BOOST_FILESYSTEM_HAS_STATX) && defined(BOOST_FILESYSTEM_HAS_STATX_SYSCALL) ++ statx_t* stx = &statx_fstatat; ++ if (major_ver > 4u || (major_ver == 4u && minor_ver >= 11u)) ++ stx = &statx_syscall; ++ ++ filesystem::detail::atomic_store_relaxed(statx_ptr, stx); ++#endif // !defined(BOOST_FILESYSTEM_HAS_STATX) && defined(BOOST_FILESYSTEM_HAS_STATX_SYSCALL) ++} ++ ++#endif // defined(linux) || defined(__linux) || defined(__linux__) ++ ++#if defined(BOOST_FILESYSTEM_USE_STATX) ++ ++//! Returns \c true if the two \c statx structures refer to the same file ++inline bool equivalent_stat(struct ::statx const& s1, struct ::statx const& s2) BOOST_NOEXCEPT ++{ ++ return s1.stx_dev_major == s2.stx_dev_major && s1.stx_dev_minor == s2.stx_dev_minor && s1.stx_ino == s2.stx_ino; ++} ++ ++//! Returns file type/access mode from \c statx structure ++inline mode_t get_mode(struct ::statx const& st) BOOST_NOEXCEPT ++{ ++ return st.stx_mode; ++} ++ ++//! Returns file size from \c statx structure ++inline uintmax_t get_size(struct ::statx const& st) BOOST_NOEXCEPT ++{ ++ return st.stx_size; ++} ++ ++//! Returns optimal block size from \c statx structure ++inline std::size_t get_blksize(struct ::statx const& st) BOOST_NOEXCEPT ++{ ++ return st.stx_blksize; ++} ++ ++#else // defined(BOOST_FILESYSTEM_USE_STATX) ++ ++//! Returns \c true if the two \c stat structures refer to the same file ++inline bool equivalent_stat(struct ::stat const& s1, struct ::stat const& s2) BOOST_NOEXCEPT ++{ ++ // According to the POSIX stat specs, "The st_ino and st_dev fields ++ // taken together uniquely identify the file within the system." ++ return s1.st_dev == s2.st_dev && s1.st_ino == s2.st_ino; ++} ++ ++//! Returns file type/access mode from \c stat structure ++inline mode_t get_mode(struct ::stat const& st) BOOST_NOEXCEPT ++{ ++ return st.st_mode; ++} ++ ++//! Returns file size from \c stat structure ++inline uintmax_t get_size(struct ::stat const& st) BOOST_NOEXCEPT ++{ ++ return st.st_size; ++} ++ ++//! Returns optimal block size from \c stat structure ++inline std::size_t get_blksize(struct ::stat const& st) BOOST_NOEXCEPT ++{ ++#if defined(BOOST_FILESYSTEM_HAS_STAT_ST_BLKSIZE) ++ return st.st_blksize; ++#else ++ return 4096u; // a suitable default used on most modern SSDs/HDDs ++#endif ++} ++ ++#endif // defined(BOOST_FILESYSTEM_USE_STATX) ++ ++//! status() implementation ++file_status status_impl ++( ++ path const& p, ++ error_code* ec ++#if defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) || defined(BOOST_FILESYSTEM_USE_STATX) ++ , int basedir_fd = AT_FDCWD ++#endif ++) ++{ ++#if defined(BOOST_FILESYSTEM_USE_STATX) ++ struct ::statx path_stat; ++ int err = invoke_statx(basedir_fd, p.c_str(), AT_NO_AUTOMOUNT, STATX_TYPE | STATX_MODE, &path_stat); ++#elif defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) ++ struct ::stat path_stat; ++ int err = ::fstatat(basedir_fd, p.c_str(), &path_stat, AT_NO_AUTOMOUNT); ++#else ++ struct ::stat path_stat; ++ int err = ::stat(p.c_str(), &path_stat); ++#endif ++ ++ if (err != 0) ++ { ++ err = errno; ++ if (ec) // always report errno, even though some ++ ec->assign(err, system_category()); // errno values are not status_errors ++ ++ if (not_found_error(err)) ++ return fs::file_status(fs::file_not_found, fs::no_perms); ++ ++ if (!ec) ++ BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::status", p, error_code(err, system_category()))); ++ ++ return fs::file_status(fs::status_error); ++ } ++ ++#if defined(BOOST_FILESYSTEM_USE_STATX) ++ if (BOOST_UNLIKELY((path_stat.stx_mask & (STATX_TYPE | STATX_MODE)) != (STATX_TYPE | STATX_MODE))) ++ { ++ emit_error(BOOST_ERROR_NOT_SUPPORTED, p, ec, "boost::filesystem::status"); ++ return fs::file_status(fs::status_error); ++ } ++#endif ++ ++ const mode_t mode = get_mode(path_stat); ++ if (S_ISDIR(mode)) ++ return fs::file_status(fs::directory_file, static_cast< perms >(mode) & fs::perms_mask); ++ if (S_ISREG(mode)) ++ return fs::file_status(fs::regular_file, static_cast< perms >(mode) & fs::perms_mask); ++ if (S_ISBLK(mode)) ++ return fs::file_status(fs::block_file, static_cast< perms >(mode) & fs::perms_mask); ++ if (S_ISCHR(mode)) ++ return fs::file_status(fs::character_file, static_cast< perms >(mode) & fs::perms_mask); ++ if (S_ISFIFO(mode)) ++ return fs::file_status(fs::fifo_file, static_cast< perms >(mode) & fs::perms_mask); ++ if (S_ISSOCK(mode)) ++ return fs::file_status(fs::socket_file, static_cast< perms >(mode) & fs::perms_mask); ++ ++ return fs::file_status(fs::type_unknown); ++} ++ ++//! symlink_status() implementation ++file_status symlink_status_impl ++( ++ path const& p, ++ error_code* ec ++#if defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) || defined(BOOST_FILESYSTEM_USE_STATX) ++ , int basedir_fd = AT_FDCWD ++#endif ++) ++{ ++#if defined(BOOST_FILESYSTEM_USE_STATX) ++ struct ::statx path_stat; ++ int err = invoke_statx(basedir_fd, p.c_str(), AT_SYMLINK_NOFOLLOW | AT_NO_AUTOMOUNT, STATX_TYPE | STATX_MODE, &path_stat); ++#elif defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) ++ struct ::stat path_stat; ++ int err = ::fstatat(basedir_fd, p.c_str(), &path_stat, AT_SYMLINK_NOFOLLOW | AT_NO_AUTOMOUNT); ++#else ++ struct ::stat path_stat; ++ int err = ::lstat(p.c_str(), &path_stat); ++#endif ++ ++ if (err != 0) ++ { ++ err = errno; ++ if (ec) // always report errno, even though some ++ ec->assign(err, system_category()); // errno values are not status_errors ++ ++ if (not_found_error(err)) // these are not errors ++ return fs::file_status(fs::file_not_found, fs::no_perms); ++ ++ if (!ec) ++ BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::symlink_status", p, error_code(err, system_category()))); ++ ++ return fs::file_status(fs::status_error); ++ } ++ ++#if defined(BOOST_FILESYSTEM_USE_STATX) ++ if (BOOST_UNLIKELY((path_stat.stx_mask & (STATX_TYPE | STATX_MODE)) != (STATX_TYPE | STATX_MODE))) ++ { ++ emit_error(BOOST_ERROR_NOT_SUPPORTED, p, ec, "boost::filesystem::symlink_status"); ++ return fs::file_status(fs::status_error); ++ } ++#endif ++ ++ const mode_t mode = get_mode(path_stat); ++ if (S_ISREG(mode)) ++ return fs::file_status(fs::regular_file, static_cast< perms >(mode) & fs::perms_mask); ++ if (S_ISDIR(mode)) ++ return fs::file_status(fs::directory_file, static_cast< perms >(mode) & fs::perms_mask); ++ if (S_ISLNK(mode)) ++ return fs::file_status(fs::symlink_file, static_cast< perms >(mode) & fs::perms_mask); ++ if (S_ISBLK(mode)) ++ return fs::file_status(fs::block_file, static_cast< perms >(mode) & fs::perms_mask); ++ if (S_ISCHR(mode)) ++ return fs::file_status(fs::character_file, static_cast< perms >(mode) & fs::perms_mask); ++ if (S_ISFIFO(mode)) ++ return fs::file_status(fs::fifo_file, static_cast< perms >(mode) & fs::perms_mask); ++ if (S_ISSOCK(mode)) ++ return fs::file_status(fs::socket_file, static_cast< perms >(mode) & fs::perms_mask); ++ ++ return fs::file_status(fs::type_unknown); ++} ++ ++//! Flushes buffered data and attributes written to the file to permanent storage ++inline int full_sync(int fd) ++{ ++ while (true) ++ { ++#if defined(__APPLE__) && defined(__MACH__) && defined(F_FULLFSYNC) ++ // Mac OS does not flush data to physical storage with fsync() ++ int err = ::fcntl(fd, F_FULLFSYNC); ++#else ++ int err = ::fsync(fd); ++#endif ++ if (BOOST_UNLIKELY(err < 0)) ++ { ++ err = errno; ++ // POSIX says fsync can return EINTR (https://pubs.opengroup.org/onlinepubs/9699919799/functions/fsync.html). ++ // fcntl(F_FULLFSYNC) isn't documented to return EINTR, but it doesn't hurt to check. ++ if (err == EINTR) ++ continue; ++ ++ return err; ++ } ++ ++ break; ++ } ++ ++ return 0; ++} ++ ++//! Flushes buffered data written to the file to permanent storage ++inline int data_sync(int fd) ++{ ++#if defined(BOOST_FILESYSTEM_HAS_FDATASYNC) && !(defined(__APPLE__) && defined(__MACH__) && defined(F_FULLFSYNC)) ++ while (true) ++ { ++ int err = ::fdatasync(fd); ++ if (BOOST_UNLIKELY(err != 0)) ++ { ++ err = errno; ++ // POSIX says fsync can return EINTR (https://pubs.opengroup.org/onlinepubs/9699919799/functions/fsync.html). ++ // It doesn't say so for fdatasync, but it is reasonable to expect it as well. ++ if (err == EINTR) ++ continue; ++ ++ return err; ++ } ++ ++ break; ++ } ++ ++ return 0; ++#else ++ return full_sync(fd); ++#endif ++} ++ ++// Min and max buffer sizes are selected to minimize the overhead from system calls. ++// The values are picked based on coreutils cp(1) benchmarking data described here: ++// https://github.com/coreutils/coreutils/blob/d1b0257077c0b0f0ee25087efd46270345d1dd1f/src/ioblksize.h#L23-L72 ++BOOST_CONSTEXPR_OR_CONST uint_least32_t min_read_write_buf_size = 8u * 1024u; ++BOOST_CONSTEXPR_OR_CONST uint_least32_t max_read_write_buf_size = 256u * 1024u; ++ ++//! copy_file read/write loop implementation ++int copy_file_data_read_write_impl(int infile, int outfile, char* buf, std::size_t buf_size) ++{ ++#if defined(BOOST_FILESYSTEM_HAS_POSIX_FADVISE) ++ ::posix_fadvise(infile, 0, 0, POSIX_FADV_SEQUENTIAL); ++#endif ++ ++ // Don't use file size to limit the amount of data to copy since some filesystems, like procfs or sysfs, ++ // provide files with generated content and indicate that their size is zero or 4096. Just copy as much data ++ // as we can read from the input file. ++ while (true) ++ { ++ ssize_t sz_read = ::read(infile, buf, buf_size); ++ if (sz_read == 0) ++ break; ++ if (BOOST_UNLIKELY(sz_read < 0)) ++ { ++ int err = errno; ++ if (err == EINTR) ++ continue; ++ return err; ++ } ++ ++ // Allow for partial writes - see Advanced Unix Programming (2nd Ed.), ++ // Marc Rochkind, Addison-Wesley, 2004, page 94 ++ for (ssize_t sz_wrote = 0; sz_wrote < sz_read;) ++ { ++ ssize_t sz = ::write(outfile, buf + sz_wrote, static_cast< std::size_t >(sz_read - sz_wrote)); ++ if (BOOST_UNLIKELY(sz < 0)) ++ { ++ int err = errno; ++ if (err == EINTR) ++ continue; ++ return err; ++ } ++ ++ sz_wrote += sz; ++ } ++ } ++ ++ return 0; ++} ++ ++//! copy_file implementation that uses read/write loop (fallback using a stack buffer) ++int copy_file_data_read_write_stack_buf(int infile, int outfile) ++{ ++ char stack_buf[min_read_write_buf_size]; ++ return copy_file_data_read_write_impl(infile, outfile, stack_buf, sizeof(stack_buf)); ++} ++ ++//! copy_file implementation that uses read/write loop ++int copy_file_data_read_write(int infile, int outfile, uintmax_t size, std::size_t blksize) ++{ ++ { ++ uintmax_t buf_sz = size; ++ // Prefer the buffer to be larger than the file size so that we don't have ++ // to perform an extra read if the file fits in the buffer exactly. ++ buf_sz += (buf_sz < ~static_cast< uintmax_t >(0u)); ++ if (buf_sz < blksize) ++ buf_sz = blksize; ++ if (buf_sz < min_read_write_buf_size) ++ buf_sz = min_read_write_buf_size; ++ if (buf_sz > max_read_write_buf_size) ++ buf_sz = max_read_write_buf_size; ++ const std::size_t buf_size = static_cast< std::size_t >(boost::core::bit_ceil(static_cast< uint_least32_t >(buf_sz))); ++ boost::scoped_array< char > buf(new (std::nothrow) char[buf_size]); ++ if (BOOST_LIKELY(!!buf.get())) ++ return copy_file_data_read_write_impl(infile, outfile, buf.get(), buf_size); ++ } ++ ++ return copy_file_data_read_write_stack_buf(infile, outfile); ++} ++ ++typedef int copy_file_data_t(int infile, int outfile, uintmax_t size, std::size_t blksize); ++ ++//! Pointer to the actual implementation of the copy_file_data implementation ++copy_file_data_t* copy_file_data = ©_file_data_read_write; ++ ++#if defined(BOOST_FILESYSTEM_USE_SENDFILE) || defined(BOOST_FILESYSTEM_USE_COPY_FILE_RANGE) ++ ++//! copy_file_data wrapper that tests if a read/write loop must be used for a given filesystem ++template< typename CopyFileData > ++int check_fs_type(int infile, int outfile, uintmax_t size, std::size_t blksize); ++ ++#endif // defined(BOOST_FILESYSTEM_USE_SENDFILE) || defined(BOOST_FILESYSTEM_USE_COPY_FILE_RANGE) ++ ++#if defined(BOOST_FILESYSTEM_USE_SENDFILE) ++ ++struct copy_file_data_sendfile ++{ ++ //! copy_file implementation that uses sendfile loop. Requires sendfile to support file descriptors. ++ static int impl(int infile, int outfile, uintmax_t size, std::size_t blksize) ++ { ++ // sendfile will not send more than this amount of data in one call ++ BOOST_CONSTEXPR_OR_CONST std::size_t max_batch_size = 0x7ffff000u; ++ uintmax_t offset = 0u; ++ while (offset < size) ++ { ++ uintmax_t size_left = size - offset; ++ std::size_t size_to_copy = max_batch_size; ++ if (size_left < static_cast< uintmax_t >(max_batch_size)) ++ size_to_copy = static_cast< std::size_t >(size_left); ++ ssize_t sz = ::sendfile(outfile, infile, NULL, size_to_copy); ++ if (BOOST_UNLIKELY(sz < 0)) ++ { ++ int err = errno; ++ if (err == EINTR) ++ continue; ++ ++ if (offset == 0u) ++ { ++ // sendfile may fail with EINVAL if the underlying filesystem does not support it ++ if (err == EINVAL) ++ { ++ fallback_to_read_write: ++ return copy_file_data_read_write(infile, outfile, size, blksize); ++ } ++ ++ if (err == ENOSYS) ++ { ++ filesystem::detail::atomic_store_relaxed(copy_file_data, ©_file_data_read_write); ++ goto fallback_to_read_write; ++ } ++ } ++ ++ return err; ++ } ++ ++ offset += sz; ++ } ++ ++ return 0; ++ } ++}; ++ ++#endif // defined(BOOST_FILESYSTEM_USE_SENDFILE) ++ ++#if defined(BOOST_FILESYSTEM_USE_COPY_FILE_RANGE) ++ ++struct copy_file_data_copy_file_range ++{ ++ //! copy_file implementation that uses copy_file_range loop. Requires copy_file_range to support cross-filesystem copying. ++ static int impl(int infile, int outfile, uintmax_t size, std::size_t blksize) ++ { ++ // Although copy_file_range does not document any particular upper limit of one transfer, still use some upper bound to guarantee ++ // that size_t is not overflown in case if off_t is larger and the file size does not fit in size_t. ++ BOOST_CONSTEXPR_OR_CONST std::size_t max_batch_size = 0x7ffff000u; ++ uintmax_t offset = 0u; ++ while (offset < size) ++ { ++ uintmax_t size_left = size - offset; ++ std::size_t size_to_copy = max_batch_size; ++ if (size_left < static_cast< uintmax_t >(max_batch_size)) ++ size_to_copy = static_cast< std::size_t >(size_left); ++ // Note: Use syscall directly to avoid depending on libc version. copy_file_range is added in glibc 2.27. ++ // uClibc-ng does not have copy_file_range as of the time of this writing (the latest uClibc-ng release is 1.0.33). ++ loff_t sz = ::syscall(__NR_copy_file_range, infile, (loff_t*)NULL, outfile, (loff_t*)NULL, size_to_copy, (unsigned int)0u); ++ if (BOOST_UNLIKELY(sz < 0)) ++ { ++ int err = errno; ++ if (err == EINTR) ++ continue; ++ ++ if (offset == 0u) ++ { ++ // copy_file_range may fail with EINVAL if the underlying filesystem does not support it. ++ // In some RHEL/CentOS 7.7-7.8 kernel versions, copy_file_range on NFSv4 is also known to return EOPNOTSUPP ++ // if the remote server does not support COPY, despite that it is not a documented error code. ++ // See https://patchwork.kernel.org/project/linux-nfs/patch/20190411183418.4510-1-olga.kornievskaia@gmail.com/ ++ // and https://bugzilla.redhat.com/show_bug.cgi?id=1783554. ++ if (err == EINVAL || err == EOPNOTSUPP) ++ { ++#if !defined(BOOST_FILESYSTEM_USE_SENDFILE) ++ fallback_to_read_write: ++#endif ++ return copy_file_data_read_write(infile, outfile, size, blksize); ++ } ++ ++ if (err == EXDEV) ++ { ++#if defined(BOOST_FILESYSTEM_USE_SENDFILE) ++ fallback_to_sendfile: ++ return copy_file_data_sendfile::impl(infile, outfile, size, blksize); ++#else ++ goto fallback_to_read_write; ++#endif ++ } ++ ++ if (err == ENOSYS) ++ { ++#if defined(BOOST_FILESYSTEM_USE_SENDFILE) ++ filesystem::detail::atomic_store_relaxed(copy_file_data, &check_fs_type< copy_file_data_sendfile >); ++ goto fallback_to_sendfile; ++#else ++ filesystem::detail::atomic_store_relaxed(copy_file_data, ©_file_data_read_write); ++ goto fallback_to_read_write; ++#endif ++ } ++ } ++ ++ return err; ++ } ++ ++ offset += sz; ++ } ++ ++ return 0; ++ } ++}; ++ ++#endif // defined(BOOST_FILESYSTEM_USE_COPY_FILE_RANGE) ++ ++#if defined(BOOST_FILESYSTEM_USE_SENDFILE) || defined(BOOST_FILESYSTEM_USE_COPY_FILE_RANGE) ++ ++//! copy_file_data wrapper that tests if a read/write loop must be used for a given filesystem ++template< typename CopyFileData > ++int check_fs_type(int infile, int outfile, uintmax_t size, std::size_t blksize) ++{ ++ { ++ // Some filesystems have regular files with generated content. Such files have arbitrary size, including zero, ++ // but have actual content. Linux system calls sendfile or copy_file_range will not copy contents of such files, ++ // so we must use a read/write loop to handle them. ++ // https://lore.kernel.org/linux-fsdevel/20210212044405.4120619-1-drinkcat@chromium.org/T/ ++ struct statfs sfs; ++ while (true) ++ { ++ int err = ::fstatfs(infile, &sfs); ++ if (BOOST_UNLIKELY(err < 0)) ++ { ++ err = errno; ++ if (err == EINTR) ++ continue; ++ ++ goto fallback_to_read_write; ++ } ++ ++ break; ++ } ++ ++ if (BOOST_UNLIKELY(sfs.f_type == PROC_SUPER_MAGIC || ++ sfs.f_type == SYSFS_MAGIC || ++ sfs.f_type == TRACEFS_MAGIC || ++ sfs.f_type == DEBUGFS_MAGIC)) ++ { ++ fallback_to_read_write: ++ return copy_file_data_read_write(infile, outfile, size, blksize); ++ } ++ } ++ ++ return CopyFileData::impl(infile, outfile, size, blksize); ++} ++ ++#endif // defined(BOOST_FILESYSTEM_USE_SENDFILE) || defined(BOOST_FILESYSTEM_USE_COPY_FILE_RANGE) ++ ++#if defined(linux) || defined(__linux) || defined(__linux__) ++ ++//! Initializes copy_file_data implementation pointer ++inline void init_copy_file_data_impl(unsigned int major_ver, unsigned int minor_ver, unsigned int patch_ver) ++{ ++#if defined(BOOST_FILESYSTEM_USE_SENDFILE) || defined(BOOST_FILESYSTEM_USE_COPY_FILE_RANGE) ++ copy_file_data_t* cfd = ©_file_data_read_write; ++ ++#if defined(BOOST_FILESYSTEM_USE_SENDFILE) ++ // sendfile started accepting file descriptors as the target in Linux 2.6.33 ++ if (major_ver > 2u || (major_ver == 2u && (minor_ver > 6u || (minor_ver == 6u && patch_ver >= 33u)))) ++ cfd = &check_fs_type< copy_file_data_sendfile >; ++#endif ++ ++#if defined(BOOST_FILESYSTEM_USE_COPY_FILE_RANGE) ++ // Although copy_file_range appeared in Linux 4.5, it did not support cross-filesystem copying until 5.3. ++ // copy_file_data_copy_file_range will fallback to copy_file_data_sendfile if copy_file_range returns EXDEV. ++ if (major_ver > 4u || (major_ver == 4u && minor_ver >= 5u)) ++ cfd = &check_fs_type< copy_file_data_copy_file_range >; ++#endif ++ ++ filesystem::detail::atomic_store_relaxed(copy_file_data, cfd); ++#endif // defined(BOOST_FILESYSTEM_USE_SENDFILE) || defined(BOOST_FILESYSTEM_USE_COPY_FILE_RANGE) ++} ++ ++#endif // defined(linux) || defined(__linux) || defined(__linux__) ++ ++#if defined(linux) || defined(__linux) || defined(__linux__) ++ ++struct syscall_initializer ++{ ++ syscall_initializer() ++ { ++ struct ::utsname system_info; ++ if (BOOST_UNLIKELY(::uname(&system_info) < 0)) ++ return; ++ ++ unsigned int major_ver = 0u, minor_ver = 0u, patch_ver = 0u; ++ int count = std::sscanf(system_info.release, "%u.%u.%u", &major_ver, &minor_ver, &patch_ver); ++ if (BOOST_UNLIKELY(count < 3)) ++ return; ++ ++ init_statx_impl(major_ver, minor_ver, patch_ver); ++ init_copy_file_data_impl(major_ver, minor_ver, patch_ver); ++ init_fill_random_impl(major_ver, minor_ver, patch_ver); ++ } ++}; ++ ++BOOST_FILESYSTEM_INIT_PRIORITY(BOOST_FILESYSTEM_FUNC_PTR_INIT_PRIORITY) BOOST_ATTRIBUTE_UNUSED BOOST_FILESYSTEM_ATTRIBUTE_RETAIN ++const syscall_initializer syscall_init; ++ ++#endif // defined(linux) || defined(__linux) || defined(__linux__) ++ ++//! remove() implementation ++inline bool remove_impl ++( ++ path const& p, ++ fs::file_type type, ++ error_code* ec ++#if defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) ++ , int basedir_fd = AT_FDCWD ++#endif ++) ++{ ++ if (type == fs::file_not_found) ++ return false; ++ ++ int res; ++#if defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) ++ res = ::unlinkat(basedir_fd, p.c_str(), type == fs::directory_file ? AT_REMOVEDIR : 0); ++#else ++ if (type == fs::directory_file) ++ res = ::rmdir(p.c_str()); ++ else ++ res = ::unlink(p.c_str()); ++#endif ++ ++ if (res != 0) ++ { ++ int err = errno; ++ if (BOOST_UNLIKELY(!not_found_error(err))) ++ emit_error(err, p, ec, "boost::filesystem::remove"); ++ ++ return false; ++ } ++ ++ return true; ++} ++ ++//! remove() implementation ++inline bool remove_impl(path const& p, error_code* ec) ++{ ++ // Since POSIX remove() is specified to work with either files or directories, in a ++ // perfect world it could just be called. But some important real-world operating ++ // systems (Windows, Mac OS, for example) don't implement the POSIX spec. So ++ // we have to distinguish between files and directories and call corresponding APIs ++ // to remove them. ++ ++ error_code local_ec; ++ fs::file_type type = fs::detail::symlink_status_impl(p, &local_ec).type(); ++ if (BOOST_UNLIKELY(type == fs::status_error)) ++ { ++ if (!ec) ++ BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::remove", p, local_ec)); ++ ++ *ec = local_ec; ++ return false; ++ } ++ ++ return fs::detail::remove_impl(p, type, ec); ++} ++ ++//! remove_all() implementation ++uintmax_t remove_all_impl ++( ++ path const& p, ++ error_code* ec ++#if defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW) && defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) ++ , int basedir_fd = AT_FDCWD ++#endif ++) ++{ ++#if defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW) && defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) ++ fs::detail::directory_iterator_params params; ++ params.basedir_fd = basedir_fd; ++ params.iterator_fd = -1; ++#endif ++ ++ error_code dit_create_ec; ++ for (unsigned int attempt = 0u; attempt < remove_all_directory_replaced_retry_count; ++attempt) ++ { ++ fs::file_type type; ++ { ++ error_code local_ec; ++ type = fs::detail::symlink_status_impl ++ ( ++ p, ++ &local_ec ++#if defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW) && defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) ++ , basedir_fd ++#endif ++ ).type(); ++ ++ if (type == fs::file_not_found) ++ return 0u; ++ ++ if (BOOST_UNLIKELY(type == fs::status_error)) ++ { ++ if (!ec) ++ BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::remove_all", p, local_ec)); ++ ++ *ec = local_ec; ++ return static_cast< uintmax_t >(-1); ++ } ++ } ++ ++ uintmax_t count = 0u; ++ if (type == fs::directory_file) // but not a directory symlink ++ { ++ fs::directory_iterator itr; ++ fs::detail::directory_iterator_construct ++ ( ++ itr, ++ p, ++ static_cast< unsigned int >(directory_options::_detail_no_follow), ++#if defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW) && defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) ++ ¶ms, ++#else ++ NULL, ++#endif ++ &dit_create_ec ++ ); ++ ++ if (BOOST_UNLIKELY(!!dit_create_ec)) ++ { ++ if (dit_create_ec == error_code(ENOTDIR, system_category())) ++ continue; ++ ++#if defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW) ++ // If open(2) with O_NOFOLLOW fails with ELOOP, this means that either the path contains a loop ++ // of symbolic links, or the last element of the path is a symbolic link. Given that lstat(2) above ++ // did not fail, most likely it is the latter case. I.e. between the lstat above and this open call ++ // the filesystem was modified so that the path no longer refers to a directory file (as opposed to a symlink). ++ if (dit_create_ec == error_code(ELOOP, system_category())) ++ continue; ++#endif // defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW) ++ ++ if (!ec) ++ BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::remove_all", p, dit_create_ec)); ++ ++ *ec = dit_create_ec; ++ return static_cast< uintmax_t >(-1); ++ } ++ ++ const fs::directory_iterator end_dit; ++ while (itr != end_dit) ++ { ++ count += fs::detail::remove_all_impl ++ ( ++#if defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW) && defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) ++ path_algorithms::filename_v4(itr->path()), ++#else ++ itr->path(), ++#endif ++ ec ++#if defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW) && defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) ++ , params.iterator_fd ++#endif ++ ); ++ if (ec && *ec) ++ return static_cast< uintmax_t >(-1); ++ ++ fs::detail::directory_iterator_increment(itr, ec); ++ if (ec && *ec) ++ return static_cast< uintmax_t >(-1); ++ } ++ } ++ ++ count += fs::detail::remove_impl ++ ( ++ p, ++ type, ++ ec ++#if defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW) && defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) ++ , basedir_fd ++#endif ++ ); ++ if (ec && *ec) ++ return static_cast< uintmax_t >(-1); ++ ++ return count; ++ } ++ ++ if (!ec) ++ BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::remove_all: path cannot be opened as a directory", p, dit_create_ec)); ++ ++ *ec = dit_create_ec; ++ return static_cast< uintmax_t >(-1); ++} ++ ++#else // defined(BOOST_POSIX_API) ++ ++//--------------------------------------------------------------------------------------// ++// // ++// Windows-specific helpers // ++// // ++//--------------------------------------------------------------------------------------// ++ ++//! FILE_BASIC_INFO definition from Windows SDK ++struct file_basic_info ++{ ++ LARGE_INTEGER CreationTime; ++ LARGE_INTEGER LastAccessTime; ++ LARGE_INTEGER LastWriteTime; ++ LARGE_INTEGER ChangeTime; ++ DWORD FileAttributes; ++}; ++ ++//! FILE_DISPOSITION_INFO definition from Windows SDK ++struct file_disposition_info ++{ ++ BOOLEAN DeleteFile; ++}; ++ ++//! FILE_DISPOSITION_INFO_EX definition from Windows SDK ++struct file_disposition_info_ex ++{ ++ DWORD Flags; ++}; ++ ++#ifndef FILE_DISPOSITION_FLAG_DELETE ++#define FILE_DISPOSITION_FLAG_DELETE 0x00000001 ++#endif ++// Available since Windows 10 1709 ++#ifndef FILE_DISPOSITION_FLAG_POSIX_SEMANTICS ++#define FILE_DISPOSITION_FLAG_POSIX_SEMANTICS 0x00000002 ++#endif ++// Available since Windows 10 1809 ++#ifndef FILE_DISPOSITION_FLAG_IGNORE_READONLY_ATTRIBUTE ++#define FILE_DISPOSITION_FLAG_IGNORE_READONLY_ATTRIBUTE 0x00000010 ++#endif ++ ++// REPARSE_DATA_BUFFER related definitions are found in ntifs.h, which is part of the ++// Windows Device Driver Kit. Since that's inconvenient, the definitions are provided ++// here. See http://msdn.microsoft.com/en-us/library/ms791514.aspx ++struct reparse_data_buffer ++{ ++ ULONG ReparseTag; ++ USHORT ReparseDataLength; ++ USHORT Reserved; ++ union ++ { ++ /* ++ * In SymbolicLink and MountPoint reparse points, there are two names. ++ * SubstituteName is the effective replacement path for the reparse point. ++ * This is what should be used for path traversal. ++ * PrintName is intended for presentation to the user and may omit some ++ * elements of the path or be absent entirely. ++ * ++ * Examples of substitute and print names: ++ * mklink /D ldrive c:\ ++ * SubstituteName: "\??\c:\" ++ * PrintName: "c:\" ++ * ++ * mklink /J ldrive c:\ ++ * SubstituteName: "\??\C:\" ++ * PrintName: "c:\" ++ * ++ * junction ldrive c:\ ++ * SubstituteName: "\??\C:\" ++ * PrintName: "" ++ * ++ * box.com mounted cloud storage ++ * SubstituteName: "\??\Volume{}\" ++ * PrintName: "" ++ */ ++ struct ++ { ++ USHORT SubstituteNameOffset; ++ USHORT SubstituteNameLength; ++ USHORT PrintNameOffset; ++ USHORT PrintNameLength; ++ ULONG Flags; ++ WCHAR PathBuffer[1]; ++ } SymbolicLinkReparseBuffer; ++ struct ++ { ++ USHORT SubstituteNameOffset; ++ USHORT SubstituteNameLength; ++ USHORT PrintNameOffset; ++ USHORT PrintNameLength; ++ WCHAR PathBuffer[1]; ++ } MountPointReparseBuffer; ++ struct ++ { ++ UCHAR DataBuffer[1]; ++ } GenericReparseBuffer; ++ }; ++}; ++ ++// Our convenience type for allocating REPARSE_DATA_BUFFER along with sufficient space after it ++union reparse_data_buffer_with_storage ++{ ++ reparse_data_buffer rdb; ++ unsigned char storage[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; ++}; ++ ++// Windows kernel32.dll functions that may or may not be present ++// must be accessed through pointers ++ ++typedef BOOL (WINAPI CreateHardLinkW_t)( ++ /*__in*/ LPCWSTR lpFileName, ++ /*__in*/ LPCWSTR lpExistingFileName, ++ /*__reserved*/ LPSECURITY_ATTRIBUTES lpSecurityAttributes); ++ ++CreateHardLinkW_t* create_hard_link_api = NULL; ++ ++typedef BOOLEAN (WINAPI CreateSymbolicLinkW_t)( ++ /*__in*/ LPCWSTR lpSymlinkFileName, ++ /*__in*/ LPCWSTR lpTargetFileName, ++ /*__in*/ DWORD dwFlags); ++ ++CreateSymbolicLinkW_t* create_symbolic_link_api = NULL; ++ ++//! SetFileInformationByHandle signature. Available since Windows Vista. ++typedef BOOL (WINAPI SetFileInformationByHandle_t)( ++ /*_In_*/ HANDLE hFile, ++ /*_In_*/ file_info_by_handle_class FileInformationClass, // the actual type is FILE_INFO_BY_HANDLE_CLASS enum ++ /*_In_reads_bytes_(dwBufferSize)*/ LPVOID lpFileInformation, ++ /*_In_*/ DWORD dwBufferSize); ++ ++SetFileInformationByHandle_t* set_file_information_by_handle_api = NULL; ++ ++} // unnamed namespace ++ ++GetFileInformationByHandleEx_t* get_file_information_by_handle_ex_api = NULL; ++ ++#if !defined(UNDER_CE) ++NtCreateFile_t* nt_create_file_api = NULL; ++NtQueryDirectoryFile_t* nt_query_directory_file_api = NULL; ++#endif // !defined(UNDER_CE) ++ ++namespace { ++ ++//! remove() implementation type ++enum remove_impl_type ++{ ++ remove_nt5, //!< Use Windows XP API ++ remove_disp, //!< Use FILE_DISPOSITION_INFO (Windows Vista and later) ++ remove_disp_ex_flag_posix_semantics, //!< Use FILE_DISPOSITION_INFO_EX with FILE_DISPOSITION_FLAG_POSIX_SEMANTICS ++ remove_disp_ex_flag_ignore_readonly //!< Use FILE_DISPOSITION_INFO_EX with FILE_DISPOSITION_FLAG_POSIX_SEMANTICS | FILE_DISPOSITION_FLAG_IGNORE_READONLY_ATTRIBUTE ++}; ++ ++remove_impl_type g_remove_impl_type = remove_nt5; ++ ++//! Initializes WinAPI function pointers ++BOOST_FILESYSTEM_INIT_FUNC init_winapi_func_ptrs() ++{ ++ boost::winapi::HMODULE_ h = boost::winapi::GetModuleHandleW(L"kernel32.dll"); ++ if (BOOST_LIKELY(!!h)) ++ { ++ GetFileInformationByHandleEx_t* get_file_information_by_handle_ex = (GetFileInformationByHandleEx_t*)boost::winapi::get_proc_address(h, "GetFileInformationByHandleEx"); ++ filesystem::detail::atomic_store_relaxed(get_file_information_by_handle_ex_api, get_file_information_by_handle_ex); ++ SetFileInformationByHandle_t* set_file_information_by_handle = (SetFileInformationByHandle_t*)boost::winapi::get_proc_address(h, "SetFileInformationByHandle"); ++ filesystem::detail::atomic_store_relaxed(set_file_information_by_handle_api, set_file_information_by_handle); ++ filesystem::detail::atomic_store_relaxed(create_hard_link_api, (CreateHardLinkW_t*)boost::winapi::get_proc_address(h, "CreateHardLinkW")); ++ filesystem::detail::atomic_store_relaxed(create_symbolic_link_api, (CreateSymbolicLinkW_t*)boost::winapi::get_proc_address(h, "CreateSymbolicLinkW")); ++ ++ if (get_file_information_by_handle_ex && set_file_information_by_handle) ++ { ++ // Enable the most advanced implementation based on GetFileInformationByHandleEx/SetFileInformationByHandle. ++ // If certain flags are not supported by the OS, the remove() implementation will downgrade accordingly. ++ filesystem::detail::atomic_store_relaxed(g_remove_impl_type, remove_disp_ex_flag_ignore_readonly); ++ } ++ } ++ ++#if !defined(UNDER_CE) ++ h = boost::winapi::GetModuleHandleW(L"ntdll.dll"); ++ if (BOOST_LIKELY(!!h)) ++ { ++ filesystem::detail::atomic_store_relaxed(nt_create_file_api, (NtCreateFile_t*)boost::winapi::get_proc_address(h, "NtCreateFile")); ++ filesystem::detail::atomic_store_relaxed(nt_query_directory_file_api, (NtQueryDirectoryFile_t*)boost::winapi::get_proc_address(h, "NtQueryDirectoryFile")); ++ } ++ ++ init_directory_iterator_impl(); ++#endif // !defined(UNDER_CE) ++ ++ return BOOST_FILESYSTEM_INITRETSUCCESS_V; ++} ++ ++#if defined(_MSC_VER) ++ ++#if _MSC_VER >= 1400 ++ ++#pragma section(".CRT$XCL", long, read) ++__declspec(allocate(".CRT$XCL")) BOOST_ATTRIBUTE_UNUSED BOOST_FILESYSTEM_ATTRIBUTE_RETAIN ++extern const init_func_ptr_t p_init_winapi_func_ptrs = &init_winapi_func_ptrs; ++ ++#else // _MSC_VER >= 1400 ++ ++#if (_MSC_VER >= 1300) // 1300 == VC++ 7.0 ++#pragma data_seg(push, old_seg) ++#endif ++#pragma data_seg(".CRT$XCL") ++BOOST_ATTRIBUTE_UNUSED BOOST_FILESYSTEM_ATTRIBUTE_RETAIN ++extern const init_func_ptr_t p_init_winapi_func_ptrs = &init_winapi_func_ptrs; ++#pragma data_seg() ++#if (_MSC_VER >= 1300) // 1300 == VC++ 7.0 ++#pragma data_seg(pop, old_seg) ++#endif ++ ++#endif // _MSC_VER >= 1400 ++ ++#if defined(BOOST_FILESYSTEM_NO_ATTRIBUTE_RETAIN) ++//! Makes sure the global initializer pointers are referenced and not removed by linker ++struct globals_retainer ++{ ++ const init_func_ptr_t* volatile m_p_init_winapi_func_ptrs; ++ ++ globals_retainer() { m_p_init_winapi_func_ptrs = &p_init_winapi_func_ptrs; } ++}; ++BOOST_ATTRIBUTE_UNUSED ++const globals_retainer g_globals_retainer; ++#endif // defined(BOOST_FILESYSTEM_NO_ATTRIBUTE_RETAIN) ++ ++#else // defined(_MSC_VER) ++ ++//! Invokes WinAPI function pointers initialization ++struct winapi_func_ptrs_initializer ++{ ++ winapi_func_ptrs_initializer() { init_winapi_func_ptrs(); } ++}; ++ ++BOOST_FILESYSTEM_INIT_PRIORITY(BOOST_FILESYSTEM_FUNC_PTR_INIT_PRIORITY) BOOST_ATTRIBUTE_UNUSED BOOST_FILESYSTEM_ATTRIBUTE_RETAIN ++const winapi_func_ptrs_initializer winapi_func_ptrs_init; ++ ++#endif // defined(_MSC_VER) ++ ++ ++// Windows CE has no environment variables ++#if !defined(UNDER_CE) ++inline std::wstring wgetenv(const wchar_t* name) ++{ ++ // use a separate buffer since C++03 basic_string is not required to be contiguous ++ const DWORD size = ::GetEnvironmentVariableW(name, NULL, 0); ++ if (size > 0) ++ { ++ boost::scoped_array< wchar_t > buf(new wchar_t[size]); ++ if (BOOST_LIKELY(::GetEnvironmentVariableW(name, buf.get(), size) > 0)) ++ return std::wstring(buf.get()); ++ } ++ ++ return std::wstring(); ++} ++#endif // !defined(UNDER_CE) ++ ++inline bool not_found_error(int errval) BOOST_NOEXCEPT ++{ ++ return errval == ERROR_FILE_NOT_FOUND || errval == ERROR_PATH_NOT_FOUND || errval == ERROR_INVALID_NAME // "tools/jam/src/:sys:stat.h", "//foo" ++ || errval == ERROR_INVALID_DRIVE // USB card reader with no card inserted ++ || errval == ERROR_NOT_READY // CD/DVD drive with no disc inserted ++ || errval == ERROR_INVALID_PARAMETER // ":sys:stat.h" ++ || errval == ERROR_BAD_PATHNAME // "//no-host" on Win64 ++ || errval == ERROR_BAD_NETPATH // "//no-host" on Win32 ++ || errval == ERROR_BAD_NET_NAME; // "//no-host/no-share" on Win10 x64 ++} ++ ++// these constants come from inspecting some Microsoft sample code ++inline std::time_t to_time_t(FILETIME const& ft) BOOST_NOEXCEPT ++{ ++ uint64_t t = (static_cast< uint64_t >(ft.dwHighDateTime) << 32) | ft.dwLowDateTime; ++ t -= 116444736000000000ull; ++ t /= 10000000u; ++ return static_cast< std::time_t >(t); ++} ++ ++inline void to_FILETIME(std::time_t t, FILETIME& ft) BOOST_NOEXCEPT ++{ ++ uint64_t temp = t; ++ temp *= 10000000u; ++ temp += 116444736000000000ull; ++ ft.dwLowDateTime = static_cast< DWORD >(temp); ++ ft.dwHighDateTime = static_cast< DWORD >(temp >> 32); ++} ++ ++} // unnamed namespace ++ ++#if !defined(UNDER_CE) ++ ++//! The flag indicates whether OBJ_DONT_REPARSE flag is not supported by the kernel ++static bool g_no_obj_dont_reparse = false; ++ ++//! Creates a file handle for a file relative to a previously opened base directory. The file path must be relative and in preferred format. ++boost::winapi::NTSTATUS_ nt_create_file_handle_at(HANDLE& out, HANDLE basedir_handle, boost::filesystem::path const& p, ULONG FileAttributes, ACCESS_MASK DesiredAccess, ULONG ShareMode, ULONG CreateDisposition, ULONG CreateOptions) ++{ ++ NtCreateFile_t* nt_create_file = filesystem::detail::atomic_load_relaxed(nt_create_file_api); ++ if (BOOST_UNLIKELY(!nt_create_file)) ++ return STATUS_NOT_IMPLEMENTED; ++ ++ unicode_string obj_name = {}; ++ obj_name.Buffer = const_cast< wchar_t* >(p.c_str()); ++ obj_name.Length = obj_name.MaximumLength = static_cast< USHORT >(p.size() * sizeof(wchar_t)); ++ ++ object_attributes obj_attrs = {}; ++ obj_attrs.Length = sizeof(obj_attrs); ++ obj_attrs.RootDirectory = basedir_handle; ++ obj_attrs.ObjectName = &obj_name; ++ ++ obj_attrs.Attributes = OBJ_CASE_INSENSITIVE; ++ if ((CreateOptions & FILE_OPEN_REPARSE_POINT) != 0u && !filesystem::detail::atomic_load_relaxed(g_no_obj_dont_reparse)) ++ obj_attrs.Attributes |= OBJ_DONT_REPARSE; ++ ++ io_status_block iosb; ++ boost::winapi::NTSTATUS_ status = nt_create_file ++ ( ++ &out, ++ DesiredAccess, ++ &obj_attrs, ++ &iosb, ++ NULL, // AllocationSize ++ FileAttributes, ++ ShareMode, ++ CreateDisposition, ++ CreateOptions, ++ NULL, // EaBuffer ++ 0u // EaLength ++ ); ++ ++ if (BOOST_UNLIKELY(status == STATUS_INVALID_PARAMETER && (obj_attrs.Attributes & OBJ_DONT_REPARSE) != 0u)) ++ { ++ // OBJ_DONT_REPARSE is supported since Windows 10, retry without it ++ filesystem::detail::atomic_store_relaxed(g_no_obj_dont_reparse, true); ++ obj_attrs.Attributes &= ~static_cast< ULONG >(OBJ_DONT_REPARSE); ++ ++ status = nt_create_file ++ ( ++ &out, ++ DesiredAccess, ++ &obj_attrs, ++ &iosb, ++ NULL, // AllocationSize ++ FileAttributes, ++ ShareMode, ++ CreateDisposition, ++ CreateOptions, ++ NULL, // EaBuffer ++ 0u // EaLength ++ ); ++ } ++ ++ return status; ++} ++ ++#endif // !defined(UNDER_CE) ++ ++ULONG get_reparse_point_tag_ioctl(HANDLE h) ++{ ++ boost::scoped_ptr< reparse_data_buffer_with_storage > buf(new reparse_data_buffer_with_storage); ++ ++ // Query the reparse data ++ DWORD dwRetLen = 0u; ++ BOOL result = ::DeviceIoControl(h, FSCTL_GET_REPARSE_POINT, NULL, 0, buf.get(), sizeof(*buf), &dwRetLen, NULL); ++ if (BOOST_UNLIKELY(!result)) ++ return false; ++ ++ return buf->rdb.ReparseTag; ++} ++ ++namespace { ++ ++inline bool is_reparse_point_a_symlink(path const& p) ++{ ++ handle_wrapper h(create_file_handle( ++ p, ++ FILE_READ_ATTRIBUTES | FILE_READ_EA, ++ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, ++ NULL, ++ OPEN_EXISTING, ++ FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT)); ++ if (BOOST_UNLIKELY(h.handle == INVALID_HANDLE_VALUE)) ++ return false; ++ ++ GetFileInformationByHandleEx_t* get_file_information_by_handle_ex = filesystem::detail::atomic_load_relaxed(get_file_information_by_handle_ex_api); ++ if (BOOST_LIKELY(get_file_information_by_handle_ex != NULL)) ++ { ++ file_attribute_tag_info info; ++ BOOL result = get_file_information_by_handle_ex(h.handle, file_attribute_tag_info_class, &info, sizeof(info)); ++ if (BOOST_UNLIKELY(!result)) ++ return false; ++ ++ if ((info.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) == 0u) ++ return false; ++ ++ return is_reparse_point_tag_a_symlink(info.ReparseTag); ++ } ++ ++ return is_reparse_point_a_symlink_ioctl(h.handle); ++} ++ ++inline std::size_t get_full_path_name(path const& src, std::size_t len, wchar_t* buf, wchar_t** p) ++{ ++ return static_cast< std::size_t >(::GetFullPathNameW(src.c_str(), static_cast< DWORD >(len), buf, p)); ++} ++ ++inline fs::file_status process_status_failure(DWORD errval, path const& p, error_code* ec) ++{ ++ if (ec) // always report errval, even though some ++ ec->assign(errval, system_category()); // errval values are not status_errors ++ ++ if (not_found_error(errval)) ++ { ++ return fs::file_status(fs::file_not_found, fs::no_perms); ++ } ++ else if (errval == ERROR_SHARING_VIOLATION) ++ { ++ return fs::file_status(fs::type_unknown); ++ } ++ ++ if (!ec) ++ BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::status", p, error_code(errval, system_category()))); ++ ++ return fs::file_status(fs::status_error); ++} ++ ++inline fs::file_status process_status_failure(path const& p, error_code* ec) ++{ ++ return process_status_failure(::GetLastError(), p, ec); ++} ++ ++//! (symlink_)status() by handle implementation ++fs::file_status status_by_handle(HANDLE h, path const& p, error_code* ec) ++{ ++ fs::file_type ftype; ++ DWORD attrs; ++ ULONG reparse_tag = 0u; ++ GetFileInformationByHandleEx_t* get_file_information_by_handle_ex = filesystem::detail::atomic_load_relaxed(get_file_information_by_handle_ex_api); ++ if (BOOST_LIKELY(get_file_information_by_handle_ex != NULL)) ++ { ++ file_attribute_tag_info info; ++ BOOL res = get_file_information_by_handle_ex(h, file_attribute_tag_info_class, &info, sizeof(info)); ++ if (BOOST_UNLIKELY(!res)) ++ { ++ // On FAT/exFAT filesystems requesting FILE_ATTRIBUTE_TAG_INFO returns ERROR_INVALID_PARAMETER. ++ // Presumably, this is because these filesystems don't support reparse points, so ReparseTag ++ // cannot be returned. Also check ERROR_NOT_SUPPORTED for good measure. Fall back to the legacy ++ // code path in this case. ++ DWORD err = ::GetLastError(); ++ if (err == ERROR_INVALID_PARAMETER || err == ERROR_NOT_SUPPORTED) ++ goto use_get_file_information_by_handle; ++ ++ return process_status_failure(err, p, ec); ++ } ++ ++ attrs = info.FileAttributes; ++ reparse_tag = info.ReparseTag; ++ } ++ else ++ { ++ use_get_file_information_by_handle: ++ BY_HANDLE_FILE_INFORMATION info; ++ BOOL res = ::GetFileInformationByHandle(h, &info); ++ if (BOOST_UNLIKELY(!res)) ++ return process_status_failure(p, ec); ++ ++ attrs = info.dwFileAttributes; ++ ++ if ((attrs & FILE_ATTRIBUTE_REPARSE_POINT) != 0u) ++ reparse_tag = get_reparse_point_tag_ioctl(h); ++ } ++ ++ if ((attrs & FILE_ATTRIBUTE_REPARSE_POINT) != 0u) ++ { ++ if (reparse_tag == IO_REPARSE_TAG_DEDUP) ++ ftype = fs::regular_file; ++ else if (is_reparse_point_tag_a_symlink(reparse_tag)) ++ ftype = fs::symlink_file; ++ else ++ ftype = fs::reparse_file; ++ } ++ else if ((attrs & FILE_ATTRIBUTE_DIRECTORY) != 0u) ++ { ++ ftype = fs::directory_file; ++ } ++ else ++ { ++ ftype = fs::regular_file; ++ } ++ ++ return fs::file_status(ftype, make_permissions(p, attrs)); ++} ++ ++//! symlink_status() implementation ++fs::file_status symlink_status_impl(path const& p, error_code* ec) ++{ ++ // Normally, we only need FILE_READ_ATTRIBUTES access mode. But SMBv1 reports incorrect ++ // file attributes in GetFileInformationByHandleEx in this case (e.g. it reports FILE_ATTRIBUTE_NORMAL ++ // for a directory in a SMBv1 share), so we add FILE_READ_EA as a workaround. ++ // https://github.com/boostorg/filesystem/issues/282 ++ handle_wrapper h(create_file_handle( ++ p.c_str(), ++ FILE_READ_ATTRIBUTES | FILE_READ_EA, ++ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, ++ NULL, // lpSecurityAttributes ++ OPEN_EXISTING, ++ FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT)); ++ ++ if (h.handle == INVALID_HANDLE_VALUE) ++ { ++ // For some system files and folders like "System Volume Information" CreateFileW fails ++ // with ERROR_ACCESS_DENIED. GetFileAttributesW succeeds for such files, so try that. ++ // Though this will only help if the file is not a reparse point (symlink or not). ++ DWORD err = ::GetLastError(); ++ if (err == ERROR_ACCESS_DENIED) ++ { ++ DWORD attrs = ::GetFileAttributesW(p.c_str()); ++ if (attrs != INVALID_FILE_ATTRIBUTES) ++ { ++ if ((attrs & FILE_ATTRIBUTE_REPARSE_POINT) == 0u) ++ return fs::file_status((attrs & FILE_ATTRIBUTE_DIRECTORY) ? fs::directory_file : fs::regular_file, make_permissions(p, attrs)); ++ } ++ else ++ { ++ err = ::GetLastError(); ++ } ++ } ++ ++ return process_status_failure(err, p, ec); ++ } ++ ++ return detail::status_by_handle(h.handle, p, ec); ++} ++ ++//! status() implementation ++fs::file_status status_impl(path const& p, error_code* ec) ++{ ++ // We should first test if the file is a symlink or a reparse point. Resolving some reparse ++ // points by opening the file may fail, and status() should return file_status(reparse_file) in this case. ++ // Which is what symlink_status() returns. ++ fs::file_status st(detail::symlink_status_impl(p, ec)); ++ if (st.type() == symlink_file) ++ { ++ // Resolve the symlink ++ handle_wrapper h(create_file_handle( ++ p.c_str(), ++ FILE_READ_ATTRIBUTES | FILE_READ_EA, // see the comment in symlink_status_impl re. access mode ++ FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, ++ NULL, // lpSecurityAttributes ++ OPEN_EXISTING, ++ FILE_FLAG_BACKUP_SEMANTICS)); ++ ++ if (h.handle == INVALID_HANDLE_VALUE) ++ return process_status_failure(p, ec); ++ ++ st = detail::status_by_handle(h.handle, p, ec); ++ } ++ ++ return st; ++} ++ ++//! remove() implementation for Windows XP and older ++bool remove_nt5_impl(path const& p, DWORD attrs, error_code* ec) ++{ ++ const bool is_directory = (attrs & FILE_ATTRIBUTE_DIRECTORY) != 0; ++ const bool is_read_only = (attrs & FILE_ATTRIBUTE_READONLY) != 0; ++ if (is_read_only) ++ { ++ // RemoveDirectoryW and DeleteFileW do not allow to remove a read-only file, so we have to drop the attribute ++ DWORD new_attrs = attrs & ~FILE_ATTRIBUTE_READONLY; ++ BOOL res = ::SetFileAttributesW(p.c_str(), new_attrs); ++ if (BOOST_UNLIKELY(!res)) ++ { ++ DWORD err = ::GetLastError(); ++ if (!not_found_error(err)) ++ emit_error(err, p, ec, "boost::filesystem::remove"); ++ ++ return false; ++ } ++ } ++ ++ BOOL res; ++ if (!is_directory) ++ { ++ // DeleteFileW works for file symlinks by removing the symlink, not the target. ++ res = ::DeleteFileW(p.c_str()); ++ } ++ else ++ { ++ // RemoveDirectoryW works for symlinks and junctions by removing the symlink, not the target, ++ // even if the target directory is not empty. ++ // Note that unlike opening the directory with FILE_FLAG_DELETE_ON_CLOSE flag, RemoveDirectoryW ++ // will fail if the directory is not empty. ++ res = ::RemoveDirectoryW(p.c_str()); ++ } ++ ++ if (BOOST_UNLIKELY(!res)) ++ { ++ DWORD err = ::GetLastError(); ++ if (!not_found_error(err)) ++ { ++ if (is_read_only) ++ { ++ // Try to restore the read-only attribute ++ ::SetFileAttributesW(p.c_str(), attrs); ++ } ++ ++ emit_error(err, p, ec, "boost::filesystem::remove"); ++ } ++ ++ return false; ++ } ++ ++ return true; ++} ++ ++//! remove() by handle implementation for Windows Vista and newer ++DWORD remove_nt6_by_handle(HANDLE handle, remove_impl_type impl) ++{ ++ GetFileInformationByHandleEx_t* get_file_information_by_handle_ex = filesystem::detail::atomic_load_relaxed(get_file_information_by_handle_ex_api); ++ SetFileInformationByHandle_t* set_file_information_by_handle = filesystem::detail::atomic_load_relaxed(set_file_information_by_handle_api); ++ DWORD err = 0u; ++ switch (impl) ++ { ++ case remove_disp_ex_flag_ignore_readonly: ++ { ++ file_disposition_info_ex info; ++ info.Flags = FILE_DISPOSITION_FLAG_DELETE | FILE_DISPOSITION_FLAG_POSIX_SEMANTICS | FILE_DISPOSITION_FLAG_IGNORE_READONLY_ATTRIBUTE; ++ BOOL res = set_file_information_by_handle(handle, file_disposition_info_ex_class, &info, sizeof(info)); ++ if (BOOST_LIKELY(!!res)) ++ break; ++ ++ err = ::GetLastError(); ++ if (BOOST_UNLIKELY(err == ERROR_INVALID_PARAMETER || err == ERROR_INVALID_FUNCTION || err == ERROR_NOT_SUPPORTED || err == ERROR_CALL_NOT_IMPLEMENTED)) ++ { ++ // Downgrade to the older implementation ++ impl = remove_disp_ex_flag_posix_semantics; ++ filesystem::detail::atomic_store_relaxed(g_remove_impl_type, impl); ++ } ++ else ++ { ++ break; ++ } ++ } ++ BOOST_FALLTHROUGH; ++ ++ case remove_disp_ex_flag_posix_semantics: ++ { ++ file_disposition_info_ex info; ++ info.Flags = FILE_DISPOSITION_FLAG_DELETE | FILE_DISPOSITION_FLAG_POSIX_SEMANTICS; ++ BOOL res = set_file_information_by_handle(handle, file_disposition_info_ex_class, &info, sizeof(info)); ++ if (BOOST_LIKELY(!!res)) ++ { ++ err = 0u; ++ break; ++ } ++ ++ err = ::GetLastError(); ++ if (err == ERROR_ACCESS_DENIED) ++ { ++ // Check if the file is read-only and reset the attribute ++ file_basic_info basic_info; ++ res = get_file_information_by_handle_ex(handle, file_basic_info_class, &basic_info, sizeof(basic_info)); ++ if (BOOST_UNLIKELY(!res || (basic_info.FileAttributes & FILE_ATTRIBUTE_READONLY) == 0)) ++ break; // return ERROR_ACCESS_DENIED ++ ++ basic_info.FileAttributes &= ~FILE_ATTRIBUTE_READONLY; ++ ++ res = set_file_information_by_handle(handle, file_basic_info_class, &basic_info, sizeof(basic_info)); ++ if (BOOST_UNLIKELY(!res)) ++ { ++ err = ::GetLastError(); ++ break; ++ } ++ ++ // Try to set the flag again ++ res = set_file_information_by_handle(handle, file_disposition_info_ex_class, &info, sizeof(info)); ++ if (BOOST_LIKELY(!!res)) ++ { ++ err = 0u; ++ break; ++ } ++ ++ err = ::GetLastError(); ++ ++ // Try to restore the read-only flag ++ basic_info.FileAttributes |= FILE_ATTRIBUTE_READONLY; ++ set_file_information_by_handle(handle, file_basic_info_class, &basic_info, sizeof(basic_info)); ++ ++ break; ++ } ++ else if (BOOST_UNLIKELY(err == ERROR_INVALID_PARAMETER || err == ERROR_INVALID_FUNCTION || err == ERROR_NOT_SUPPORTED || err == ERROR_CALL_NOT_IMPLEMENTED)) ++ { ++ // Downgrade to the older implementation ++ impl = remove_disp; ++ filesystem::detail::atomic_store_relaxed(g_remove_impl_type, impl); ++ } ++ else ++ { ++ break; ++ } ++ } ++ BOOST_FALLTHROUGH; ++ ++ default: ++ { ++ file_disposition_info info; ++ info.DeleteFile = true; ++ BOOL res = set_file_information_by_handle(handle, file_disposition_info_class, &info, sizeof(info)); ++ if (BOOST_LIKELY(!!res)) ++ { ++ err = 0u; ++ break; ++ } ++ ++ err = ::GetLastError(); ++ if (err == ERROR_ACCESS_DENIED) ++ { ++ // Check if the file is read-only and reset the attribute ++ file_basic_info basic_info; ++ res = get_file_information_by_handle_ex(handle, file_basic_info_class, &basic_info, sizeof(basic_info)); ++ if (BOOST_UNLIKELY(!res || (basic_info.FileAttributes & FILE_ATTRIBUTE_READONLY) == 0)) ++ break; // return ERROR_ACCESS_DENIED ++ ++ basic_info.FileAttributes &= ~FILE_ATTRIBUTE_READONLY; ++ ++ res = set_file_information_by_handle(handle, file_basic_info_class, &basic_info, sizeof(basic_info)); ++ if (BOOST_UNLIKELY(!res)) ++ { ++ err = ::GetLastError(); ++ break; ++ } ++ ++ // Try to set the flag again ++ res = set_file_information_by_handle(handle, file_disposition_info_class, &info, sizeof(info)); ++ if (BOOST_LIKELY(!!res)) ++ { ++ err = 0u; ++ break; ++ } ++ ++ err = ::GetLastError(); ++ ++ // Try to restore the read-only flag ++ basic_info.FileAttributes |= FILE_ATTRIBUTE_READONLY; ++ set_file_information_by_handle(handle, file_basic_info_class, &basic_info, sizeof(basic_info)); ++ } ++ ++ break; ++ } ++ } ++ ++ return err; ++} ++ ++//! remove() implementation for Windows Vista and newer ++inline bool remove_nt6_impl(path const& p, remove_impl_type impl, error_code* ec) ++{ ++ handle_wrapper h(create_file_handle( ++ p, ++ DELETE | FILE_READ_ATTRIBUTES | FILE_READ_EA | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA, ++ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, ++ NULL, ++ OPEN_EXISTING, ++ FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT)); ++ DWORD err = 0u; ++ if (BOOST_UNLIKELY(h.handle == INVALID_HANDLE_VALUE)) ++ { ++ err = ::GetLastError(); ++ ++ return_error: ++ if (!not_found_error(err)) ++ emit_error(err, p, ec, "boost::filesystem::remove"); ++ ++ return false; ++ } ++ ++ err = fs::detail::remove_nt6_by_handle(h.handle, impl); ++ if (BOOST_UNLIKELY(err != 0u)) ++ goto return_error; ++ ++ return true; ++} ++ ++//! remove() implementation ++inline bool remove_impl(path const& p, error_code* ec) ++{ ++ remove_impl_type impl = fs::detail::atomic_load_relaxed(g_remove_impl_type); ++ if (BOOST_LIKELY(impl != remove_nt5)) ++ { ++ return fs::detail::remove_nt6_impl(p, impl, ec); ++ } ++ else ++ { ++ const DWORD attrs = ::GetFileAttributesW(p.c_str()); ++ if (BOOST_UNLIKELY(attrs == INVALID_FILE_ATTRIBUTES)) ++ { ++ DWORD err = ::GetLastError(); ++ if (!not_found_error(err)) ++ emit_error(err, p, ec, "boost::filesystem::remove"); ++ ++ return false; ++ } ++ ++ return fs::detail::remove_nt5_impl(p, attrs, ec); ++ } ++} ++ ++#if !defined(UNDER_CE) ++ ++//! remove_all() by handle implementation for Windows Vista and newer ++uintmax_t remove_all_nt6_by_handle(HANDLE h, path const& p, error_code* ec) ++{ ++ error_code local_ec; ++ fs::file_status st(fs::detail::status_by_handle(h, p, &local_ec)); ++ if (BOOST_UNLIKELY(st.type() == fs::status_error)) ++ { ++ if (!ec) ++ BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::remove_all", p, local_ec)); ++ ++ *ec = local_ec; ++ return static_cast< uintmax_t >(-1); ++ } ++ ++ uintmax_t count = 0u; ++ if (st.type() == fs::directory_file) ++ { ++ local_ec.clear(); ++ ++ fs::directory_iterator itr; ++ directory_iterator_params params; ++ params.use_handle = h; ++ params.close_handle = false; // the caller will close the handle ++ fs::detail::directory_iterator_construct(itr, p, static_cast< unsigned int >(directory_options::_detail_no_follow), ¶ms, &local_ec); ++ if (BOOST_UNLIKELY(!!local_ec)) ++ { ++ if (!ec) ++ BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::remove_all", p, local_ec)); ++ ++ *ec = local_ec; ++ return static_cast< uintmax_t >(-1); ++ } ++ ++ NtCreateFile_t* nt_create_file = filesystem::detail::atomic_load_relaxed(nt_create_file_api); ++ const fs::directory_iterator end_dit; ++ while (itr != end_dit) ++ { ++ fs::path nested_path(itr->path()); ++ handle_wrapper hh; ++ if (BOOST_LIKELY(nt_create_file != NULL)) ++ { ++ // Note: WinAPI methods like CreateFileW implicitly request SYNCHRONIZE access but NtCreateFile doesn't. ++ // Without SYNCHRONIZE access querying file attributes via GetFileInformationByHandleEx fails with ERROR_ACCESS_DENIED. ++ boost::winapi::NTSTATUS_ status = nt_create_file_handle_at ++ ( ++ hh.handle, ++ h, ++ path_algorithms::filename_v4(nested_path), ++ 0u, // FileAttributes ++ FILE_LIST_DIRECTORY | DELETE | FILE_READ_ATTRIBUTES | FILE_READ_EA | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA | SYNCHRONIZE, ++ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, ++ FILE_OPEN, ++ FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT | FILE_OPEN_REPARSE_POINT ++ ); ++ ++ if (!NT_SUCCESS(status)) ++ { ++ if (status == STATUS_NO_SUCH_FILE || ++ status == STATUS_OBJECT_NAME_NOT_FOUND || ++ status == STATUS_OBJECT_PATH_NOT_FOUND || ++ status == STATUS_BAD_NETWORK_PATH || ++ status == STATUS_BAD_NETWORK_NAME) ++ { ++ goto next_entry; ++ } ++ ++ DWORD err = translate_ntstatus(status); ++ emit_error(err, nested_path, ec, "boost::filesystem::remove_all"); ++ return static_cast< uintmax_t >(-1); ++ } ++ } ++ else ++ { ++ hh.handle = create_file_handle( ++ nested_path, ++ FILE_LIST_DIRECTORY | DELETE | FILE_READ_ATTRIBUTES | FILE_READ_EA | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA | SYNCHRONIZE, ++ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, ++ NULL, ++ OPEN_EXISTING, ++ FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT); ++ ++ if (BOOST_UNLIKELY(hh.handle == INVALID_HANDLE_VALUE)) ++ { ++ DWORD err = ::GetLastError(); ++ if (not_found_error(err)) ++ goto next_entry; ++ ++ emit_error(err, nested_path, ec, "boost::filesystem::remove_all"); ++ return static_cast< uintmax_t >(-1); ++ } ++ } ++ ++ count += fs::detail::remove_all_nt6_by_handle(hh.handle, nested_path, ec); ++ if (ec && *ec) ++ return static_cast< uintmax_t >(-1); ++ ++ next_entry: ++ fs::detail::directory_iterator_increment(itr, ec); ++ if (ec && *ec) ++ return static_cast< uintmax_t >(-1); ++ } ++ } ++ ++ DWORD err = fs::detail::remove_nt6_by_handle(h, fs::detail::atomic_load_relaxed(g_remove_impl_type)); ++ if (BOOST_UNLIKELY(err != 0u)) ++ { ++ emit_error(err, p, ec, "boost::filesystem::remove_all"); ++ return static_cast< uintmax_t >(-1); ++ } ++ ++ ++count; ++ return count; ++} ++ ++#endif // !defined(UNDER_CE) ++ ++//! remove_all() implementation for Windows XP and older ++uintmax_t remove_all_nt5_impl(path const& p, error_code* ec) ++{ ++ error_code dit_create_ec; ++ for (unsigned int attempt = 0u; attempt < remove_all_directory_replaced_retry_count; ++attempt) ++ { ++ const DWORD attrs = ::GetFileAttributesW(p.c_str()); ++ if (BOOST_UNLIKELY(attrs == INVALID_FILE_ATTRIBUTES)) ++ { ++ DWORD err = ::GetLastError(); ++ if (not_found_error(err)) ++ return 0u; ++ ++ emit_error(err, p, ec, "boost::filesystem::remove_all"); ++ return static_cast< uintmax_t >(-1); ++ } ++ ++ // Recurse into directories, but not into junctions or directory symlinks ++ const bool recurse = (attrs & FILE_ATTRIBUTE_DIRECTORY) != 0 && (attrs & FILE_ATTRIBUTE_REPARSE_POINT) == 0; ++ uintmax_t count = 0u; ++ if (recurse) ++ { ++ fs::directory_iterator itr; ++ fs::detail::directory_iterator_construct(itr, p, static_cast< unsigned int >(directory_options::_detail_no_follow), NULL, &dit_create_ec); ++ if (BOOST_UNLIKELY(!!dit_create_ec)) ++ { ++ if (dit_create_ec == make_error_condition(system::errc::not_a_directory) || ++ dit_create_ec == make_error_condition(system::errc::too_many_symbolic_link_levels)) ++ { ++ continue; ++ } ++ ++ if (!ec) ++ BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::remove_all", p, dit_create_ec)); ++ ++ *ec = dit_create_ec; ++ return static_cast< uintmax_t >(-1); ++ } ++ ++ const fs::directory_iterator end_dit; ++ while (itr != end_dit) ++ { ++ count += fs::detail::remove_all_nt5_impl(itr->path(), ec); ++ if (ec && *ec) ++ return static_cast< uintmax_t >(-1); ++ ++ fs::detail::directory_iterator_increment(itr, ec); ++ if (ec && *ec) ++ return static_cast< uintmax_t >(-1); ++ } ++ } ++ ++ bool removed = fs::detail::remove_nt5_impl(p, attrs, ec); ++ if (ec && *ec) ++ return static_cast< uintmax_t >(-1); ++ ++ count += removed; ++ return count; ++ } ++ ++ if (!ec) ++ BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::remove_all: path cannot be opened as a directory", p, dit_create_ec)); ++ ++ *ec = dit_create_ec; ++ return static_cast< uintmax_t >(-1); ++} ++ ++//! remove_all() implementation ++inline uintmax_t remove_all_impl(path const& p, error_code* ec) ++{ ++#if !defined(UNDER_CE) ++ remove_impl_type impl = fs::detail::atomic_load_relaxed(g_remove_impl_type); ++ if (BOOST_LIKELY(impl != remove_nt5)) ++ { ++ handle_wrapper h(create_file_handle( ++ p, ++ FILE_LIST_DIRECTORY | DELETE | FILE_READ_ATTRIBUTES | FILE_READ_EA | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA | SYNCHRONIZE, ++ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, ++ NULL, ++ OPEN_EXISTING, ++ FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT)); ++ ++ if (BOOST_UNLIKELY(h.handle == INVALID_HANDLE_VALUE)) ++ { ++ DWORD err = ::GetLastError(); ++ if (not_found_error(err)) ++ return 0u; ++ ++ emit_error(err, p, ec, "boost::filesystem::remove_all"); ++ return static_cast< uintmax_t >(-1); ++ } ++ ++ return fs::detail::remove_all_nt6_by_handle(h.handle, p, ec); ++ } ++#endif // !defined(UNDER_CE) ++ ++ return fs::detail::remove_all_nt5_impl(p, ec); ++} ++ ++inline BOOL resize_file_impl(const wchar_t* p, uintmax_t size) ++{ ++ handle_wrapper h(CreateFileW(p, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)); ++ LARGE_INTEGER sz; ++ sz.QuadPart = size; ++ return h.handle != INVALID_HANDLE_VALUE && ::SetFilePointerEx(h.handle, sz, 0, FILE_BEGIN) && ::SetEndOfFile(h.handle); ++} ++ ++//! Converts NT path to a Win32 path ++inline path convert_nt_path_to_win32_path(const wchar_t* nt_path, std::size_t size) ++{ ++ // https://googleprojectzero.blogspot.com/2016/02/the-definitive-guide-on-win32-to-nt.html ++ // https://stackoverflow.com/questions/23041983/path-prefixes-and ++ // ++ // NT paths can be used to identify practically any named objects, devices, files, local and remote shares, etc. ++ // The path starts with a leading backslash and consists of one or more path elements separated with backslashes. ++ // The set of characters allowed in NT path elements is significantly larger than that of Win32 paths - basically, ++ // any character except the backslash is allowed. Path elements are case-insensitive. ++ // ++ // NT paths that start with the "\??\" prefix are used to indicate the current user's session namespace. The prefix ++ // indicates to the NT object manager to lookup the object relative to "\Sessions\0\DosDevices\[Logon Authentication ID]". ++ // ++ // There is also a special "\Global??\" prefix that refers to the system logon. User's session directory shadows ++ // the system logon directory, so that when the referenced object is not found in the user's namespace, ++ // system logon is looked up instead. ++ // ++ // There is a symlink "Global" in the user's session namespace that refers to the global namespace, so "\??\Global" ++ // effectively resolves to "\Global??". This allows Win32 applications to directly refer to the system objects, ++ // even if shadowed by the current user's logon object. ++ // ++ // NT paths can be used to reference not only local filesystems, but also devices and remote shares identifiable via ++ // UNC paths. For this, there is a special "UNC" device (which is a symlink to "\Device\Mup") in the system logon ++ // namespace, so "\??\UNC\host\share" (or "\??\Global\UNC\host\share", or "\Global??\UNC\host\share") is equivalent ++ // to "\\host\share". ++ // ++ // NT paths are not universally accepted by Win32 applications and APIs. For example, Far supports paths starting ++ // with "\??\" and "\??\Global\" but not with "\Global??\". As of Win10 21H1, File Explorer, cmd.exe and PowerShell ++ // don't support any of these. Given this, and that NT paths have a different set of allowed characters from Win32 paths, ++ // we should normally avoid exposing NT paths to users that expect Win32 paths. ++ // ++ // In Boost.Filesystem we only deal with NT paths that come from reparse points, such as symlinks and mount points, ++ // including directory junctions. It was observed that reparse points created by junction.exe and mklink use the "\??\" ++ // prefix for directory junctions and absolute symlink and unqualified relative path for relative symlinks. ++ // Absolute paths are using drive letters for mounted drives (e.g. "\??\C:\directory"), although it is possible ++ // to create a junction to an directory using a different way of identifying the filesystem (e.g. ++ // "\??\Volume{00000000-0000-0000-0000-000000000000}\directory"). ++ // mklink does not support creating junctions pointing to a UNC path. junction.exe does create a junction that ++ // uses a seemingly invalid syntax like "\??\\\host\share", i.e. it basically does not expect an UNC path. It is not known ++ // if reparse points that refer to a UNC path are considered valid. ++ // There are reparse points created as mount points for local and remote filsystems (for example, a cloud storage mounted ++ // in the local filesystem). Such mount points have the form of "\??\Volume{00000000-0000-0000-0000-000000000000}\", ++ // "\??\Harddisk0Partition1\" or "\??\HarddiskVolume1\". ++ // Reparse points that refer directly to a global namespace (through "\??\Global\" or "\Global??\" prefixes) or ++ // devices (e.g. "\Device\HarddiskVolume1") have not been observed so far. ++ ++ path win32_path; ++ std::size_t pos = 0u; ++ bool global_namespace = false; ++ ++ // Check for the "\??\" prefix ++ if (size >= 4u && ++ nt_path[0] == path::preferred_separator && ++ nt_path[1] == questionmark && ++ nt_path[2] == questionmark && ++ nt_path[3] == path::preferred_separator) ++ { ++ pos = 4u; ++ ++ // Check "Global" ++ if ((size - pos) >= 6u && ++ (nt_path[pos] == L'G' || nt_path[pos] == L'g') && ++ (nt_path[pos + 1] == L'l' || nt_path[pos + 1] == L'L') && ++ (nt_path[pos + 2] == L'o' || nt_path[pos + 2] == L'O') && ++ (nt_path[pos + 3] == L'b' || nt_path[pos + 3] == L'B') && ++ (nt_path[pos + 4] == L'a' || nt_path[pos + 4] == L'A') && ++ (nt_path[pos + 5] == L'l' || nt_path[pos + 5] == L'L')) ++ { ++ if ((size - pos) == 6u) ++ { ++ pos += 6u; ++ global_namespace = true; ++ } ++ else if (detail::is_directory_separator(nt_path[pos + 6u])) ++ { ++ pos += 7u; ++ global_namespace = true; ++ } ++ } ++ } ++ // Check for the "\Global??\" prefix ++ else if (size >= 10u && ++ nt_path[0] == path::preferred_separator && ++ (nt_path[1] == L'G' || nt_path[1] == L'g') && ++ (nt_path[2] == L'l' || nt_path[2] == L'L') && ++ (nt_path[3] == L'o' || nt_path[3] == L'O') && ++ (nt_path[4] == L'b' || nt_path[4] == L'B') && ++ (nt_path[5] == L'a' || nt_path[5] == L'A') && ++ (nt_path[6] == L'l' || nt_path[6] == L'L') && ++ nt_path[7] == questionmark && ++ nt_path[8] == questionmark && ++ nt_path[9] == path::preferred_separator) ++ { ++ pos = 10u; ++ global_namespace = true; ++ } ++ ++ if (pos > 0u) ++ { ++ if ((size - pos) >= 2u && ++ ( ++ // Check if the following is a drive letter ++ ( ++ detail::is_letter(nt_path[pos]) && nt_path[pos + 1u] == colon && ++ ((size - pos) == 2u || detail::is_directory_separator(nt_path[pos + 2u])) ++ ) || ++ // Check for an "incorrect" syntax for UNC path junction points ++ ( ++ detail::is_directory_separator(nt_path[pos]) && detail::is_directory_separator(nt_path[pos + 1u]) && ++ ((size - pos) == 2u || !detail::is_directory_separator(nt_path[pos + 2u])) ++ ) ++ )) ++ { ++ // Strip the NT path prefix ++ goto done; ++ } ++ ++ static const wchar_t win32_path_prefix[4u] = { path::preferred_separator, path::preferred_separator, questionmark, path::preferred_separator }; ++ ++ // Check for a UNC path ++ if ((size - pos) >= 4u && ++ (nt_path[pos] == L'U' || nt_path[pos] == L'u') && ++ (nt_path[pos + 1] == L'N' || nt_path[pos + 1] == L'n') && ++ (nt_path[pos + 2] == L'C' || nt_path[pos + 2] == L'c') && ++ nt_path[pos + 3] == path::preferred_separator) ++ { ++ win32_path.assign(win32_path_prefix, win32_path_prefix + 2); ++ pos += 4u; ++ goto done; ++ } ++ ++ // This is some other NT path, possibly a volume mount point. Replace the NT prefix with a Win32 filesystem prefix "\\?\". ++ win32_path.assign(win32_path_prefix, win32_path_prefix + 4); ++ if (global_namespace) ++ { ++ static const wchar_t win32_path_global_prefix[7u] = { L'G', L'l', L'o', L'b', L'a', L'l', path::preferred_separator }; ++ win32_path.concat(win32_path_global_prefix, win32_path_global_prefix + 7); ++ } ++ } ++ ++done: ++ win32_path.concat(nt_path + pos, nt_path + size); ++ return win32_path; ++} ++ ++#endif // defined(BOOST_POSIX_API) ++ ++} // unnamed namespace ++} // namespace detail ++ ++//--------------------------------------------------------------------------------------// ++// // ++// operations functions declared in operations.hpp // ++// // ++//--------------------------------------------------------------------------------------// ++ ++namespace detail { ++ ++BOOST_FILESYSTEM_DECL bool possible_large_file_size_support() ++{ ++#ifdef BOOST_POSIX_API ++ typedef struct stat struct_stat; ++ return sizeof(struct_stat().st_size) > 4; ++#else ++ return true; ++#endif ++} ++ ++BOOST_FILESYSTEM_DECL ++path absolute(path const& p, path const& base, system::error_code* ec) ++{ ++ if (ec) ++ ec->clear(); ++ ++ if (p.is_absolute()) ++ return p; ++ ++ // recursively calling absolute is sub-optimal, but is sure and simple ++ path abs_base = base; ++ if (!base.is_absolute()) ++ { ++ if (ec) ++ { ++ abs_base = absolute(base, *ec); ++ if (*ec) ++ return path(); ++ } ++ else ++ { ++ abs_base = absolute(base); ++ } ++ } ++ ++ if (p.empty()) ++ return abs_base; ++ ++ path res; ++ if (p.has_root_name()) ++ res = p.root_name(); ++ else ++ res = abs_base.root_name(); ++ ++ if (p.has_root_directory()) ++ { ++ res.concat(p.root_directory()); ++ } ++ else ++ { ++ res.concat(abs_base.root_directory()); ++ path_algorithms::append_v4(res, abs_base.relative_path()); ++ } ++ ++ path p_relative_path(p.relative_path()); ++ if (!p_relative_path.empty()) ++ path_algorithms::append_v4(res, p_relative_path); ++ ++ return res; ++} ++ ++BOOST_FILESYSTEM_DECL ++path canonical(path const& p, path const& base, system::error_code* ec) ++{ ++ if (ec) ++ ec->clear(); ++ ++ path source(p); ++ if (!p.is_absolute()) ++ { ++ source = detail::absolute(p, base, ec); ++ if (ec && *ec) ++ { ++ return_empty_path: ++ return path(); ++ } ++ } ++ ++ system::error_code local_ec; ++ file_status st(detail::status_impl(source, &local_ec)); ++ ++ if (st.type() == fs::file_not_found) ++ { ++ local_ec = system::errc::make_error_code(system::errc::no_such_file_or_directory); ++ goto fail_local_ec; ++ } ++ else if (local_ec) ++ { ++ fail_local_ec: ++ if (!ec) ++ BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::canonical", source, local_ec)); ++ ++ *ec = local_ec; ++ goto return_empty_path; ++ } ++ ++ path root(source.root_path()); ++ path const& dot_p = dot_path(); ++ path const& dot_dot_p = dot_dot_path(); ++ unsigned int symlinks_allowed = symloop_max; ++ path result; ++ while (true) ++ { ++ for (path::iterator itr(source.begin()), end(source.end()); itr != end; path_algorithms::increment_v4(itr)) ++ { ++ if (path_algorithms::compare_v4(*itr, dot_p) == 0) ++ continue; ++ if (path_algorithms::compare_v4(*itr, dot_dot_p) == 0) ++ { ++ if (path_algorithms::compare_v4(result, root) != 0) ++ result.remove_filename_and_trailing_separators(); ++ continue; ++ } ++ ++ if (itr->size() == 1u && detail::is_directory_separator(itr->native()[0])) ++ { ++ // Convert generic separator returned by the iterator for the root directory to ++ // the preferred separator. This is important on Windows, as in some cases, ++ // like paths for network shares and cloud storage mount points GetFileAttributesW ++ // will return "file not found" if the path contains forward slashes. ++ result += path::preferred_separator; ++ // We don't need to check for a symlink after adding a separator. ++ continue; ++ } ++ ++ path_algorithms::append_v4(result, *itr); ++ ++ // If we don't have an absolute path yet then don't check symlink status. ++ // This avoids checking "C:" which is "the current directory on drive C" ++ // and hence not what we want to check/resolve here. ++ if (!result.is_absolute()) ++ continue; ++ ++ st = detail::symlink_status_impl(result, ec); ++ if (ec && *ec) ++ goto return_empty_path; ++ ++ if (is_symlink(st)) ++ { ++ if (symlinks_allowed == 0) ++ { ++ local_ec = system::errc::make_error_code(system::errc::too_many_symbolic_link_levels); ++ goto fail_local_ec; ++ } ++ ++ --symlinks_allowed; ++ ++ path link(detail::read_symlink(result, ec)); ++ if (ec && *ec) ++ goto return_empty_path; ++ result.remove_filename_and_trailing_separators(); ++ ++ if (link.is_absolute()) ++ { ++ for (path_algorithms::increment_v4(itr); itr != end; path_algorithms::increment_v4(itr)) ++ { ++ if (path_algorithms::compare_v4(*itr, dot_p) != 0) ++ path_algorithms::append_v4(link, *itr); ++ } ++ source = link; ++ root = source.root_path(); ++ } ++ else // link is relative ++ { ++ link.remove_trailing_separator(); ++ if (path_algorithms::compare_v4(link, dot_p) == 0) ++ continue; ++ ++ path new_source(result); ++ path_algorithms::append_v4(new_source, link); ++ for (path_algorithms::increment_v4(itr); itr != end; path_algorithms::increment_v4(itr)) ++ { ++ if (path_algorithms::compare_v4(*itr, dot_p) != 0) ++ path_algorithms::append_v4(new_source, *itr); ++ } ++ source = new_source; ++ } ++ ++ // symlink causes scan to be restarted ++ goto restart_scan; ++ } ++ } ++ ++ break; ++ ++ restart_scan: ++ result.clear(); ++ } ++ ++ BOOST_ASSERT_MSG(result.is_absolute(), "canonical() implementation error; please report"); ++ return result; ++} ++ ++BOOST_FILESYSTEM_DECL ++void copy(path const& from, path const& to, unsigned int options, system::error_code* ec) ++{ ++ BOOST_ASSERT((((options & static_cast< unsigned int >(copy_options::overwrite_existing)) != 0u) + ++ ((options & static_cast< unsigned int >(copy_options::skip_existing)) != 0u) + ++ ((options & static_cast< unsigned int >(copy_options::update_existing)) != 0u)) <= 1); ++ ++ BOOST_ASSERT((((options & static_cast< unsigned int >(copy_options::copy_symlinks)) != 0u) + ++ ((options & static_cast< unsigned int >(copy_options::skip_symlinks)) != 0u)) <= 1); ++ ++ BOOST_ASSERT((((options & static_cast< unsigned int >(copy_options::directories_only)) != 0u) + ++ ((options & static_cast< unsigned int >(copy_options::create_symlinks)) != 0u) + ++ ((options & static_cast< unsigned int >(copy_options::create_hard_links)) != 0u)) <= 1); ++ ++ if (ec) ++ ec->clear(); ++ ++ file_status from_stat; ++ if ((options & (static_cast< unsigned int >(copy_options::copy_symlinks) | ++ static_cast< unsigned int >(copy_options::skip_symlinks) | ++ static_cast< unsigned int >(copy_options::create_symlinks))) != 0u) ++ { ++ from_stat = detail::symlink_status_impl(from, ec); ++ } ++ else ++ { ++ from_stat = detail::status_impl(from, ec); ++ } ++ ++ if (ec && *ec) ++ return; ++ ++ if (!exists(from_stat)) ++ { ++ emit_error(BOOST_ERROR_FILE_NOT_FOUND, from, to, ec, "boost::filesystem::copy"); ++ return; ++ } ++ ++ if (is_symlink(from_stat)) ++ { ++ if ((options & static_cast< unsigned int >(copy_options::skip_symlinks)) != 0u) ++ return; ++ ++ if ((options & static_cast< unsigned int >(copy_options::copy_symlinks)) == 0u) ++ goto fail; ++ ++ detail::copy_symlink(from, to, ec); ++ } ++ else if (is_regular_file(from_stat)) ++ { ++ if ((options & static_cast< unsigned int >(copy_options::directories_only)) != 0u) ++ return; ++ ++ if ((options & static_cast< unsigned int >(copy_options::create_symlinks)) != 0u) ++ { ++ const path* pfrom = &from; ++ path relative_from; ++ if (!from.is_absolute()) ++ { ++ // Try to generate a relative path from the target location to the original file ++ path cur_dir = detail::current_path(ec); ++ if (ec && *ec) ++ return; ++ path abs_from = detail::absolute(from.parent_path(), cur_dir, ec); ++ if (ec && *ec) ++ return; ++ path abs_to = to.parent_path(); ++ if (!abs_to.is_absolute()) ++ { ++ abs_to = detail::absolute(abs_to, cur_dir, ec); ++ if (ec && *ec) ++ return; ++ } ++ relative_from = detail::relative(abs_from, abs_to, ec); ++ if (ec && *ec) ++ return; ++ if (path_algorithms::compare_v4(relative_from, dot_path()) != 0) ++ path_algorithms::append_v4(relative_from, path_algorithms::filename_v4(from)); ++ else ++ relative_from = path_algorithms::filename_v4(from); ++ pfrom = &relative_from; ++ } ++ detail::create_symlink(*pfrom, to, ec); ++ return; ++ } ++ ++ if ((options & static_cast< unsigned int >(copy_options::create_hard_links)) != 0u) ++ { ++ detail::create_hard_link(from, to, ec); ++ return; ++ } ++ ++ error_code local_ec; ++ file_status to_stat; ++ if ((options & (static_cast< unsigned int >(copy_options::skip_symlinks) | ++ static_cast< unsigned int >(copy_options::create_symlinks))) != 0u) ++ { ++ to_stat = detail::symlink_status_impl(to, &local_ec); ++ } ++ else ++ { ++ to_stat = detail::status_impl(to, &local_ec); ++ } ++ ++ // Note: local_ec may be set by (symlink_)status() even in some non-fatal situations, e.g. when the file does not exist. ++ // OTOH, when it returns status_error, then a real error have happened and it must have set local_ec. ++ if (to_stat.type() == fs::status_error) ++ { ++ if (!ec) ++ BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::copy", from, to, local_ec)); ++ *ec = local_ec; ++ return; ++ } ++ ++ if (is_directory(to_stat)) ++ { ++ path target(to); ++ path_algorithms::append_v4(target, path_algorithms::filename_v4(from)); ++ detail::copy_file(from, target, options, ec); ++ } ++ else ++ detail::copy_file(from, to, options, ec); ++ } ++ else if (is_directory(from_stat)) ++ { ++ error_code local_ec; ++ if ((options & static_cast< unsigned int >(copy_options::create_symlinks)) != 0u) ++ { ++ local_ec = make_error_code(system::errc::is_a_directory); ++ if (!ec) ++ BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::copy", from, to, local_ec)); ++ *ec = local_ec; ++ return; ++ } ++ ++ file_status to_stat; ++ if ((options & (static_cast< unsigned int >(copy_options::skip_symlinks) | ++ static_cast< unsigned int >(copy_options::create_symlinks))) != 0u) ++ { ++ to_stat = detail::symlink_status_impl(to, &local_ec); ++ } ++ else ++ { ++ to_stat = detail::status_impl(to, &local_ec); ++ } ++ ++ // Note: ec may be set by (symlink_)status() even in some non-fatal situations, e.g. when the file does not exist. ++ // OTOH, when it returns status_error, then a real error have happened and it must have set local_ec. ++ if (to_stat.type() == fs::status_error) ++ { ++ if (!ec) ++ BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::copy", from, to, local_ec)); ++ *ec = local_ec; ++ return; ++ } ++ ++ if (!exists(to_stat)) ++ { ++ detail::create_directory(to, &from, ec); ++ if (ec && *ec) ++ return; ++ } ++ ++ if ((options & static_cast< unsigned int >(copy_options::recursive)) != 0u || options == 0u) ++ { ++ fs::directory_iterator itr; ++ detail::directory_iterator_construct(itr, from, static_cast< unsigned int >(directory_options::none), NULL, ec); ++ if (ec && *ec) ++ return; ++ ++ const fs::directory_iterator end_dit; ++ while (itr != end_dit) ++ { ++ path const& p = itr->path(); ++ { ++ path target(to); ++ path_algorithms::append_v4(target, path_algorithms::filename_v4(p)); ++ // Set _detail_recursing flag so that we don't recurse more than for one level deeper into the directory if options are copy_options::none ++ detail::copy(p, target, options | static_cast< unsigned int >(copy_options::_detail_recursing), ec); ++ } ++ if (ec && *ec) ++ return; ++ ++ detail::directory_iterator_increment(itr, ec); ++ if (ec && *ec) ++ return; ++ } ++ } ++ } ++ else ++ { ++ fail: ++ emit_error(BOOST_ERROR_NOT_SUPPORTED, from, to, ec, "boost::filesystem::copy"); ++ } ++} ++ ++BOOST_FILESYSTEM_DECL ++bool copy_file(path const& from, path const& to, unsigned int options, error_code* ec) ++{ ++ BOOST_ASSERT((((options & static_cast< unsigned int >(copy_options::overwrite_existing)) != 0u) + ++ ((options & static_cast< unsigned int >(copy_options::skip_existing)) != 0u) + ++ ((options & static_cast< unsigned int >(copy_options::update_existing)) != 0u)) <= 1); ++ ++ if (ec) ++ ec->clear(); ++ ++#if defined(BOOST_POSIX_API) ++ ++ int err = 0; ++ ++ // Note: Declare fd_wrappers here so that errno is not clobbered by close() that may be called in fd_wrapper destructors ++ fd_wrapper infile, outfile; ++ ++ while (true) ++ { ++ infile.fd = ::open(from.c_str(), O_RDONLY | O_CLOEXEC); ++ if (BOOST_UNLIKELY(infile.fd < 0)) ++ { ++ err = errno; ++ if (err == EINTR) ++ continue; ++ ++ fail: ++ emit_error(err, from, to, ec, "boost::filesystem::copy_file"); ++ return false; ++ } ++ ++ break; ++ } ++ ++#if defined(BOOST_FILESYSTEM_USE_STATX) ++ unsigned int statx_data_mask = STATX_TYPE | STATX_MODE | STATX_INO | STATX_SIZE; ++ if ((options & static_cast< unsigned int >(copy_options::update_existing)) != 0u) ++ statx_data_mask |= STATX_MTIME; ++ ++ struct ::statx from_stat; ++ if (BOOST_UNLIKELY(invoke_statx(infile.fd, "", AT_EMPTY_PATH | AT_NO_AUTOMOUNT, statx_data_mask, &from_stat) < 0)) ++ { ++ fail_errno: ++ err = errno; ++ goto fail; ++ } ++ ++ if (BOOST_UNLIKELY((from_stat.stx_mask & statx_data_mask) != statx_data_mask)) ++ { ++ err = ENOSYS; ++ goto fail; ++ } ++#else ++ struct ::stat from_stat; ++ if (BOOST_UNLIKELY(::fstat(infile.fd, &from_stat) != 0)) ++ { ++ fail_errno: ++ err = errno; ++ goto fail; ++ } ++#endif ++ ++ const mode_t from_mode = get_mode(from_stat); ++ if (BOOST_UNLIKELY(!S_ISREG(from_mode))) ++ { ++ err = ENOSYS; ++ goto fail; ++ } ++ ++ mode_t to_mode = from_mode; ++#if !defined(BOOST_FILESYSTEM_USE_WASI) ++ // Enable writing for the newly created files. Having write permission set is important e.g. for NFS, ++ // which checks the file permission on the server, even if the client's file descriptor supports writing. ++ to_mode |= S_IWUSR; ++#endif ++ int oflag = O_WRONLY | O_CLOEXEC; ++ ++ if ((options & static_cast< unsigned int >(copy_options::update_existing)) != 0u) ++ { ++ // Try opening the existing file without truncation to test the modification time later ++ while (true) ++ { ++ outfile.fd = ::open(to.c_str(), oflag, to_mode); ++ if (outfile.fd < 0) ++ { ++ err = errno; ++ if (err == EINTR) ++ continue; ++ ++ if (err == ENOENT) ++ goto create_outfile; ++ ++ goto fail; ++ } ++ ++ break; ++ } ++ } ++ else ++ { ++ create_outfile: ++ oflag |= O_CREAT | O_TRUNC; ++ if (((options & static_cast< unsigned int >(copy_options::overwrite_existing)) == 0u || ++ (options & static_cast< unsigned int >(copy_options::skip_existing)) != 0u) && ++ (options & static_cast< unsigned int >(copy_options::update_existing)) == 0u) ++ { ++ oflag |= O_EXCL; ++ } ++ ++ while (true) ++ { ++ outfile.fd = ::open(to.c_str(), oflag, to_mode); ++ if (outfile.fd < 0) ++ { ++ err = errno; ++ if (err == EINTR) ++ continue; ++ ++ if (err == EEXIST && (options & static_cast< unsigned int >(copy_options::skip_existing)) != 0u) ++ return false; ++ ++ goto fail; ++ } ++ ++ break; ++ } ++ } ++ ++#if defined(BOOST_FILESYSTEM_USE_STATX) ++ statx_data_mask = STATX_TYPE | STATX_MODE | STATX_INO; ++ if ((oflag & O_TRUNC) == 0) ++ { ++ // O_TRUNC is not set if copy_options::update_existing is set and an existing file was opened. ++ statx_data_mask |= STATX_MTIME; ++ } ++ ++ struct ::statx to_stat; ++ if (BOOST_UNLIKELY(invoke_statx(outfile.fd, "", AT_EMPTY_PATH | AT_NO_AUTOMOUNT, statx_data_mask, &to_stat) < 0)) ++ goto fail_errno; ++ ++ if (BOOST_UNLIKELY((to_stat.stx_mask & statx_data_mask) != statx_data_mask)) ++ { ++ err = ENOSYS; ++ goto fail; ++ } ++#else ++ struct ::stat to_stat; ++ if (BOOST_UNLIKELY(::fstat(outfile.fd, &to_stat) != 0)) ++ goto fail_errno; ++#endif ++ ++ to_mode = get_mode(to_stat); ++ if (BOOST_UNLIKELY(!S_ISREG(to_mode))) ++ { ++ err = ENOSYS; ++ goto fail; ++ } ++ ++ if (BOOST_UNLIKELY(detail::equivalent_stat(from_stat, to_stat))) ++ { ++ err = EEXIST; ++ goto fail; ++ } ++ ++ if ((oflag & O_TRUNC) == 0) ++ { ++ // O_TRUNC is not set if copy_options::update_existing is set and an existing file was opened. ++ // We need to check the last write times. ++#if defined(BOOST_FILESYSTEM_USE_STATX) ++ if (from_stat.stx_mtime.tv_sec < to_stat.stx_mtime.tv_sec || (from_stat.stx_mtime.tv_sec == to_stat.stx_mtime.tv_sec && from_stat.stx_mtime.tv_nsec <= to_stat.stx_mtime.tv_nsec)) ++ return false; ++#elif defined(BOOST_FILESYSTEM_STAT_ST_MTIMENSEC) ++ // Modify time is available with nanosecond precision. ++ if (from_stat.st_mtime < to_stat.st_mtime || (from_stat.st_mtime == to_stat.st_mtime && from_stat.BOOST_FILESYSTEM_STAT_ST_MTIMENSEC <= to_stat.BOOST_FILESYSTEM_STAT_ST_MTIMENSEC)) ++ return false; ++#else ++ if (from_stat.st_mtime <= to_stat.st_mtime) ++ return false; ++#endif ++ ++ if (BOOST_UNLIKELY(::ftruncate(outfile.fd, 0) != 0)) ++ goto fail_errno; ++ } ++ ++ // Note: Use block size of the target file since it is most important for writing performance. ++ err = filesystem::detail::atomic_load_relaxed(filesystem::detail::copy_file_data)(infile.fd, outfile.fd, get_size(from_stat), get_blksize(to_stat)); ++ if (BOOST_UNLIKELY(err != 0)) ++ goto fail; // err already contains the error code ++ ++#if !defined(BOOST_FILESYSTEM_USE_WASI) ++ // If we created a new file with an explicitly added S_IWUSR permission, ++ // we may need to update its mode bits to match the source file. ++ if (to_mode != from_mode) ++ { ++ if (BOOST_UNLIKELY(::fchmod(outfile.fd, from_mode) != 0)) ++ goto fail_errno; ++ } ++#endif ++ ++ if ((options & (static_cast< unsigned int >(copy_options::synchronize_data) | static_cast< unsigned int >(copy_options::synchronize))) != 0u) ++ { ++ if ((options & static_cast< unsigned int >(copy_options::synchronize)) != 0u) ++ err = full_sync(outfile.fd); ++ else ++ err = data_sync(outfile.fd); ++ ++ if (BOOST_UNLIKELY(err != 0)) ++ goto fail; ++ } ++ ++ // We have to explicitly close the output file descriptor in order to handle a possible error returned from it. The error may indicate ++ // a failure of a prior write operation. ++ err = close_fd(outfile.fd); ++ outfile.fd = -1; ++ if (BOOST_UNLIKELY(err < 0)) ++ { ++ err = errno; ++ // EINPROGRESS is an allowed error code in future POSIX revisions, according to https://www.austingroupbugs.net/view.php?id=529#c1200. ++ if (err != EINTR && err != EINPROGRESS) ++ goto fail; ++ } ++ ++ return true; ++ ++#else // defined(BOOST_POSIX_API) ++ ++ DWORD copy_flags = 0u; ++ if ((options & static_cast< unsigned int >(copy_options::overwrite_existing)) == 0u || ++ (options & static_cast< unsigned int >(copy_options::skip_existing)) != 0u) ++ { ++ copy_flags |= COPY_FILE_FAIL_IF_EXISTS; ++ } ++ ++ if ((options & static_cast< unsigned int >(copy_options::update_existing)) != 0u) ++ { ++ // Create handle_wrappers here so that CloseHandle calls don't clobber error code returned by GetLastError ++ handle_wrapper hw_from, hw_to; ++ ++ hw_from.handle = create_file_handle(from.c_str(), GENERIC_READ, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS); ++ ++ FILETIME lwt_from; ++ if (hw_from.handle == INVALID_HANDLE_VALUE) ++ { ++ fail_last_error: ++ DWORD err = ::GetLastError(); ++ emit_error(err, from, to, ec, "boost::filesystem::copy_file"); ++ return false; ++ } ++ ++ if (!::GetFileTime(hw_from.handle, NULL, NULL, &lwt_from)) ++ goto fail_last_error; ++ ++ hw_to.handle = create_file_handle(to.c_str(), GENERIC_READ, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS); ++ ++ if (hw_to.handle != INVALID_HANDLE_VALUE) ++ { ++ FILETIME lwt_to; ++ if (!::GetFileTime(hw_to.handle, NULL, NULL, &lwt_to)) ++ goto fail_last_error; ++ ++ ULONGLONG tfrom = (static_cast< ULONGLONG >(lwt_from.dwHighDateTime) << 32) | static_cast< ULONGLONG >(lwt_from.dwLowDateTime); ++ ULONGLONG tto = (static_cast< ULONGLONG >(lwt_to.dwHighDateTime) << 32) | static_cast< ULONGLONG >(lwt_to.dwLowDateTime); ++ if (tfrom <= tto) ++ return false; ++ } ++ ++ copy_flags &= ~static_cast< DWORD >(COPY_FILE_FAIL_IF_EXISTS); ++ } ++ ++ struct callback_context ++ { ++ DWORD flush_error; ++ }; ++ ++ struct local ++ { ++ //! Callback that is called to report progress of \c CopyFileExW ++ static DWORD WINAPI on_copy_file_progress( ++ LARGE_INTEGER total_file_size, ++ LARGE_INTEGER total_bytes_transferred, ++ LARGE_INTEGER stream_size, ++ LARGE_INTEGER stream_bytes_transferred, ++ DWORD stream_number, ++ DWORD callback_reason, ++ HANDLE from_handle, ++ HANDLE to_handle, ++ LPVOID ctx) ++ { ++ // For each stream, CopyFileExW will open a separate pair of file handles, so we need to flush each stream separately. ++ if (stream_bytes_transferred.QuadPart == stream_size.QuadPart) ++ { ++ BOOL res = ::FlushFileBuffers(to_handle); ++ if (BOOST_UNLIKELY(!res)) ++ { ++ callback_context* context = static_cast< callback_context* >(ctx); ++ if (BOOST_LIKELY(context->flush_error == 0u)) ++ context->flush_error = ::GetLastError(); ++ } ++ } ++ ++ return PROGRESS_CONTINUE; ++ } ++ }; ++ ++ callback_context cb_context = {}; ++ LPPROGRESS_ROUTINE cb = NULL; ++ LPVOID cb_ctx = NULL; ++ ++ if ((options & (static_cast< unsigned int >(copy_options::synchronize_data) | static_cast< unsigned int >(copy_options::synchronize))) != 0u) ++ { ++ cb = &local::on_copy_file_progress; ++ cb_ctx = &cb_context; ++ } ++ ++ BOOL cancelled = FALSE; ++ BOOL res = ::CopyFileExW(from.c_str(), to.c_str(), cb, cb_ctx, &cancelled, copy_flags); ++ DWORD err; ++ if (BOOST_UNLIKELY(!res)) ++ { ++ err = ::GetLastError(); ++ if ((err == ERROR_FILE_EXISTS || err == ERROR_ALREADY_EXISTS) && (options & static_cast< unsigned int >(copy_options::skip_existing)) != 0u) ++ return false; ++ ++ copy_failed: ++ emit_error(err, from, to, ec, "boost::filesystem::copy_file"); ++ return false; ++ } ++ ++ if (BOOST_UNLIKELY(cb_context.flush_error != 0u)) ++ { ++ err = cb_context.flush_error; ++ goto copy_failed; ++ } ++ ++ return true; ++ ++#endif // defined(BOOST_POSIX_API) ++} ++ ++BOOST_FILESYSTEM_DECL ++void copy_symlink(path const& existing_symlink, path const& new_symlink, system::error_code* ec) ++{ ++ path p(read_symlink(existing_symlink, ec)); ++ if (ec && *ec) ++ return; ++ create_symlink(p, new_symlink, ec); ++} ++ ++BOOST_FILESYSTEM_DECL ++bool create_directories(path const& p, system::error_code* ec) ++{ ++ if (p.empty()) ++ { ++ if (!ec) ++ { ++ BOOST_FILESYSTEM_THROW(filesystem_error( ++ "boost::filesystem::create_directories", p, ++ system::errc::make_error_code(system::errc::invalid_argument))); ++ } ++ ec->assign(system::errc::invalid_argument, system::generic_category()); ++ return false; ++ } ++ ++ if (ec) ++ ec->clear(); ++ ++ path::const_iterator e(p.end()), it(e); ++ path parent(p); ++ path const& dot_p = dot_path(); ++ path const& dot_dot_p = dot_dot_path(); ++ error_code local_ec; ++ ++ // Find the initial part of the path that exists ++ for (path fname = path_algorithms::filename_v4(parent); parent.has_relative_path(); fname = path_algorithms::filename_v4(parent)) ++ { ++ if (!fname.empty() && path_algorithms::compare_v4(fname, dot_p) != 0 && path_algorithms::compare_v4(fname, dot_dot_p) != 0) ++ { ++ file_status existing_status = detail::status_impl(parent, &local_ec); ++ ++ if (existing_status.type() == directory_file) ++ { ++ break; ++ } ++ else if (BOOST_UNLIKELY(existing_status.type() == status_error)) ++ { ++ if (!ec) ++ BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::create_directories", p, parent, local_ec)); ++ *ec = local_ec; ++ return false; ++ } ++ } ++ ++ path_algorithms::decrement_v4(it); ++ parent.remove_filename_and_trailing_separators(); ++ } ++ ++ // Create missing directories ++ bool created = false; ++ for (; it != e; path_algorithms::increment_v4(it)) ++ { ++ path const& fname = *it; ++ path_algorithms::append_v4(parent, fname); ++ if (!fname.empty() && path_algorithms::compare_v4(fname, dot_p) != 0 && path_algorithms::compare_v4(fname, dot_dot_p) != 0) ++ { ++ created = detail::create_directory(parent, NULL, &local_ec); ++ if (BOOST_UNLIKELY(!!local_ec)) ++ { ++ if (!ec) ++ BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::create_directories", p, parent, local_ec)); ++ *ec = local_ec; ++ return false; ++ } ++ } ++ } ++ ++ return created; ++} ++ ++BOOST_FILESYSTEM_DECL ++bool create_directory(path const& p, const path* existing, error_code* ec) ++{ ++ if (ec) ++ ec->clear(); ++ ++#if defined(BOOST_POSIX_API) ++ ++ mode_t mode = S_IRWXU | S_IRWXG | S_IRWXO; ++ if (existing) ++ { ++#if defined(BOOST_FILESYSTEM_USE_STATX) ++ struct ::statx existing_stat; ++ if (BOOST_UNLIKELY(invoke_statx(AT_FDCWD, existing->c_str(), AT_NO_AUTOMOUNT, STATX_TYPE | STATX_MODE, &existing_stat) < 0)) ++ { ++ emit_error(errno, p, *existing, ec, "boost::filesystem::create_directory"); ++ return false; ++ } ++ ++ if (BOOST_UNLIKELY((existing_stat.stx_mask & (STATX_TYPE | STATX_MODE)) != (STATX_TYPE | STATX_MODE))) ++ { ++ emit_error(BOOST_ERROR_NOT_SUPPORTED, p, *existing, ec, "boost::filesystem::create_directory"); ++ return false; ++ } ++#else ++ struct ::stat existing_stat; ++ if (::stat(existing->c_str(), &existing_stat) < 0) ++ { ++ emit_error(errno, p, *existing, ec, "boost::filesystem::create_directory"); ++ return false; ++ } ++#endif ++ ++ const mode_t existing_mode = get_mode(existing_stat); ++ if (!S_ISDIR(existing_mode)) ++ { ++ emit_error(ENOTDIR, p, *existing, ec, "boost::filesystem::create_directory"); ++ return false; ++ } ++ ++ mode = existing_mode; ++ } ++ ++ if (::mkdir(p.c_str(), mode) == 0) ++ return true; ++ ++#else // defined(BOOST_POSIX_API) ++ ++ BOOL res; ++ if (existing) ++ res = ::CreateDirectoryExW(existing->c_str(), p.c_str(), NULL); ++ else ++ res = ::CreateDirectoryW(p.c_str(), NULL); ++ ++ if (res) ++ return true; ++ ++#endif // defined(BOOST_POSIX_API) ++ ++ // attempt to create directory failed ++ err_t errval = BOOST_ERRNO; // save reason for failure ++ error_code dummy; ++ ++ if (is_directory(p, dummy)) ++ return false; ++ ++ // attempt to create directory failed && it doesn't already exist ++ emit_error(errval, p, ec, "boost::filesystem::create_directory"); ++ return false; ++} ++ ++// Deprecated, to be removed in a future release ++BOOST_FILESYSTEM_DECL ++void copy_directory(path const& from, path const& to, system::error_code* ec) ++{ ++ if (ec) ++ ec->clear(); ++ ++#if defined(BOOST_POSIX_API) ++ ++#if defined(BOOST_FILESYSTEM_USE_STATX) ++ int err; ++ struct ::statx from_stat; ++ if (BOOST_UNLIKELY(invoke_statx(AT_FDCWD, from.c_str(), AT_NO_AUTOMOUNT, STATX_TYPE | STATX_MODE, &from_stat) < 0)) ++ { ++ fail_errno: ++ err = errno; ++ fail: ++ emit_error(err, from, to, ec, "boost::filesystem::copy_directory"); ++ return; ++ } ++ ++ if (BOOST_UNLIKELY((from_stat.stx_mask & (STATX_TYPE | STATX_MODE)) != (STATX_TYPE | STATX_MODE))) ++ { ++ err = BOOST_ERROR_NOT_SUPPORTED; ++ goto fail; ++ } ++#else ++ struct ::stat from_stat; ++ if (BOOST_UNLIKELY(::stat(from.c_str(), &from_stat) < 0)) ++ { ++ fail_errno: ++ emit_error(errno, from, to, ec, "boost::filesystem::copy_directory"); ++ return; ++ } ++#endif ++ ++ if (BOOST_UNLIKELY(::mkdir(to.c_str(), get_mode(from_stat)) < 0)) ++ goto fail_errno; ++ ++#else // defined(BOOST_POSIX_API) ++ ++ if (BOOST_UNLIKELY(!::CreateDirectoryExW(from.c_str(), to.c_str(), 0))) ++ emit_error(BOOST_ERRNO, from, to, ec, "boost::filesystem::copy_directory"); ++ ++#endif // defined(BOOST_POSIX_API) ++} ++ ++BOOST_FILESYSTEM_DECL ++void create_directory_symlink(path const& to, path const& from, system::error_code* ec) ++{ ++ if (ec) ++ ec->clear(); ++ ++#if defined(BOOST_POSIX_API) ++ int err = ::symlink(to.c_str(), from.c_str()); ++ if (BOOST_UNLIKELY(err < 0)) ++ { ++ err = errno; ++ emit_error(err, to, from, ec, "boost::filesystem::create_directory_symlink"); ++ } ++#else ++ // see if actually supported by Windows runtime dll ++ if (!create_symbolic_link_api) ++ { ++ emit_error(BOOST_ERROR_NOT_SUPPORTED, to, from, ec, "boost::filesystem::create_directory_symlink"); ++ return; ++ } ++ ++ if (!create_symbolic_link_api(from.c_str(), to.c_str(), SYMBOLIC_LINK_FLAG_DIRECTORY | SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE)) ++ { ++ emit_error(BOOST_ERRNO, to, from, ec, "boost::filesystem::create_directory_symlink"); ++ } ++#endif ++} ++ ++BOOST_FILESYSTEM_DECL ++void create_hard_link(path const& to, path const& from, error_code* ec) ++{ ++ if (ec) ++ ec->clear(); ++ ++#if defined(BOOST_POSIX_API) ++ int err = ::link(to.c_str(), from.c_str()); ++ if (BOOST_UNLIKELY(err < 0)) ++ { ++ err = errno; ++ emit_error(err, to, from, ec, "boost::filesystem::create_hard_link"); ++ } ++#else ++ // see if actually supported by Windows runtime dll ++ CreateHardLinkW_t* chl_api = filesystem::detail::atomic_load_relaxed(create_hard_link_api); ++ if (BOOST_UNLIKELY(!chl_api)) ++ { ++ emit_error(BOOST_ERROR_NOT_SUPPORTED, to, from, ec, "boost::filesystem::create_hard_link"); ++ return; ++ } ++ ++ if (BOOST_UNLIKELY(!chl_api(from.c_str(), to.c_str(), NULL))) ++ { ++ emit_error(BOOST_ERRNO, to, from, ec, "boost::filesystem::create_hard_link"); ++ } ++#endif ++} ++ ++BOOST_FILESYSTEM_DECL ++void create_symlink(path const& to, path const& from, error_code* ec) ++{ ++ if (ec) ++ ec->clear(); ++ ++#if defined(BOOST_POSIX_API) ++ int err = ::symlink(to.c_str(), from.c_str()); ++ if (BOOST_UNLIKELY(err < 0)) ++ { ++ err = errno; ++ emit_error(err, to, from, ec, "boost::filesystem::create_symlink"); ++ } ++#else ++ // see if actually supported by Windows runtime dll ++ CreateSymbolicLinkW_t* csl_api = filesystem::detail::atomic_load_relaxed(create_symbolic_link_api); ++ if (BOOST_UNLIKELY(!csl_api)) ++ { ++ emit_error(BOOST_ERROR_NOT_SUPPORTED, to, from, ec, "boost::filesystem::create_symlink"); ++ return; ++ } ++ ++ if (BOOST_UNLIKELY(!csl_api(from.c_str(), to.c_str(), SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE))) ++ { ++ emit_error(BOOST_ERRNO, to, from, ec, "boost::filesystem::create_symlink"); ++ } ++#endif ++} ++ ++BOOST_FILESYSTEM_DECL ++path current_path(error_code* ec) ++{ ++#if defined(UNDER_CE) || defined(BOOST_FILESYSTEM_USE_WASI) ++ // Windows CE has no current directory, so everything's relative to the root of the directory tree. ++ // WASI also does not support current path. ++ emit_error(BOOST_ERROR_NOT_SUPPORTED, ec, "boost::filesystem::current_path"); ++ return path(); ++#elif defined(BOOST_POSIX_API) ++ struct local ++ { ++ static bool getcwd_error(error_code* ec) ++ { ++ const int err = errno; ++ return error((err != ERANGE ++#if defined(__MSL__) && (defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__)) ++ // bug in some versions of the Metrowerks C lib on the Mac: wrong errno set ++ && err != 0 ++#endif ++ ) ? err : 0, ++ ec, "boost::filesystem::current_path"); ++ } ++ }; ++ ++ path cur; ++ char small_buf[small_path_size]; ++ const char* p = ::getcwd(small_buf, sizeof(small_buf)); ++ if (BOOST_LIKELY(!!p)) ++ { ++ cur = p; ++ if (ec) ++ ec->clear(); ++ } ++ else if (BOOST_LIKELY(!local::getcwd_error(ec))) ++ { ++ for (std::size_t path_max = sizeof(small_buf) * 2u;; path_max *= 2u) // loop 'til buffer large enough ++ { ++ if (BOOST_UNLIKELY(path_max > absolute_path_max)) ++ { ++ emit_error(ENAMETOOLONG, ec, "boost::filesystem::current_path"); ++ break; ++ } ++ ++ boost::scoped_array< char > buf(new char[path_max]); ++ p = ::getcwd(buf.get(), path_max); ++ if (BOOST_LIKELY(!!p)) ++ { ++ cur = buf.get(); ++ if (ec) ++ ec->clear(); ++ break; ++ } ++ else if (BOOST_UNLIKELY(local::getcwd_error(ec))) ++ { ++ break; ++ } ++ } ++ } ++ ++ return cur; ++#else ++ DWORD sz; ++ if ((sz = ::GetCurrentDirectoryW(0, NULL)) == 0) ++ sz = 1; ++ boost::scoped_array< path::value_type > buf(new path::value_type[sz]); ++ error(::GetCurrentDirectoryW(sz, buf.get()) == 0 ? BOOST_ERRNO : 0, ec, "boost::filesystem::current_path"); ++ return path(buf.get()); ++#endif ++} ++ ++BOOST_FILESYSTEM_DECL ++void current_path(path const& p, system::error_code* ec) ++{ ++#if defined(UNDER_CE) || defined(BOOST_FILESYSTEM_USE_WASI) ++ emit_error(BOOST_ERROR_NOT_SUPPORTED, p, ec, "boost::filesystem::current_path"); ++#else ++ error(!BOOST_SET_CURRENT_DIRECTORY(p.c_str()) ? BOOST_ERRNO : 0, p, ec, "boost::filesystem::current_path"); ++#endif ++} ++ ++BOOST_FILESYSTEM_DECL ++bool equivalent(path const& p1, path const& p2, system::error_code* ec) ++{ ++#if defined(BOOST_POSIX_API) ++ ++ // p2 is done first, so any error reported is for p1 ++#if defined(BOOST_FILESYSTEM_USE_STATX) ++ struct ::statx s2; ++ int e2 = invoke_statx(AT_FDCWD, p2.c_str(), AT_NO_AUTOMOUNT, STATX_INO, &s2); ++ if (BOOST_LIKELY(e2 == 0)) ++ { ++ if (BOOST_UNLIKELY((s2.stx_mask & STATX_INO) != STATX_INO)) ++ { ++ fail_unsupported: ++ emit_error(BOOST_ERROR_NOT_SUPPORTED, p1, p2, ec, "boost::filesystem::equivalent"); ++ return false; ++ } ++ } ++ ++ struct ::statx s1; ++ int e1 = invoke_statx(AT_FDCWD, p1.c_str(), AT_NO_AUTOMOUNT, STATX_INO, &s1); ++ if (BOOST_LIKELY(e1 == 0)) ++ { ++ if (BOOST_UNLIKELY((s1.stx_mask & STATX_INO) != STATX_INO)) ++ goto fail_unsupported; ++ } ++#else ++ struct ::stat s2; ++ int e2 = ::stat(p2.c_str(), &s2); ++ struct ::stat s1; ++ int e1 = ::stat(p1.c_str(), &s1); ++#endif ++ ++ if (BOOST_UNLIKELY(e1 != 0 || e2 != 0)) ++ { ++ // if one is invalid and the other isn't then they aren't equivalent, ++ // but if both are invalid then it is an error ++ if (e1 != 0 && e2 != 0) ++ emit_error(errno, p1, p2, ec, "boost::filesystem::equivalent"); ++ return false; ++ } ++ ++ return equivalent_stat(s1, s2); ++ ++#else // Windows ++ ++ // Thanks to Jeremy Maitin-Shepard for much help and for permission to ++ // base the equivalent() implementation on portions of his ++ // file-equivalence-win32.cpp experimental code. ++ ++ // Note well: Physical location on external media is part of the ++ // equivalence criteria. If there are no open handles, physical location ++ // can change due to defragmentation or other relocations. Thus handles ++ // must be held open until location information for both paths has ++ // been retrieved. ++ ++ // p2 is done first, so any error reported is for p1 ++ handle_wrapper h2(create_file_handle( ++ p2.c_str(), ++ FILE_READ_ATTRIBUTES, ++ FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, ++ NULL, ++ OPEN_EXISTING, ++ FILE_FLAG_BACKUP_SEMANTICS)); ++ ++ handle_wrapper h1(create_file_handle( ++ p1.c_str(), ++ FILE_READ_ATTRIBUTES, ++ FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, ++ NULL, ++ OPEN_EXISTING, ++ FILE_FLAG_BACKUP_SEMANTICS)); ++ ++ if (BOOST_UNLIKELY(h1.handle == INVALID_HANDLE_VALUE || h2.handle == INVALID_HANDLE_VALUE)) ++ { ++ // if one is invalid and the other isn't, then they aren't equivalent, ++ // but if both are invalid then it is an error ++ if (h1.handle == INVALID_HANDLE_VALUE && h2.handle == INVALID_HANDLE_VALUE) ++ error(BOOST_ERRNO, p1, p2, ec, "boost::filesystem::equivalent"); ++ return false; ++ } ++ ++ // at this point, both handles are known to be valid ++ ++ BY_HANDLE_FILE_INFORMATION info1, info2; ++ ++ if (error(!::GetFileInformationByHandle(h1.handle, &info1) ? BOOST_ERRNO : 0, p1, p2, ec, "boost::filesystem::equivalent")) ++ return false; ++ ++ if (error(!::GetFileInformationByHandle(h2.handle, &info2) ? BOOST_ERRNO : 0, p1, p2, ec, "boost::filesystem::equivalent")) ++ return false; ++ ++ // In theory, volume serial numbers are sufficient to distinguish between ++ // devices, but in practice VSN's are sometimes duplicated, so last write ++ // time and file size are also checked. ++ return info1.dwVolumeSerialNumber == info2.dwVolumeSerialNumber && ++ info1.nFileIndexHigh == info2.nFileIndexHigh && ++ info1.nFileIndexLow == info2.nFileIndexLow && ++ info1.nFileSizeHigh == info2.nFileSizeHigh && ++ info1.nFileSizeLow == info2.nFileSizeLow && ++ info1.ftLastWriteTime.dwLowDateTime == info2.ftLastWriteTime.dwLowDateTime && ++ info1.ftLastWriteTime.dwHighDateTime == info2.ftLastWriteTime.dwHighDateTime; ++ ++#endif ++} ++ ++BOOST_FILESYSTEM_DECL ++uintmax_t file_size(path const& p, error_code* ec) ++{ ++ if (ec) ++ ec->clear(); ++ ++#if defined(BOOST_POSIX_API) ++ ++#if defined(BOOST_FILESYSTEM_USE_STATX) ++ struct ::statx path_stat; ++ if (BOOST_UNLIKELY(invoke_statx(AT_FDCWD, p.c_str(), AT_NO_AUTOMOUNT, STATX_TYPE | STATX_SIZE, &path_stat) < 0)) ++ { ++ emit_error(errno, p, ec, "boost::filesystem::file_size"); ++ return static_cast< uintmax_t >(-1); ++ } ++ ++ if (BOOST_UNLIKELY((path_stat.stx_mask & (STATX_TYPE | STATX_SIZE)) != (STATX_TYPE | STATX_SIZE) || !S_ISREG(path_stat.stx_mode))) ++ { ++ emit_error(BOOST_ERROR_NOT_SUPPORTED, p, ec, "boost::filesystem::file_size"); ++ return static_cast< uintmax_t >(-1); ++ } ++#else ++ struct ::stat path_stat; ++ if (BOOST_UNLIKELY(::stat(p.c_str(), &path_stat) < 0)) ++ { ++ emit_error(errno, p, ec, "boost::filesystem::file_size"); ++ return static_cast< uintmax_t >(-1); ++ } ++ ++ if (BOOST_UNLIKELY(!S_ISREG(path_stat.st_mode))) ++ { ++ emit_error(BOOST_ERROR_NOT_SUPPORTED, p, ec, "boost::filesystem::file_size"); ++ return static_cast< uintmax_t >(-1); ++ } ++#endif ++ ++ return get_size(path_stat); ++ ++#else // defined(BOOST_POSIX_API) ++ ++ // assume uintmax_t is 64-bits on all Windows compilers ++ ++ WIN32_FILE_ATTRIBUTE_DATA fad; ++ ++ if (BOOST_UNLIKELY(!::GetFileAttributesExW(p.c_str(), ::GetFileExInfoStandard, &fad))) ++ { ++ emit_error(BOOST_ERRNO, p, ec, "boost::filesystem::file_size"); ++ return static_cast< uintmax_t >(-1); ++ } ++ ++ if (BOOST_UNLIKELY((fad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0)) ++ { ++ emit_error(ERROR_NOT_SUPPORTED, p, ec, "boost::filesystem::file_size"); ++ return static_cast< uintmax_t >(-1); ++ } ++ ++ return (static_cast< uintmax_t >(fad.nFileSizeHigh) ++ << (sizeof(fad.nFileSizeLow) * 8u)) | ++ fad.nFileSizeLow; ++ ++#endif // defined(BOOST_POSIX_API) ++} ++ ++BOOST_FILESYSTEM_DECL ++uintmax_t hard_link_count(path const& p, system::error_code* ec) ++{ ++ if (ec) ++ ec->clear(); ++ ++#if defined(BOOST_POSIX_API) ++ ++#if defined(BOOST_FILESYSTEM_USE_STATX) ++ struct ::statx path_stat; ++ if (BOOST_UNLIKELY(invoke_statx(AT_FDCWD, p.c_str(), AT_NO_AUTOMOUNT, STATX_NLINK, &path_stat) < 0)) ++ { ++ emit_error(errno, p, ec, "boost::filesystem::hard_link_count"); ++ return static_cast< uintmax_t >(-1); ++ } ++ ++ if (BOOST_UNLIKELY((path_stat.stx_mask & STATX_NLINK) != STATX_NLINK)) ++ { ++ emit_error(BOOST_ERROR_NOT_SUPPORTED, p, ec, "boost::filesystem::hard_link_count"); ++ return static_cast< uintmax_t >(-1); ++ } ++ ++ return static_cast< uintmax_t >(path_stat.stx_nlink); ++#else ++ struct ::stat path_stat; ++ if (BOOST_UNLIKELY(::stat(p.c_str(), &path_stat) < 0)) ++ { ++ emit_error(errno, p, ec, "boost::filesystem::hard_link_count"); ++ return static_cast< uintmax_t >(-1); ++ } ++ ++ return static_cast< uintmax_t >(path_stat.st_nlink); ++#endif ++ ++#else // defined(BOOST_POSIX_API) ++ ++ handle_wrapper h(create_file_handle( ++ p.c_str(), ++ FILE_READ_ATTRIBUTES, ++ FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, ++ NULL, ++ OPEN_EXISTING, ++ FILE_FLAG_BACKUP_SEMANTICS)); ++ ++ if (BOOST_UNLIKELY(h.handle == INVALID_HANDLE_VALUE)) ++ { ++ fail_errno: ++ emit_error(BOOST_ERRNO, p, ec, "boost::filesystem::hard_link_count"); ++ return static_cast< uintmax_t >(-1); ++ } ++ ++ // Link count info is only available through GetFileInformationByHandle ++ BY_HANDLE_FILE_INFORMATION info; ++ if (BOOST_UNLIKELY(!::GetFileInformationByHandle(h.handle, &info))) ++ goto fail_errno; ++ ++ return static_cast< uintmax_t >(info.nNumberOfLinks); ++ ++#endif // defined(BOOST_POSIX_API) ++} ++ ++BOOST_FILESYSTEM_DECL ++path initial_path(error_code* ec) ++{ ++ static path init_path; ++ if (init_path.empty()) ++ init_path = current_path(ec); ++ else if (ec) ++ ec->clear(); ++ return init_path; ++} ++ ++BOOST_FILESYSTEM_DECL ++bool is_empty(path const& p, system::error_code* ec) ++{ ++ if (ec) ++ ec->clear(); ++ ++#if defined(BOOST_POSIX_API) ++ ++#if defined(BOOST_FILESYSTEM_USE_STATX) ++ struct ::statx path_stat; ++ if (BOOST_UNLIKELY(invoke_statx(AT_FDCWD, p.c_str(), AT_NO_AUTOMOUNT, STATX_TYPE | STATX_SIZE, &path_stat) < 0)) ++ { ++ emit_error(errno, p, ec, "boost::filesystem::is_empty"); ++ return false; ++ } ++ ++ if (BOOST_UNLIKELY((path_stat.stx_mask & STATX_TYPE) != STATX_TYPE)) ++ { ++ fail_unsupported: ++ emit_error(BOOST_ERROR_NOT_SUPPORTED, p, ec, "boost::filesystem::is_empty"); ++ return false; ++ } ++ ++ if (S_ISDIR(get_mode(path_stat))) ++ return is_empty_directory(p, ec); ++ ++ if (BOOST_UNLIKELY((path_stat.stx_mask & STATX_SIZE) != STATX_SIZE)) ++ goto fail_unsupported; ++ ++ return get_size(path_stat) == 0u; ++#else ++ struct ::stat path_stat; ++ if (BOOST_UNLIKELY(::stat(p.c_str(), &path_stat) < 0)) ++ { ++ emit_error(errno, p, ec, "boost::filesystem::is_empty"); ++ return false; ++ } ++ ++ return S_ISDIR(get_mode(path_stat)) ? is_empty_directory(p, ec) : get_size(path_stat) == 0u; ++#endif ++ ++#else // defined(BOOST_POSIX_API) ++ ++ WIN32_FILE_ATTRIBUTE_DATA fad; ++ if (BOOST_UNLIKELY(!::GetFileAttributesExW(p.c_str(), ::GetFileExInfoStandard, &fad))) ++ { ++ emit_error(BOOST_ERRNO, p, ec, "boost::filesystem::is_empty"); ++ return false; ++ } ++ ++ return (fad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? is_empty_directory(p, ec) : (!fad.nFileSizeHigh && !fad.nFileSizeLow); ++ ++#endif // defined(BOOST_POSIX_API) ++} ++ ++BOOST_FILESYSTEM_DECL ++std::time_t creation_time(path const& p, system::error_code* ec) ++{ ++ if (ec) ++ ec->clear(); ++ ++#if defined(BOOST_POSIX_API) ++ ++#if defined(BOOST_FILESYSTEM_USE_STATX) ++ struct ::statx stx; ++ if (BOOST_UNLIKELY(invoke_statx(AT_FDCWD, p.c_str(), AT_NO_AUTOMOUNT, STATX_BTIME, &stx) < 0)) ++ { ++ emit_error(BOOST_ERRNO, p, ec, "boost::filesystem::creation_time"); ++ return (std::numeric_limits< std::time_t >::min)(); ++ } ++ if (BOOST_UNLIKELY((stx.stx_mask & STATX_BTIME) != STATX_BTIME)) ++ { ++ emit_error(BOOST_ERROR_NOT_SUPPORTED, p, ec, "boost::filesystem::creation_time"); ++ return (std::numeric_limits< std::time_t >::min)(); ++ } ++ return stx.stx_btime.tv_sec; ++#elif defined(BOOST_FILESYSTEM_STAT_ST_BIRTHTIME) && defined(BOOST_FILESYSTEM_STAT_ST_BIRTHTIMENSEC) ++ struct ::stat st; ++ if (BOOST_UNLIKELY(::stat(p.c_str(), &st) < 0)) ++ { ++ emit_error(BOOST_ERRNO, p, ec, "boost::filesystem::creation_time"); ++ return (std::numeric_limits< std::time_t >::min)(); ++ } ++ return st.BOOST_FILESYSTEM_STAT_ST_BIRTHTIME; ++#else ++ emit_error(BOOST_ERROR_NOT_SUPPORTED, p, ec, "boost::filesystem::creation_time"); ++ return (std::numeric_limits< std::time_t >::min)(); ++#endif ++ ++#else // defined(BOOST_POSIX_API) ++ ++ handle_wrapper hw(create_file_handle( ++ p.c_str(), ++ GENERIC_READ, ++ FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, ++ NULL, ++ OPEN_EXISTING, ++ FILE_FLAG_BACKUP_SEMANTICS)); ++ ++ if (BOOST_UNLIKELY(hw.handle == INVALID_HANDLE_VALUE)) ++ { ++ fail: ++ emit_error(BOOST_ERRNO, p, ec, "boost::filesystem::creation_time"); ++ return (std::numeric_limits< std::time_t >::min)(); ++ } ++ ++ FILETIME ct; ++ if (BOOST_UNLIKELY(!::GetFileTime(hw.handle, &ct, NULL, NULL))) ++ goto fail; ++ ++ return to_time_t(ct); ++ ++#endif // defined(BOOST_POSIX_API) ++} ++ ++BOOST_FILESYSTEM_DECL ++std::time_t last_write_time(path const& p, system::error_code* ec) ++{ ++ if (ec) ++ ec->clear(); ++ ++#if defined(BOOST_POSIX_API) ++ ++#if defined(BOOST_FILESYSTEM_USE_STATX) ++ struct ::statx stx; ++ if (BOOST_UNLIKELY(invoke_statx(AT_FDCWD, p.c_str(), AT_NO_AUTOMOUNT, STATX_MTIME, &stx) < 0)) ++ { ++ emit_error(BOOST_ERRNO, p, ec, "boost::filesystem::last_write_time"); ++ return (std::numeric_limits< std::time_t >::min)(); ++ } ++ if (BOOST_UNLIKELY((stx.stx_mask & STATX_MTIME) != STATX_MTIME)) ++ { ++ emit_error(BOOST_ERROR_NOT_SUPPORTED, p, ec, "boost::filesystem::last_write_time"); ++ return (std::numeric_limits< std::time_t >::min)(); ++ } ++ return stx.stx_mtime.tv_sec; ++#else ++ struct ::stat st; ++ if (BOOST_UNLIKELY(::stat(p.c_str(), &st) < 0)) ++ { ++ emit_error(BOOST_ERRNO, p, ec, "boost::filesystem::last_write_time"); ++ return (std::numeric_limits< std::time_t >::min)(); ++ } ++ return st.st_mtime; ++#endif ++ ++#else // defined(BOOST_POSIX_API) ++ ++ handle_wrapper hw(create_file_handle( ++ p.c_str(), ++ GENERIC_READ, ++ FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, ++ NULL, ++ OPEN_EXISTING, ++ FILE_FLAG_BACKUP_SEMANTICS)); ++ ++ if (BOOST_UNLIKELY(hw.handle == INVALID_HANDLE_VALUE)) ++ { ++ fail: ++ emit_error(BOOST_ERRNO, p, ec, "boost::filesystem::last_write_time"); ++ return (std::numeric_limits< std::time_t >::min)(); ++ } ++ ++ FILETIME lwt; ++ if (BOOST_UNLIKELY(!::GetFileTime(hw.handle, NULL, NULL, &lwt))) ++ goto fail; ++ ++ return to_time_t(lwt); ++ ++#endif // defined(BOOST_POSIX_API) ++} ++ ++BOOST_FILESYSTEM_DECL ++void last_write_time(path const& p, const std::time_t new_time, system::error_code* ec) ++{ ++ if (ec) ++ ec->clear(); ++ ++#if defined(BOOST_POSIX_API) ++ ++#if defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) ++ ++ struct timespec times[2] = {}; ++ ++ // Keep the last access time unchanged ++ times[0].tv_nsec = UTIME_OMIT; ++ ++ times[1].tv_sec = new_time; ++ ++ if (BOOST_UNLIKELY(::utimensat(AT_FDCWD, p.c_str(), times, 0) != 0)) ++ { ++ emit_error(BOOST_ERRNO, p, ec, "boost::filesystem::last_write_time"); ++ return; ++ } ++ ++#else // defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) ++ ++ struct ::stat st; ++ if (BOOST_UNLIKELY(::stat(p.c_str(), &st) < 0)) ++ { ++ emit_error(BOOST_ERRNO, p, ec, "boost::filesystem::last_write_time"); ++ return; ++ } ++ ++ ::utimbuf buf; ++ buf.actime = st.st_atime; // utime() updates access time too :-( ++ buf.modtime = new_time; ++ if (BOOST_UNLIKELY(::utime(p.c_str(), &buf) < 0)) ++ emit_error(BOOST_ERRNO, p, ec, "boost::filesystem::last_write_time"); ++ ++#endif // defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) ++ ++#else // defined(BOOST_POSIX_API) ++ ++ handle_wrapper hw(create_file_handle( ++ p.c_str(), ++ FILE_WRITE_ATTRIBUTES, ++ FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, ++ NULL, ++ OPEN_EXISTING, ++ FILE_FLAG_BACKUP_SEMANTICS)); ++ ++ if (BOOST_UNLIKELY(hw.handle == INVALID_HANDLE_VALUE)) ++ { ++ fail: ++ emit_error(BOOST_ERRNO, p, ec, "boost::filesystem::last_write_time"); ++ return; ++ } ++ ++ FILETIME lwt; ++ to_FILETIME(new_time, lwt); ++ ++ if (BOOST_UNLIKELY(!::SetFileTime(hw.handle, NULL, NULL, &lwt))) ++ goto fail; ++ ++#endif // defined(BOOST_POSIX_API) ++} ++ ++#ifdef BOOST_POSIX_API ++const perms active_bits(all_all | set_uid_on_exe | set_gid_on_exe | sticky_bit); ++inline mode_t mode_cast(perms prms) ++{ ++ return prms & active_bits; ++} ++#endif ++ ++BOOST_FILESYSTEM_DECL ++void permissions(path const& p, perms prms, system::error_code* ec) ++{ ++ BOOST_ASSERT_MSG(!((prms & add_perms) && (prms & remove_perms)), "add_perms and remove_perms are mutually exclusive"); ++ ++ if ((prms & add_perms) && (prms & remove_perms)) // precondition failed ++ return; ++ ++#if defined(BOOST_FILESYSTEM_USE_WASI) ++ emit_error(BOOST_ERROR_NOT_SUPPORTED, p, ec, "boost::filesystem::permissions"); ++#elif defined(BOOST_POSIX_API) ++ error_code local_ec; ++ file_status current_status((prms & symlink_perms) ? detail::symlink_status_impl(p, &local_ec) : detail::status_impl(p, &local_ec)); ++ if (local_ec) ++ { ++ if (!ec) ++ BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::permissions", p, local_ec)); ++ ++ *ec = local_ec; ++ return; ++ } ++ ++ if (prms & add_perms) ++ prms |= current_status.permissions(); ++ else if (prms & remove_perms) ++ prms = current_status.permissions() & ~prms; ++ ++ // OS X <10.10, iOS <8.0 and some other platforms don't support fchmodat(). ++ // Solaris (SunPro and gcc) only support fchmodat() on Solaris 11 and higher, ++ // and a runtime check is too much trouble. ++ // Linux does not support permissions on symbolic links and has no plans to ++ // support them in the future. The chmod() code is thus more practical, ++ // rather than always hitting ENOTSUP when sending in AT_SYMLINK_NO_FOLLOW. ++ // - See the 3rd paragraph of ++ // "Symbolic link ownership, permissions, and timestamps" at: ++ // "http://man7.org/linux/man-pages/man7/symlink.7.html" ++ // - See the fchmodat() Linux man page: ++ // "http://man7.org/linux/man-pages/man2/fchmodat.2.html" ++#if defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) && \ ++ !(defined(__SUNPRO_CC) || defined(__sun) || defined(sun)) && \ ++ !(defined(linux) || defined(__linux) || defined(__linux__)) && \ ++ !(defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED < 101000) && \ ++ !(defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && __IPHONE_OS_VERSION_MIN_REQUIRED < 80000) && \ ++ !(defined(__rtems__)) && \ ++ !(defined(__QNX__) && (_NTO_VERSION <= 700)) ++ if (::fchmodat(AT_FDCWD, p.c_str(), mode_cast(prms), !(prms & symlink_perms) ? 0 : AT_SYMLINK_NOFOLLOW)) ++#else // fallback if fchmodat() not supported ++ if (::chmod(p.c_str(), mode_cast(prms))) ++#endif ++ { ++ const int err = errno; ++ if (!ec) ++ { ++ BOOST_FILESYSTEM_THROW(filesystem_error( ++ "boost::filesystem::permissions", p, error_code(err, system::generic_category()))); ++ } ++ ++ ec->assign(err, system::generic_category()); ++ } ++ ++#else // Windows ++ ++ // if not going to alter FILE_ATTRIBUTE_READONLY, just return ++ if (!(!((prms & (add_perms | remove_perms))) || (prms & (owner_write | group_write | others_write)))) ++ return; ++ ++ DWORD attr = ::GetFileAttributesW(p.c_str()); ++ ++ if (error(attr == 0 ? BOOST_ERRNO : 0, p, ec, "boost::filesystem::permissions")) ++ return; ++ ++ if (prms & add_perms) ++ attr &= ~FILE_ATTRIBUTE_READONLY; ++ else if (prms & remove_perms) ++ attr |= FILE_ATTRIBUTE_READONLY; ++ else if (prms & (owner_write | group_write | others_write)) ++ attr &= ~FILE_ATTRIBUTE_READONLY; ++ else ++ attr |= FILE_ATTRIBUTE_READONLY; ++ ++ error(::SetFileAttributesW(p.c_str(), attr) == 0 ? BOOST_ERRNO : 0, p, ec, "boost::filesystem::permissions"); ++#endif ++} ++ ++BOOST_FILESYSTEM_DECL ++path read_symlink(path const& p, system::error_code* ec) ++{ ++ if (ec) ++ ec->clear(); ++ ++ path symlink_path; ++ ++#ifdef BOOST_POSIX_API ++ const char* const path_str = p.c_str(); ++ char small_buf[small_path_size]; ++ ssize_t result = ::readlink(path_str, small_buf, sizeof(small_buf)); ++ if (BOOST_UNLIKELY(result < 0)) ++ { ++ fail: ++ const int err = errno; ++ if (!ec) ++ BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::read_symlink", p, error_code(err, system_category()))); ++ ++ ec->assign(err, system_category()); ++ } ++ else if (BOOST_LIKELY(static_cast< std::size_t >(result) < sizeof(small_buf))) ++ { ++ symlink_path.assign(small_buf, small_buf + result); ++ } ++ else ++ { ++ for (std::size_t path_max = sizeof(small_buf) * 2u;; path_max *= 2u) // loop 'til buffer large enough ++ { ++ if (BOOST_UNLIKELY(path_max > absolute_path_max)) ++ { ++ if (!ec) ++ BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::read_symlink", p, error_code(ENAMETOOLONG, system_category()))); ++ ++ ec->assign(ENAMETOOLONG, system_category()); ++ break; ++ } ++ ++ boost::scoped_array< char > buf(new char[path_max]); ++ result = ::readlink(path_str, buf.get(), path_max); ++ if (BOOST_UNLIKELY(result < 0)) ++ { ++ goto fail; ++ } ++ else if (BOOST_LIKELY(static_cast< std::size_t >(result) < path_max)) ++ { ++ symlink_path.assign(buf.get(), buf.get() + result); ++ break; ++ } ++ } ++ } ++ ++#else ++ ++ handle_wrapper h(create_file_handle( ++ p.c_str(), ++ FILE_READ_ATTRIBUTES, ++ FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, ++ NULL, ++ OPEN_EXISTING, ++ FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT)); ++ ++ DWORD error; ++ if (BOOST_UNLIKELY(h.handle == INVALID_HANDLE_VALUE)) ++ { ++ return_last_error: ++ error = ::GetLastError(); ++ emit_error(error, p, ec, "boost::filesystem::read_symlink"); ++ return symlink_path; ++ } ++ ++ boost::scoped_ptr< reparse_data_buffer_with_storage > buf(new reparse_data_buffer_with_storage); ++ DWORD sz = 0u; ++ if (BOOST_UNLIKELY(!::DeviceIoControl(h.handle, FSCTL_GET_REPARSE_POINT, NULL, 0, buf.get(), sizeof(*buf), &sz, NULL))) ++ goto return_last_error; ++ ++ const wchar_t* buffer; ++ std::size_t offset, len; ++ switch (buf->rdb.ReparseTag) ++ { ++ case IO_REPARSE_TAG_MOUNT_POINT: ++ buffer = buf->rdb.MountPointReparseBuffer.PathBuffer; ++ offset = buf->rdb.MountPointReparseBuffer.SubstituteNameOffset; ++ len = buf->rdb.MountPointReparseBuffer.SubstituteNameLength; ++ break; ++ ++ case IO_REPARSE_TAG_SYMLINK: ++ buffer = buf->rdb.SymbolicLinkReparseBuffer.PathBuffer; ++ offset = buf->rdb.SymbolicLinkReparseBuffer.SubstituteNameOffset; ++ len = buf->rdb.SymbolicLinkReparseBuffer.SubstituteNameLength; ++ // Note: iff info.rdb.SymbolicLinkReparseBuffer.Flags & SYMLINK_FLAG_RELATIVE ++ // -> resulting path is relative to the source ++ break; ++ ++ default: ++ emit_error(BOOST_ERROR_NOT_SUPPORTED, p, ec, "Unknown ReparseTag in boost::filesystem::read_symlink"); ++ return symlink_path; ++ } ++ ++ symlink_path = convert_nt_path_to_win32_path(buffer + offset / sizeof(wchar_t), len / sizeof(wchar_t)); ++#endif ++ ++ return symlink_path; ++} ++ ++BOOST_FILESYSTEM_DECL ++path relative(path const& p, path const& base, error_code* ec) ++{ ++ if (ec) ++ ec->clear(); ++ ++ error_code local_ec; ++ path cur_path; ++ if (!p.is_absolute() || !base.is_absolute()) ++ { ++ cur_path = detail::current_path(&local_ec); ++ if (BOOST_UNLIKELY(!!local_ec)) ++ { ++ fail_local_ec: ++ if (!ec) ++ BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::relative", p, base, local_ec)); ++ ++ *ec = local_ec; ++ return path(); ++ } ++ } ++ ++ path wc_base(detail::weakly_canonical(base, cur_path, &local_ec)); ++ if (BOOST_UNLIKELY(!!local_ec)) ++ goto fail_local_ec; ++ path wc_p(detail::weakly_canonical(p, cur_path, &local_ec)); ++ if (BOOST_UNLIKELY(!!local_ec)) ++ goto fail_local_ec; ++ return wc_p.lexically_relative(wc_base); ++} ++ ++BOOST_FILESYSTEM_DECL ++bool remove(path const& p, error_code* ec) ++{ ++ if (ec) ++ ec->clear(); ++ ++ return detail::remove_impl(p, ec); ++} ++ ++BOOST_FILESYSTEM_DECL ++uintmax_t remove_all(path const& p, error_code* ec) ++{ ++ if (ec) ++ ec->clear(); ++ ++ return detail::remove_all_impl(p, ec); ++} ++ ++BOOST_FILESYSTEM_DECL ++void rename(path const& old_p, path const& new_p, error_code* ec) ++{ ++ error(!BOOST_MOVE_FILE(old_p.c_str(), new_p.c_str()) ? BOOST_ERRNO : 0, old_p, new_p, ec, "boost::filesystem::rename"); ++} ++ ++BOOST_FILESYSTEM_DECL ++void resize_file(path const& p, uintmax_t size, system::error_code* ec) ++{ ++#if defined(BOOST_POSIX_API) ++ if (BOOST_UNLIKELY(size > static_cast< uintmax_t >((std::numeric_limits< off_t >::max)()))) ++ { ++ emit_error(system::errc::file_too_large, p, ec, "boost::filesystem::resize_file"); ++ return; ++ } ++#endif ++ error(!BOOST_RESIZE_FILE(p.c_str(), size) ? BOOST_ERRNO : 0, p, ec, "boost::filesystem::resize_file"); ++} ++ ++BOOST_FILESYSTEM_DECL ++space_info space(path const& p, error_code* ec) ++{ ++ space_info info; ++ // Initialize members to -1, as required by C++20 [fs.op.space]/1 in case of error ++ info.capacity = static_cast< uintmax_t >(-1); ++ info.free = static_cast< uintmax_t >(-1); ++ info.available = static_cast< uintmax_t >(-1); ++ ++ if (ec) ++ ec->clear(); ++ ++#if defined(BOOST_FILESYSTEM_USE_WASI) ++ ++ emit_error(BOOST_ERROR_NOT_SUPPORTED, p, ec, "boost::filesystem::space"); ++ ++#elif defined(BOOST_POSIX_API) ++ ++ struct BOOST_STATVFS vfs; ++ if (!error(::BOOST_STATVFS(p.c_str(), &vfs) ? BOOST_ERRNO : 0, p, ec, "boost::filesystem::space")) ++ { ++ info.capacity = static_cast< uintmax_t >(vfs.f_blocks) * BOOST_STATVFS_F_FRSIZE; ++ info.free = static_cast< uintmax_t >(vfs.f_bfree) * BOOST_STATVFS_F_FRSIZE; ++ info.available = static_cast< uintmax_t >(vfs.f_bavail) * BOOST_STATVFS_F_FRSIZE; ++ } ++ ++#else ++ ++ // GetDiskFreeSpaceExW requires a directory path, which is unlike statvfs, which accepts any file. ++ // To work around this, test if the path refers to a directory and use the parent directory if not. ++ error_code local_ec; ++ file_status status = detail::status_impl(p, &local_ec); ++ if (status.type() == fs::status_error || status.type() == fs::file_not_found) ++ { ++ fail_local_ec: ++ if (!ec) ++ BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::space", p, local_ec)); ++ *ec = local_ec; ++ return info; ++ } ++ ++ path dir_path = p; ++ if (!is_directory(status)) ++ { ++ path cur_path = detail::current_path(ec); ++ if (ec && *ec) ++ return info; ++ ++ status = detail::symlink_status_impl(p, &local_ec); ++ if (status.type() == fs::status_error) ++ goto fail_local_ec; ++ if (is_symlink(status)) ++ { ++ // We need to resolve the symlink so that we report the space for the symlink target ++ dir_path = detail::canonical(p, cur_path, ec); ++ if (ec && *ec) ++ return info; ++ } ++ ++ dir_path = dir_path.parent_path(); ++ if (dir_path.empty()) ++ { ++ // The original path was just a filename, which is a relative path wrt. current directory ++ dir_path = cur_path; ++ } ++ } ++ ++ // For UNC names, the path must also include a trailing slash. ++ path::string_type str = dir_path.native(); ++ if (str.size() >= 2u && detail::is_directory_separator(str[0]) && detail::is_directory_separator(str[1]) && !detail::is_directory_separator(*(str.end() - 1))) ++ str.push_back(path::preferred_separator); ++ ++ ULARGE_INTEGER avail, total, free; ++ if (!error(::GetDiskFreeSpaceExW(str.c_str(), &avail, &total, &free) == 0, p, ec, "boost::filesystem::space")) ++ { ++ info.capacity = static_cast< uintmax_t >(total.QuadPart); ++ info.free = static_cast< uintmax_t >(free.QuadPart); ++ info.available = static_cast< uintmax_t >(avail.QuadPart); ++ } ++ ++#endif ++ ++ return info; ++} ++ ++BOOST_FILESYSTEM_DECL ++file_status status(path const& p, error_code* ec) ++{ ++ if (ec) ++ ec->clear(); ++ ++ return detail::status_impl(p, ec); ++} ++ ++BOOST_FILESYSTEM_DECL ++file_status symlink_status(path const& p, error_code* ec) ++{ ++ if (ec) ++ ec->clear(); ++ ++ return detail::symlink_status_impl(p, ec); ++} ++ ++// contributed by Jeff Flinn ++BOOST_FILESYSTEM_DECL ++path temp_directory_path(system::error_code* ec) ++{ ++ if (ec) ++ ec->clear(); ++ ++#ifdef BOOST_POSIX_API ++ const char* val = NULL; ++ ++ (val = std::getenv("TMPDIR")) || ++ (val = std::getenv("TMP")) || ++ (val = std::getenv("TEMP")) || ++ (val = std::getenv("TEMPDIR")); ++ ++#ifdef __ANDROID__ ++ const char* default_tmp = "/data/local/tmp"; ++#else ++ const char* default_tmp = "/tmp"; ++#endif ++ path p((val != NULL) ? val : default_tmp); ++ ++ if (BOOST_UNLIKELY(p.empty())) ++ { ++ fail_not_dir: ++ error(ENOTDIR, p, ec, "boost::filesystem::temp_directory_path"); ++ return p; ++ } ++ ++ file_status status = detail::status_impl(p, ec); ++ if (BOOST_UNLIKELY(ec && *ec)) ++ return path(); ++ if (BOOST_UNLIKELY(!is_directory(status))) ++ goto fail_not_dir; ++ ++ return p; ++ ++#else // Windows ++#if !defined(UNDER_CE) ++ ++ static const wchar_t* env_list[] = { L"TMP", L"TEMP", L"LOCALAPPDATA", L"USERPROFILE" }; ++ static const wchar_t temp_dir[] = L"Temp"; ++ ++ path p; ++ for (unsigned int i = 0; i < sizeof(env_list) / sizeof(*env_list); ++i) ++ { ++ std::wstring env = wgetenv(env_list[i]); ++ if (!env.empty()) ++ { ++ p = env; ++ if (i >= 2) ++ path_algorithms::append_v4(p, temp_dir, temp_dir + (sizeof(temp_dir) / sizeof(*temp_dir) - 1u)); ++ error_code lcl_ec; ++ if (exists(p, lcl_ec) && !lcl_ec && is_directory(p, lcl_ec) && !lcl_ec) ++ break; ++ p.clear(); ++ } ++ } ++ ++ if (p.empty()) ++ { ++ // use a separate buffer since in C++03 a string is not required to be contiguous ++ const UINT size = ::GetWindowsDirectoryW(NULL, 0); ++ if (BOOST_UNLIKELY(size == 0)) ++ { ++ getwindir_error: ++ int errval = ::GetLastError(); ++ error(errval, ec, "boost::filesystem::temp_directory_path"); ++ return path(); ++ } ++ ++ boost::scoped_array< wchar_t > buf(new wchar_t[size]); ++ if (BOOST_UNLIKELY(::GetWindowsDirectoryW(buf.get(), size) == 0)) ++ goto getwindir_error; ++ ++ p = buf.get(); // do not depend on initial buf size, see ticket #10388 ++ path_algorithms::append_v4(p, temp_dir, temp_dir + (sizeof(temp_dir) / sizeof(*temp_dir) - 1u)); ++ } ++ ++ return p; ++ ++#else // Windows CE ++ ++ // Windows CE has no environment variables, so the same code as used for ++ // regular Windows, above, doesn't work. ++ ++ DWORD size = ::GetTempPathW(0, NULL); ++ if (size == 0u) ++ { ++ fail: ++ int errval = ::GetLastError(); ++ error(errval, ec, "boost::filesystem::temp_directory_path"); ++ return path(); ++ } ++ ++ boost::scoped_array< wchar_t > buf(new wchar_t[size]); ++ if (::GetTempPathW(size, buf.get()) == 0) ++ goto fail; ++ ++ path p(buf.get()); ++ p.remove_trailing_separator(); ++ ++ file_status status = detail::status_impl(p, ec); ++ if (ec && *ec) ++ return path(); ++ if (!is_directory(status)) ++ { ++ error(ERROR_PATH_NOT_FOUND, p, ec, "boost::filesystem::temp_directory_path"); ++ return path(); ++ } ++ ++ return p; ++ ++#endif // !defined(UNDER_CE) ++#endif ++} ++ ++BOOST_FILESYSTEM_DECL ++path system_complete(path const& p, system::error_code* ec) ++{ ++#ifdef BOOST_POSIX_API ++ ++ if (p.empty() || p.is_absolute()) ++ return p; ++ ++ path res(current_path()); ++ path_algorithms::append_v4(res, p); ++ return res; ++ ++#else ++ if (p.empty()) ++ { ++ if (ec) ++ ec->clear(); ++ return p; ++ } ++ ++ BOOST_CONSTEXPR_OR_CONST std::size_t buf_size = 128u; ++ wchar_t buf[buf_size]; ++ wchar_t* pfn; ++ std::size_t len = get_full_path_name(p, buf_size, buf, &pfn); ++ ++ if (error(len == 0 ? BOOST_ERRNO : 0, p, ec, "boost::filesystem::system_complete")) ++ return path(); ++ ++ if (len < buf_size) // len does not include null termination character ++ return path(&buf[0]); ++ ++ boost::scoped_array< wchar_t > big_buf(new wchar_t[len]); ++ ++ return error(get_full_path_name(p, len, big_buf.get(), &pfn) == 0 ? BOOST_ERRNO : 0, p, ec, "boost::filesystem::system_complete") ? path() : path(big_buf.get()); ++#endif ++} ++ ++BOOST_FILESYSTEM_DECL ++path weakly_canonical(path const& p, path const& base, system::error_code* ec) ++{ ++ system::error_code local_ec; ++ const path::iterator p_end(p.end()); ++ ++#if defined(BOOST_POSIX_API) ++ ++ path::iterator itr(p_end); ++ path head(p); ++ for (; !head.empty(); path_algorithms::decrement_v4(itr)) ++ { ++ file_status head_status(detail::status_impl(head, &local_ec)); ++ if (BOOST_UNLIKELY(head_status.type() == fs::status_error)) ++ { ++ if (!ec) ++ BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::weakly_canonical", head, local_ec)); ++ ++ *ec = local_ec; ++ return path(); ++ } ++ ++ if (head_status.type() != fs::file_not_found) ++ break; ++ ++ head.remove_filename_and_trailing_separators(); ++ } ++ ++ if (head.empty()) ++ return path_algorithms::lexically_normal_v4(p); ++ ++ path const& dot_p = dot_path(); ++ path const& dot_dot_p = dot_dot_path(); ++ ++#else ++ ++ // On Windows, filesystem APIs such as GetFileAttributesW and CreateFileW perform lexical path normalization ++ // internally. As a result, a path like "c:\a\.." can be reported as present even if "c:\a" is not. This would ++ // break canonical, as symlink_status that it calls internally would report an error that the file at the ++ // intermediate path does not exist. To avoid this, scan the initial path in the forward direction. ++ // Also, operate on paths with preferred separators. This can be important on Windows since GetFileAttributesW ++ // or CreateFileW, which is called in status() may return "file not found" for paths to network shares and ++ // mounted cloud storages that have forward slashes as separators. ++ // Also, avoid querying status of the root name such as \\?\c: as CreateFileW returns ERROR_INVALID_FUNCTION for ++ // such path. Querying the status of a root name such as c: is also not right as this path refers to the current ++ // directory on drive C:, which is not what we want to test for existence anyway. ++ path::iterator itr(p.begin()); ++ path head; ++ if (p.has_root_name()) ++ { ++ BOOST_ASSERT(itr != p_end); ++ head = *itr; ++ path_algorithms::increment_v4(itr); ++ } ++ ++ if (p.has_root_directory()) ++ { ++ BOOST_ASSERT(itr != p_end); ++ // Convert generic separator returned by the iterator for the root directory to ++ // the preferred separator. ++ head += path::preferred_separator; ++ path_algorithms::increment_v4(itr); ++ } ++ ++ if (!head.empty()) ++ { ++ file_status head_status(detail::status_impl(head, &local_ec)); ++ if (BOOST_UNLIKELY(head_status.type() == fs::status_error)) ++ { ++ if (!ec) ++ BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::weakly_canonical", head, local_ec)); ++ ++ *ec = local_ec; ++ return path(); ++ } ++ ++ if (head_status.type() == fs::file_not_found) ++ { ++ // If the root path does not exist then no path element exists ++ return path_algorithms::lexically_normal_v4(p); ++ } ++ } ++ ++ path const& dot_p = dot_path(); ++ path const& dot_dot_p = dot_dot_path(); ++ for (; itr != p_end; path_algorithms::increment_v4(itr)) ++ { ++ path const& p_elem = *itr; ++ ++ // Avoid querying status of paths containing dot and dot-dot elements, as this will break ++ // if the root name starts with "\\?\". ++ if (path_algorithms::compare_v4(p_elem, dot_p) == 0) ++ continue; ++ ++ if (path_algorithms::compare_v4(p_elem, dot_dot_p) == 0) ++ { ++ if (head.has_relative_path()) ++ head.remove_filename_and_trailing_separators(); ++ ++ continue; ++ } ++ ++ path_algorithms::append_v4(head, p_elem); ++ ++ file_status head_status(detail::status_impl(head, &local_ec)); ++ if (BOOST_UNLIKELY(head_status.type() == fs::status_error)) ++ { ++ if (!ec) ++ BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::weakly_canonical", head, local_ec)); ++ ++ *ec = local_ec; ++ return path(); ++ } ++ ++ if (head_status.type() == fs::file_not_found) ++ { ++ head.remove_filename_and_trailing_separators(); ++ break; ++ } ++ } ++ ++ if (head.empty()) ++ return path_algorithms::lexically_normal_v4(p); ++ ++#endif ++ ++ path tail; ++ bool tail_has_dots = false; ++ for (; itr != p_end; path_algorithms::increment_v4(itr)) ++ { ++ path const& tail_elem = *itr; ++ path_algorithms::append_v4(tail, tail_elem); ++ // for a later optimization, track if any dot or dot-dot elements are present ++ if (!tail_has_dots && (path_algorithms::compare_v4(tail_elem, dot_p) == 0 || path_algorithms::compare_v4(tail_elem, dot_dot_p) == 0)) ++ tail_has_dots = true; ++ } ++ ++ head = detail::canonical(head, base, &local_ec); ++ if (BOOST_UNLIKELY(!!local_ec)) ++ { ++ if (!ec) ++ BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::weakly_canonical", head, local_ec)); ++ ++ *ec = local_ec; ++ return path(); ++ } ++ ++ if (BOOST_LIKELY(!tail.empty())) ++ { ++ path_algorithms::append_v4(head, tail); ++ ++ // optimization: only normalize if tail had dot or dot-dot element ++ if (tail_has_dots) ++ return path_algorithms::lexically_normal_v4(head); ++ } ++ ++ return head; ++} ++ ++} // namespace detail ++} // namespace filesystem ++} // namespace boost ++ ++#include +diff -urN boost_1_83_0.orig/libs/filesystem/src/path.cpp boost_1_83_0/libs/filesystem/src/path.cpp +--- boost_1_83_0.orig/libs/filesystem/src/path.cpp 2023-08-08 16:02:51.000000000 -0500 ++++ boost_1_83_0/libs/filesystem/src/path.cpp 2023-12-20 19:37:21.249966924 -0600 +@@ -28,7 +28,7 @@ + #include "windows_file_codecvt.hpp" + #include "windows_tools.hpp" + #include +-#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__) ++#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__) || defined(__ANDROID__) + #include + #endif + +@@ -1329,7 +1329,7 @@ + #if defined(BOOST_WINDOWS_API) + std::locale global_loc = std::locale(); + return std::locale(global_loc, new boost::filesystem::detail::windows_file_codecvt()); +-#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__) ++#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__) || defined(__ANDROID__) + // "All BSD system functions expect their string parameters to be in UTF-8 encoding + // and nothing else." See + // http://developer.apple.com/mac/library/documentation/MacOSX/Conceptual/BPInternational/Articles/FileEncodings.html +diff -urN boost_1_83_0.orig/libs/filesystem/src/path.cpp.orig boost_1_83_0/libs/filesystem/src/path.cpp.orig +--- boost_1_83_0.orig/libs/filesystem/src/path.cpp.orig 1969-12-31 18:00:00.000000000 -0600 ++++ boost_1_83_0/libs/filesystem/src/path.cpp.orig 2023-12-20 19:37:21.249966924 -0600 +@@ -0,0 +1,1633 @@ ++// filesystem path.cpp ------------------------------------------------------------- // ++ ++// Copyright Beman Dawes 2008 ++// Copyright Andrey Semashev 2021-2023 ++ ++// Distributed under the Boost Software License, Version 1.0. ++// See http://www.boost.org/LICENSE_1_0.txt ++ ++// Library home page: http://www.boost.org/libs/filesystem ++ ++#include "platform_config.hpp" ++ ++#include ++#include ++#include // codecvt_error_category() ++#include ++#include // for BOOST_SYSTEM_HAS_CONSTEXPR ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include // std::atexit ++ ++#ifdef BOOST_WINDOWS_API ++#include "windows_file_codecvt.hpp" ++#include "windows_tools.hpp" ++#include ++#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__) ++#include ++#endif ++ ++#ifdef BOOST_FILESYSTEM_DEBUG ++#include ++#include ++#endif ++ ++#include "atomic_tools.hpp" ++#include "private_config.hpp" ++ ++#include // must be the last #include ++ ++namespace fs = boost::filesystem; ++ ++using boost::filesystem::path; ++ ++//--------------------------------------------------------------------------------------// ++// // ++// class path helpers // ++// // ++//--------------------------------------------------------------------------------------// ++ ++namespace { ++//------------------------------------------------------------------------------------// ++// miscellaneous class path helpers // ++//------------------------------------------------------------------------------------// ++ ++typedef path::value_type value_type; ++typedef path::string_type string_type; ++typedef string_type::size_type size_type; ++ ++#ifdef BOOST_WINDOWS_API ++ ++const wchar_t dot_path_literal[] = L"."; ++const wchar_t dot_dot_path_literal[] = L".."; ++const wchar_t separators[] = L"/\\"; ++using boost::filesystem::detail::colon; ++using boost::filesystem::detail::questionmark; ++ ++inline bool is_alnum(wchar_t c) ++{ ++ return boost::filesystem::detail::is_letter(c) || (c >= L'0' && c <= L'9'); ++} ++ ++inline bool is_device_name_char(wchar_t c) ++{ ++ // https://googleprojectzero.blogspot.com/2016/02/the-definitive-guide-on-win32-to-nt.html ++ // Device names are: ++ // ++ // - PRN ++ // - AUX ++ // - NUL ++ // - CON ++ // - LPT[1-9] ++ // - COM[1-9] ++ // - CONIN$ ++ // - CONOUT$ ++ return is_alnum(c) || c == L'$'; ++} ++ ++//! Returns position of the first directory separator in the \a size initial characters of \a p, or \a size if not found ++inline size_type find_separator(const wchar_t* p, size_type size) BOOST_NOEXCEPT ++{ ++ size_type pos = 0u; ++ for (; pos < size; ++pos) ++ { ++ const wchar_t c = p[pos]; ++ if (boost::filesystem::detail::is_directory_separator(c)) ++ break; ++ } ++ return pos; ++} ++ ++#else // BOOST_WINDOWS_API ++ ++const char dot_path_literal[] = "."; ++const char dot_dot_path_literal[] = ".."; ++const char separators[] = "/"; ++ ++//! Returns position of the first directory separator in the \a size initial characters of \a p, or \a size if not found ++inline size_type find_separator(const char* p, size_type size) BOOST_NOEXCEPT ++{ ++ const char* sep = static_cast< const char* >(std::memchr(p, '/', size)); ++ size_type pos = size; ++ if (BOOST_LIKELY(!!sep)) ++ pos = sep - p; ++ return pos; ++} ++ ++#endif // BOOST_WINDOWS_API ++ ++// pos is position of the separator ++bool is_root_separator(string_type const& str, size_type root_dir_pos, size_type pos); ++ ++// Returns: Size of the filename element that ends at end_pos (which is past-the-end position). 0 if no filename found. ++size_type find_filename_size(string_type const& str, size_type root_name_size, size_type end_pos); ++ ++// Returns: starting position of root directory or size if not found. Sets root_name_size to length ++// of the root name if the characters before the returned position (if any) are considered a root name. ++size_type find_root_directory_start(const value_type* path, size_type size, size_type& root_name_size); ++ ++// Finds position and size of the first element of the path ++void first_element(string_type const& src, size_type& element_pos, size_type& element_size, size_type size); ++ ++// Finds position and size of the first element of the path ++inline void first_element(string_type const& src, size_type& element_pos, size_type& element_size) ++{ ++ first_element(src, element_pos, element_size, src.size()); ++} ++ ++} // unnamed namespace ++ ++//--------------------------------------------------------------------------------------// ++// // ++// class path implementation // ++// // ++//--------------------------------------------------------------------------------------// ++ ++namespace boost { ++namespace filesystem { ++namespace detail { ++ ++// C++14 provides a mismatch algorithm with four iterator arguments(), but earlier ++// standard libraries didn't, so provide this needed functionality. ++inline std::pair< path::iterator, path::iterator > mismatch(path::iterator it1, path::iterator it1end, path::iterator it2, path::iterator it2end) ++{ ++ for (; it1 != it1end && it2 != it2end && path_algorithms::compare_v4(*it1, *it2) == 0;) ++ { ++ path_algorithms::increment_v4(it1); ++ path_algorithms::increment_v4(it2); ++ } ++ return std::make_pair(it1, it2); ++} ++ ++// normal --------------------------------------------------------------------------// ++ ++BOOST_FILESYSTEM_DECL path path_algorithms::lexically_normal_v3(path const& p) ++{ ++ const value_type* const pathname = p.m_pathname.c_str(); ++ const size_type pathname_size = p.m_pathname.size(); ++ size_type root_name_size = 0; ++ size_type root_dir_pos = find_root_directory_start(pathname, pathname_size, root_name_size); ++ path normal(pathname, pathname + root_name_size); ++ ++#if defined(BOOST_WINDOWS_API) ++ for (size_type i = 0; i < root_name_size; ++i) ++ { ++ if (normal.m_pathname[i] == path::separator) ++ normal.m_pathname[i] = path::preferred_separator; ++ } ++#endif ++ ++ size_type root_path_size = root_name_size; ++ if (root_dir_pos < pathname_size) ++ { ++ root_path_size = root_dir_pos + 1; ++ normal.m_pathname.push_back(path::preferred_separator); ++ } ++ ++ size_type i = root_path_size; ++ ++ // Skip redundant directory separators after the root directory ++ while (i < pathname_size && detail::is_directory_separator(pathname[i])) ++ ++i; ++ ++ if (i < pathname_size) ++ { ++ bool last_element_was_dot = false; ++ while (true) ++ { ++ { ++ const size_type start_pos = i; ++ ++ // Find next separator ++ i += find_separator(pathname + i, pathname_size - i); ++ ++ const size_type size = i - start_pos; ++ ++ // Skip dot elements ++ if (size == 1u && pathname[start_pos] == path::dot) ++ { ++ last_element_was_dot = true; ++ goto skip_append; ++ } ++ ++ last_element_was_dot = false; ++ ++ // Process dot dot elements ++ if (size == 2u && pathname[start_pos] == path::dot && pathname[start_pos + 1] == path::dot && normal.m_pathname.size() > root_path_size) ++ { ++ // Don't remove previous dot dot elements ++ const size_type normal_size = normal.m_pathname.size(); ++ size_type filename_size = find_filename_size(normal.m_pathname, root_path_size, normal_size); ++ size_type pos = normal_size - filename_size; ++ if (filename_size != 2u || normal.m_pathname[pos] != path::dot || normal.m_pathname[pos + 1] != path::dot) ++ { ++ if (pos > root_path_size && detail::is_directory_separator(normal.m_pathname[pos - 1])) ++ --pos; ++ normal.m_pathname.erase(normal.m_pathname.begin() + pos , normal.m_pathname.end()); ++ goto skip_append; ++ } ++ } ++ ++ // Append the element ++ path_algorithms::append_separator_if_needed(normal); ++ normal.m_pathname.append(pathname + start_pos, size); ++ } ++ ++ skip_append: ++ if (i == pathname_size) ++ break; ++ ++ // Skip directory separators, including duplicates ++ while (i < pathname_size && detail::is_directory_separator(pathname[i])) ++ ++i; ++ ++ if (i == pathname_size) ++ { ++ // If a path ends with a separator, add a trailing dot element ++ goto append_trailing_dot; ++ } ++ } ++ ++ if (normal.empty() || last_element_was_dot) ++ { ++ append_trailing_dot: ++ path_algorithms::append_separator_if_needed(normal); ++ normal.m_pathname.push_back(path::dot); ++ } ++ } ++ ++ return normal; ++} ++ ++BOOST_FILESYSTEM_DECL path path_algorithms::lexically_normal_v4(path const& p) ++{ ++ const value_type* const pathname = p.m_pathname.c_str(); ++ const size_type pathname_size = p.m_pathname.size(); ++ size_type root_name_size = 0; ++ size_type root_dir_pos = find_root_directory_start(pathname, pathname_size, root_name_size); ++ path normal(pathname, pathname + root_name_size); ++ ++#if defined(BOOST_WINDOWS_API) ++ for (size_type i = 0; i < root_name_size; ++i) ++ { ++ if (normal.m_pathname[i] == path::separator) ++ normal.m_pathname[i] = path::preferred_separator; ++ } ++#endif ++ ++ size_type root_path_size = root_name_size; ++ if (root_dir_pos < pathname_size) ++ { ++ root_path_size = root_dir_pos + 1; ++ normal.m_pathname.push_back(path::preferred_separator); ++ } ++ ++ size_type i = root_path_size; ++ ++ // Skip redundant directory separators after the root directory ++ while (i < pathname_size && detail::is_directory_separator(pathname[i])) ++ ++i; ++ ++ if (i < pathname_size) ++ { ++ while (true) ++ { ++ bool last_element_was_dot = false; ++ { ++ const size_type start_pos = i; ++ ++ // Find next separator ++ i += find_separator(pathname + i, pathname_size - i); ++ ++ const size_type size = i - start_pos; ++ ++ // Skip dot elements ++ if (size == 1u && pathname[start_pos] == path::dot) ++ { ++ last_element_was_dot = true; ++ goto skip_append; ++ } ++ ++ // Process dot dot elements ++ if (size == 2u && pathname[start_pos] == path::dot && pathname[start_pos + 1] == path::dot && normal.m_pathname.size() > root_path_size) ++ { ++ // Don't remove previous dot dot elements ++ const size_type normal_size = normal.m_pathname.size(); ++ size_type filename_size = find_filename_size(normal.m_pathname, root_path_size, normal_size); ++ size_type pos = normal_size - filename_size; ++ if (filename_size != 2u || normal.m_pathname[pos] != path::dot || normal.m_pathname[pos + 1] != path::dot) ++ { ++ if (pos > root_path_size && detail::is_directory_separator(normal.m_pathname[pos - 1])) ++ --pos; ++ normal.m_pathname.erase(normal.m_pathname.begin() + pos, normal.m_pathname.end()); ++ goto skip_append; ++ } ++ } ++ ++ // Append the element ++ path_algorithms::append_separator_if_needed(normal); ++ normal.m_pathname.append(pathname + start_pos, size); ++ } ++ ++ skip_append: ++ if (i == pathname_size) ++ { ++ // If a path ends with a trailing dot after a directory element, add a trailing separator ++ if (last_element_was_dot && !normal.empty() && !normal.filename_is_dot_dot()) ++ path_algorithms::append_separator_if_needed(normal); ++ ++ break; ++ } ++ ++ // Skip directory separators, including duplicates ++ while (i < pathname_size && detail::is_directory_separator(pathname[i])) ++ ++i; ++ ++ if (i == pathname_size) ++ { ++ // If a path ends with a separator, add a trailing separator ++ if (!normal.empty() && !normal.filename_is_dot_dot()) ++ path_algorithms::append_separator_if_needed(normal); ++ break; ++ } ++ } ++ ++ // If the original path was not empty and normalized ended up being empty, make it a dot ++ if (normal.empty()) ++ normal.m_pathname.push_back(path::dot); ++ } ++ ++ return normal; ++} ++ ++// append --------------------------------------------------------------------------// ++ ++BOOST_FILESYSTEM_DECL void path_algorithms::append_v3(path& p, const value_type* begin, const value_type* end) ++{ ++ if (begin != end) ++ { ++ if (BOOST_LIKELY(begin < p.m_pathname.data() || begin >= (p.m_pathname.data() + p.m_pathname.size()))) ++ { ++ if (!detail::is_directory_separator(*begin)) ++ path_algorithms::append_separator_if_needed(p); ++ p.m_pathname.append(begin, end); ++ } ++ else ++ { ++ // overlapping source ++ string_type rhs(begin, end); ++ path_algorithms::append_v3(p, rhs.data(), rhs.data() + rhs.size()); ++ } ++ } ++} ++ ++BOOST_FILESYSTEM_DECL void path_algorithms::append_v4(path& p, const value_type* begin, const value_type* end) ++{ ++ if (begin != end) ++ { ++ if (BOOST_LIKELY(begin < p.m_pathname.data() || begin >= (p.m_pathname.data() + p.m_pathname.size()))) ++ { ++ const size_type that_size = end - begin; ++ size_type that_root_name_size = 0; ++ size_type that_root_dir_pos = find_root_directory_start(begin, that_size, that_root_name_size); ++ ++ // if (p.is_absolute()) ++ if ++ ( ++#if defined(BOOST_WINDOWS_API) && !defined(UNDER_CE) ++ that_root_name_size > 0 && ++#endif ++ that_root_dir_pos < that_size ++ ) ++ { ++ return_assign: ++ p.assign(begin, end); ++ return; ++ } ++ ++ size_type this_root_name_size = 0; ++ find_root_directory_start(p.m_pathname.c_str(), p.m_pathname.size(), this_root_name_size); ++ ++ if ++ ( ++ that_root_name_size > 0 && ++ (that_root_name_size != this_root_name_size || std::memcmp(p.m_pathname.c_str(), begin, this_root_name_size * sizeof(value_type)) != 0) ++ ) ++ { ++ goto return_assign; ++ } ++ ++ if (that_root_dir_pos < that_size) ++ { ++ // Remove root directory (if any) and relative path to replace with those from p ++ p.m_pathname.erase(p.m_pathname.begin() + this_root_name_size, p.m_pathname.end()); ++ } ++ ++ const value_type* const that_path = begin + that_root_name_size; ++ if (!detail::is_directory_separator(*that_path)) ++ path_algorithms::append_separator_if_needed(p); ++ p.m_pathname.append(that_path, end); ++ } ++ else ++ { ++ // overlapping source ++ string_type rhs(begin, end); ++ path_algorithms::append_v4(p, rhs.data(), rhs.data() + rhs.size()); ++ } ++ } ++ else if (path_algorithms::has_filename_v4(p)) ++ { ++ p.m_pathname.push_back(path::preferred_separator); ++ } ++} ++ ++// compare -------------------------------------------------------------------------// ++ ++BOOST_FILESYSTEM_DECL int path_algorithms::lex_compare_v3 ++( ++ path_detail::path_iterator first1, path_detail::path_iterator const& last1, ++ path_detail::path_iterator first2, path_detail::path_iterator const& last2 ++) ++{ ++ for (; first1 != last1 && first2 != last2;) ++ { ++ if (first1->native() < first2->native()) ++ return -1; ++ if (first2->native() < first1->native()) ++ return 1; ++ BOOST_ASSERT(first2->native() == first1->native()); ++ path_algorithms::increment_v3(first1); ++ path_algorithms::increment_v3(first2); ++ } ++ if (first1 == last1 && first2 == last2) ++ return 0; ++ return first1 == last1 ? -1 : 1; ++} ++ ++BOOST_FILESYSTEM_DECL int path_algorithms::lex_compare_v4 ++( ++ path_detail::path_iterator first1, path_detail::path_iterator const& last1, ++ path_detail::path_iterator first2, path_detail::path_iterator const& last2 ++) ++{ ++ for (; first1 != last1 && first2 != last2;) ++ { ++ if (first1->native() < first2->native()) ++ return -1; ++ if (first2->native() < first1->native()) ++ return 1; ++ BOOST_ASSERT(first2->native() == first1->native()); ++ path_algorithms::increment_v4(first1); ++ path_algorithms::increment_v4(first2); ++ } ++ if (first1 == last1 && first2 == last2) ++ return 0; ++ return first1 == last1 ? -1 : 1; ++} ++ ++BOOST_FILESYSTEM_DECL int path_algorithms::compare_v3(path const& left, path const& right) ++{ ++ return path_algorithms::lex_compare_v3(left.begin(), left.end(), right.begin(), right.end()); ++} ++ ++BOOST_FILESYSTEM_DECL int path_algorithms::compare_v4(path const& left, path const& right) ++{ ++ return path_algorithms::lex_compare_v4(left.begin(), left.end(), right.begin(), right.end()); ++} ++ ++// append_separator_if_needed ------------------------------------------------------// ++ ++BOOST_FILESYSTEM_DECL path_algorithms::string_type::size_type path_algorithms::append_separator_if_needed(path& p) ++{ ++ if (!p.m_pathname.empty() && ++#ifdef BOOST_WINDOWS_API ++ *(p.m_pathname.end() - 1) != colon && ++#endif ++ !detail::is_directory_separator(*(p.m_pathname.end() - 1))) ++ { ++ string_type::size_type tmp(p.m_pathname.size()); ++ p.m_pathname.push_back(path::preferred_separator); ++ return tmp; ++ } ++ return 0; ++} ++ ++// erase_redundant_separator -------------------------------------------------------// ++ ++BOOST_FILESYSTEM_DECL void path_algorithms::erase_redundant_separator(path& p, string_type::size_type sep_pos) ++{ ++ if (sep_pos // a separator was added ++ && sep_pos < p.m_pathname.size() // and something was appended ++ && (p.m_pathname[sep_pos + 1] == path::separator // and it was also separator ++#ifdef BOOST_WINDOWS_API ++ || p.m_pathname[sep_pos + 1] == path::preferred_separator // or preferred_separator ++#endif ++ )) ++ { ++ p.m_pathname.erase(p.m_pathname.begin() + sep_pos); // erase the added separator ++ } ++} ++ ++// modifiers -----------------------------------------------------------------------// ++ ++BOOST_FILESYSTEM_DECL void path_algorithms::remove_filename_v3(path& p) ++{ ++ p.remove_filename_and_trailing_separators(); ++} ++ ++BOOST_FILESYSTEM_DECL void path_algorithms::remove_filename_v4(path& p) ++{ ++ size_type filename_size = path_algorithms::find_filename_v4_size(p); ++ p.m_pathname.erase(p.m_pathname.begin() + (p.m_pathname.size() - filename_size), p.m_pathname.end()); ++} ++ ++BOOST_FILESYSTEM_DECL void path_algorithms::replace_extension_v3(path& p, path const& new_extension) ++{ ++ // erase existing extension, including the dot, if any ++ size_type ext_pos = p.m_pathname.size() - path_algorithms::extension_v3(p).m_pathname.size(); ++ p.m_pathname.erase(p.m_pathname.begin() + ext_pos, p.m_pathname.end()); ++ ++ if (!new_extension.empty()) ++ { ++ // append new_extension, adding the dot if necessary ++ if (new_extension.m_pathname[0] != path::dot) ++ p.m_pathname.push_back(path::dot); ++ p.m_pathname.append(new_extension.m_pathname); ++ } ++} ++ ++BOOST_FILESYSTEM_DECL void path_algorithms::replace_extension_v4(path& p, path const& new_extension) ++{ ++ // erase existing extension, including the dot, if any ++ size_type ext_pos = p.m_pathname.size() - path_algorithms::find_extension_v4_size(p); ++ p.m_pathname.erase(p.m_pathname.begin() + ext_pos, p.m_pathname.end()); ++ ++ if (!new_extension.empty()) ++ { ++ // append new_extension, adding the dot if necessary ++ if (new_extension.m_pathname[0] != path::dot) ++ p.m_pathname.push_back(path::dot); ++ p.m_pathname.append(new_extension.m_pathname); ++ } ++} ++ ++// decomposition -------------------------------------------------------------------// ++ ++BOOST_FILESYSTEM_DECL size_type path_algorithms::find_root_name_size(path const& p) ++{ ++ size_type root_name_size = 0; ++ find_root_directory_start(p.m_pathname.c_str(), p.m_pathname.size(), root_name_size); ++ return root_name_size; ++} ++ ++BOOST_FILESYSTEM_DECL size_type path_algorithms::find_root_path_size(path const& p) ++{ ++ size_type root_name_size = 0; ++ size_type root_dir_pos = find_root_directory_start(p.m_pathname.c_str(), p.m_pathname.size(), root_name_size); ++ ++ size_type size = root_name_size; ++ if (root_dir_pos < p.m_pathname.size()) ++ size = root_dir_pos + 1; ++ ++ return size; ++} ++ ++BOOST_FILESYSTEM_DECL path_algorithms::substring path_algorithms::find_root_directory(path const& p) ++{ ++ substring root_dir; ++ size_type root_name_size = 0; ++ root_dir.pos = find_root_directory_start(p.m_pathname.c_str(), p.m_pathname.size(), root_name_size); ++ root_dir.size = static_cast< std::size_t >(root_dir.pos < p.m_pathname.size()); ++ return root_dir; ++} ++ ++BOOST_FILESYSTEM_DECL path_algorithms::substring path_algorithms::find_relative_path(path const& p) ++{ ++ size_type root_name_size = 0; ++ size_type root_dir_pos = find_root_directory_start(p.m_pathname.c_str(), p.m_pathname.size(), root_name_size); ++ ++ // Skip root name, root directory and any duplicate separators ++ size_type size = root_name_size; ++ if (root_dir_pos < p.m_pathname.size()) ++ { ++ size = root_dir_pos + 1; ++ ++ for (size_type n = p.m_pathname.size(); size < n; ++size) ++ { ++ if (!detail::is_directory_separator(p.m_pathname[size])) ++ break; ++ } ++ } ++ ++ substring rel_path; ++ rel_path.pos = size; ++ rel_path.size = p.m_pathname.size() - size; ++ ++ return rel_path; ++} ++ ++BOOST_FILESYSTEM_DECL path_algorithms::string_type::size_type path_algorithms::find_parent_path_size(path const& p) ++{ ++ const size_type size = p.m_pathname.size(); ++ size_type root_name_size = 0; ++ size_type root_dir_pos = find_root_directory_start(p.m_pathname.c_str(), size, root_name_size); ++ ++ size_type filename_size = find_filename_size(p.m_pathname, root_name_size, size); ++ size_type end_pos = size - filename_size; ++ while (true) ++ { ++ if (end_pos <= root_name_size) ++ { ++ // Keep the root name as the parent path if there was a filename ++ if (filename_size == 0) ++ end_pos = 0u; ++ break; ++ } ++ ++ --end_pos; ++ ++ if (!detail::is_directory_separator(p.m_pathname[end_pos])) ++ { ++ ++end_pos; ++ break; ++ } ++ ++ if (end_pos == root_dir_pos) ++ { ++ // Keep the trailing root directory if there was a filename ++ end_pos += filename_size > 0; ++ break; ++ } ++ } ++ ++ return end_pos; ++} ++ ++BOOST_FILESYSTEM_DECL path path_algorithms::filename_v3(path const& p) ++{ ++ const size_type size = p.m_pathname.size(); ++ size_type root_name_size = 0; ++ size_type root_dir_pos = find_root_directory_start(p.m_pathname.c_str(), size, root_name_size); ++ size_type filename_size, pos; ++ if (root_dir_pos < size && detail::is_directory_separator(p.m_pathname[size - 1]) && is_root_separator(p.m_pathname, root_dir_pos, size - 1)) ++ { ++ // Return root directory ++ pos = root_dir_pos; ++ filename_size = 1u; ++ } ++ else if (root_name_size == size) ++ { ++ // Return root name ++ pos = 0u; ++ filename_size = root_name_size; ++ } ++ else ++ { ++ filename_size = find_filename_size(p.m_pathname, root_name_size, size); ++ pos = size - filename_size; ++ if (filename_size == 0u && pos > root_name_size && detail::is_directory_separator(p.m_pathname[pos - 1]) && !is_root_separator(p.m_pathname, root_dir_pos, pos - 1)) ++ return detail::dot_path(); ++ } ++ ++ const value_type* ptr = p.m_pathname.c_str() + pos; ++ return path(ptr, ptr + filename_size); ++} ++ ++BOOST_FILESYSTEM_DECL path_algorithms::string_type::size_type path_algorithms::find_filename_v4_size(path const& p) ++{ ++ const size_type size = p.m_pathname.size(); ++ size_type root_name_size = 0; ++ find_root_directory_start(p.m_pathname.c_str(), size, root_name_size); ++ return find_filename_size(p.m_pathname, root_name_size, size); ++} ++ ++BOOST_FILESYSTEM_DECL path path_algorithms::stem_v3(path const& p) ++{ ++ path name(path_algorithms::filename_v3(p)); ++ if (path_algorithms::compare_v4(name, detail::dot_path()) != 0 && path_algorithms::compare_v4(name, detail::dot_dot_path()) != 0) ++ { ++ size_type pos = name.m_pathname.rfind(path::dot); ++ if (pos != string_type::npos) ++ name.m_pathname.erase(name.m_pathname.begin() + pos, name.m_pathname.end()); ++ } ++ return name; ++} ++ ++BOOST_FILESYSTEM_DECL path path_algorithms::stem_v4(path const& p) ++{ ++ path name(path_algorithms::filename_v4(p)); ++ if (path_algorithms::compare_v4(name, detail::dot_path()) != 0 && path_algorithms::compare_v4(name, detail::dot_dot_path()) != 0) ++ { ++ size_type pos = name.m_pathname.rfind(path::dot); ++ if (pos != 0 && pos != string_type::npos) ++ name.m_pathname.erase(name.m_pathname.begin() + pos, name.m_pathname.end()); ++ } ++ return name; ++} ++ ++BOOST_FILESYSTEM_DECL path path_algorithms::extension_v3(path const& p) ++{ ++ path name(path_algorithms::filename_v3(p)); ++ if (path_algorithms::compare_v4(name, detail::dot_path()) == 0 || path_algorithms::compare_v4(name, detail::dot_dot_path()) == 0) ++ return path(); ++ size_type pos(name.m_pathname.rfind(path::dot)); ++ return pos == string_type::npos ? path() : path(name.m_pathname.c_str() + pos); ++} ++ ++BOOST_FILESYSTEM_DECL path_algorithms::string_type::size_type path_algorithms::find_extension_v4_size(path const& p) ++{ ++ const size_type size = p.m_pathname.size(); ++ size_type root_name_size = 0; ++ find_root_directory_start(p.m_pathname.c_str(), size, root_name_size); ++ size_type filename_size = find_filename_size(p.m_pathname, root_name_size, size); ++ size_type filename_pos = size - filename_size; ++ if ++ ( ++ filename_size > 0u && ++ // Check for "." and ".." filenames ++ !(p.m_pathname[filename_pos] == path::dot && ++ (filename_size == 1u || (filename_size == 2u && p.m_pathname[filename_pos + 1u] == path::dot))) ++ ) ++ { ++ size_type ext_pos = size; ++ while (ext_pos > filename_pos) ++ { ++ --ext_pos; ++ if (p.m_pathname[ext_pos] == path::dot) ++ break; ++ } ++ ++ if (ext_pos > filename_pos) ++ return size - ext_pos; ++ } ++ ++ return 0u; ++} ++ ++} // namespace detail ++ ++BOOST_FILESYSTEM_DECL path& path::remove_filename_and_trailing_separators() ++{ ++ size_type end_pos = detail::path_algorithms::find_parent_path_size(*this); ++ m_pathname.erase(m_pathname.begin() + end_pos, m_pathname.end()); ++ return *this; ++} ++ ++BOOST_FILESYSTEM_DECL path& path::remove_trailing_separator() ++{ ++ if (!m_pathname.empty() && detail::is_directory_separator(m_pathname[m_pathname.size() - 1])) ++ m_pathname.erase(m_pathname.end() - 1); ++ return *this; ++} ++ ++BOOST_FILESYSTEM_DECL path& path::replace_filename(path const& replacement) ++{ ++ detail::path_algorithms::remove_filename_v4(*this); ++ detail::path_algorithms::append_v4(*this, replacement.m_pathname.data(), replacement.m_pathname.data() + replacement.m_pathname.size()); ++ return *this; ++} ++ ++// lexical operations --------------------------------------------------------------// ++ ++BOOST_FILESYSTEM_DECL path path::lexically_relative(path const& base) const ++{ ++ path::iterator b = begin(), e = end(), base_b = base.begin(), base_e = base.end(); ++ std::pair< path::iterator, path::iterator > mm = detail::mismatch(b, e, base_b, base_e); ++ if (mm.first == b && mm.second == base_b) ++ return path(); ++ if (mm.first == e && mm.second == base_e) ++ return detail::dot_path(); ++ ++ std::ptrdiff_t n = 0; ++ for (; mm.second != base_e; detail::path_algorithms::increment_v4(mm.second)) ++ { ++ path const& p = *mm.second; ++ if (detail::path_algorithms::compare_v4(p, detail::dot_dot_path()) == 0) ++ --n; ++ else if (!p.empty() && detail::path_algorithms::compare_v4(p, detail::dot_path()) != 0) ++ ++n; ++ } ++ if (n < 0) ++ return path(); ++ if (n == 0 && (mm.first == e || mm.first->empty())) ++ return detail::dot_path(); ++ ++ path tmp; ++ for (; n > 0; --n) ++ detail::path_algorithms::append_v4(tmp, detail::dot_dot_path()); ++ for (; mm.first != e; detail::path_algorithms::increment_v4(mm.first)) ++ detail::path_algorithms::append_v4(tmp, *mm.first); ++ return tmp; ++} ++ ++#if defined(BOOST_WINDOWS_API) ++ ++BOOST_FILESYSTEM_DECL path path::generic_path() const ++{ ++ path tmp(*this); ++ std::replace(tmp.m_pathname.begin(), tmp.m_pathname.end(), L'\\', L'/'); ++ return tmp; ++} ++ ++BOOST_FILESYSTEM_DECL path& path::make_preferred() ++{ ++ std::replace(m_pathname.begin(), m_pathname.end(), L'/', L'\\'); ++ return *this; ++} ++ ++#endif // defined(BOOST_WINDOWS_API) ++ ++} // namespace filesystem ++} // namespace boost ++ ++//--------------------------------------------------------------------------------------// ++// // ++// class path helpers implementation // ++// // ++//--------------------------------------------------------------------------------------// ++ ++namespace { ++ ++// is_root_separator ---------------------------------------------------------------// ++ ++// pos is position of the separator ++inline bool is_root_separator(string_type const& str, size_type root_dir_pos, size_type pos) ++{ ++ BOOST_ASSERT_MSG(pos < str.size() && fs::detail::is_directory_separator(str[pos]), "precondition violation"); ++ ++ // root_dir_pos points at the leftmost separator, we need to skip any duplicate separators right of root dir ++ while (pos > root_dir_pos && fs::detail::is_directory_separator(str[pos - 1])) ++ --pos; ++ ++ return pos == root_dir_pos; ++} ++ ++// find_filename_size --------------------------------------------------------------// ++ ++// Returns: Size of the filename element that ends at end_pos (which is past-the-end position). 0 if no filename found. ++inline size_type find_filename_size(string_type const& str, size_type root_name_size, size_type end_pos) ++{ ++ size_type pos = end_pos; ++ while (pos > root_name_size) ++ { ++ --pos; ++ ++ if (fs::detail::is_directory_separator(str[pos])) ++ { ++ ++pos; // filename starts past the separator ++ break; ++ } ++ } ++ ++ return end_pos - pos; ++} ++ ++// find_root_directory_start -------------------------------------------------------// ++ ++// Returns: starting position of root directory or size if not found ++size_type find_root_directory_start(const value_type* path, size_type size, size_type& root_name_size) ++{ ++ root_name_size = 0; ++ if (size == 0) ++ return 0; ++ ++ bool parsing_root_name = false; ++ size_type pos = 0; ++ ++ // case "//", possibly followed by more characters ++ if (fs::detail::is_directory_separator(path[0])) ++ { ++ if (size >= 2 && fs::detail::is_directory_separator(path[1])) ++ { ++ if (size == 2) ++ { ++ // The whole path is just a pair of separators ++ root_name_size = 2; ++ return 2; ++ } ++#ifdef BOOST_WINDOWS_API ++ // https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file ++ // cases "\\?\" and "\\.\" ++ else if (size >= 4 && (path[2] == questionmark || path[2] == fs::path::dot) && fs::detail::is_directory_separator(path[3])) ++ { ++ parsing_root_name = true; ++ pos += 4; ++ } ++#endif ++ else if (fs::detail::is_directory_separator(path[2])) ++ { ++ // The path starts with three directory separators, which is interpreted as a root directory followed by redundant separators ++ return 0; ++ } ++ else ++ { ++ // case "//net {/}" ++ parsing_root_name = true; ++ pos += 2; ++ goto find_next_separator; ++ } ++ } ++#ifdef BOOST_WINDOWS_API ++ // https://stackoverflow.com/questions/23041983/path-prefixes-and ++ // case "\??\" (NT path prefix) ++ else if (size >= 4 && path[1] == questionmark && path[2] == questionmark && fs::detail::is_directory_separator(path[3])) ++ { ++ parsing_root_name = true; ++ pos += 4; ++ } ++#endif ++ else ++ { ++ // The path starts with a separator, possibly followed by a non-separator character ++ return 0; ++ } ++ } ++ ++#ifdef BOOST_WINDOWS_API ++ // case "c:" or "prn:" ++ // Note: There is ambiguity in a "c:x" path interpretation. It could either mean a file "x" located at the current directory for drive C:, ++ // or an alternative stream "x" of a file "c". Windows API resolve this as the former, and so do we. ++ if ((size - pos) >= 2 && fs::detail::is_letter(path[pos])) ++ { ++ size_type i = pos + 1; ++ for (; i < size; ++i) ++ { ++ if (!is_device_name_char(path[i])) ++ break; ++ } ++ ++ if (i < size && path[i] == colon) ++ { ++ pos = i + 1; ++ root_name_size = pos; ++ parsing_root_name = false; ++ ++ if (pos < size && fs::detail::is_directory_separator(path[pos])) ++ return pos; ++ } ++ } ++#endif ++ ++ if (!parsing_root_name) ++ return size; ++ ++find_next_separator: ++ pos += find_separator(path + pos, size - pos); ++ if (parsing_root_name) ++ root_name_size = pos; ++ ++ return pos; ++} ++ ++//--------------------------------------------------------------------------------------// ++// // ++// class path::iterator implementation // ++// // ++//--------------------------------------------------------------------------------------// ++ ++// first_element ----------------------------------------------------------------------// ++ ++// sets pos and len of first element, excluding extra separators ++// if src.empty(), sets pos,len, to 0,0. ++void first_element(string_type const& src, size_type& element_pos, size_type& element_size, size_type size) ++{ ++ element_pos = 0; ++ element_size = 0; ++ if (src.empty()) ++ return; ++ ++ size_type root_name_size = 0; ++ size_type root_dir_pos = find_root_directory_start(src.c_str(), size, root_name_size); ++ ++ // First element is the root name, if there is one ++ if (root_name_size > 0) ++ { ++ element_size = root_name_size; ++ return; ++ } ++ ++ // Otherwise, the root directory ++ if (root_dir_pos < size) ++ { ++ element_pos = root_dir_pos; ++ element_size = 1u; ++ return; ++ } ++ ++ // Otherwise, the first filename or directory name in a relative path ++ size_type end_pos = src.find_first_of(separators); ++ if (end_pos == string_type::npos) ++ end_pos = src.size(); ++ element_size = end_pos; ++} ++ ++} // unnamed namespace ++ ++namespace boost { ++namespace filesystem { ++namespace detail { ++ ++BOOST_FILESYSTEM_DECL void path_algorithms::increment_v3(path_detail::path_iterator& it) ++{ ++ const size_type size = it.m_path_ptr->m_pathname.size(); ++ BOOST_ASSERT_MSG(it.m_pos < size, "path::iterator increment past end()"); ++ ++ // increment to position past current element; if current element is implicit dot, ++ // this will cause m_pos to represent the end iterator ++ it.m_pos += it.m_element.m_pathname.size(); ++ ++ // if the end is reached, we are done ++ if (it.m_pos >= size) ++ { ++ BOOST_ASSERT_MSG(it.m_pos == size, "path::iterator increment after the referenced path was modified"); ++ it.m_element.clear(); // aids debugging ++ return; ++ } ++ ++ // process separator (Windows drive spec is only case not a separator) ++ if (detail::is_directory_separator(it.m_path_ptr->m_pathname[it.m_pos])) ++ { ++ size_type root_name_size = 0; ++ size_type root_dir_pos = find_root_directory_start(it.m_path_ptr->m_pathname.c_str(), size, root_name_size); ++ ++ // detect root directory and set iterator value to the separator if it is ++ if (it.m_pos == root_dir_pos && it.m_element.m_pathname.size() == root_name_size) ++ { ++ it.m_element.m_pathname = path::separator; // generic format; see docs ++ return; ++ } ++ ++ // skip separators until m_pos points to the start of the next element ++ while (it.m_pos != size && detail::is_directory_separator(it.m_path_ptr->m_pathname[it.m_pos])) ++ { ++ ++it.m_pos; ++ } ++ ++ // detect trailing separator, and treat it as ".", per POSIX spec ++ if (it.m_pos == size && ++ !is_root_separator(it.m_path_ptr->m_pathname, root_dir_pos, it.m_pos - 1)) ++ { ++ --it.m_pos; ++ it.m_element = detail::dot_path(); ++ return; ++ } ++ } ++ ++ // get m_element ++ size_type end_pos = it.m_path_ptr->m_pathname.find_first_of(separators, it.m_pos); ++ if (end_pos == string_type::npos) ++ end_pos = size; ++ const path::value_type* p = it.m_path_ptr->m_pathname.c_str(); ++ it.m_element.m_pathname.assign(p + it.m_pos, p + end_pos); ++} ++ ++BOOST_FILESYSTEM_DECL void path_algorithms::increment_v4(path_detail::path_iterator& it) ++{ ++ const size_type size = it.m_path_ptr->m_pathname.size(); ++ BOOST_ASSERT_MSG(it.m_pos <= size, "path::iterator increment past end()"); ++ ++ if (it.m_element.m_pathname.empty() && (it.m_pos + 1) == size && detail::is_directory_separator(it.m_path_ptr->m_pathname[it.m_pos])) ++ { ++ // The iterator was pointing to the last empty element of the path; set to end. ++ it.m_pos = size; ++ return; ++ } ++ ++ // increment to position past current element; if current element is implicit dot, ++ // this will cause m_pos to represent the end iterator ++ it.m_pos += it.m_element.m_pathname.size(); ++ ++ // if the end is reached, we are done ++ if (it.m_pos >= size) ++ { ++ BOOST_ASSERT_MSG(it.m_pos == size, "path::iterator increment after the referenced path was modified"); ++ it.m_element.clear(); // aids debugging ++ return; ++ } ++ ++ // process separator (Windows drive spec is only case not a separator) ++ if (detail::is_directory_separator(it.m_path_ptr->m_pathname[it.m_pos])) ++ { ++ size_type root_name_size = 0; ++ size_type root_dir_pos = find_root_directory_start(it.m_path_ptr->m_pathname.c_str(), size, root_name_size); ++ ++ // detect root directory and set iterator value to the separator if it is ++ if (it.m_pos == root_dir_pos && it.m_element.m_pathname.size() == root_name_size) ++ { ++ it.m_element.m_pathname = path::separator; // generic format; see docs ++ return; ++ } ++ ++ // skip separators until m_pos points to the start of the next element ++ while (it.m_pos != size && detail::is_directory_separator(it.m_path_ptr->m_pathname[it.m_pos])) ++ { ++ ++it.m_pos; ++ } ++ ++ // detect trailing separator ++ if (it.m_pos == size && ++ !is_root_separator(it.m_path_ptr->m_pathname, root_dir_pos, it.m_pos - 1)) ++ { ++ --it.m_pos; ++ it.m_element.m_pathname.clear(); ++ return; ++ } ++ } ++ ++ // get m_element ++ size_type end_pos = it.m_path_ptr->m_pathname.find_first_of(separators, it.m_pos); ++ if (end_pos == string_type::npos) ++ end_pos = size; ++ const path::value_type* p = it.m_path_ptr->m_pathname.c_str(); ++ it.m_element.m_pathname.assign(p + it.m_pos, p + end_pos); ++} ++ ++BOOST_FILESYSTEM_DECL void path_algorithms::decrement_v3(path_detail::path_iterator& it) ++{ ++ const size_type size = it.m_path_ptr->m_pathname.size(); ++ BOOST_ASSERT_MSG(it.m_pos > 0, "path::iterator decrement past begin()"); ++ BOOST_ASSERT_MSG(it.m_pos <= size, "path::iterator decrement after the referenced path was modified"); ++ ++ size_type root_name_size = 0; ++ size_type root_dir_pos = find_root_directory_start(it.m_path_ptr->m_pathname.c_str(), size, root_name_size); ++ ++ if (root_dir_pos < size && it.m_pos == root_dir_pos) ++ { ++ // Was pointing at root directory, decrement to root name ++ set_to_root_name: ++ it.m_pos = 0u; ++ const path::value_type* p = it.m_path_ptr->m_pathname.c_str(); ++ it.m_element.m_pathname.assign(p, p + root_name_size); ++ return; ++ } ++ ++ // if at end and there was a trailing non-root '/', return "." ++ if (it.m_pos == size && ++ size > 1 && ++ detail::is_directory_separator(it.m_path_ptr->m_pathname[it.m_pos - 1]) && ++ !is_root_separator(it.m_path_ptr->m_pathname, root_dir_pos, it.m_pos - 1)) ++ { ++ --it.m_pos; ++ it.m_element = detail::dot_path(); ++ return; ++ } ++ ++ // skip separators unless root directory ++ size_type end_pos = it.m_pos; ++ while (end_pos > root_name_size) ++ { ++ --end_pos; ++ ++ if (end_pos == root_dir_pos) ++ { ++ // Decremented to the root directory ++ it.m_pos = end_pos; ++ it.m_element.m_pathname = path::separator; // generic format; see docs ++ return; ++ } ++ ++ if (!detail::is_directory_separator(it.m_path_ptr->m_pathname[end_pos])) ++ { ++ ++end_pos; ++ break; ++ } ++ } ++ ++ if (end_pos <= root_name_size) ++ goto set_to_root_name; ++ ++ size_type filename_size = find_filename_size(it.m_path_ptr->m_pathname, root_name_size, end_pos); ++ it.m_pos = end_pos - filename_size; ++ const path::value_type* p = it.m_path_ptr->m_pathname.c_str(); ++ it.m_element.m_pathname.assign(p + it.m_pos, p + end_pos); ++} ++ ++BOOST_FILESYSTEM_DECL void path_algorithms::decrement_v4(path_detail::path_iterator& it) ++{ ++ const size_type size = it.m_path_ptr->m_pathname.size(); ++ BOOST_ASSERT_MSG(it.m_pos > 0, "path::iterator decrement past begin()"); ++ BOOST_ASSERT_MSG(it.m_pos <= size, "path::iterator decrement after the referenced path was modified"); ++ ++ size_type root_name_size = 0; ++ size_type root_dir_pos = find_root_directory_start(it.m_path_ptr->m_pathname.c_str(), size, root_name_size); ++ ++ if (root_dir_pos < size && it.m_pos == root_dir_pos) ++ { ++ // Was pointing at root directory, decrement to root name ++ set_to_root_name: ++ it.m_pos = 0u; ++ const path::value_type* p = it.m_path_ptr->m_pathname.c_str(); ++ it.m_element.m_pathname.assign(p, p + root_name_size); ++ return; ++ } ++ ++ // if at end and there was a trailing '/', return "" ++ if (it.m_pos == size && ++ size > 1 && ++ detail::is_directory_separator(it.m_path_ptr->m_pathname[it.m_pos - 1]) && ++ !is_root_separator(it.m_path_ptr->m_pathname, root_dir_pos, it.m_pos - 1)) ++ { ++ --it.m_pos; ++ it.m_element.m_pathname.clear(); ++ return; ++ } ++ ++ // skip separators unless root directory ++ size_type end_pos = it.m_pos; ++ while (end_pos > root_name_size) ++ { ++ --end_pos; ++ ++ if (end_pos == root_dir_pos) ++ { ++ // Decremented to the root directory ++ it.m_pos = end_pos; ++ it.m_element.m_pathname = path::separator; // generic format; see docs ++ return; ++ } ++ ++ if (!detail::is_directory_separator(it.m_path_ptr->m_pathname[end_pos])) ++ { ++ ++end_pos; ++ break; ++ } ++ } ++ ++ if (end_pos <= root_name_size) ++ goto set_to_root_name; ++ ++ size_type filename_size = find_filename_size(it.m_path_ptr->m_pathname, root_name_size, end_pos); ++ it.m_pos = end_pos - filename_size; ++ const path::value_type* p = it.m_path_ptr->m_pathname.c_str(); ++ it.m_element.m_pathname.assign(p + it.m_pos, p + end_pos); ++} ++ ++} // namespace detail ++ ++// path iterators ------------------------------------------------------------------// ++ ++BOOST_FILESYSTEM_DECL path::iterator path::begin() const ++{ ++ iterator itr; ++ itr.m_path_ptr = this; ++ ++ size_type element_size; ++ first_element(m_pathname, itr.m_pos, element_size); ++ ++ if (element_size > 0) ++ { ++ itr.m_element = m_pathname.substr(itr.m_pos, element_size); ++#ifdef BOOST_WINDOWS_API ++ if (itr.m_element.m_pathname.size() == 1u && itr.m_element.m_pathname[0] == path::preferred_separator) ++ itr.m_element.m_pathname[0] = path::separator; ++#endif ++ } ++ ++ return itr; ++} ++ ++BOOST_FILESYSTEM_DECL path::iterator path::end() const ++{ ++ iterator itr; ++ itr.m_path_ptr = this; ++ itr.m_pos = m_pathname.size(); ++ return itr; ++} ++ ++} // namespace filesystem ++} // namespace boost ++ ++namespace { ++ ++//------------------------------------------------------------------------------------// ++// locale helpers // ++//------------------------------------------------------------------------------------// ++ ++// Prior versions of these locale and codecvt implementations tried to take advantage ++// of static initialization where possible, kept a local copy of the current codecvt ++// facet (to avoid codecvt() having to call use_facet()), and was not multi-threading ++// safe (again for efficiency). ++// ++// This was error prone, and required different implementation techniques depending ++// on the compiler and also whether static or dynamic linking was used. Furthermore, ++// users could not easily provide their multi-threading safe wrappers because the ++// path interface requires the implementation itself to call codecvt() to obtain the ++// default facet, and the initialization of the static within path_locale() could race. ++// ++// The code below is portable to all platforms, is much simpler, and hopefully will be ++// much more robust. Timing tests (on Windows, using a Visual C++ release build) ++// indicated the current code is roughly 9% slower than the previous code, and that ++// seems a small price to pay for better code that is easier to use. ++ ++std::locale default_locale() ++{ ++#if defined(BOOST_WINDOWS_API) ++ std::locale global_loc = std::locale(); ++ return std::locale(global_loc, new boost::filesystem::detail::windows_file_codecvt()); ++#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__) ++ // "All BSD system functions expect their string parameters to be in UTF-8 encoding ++ // and nothing else." See ++ // http://developer.apple.com/mac/library/documentation/MacOSX/Conceptual/BPInternational/Articles/FileEncodings.html ++ // ++ // "The kernel will reject any filename that is not a valid UTF-8 string, and it will ++ // even be normalized (to Unicode NFD) before stored on disk, at least when using HFS. ++ // The right way to deal with it would be to always convert the filename to UTF-8 ++ // before trying to open/create a file." See ++ // http://lists.apple.com/archives/unix-porting/2007/Sep/msg00023.html ++ // ++ // "How a file name looks at the API level depends on the API. Current Carbon APIs ++ // handle file names as an array of UTF-16 characters; POSIX ones handle them as an ++ // array of UTF-8, which is why UTF-8 works well in Terminal. How it's stored on disk ++ // depends on the disk format; HFS+ uses UTF-16, but that's not important in most ++ // cases." See ++ // http://lists.apple.com/archives/applescript-users/2002/Sep/msg00319.html ++ // ++ // Many thanks to Peter Dimov for digging out the above references! ++ ++ std::locale global_loc = std::locale(); ++ return std::locale(global_loc, new boost::filesystem::detail::utf8_codecvt_facet()); ++#else // Other POSIX ++ // ISO C calls std::locale("") "the locale-specific native environment", and this ++ // locale is the default for many POSIX-based operating systems such as Linux. ++ return std::locale(""); ++#endif ++} ++ ++std::locale* g_path_locale = NULL; ++ ++void schedule_path_locale_cleanup() BOOST_NOEXCEPT; ++ ++// std::locale("") construction, needed on non-Apple POSIX systems, can throw ++// (if environmental variables LC_MESSAGES or LANG are wrong, for example), so ++// get_path_locale() provides lazy initialization to ensure that any ++// exceptions occur after main() starts and so can be caught. Furthermore, ++// g_path_locale is only initialized if path::codecvt() or path::imbue() are themselves ++// actually called, ensuring that an exception will only be thrown if std::locale("") ++// is really needed. ++inline std::locale& get_path_locale() ++{ ++#if !defined(BOOST_FILESYSTEM_SINGLE_THREADED) ++ atomic_ns::atomic_ref< std::locale* > a(g_path_locale); ++ std::locale* p = a.load(atomic_ns::memory_order_acquire); ++ if (BOOST_UNLIKELY(!p)) ++ { ++ std::locale* new_p = new std::locale(default_locale()); ++ if (a.compare_exchange_strong(p, new_p, atomic_ns::memory_order_acq_rel, atomic_ns::memory_order_acquire)) ++ { ++ p = new_p; ++ schedule_path_locale_cleanup(); ++ } ++ else ++ { ++ delete new_p; ++ } ++ } ++ return *p; ++#else // !defined(BOOST_FILESYSTEM_SINGLE_THREADED) ++ std::locale* p = g_path_locale; ++ if (BOOST_UNLIKELY(!p)) ++ { ++ g_path_locale = p = new std::locale(default_locale()); ++ schedule_path_locale_cleanup(); ++ } ++ return *p; ++#endif // !defined(BOOST_FILESYSTEM_SINGLE_THREADED) ++} ++ ++inline std::locale* replace_path_locale(std::locale const& loc) ++{ ++ std::locale* new_p = new std::locale(loc); ++#if !defined(BOOST_FILESYSTEM_SINGLE_THREADED) ++ std::locale* p = atomic_ns::atomic_ref< std::locale* >(g_path_locale).exchange(new_p, atomic_ns::memory_order_acq_rel); ++#else ++ std::locale* p = g_path_locale; ++ g_path_locale = new_p; ++#endif ++ if (!p) ++ schedule_path_locale_cleanup(); ++ return p; ++} ++ ++#if defined(_MSC_VER) ++ ++const boost::filesystem::path* g_dot_path = NULL; ++const boost::filesystem::path* g_dot_dot_path = NULL; ++ ++inline void schedule_path_locale_cleanup() BOOST_NOEXCEPT ++{ ++} ++ ++inline boost::filesystem::path const& get_dot_path() ++{ ++#if !defined(BOOST_FILESYSTEM_SINGLE_THREADED) ++ atomic_ns::atomic_ref< const boost::filesystem::path* > a(g_dot_path); ++ const boost::filesystem::path* p = a.load(atomic_ns::memory_order_acquire); ++ if (BOOST_UNLIKELY(!p)) ++ { ++ const boost::filesystem::path* new_p = new boost::filesystem::path(dot_path_literal); ++ if (a.compare_exchange_strong(p, new_p, atomic_ns::memory_order_acq_rel, atomic_ns::memory_order_acquire)) ++ p = new_p; ++ else ++ delete new_p; ++ } ++ return *p; ++#else // !defined(BOOST_FILESYSTEM_SINGLE_THREADED) ++ const boost::filesystem::path* p = g_dot_path; ++ if (BOOST_UNLIKELY(!p)) ++ g_dot_path = p = new boost::filesystem::path(dot_path_literal); ++ return *p; ++#endif // !defined(BOOST_FILESYSTEM_SINGLE_THREADED) ++} ++ ++inline boost::filesystem::path const& get_dot_dot_path() ++{ ++#if !defined(BOOST_FILESYSTEM_SINGLE_THREADED) ++ atomic_ns::atomic_ref< const boost::filesystem::path* > a(g_dot_dot_path); ++ const boost::filesystem::path* p = a.load(atomic_ns::memory_order_acquire); ++ if (BOOST_UNLIKELY(!p)) ++ { ++ const boost::filesystem::path* new_p = new boost::filesystem::path(dot_dot_path_literal); ++ if (a.compare_exchange_strong(p, new_p, atomic_ns::memory_order_acq_rel, atomic_ns::memory_order_acquire)) ++ p = new_p; ++ else ++ delete new_p; ++ } ++ return *p; ++#else // !defined(BOOST_FILESYSTEM_SINGLE_THREADED) ++ const boost::filesystem::path* p = g_dot_dot_path; ++ if (BOOST_UNLIKELY(!p)) ++ g_dot_dot_path = p = new boost::filesystem::path(dot_dot_path_literal); ++ return *p; ++#endif // !defined(BOOST_FILESYSTEM_SINGLE_THREADED) ++} ++ ++void __cdecl destroy_path_globals() ++{ ++ delete g_dot_dot_path; ++ g_dot_dot_path = NULL; ++ delete g_dot_path; ++ g_dot_path = NULL; ++ delete g_path_locale; ++ g_path_locale = NULL; ++} ++ ++BOOST_FILESYSTEM_INIT_FUNC init_path_globals() ++{ ++#if !defined(BOOST_SYSTEM_HAS_CONSTEXPR) ++ // codecvt_error_category needs to be called early to dynamic-initialize the error category instance ++ boost::filesystem::codecvt_error_category(); ++#endif ++ std::atexit(&destroy_path_globals); ++ return BOOST_FILESYSTEM_INITRETSUCCESS_V; ++} ++ ++#if _MSC_VER >= 1400 ++ ++#pragma section(".CRT$XCM", long, read) ++__declspec(allocate(".CRT$XCM")) BOOST_ATTRIBUTE_UNUSED BOOST_FILESYSTEM_ATTRIBUTE_RETAIN ++extern const init_func_ptr_t p_init_path_globals = &init_path_globals; ++ ++#else // _MSC_VER >= 1400 ++ ++#if (_MSC_VER >= 1300) // 1300 == VC++ 7.0 ++#pragma data_seg(push, old_seg) ++#endif ++#pragma data_seg(".CRT$XCM") ++BOOST_ATTRIBUTE_UNUSED BOOST_FILESYSTEM_ATTRIBUTE_RETAIN ++extern const init_func_ptr_t p_init_path_globals = &init_path_globals; ++#pragma data_seg() ++#if (_MSC_VER >= 1300) // 1300 == VC++ 7.0 ++#pragma data_seg(pop, old_seg) ++#endif ++ ++#endif // _MSC_VER >= 1400 ++ ++#if defined(BOOST_FILESYSTEM_NO_ATTRIBUTE_RETAIN) ++//! Makes sure the global initializer pointers are referenced and not removed by linker ++struct globals_retainer ++{ ++ const init_func_ptr_t* volatile m_p_init_path_globals; ++ ++ globals_retainer() { m_p_init_path_globals = &p_init_path_globals; } ++}; ++BOOST_ATTRIBUTE_UNUSED ++static const globals_retainer g_globals_retainer; ++#endif // defined(BOOST_FILESYSTEM_NO_ATTRIBUTE_RETAIN) ++ ++#else // defined(_MSC_VER) ++ ++struct path_locale_deleter ++{ ++ ~path_locale_deleter() ++ { ++ delete g_path_locale; ++ g_path_locale = NULL; ++ } ++}; ++ ++#if defined(BOOST_FILESYSTEM_HAS_INIT_PRIORITY) ++ ++BOOST_FILESYSTEM_INIT_PRIORITY(BOOST_FILESYSTEM_PATH_GLOBALS_INIT_PRIORITY) BOOST_ATTRIBUTE_UNUSED ++const path_locale_deleter g_path_locale_deleter = {}; ++BOOST_FILESYSTEM_INIT_PRIORITY(BOOST_FILESYSTEM_PATH_GLOBALS_INIT_PRIORITY) ++const boost::filesystem::path g_dot_path(dot_path_literal); ++BOOST_FILESYSTEM_INIT_PRIORITY(BOOST_FILESYSTEM_PATH_GLOBALS_INIT_PRIORITY) ++const boost::filesystem::path g_dot_dot_path(dot_dot_path_literal); ++ ++inline void schedule_path_locale_cleanup() BOOST_NOEXCEPT ++{ ++} ++ ++inline boost::filesystem::path const& get_dot_path() ++{ ++ return g_dot_path; ++} ++ ++inline boost::filesystem::path const& get_dot_dot_path() ++{ ++ return g_dot_dot_path; ++} ++ ++#else // defined(BOOST_FILESYSTEM_HAS_INIT_PRIORITY) ++ ++inline void schedule_path_locale_cleanup() BOOST_NOEXCEPT ++{ ++ BOOST_ATTRIBUTE_UNUSED static const path_locale_deleter g_path_locale_deleter; ++} ++ ++inline boost::filesystem::path const& get_dot_path() ++{ ++ static const boost::filesystem::path g_dot_path(dot_path_literal); ++ return g_dot_path; ++} ++ ++inline boost::filesystem::path const& get_dot_dot_path() ++{ ++ static const boost::filesystem::path g_dot_dot_path(dot_dot_path_literal); ++ return g_dot_dot_path; ++} ++ ++#endif // defined(BOOST_FILESYSTEM_HAS_INIT_PRIORITY) ++ ++#endif // defined(_MSC_VER) ++ ++} // unnamed namespace ++ ++//--------------------------------------------------------------------------------------// ++// path::codecvt() and path::imbue() implementation // ++//--------------------------------------------------------------------------------------// ++ ++namespace boost { ++namespace filesystem { ++ ++BOOST_FILESYSTEM_DECL path::codecvt_type const& path::codecvt() ++{ ++#ifdef BOOST_FILESYSTEM_DEBUG ++ std::cout << "***** path::codecvt() called" << std::endl; ++#endif ++ return std::use_facet< std::codecvt< wchar_t, char, std::mbstate_t > >(get_path_locale()); ++} ++ ++BOOST_FILESYSTEM_DECL std::locale path::imbue(std::locale const& loc) ++{ ++#ifdef BOOST_FILESYSTEM_DEBUG ++ std::cout << "***** path::imbue() called" << std::endl; ++#endif ++ std::locale* p = replace_path_locale(loc); ++ if (BOOST_LIKELY(p != NULL)) ++ { ++ // Note: copying/moving std::locale does not throw ++#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) ++ std::locale temp(std::move(*p)); ++#else ++ std::locale temp(*p); ++#endif ++ delete p; ++ return temp; ++ } ++ ++ return default_locale(); ++} ++ ++namespace detail { ++ ++BOOST_FILESYSTEM_DECL path const& dot_path() ++{ ++ return get_dot_path(); ++} ++ ++BOOST_FILESYSTEM_DECL path const& dot_dot_path() ++{ ++ return get_dot_dot_path(); ++} ++ ++} // namespace detail ++} // namespace filesystem ++} // namespace boost ++ ++#include +diff -urN boost_1_83_0.orig/tools/build/src/tools/common.jam boost_1_83_0/tools/build/src/tools/common.jam +--- boost_1_83_0.orig/tools/build/src/tools/common.jam 2023-08-08 16:02:57.000000000 -0500 ++++ boost_1_83_0/tools/build/src/tools/common.jam 2023-12-20 19:37:21.249966924 -0600 +@@ -981,7 +981,7 @@ + } + + # Ditto, from Clang 4 +- if ( $(tag) = clang || $(tag) = clangw ) && $(version[1]) && [ numbers.less 3 $(version[1]) ] ++ #if( $(tag) = clang || $(tag) = clangw ) && $(version[1]) && [ numbers.less 3 $(version[1]) ] + { + version = $(version[1]) ; + }