1 // Copyright 2018 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #ifndef GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_INTERNAL_FILESYSTEM_H
16 #define GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_INTERNAL_FILESYSTEM_H
17 
18 #include "google/cloud/version.h"
19 #include <cinttypes>
20 #include <system_error>
21 
22 namespace google {
23 namespace cloud {
24 inline namespace GOOGLE_CLOUD_CPP_NS {
25 namespace internal {
26 
27 enum class file_type {
28   none = 0,   // NOLINT(readability-identifier-naming)
29   not_found,  // NOLINT(readability-identifier-naming)
30   regular,    // NOLINT(readability-identifier-naming)
31   directory,  // NOLINT(readability-identifier-naming)
32   symlink,    // NOLINT(readability-identifier-naming)
33   block,      // NOLINT(readability-identifier-naming)
34   character,  // NOLINT(readability-identifier-naming)
35   fifo,       // NOLINT(readability-identifier-naming)
36   socket,     // NOLINT(readability-identifier-naming)
37   unknown,    // NOLINT(readability-identifier-naming)
38 };
39 
40 enum class perms {
41   none = 0,             // NOLINT(readability-identifier-naming)
42   owner_read = 0400,    // NOLINT(readability-identifier-naming)
43   owner_write = 0200,   // NOLINT(readability-identifier-naming)
44   owner_exec = 0100,    // NOLINT(readability-identifier-naming)
45   owner_all = 0700,     // NOLINT(readability-identifier-naming)
46   group_read = 0040,    // NOLINT(readability-identifier-naming)
47   group_write = 0020,   // NOLINT(readability-identifier-naming)
48   group_exec = 0010,    // NOLINT(readability-identifier-naming)
49   group_all = 0070,     // NOLINT(readability-identifier-naming)
50   others_read = 0004,   // NOLINT(readability-identifier-naming)
51   others_write = 0002,  // NOLINT(readability-identifier-naming)
52   others_exec = 0001,   // NOLINT(readability-identifier-naming)
53   others_all = 0007,    // NOLINT(readability-identifier-naming)
54   all = 0777,           // NOLINT(readability-identifier-naming)
55   set_uid = 04000,      // NOLINT(readability-identifier-naming)
56   set_gid = 02000,      // NOLINT(readability-identifier-naming)
57   sticky_bit = 01000,   // NOLINT(readability-identifier-naming)
58   mask = 07777,         // NOLINT(readability-identifier-naming)
59 
60   unknown = 0xFFFF,  // NOLINT(readability-identifier-naming)
61 };
62 
63 inline perms operator&(perms lhs, perms rhs) {
64   return static_cast<perms>(static_cast<unsigned>(lhs) &
65                             static_cast<unsigned>(rhs));
66 }
67 
68 inline perms operator|(perms lhs, perms rhs) {
69   return static_cast<perms>(static_cast<unsigned>(lhs) |
70                             static_cast<unsigned>(rhs));
71 }
72 
73 inline perms operator^(perms lhs, perms rhs) {
74   return static_cast<perms>(static_cast<unsigned>(lhs) ^
75                             static_cast<unsigned>(rhs));
76 }
77 
78 inline perms operator~(perms lhs) {
79   return static_cast<perms>(static_cast<unsigned>(perms::mask) &
80                             ~static_cast<unsigned>(lhs));
81 }
82 
83 inline perms& operator&=(perms& lhs, perms rhs) {
84   lhs = lhs & rhs;
85   return lhs;
86 }
87 
88 inline perms operator|=(perms& lhs, perms rhs) {
89   lhs = lhs | rhs;
90   return lhs;
91 }
92 
93 inline perms operator^=(perms& lhs, perms rhs) {
94   lhs = lhs ^ rhs;
95   return lhs;
96 }
97 
98 /**
99  * A drop-in replacement for `std::filesystem::file_status`.
100  *
101  * Implement the C++17 `std::filesystem::file_status` class.
102  */
103 class file_status {  // NOLINT(readability-identifier-naming)
104  public:
file_status()105   file_status() noexcept : file_status(file_type::none) {}
106   explicit file_status(file_type type, perms permissions = perms::unknown)
type_(type)107       : type_(type), permissions_(permissions) {}
108   file_status(file_status const&) noexcept = default;
109   file_status(file_status&&) noexcept = default;
110   file_status& operator=(file_status const&) noexcept = default;
111   file_status& operator=(file_status&&) noexcept = default;
112 
type()113   file_type type() const noexcept { return type_; }
type(file_type type)114   void type(file_type type) noexcept { type_ = type; }
permissions()115   perms permissions() const noexcept { return permissions_; }
permissions(perms permissions)116   void permissions(perms permissions) noexcept { permissions_ = permissions; }
117 
118  private:
119   file_type type_;
120   perms permissions_;
121 };
122 
123 file_status status(std::string const& path);
124 file_status status(std::string const& path, std::error_code& ec) noexcept;
125 
status_known(file_status s)126 inline bool status_known(file_status s) noexcept {
127   return s.type() != file_type::none;
128 }
129 
is_block_file(file_status s)130 inline bool is_block_file(file_status s) noexcept {
131   return s.type() == file_type::block;
132 }
133 
is_character_file(file_status s)134 inline bool is_character_file(file_status s) noexcept {
135   return s.type() == file_type::character;
136 }
137 
is_directory(file_status s)138 inline bool is_directory(file_status s) noexcept {
139   return s.type() == file_type::directory;
140 }
141 
is_fifo(file_status s)142 inline bool is_fifo(file_status s) noexcept {
143   return s.type() == file_type::fifo;
144 }
145 
is_regular(file_status s)146 inline bool is_regular(file_status s) noexcept {
147   return s.type() == file_type::regular;
148 }
149 
is_socket(file_status s)150 inline bool is_socket(file_status s) noexcept {
151   return s.type() == file_type::socket;
152 }
153 
is_symlink(file_status s)154 inline bool is_symlink(file_status s) noexcept {
155   return s.type() == file_type::symlink;
156 }
157 
exists(file_status s)158 inline bool exists(file_status s) noexcept {
159   return status_known(s) && s.type() != file_type::not_found;
160 }
161 
is_other(file_status s)162 inline bool is_other(file_status s) noexcept {
163   return exists(s) && !is_regular(s) && !is_directory(s) && !is_symlink(s);
164 }
165 
166 std::uintmax_t file_size(std::string const& path);
167 std::uintmax_t file_size(std::string const& path, std::error_code& ec) noexcept;
168 
169 }  // namespace internal
170 }  // namespace GOOGLE_CLOUD_CPP_NS
171 }  // namespace cloud
172 }  // namespace google
173 
174 #endif  // GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_INTERNAL_FILESYSTEM_H
175