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_instance:
image_family: freebsd-14-0
image_family: freebsd-12-1
install_script: |
pkg install -y cmake
pw groupadd testgrp
@ -11,24 +11,25 @@ freebsd_task:
test_script: |
sudo -u testuser .ci/unix-test.sh
rockylinux8_task:
centos7_task:
container:
image: docker.io/rockylinux:8
image: centos:7
install_script: |
dnf group install -y "Development Tools"
dnf install cmake -y
yum install -y centos-release-scl
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: |
.ci/unix-build.sh
source /opt/rh/devtoolset-9/enable && PATH=$PATH:/usr/local/bin .ci/unix-build.sh
test_script: |
.ci/unix-test.sh
PATH=$PATH:/usr/local/bin .ci/unix-test.sh
rockylinux9_task:
centos8_task:
container:
image: docker.io/rockylinux:9
image: quay.io/centos/centos:stream8
install_script: |
dnf group install -y "Development Tools"
dnf install cmake -y
yum group install -y "Development Tools"
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: |
.ci/unix-build.sh
PATH=$PATH:/usr/local/bin .ci/unix-build.sh
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
matrix:
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"
os: ubuntu-20.04
build_type: Release
@ -82,6 +46,69 @@ jobs:
cc: gcc
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"
os: windows-2019
build_type: Release
@ -91,12 +118,21 @@ jobs:
cc: cl
cxx: cl
- name: "macOS 13 AppleClang"
os: macos-13
- name: "macOS 10.15 AppleClang"
os: macos-10.15
build_type: Release
packages: 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
cxx: clang++

View File

