648db22b |
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 |
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 |
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 |
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 |
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 |
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 |
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 | } |