gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/test/util/fs_util.h (about) 1 // Copyright 2018 The gVisor Authors. 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 GVISOR_TEST_UTIL_FS_UTIL_H_ 16 #define GVISOR_TEST_UTIL_FS_UTIL_H_ 17 18 #include <dirent.h> 19 #include <sys/stat.h> 20 #include <sys/statfs.h> 21 #include <sys/types.h> 22 #include <unistd.h> 23 24 #include "gtest/gtest.h" 25 #include "absl/strings/string_view.h" 26 #include "test/util/file_descriptor.h" 27 #include "test/util/posix_error.h" 28 29 namespace gvisor { 30 namespace testing { 31 32 // O_LARGEFILE as defined by Linux. glibc tries to be clever by setting it to 0 33 // because "it isn't needed", even though Linux can return it via F_GETFL. 34 #if defined(__x86_64__) || defined(__riscv) 35 constexpr int kOLargeFile = 00100000; 36 #elif defined(__aarch64__) 37 constexpr int kOLargeFile = 00400000; 38 #else 39 #error "Unknown architecture" 40 #endif 41 42 // From linux/magic.h. For some reason, not defined in the headers for some 43 // build environments. 44 #define OVERLAYFS_SUPER_MAGIC 0x794c7630 45 46 // Returns a status or the current working directory. 47 PosixErrorOr<std::string> GetCWD(); 48 49 // Returns true/false depending on whether or not path exists, or an error if it 50 // can't be determined. 51 PosixErrorOr<bool> Exists(absl::string_view path); 52 53 // Returns a stat structure for the given path or an error. If the path 54 // represents a symlink, it will be traversed. 55 PosixErrorOr<struct stat> Stat(absl::string_view path); 56 57 // Returns a stat structure for the given path or an error. If the path 58 // represents a symlink, it will not be traversed. 59 PosixErrorOr<struct stat> Lstat(absl::string_view path); 60 61 // Returns a stat struct for the given fd. 62 PosixErrorOr<struct stat> Fstat(int fd); 63 64 // Deletes the file or directory at path or returns an error. 65 PosixError Delete(absl::string_view path); 66 67 // Changes the mode of a file or returns an error. 68 PosixError Chmod(absl::string_view path, int mode); 69 70 // Create a special or ordinary file. 71 PosixError MknodAt(const FileDescriptor& dfd, absl::string_view path, int mode, 72 dev_t dev); 73 74 // Unlink the file. 75 PosixError Unlink(absl::string_view path); 76 PosixError UnlinkAt(const FileDescriptor& dfd, absl::string_view path, 77 int flags); 78 79 // Truncates a file to the given length or returns an error. 80 PosixError Truncate(absl::string_view path, int length); 81 82 // Returns true/false depending on whether or not the path is a directory or 83 // returns an error. 84 PosixErrorOr<bool> IsDirectory(absl::string_view path); 85 86 // Makes a directory or returns an error. 87 PosixError Mkdir(absl::string_view path, int mode = 0755); 88 89 // Removes a directory or returns an error. 90 PosixError Rmdir(absl::string_view path); 91 92 // Attempts to set the contents of a file or returns an error. 93 PosixError SetContents(absl::string_view path, absl::string_view contents); 94 95 // Creates a file with the given contents and mode or returns an error. 96 PosixError CreateWithContents(absl::string_view path, 97 absl::string_view contents, int mode = 0666); 98 99 // Attempts to read the entire contents of the file into the provided string 100 // buffer or returns an error. 101 PosixError GetContents(absl::string_view path, std::string* output); 102 103 // Attempts to read the entire contents of the file or returns an error. 104 PosixErrorOr<std::string> GetContents(absl::string_view path); 105 106 // Attempts to read the entire contents of the provided fd into the provided 107 // string or returns an error. 108 PosixError GetContentsFD(int fd, std::string* output); 109 110 // Attempts to read the entire contents of the provided fd or returns an error. 111 PosixErrorOr<std::string> GetContentsFD(int fd); 112 113 // Executes the readlink(2) system call or returns an error. 114 PosixErrorOr<std::string> ReadLink(absl::string_view path); 115 116 // WalkTree will walk a directory tree in a depth first search manner (if 117 // recursive). It will invoke a provided callback for each file and directory, 118 // the parent will always be invoked last making this appropriate for things 119 // such as deleting an entire directory tree. 120 // 121 // This method will return an error when it's unable to access the provided 122 // path, or when the path is not a directory. 123 PosixError WalkTree( 124 absl::string_view path, bool recursive, 125 const std::function<void(absl::string_view, const struct stat&)>& cb); 126 127 // Returns the base filenames for all files under a given absolute path. If 128 // skipdots is true the returned vector will not contain "." or "..". This 129 // method does not walk the tree recursively it only returns the elements 130 // in that directory. 131 PosixErrorOr<std::vector<std::string>> ListDir(absl::string_view abspath, 132 bool skipdots); 133 134 // Check that a directory contains children nodes named in expect, and does not 135 // contain any children nodes named in exclude. 136 PosixError DirContains(absl::string_view path, 137 const std::vector<std::string>& expect, 138 const std::vector<std::string>& exclude); 139 140 // Same as DirContains, but adds a retry. Suitable for checking a directory 141 // being modified asynchronously. 142 PosixError EventuallyDirContains(absl::string_view path, 143 const std::vector<std::string>& expect, 144 const std::vector<std::string>& exclude); 145 146 // Attempt to recursively delete a directory or file. Returns an error and 147 // the number of undeleted directories and files. If either 148 // undeleted_dirs or undeleted_files is nullptr then it will not be used. 149 PosixError RecursivelyDelete(absl::string_view path, int* undeleted_dirs, 150 int* undeleted_files); 151 152 // Recursively create the directory provided or return an error. 153 PosixError RecursivelyCreateDir(absl::string_view path); 154 155 // Makes a path absolute with respect to an optional base. If no base is 156 // provided it will use the current working directory. 157 PosixErrorOr<std::string> MakeAbsolute(absl::string_view filename, 158 absl::string_view base); 159 160 // Generates a relative path from the source directory to the destination 161 // (dest) file or directory. This uses ../ when necessary for destinations 162 // which are not nested within the source. Both source and dest are required 163 // to be absolute paths, and an empty string will be returned if they are not. 164 PosixErrorOr<std::string> GetRelativePath(absl::string_view source, 165 absl::string_view dest); 166 167 // Returns the part of the path before the final "/", EXCEPT: 168 // * If there is a single leading "/" in the path, the result will be the 169 // leading "/". 170 // * If there is no "/" in the path, the result is the empty prefix of the 171 // input string. 172 absl::string_view Dirname(absl::string_view path); 173 174 // Return the parts of the path, split on the final "/". If there is no 175 // "/" in the path, the first part of the output is empty and the second 176 // is the input. If the only "/" in the path is the first character, it is 177 // the first part of the output. 178 std::pair<absl::string_view, absl::string_view> SplitPath( 179 absl::string_view path); 180 181 // Returns the part of the path after the final "/". If there is no 182 // "/" in the path, the result is the same as the input. 183 // Note that this function's behavior differs from the Unix basename 184 // command if path ends with "/". For such paths, this function returns the 185 // empty string. 186 absl::string_view Basename(absl::string_view path); 187 188 // Collapse duplicate "/"s, resolve ".." and "." path elements, remove 189 // trailing "/". 190 // 191 // NOTE: This respects relative vs. absolute paths, but does not 192 // invoke any system calls (getcwd(2)) in order to resolve relative 193 // paths wrt actual working directory. That is, this is purely a 194 // string manipulation, completely independent of process state. 195 std::string CleanPath(absl::string_view path); 196 197 // Returns the full path to the executable of the given pid or a PosixError. 198 PosixErrorOr<std::string> ProcessExePath(int pid); 199 200 #ifdef __linux__ 201 // IsTmpfs returns true if the file at path is backed by tmpfs. 202 PosixErrorOr<bool> IsTmpfs(const std::string& path); 203 #endif // __linux__ 204 205 // IsOverlayfs returns true if the file at path is backed by overlayfs. 206 PosixErrorOr<bool> IsOverlayfs(const std::string& path); 207 208 PosixError CheckSameFile(const FileDescriptor& fd1, const FileDescriptor& fd2); 209 210 namespace internal { 211 // Not part of the public API. 212 std::string JoinPathImpl(std::initializer_list<absl::string_view> paths); 213 } // namespace internal 214 215 // Join multiple paths together. 216 // All paths will be treated as relative paths, regardless of whether or not 217 // they start with a leading '/'. That is, all paths will be concatenated 218 // together, with the appropriate path separator inserted in between. 219 // Arguments must be convertible to absl::string_view. 220 // 221 // Usage: 222 // std::string path = JoinPath("/foo", dirname, filename); 223 // std::string path = JoinPath(::testing::SrcDir(), filename); 224 // 225 // 0, 1, 2-path specializations exist to optimize common cases. 226 inline std::string JoinPath() { return std::string(); } 227 inline std::string JoinPath(absl::string_view path) { 228 return std::string(path.data(), path.size()); 229 } 230 231 std::string JoinPath(absl::string_view path1, absl::string_view path2); 232 template <typename... T> 233 inline std::string JoinPath(absl::string_view path1, absl::string_view path2, 234 absl::string_view path3, const T&... args) { 235 return internal::JoinPathImpl({path1, path2, path3, args...}); 236 } 237 238 // A matcher which checks whether the file permissions bits for a mode value 239 // matches an expected value. 240 class ModePermissionMatcher : public ::testing::MatcherInterface<mode_t> { 241 public: 242 explicit ModePermissionMatcher(mode_t want) : want_(want) {} 243 244 bool MatchAndExplain( 245 mode_t got, 246 ::testing::MatchResultListener* const listener) const override { 247 const mode_t masked = got & (S_IRWXU | S_IRWXG | S_IRWXO); 248 if (masked == want_) { 249 return true; 250 } 251 *listener << "Permission 0" << std::oct << masked; 252 return false; 253 } 254 255 void DescribeTo(std::ostream* const os) const override { 256 *os << "File permission is 0" << std::oct << want_; 257 } 258 259 void DescribeNegationTo(std::ostream* const os) const override { 260 *os << "File permission is not 0" << std::oct << want_; 261 } 262 263 private: 264 mode_t want_; 265 }; 266 267 ::testing::Matcher<mode_t> PermissionIs(mode_t want); 268 269 } // namespace testing 270 } // namespace gvisor 271 #endif // GVISOR_TEST_UTIL_FS_UTIL_H_