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_