Compare commits

..

No commits in common. "master" and "v1.5.12" have entirely different histories.

14 changed files with 358 additions and 578 deletions

View File

@ -1,6 +1,6 @@
freebsd_task: freebsd_task:
freebsd_instance: freebsd_instance:
image_family: freebsd-14-0 image_family: freebsd-12-1
install_script: | install_script: |
pkg install -y cmake pkg install -y cmake
pw groupadd testgrp pw groupadd testgrp
@ -11,24 +11,25 @@ freebsd_task:
test_script: | test_script: |
sudo -u testuser .ci/unix-test.sh sudo -u testuser .ci/unix-test.sh
rockylinux8_task: centos7_task:
container: container:
image: docker.io/rockylinux:8 image: centos:7
install_script: | install_script: |
dnf group install -y "Development Tools" yum install -y centos-release-scl
dnf install cmake -y yum install -y devtoolset-9
curl -L https://github.com/Kitware/CMake/releases/download/v3.16.4/cmake-3.16.4-Linux-x86_64.tar.gz | tar xzvf - -C /usr/local --strip-components 1
build_script: | build_script: |
.ci/unix-build.sh source /opt/rh/devtoolset-9/enable && PATH=$PATH:/usr/local/bin .ci/unix-build.sh
test_script: | test_script: |
.ci/unix-test.sh PATH=$PATH:/usr/local/bin .ci/unix-test.sh
rockylinux9_task: centos8_task:
container: container:
image: docker.io/rockylinux:9 image: quay.io/centos/centos:stream8
install_script: | install_script: |
dnf group install -y "Development Tools" yum group install -y "Development Tools"
dnf install cmake -y curl -L https://github.com/Kitware/CMake/releases/download/v3.16.4/cmake-3.16.4-Linux-x86_64.tar.gz | tar xzvf - -C /usr/local --strip-components 1
build_script: | build_script: |
.ci/unix-build.sh PATH=$PATH:/usr/local/bin .ci/unix-build.sh
test_script: | test_script: |
.ci/unix-test.sh PATH=$PATH:/usr/local/bin .ci/unix-test.sh

View File

@ -10,42 +10,6 @@ jobs:
fail-fast: false fail-fast: false
matrix: matrix:
config: config:
- name: "Ubuntu 22.04 GCC 11"
os: ubuntu-22.04
build_type: Release
packages: ninja-build
generator: Ninja
compatibility: "cxx_std_11;cxx_std_17;cxx_std_20"
cc: gcc
cxx: g++
- name: "Ubuntu 22.04 Clang 13.0"
os: ubuntu-22.04
build_type: Release
packages: ninja-build libc++-13-dev libc++abi-13-dev
generator: Ninja
compatibility: "cxx_std_11;cxx_std_17;cxx_std_20"
cc: clang-13
cxx: clang++-13
- name: "Ubuntu 22.04 Clang 15.0"
os: ubuntu-22.04
build_type: Release
packages: ninja-build libc++-15-dev libc++abi-15-dev
generator: Ninja
compatibility: "cxx_std_11;cxx_std_17;cxx_std_20"
cc: clang-15
cxx: clang++-15
- name: "Ubuntu 22.04 GCC 11 coverage"
os: ubuntu-22.04
build_type: Debug
packages: ninja-build lcov
generator: Ninja
compatibility: "cxx_std_11;cxx_std_17;cxx_std_20"
cc: gcc
cxx: g++
- name: "Ubuntu 20.04 GCC 9.3" - name: "Ubuntu 20.04 GCC 9.3"
os: ubuntu-20.04 os: ubuntu-20.04
build_type: Release build_type: Release
@ -82,6 +46,69 @@ jobs:
cc: gcc cc: gcc
cxx: g++ cxx: g++
- name: "Ubuntu 18.04 GCC 8.4"
os: ubuntu-18.04
build_type: Release
packages: ninja-build gcc-8 g++-8
generator: Ninja
compatibility: "cxx_std_11;cxx_std_17"
cc: gcc-8
cxx: g++-8
- name: "Ubuntu 18.04 GCC 7.5"
os: ubuntu-18.04
build_type: Release
packages: ninja-build
generator: Ninja
compatibility: "cxx_std_11;cxx_std_17"
cc: gcc-7
cxx: g++-7
- name: "Ubuntu 18.04 GCC 6.5"
os: ubuntu-18.04
build_type: Release
packages: ninja-build gcc-6 g++-6
generator: Ninja
compatibility: "cxx_std_11;cxx_std_17"
cc: gcc-6
cxx: g++-6
- name: "Ubuntu 18.04 GCC 5.5"
os: ubuntu-18.04
build_type: Release
packages: ninja-build gcc-5 g++-5
generator: Ninja
compatibility: "cxx_std_11;cxx_std_17"
cc: gcc-5
cxx: g++-5
- name: "Ubuntu 18.04 Clang 9.0"
os: ubuntu-18.04
build_type: Release
packages: ninja-build libc++-9-dev libc++abi-9-dev
generator: Ninja
compatibility: "cxx_std_11;cxx_std_17;cxx_std_20"
cc: clang
cxx: clang++
- name: "Ubuntu 18.04 Clang 6.0"
os: ubuntu-18.04
build_type: Release
packages: ninja-build clang-6.0
generator: Ninja
compatibility: "cxx_std_11;cxx_std_17"
cc: clang-6.0
cxx: clang++-6.0
- name: "Ubuntu 18.04 Clang 5.0"
os: ubuntu-18.04
build_type: Release
packages: ninja-build clang-5.0
generator: Ninja
compatibility: "cxx_std_11;cxx_std_17"
cc: clang-5.0
cxx: clang++-5.0
- name: "Windows MSVC 2019" - name: "Windows MSVC 2019"
os: windows-2019 os: windows-2019
build_type: Release build_type: Release
@ -91,12 +118,21 @@ jobs:
cc: cl cc: cl
cxx: cl cxx: cl
- name: "macOS 13 AppleClang" - name: "macOS 10.15 AppleClang"
os: macos-13 os: macos-10.15
build_type: Release build_type: Release
packages: ninja packages: ninja
generator: Ninja generator: Ninja
compatibility: "cxx_std_11;cxx_std_17;cxx_std_20" compatibility: "cxx_std_11;cxx_std_17"
cc: clang
cxx: clang++
- name: "macOS 11.6 AppleClang"
os: macos-11
build_type: Release
packages: ninja
generator: Ninja
compatibility: "cxx_std_11;cxx_std_17"
cc: clang cc: clang
cxx: clang++ cxx: clang++

View File

