1 /* 2 * Copyright (c) Meta Platforms, Inc. and affiliates. 3 * All rights reserved. 4 * 5 * This source code is licensed under both the BSD-style license (found in the 6 * LICENSE file in the root directory of this source tree) and the GPLv2 (found 7 * in the COPYING file in the root directory of this source tree). 8 */ 9 #pragma once 10 11 #include "utils/Portability.h" 12 #include "utils/Range.h" 13 14 #include <sys/stat.h> 15 #include <cerrno> 16 #include <cstdint> 17 #include <limits> 18 #include <system_error> 19 20 // A small subset of `std::filesystem`. 21 // `std::filesystem` should be a drop in replacement. 22 // See https://en.cppreference.com/w/cpp/filesystem for documentation. 23 24 namespace pzstd { 25 26 // using file_status = ... causes gcc to emit a false positive warning 27 #if defined(_MSC_VER) 28 typedef struct ::_stat64 file_status; 29 #else 30 typedef struct ::stat file_status; 31 #endif 32 33 /// https://en.cppreference.com/w/cpp/filesystem/status status(StringPiece path,std::error_code & ec)34 inline file_status status(StringPiece path, std::error_code& ec) noexcept { 35 file_status status; 36 #if defined(_MSC_VER) 37 const auto error = ::_stat64(path.data(), &status); 38 #else 39 const auto error = ::stat(path.data(), &status); 40 #endif 41 if (error) { 42 ec.assign(errno, std::generic_category()); 43 } else { 44 ec.clear(); 45 } 46 return status; 47 } 48 49 /// https://en.cppreference.com/w/cpp/filesystem/is_regular_file is_regular_file(file_status status)50 inline bool is_regular_file(file_status status) noexcept { 51 #if defined(S_ISREG) 52 return S_ISREG(status.st_mode); 53 #elif !defined(S_ISREG) && defined(S_IFMT) && defined(S_IFREG) 54 return (status.st_mode & S_IFMT) == S_IFREG; 55 #else 56 static_assert(false, "No POSIX stat() support."); 57 #endif 58 } 59 60 /// https://en.cppreference.com/w/cpp/filesystem/is_regular_file is_regular_file(StringPiece path,std::error_code & ec)61 inline bool is_regular_file(StringPiece path, std::error_code& ec) noexcept { 62 return is_regular_file(status(path, ec)); 63 } 64 65 /// https://en.cppreference.com/w/cpp/filesystem/is_directory is_directory(file_status status)66 inline bool is_directory(file_status status) noexcept { 67 #if defined(S_ISDIR) 68 return S_ISDIR(status.st_mode); 69 #elif !defined(S_ISDIR) && defined(S_IFMT) && defined(S_IFDIR) 70 return (status.st_mode & S_IFMT) == S_IFDIR; 71 #else 72 static_assert(false, "NO POSIX stat() support."); 73 #endif 74 } 75 76 /// https://en.cppreference.com/w/cpp/filesystem/is_directory is_directory(StringPiece path,std::error_code & ec)77 inline bool is_directory(StringPiece path, std::error_code& ec) noexcept { 78 return is_directory(status(path, ec)); 79 } 80 81 /// https://en.cppreference.com/w/cpp/filesystem/file_size file_size(StringPiece path,std::error_code & ec)82 inline std::uintmax_t file_size( 83 StringPiece path, 84 std::error_code& ec) noexcept { 85 auto stat = status(path, ec); 86 if (ec) { 87 return std::numeric_limits<uintmax_t>::max(); 88 } 89 if (!is_regular_file(stat)) { 90 ec.assign(ENOTSUP, std::generic_category()); 91 return std::numeric_limits<uintmax_t>::max(); 92 } 93 ec.clear(); 94 return stat.st_size; 95 } 96 } 97