@ -1,8 +1,5 @@
cmake_minimum_required(VERSION 3.7.2)
project(
ghcfilesystem,
VERSION 1.5.15
)
project(ghcfilesystem)
if (POLICY CMP0077)
cmake_policy(SET CMP0077 NEW)
@ -18,7 +15,7 @@ if(CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR)
else()
option(GHC_FILESYSTEM_BUILD_EXAMPLES "Build examples" 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()
option(GHC_FILESYSTEM_BUILD_STD_TESTING "Enable STD tests" ${GHC_FILESYSTEM_BUILD_TESTING})
if(NOT DEFINED GHC_FILESYSTEM_TEST_COMPILE_FEATURES)
@ -35,14 +32,11 @@ endif()
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.")
endif()
if(CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR)
message(STATUS "System name: ${CMAKE_SYSTEM_NAME}")
message(STATUS "Compiler ID: ${CMAKE_CXX_COMPILER_ID}")
message(STATUS "CMAKE_CXX_COMPILE_FEATURES: ${CMAKE_CXX_COMPILE_FEATURES}")
endif()
message(STATUS "System name: ${CMAKE_SYSTEM_NAME}")
message(STATUS "Compiler ID: ${CMAKE_CXX_COMPILER_ID}")
message(STATUS "CMAKE_CXX_COMPILE_FEATURES: ${CMAKE_CXX_COMPILE_FEATURES}")
add_library(ghc_filesystem INTERFACE)
add_library(ghcFilesystem::ghc_filesystem ALIAS ghc_filesystem)
target_include_directories(ghc_filesystem INTERFACE
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>)
@ -76,15 +70,7 @@ if(GHC_FILESYSTEM_WITH_INSTALL)
"${PROJECT_BINARY_DIR}/cmake/ghc_filesystem-config.cmake"
INSTALL_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/ghc_filesystem"
PATH_VARS CMAKE_INSTALL_INCLUDEDIR)
write_basic_package_version_file(
"${PROJECT_BINARY_DIR}/cmake/ghc_filesystem-config-version.cmake"
VERSION ${PROJECT_VERSION}
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"
)
install(FILES "${PROJECT_BINARY_DIR}/cmake/ghc_filesystem-config.cmake"
DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/ghc_filesystem")
add_library(ghcFilesystem::ghc_filesystem ALIAS ghc_filesystem)
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)
[![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://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)
[![Latest Release Tag](https://img.shields.io/github/tag/gulrak/filesystem.svg)](https://github.com/gulrak/filesystem/tree/v1.5.14)
<!-- [![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 -->
[![Latest Release Tag](https://img.shields.io/github/tag/gulrak/filesystem.svg)](https://github.com/gulrak/filesystem/tree/v1.5.12)
- [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
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
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
is experimental support for QNX. The support of Android NDK, Emscripten, QNX, and since 1.5.14
GNU/Hurd and Haiku is not backed up by automated testing but PRs and bug reports are welcome
for those too and they are reported to work.
is experimental support for QNX. The support of Android NDK, Emscripten and QNX is not
backed up by automated testing but PRs and bug reports are welcome for those too.
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).
@ -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
* 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 (Alpine ARM/ARM64): GCC 9.2.0~~ (The Drone build scripts stopped working,
as they where a contribution, I couldn't figure out what went wrong, any help appreciated.)
* Linux (Alpine ARM/ARM64): GCC 9.2.0
* FreeBSD: Clang 8.0
* Solaris: GCC 5.5
@ -154,8 +149,8 @@ in the standard, and there might be issues in these implementations too.
### Downloads
The latest release version is [v1.5.14](https://github.com/gulrak/filesystem/tree/v1.5.14) and
source archives can be found [here](https://github.com/gulrak/filesystem/releases/tag/v1.5.14).
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.12).
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).
@ -176,83 +171,60 @@ Everything is in the namespace `ghc::filesystem`, so one way to use it only as
a fallback could be:
```cpp
#if _MSVC_LANG >= 201703L || __cplusplus >= 201703L && defined(__has_include)
// ^ 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 __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
#ifdef __APPLE__
#include <Availability.h> // for deployment target to support pre-catalina targets without std::fs
#endif
#ifdef GHC_USE_STD_FS
#include <filesystem>
namespace fs = std::filesystem;
#else
#include "filesystem.hpp"
namespace fs = ghc::filesystem;
#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
```
**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,
you might use:
```cpp
#if _MSVC_LANG >= 201703L || __cplusplus >= 201703L && defined(__has_include)
// ^ 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 __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
#ifdef __APPLE__
#include <Availability.h> // for deployment target to support pre-catalina targets without std::fs
#endif
#ifdef GHC_USE_STD_FS
#include <filesystem>
namespace fs {
using namespace std::filesystem;
using ifstream = std::ifstream;
using ofstream = std::ofstream;
using fstream = std::fstream;
}
#else
#include "filesystem.hpp"
namespace fs {
using namespace ghc::filesystem;
using ifstream = ghc::filesystem::ifstream;
using ofstream = ghc::filesystem::ofstream;
using fstream = ghc::filesystem::fstream;
}
#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 {
using namespace std::filesystem;
using ifstream = std::ifstream;
using ofstream = std::ofstream;
using fstream = std::fstream;
}
#endif
#endif
#ifndef GHC_USE_STD_FS
#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
```
@ -292,46 +264,29 @@ If you use the forwarding/implementation approach, you can still use the dynamic
switching like this:
```cpp
#if _MSVC_LANG >= 201703L || __cplusplus >= 201703L && defined(__has_include)
// ^ 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 __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
#ifdef __APPLE__
#include <Availability.h> // for deployment target to support pre-catalina targets without std::fs
#endif
#ifdef GHC_USE_STD_FS
#include <filesystem>
namespace fs {
using namespace std::filesystem;
using ifstream = std::ifstream;
using ofstream = std::ofstream;
using fstream = std::fstream;
}
#else
#include "fs_fwd.hpp"
namespace fs {
using namespace ghc::filesystem;
using ifstream = ghc::filesystem::ifstream;
using ofstream = ghc::filesystem::ofstream;
using fstream = ghc::filesystem::fstream;
}
#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 {
using namespace std::filesystem;
using ifstream = std::ifstream;
using ofstream = std::ofstream;
using fstream = std::fstream;
}
#endif
#endif
#ifndef GHC_USE_STD_FS
#include <ghc/fs-fwd.hpp>
namespace fs {
using namespace ghc::filesystem;
using ifstream = ghc::filesystem::ifstream;
using ofstream = ghc::filesystem::ofstream;
using fstream = ghc::filesystem::fstream;
}
#endif
```
@ -339,38 +294,25 @@ and in the implementation hiding cpp, you might use (before any include that inc
to take precedence:
```cpp
#if _MSVC_LANG >= 201703L || __cplusplus >= 201703L && defined(__has_include)
// ^ 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 __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
#ifdef __APPLE__ // for deployment target to support pre-catalina targets without std::fs
#include <Availability.h>
#endif
#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
#endif
#endif
#ifndef GHC_USE_STD_FS
#include "fs_impl.hpp"
#define GHC_FILESYSTEM_IMPLEMENTATION
#include <ghc/filesystem.hpp>
#endif
```
: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
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
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
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);
}
// 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;
@ -646,49 +584,6 @@ to the expected behavior.
## 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)
* 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)")
target_link_libraries(filesystem_test xnet)
endif()
if(${CMAKE_SYSTEM_NAME} MATCHES "Haiku")
target_link_libraries(filesystem_test network)
endif()
target_compile_definitions(${targetName} PRIVATE USE_STD_FS)
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)")
target_link_libraries(${targetName} xnet)
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_definitions(${targetName} PRIVATE USE_STD_FS)
endif()
@ -61,9 +55,6 @@ macro(AddTestExecutableWithStdCpp cppStd)
if(${CMAKE_SYSTEM_NAME} MATCHES "(SunOS|Solaris)")
target_link_libraries(filesystem_test_cpp${cppStd} xnet)
endif()
if(${CMAKE_SYSTEM_NAME} MATCHES "Haiku")
target_link_libraries(filesystem_test_cpp${cppStd} network)
endif()
target_compile_options(filesystem_test_cpp${cppStd} PRIVATE
$<$<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>

View File

@ -25,6 +25,23 @@
// 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
#define GHC_FILESYSTEM_H
@ -36,7 +53,7 @@
#ifndef GHC_OS_DETECTED
#if defined(__APPLE__) && defined(__MACH__)
#define GHC_OS_APPLE
#define GHC_OS_MACOS
#elif defined(__linux__)
#define GHC_OS_LINUX
#if defined(__ANDROID__)
@ -61,8 +78,6 @@
#include <wasi/api.h>
#elif defined(__QNX__)
#define GHC_OS_QNX
#elif defined(__HAIKU__)
#define GHC_OS_HAIKU
#else
#error "Operating system currently not supported!"
#endif
@ -164,7 +179,7 @@
#include <langinfo.h>
#endif
#endif
#ifdef GHC_OS_APPLE
#ifdef GHC_OS_MACOS
#include <Availability.h>
#endif
@ -291,7 +306,7 @@
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// 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))
#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;
#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
template <class charT, class traits = std::char_traits<charT>>
class basic_filebuf : public std::basic_filebuf<charT, traits>
@ -1157,7 +1168,7 @@ public:
const basic_filebuf& operator=(const basic_filebuf&) = delete;
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;
#else
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:
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)
: std::basic_ifstream<charT, traits>(p.wstring().c_str(), mode)
{
@ -1193,7 +1204,7 @@ class basic_ofstream : public std::basic_ofstream<charT, traits>
{
public:
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)
: std::basic_ofstream<charT, traits>(p.wstring().c_str(), mode)
{
@ -1216,7 +1227,7 @@ class basic_fstream : public std::basic_fstream<charT, traits>
{
public:
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)
: 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
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wcast-function-type"
#elif defined(_MSC_VER) && !defined(__INTEL_COMPILER) && !defined(__clang__)
#pragma warning(push)
#pragma warning(disable : 4191)
#endif
static CreateSymbolicLinkW_fp api_call = reinterpret_cast<CreateSymbolicLinkW_fp>(GetProcAddress(GetModuleHandleW(L"kernel32.dll"), "CreateSymbolicLinkW"));
#if defined(__GNUC__) && __GNUC__ >= 8
#pragma GCC diagnostic pop
#elif defined(_MSC_VER) && !defined(__INTEL_COMPILER) && !defined(__clang__)
#pragma warning(pop)
#endif
if (api_call) {
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
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wcast-function-type"
#elif defined(_MSC_VER) && !defined(__INTEL_COMPILER) && !defined(__clang__)
#pragma warning(push)
#pragma warning(disable : 4191)
#endif
static CreateHardLinkW_fp api_call = reinterpret_cast<CreateHardLinkW_fp>(GetProcAddress(GetModuleHandleW(L"kernel32.dll"), "CreateHardLinkW"));
#if defined(__GNUC__) && __GNUC__ >= 8
#pragma GCC diagnostic pop
#elif defined(_MSC_VER) && !defined(__INTEL_COMPILER) && !defined(__clang__)
#pragma warning(pop)
#endif
if (api_call) {
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)
{
ULARGE_INTEGER ull;
ull.QuadPart = static_cast<ULONGLONG>((t * 10000000LL) + 116444736000000000LL);
ft.dwLowDateTime = ull.LowPart;
ft.dwHighDateTime = ull.HighPart;
LONGLONG ll;
ll = Int32x32To64(t, 10000000) + 116444736000000000;
ft.dwLowDateTime = static_cast<DWORD>(ll);
ft.dwHighDateTime = static_cast<DWORD>(ll >> 32);
}
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>
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)) {
auto reparseData = detail::getReparseData(p, ec);
if (!ec && reparseData && IsReparseTagMicrosoft(reparseData->ReparseTag) && reparseData->ReparseTag == IO_REPARSE_TAG_SYMLINK) {
return true;
}
}
return false;
return 0;
}
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
// 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;
return info->dwReserved0;
}
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)
{
file_type ft = file_type::unknown;
if (is_symlink_from_INFO(p, info, ec)) {
ft = file_type::symlink;
}
else if ((info->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
ft = file_type::directory;
if (sizeof(INFO) == sizeof(WIN32_FIND_DATAW)) {
if (detail::reparse_tag_from_INFO(info) == IO_REPARSE_TAG_SYMLINK) {
ft = file_type::symlink;
}
}
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;
if (!(info->dwFileAttributes & FILE_ATTRIBUTE_READONLY)) {
@ -3157,7 +3156,7 @@ GHC_INLINE path path::extension() const
auto iter = end();
const auto& fn = *--iter;
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);
}
}
@ -3306,9 +3305,6 @@ GHC_INLINE path path::lexically_relative(const path& base) const
--count;
}
}
if (count == 0 && (a == end() || a->empty())) {
return path(".");
}
if (count < 0) {
return path();
}
@ -3369,14 +3365,10 @@ GHC_INLINE path::impl_string_type::const_iterator path::iterator::increment(cons
}
}
else {
#ifdef GHC_OS_WINDOWS
if (fromStart && i != _last && *i == ':') {
++i;
}
else {
#else
{
#endif
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;
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 ((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) {
auto from_time = last_write_time(from, ec);
if (ec) {
@ -3967,33 +3956,15 @@ GHC_INLINE bool copy_file(const path& from, const path& to, copy_options options
::close(in);
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;
while (true) {
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;
}
while ((br = ::read(in, buffer.data(), buffer.size())) > 0) {
ssize_t offset = 0;
do {
if ((bw = ::write(out, buffer.data() + offset, static_cast<size_t>(br))) > 0) {
br -= bw;
offset += bw;
}
else if (bw < 0 && errno != EINTR) {
else if (bw < 0) {
ec = detail::make_system_error();
::close(in);
::close(out);
@ -4228,13 +4199,6 @@ GHC_INLINE path current_path(std::error_code& ec)
return path();
}
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
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]);
@ -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)) {
ec = detail::make_system_error();
}
#elif defined(GHC_OS_APPLE) && \
(__MAC_OS_X_VERSION_MIN_REQUIRED && __MAC_OS_X_VERSION_MIN_REQUIRED < 101300 \
|| __IPHONE_OS_VERSION_MIN_REQUIRED && __IPHONE_OS_VERSION_MIN_REQUIRED < 110000 \
|| __TV_OS_VERSION_MIN_REQUIRED && __TVOS_VERSION_MIN_REQUIRED < 110000 \
|| __WATCH_OS_VERSION_MIN_REQUIRED && __WATCHOS_VERSION_MIN_REQUIRED < 40000)
#elif defined(GHC_OS_MACOS)
#ifdef __MAC_OS_X_VERSION_MIN_REQUIRED
#if __MAC_OS_X_VERSION_MIN_REQUIRED < 101300
struct ::stat fs;
if (::stat(p.c_str(), &fs) == 0) {
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();
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
#ifndef UTIME_OMIT
#define UTIME_OMIT ((1l << 30) - 2l)
@ -5285,7 +5259,7 @@ GHC_INLINE void directory_entry::refresh()
{
std::error_code 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);
}
}
@ -5696,7 +5670,7 @@ public:
, _entry(nullptr)
{
if (!path.empty()) {
do { _dir = ::opendir(path.native().c_str()); } while(errno == EINTR && !_dir);
_dir = ::opendir(path.native().c_str());
if (!_dir) {
auto error = errno;
_base = filesystem::path();
@ -5723,7 +5697,7 @@ public:
do {
skip = false;
errno = 0;
do { _entry = ::readdir(_dir); } while(errno == EINTR && !_entry);
_entry = ::readdir(_dir);
if (_entry) {
_dir_entry._path = _base;
_dir_entry._path.append_name(_entry->d_name);
@ -5737,7 +5711,7 @@ public:
::closedir(_dir);
_dir = nullptr;
_dir_entry._path.clear();
if (errno && errno != EINTR) {
if (errno) {
ec = detail::make_system_error();
}
break;

View File

@ -25,7 +25,7 @@
// 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.
// 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,
@ -34,5 +34,5 @@
#ifndef GHC_FILESYSTEM_FWD_H
#define GHC_FILESYSTEM_FWD_H
#define GHC_FILESYSTEM_FWD
#include "filesystem.hpp"
#include <ghc/filesystem.hpp>
#endif // GHC_FILESYSTEM_FWD_H

View File

@ -25,11 +25,11 @@
// 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.
// 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
// header to work.
//---------------------------------------------------------------------------------------
#define GHC_FILESYSTEM_IMPLEMENTATION
#include "filesystem.hpp"
#include <ghc/filesystem.hpp>

View File

@ -31,47 +31,30 @@
//---------------------------------------------------------------------------------------
#ifndef GHC_FILESYSTEM_STD_H
#define GHC_FILESYSTEM_STD_H
#if defined(_MSVC_LANG) && _MSVC_LANG >= 201703L || __cplusplus >= 201703L && defined(__has_include)
// ^ 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
#if defined(__APPLE__)
#include <Availability.h>
#endif
#ifdef GHC_USE_STD_FS
#include <filesystem>
namespace fs {
using namespace std::filesystem;
using ifstream = std::ifstream;
using ofstream = std::ofstream;
using fstream = std::fstream;
}
#else
#include "filesystem.hpp"
namespace fs {
using namespace ghc::filesystem;
using ifstream = ghc::filesystem::ifstream;
using ofstream = ghc::filesystem::ofstream;
using fstream = ghc::filesystem::fstream;
}
#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 {
using namespace std::filesystem;
using ifstream = std::ifstream;
using ofstream = std::ofstream;
using fstream = std::fstream;
}
#endif
#endif
#ifndef GHC_USE_STD_FS
//#define GHC_WIN_DISABLE_WSTRING_STORAGE_TYPE
#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 // GHC_FILESYSTEM_STD_H

View File

@ -25,7 +25,7 @@
// 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.
// 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,
@ -33,47 +33,31 @@
//---------------------------------------------------------------------------------------
#ifndef GHC_FILESYSTEM_STD_FWD_H
#define GHC_FILESYSTEM_STD_FWD_H
#if defined(_MSVC_LANG) && _MSVC_LANG >= 201703L || __cplusplus >= 201703L && defined(__has_include)
// ^ 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
#if defined(__APPLE__)
#include <Availability.h>
#endif
#ifdef GHC_USE_STD_FS
#include <filesystem>
namespace fs {
using namespace std::filesystem;
using ifstream = std::ifstream;
using ofstream = std::ofstream;
using fstream = std::fstream;
}
#else
#include "fs_fwd.hpp"
namespace fs {
using namespace ghc::filesystem;
using ifstream = ghc::filesystem::ifstream;
using ofstream = ghc::filesystem::ofstream;
using fstream = ghc::filesystem::fstream;
}
#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 {
using namespace std::filesystem;
using ifstream = std::ifstream;
using ofstream = std::ofstream;
using fstream = std::fstream;
}
#endif
#endif
#ifndef GHC_USE_STD_FS
//#define GHC_WIN_DISABLE_WSTRING_STORAGE_TYPE
#define GHC_FILESYSTEM_FWD
#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 // GHC_FILESYSTEM_STD_FWD_H

View File

@ -25,36 +25,22 @@
// 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.
// 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
// header to work.
//---------------------------------------------------------------------------------------
#if defined(_MSVC_LANG) && _MSVC_LANG >= 201703L || __cplusplus >= 201703L && defined(__has_include)
// ^ 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
#if defined(__APPLE__)
#include <Availability.h>
#endif
#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
#endif
#endif
#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

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)
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)
target_compile_options(${target_name} PRIVATE
$<$<BOOL:${EMSCRIPTEN}>:-s DISABLE_EXCEPTION_CATCHING=0>
@ -30,9 +25,6 @@ if(GHC_COVERAGE)
if(${CMAKE_SYSTEM_NAME} MATCHES "(SunOS|Solaris)")
target_link_libraries(filesystem_test PUBLIC xnet)
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)
AddTestExecutableWithStdCpp(17 filesystem_test.cpp catch.hpp)
endif()
@ -46,9 +38,6 @@ else()
if(${CMAKE_SYSTEM_NAME} MATCHES "(SunOS|Solaris)")
target_link_libraries(filesystem_test xnet)
endif()
if(${CMAKE_SYSTEM_NAME} MATCHES "Haiku")
target_link_libraries(filesystem_test network)
endif()
SetTestCompileOptions(filesystem_test)
if(CMAKE_CXX_COMPILER_ID MATCHES MSVC)
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)")
target_link_libraries(fwd_impl_test xnet)
endif()
if(${CMAKE_SYSTEM_NAME} MATCHES "Haiku")
target_link_libraries(fwd_impl_test network)
endif()
SetTestCompileOptions(fwd_impl_test)
if(CMAKE_CXX_COMPILER_ID MATCHES MSVC)
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>
static std::time_t to_time_t(TP tp)
std::time_t to_time_t(TP tp)
{
using namespace std::chrono;
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>
static TP from_time_t(std::time_t t)
TP from_time_t(std::time_t t)
{
using namespace std::chrono;
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
#if !defined(_WIN64) && defined(KEY_WOW64_64KEY)
static bool isWow64Proc()
inline bool isWow64Proc()
{
typedef BOOL(WINAPI * IsWow64Process_t)(HANDLE, PBOOL);
BOOL bIsWow64 = FALSE;
@ -227,7 +226,6 @@ static bool isWow64Proc()
}
return bIsWow64 == TRUE;
}
#endif
static bool is_symlink_creation_supported()
{
@ -305,13 +303,13 @@ public:
};
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;
}
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);
}
@ -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("t:est.txt").filename() == "est.txt");
#else
CHECK(fs::path("t:est.txt").filename() == "t:est.txt");
#endif
// 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(".bar").stem() == ".bar");
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()
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(".bar").extension() == "");
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()) {
// //host-based root-names
@ -965,10 +950,6 @@ TEST_CASE("fs.path.gen - path generation", "[filesystem][path][fs.path.gen]")
// lexically_relative()
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/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/x/y") == "../..");
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");
}
static constexpr fs::perms constExprOwnerAll()
constexpr fs::perms constExprOwnerAll()
{
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(d1 == d1);
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]")
@ -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(ec);
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]")