@ -1,8 +1,5 @@
cmake_minimum_required(VERSION 3.7.2) cmake_minimum_required(VERSION 3.7.2)
project( project(ghcfilesystem)
ghcfilesystem,
VERSION 1.5.15
)
if (POLICY CMP0077) if (POLICY CMP0077)
cmake_policy(SET CMP0077 NEW) cmake_policy(SET CMP0077 NEW)
@ -18,7 +15,7 @@ if(CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR)
else() else()
option(GHC_FILESYSTEM_BUILD_EXAMPLES "Build examples" OFF) option(GHC_FILESYSTEM_BUILD_EXAMPLES "Build examples" OFF)
option(GHC_FILESYSTEM_BUILD_TESTING "Enable tests" OFF) option(GHC_FILESYSTEM_BUILD_TESTING "Enable tests" OFF)
option(GHC_FILESYSTEM_WITH_INSTALL "With install target" OFF) option(GHC_FILESYSTEM_WITH_INSTALL "With install target" ON)
endif() endif()
option(GHC_FILESYSTEM_BUILD_STD_TESTING "Enable STD tests" ${GHC_FILESYSTEM_BUILD_TESTING}) option(GHC_FILESYSTEM_BUILD_STD_TESTING "Enable STD tests" ${GHC_FILESYSTEM_BUILD_TESTING})
if(NOT DEFINED GHC_FILESYSTEM_TEST_COMPILE_FEATURES) if(NOT DEFINED GHC_FILESYSTEM_TEST_COMPILE_FEATURES)
@ -35,14 +32,11 @@ endif()
if(CMAKE_CXX_STANDARD LESS 11) if(CMAKE_CXX_STANDARD LESS 11)
message(FATAL_ERROR "CMAKE_CXX_STANDARD is less than 11, ghc::filesystem only works with C++11 and above.") message(FATAL_ERROR "CMAKE_CXX_STANDARD is less than 11, ghc::filesystem only works with C++11 and above.")
endif() endif()
if(CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR) message(STATUS "System name: ${CMAKE_SYSTEM_NAME}")
message(STATUS "System name: ${CMAKE_SYSTEM_NAME}") message(STATUS "Compiler ID: ${CMAKE_CXX_COMPILER_ID}")
message(STATUS "Compiler ID: ${CMAKE_CXX_COMPILER_ID}") message(STATUS "CMAKE_CXX_COMPILE_FEATURES: ${CMAKE_CXX_COMPILE_FEATURES}")
message(STATUS "CMAKE_CXX_COMPILE_FEATURES: ${CMAKE_CXX_COMPILE_FEATURES}")
endif()
add_library(ghc_filesystem INTERFACE) add_library(ghc_filesystem INTERFACE)
add_library(ghcFilesystem::ghc_filesystem ALIAS ghc_filesystem)
target_include_directories(ghc_filesystem INTERFACE target_include_directories(ghc_filesystem INTERFACE
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>) $<INSTALL_INTERFACE:include>)
@ -76,15 +70,7 @@ if(GHC_FILESYSTEM_WITH_INSTALL)
"${PROJECT_BINARY_DIR}/cmake/ghc_filesystem-config.cmake" "${PROJECT_BINARY_DIR}/cmake/ghc_filesystem-config.cmake"
INSTALL_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/ghc_filesystem" INSTALL_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/ghc_filesystem"
PATH_VARS CMAKE_INSTALL_INCLUDEDIR) PATH_VARS CMAKE_INSTALL_INCLUDEDIR)
write_basic_package_version_file( install(FILES "${PROJECT_BINARY_DIR}/cmake/ghc_filesystem-config.cmake"
"${PROJECT_BINARY_DIR}/cmake/ghc_filesystem-config-version.cmake" DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/ghc_filesystem")
VERSION ${PROJECT_VERSION} add_library(ghcFilesystem::ghc_filesystem ALIAS ghc_filesystem)
COMPATIBILITY SameMinorVersion
)
install(
FILES
"${PROJECT_BINARY_DIR}/cmake/ghc_filesystem-config.cmake"
"${PROJECT_BINARY_DIR}/cmake/ghc_filesystem-config-version.cmake"
DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/ghc_filesystem"
)
endif() endif()

333
README.md
View File

@ -3,40 +3,37 @@
[![CMake Build Matrix](https://github.com/gulrak/filesystem/actions/workflows/build_cmake.yml/badge.svg?branch=master)](https://github.com/gulrak/filesystem/actions/workflows/build_cmake.yml) [![CMake Build Matrix](https://github.com/gulrak/filesystem/actions/workflows/build_cmake.yml/badge.svg?branch=master)](https://github.com/gulrak/filesystem/actions/workflows/build_cmake.yml)
[![Build Status](https://ci.appveyor.com/api/projects/status/t07wp3k2cddo0hpo/branch/master?svg=true)](https://ci.appveyor.com/project/gulrak/filesystem) [![Build Status](https://ci.appveyor.com/api/projects/status/t07wp3k2cddo0hpo/branch/master?svg=true)](https://ci.appveyor.com/project/gulrak/filesystem)
[![Build Status](https://api.cirrus-ci.com/github/gulrak/filesystem.svg?branch=master)](https://cirrus-ci.com/github/gulrak/filesystem) [![Build Status](https://api.cirrus-ci.com/github/gulrak/filesystem.svg?branch=master)](https://cirrus-ci.com/github/gulrak/filesystem)
[![Build Status](https://cloud.drone.io/api/badges/gulrak/filesystem/status.svg?ref=refs/heads/master)](https://cloud.drone.io/gulrak/filesystem)
[![Coverage Status](https://coveralls.io/repos/github/gulrak/filesystem/badge.svg?branch=master)](https://coveralls.io/github/gulrak/filesystem?branch=master) [![Coverage Status](https://coveralls.io/repos/github/gulrak/filesystem/badge.svg?branch=master)](https://coveralls.io/github/gulrak/filesystem?branch=master)
[![Latest Release Tag](https://img.shields.io/github/tag/gulrak/filesystem.svg)](https://github.com/gulrak/filesystem/tree/v1.5.14) [![Latest Release Tag](https://img.shields.io/github/tag/gulrak/filesystem.svg)](https://github.com/gulrak/filesystem/tree/v1.5.12)
<!-- [![Build Status](https://cloud.drone.io/api/badges/gulrak/filesystem/status.svg?ref=refs/heads/master)](https://cloud.drone.io/gulrak/filesystem) -->
<!-- TOC -->
* [Filesystem](#filesystem)
* [Motivation](#motivation)
* [Why the namespace GHC?](#why-the-namespace-ghc)
* [Platforms](#platforms)
* [Tests](#tests)
* [Usage](#usage)
* [Downloads](#downloads)
* [Using it as Single-File-Header](#using-it-as-single-file-header)
* [Using it as Forwarding-/Implementation-Header](#using-it-as-forwarding-implementation-header)
* [Git Submodule and CMake](#git-submodule-and-cmake)
* [Versioning](#versioning)
* [Documentation](#documentation)
* [`ghc::filesystem::ifstream`, `ghc::filesystem::ofstream`, `ghc::filesystem::fstream`](#ghcfilesystemifstream--ghcfilesystemofstream--ghcfilesystemfstream)
* [`ghc::filesystem::u8arguments`](#ghcfilesystemu8arguments)
* [Differences](#differences)
* [LWG Defects](#lwg-defects)
* [Not Implemented on C++ before C++17](#not-implemented-on-c-before-c17)
* [Differences in API](#differences-in-api)
* [Differences of Specific Interfaces](#differences-of-specific-interfaces)
* [Differences in Behavior](#differences-in-behavior)
* [fs.path (ref)](#fspath--ref-)
* [Open Issues](#open-issues)
* [Windows](#windows)
* [Symbolic Links on Windows](#symbolic-links-on-windows)
* [Permissions](#permissions)
* [Release Notes](#release-notes)
<!-- TOC -->
- [Filesystem](#filesystem)
- [Motivation](#motivation)
- [Why the namespace GHC?](#why-the-namespace-ghc)
- [Platforms](#platforms)
- [Tests](#tests)
- [Usage](#usage)
- [Downloads](#downloads)
- [Using it as Single-File-Header](#using-it-as-single-file-header)
- [Using it as Forwarding-/Implementation-Header](#using-it-as-forwarding-implementation-header)
- [Git Submodule and CMake](#git-submodule-and-cmake)
- [Versioning](#versioning)
- [Documentation](#documentation)
- [`ghc::filesystem::ifstream`, `ghc::filesystem::ofstream`, `ghc::filesystem::fstream`](#ghcfilesystemifstream-ghcfilesystemofstream-ghcfilesystemfstream)
- [`ghc::filesystem::u8arguments`](#ghcfilesystemu8arguments)
- [Differences](#differences)
- [LWG Defects](#lwg-defects)
- [Not Implemented on C++ before C++17](#not-implemented-on-c-before-c17)
- [Differences in API](#differences-in-api)
- [Differences of Specific Interfaces](#differences-of-specific-interfaces)
- [Differences in Behavior](#differences-in-behavior)
- [fs.path](#fspath-refhttpsencppreferencecomwcppfilesystempath)
- [Open Issues](#open-issues)
- [Windows](#windows)
- [Symbolic Links on Windows](#symbolic-links-on-windows)
- [Permissions](#permissions)
- [Release Notes](#release-notes)
# Filesystem # Filesystem
This is a header-only single-file `std::filesystem` compatible helper library, This is a header-only single-file `std::filesystem` compatible helper library,
@ -46,9 +43,8 @@ macOS 10.12/10.14/10.15/11.6, Windows 10, Ubuntu 18.04, Ubuntu 20.04, CentOS 7,
Alpine ARM/ARM64 Linux and Solaris 10 but should work on other systems too, as long as you have Alpine ARM/ARM64 Linux and Solaris 10 but should work on other systems too, as long as you have
at least a C++11 compatible compiler. It should work with Android NDK, Emscripten and I even at least a C++11 compatible compiler. It should work with Android NDK, Emscripten and I even
had reports of it being used on iOS (within sandboxing constraints) and with v1.5.6 there had reports of it being used on iOS (within sandboxing constraints) and with v1.5.6 there
is experimental support for QNX. The support of Android NDK, Emscripten, QNX, and since 1.5.14 is experimental support for QNX. The support of Android NDK, Emscripten and QNX is not
GNU/Hurd and Haiku is not backed up by automated testing but PRs and bug reports are welcome backed up by automated testing but PRs and bug reports are welcome for those too.
for those too and they are reported to work.
It is of course in its own namespace `ghc::filesystem` to not interfere with a regular `std::filesystem` It is of course in its own namespace `ghc::filesystem` to not interfere with a regular `std::filesystem`
should you use it in a mixed C++17 environment (which is possible). should you use it in a mixed C++17 environment (which is possible).
@ -111,8 +107,7 @@ Unit tests are currently run with:
* macOS 10.12: Xcode 9.2 (clang-900.0.39.2), GCC 9.2, Clang 9.0, macOS 10.13: Xcode 10.1, macOS 10.14: Xcode 11.2, macOS 10.15: Xcode 11.6, Xcode 12.4 * macOS 10.12: Xcode 9.2 (clang-900.0.39.2), GCC 9.2, Clang 9.0, macOS 10.13: Xcode 10.1, macOS 10.14: Xcode 11.2, macOS 10.15: Xcode 11.6, Xcode 12.4
* Windows: Visual Studio 2017, Visual Studio 2015, Visual Studio 2019, MinGW GCC 6.3 (Win32), GCC 7.2 (Win64), Cygwin GCC 10.2 (no CI yet) * Windows: Visual Studio 2017, Visual Studio 2015, Visual Studio 2019, MinGW GCC 6.3 (Win32), GCC 7.2 (Win64), Cygwin GCC 10.2 (no CI yet)
* Linux (Ubuntu): GCC (5.5, 6.5, 7.4, 8.3, 9.2), Clang (5.0, 6.0, 7.1, 8.0, 9.0) * Linux (Ubuntu): GCC (5.5, 6.5, 7.4, 8.3, 9.2), Clang (5.0, 6.0, 7.1, 8.0, 9.0)
* ~~Linux (Alpine ARM/ARM64): GCC 9.2.0~~ (The Drone build scripts stopped working, * Linux (Alpine ARM/ARM64): GCC 9.2.0
as they where a contribution, I couldn't figure out what went wrong, any help appreciated.)
* FreeBSD: Clang 8.0 * FreeBSD: Clang 8.0
* Solaris: GCC 5.5 * Solaris: GCC 5.5
@ -154,8 +149,8 @@ in the standard, and there might be issues in these implementations too.
### Downloads ### Downloads
The latest release version is [v1.5.14](https://github.com/gulrak/filesystem/tree/v1.5.14) and The latest release version is [v1.5.12](https://github.com/gulrak/filesystem/tree/v1.5.12) and
source archives can be found [here](https://github.com/gulrak/filesystem/releases/tag/v1.5.14). source archives can be found [here](https://github.com/gulrak/filesystem/releases/tag/v1.5.12).
The latest pre-native-backend version is [v1.4.0](https://github.com/gulrak/filesystem/tree/v1.4.0) and The latest pre-native-backend version is [v1.4.0](https://github.com/gulrak/filesystem/tree/v1.4.0) and
source archives can be found [here](https://github.com/gulrak/filesystem/releases/tag/v1.4.0). source archives can be found [here](https://github.com/gulrak/filesystem/releases/tag/v1.4.0).
@ -176,83 +171,60 @@ Everything is in the namespace `ghc::filesystem`, so one way to use it only as
a fallback could be: a fallback could be:
```cpp ```cpp
#if _MSVC_LANG >= 201703L || __cplusplus >= 201703L && defined(__has_include) #ifdef __APPLE__
// ^ Supports MSVC prior to 15.7 without setting /Zc:__cplusplus to fix __cplusplus #include <Availability.h> // for deployment target to support pre-catalina targets without std::fs
// _MSVC_LANG works regardless. But without the switch, the compiler always reported 199711L: https://blogs.msdn.microsoft.com/vcblog/2018/04/09/msvc-now-correctly-reports-__cplusplus/
#if __has_include(<filesystem>) // Two stage __has_include needed for MSVC 2015 and per https://gcc.gnu.org/onlinedocs/cpp/_005f_005fhas_005finclude.html
#define GHC_USE_STD_FS
// Old Apple OSs don't support std::filesystem, though the header is available at compile
// time. In particular, std::filesystem is unavailable before macOS 10.15, iOS/tvOS 13.0,
// and watchOS 6.0.
#ifdef __APPLE__
#include <Availability.h>
// Note: This intentionally uses std::filesystem on any new Apple OS, like visionOS
// released after std::filesystem, where std::filesystem is always available.
// (All other __<platform>_VERSION_MIN_REQUIREDs will be undefined and thus 0.)
#if __MAC_OS_X_VERSION_MIN_REQUIRED && __MAC_OS_X_VERSION_MIN_REQUIRED < 101500 \
|| __IPHONE_OS_VERSION_MIN_REQUIRED && __IPHONE_OS_VERSION_MIN_REQUIRED < 130000 \
|| __TV_OS_VERSION_MIN_REQUIRED && __TV_OS_VERSION_MIN_REQUIRED < 130000 \
|| __WATCH_OS_VERSION_MAX_ALLOWED && __WATCH_OS_VERSION_MAX_ALLOWED < 60000
#undef GHC_USE_STD_FS
#endif
#endif
#endif
#endif #endif
#if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || (defined(__cplusplus) && __cplusplus >= 201703L)) && defined(__has_include)
#ifdef GHC_USE_STD_FS #if __has_include(<filesystem>) && (!defined(__MAC_OS_X_VERSION_MIN_REQUIRED) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 101500)
#include <filesystem> #define GHC_USE_STD_FS
namespace fs = std::filesystem; #include <filesystem>
#else namespace fs = std::filesystem;
#include "filesystem.hpp" #endif
namespace fs = ghc::filesystem; #endif
#ifndef GHC_USE_STD_FS
#include <ghc/filesystem.hpp>
namespace fs = ghc::filesystem;
#endif #endif
``` ```
**Note that this code uses a two-stage preprocessor condition because Visual Studio 2015
doesn't like the `(<...>)` syntax, even if it could cut evaluation early before. This code also
used the minimum deployment target to detect if `std::filesystem` really is available on macOS
compilation.**
**Note also, this detection now works on MSVC versions prior to 15.7 on, or without setting
the `/Zc:__cplusplus` compile switch that would fix `__cplusplus` on MSVC. (Without the switch
the compiler always reports `199711L`
([see](https://blogs.msdn.microsoft.com/vcblog/2018/04/09/msvc-now-correctly-reports-__cplusplus/)),
but `_MSVC_LANG` works without it.**
If you want to also use the `fstream` wrapper with `path` support as fallback, If you want to also use the `fstream` wrapper with `path` support as fallback,
you might use: you might use:
```cpp ```cpp
#if _MSVC_LANG >= 201703L || __cplusplus >= 201703L && defined(__has_include) #ifdef __APPLE__
// ^ Supports MSVC prior to 15.7 without setting /Zc:__cplusplus to fix __cplusplus #include <Availability.h> // for deployment target to support pre-catalina targets without std::fs
// _MSVC_LANG works regardless. But without the switch, the compiler always reported 199711L: https://blogs.msdn.microsoft.com/vcblog/2018/04/09/msvc-now-correctly-reports-__cplusplus/
#if __has_include(<filesystem>) // Two stage __has_include needed for MSVC 2015 and per https://gcc.gnu.org/onlinedocs/cpp/_005f_005fhas_005finclude.html
#define GHC_USE_STD_FS
// Old Apple OSs don't support std::filesystem, though the header is available at compile
// time. In particular, std::filesystem is unavailable before macOS 10.15, iOS/tvOS 13.0,
// and watchOS 6.0.
#ifdef __APPLE__
#include <Availability.h>
// Note: This intentionally uses std::filesystem on any new Apple OS, like visionOS
// released after std::filesystem, where std::filesystem is always available.
// (All other __<platform>_VERSION_MIN_REQUIREDs will be undefined and thus 0.)
#if __MAC_OS_X_VERSION_MIN_REQUIRED && __MAC_OS_X_VERSION_MIN_REQUIRED < 101500 \
|| __IPHONE_OS_VERSION_MIN_REQUIRED && __IPHONE_OS_VERSION_MIN_REQUIRED < 130000 \
|| __TV_OS_VERSION_MIN_REQUIRED && __TV_OS_VERSION_MIN_REQUIRED < 130000 \
|| __WATCH_OS_VERSION_MAX_ALLOWED && __WATCH_OS_VERSION_MAX_ALLOWED < 60000
#undef GHC_USE_STD_FS
#endif
#endif
#endif
#endif #endif
#if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || (defined(__cplusplus) && __cplusplus >= 201703L)) && defined(__has_include)
#ifdef GHC_USE_STD_FS #if __has_include(<filesystem>) && (!defined(__MAC_OS_X_VERSION_MIN_REQUIRED) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 101500)
#include <filesystem> #define GHC_USE_STD_FS
namespace fs { #include <filesystem>
using namespace std::filesystem; namespace fs {
using ifstream = std::ifstream; using namespace std::filesystem;
using ofstream = std::ofstream; using ifstream = std::ifstream;
using fstream = std::fstream; using ofstream = std::ofstream;
} using fstream = std::fstream;
#else }
#include "filesystem.hpp" #endif
namespace fs { #endif
using namespace ghc::filesystem; #ifndef GHC_USE_STD_FS
using ifstream = ghc::filesystem::ifstream; #include <ghc/filesystem.hpp>
using ofstream = ghc::filesystem::ofstream; namespace fs {
using fstream = ghc::filesystem::fstream; using namespace ghc::filesystem;
} using ifstream = ghc::filesystem::ifstream;
using ofstream = ghc::filesystem::ofstream;
using fstream = ghc::filesystem::fstream;
}
#endif #endif
``` ```
@ -292,46 +264,29 @@ If you use the forwarding/implementation approach, you can still use the dynamic
switching like this: switching like this:
```cpp ```cpp
#if _MSVC_LANG >= 201703L || __cplusplus >= 201703L && defined(__has_include) #ifdef __APPLE__
// ^ Supports MSVC prior to 15.7 without setting /Zc:__cplusplus to fix __cplusplus #include <Availability.h> // for deployment target to support pre-catalina targets without std::fs
// _MSVC_LANG works regardless. But without the switch, the compiler always reported 199711L: https://blogs.msdn.microsoft.com/vcblog/2018/04/09/msvc-now-correctly-reports-__cplusplus/
#if __has_include(<filesystem>) // Two stage __has_include needed for MSVC 2015 and per https://gcc.gnu.org/onlinedocs/cpp/_005f_005fhas_005finclude.html
#define GHC_USE_STD_FS
// Old Apple OSs don't support std::filesystem, though the header is available at compile
// time. In particular, std::filesystem is unavailable before macOS 10.15, iOS/tvOS 13.0,
// and watchOS 6.0.
#ifdef __APPLE__
#include <Availability.h>
// Note: This intentionally uses std::filesystem on any new Apple OS, like visionOS
// released after std::filesystem, where std::filesystem is always available.
// (All other __<platform>_VERSION_MIN_REQUIREDs will be undefined and thus 0.)
#if __MAC_OS_X_VERSION_MIN_REQUIRED && __MAC_OS_X_VERSION_MIN_REQUIRED < 101500 \
|| __IPHONE_OS_VERSION_MIN_REQUIRED && __IPHONE_OS_VERSION_MIN_REQUIRED < 130000 \
|| __TV_OS_VERSION_MIN_REQUIRED && __TV_OS_VERSION_MIN_REQUIRED < 130000 \
|| __WATCH_OS_VERSION_MAX_ALLOWED && __WATCH_OS_VERSION_MAX_ALLOWED < 60000
#undef GHC_USE_STD_FS
#endif
#endif
#endif
#endif #endif
#if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || (defined(__cplusplus) && __cplusplus >= 201703L)) && defined(__has_include)
#ifdef GHC_USE_STD_FS #if __has_include(<filesystem>) && (!defined(__MAC_OS_X_VERSION_MIN_REQUIRED) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 101500)
#include <filesystem> #define GHC_USE_STD_FS
namespace fs { #include <filesystem>
using namespace std::filesystem; namespace fs {
using ifstream = std::ifstream; using namespace std::filesystem;
using ofstream = std::ofstream; using ifstream = std::ifstream;
using fstream = std::fstream; using ofstream = std::ofstream;
} using fstream = std::fstream;
#else }
#include "fs_fwd.hpp" #endif
namespace fs { #endif
using namespace ghc::filesystem; #ifndef GHC_USE_STD_FS
using ifstream = ghc::filesystem::ifstream; #include <ghc/fs-fwd.hpp>
using ofstream = ghc::filesystem::ofstream; namespace fs {
using fstream = ghc::filesystem::fstream; using namespace ghc::filesystem;
} using ifstream = ghc::filesystem::ifstream;
using ofstream = ghc::filesystem::ofstream;
using fstream = ghc::filesystem::fstream;
}
#endif #endif
``` ```
@ -339,38 +294,25 @@ and in the implementation hiding cpp, you might use (before any include that inc
to take precedence: to take precedence:
```cpp ```cpp
#if _MSVC_LANG >= 201703L || __cplusplus >= 201703L && defined(__has_include) #ifdef __APPLE__ // for deployment target to support pre-catalina targets without std::fs
// ^ Supports MSVC prior to 15.7 without setting /Zc:__cplusplus to fix __cplusplus #include <Availability.h>
// _MSVC_LANG works regardless. But without the switch, the compiler always reported 199711L: https://blogs.msdn.microsoft.com/vcblog/2018/04/09/msvc-now-correctly-reports-__cplusplus/ #endif
#if __has_include(<filesystem>) // Two stage __has_include needed for MSVC 2015 and per https://gcc.gnu.org/onlinedocs/cpp/_005f_005fhas_005finclude.html #if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || (defined(__cplusplus) && __cplusplus >= 201703L)) && defined(__has_include)
#define GHC_USE_STD_FS #if __has_include(<filesystem>) && (!defined(__MAC_OS_X_VERSION_MIN_REQUIRED) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 101500)
#define GHC_USE_STD_FS
// Old Apple OSs don't support std::filesystem, though the header is available at compile #endif
// time. In particular, std::filesystem is unavailable before macOS 10.15, iOS/tvOS 13.0,
// and watchOS 6.0.
#ifdef __APPLE__
#include <Availability.h>
// Note: This intentionally uses std::filesystem on any new Apple OS, like visionOS
// released after std::filesystem, where std::filesystem is always available.
// (All other __<platform>_VERSION_MIN_REQUIREDs will be undefined and thus 0.)
#if __MAC_OS_X_VERSION_MIN_REQUIRED && __MAC_OS_X_VERSION_MIN_REQUIRED < 101500 \
|| __IPHONE_OS_VERSION_MIN_REQUIRED && __IPHONE_OS_VERSION_MIN_REQUIRED < 130000 \
|| __TV_OS_VERSION_MIN_REQUIRED && __TV_OS_VERSION_MIN_REQUIRED < 130000 \
|| __WATCH_OS_VERSION_MAX_ALLOWED && __WATCH_OS_VERSION_MAX_ALLOWED < 60000
#undef GHC_USE_STD_FS
#endif
#endif
#endif
#endif #endif
#ifndef GHC_USE_STD_FS #ifndef GHC_USE_STD_FS
#include "fs_impl.hpp" #define GHC_FILESYSTEM_IMPLEMENTATION
#include <ghc/filesystem.hpp>
#endif #endif
``` ```
:information_source: **Hint:** There are additional helper headers, named `ghc/fs_std_fwd.hpp` and :information_source: **Hint:** There are additional helper headers, named `ghc/fs_std_fwd.hpp` and
`ghc/fs_std_impl.hpp` that use this technique, so you can simply include them `ghc/fs_std_impl.hpp` that use this technique, so you can simply include them
if you want to dynamically select the filesystem implementation. if you want to dynamically select the filesystem implementation. they also
enable the `wchar_t` support on `ghc::filesystem` on Windows, so the resulting
implementation in the `fs` namespace will be compatible.
@ -397,10 +339,6 @@ The `CMakeLists.txt` offers a few options to customize its behavior:
`CMAKE_CXX_COMPILE_FEATURES` when the detection of C++17 or C++20 for additional tests `CMAKE_CXX_COMPILE_FEATURES` when the detection of C++17 or C++20 for additional tests
is not working (e.g. `cxx_std_20` to enforce building a `filesystem_test_cpp20` with C++20). is not working (e.g. `cxx_std_20` to enforce building a `filesystem_test_cpp20` with C++20).
### Bazel
Please use [hedronvision/bazel-cc-filesystem-backport](https://github.com/hedronvision/bazel-cc-filesystem-backport), which will automatically set everything up for you.
### Versioning ### Versioning
There is a version macro `GHC_FILESYSTEM_VERSION` defined in case future changes There is a version macro `GHC_FILESYSTEM_VERSION` defined in case future changes
@ -466,7 +404,7 @@ int main(int argc, char* argv[])
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
// now use argc/argv as usual, they have utf-8 encoding on windows // now use argc/argv as usual, they have utf-8 enconding on windows
// ... // ...
return 0; return 0;
@ -646,49 +584,6 @@ to the expected behavior.
## Release Notes ## Release Notes
### v1.5.15 (wip)
* Fix for [#166](https://github.com/gulrak/filesystem/issues/166),
`extension()` did return non empty result for the directory name
`".."`
### [v1.5.14](https://github.com/gulrak/filesystem/releases/tag/v1.5.14)
* Pull request [#163](https://github.com/gulrak/filesystem/pull/163), build
support for Haiku (also fixes [#159](https://github.com/gulrak/filesystem/issues/159))
* Pull request [#162](https://github.com/gulrak/filesystem/pull/162), fix for
directory iterator treating all files subsequent to a symlink as symlink
on Windows
* Pull request [#161](https://github.com/gulrak/filesystem/pull/161), the
CMake alias `ghcFilesystem::ghc_filesystem` is now set unconditionally
* Fix for [#160](https://github.com/gulrak/filesystem/issues/160), the cmake
config now only sets install targets by default if the project is no
subproject, as documented
* Fix for [#157](https://github.com/gulrak/filesystem/issues/157), suppress
C4191 warning on MSVC for GetProcAddress casts
* Fix for [#156](https://github.com/gulrak/filesystem/issues/156), on POSIX
`stem()`, `filename()` and `extension()` of `fs::path` would return wrong
result if a colon was in the filename
* Pull request [#154](https://github.com/gulrak/filesystem/pull/145), build
support for GNU/Hurd
* Pull request [#153](https://github.com/gulrak/filesystem/pull/153), fixed
`fs::last_write_time(path, time, ec)` setter on iOS, tvOS and watchOS
* Fix for [#151](https://github.com/gulrak/filesystem/issues/156),
`fs::directory_entry::refresh()` now, consistently with `status()` will not
throw on symlinks to non-existing targets, but make the entry have
`file_type::not_found` as the type
* Pull request [#149](https://github.com/gulrak/filesystem/pull/149), add
version to CMake project and export it
* Fix for [#146](https://github.com/gulrak/filesystem/issues/146), handle `EINTR`
on POSIX directory iteration and file copy to avoid errors on network
filesystems
* Pull request [#145](https://github.com/gulrak/filesystem/pull/145), fix for
Y2038 bug in timeToFILETIME on Windows
* Pull request [#144](https://github.com/gulrak/filesystem/pull/144), `fs::copy_file()`
now also copies the permissions
* Pull request [#143](https://github.com/gulrak/filesystem/pull/143), fix
for `fs::copy_file()` ignoring the `skip_existing` option.
### [v1.5.12](https://github.com/gulrak/filesystem/releases/tag/v1.5.12) ### [v1.5.12](https://github.com/gulrak/filesystem/releases/tag/v1.5.12)
* Fix for [#142](https://github.com/gulrak/filesystem/issues/142), removed need * Fix for [#142](https://github.com/gulrak/filesystem/issues/142), removed need

View File

@ -22,9 +22,6 @@ if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang" AND (CMAKE_CXX_COMPILER_VERSION V
if(${CMAKE_SYSTEM_NAME} MATCHES "(SunOS|Solaris)") if(${CMAKE_SYSTEM_NAME} MATCHES "(SunOS|Solaris)")
target_link_libraries(filesystem_test xnet) target_link_libraries(filesystem_test xnet)
endif() endif()
if(${CMAKE_SYSTEM_NAME} MATCHES "Haiku")
target_link_libraries(filesystem_test network)
endif()
target_compile_definitions(${targetName} PRIVATE USE_STD_FS) target_compile_definitions(${targetName} PRIVATE USE_STD_FS)
endif() endif()
@ -37,9 +34,6 @@ if (CMAKE_COMPILER_IS_GNUCXX AND (CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 8.0 O
if(${CMAKE_SYSTEM_NAME} MATCHES "(SunOS|Solaris)") if(${CMAKE_SYSTEM_NAME} MATCHES "(SunOS|Solaris)")
target_link_libraries(${targetName} xnet) target_link_libraries(${targetName} xnet)
endif() endif()
if(${CMAKE_SYSTEM_NAME} MATCHES "Haiku")
target_link_libraries(${targetName} network)
endif()
target_compile_options(${targetName} PRIVATE $<$<BOOL:${CYGWIN}>:-Wa,-mbig-obj>) target_compile_options(${targetName} PRIVATE $<$<BOOL:${CYGWIN}>:-Wa,-mbig-obj>)
target_compile_definitions(${targetName} PRIVATE USE_STD_FS) target_compile_definitions(${targetName} PRIVATE USE_STD_FS)
endif() endif()
@ -61,9 +55,6 @@ macro(AddTestExecutableWithStdCpp cppStd)
if(${CMAKE_SYSTEM_NAME} MATCHES "(SunOS|Solaris)") if(${CMAKE_SYSTEM_NAME} MATCHES "(SunOS|Solaris)")
target_link_libraries(filesystem_test_cpp${cppStd} xnet) target_link_libraries(filesystem_test_cpp${cppStd} xnet)
endif() endif()
if(${CMAKE_SYSTEM_NAME} MATCHES "Haiku")
target_link_libraries(filesystem_test_cpp${cppStd} network)
endif()
target_compile_options(filesystem_test_cpp${cppStd} PRIVATE target_compile_options(filesystem_test_cpp${cppStd} PRIVATE
$<$<BOOL:${EMSCRIPTEN}>:-s DISABLE_EXCEPTION_CATCHING=0> $<$<BOOL:${EMSCRIPTEN}>:-s DISABLE_EXCEPTION_CATCHING=0>
$<$<OR:$<CXX_COMPILER_ID:Clang>,$<CXX_COMPILER_ID:AppleClang>>:-Wall -Wextra -Wshadow -Wconversion -Wsign-conversion -Wpedantic -Werror -Wno-error=deprecated-declarations> $<$<OR:$<CXX_COMPILER_ID:Clang>,$<CXX_COMPILER_ID:AppleClang>>:-Wall -Wextra -Wshadow -Wconversion -Wsign-conversion -Wpedantic -Werror -Wno-error=deprecated-declarations>

View File

@ -25,6 +25,23 @@
// SOFTWARE. // SOFTWARE.
// //
//--------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------
//
// To dynamically select std::filesystem where available on most platforms,
// you could use:
//
// #if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || (defined(__cplusplus) && __cplusplus >= 201703L)) && defined(__has_include)
// #if __has_include(<filesystem>) && (!defined(__MAC_OS_X_VERSION_MIN_REQUIRED) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 101500)
// #define GHC_USE_STD_FS
// #include <filesystem>
// namespace fs = std::filesystem;
// #endif
// #endif
// #ifndef GHC_USE_STD_FS
// #include <ghc/filesystem.hpp>
// namespace fs = ghc::filesystem;
// #endif
//
//---------------------------------------------------------------------------------------
#ifndef GHC_FILESYSTEM_H #ifndef GHC_FILESYSTEM_H
#define GHC_FILESYSTEM_H #define GHC_FILESYSTEM_H
@ -36,7 +53,7 @@
#ifndef GHC_OS_DETECTED #ifndef GHC_OS_DETECTED
#if defined(__APPLE__) && defined(__MACH__) #if defined(__APPLE__) && defined(__MACH__)
#define GHC_OS_APPLE #define GHC_OS_MACOS
#elif defined(__linux__) #elif defined(__linux__)
#define GHC_OS_LINUX #define GHC_OS_LINUX
#if defined(__ANDROID__) #if defined(__ANDROID__)
@ -61,8 +78,6 @@
#include <wasi/api.h> #include <wasi/api.h>
#elif defined(__QNX__) #elif defined(__QNX__)
#define GHC_OS_QNX #define GHC_OS_QNX
#elif defined(__HAIKU__)
#define GHC_OS_HAIKU
#else #else
#error "Operating system currently not supported!" #error "Operating system currently not supported!"
#endif #endif
@ -164,7 +179,7 @@
#include <langinfo.h> #include <langinfo.h>
#endif #endif
#endif #endif
#ifdef GHC_OS_APPLE #ifdef GHC_OS_MACOS
#include <Availability.h> #include <Availability.h>
#endif #endif
@ -291,7 +306,7 @@
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// ghc::filesystem version in decimal (major * 10000 + minor * 100 + patch) // ghc::filesystem version in decimal (major * 10000 + minor * 100 + patch)
#define GHC_FILESYSTEM_VERSION 10515L #define GHC_FILESYSTEM_VERSION 10512L
#if !defined(GHC_WITH_EXCEPTIONS) && (defined(__EXCEPTIONS) || defined(__cpp_exceptions) || defined(_CPPUNWIND)) #if !defined(GHC_WITH_EXCEPTIONS) && (defined(__EXCEPTIONS) || defined(__cpp_exceptions) || defined(_CPPUNWIND))
#define GHC_WITH_EXCEPTIONS #define GHC_WITH_EXCEPTIONS
@ -1142,10 +1157,6 @@ GHC_FS_API void create_hard_link(const path& to, const path& new_hard_link, std:
GHC_FS_API uintmax_t hard_link_count(const path& p, std::error_code& ec) noexcept; GHC_FS_API uintmax_t hard_link_count(const path& p, std::error_code& ec) noexcept;
#endif #endif
#if defined(GHC_OS_WINDOWS) && (!defined(__GLIBCXX__) || (defined(_GLIBCXX_HAVE__WFOPEN) && defined(_GLIBCXX_USE_WCHAR_T)))
#define GHC_HAS_FSTREAM_OPEN_WITH_WCHAR
#endif
// Non-C++17 add-on std::fstream wrappers with path // Non-C++17 add-on std::fstream wrappers with path
template <class charT, class traits = std::char_traits<charT>> template <class charT, class traits = std::char_traits<charT>>
class basic_filebuf : public std::basic_filebuf<charT, traits> class basic_filebuf : public std::basic_filebuf<charT, traits>
@ -1157,7 +1168,7 @@ public:
const basic_filebuf& operator=(const basic_filebuf&) = delete; const basic_filebuf& operator=(const basic_filebuf&) = delete;
basic_filebuf<charT, traits>* open(const path& p, std::ios_base::openmode mode) basic_filebuf<charT, traits>* open(const path& p, std::ios_base::openmode mode)
{ {
#ifdef GHC_HAS_FSTREAM_OPEN_WITH_WCHAR #if defined(GHC_OS_WINDOWS) && !defined(__GLIBCXX__)
return std::basic_filebuf<charT, traits>::open(p.wstring().c_str(), mode) ? this : 0; return std::basic_filebuf<charT, traits>::open(p.wstring().c_str(), mode) ? this : 0;
#else #else
return std::basic_filebuf<charT, traits>::open(p.string().c_str(), mode) ? this : 0; return std::basic_filebuf<charT, traits>::open(p.string().c_str(), mode) ? this : 0;
@ -1170,7 +1181,7 @@ class basic_ifstream : public std::basic_ifstream<charT, traits>
{ {
public: public:
basic_ifstream() {} basic_ifstream() {}
#ifdef GHC_HAS_FSTREAM_OPEN_WITH_WCHAR #if defined(GHC_OS_WINDOWS) && !defined(__GLIBCXX__)
explicit basic_ifstream(const path& p, std::ios_base::openmode mode = std::ios_base::in) explicit basic_ifstream(const path& p, std::ios_base::openmode mode = std::ios_base::in)
: std::basic_ifstream<charT, traits>(p.wstring().c_str(), mode) : std::basic_ifstream<charT, traits>(p.wstring().c_str(), mode)
{ {
@ -1193,7 +1204,7 @@ class basic_ofstream : public std::basic_ofstream<charT, traits>
{ {
public: public:
basic_ofstream() {} basic_ofstream() {}
#ifdef GHC_HAS_FSTREAM_OPEN_WITH_WCHAR #if defined(GHC_OS_WINDOWS) && !defined(__GLIBCXX__)
explicit basic_ofstream(const path& p, std::ios_base::openmode mode = std::ios_base::out) explicit basic_ofstream(const path& p, std::ios_base::openmode mode = std::ios_base::out)
: std::basic_ofstream<charT, traits>(p.wstring().c_str(), mode) : std::basic_ofstream<charT, traits>(p.wstring().c_str(), mode)
{ {
@ -1216,7 +1227,7 @@ class basic_fstream : public std::basic_fstream<charT, traits>
{ {
public: public:
basic_fstream() {} basic_fstream() {}
#ifdef GHC_HAS_FSTREAM_OPEN_WITH_WCHAR #if defined(GHC_OS_WINDOWS) && !defined(__GLIBCXX__)
explicit basic_fstream(const path& p, std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out) explicit basic_fstream(const path& p, std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out)
: std::basic_fstream<charT, traits>(p.wstring().c_str(), mode) : std::basic_fstream<charT, traits>(p.wstring().c_str(), mode)
{ {
@ -1944,15 +1955,10 @@ GHC_INLINE void create_symlink(const path& target_name, const path& new_symlink,
#if defined(__GNUC__) && __GNUC__ >= 8 #if defined(__GNUC__) && __GNUC__ >= 8
#pragma GCC diagnostic push #pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wcast-function-type" #pragma GCC diagnostic ignored "-Wcast-function-type"
#elif defined(_MSC_VER) && !defined(__INTEL_COMPILER) && !defined(__clang__)
#pragma warning(push)
#pragma warning(disable : 4191)
#endif #endif
static CreateSymbolicLinkW_fp api_call = reinterpret_cast<CreateSymbolicLinkW_fp>(GetProcAddress(GetModuleHandleW(L"kernel32.dll"), "CreateSymbolicLinkW")); static CreateSymbolicLinkW_fp api_call = reinterpret_cast<CreateSymbolicLinkW_fp>(GetProcAddress(GetModuleHandleW(L"kernel32.dll"), "CreateSymbolicLinkW"));
#if defined(__GNUC__) && __GNUC__ >= 8 #if defined(__GNUC__) && __GNUC__ >= 8
#pragma GCC diagnostic pop #pragma GCC diagnostic pop
#elif defined(_MSC_VER) && !defined(__INTEL_COMPILER) && !defined(__clang__)
#pragma warning(pop)
#endif #endif
if (api_call) { if (api_call) {
if (api_call(GHC_NATIVEWP(new_symlink), GHC_NATIVEWP(target_name), to_directory ? 1 : 0) == 0) { if (api_call(GHC_NATIVEWP(new_symlink), GHC_NATIVEWP(target_name), to_directory ? 1 : 0) == 0) {
@ -1973,15 +1979,10 @@ GHC_INLINE void create_hardlink(const path& target_name, const path& new_hardlin
#if defined(__GNUC__) && __GNUC__ >= 8 #if defined(__GNUC__) && __GNUC__ >= 8
#pragma GCC diagnostic push #pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wcast-function-type" #pragma GCC diagnostic ignored "-Wcast-function-type"
#elif defined(_MSC_VER) && !defined(__INTEL_COMPILER) && !defined(__clang__)
#pragma warning(push)
#pragma warning(disable : 4191)
#endif #endif
static CreateHardLinkW_fp api_call = reinterpret_cast<CreateHardLinkW_fp>(GetProcAddress(GetModuleHandleW(L"kernel32.dll"), "CreateHardLinkW")); static CreateHardLinkW_fp api_call = reinterpret_cast<CreateHardLinkW_fp>(GetProcAddress(GetModuleHandleW(L"kernel32.dll"), "CreateHardLinkW"));
#if defined(__GNUC__) && __GNUC__ >= 8 #if defined(__GNUC__) && __GNUC__ >= 8
#pragma GCC diagnostic pop #pragma GCC diagnostic pop
#elif defined(_MSC_VER) && !defined(__INTEL_COMPILER) && !defined(__clang__)
#pragma warning(pop)
#endif #endif
if (api_call) { if (api_call) {
if (api_call(GHC_NATIVEWP(new_hardlink), GHC_NATIVEWP(target_name), NULL) == 0) { if (api_call(GHC_NATIVEWP(new_hardlink), GHC_NATIVEWP(target_name), NULL) == 0) {
@ -2240,10 +2241,10 @@ GHC_INLINE time_t timeFromFILETIME(const FILETIME& ft)
GHC_INLINE void timeToFILETIME(time_t t, FILETIME& ft) GHC_INLINE void timeToFILETIME(time_t t, FILETIME& ft)
{ {
ULARGE_INTEGER ull; LONGLONG ll;
ull.QuadPart = static_cast<ULONGLONG>((t * 10000000LL) + 116444736000000000LL); ll = Int32x32To64(t, 10000000) + 116444736000000000;
ft.dwLowDateTime = ull.LowPart; ft.dwLowDateTime = static_cast<DWORD>(ll);
ft.dwHighDateTime = ull.HighPart; ft.dwHighDateTime = static_cast<DWORD>(ll >> 32);
} }
template <typename INFO> template <typename INFO>
@ -2259,43 +2260,41 @@ GHC_INLINE uintmax_t hard_links_from_INFO<BY_HANDLE_FILE_INFORMATION>(const BY_H
} }
template <typename INFO> template <typename INFO>
GHC_INLINE bool is_symlink_from_INFO(const path &p, const INFO* info, std::error_code& ec) GHC_INLINE DWORD reparse_tag_from_INFO(const INFO*)
{ {
if ((info->dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) { return 0;
auto reparseData = detail::getReparseData(p, ec);
if (!ec && reparseData && IsReparseTagMicrosoft(reparseData->ReparseTag) && reparseData->ReparseTag == IO_REPARSE_TAG_SYMLINK) {
return true;
}
}
return false;
} }
template <> template <>
GHC_INLINE bool is_symlink_from_INFO(const path &, const WIN32_FIND_DATAW* info, std::error_code&) GHC_INLINE DWORD reparse_tag_from_INFO(const WIN32_FIND_DATAW* info)
{ {
// dwReserved0 is undefined unless dwFileAttributes includes the return info->dwReserved0;
// FILE_ATTRIBUTE_REPARSE_POINT attribute according to microsoft
// documentation. In practice, dwReserved0 is not reset which
// causes it to report the incorrect symlink status.
// Note that microsoft documentation does not say whether there is
// a null value for dwReserved0, so we test for symlink directly
// instead of returning the tag which requires returning a null
// value for non-reparse-point files.
return (info->dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) && info->dwReserved0 == IO_REPARSE_TAG_SYMLINK;
} }
template <typename INFO> template <typename INFO>
GHC_INLINE file_status status_from_INFO(const path& p, const INFO* info, std::error_code& ec, uintmax_t* sz = nullptr, time_t* lwt = nullptr) GHC_INLINE file_status status_from_INFO(const path& p, const INFO* info, std::error_code& ec, uintmax_t* sz = nullptr, time_t* lwt = nullptr)
{ {
file_type ft = file_type::unknown; file_type ft = file_type::unknown;
if (is_symlink_from_INFO(p, info, ec)) { if (sizeof(INFO) == sizeof(WIN32_FIND_DATAW)) {
ft = file_type::symlink; if (detail::reparse_tag_from_INFO(info) == IO_REPARSE_TAG_SYMLINK) {
} ft = file_type::symlink;
else if ((info->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { }
ft = file_type::directory;
} }
else { else {
ft = file_type::regular; if ((info->dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) {
auto reparseData = detail::getReparseData(p, ec);
if (!ec && reparseData && IsReparseTagMicrosoft(reparseData->ReparseTag) && reparseData->ReparseTag == IO_REPARSE_TAG_SYMLINK) {
ft = file_type::symlink;
}
}
}
if (ft == file_type::unknown) {
if ((info->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
ft = file_type::directory;
}
else {
ft = file_type::regular;
}
} }
perms prms = perms::owner_read | perms::group_read | perms::others_read; perms prms = perms::owner_read | perms::group_read | perms::others_read;
if (!(info->dwFileAttributes & FILE_ATTRIBUTE_READONLY)) { if (!(info->dwFileAttributes & FILE_ATTRIBUTE_READONLY)) {
@ -3157,7 +3156,7 @@ GHC_INLINE path path::extension() const
auto iter = end(); auto iter = end();
const auto& fn = *--iter; const auto& fn = *--iter;
impl_string_type::size_type pos = fn._path.rfind('.'); impl_string_type::size_type pos = fn._path.rfind('.');
if (pos != std::string::npos && pos > 0 && fn._path != "..") { if (pos != std::string::npos && pos > 0) {
return path(fn._path.substr(pos), native_format); return path(fn._path.substr(pos), native_format);
} }
} }
@ -3306,9 +3305,6 @@ GHC_INLINE path path::lexically_relative(const path& base) const
--count; --count;
} }
} }
if (count == 0 && (a == end() || a->empty())) {
return path(".");
}
if (count < 0) { if (count < 0) {
return path(); return path();
} }
@ -3369,14 +3365,10 @@ GHC_INLINE path::impl_string_type::const_iterator path::iterator::increment(cons
} }
} }
else { else {
#ifdef GHC_OS_WINDOWS
if (fromStart && i != _last && *i == ':') { if (fromStart && i != _last && *i == ':') {
++i; ++i;
} }
else { else {
#else
{
#endif
i = std::find(i, _last, preferred_separator); i = std::find(i, _last, preferred_separator);
} }
} }
@ -3920,14 +3912,11 @@ GHC_INLINE bool copy_file(const path& from, const path& to, copy_options options
ec = tecf; ec = tecf;
return false; return false;
} }
if (exists(st) && (!is_regular_file(st) || equivalent(from, to, ec) || (options & (copy_options::skip_existing | copy_options::overwrite_existing | copy_options::update_existing)) == copy_options::none)) {
ec = tect ? tect : detail::make_error_code(detail::portable_error::exists);
return false;
}
if (exists(st)) { if (exists(st)) {
if ((options & copy_options::skip_existing) == copy_options::skip_existing) {
return false;
}
if (!is_regular_file(st) || equivalent(from, to, ec) || (options & (copy_options::overwrite_existing | copy_options::update_existing)) == copy_options::none) {
ec = tect ? tect : detail::make_error_code(detail::portable_error::exists);
return false;
}
if ((options & copy_options::update_existing) == copy_options::update_existing) { if ((options & copy_options::update_existing) == copy_options::update_existing) {
auto from_time = last_write_time(from, ec); auto from_time = last_write_time(from, ec);
if (ec) { if (ec) {
@ -3967,33 +3956,15 @@ GHC_INLINE bool copy_file(const path& from, const path& to, copy_options options
::close(in); ::close(in);
return false; return false;
} }
if (st.permissions() != sf.permissions()) {
if (::fchmod(out, static_cast<mode_t>(sf.permissions() & perms::all)) != 0) {
ec = detail::make_system_error();
::close(in);
::close(out);
return false;
}
}
ssize_t br, bw; ssize_t br, bw;
while (true) { while ((br = ::read(in, buffer.data(), buffer.size())) > 0) {
do { br = ::read(in, buffer.data(), buffer.size()); } while(errno == EINTR && !br);
if(!br) {
break;
}
if(br < 0) {
ec = detail::make_system_error();
::close(in);
::close(out);
return false;
}
ssize_t offset = 0; ssize_t offset = 0;
do { do {
if ((bw = ::write(out, buffer.data() + offset, static_cast<size_t>(br))) > 0) { if ((bw = ::write(out, buffer.data() + offset, static_cast<size_t>(br))) > 0) {
br -= bw; br -= bw;
offset += bw; offset += bw;
} }
else if (bw < 0 && errno != EINTR) { else if (bw < 0) {
ec = detail::make_system_error(); ec = detail::make_system_error();
::close(in); ::close(in);
::close(out); ::close(out);
@ -4228,13 +4199,6 @@ GHC_INLINE path current_path(std::error_code& ec)
return path(); return path();
} }
return path(std::wstring(buffer.get()), path::native_format); return path(std::wstring(buffer.get()), path::native_format);
#elif defined(__GLIBC__)
std::unique_ptr<char, decltype(&std::free)> buffer { ::get_current_dir_name(), std::free };
if (buffer == nullptr) {
ec = detail::make_system_error();
return path();
}
return path(buffer.get());
#else #else
size_t pathlen = static_cast<size_t>(std::max(int(::pathconf(".", _PC_PATH_MAX)), int(PATH_MAX))); size_t pathlen = static_cast<size_t>(std::max(int(::pathconf(".", _PC_PATH_MAX)), int(PATH_MAX)));
std::unique_ptr<char[]> buffer(new char[pathlen + 1]); std::unique_ptr<char[]> buffer(new char[pathlen + 1]);
@ -4640,11 +4604,9 @@ GHC_INLINE void last_write_time(const path& p, file_time_type new_time, std::err
if (!::SetFileTime(file.get(), 0, 0, &ft)) { if (!::SetFileTime(file.get(), 0, 0, &ft)) {
ec = detail::make_system_error(); ec = detail::make_system_error();
} }
#elif defined(GHC_OS_APPLE) && \ #elif defined(GHC_OS_MACOS)
(__MAC_OS_X_VERSION_MIN_REQUIRED && __MAC_OS_X_VERSION_MIN_REQUIRED < 101300 \ #ifdef __MAC_OS_X_VERSION_MIN_REQUIRED
|| __IPHONE_OS_VERSION_MIN_REQUIRED && __IPHONE_OS_VERSION_MIN_REQUIRED < 110000 \ #if __MAC_OS_X_VERSION_MIN_REQUIRED < 101300
|| __TV_OS_VERSION_MIN_REQUIRED && __TVOS_VERSION_MIN_REQUIRED < 110000 \
|| __WATCH_OS_VERSION_MIN_REQUIRED && __WATCHOS_VERSION_MIN_REQUIRED < 40000)
struct ::stat fs; struct ::stat fs;
if (::stat(p.c_str(), &fs) == 0) { if (::stat(p.c_str(), &fs) == 0) {
struct ::timeval tv[2]; struct ::timeval tv[2];
@ -4658,6 +4620,18 @@ GHC_INLINE void last_write_time(const path& p, file_time_type new_time, std::err
} }
ec = detail::make_system_error(); ec = detail::make_system_error();
return; return;
#else
struct ::timespec times[2];
times[0].tv_sec = 0;
times[0].tv_nsec = UTIME_OMIT;
times[1].tv_sec = std::chrono::duration_cast<std::chrono::seconds>(d).count();
times[1].tv_nsec = 0; // std::chrono::duration_cast<std::chrono::nanoseconds>(d).count() % 1000000000;
if (::utimensat(AT_FDCWD, p.c_str(), times, AT_SYMLINK_NOFOLLOW) != 0) {
ec = detail::make_system_error();
}
return;
#endif
#endif
#else #else
#ifndef UTIME_OMIT #ifndef UTIME_OMIT
#define UTIME_OMIT ((1l << 30) - 2l) #define UTIME_OMIT ((1l << 30) - 2l)
@ -5285,7 +5259,7 @@ GHC_INLINE void directory_entry::refresh()
{ {
std::error_code ec; std::error_code ec;
refresh(ec); refresh(ec);
if (ec && (_status.type() == file_type::none || _symlink_status.type() != file_type::symlink)) { if (ec) {
throw filesystem_error(detail::systemErrorText(ec.value()), _path, ec); throw filesystem_error(detail::systemErrorText(ec.value()), _path, ec);
} }
} }
@ -5696,7 +5670,7 @@ public:
, _entry(nullptr) , _entry(nullptr)
{ {
if (!path.empty()) { if (!path.empty()) {
do { _dir = ::opendir(path.native().c_str()); } while(errno == EINTR && !_dir); _dir = ::opendir(path.native().c_str());
if (!_dir) { if (!_dir) {
auto error = errno; auto error = errno;
_base = filesystem::path(); _base = filesystem::path();
@ -5723,7 +5697,7 @@ public:
do { do {
skip = false; skip = false;
errno = 0; errno = 0;
do { _entry = ::readdir(_dir); } while(errno == EINTR && !_entry); _entry = ::readdir(_dir);
if (_entry) { if (_entry) {
_dir_entry._path = _base; _dir_entry._path = _base;
_dir_entry._path.append_name(_entry->d_name); _dir_entry._path.append_name(_entry->d_name);
@ -5737,7 +5711,7 @@ public:
::closedir(_dir); ::closedir(_dir);
_dir = nullptr; _dir = nullptr;
_dir_entry._path.clear(); _dir_entry._path.clear();
if (errno && errno != EINTR) { if (errno) {
ec = detail::make_system_error(); ec = detail::make_system_error();
} }
break; break;

View File

@ -25,7 +25,7 @@
// SOFTWARE. // SOFTWARE.
// //
//--------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------
// fs_fwd.hpp - The forwarding header for the header/implementation separated usage of // fs_fwd.hpp - The forwarding header for the header/implementation seperated usage of
// ghc::filesystem. // ghc::filesystem.
// This file can be include at any place, where ghc::filesystem api is needed while // This file can be include at any place, where ghc::filesystem api is needed while
// not bleeding implementation details (e.g. system includes) into the global namespace, // not bleeding implementation details (e.g. system includes) into the global namespace,
@ -34,5 +34,5 @@
#ifndef GHC_FILESYSTEM_FWD_H #ifndef GHC_FILESYSTEM_FWD_H
#define GHC_FILESYSTEM_FWD_H #define GHC_FILESYSTEM_FWD_H
#define GHC_FILESYSTEM_FWD #define GHC_FILESYSTEM_FWD
#include "filesystem.hpp" #include <ghc/filesystem.hpp>
#endif // GHC_FILESYSTEM_FWD_H #endif // GHC_FILESYSTEM_FWD_H

View File

@ -25,11 +25,11 @@
// SOFTWARE. // SOFTWARE.
// //
//--------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------
// fs_impl.hpp - The implementation header for the header/implementation separated usage of // fs_impl.hpp - The implementation header for the header/implementation seperated usage of
// ghc::filesystem. // ghc::filesystem.
// This file can be used to hide the implementation of ghc::filesystem into a single cpp. // This file can be used to hide the implementation of ghc::filesystem into a single cpp.
// The cpp has to include this before including fs_fwd.hpp directly or via a different // The cpp has to include this before including fs_fwd.hpp directly or via a different
// header to work. // header to work.
//--------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------
#define GHC_FILESYSTEM_IMPLEMENTATION #define GHC_FILESYSTEM_IMPLEMENTATION
#include "filesystem.hpp" #include <ghc/filesystem.hpp>

View File

@ -31,47 +31,30 @@
//--------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------
#ifndef GHC_FILESYSTEM_STD_H #ifndef GHC_FILESYSTEM_STD_H
#define GHC_FILESYSTEM_STD_H #define GHC_FILESYSTEM_STD_H
#if defined(__APPLE__)
#if defined(_MSVC_LANG) && _MSVC_LANG >= 201703L || __cplusplus >= 201703L && defined(__has_include) #include <Availability.h>
// ^ Supports MSVC prior to 15.7 without setting /Zc:__cplusplus to fix __cplusplus
// _MSVC_LANG works regardless. But without the switch, the compiler always reported 199711L: https://blogs.msdn.microsoft.com/vcblog/2018/04/09/msvc-now-correctly-reports-__cplusplus/
#if __has_include(<filesystem>) // Two stage __has_include needed for MSVC 2015 and per https://gcc.gnu.org/onlinedocs/cpp/_005f_005fhas_005finclude.html
#define GHC_USE_STD_FS
// Old Apple OSs don't support std::filesystem, though the header is available at compile
// time. In particular, std::filesystem is unavailable before macOS 10.15, iOS/tvOS 13.0,
// and watchOS 6.0.
#ifdef __APPLE__
#include <Availability.h>
// Note: This intentionally uses std::filesystem on any new Apple OS, like visionOS
// released after std::filesystem, where std::filesystem is always available.
// (All other __<platform>_VERSION_MIN_REQUIREDs will be undefined and thus 0.)
#if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED < 101500 \
|| defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && __IPHONE_OS_VERSION_MIN_REQUIRED < 130000 \
|| defined(__TV_OS_VERSION_MIN_REQUIRED) && __TV_OS_VERSION_MIN_REQUIRED < 130000 \
|| defined(__WATCH_OS_VERSION_MAX_ALLOWED) && __WATCH_OS_VERSION_MAX_ALLOWED < 60000
#undef GHC_USE_STD_FS
#endif
#endif
#endif
#endif #endif
#if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || (defined(__cplusplus) && __cplusplus >= 201703L)) && defined(__has_include)
#ifdef GHC_USE_STD_FS #if __has_include(<filesystem>) && (!defined(__MAC_OS_X_VERSION_MIN_REQUIRED) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 101500)
#include <filesystem> #define GHC_USE_STD_FS
namespace fs { #include <filesystem>
using namespace std::filesystem; namespace fs {
using ifstream = std::ifstream; using namespace std::filesystem;
using ofstream = std::ofstream; using ifstream = std::ifstream;
using fstream = std::fstream; using ofstream = std::ofstream;
} using fstream = std::fstream;
#else }
#include "filesystem.hpp" #endif
namespace fs { #endif
using namespace ghc::filesystem; #ifndef GHC_USE_STD_FS
using ifstream = ghc::filesystem::ifstream; //#define GHC_WIN_DISABLE_WSTRING_STORAGE_TYPE
using ofstream = ghc::filesystem::ofstream; #include <ghc/filesystem.hpp>
using fstream = ghc::filesystem::fstream; namespace fs {
} using namespace ghc::filesystem;
using ifstream = ghc::filesystem::ifstream;
using ofstream = ghc::filesystem::ofstream;
using fstream = ghc::filesystem::fstream;
}
#endif #endif
#endif // GHC_FILESYSTEM_STD_H #endif // GHC_FILESYSTEM_STD_H

View File

@ -25,7 +25,7 @@
// SOFTWARE. // SOFTWARE.
// //
//--------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------
// fs_std_fwd.hpp - The forwarding header for the header/implementation separated usage of // fs_std_fwd.hpp - The forwarding header for the header/implementation seperated usage of
// ghc::filesystem that uses std::filesystem if it detects it. // ghc::filesystem that uses std::filesystem if it detects it.
// This file can be include at any place, where fs::filesystem api is needed while // This file can be include at any place, where fs::filesystem api is needed while
// not bleeding implementation details (e.g. system includes) into the global namespace, // not bleeding implementation details (e.g. system includes) into the global namespace,
@ -33,47 +33,31 @@
//--------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------
#ifndef GHC_FILESYSTEM_STD_FWD_H #ifndef GHC_FILESYSTEM_STD_FWD_H
#define GHC_FILESYSTEM_STD_FWD_H #define GHC_FILESYSTEM_STD_FWD_H
#if defined(__APPLE__)
#if defined(_MSVC_LANG) && _MSVC_LANG >= 201703L || __cplusplus >= 201703L && defined(__has_include) #include <Availability.h>
// ^ Supports MSVC prior to 15.7 without setting /Zc:__cplusplus to fix __cplusplus
// _MSVC_LANG works regardless. But without the switch, the compiler always reported 199711L: https://blogs.msdn.microsoft.com/vcblog/2018/04/09/msvc-now-correctly-reports-__cplusplus/
#if __has_include(<filesystem>) // Two stage __has_include needed for MSVC 2015 and per https://gcc.gnu.org/onlinedocs/cpp/_005f_005fhas_005finclude.html
#define GHC_USE_STD_FS
// Old Apple OSs don't support std::filesystem, though the header is available at compile
// time. In particular, std::filesystem is unavailable before macOS 10.15, iOS/tvOS 13.0,
// and watchOS 6.0.
#ifdef __APPLE__
#include <Availability.h>
// Note: This intentionally uses std::filesystem on any new Apple OS, like visionOS
// released after std::filesystem, where std::filesystem is always available.
// (All other __<platform>_VERSION_MIN_REQUIREDs will be undefined and thus 0.)
#if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED < 101500 \
|| defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && __IPHONE_OS_VERSION_MIN_REQUIRED < 130000 \
|| defined(__TV_OS_VERSION_MIN_REQUIRED) && __TV_OS_VERSION_MIN_REQUIRED < 130000 \
|| defined(__WATCH_OS_VERSION_MAX_ALLOWED) && __WATCH_OS_VERSION_MAX_ALLOWED < 60000
#undef GHC_USE_STD_FS
#endif
#endif
#endif
#endif #endif
#if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || (defined(__cplusplus) && __cplusplus >= 201703L)) && defined(__has_include)
#ifdef GHC_USE_STD_FS #if __has_include(<filesystem>) && (!defined(__MAC_OS_X_VERSION_MIN_REQUIRED) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 101500)
#include <filesystem> #define GHC_USE_STD_FS
namespace fs { #include <filesystem>
using namespace std::filesystem; namespace fs {
using ifstream = std::ifstream; using namespace std::filesystem;
using ofstream = std::ofstream; using ifstream = std::ifstream;
using fstream = std::fstream; using ofstream = std::ofstream;
} using fstream = std::fstream;
#else }
#include "fs_fwd.hpp" #endif
namespace fs { #endif
using namespace ghc::filesystem; #ifndef GHC_USE_STD_FS
using ifstream = ghc::filesystem::ifstream; //#define GHC_WIN_DISABLE_WSTRING_STORAGE_TYPE
using ofstream = ghc::filesystem::ofstream; #define GHC_FILESYSTEM_FWD
using fstream = ghc::filesystem::fstream; #include <ghc/filesystem.hpp>
} namespace fs {
using namespace ghc::filesystem;
using ifstream = ghc::filesystem::ifstream;
using ofstream = ghc::filesystem::ofstream;
using fstream = ghc::filesystem::fstream;
}
#endif #endif
#endif // GHC_FILESYSTEM_STD_FWD_H #endif // GHC_FILESYSTEM_STD_FWD_H

View File

@ -25,36 +25,22 @@
// SOFTWARE. // SOFTWARE.
// //
//--------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------
// fs_std_impl.hpp - The implementation header for the header/implementation separated usage of // fs_std_impl.hpp - The implementation header for the header/implementation seperated usage of
// ghc::filesystem that does nothing if std::filesystem is detected. // ghc::filesystem that does nothing if std::filesystem is detected.
// This file can be used to hide the implementation of ghc::filesystem into a single cpp. // This file can be used to hide the implementation of ghc::filesystem into a single cpp.
// The cpp has to include this before including fs_std_fwd.hpp directly or via a different // The cpp has to include this before including fs_std_fwd.hpp directly or via a different
// header to work. // header to work.
//--------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------
#if defined(_MSVC_LANG) && _MSVC_LANG >= 201703L || __cplusplus >= 201703L && defined(__has_include) #if defined(__APPLE__)
// ^ Supports MSVC prior to 15.7 without setting /Zc:__cplusplus to fix __cplusplus #include <Availability.h>
// _MSVC_LANG works regardless. But without the switch, the compiler always reported 199711L: https://blogs.msdn.microsoft.com/vcblog/2018/04/09/msvc-now-correctly-reports-__cplusplus/ #endif
#if __has_include(<filesystem>) // Two stage __has_include needed for MSVC 2015 and per https://gcc.gnu.org/onlinedocs/cpp/_005f_005fhas_005finclude.html #if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || (defined(__cplusplus) && __cplusplus >= 201703L)) && defined(__has_include)
#define GHC_USE_STD_FS #if __has_include(<filesystem>) && (!defined(__MAC_OS_X_VERSION_MIN_REQUIRED) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 101500)
#define GHC_USE_STD_FS
// Old Apple OSs don't support std::filesystem, though the header is available at compile #endif
// time. In particular, std::filesystem is unavailable before macOS 10.15, iOS/tvOS 13.0,
// and watchOS 6.0.
#ifdef __APPLE__
#include <Availability.h>
// Note: This intentionally uses std::filesystem on any new Apple OS, like visionOS
// released after std::filesystem, where std::filesystem is always available.
// (All other __<platform>_VERSION_MIN_REQUIREDs will be undefined and thus 0.)
#if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED < 101500 \
|| defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && __IPHONE_OS_VERSION_MIN_REQUIRED < 130000 \
|| defined(__TV_OS_VERSION_MIN_REQUIRED) && __TV_OS_VERSION_MIN_REQUIRED < 130000 \
|| defined(__WATCH_OS_VERSION_MAX_ALLOWED) && __WATCH_OS_VERSION_MAX_ALLOWED < 60000
#undef GHC_USE_STD_FS
#endif
#endif
#endif
#endif #endif
#ifndef GHC_USE_STD_FS #ifndef GHC_USE_STD_FS
#include "fs_impl.hpp" //#define GHC_WIN_DISABLE_WSTRING_STORAGE_TYPE
#define GHC_FILESYSTEM_IMPLEMENTATION
#include <ghc/filesystem.hpp>
#endif #endif

View File

@ -3,11 +3,6 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake/")
set(PARSE_CATCH_TESTS_ADD_TO_CONFIGURE_DEPENDS ON) set(PARSE_CATCH_TESTS_ADD_TO_CONFIGURE_DEPENDS ON)
include(ParseAndAddCatchTests) include(ParseAndAddCatchTests)
if("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang" AND UNIX AND NOT APPLE AND NOT BSD)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++")
set(CMAKE_EXE_LINKER_FLAGS "-lc++abi")
endif()
function(SetTestCompileOptions target_name) function(SetTestCompileOptions target_name)
target_compile_options(${target_name} PRIVATE target_compile_options(${target_name} PRIVATE
$<$<BOOL:${EMSCRIPTEN}>:-s DISABLE_EXCEPTION_CATCHING=0> $<$<BOOL:${EMSCRIPTEN}>:-s DISABLE_EXCEPTION_CATCHING=0>
@ -30,9 +25,6 @@ if(GHC_COVERAGE)
if(${CMAKE_SYSTEM_NAME} MATCHES "(SunOS|Solaris)") if(${CMAKE_SYSTEM_NAME} MATCHES "(SunOS|Solaris)")
target_link_libraries(filesystem_test PUBLIC xnet) target_link_libraries(filesystem_test PUBLIC xnet)
endif() endif()
if(${CMAKE_SYSTEM_NAME} MATCHES "Haiku")
target_link_libraries(filesystem_test PUBLIC network)
endif()
if("cxx_std_17" IN_LIST GHC_FILESYSTEM_TEST_COMPILE_FEATURES) if("cxx_std_17" IN_LIST GHC_FILESYSTEM_TEST_COMPILE_FEATURES)
AddTestExecutableWithStdCpp(17 filesystem_test.cpp catch.hpp) AddTestExecutableWithStdCpp(17 filesystem_test.cpp catch.hpp)
endif() endif()
@ -46,9 +38,6 @@ else()
if(${CMAKE_SYSTEM_NAME} MATCHES "(SunOS|Solaris)") if(${CMAKE_SYSTEM_NAME} MATCHES "(SunOS|Solaris)")
target_link_libraries(filesystem_test xnet) target_link_libraries(filesystem_test xnet)
endif() endif()
if(${CMAKE_SYSTEM_NAME} MATCHES "Haiku")
target_link_libraries(filesystem_test network)
endif()
SetTestCompileOptions(filesystem_test) SetTestCompileOptions(filesystem_test)
if(CMAKE_CXX_COMPILER_ID MATCHES MSVC) if(CMAKE_CXX_COMPILER_ID MATCHES MSVC)
target_compile_definitions(filesystem_test PRIVATE _CRT_SECURE_NO_WARNINGS WIN32_LEAN_AND_MEAN NOMINMAX) target_compile_definitions(filesystem_test PRIVATE _CRT_SECURE_NO_WARNINGS WIN32_LEAN_AND_MEAN NOMINMAX)
@ -88,9 +77,6 @@ target_link_libraries(fwd_impl_test ghc_filesystem)
if(${CMAKE_SYSTEM_NAME} MATCHES "(SunOS|Solaris)") if(${CMAKE_SYSTEM_NAME} MATCHES "(SunOS|Solaris)")
target_link_libraries(fwd_impl_test xnet) target_link_libraries(fwd_impl_test xnet)
endif() endif()
if(${CMAKE_SYSTEM_NAME} MATCHES "Haiku")
target_link_libraries(fwd_impl_test network)
endif()
SetTestCompileOptions(fwd_impl_test) SetTestCompileOptions(fwd_impl_test)
if(CMAKE_CXX_COMPILER_ID MATCHES MSVC) if(CMAKE_CXX_COMPILER_ID MATCHES MSVC)
target_compile_definitions(fwd_impl_test PRIVATE _CRT_SECURE_NO_WARNINGS WIN32_LEAN_AND_MEAN NOMINMAX) target_compile_definitions(fwd_impl_test PRIVATE _CRT_SECURE_NO_WARNINGS WIN32_LEAN_AND_MEAN NOMINMAX)

View File

@ -99,7 +99,7 @@ using fstream = ghc::filesystem::fstream;
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
template <typename TP> template <typename TP>
static std::time_t to_time_t(TP tp) std::time_t to_time_t(TP tp)
{ {
using namespace std::chrono; using namespace std::chrono;
auto sctp = time_point_cast<system_clock::duration>(tp - TP::clock::now() + system_clock::now()); auto sctp = time_point_cast<system_clock::duration>(tp - TP::clock::now() + system_clock::now());
@ -107,7 +107,7 @@ static std::time_t to_time_t(TP tp)
} }
template <typename TP> template <typename TP>
static TP from_time_t(std::time_t t) TP from_time_t(std::time_t t)
{ {
using namespace std::chrono; using namespace std::chrono;
auto sctp = system_clock::from_time_t(t); auto sctp = system_clock::from_time_t(t);
@ -214,8 +214,7 @@ static void generateFile(const fs::path& pathname, int withSize = -1)
} }
#ifdef GHC_OS_WINDOWS #ifdef GHC_OS_WINDOWS
#if !defined(_WIN64) && defined(KEY_WOW64_64KEY) inline bool isWow64Proc()
static bool isWow64Proc()
{ {
typedef BOOL(WINAPI * IsWow64Process_t)(HANDLE, PBOOL); typedef BOOL(WINAPI * IsWow64Process_t)(HANDLE, PBOOL);
BOOL bIsWow64 = FALSE; BOOL bIsWow64 = FALSE;
@ -227,7 +226,6 @@ static bool isWow64Proc()
} }
return bIsWow64 == TRUE; return bIsWow64 == TRUE;
} }
#endif
static bool is_symlink_creation_supported() static bool is_symlink_creation_supported()
{ {
@ -305,13 +303,13 @@ public:
}; };
template <class T, class U> template <class T, class U>
static bool operator==(TestAllocator<T> const&, TestAllocator<U> const&) noexcept bool operator==(TestAllocator<T> const&, TestAllocator<U> const&) noexcept
{ {
return true; return true;
} }
template <class T, class U> template <class T, class U>
static bool operator!=(TestAllocator<T> const& x, TestAllocator<U> const& y) noexcept bool operator!=(TestAllocator<T> const& x, TestAllocator<U> const& y) noexcept
{ {
return !(x == y); return !(x == y);
} }
@ -792,9 +790,6 @@ TEST_CASE("fs.path.decompose - path decomposition", "[filesystem][path][fs.path.
CHECK(fs::path("C:/foo").filename() == "foo"); CHECK(fs::path("C:/foo").filename() == "foo");
CHECK(fs::path("C:\\foo").filename() == "foo"); CHECK(fs::path("C:\\foo").filename() == "foo");
CHECK(fs::path("C:foo").filename() == "foo"); CHECK(fs::path("C:foo").filename() == "foo");
CHECK(fs::path("t:est.txt").filename() == "est.txt");
#else
CHECK(fs::path("t:est.txt").filename() == "t:est.txt");
#endif #endif
// stem() // stem()
@ -812,13 +807,6 @@ TEST_CASE("fs.path.decompose - path decomposition", "[filesystem][path][fs.path.
CHECK(fs::path("/foo/.profile").stem() == ".profile"); CHECK(fs::path("/foo/.profile").stem() == ".profile");
CHECK(fs::path(".bar").stem() == ".bar"); CHECK(fs::path(".bar").stem() == ".bar");
CHECK(fs::path("..bar").stem() == "."); CHECK(fs::path("..bar").stem() == ".");
#ifdef GHC_OS_WINDOWS
CHECK(fs::path("t:est.txt").stem() == "est");
#else
CHECK(fs::path("t:est.txt").stem() == "t:est");
#endif
CHECK(fs::path("/foo/.").stem() == ".");
CHECK(fs::path("/foo/..").stem() == "..");
// extension() // extension()
CHECK(fs::path("/foo/bar.txt").extension() == ".txt"); CHECK(fs::path("/foo/bar.txt").extension() == ".txt");
@ -826,9 +814,6 @@ TEST_CASE("fs.path.decompose - path decomposition", "[filesystem][path][fs.path.
CHECK(fs::path("/foo/.profile").extension() == ""); CHECK(fs::path("/foo/.profile").extension() == "");
CHECK(fs::path(".bar").extension() == ""); CHECK(fs::path(".bar").extension() == "");
CHECK(fs::path("..bar").extension() == ".bar"); CHECK(fs::path("..bar").extension() == ".bar");
CHECK(fs::path("t:est.txt").extension() == ".txt");
CHECK(fs::path("/foo/.").extension() == "");
CHECK(fs::path("/foo/..").extension() == "");
if (has_host_root_name_support()) { if (has_host_root_name_support()) {
// //host-based root-names // //host-based root-names
@ -965,10 +950,6 @@ TEST_CASE("fs.path.gen - path generation", "[filesystem][path][fs.path.gen]")
// lexically_relative() // lexically_relative()
CHECK(fs::path("/a/d").lexically_relative("/a/b/c") == "../../d"); CHECK(fs::path("/a/d").lexically_relative("/a/b/c") == "../../d");
CHECK(fs::path("/a/b/c").lexically_relative("/a/d") == "../b/c"); CHECK(fs::path("/a/b/c").lexically_relative("/a/d") == "../b/c");
CHECK(fs::path("/a/b/c").lexically_relative("/a/b/c/d/..") == ".");
CHECK(fs::path("/a/b/c/").lexically_relative("/a/b/c/d/..") == ".");
CHECK(fs::path("").lexically_relative("/a/..") == "");
CHECK(fs::path("").lexically_relative("a/..") == ".");
CHECK(fs::path("a/b/c").lexically_relative("a") == "b/c"); CHECK(fs::path("a/b/c").lexically_relative("a") == "b/c");
CHECK(fs::path("a/b/c").lexically_relative("a/b/c/x/y") == "../.."); CHECK(fs::path("a/b/c").lexically_relative("a/b/c/x/y") == "../..");
CHECK(fs::path("a/b/c").lexically_relative("a/b/c") == "."); CHECK(fs::path("a/b/c").lexically_relative("a/b/c") == ".");
@ -1218,7 +1199,7 @@ TEST_CASE("fs.class.filesystem_error - class filesystem_error", "[filesystem][fi
CHECK(fse.path2() == "some/other"); CHECK(fse.path2() == "some/other");
} }
static constexpr fs::perms constExprOwnerAll() constexpr fs::perms constExprOwnerAll()
{ {
return fs::perms::owner_read | fs::perms::owner_write | fs::perms::owner_exec; return fs::perms::owner_read | fs::perms::owner_write | fs::perms::owner_exec;
} }
@ -1396,16 +1377,6 @@ TEST_CASE("fs.dir.entry - class directory_entry", "[filesystem][directory_entry]
CHECK(!(d2 != d2)); CHECK(!(d2 != d2));
CHECK(d1 == d1); CHECK(d1 == d1);
CHECK(!(d1 == d2)); CHECK(!(d1 == d2));
if(is_symlink_creation_supported()) {
fs::create_symlink(t.path() / "nonexistent", t.path() / "broken");
for (auto d3 : fs::directory_iterator(t.path())) {
CHECK_NOTHROW(d3.symlink_status());
CHECK_NOTHROW(d3.status());
CHECK_NOTHROW(d3.refresh());
}
fs::directory_entry entry(t.path() / "broken");
CHECK_NOTHROW(entry.refresh());
}
} }
TEST_CASE("fs.class.directory_iterator - class directory_iterator", "[filesystem][directory_iterator][fs.class.directory_iterator]") TEST_CASE("fs.class.directory_iterator - class directory_iterator", "[filesystem][directory_iterator][fs.class.directory_iterator]")
@ -1807,19 +1778,6 @@ TEST_CASE("fs.op.copy_file - copy_file", "[filesystem][operations][fs.op.copy_fi
CHECK_NOTHROW(fs::copy_file("foobar", "foobar2", ec)); CHECK_NOTHROW(fs::copy_file("foobar", "foobar2", ec));
CHECK(ec); CHECK(ec);
CHECK(!fs::exists("foobar")); CHECK(!fs::exists("foobar"));
fs::path file1("temp1.txt");
fs::path file2("temp2.txt");
generateFile(file1, 200);
generateFile(file2, 200);
auto allWrite = fs::perms::owner_write | fs::perms::group_write | fs::perms::others_write;
CHECK_NOTHROW(fs::permissions(file1, allWrite, fs::perm_options::remove));
CHECK((fs::status(file1).permissions() & fs::perms::owner_write) != fs::perms::owner_write);
CHECK_NOTHROW(fs::permissions(file2, allWrite, fs::perm_options::add));
CHECK((fs::status(file2).permissions() & fs::perms::owner_write) == fs::perms::owner_write);
fs::copy_file(file1, file2, fs::copy_options::overwrite_existing);
CHECK((fs::status(file2).permissions() & fs::perms::owner_write) != fs::perms::owner_write);
CHECK_NOTHROW(fs::permissions(file1, allWrite, fs::perm_options::add));
CHECK_NOTHROW(fs::permissions(file2, allWrite, fs::perm_options::add));
} }
TEST_CASE("fs.op.copy_symlink - copy_symlink", "[filesystem][operations][fs.op.copy_symlink]") TEST_CASE("fs.op.copy_symlink - copy_symlink", "[filesystem][operations][fs.op.copy_symlink]")