gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/test/syscalls/linux/getdents.cc (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  #include <dirent.h>
    16  #include <errno.h>
    17  #include <fcntl.h>
    18  #include <stddef.h>
    19  #include <stdint.h>
    20  #include <stdio.h>
    21  #include <string.h>
    22  #include <sys/mman.h>
    23  #include <sys/types.h>
    24  #include <syscall.h>
    25  #include <unistd.h>
    26  
    27  #include <map>
    28  #include <string>
    29  #include <unordered_map>
    30  #include <unordered_set>
    31  #include <utility>
    32  
    33  #include "gmock/gmock.h"
    34  #include "gtest/gtest.h"
    35  #include "absl/container/node_hash_map.h"
    36  #include "absl/container/node_hash_set.h"
    37  #include "absl/strings/numbers.h"
    38  #include "absl/strings/str_cat.h"
    39  #include "test/util/eventfd_util.h"
    40  #include "test/util/file_descriptor.h"
    41  #include "test/util/fs_util.h"
    42  #include "test/util/logging.h"
    43  #include "test/util/posix_error.h"
    44  #include "test/util/save_util.h"
    45  #include "test/util/temp_path.h"
    46  #include "test/util/test_util.h"
    47  
    48  using ::testing::Contains;
    49  using ::testing::IsEmpty;
    50  using ::testing::IsSupersetOf;
    51  using ::testing::Not;
    52  using ::testing::NotNull;
    53  
    54  namespace gvisor {
    55  namespace testing {
    56  
    57  namespace {
    58  
    59  // New Linux dirent format.
    60  struct linux_dirent64 {
    61    uint64_t d_ino;           // Inode number
    62    int64_t d_off;            // Offset to next linux_dirent64
    63    unsigned short d_reclen;  // NOLINT, Length of this linux_dirent64
    64    unsigned char d_type;     // NOLINT, File type
    65    char d_name[0];           // Filename (null-terminated)
    66  };
    67  
    68  // Old Linux dirent format.
    69  struct linux_dirent {
    70    unsigned long d_ino;      // NOLINT
    71    unsigned long d_off;      // NOLINT
    72    unsigned short d_reclen;  // NOLINT
    73    char d_name[0];
    74  };
    75  
    76  // Wraps a buffer to provide a set of dirents.
    77  // T is the underlying dirent type.
    78  template <typename T>
    79  class DirentBuffer {
    80   public:
    81    // DirentBuffer manages the buffer.
    82    explicit DirentBuffer(size_t size)
    83        : managed_(true), actual_size_(size), reported_size_(size) {
    84      data_ = new char[actual_size_];
    85    }
    86  
    87    // The buffer is managed externally.
    88    DirentBuffer(char* data, size_t actual_size, size_t reported_size)
    89        : managed_(false),
    90          data_(data),
    91          actual_size_(actual_size),
    92          reported_size_(reported_size) {}
    93  
    94    ~DirentBuffer() {
    95      if (managed_) {
    96        delete[] data_;
    97      }
    98    }
    99  
   100    T* Data() { return reinterpret_cast<T*>(data_); }
   101  
   102    T* Start(size_t read) {
   103      read_ = read;
   104      if (read_) {
   105        return Data();
   106      } else {
   107        return nullptr;
   108      }
   109    }
   110  
   111    T* Current() { return reinterpret_cast<T*>(&data_[off_]); }
   112  
   113    T* Next() {
   114      size_t new_off = off_ + Current()->d_reclen;
   115      if (new_off >= read_ || new_off >= actual_size_) {
   116        return nullptr;
   117      }
   118  
   119      off_ = new_off;
   120      return Current();
   121    }
   122  
   123    size_t Size() { return reported_size_; }
   124  
   125    void Reset() {
   126      off_ = 0;
   127      read_ = 0;
   128      memset(data_, 0, actual_size_);
   129    }
   130  
   131   private:
   132    bool managed_;
   133    char* data_;
   134    size_t actual_size_;
   135    size_t reported_size_;
   136  
   137    size_t off_ = 0;
   138  
   139    size_t read_ = 0;
   140  };
   141  
   142  // Test for getdents/getdents64.
   143  // T is the Linux dirent type.
   144  template <typename T>
   145  class GetdentsTest : public ::testing::Test {
   146   public:
   147    using LinuxDirentType = T;
   148    using DirentBufferType = DirentBuffer<T>;
   149  
   150   protected:
   151    void SetUp() override {
   152      dir_ = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
   153      fd_ = ASSERT_NO_ERRNO_AND_VALUE(Open(dir_.path(), O_RDONLY | O_DIRECTORY));
   154    }
   155  
   156    // Must be overridden with explicit specialization. See below.
   157    int SyscallNum();
   158  
   159    int Getdents(LinuxDirentType* dirp, unsigned int count) {
   160      return RetryEINTR(syscall)(SyscallNum(), fd_.get(), dirp, count);
   161    }
   162  
   163    // Fill directory with num files, named by number starting at 0.
   164    void FillDirectory(size_t num) {
   165      // Don't save after each file creation since num can be large.
   166      {
   167        DisableSave ds;
   168        for (size_t i = 0; i < num; i++) {
   169          auto name = JoinPath(dir_.path(), absl::StrCat(i));
   170          TEST_CHECK(CreateWithContents(name, "").ok());
   171        }
   172      }
   173      MaybeSave();
   174    }
   175  
   176    // Fill directory with a given list of filenames.
   177    void FillDirectoryWithFiles(const std::vector<std::string>& filenames) {
   178      for (const auto& filename : filenames) {
   179        auto name = JoinPath(dir_.path(), filename);
   180        TEST_CHECK(CreateWithContents(name, "").ok());
   181      }
   182    }
   183  
   184    // Seek to the start of the directory.
   185    PosixError SeekStart() {
   186      constexpr off_t kStartOfFile = 0;
   187      off_t offset = lseek(fd_.get(), kStartOfFile, SEEK_SET);
   188      if (offset < 0) {
   189        return PosixError(errno, absl::StrCat("error seeking to ", kStartOfFile));
   190      }
   191      if (offset != kStartOfFile) {
   192        return PosixError(EINVAL, absl::StrCat("tried to seek to ", kStartOfFile,
   193                                               " but got ", offset));
   194      }
   195      return NoError();
   196    }
   197  
   198    // Call getdents multiple times, reading all dirents and calling f on each.
   199    // f has the type signature PosixError f(T*).
   200    // If f returns a non-OK error, so does ReadDirents.
   201    template <typename F>
   202    PosixError ReadDirents(DirentBufferType* dirents, F const& f) {
   203      int n;
   204      do {
   205        dirents->Reset();
   206  
   207        n = Getdents(dirents->Data(), dirents->Size());
   208        MaybeSave();
   209        if (n < 0) {
   210          return PosixError(errno, "getdents");
   211        }
   212  
   213        for (auto d = dirents->Start(n); d; d = dirents->Next()) {
   214          RETURN_IF_ERRNO(f(d));
   215        }
   216      } while (n > 0);
   217  
   218      return NoError();
   219    }
   220  
   221    // Call Getdents successively and count all entries.
   222    int ReadAndCountAllEntries(DirentBufferType* dirents) {
   223      int found = 0;
   224  
   225      EXPECT_NO_ERRNO(ReadDirents(dirents, [&](LinuxDirentType* d) {
   226        found++;
   227        return NoError();
   228      }));
   229  
   230      return found;
   231    }
   232  
   233   private:
   234    TempPath dir_;
   235    FileDescriptor fd_;
   236  };
   237  
   238  // Multiple template parameters are not allowed, so we must use explicit
   239  // template specialization to set the syscall number.
   240  
   241  // SYS_getdents isn't defined on arm64.
   242  #ifdef __x86_64__
   243  template <>
   244  int GetdentsTest<struct linux_dirent>::SyscallNum() {
   245    return SYS_getdents;
   246  }
   247  #endif
   248  
   249  template <>
   250  int GetdentsTest<struct linux_dirent64>::SyscallNum() {
   251    return SYS_getdents64;
   252  }
   253  
   254  #ifdef __x86_64__
   255  // Test both legacy getdents and getdents64 on x86_64.
   256  typedef ::testing::Types<struct linux_dirent, struct linux_dirent64>
   257      GetdentsTypes;
   258  #elif defined(__aarch64__) || defined(__riscv)
   259  // Test only getdents64 on arm64 and RISC-V.
   260  typedef ::testing::Types<struct linux_dirent64> GetdentsTypes;
   261  #endif
   262  TYPED_TEST_SUITE(GetdentsTest, GetdentsTypes);
   263  
   264  // N.B. TYPED_TESTs require explicitly using this-> to access members of
   265  // GetdentsTest, since we are inside of a derived class template.
   266  
   267  TYPED_TEST(GetdentsTest, VerifyEntries) {
   268    typename TestFixture::DirentBufferType dirents(1024);
   269  
   270    this->FillDirectory(2);
   271  
   272    // Map of all the entries we expect to find.
   273    std::map<std::string, bool> found;
   274    found["."] = false;
   275    found[".."] = false;
   276    found["0"] = false;
   277    found["1"] = false;
   278  
   279    EXPECT_NO_ERRNO(this->ReadDirents(
   280        &dirents, [&](typename TestFixture::LinuxDirentType* d) {
   281          auto kv = found.find(d->d_name);
   282          EXPECT_NE(kv, found.end()) << "Unexpected file: " << d->d_name;
   283          if (kv != found.end()) {
   284            EXPECT_FALSE(kv->second);
   285          }
   286          found[d->d_name] = true;
   287          return NoError();
   288        }));
   289  
   290    for (auto& kv : found) {
   291      EXPECT_TRUE(kv.second) << "File not found: " << kv.first;
   292    }
   293  }
   294  
   295  TYPED_TEST(GetdentsTest, VerifyPadding) {
   296    typename TestFixture::DirentBufferType dirents(1024);
   297  
   298    // Create files with names of length 1 through 16.
   299    std::vector<std::string> files;
   300    std::string filename;
   301    for (int i = 0; i < 16; ++i) {
   302      absl::StrAppend(&filename, "a");
   303      files.push_back(filename);
   304    }
   305    this->FillDirectoryWithFiles(files);
   306  
   307    // We expect to find all the files, plus '.' and '..'.
   308    const int expect_found = 2 + files.size();
   309    int found = 0;
   310  
   311    EXPECT_NO_ERRNO(this->ReadDirents(
   312        &dirents, [&](typename TestFixture::LinuxDirentType* d) {
   313          EXPECT_EQ(d->d_reclen % 8, 0)
   314              << "Dirent " << d->d_name
   315              << " had reclen that was not byte aligned: " << d->d_name;
   316          found++;
   317          return NoError();
   318        }));
   319  
   320    // Make sure we found all the files.
   321    EXPECT_EQ(found, expect_found);
   322  }
   323  
   324  // For a small directory, the provided buffer should be large enough
   325  // for all entries.
   326  TYPED_TEST(GetdentsTest, SmallDir) {
   327    // . and .. should be in an otherwise empty directory.
   328    int expect = 2;
   329  
   330    // Add some actual files.
   331    this->FillDirectory(2);
   332    expect += 2;
   333  
   334    typename TestFixture::DirentBufferType dirents(256);
   335  
   336    EXPECT_EQ(expect, this->ReadAndCountAllEntries(&dirents));
   337  }
   338  
   339  // A directory with lots of files requires calling getdents multiple times.
   340  TYPED_TEST(GetdentsTest, LargeDir) {
   341    // . and .. should be in an otherwise empty directory.
   342    int expect = 2;
   343  
   344    // Add some actual files.
   345    this->FillDirectory(100);
   346    expect += 100;
   347  
   348    typename TestFixture::DirentBufferType dirents(256);
   349  
   350    EXPECT_EQ(expect, this->ReadAndCountAllEntries(&dirents));
   351  }
   352  
   353  // If we lie about the size of the buffer, we should still be able to read the
   354  // entries with the available space.
   355  TYPED_TEST(GetdentsTest, PartialBuffer) {
   356    // . and .. should be in an otherwise empty directory.
   357    int expect = 2;
   358  
   359    // Add some actual files.
   360    this->FillDirectory(100);
   361    expect += 100;
   362  
   363    void* addr = mmap(0, 2 * kPageSize, PROT_READ | PROT_WRITE,
   364                      MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
   365    ASSERT_NE(addr, MAP_FAILED);
   366  
   367    char* buf = reinterpret_cast<char*>(addr);
   368  
   369    // Guard page
   370    EXPECT_THAT(
   371        mprotect(reinterpret_cast<void*>(buf + kPageSize), kPageSize, PROT_NONE),
   372        SyscallSucceeds());
   373  
   374    // Limit space in buf to 256 bytes.
   375    buf += kPageSize - 256;
   376  
   377    // Lie about the buffer. Even though we claim the buffer is 1 page,
   378    // we should still get all of the dirents in the first 256 bytes.
   379    typename TestFixture::DirentBufferType dirents(buf, 256, kPageSize);
   380  
   381    EXPECT_EQ(expect, this->ReadAndCountAllEntries(&dirents));
   382  
   383    EXPECT_THAT(munmap(addr, 2 * kPageSize), SyscallSucceeds());
   384  }
   385  
   386  // Open many file descriptors, then scan through /proc/self/fd to find and close
   387  // them all. (The latter is commonly used to handle races between fork/execve
   388  // and the creation of unwanted non-O_CLOEXEC file descriptors.) This tests that
   389  // getdents iterates correctly despite mutation of /proc/self/fd.
   390  TYPED_TEST(GetdentsTest, ProcSelfFd) {
   391    constexpr size_t kNfds = 10;
   392    absl::node_hash_map<int, FileDescriptor> fds;
   393    fds.reserve(kNfds);
   394    for (size_t i = 0; i < kNfds; i++) {
   395      FileDescriptor fd = ASSERT_NO_ERRNO_AND_VALUE(NewEventFD());
   396      fds.emplace(fd.get(), std::move(fd));
   397    }
   398  
   399    const FileDescriptor proc_self_fd =
   400        ASSERT_NO_ERRNO_AND_VALUE(Open("/proc/self/fd", O_RDONLY | O_DIRECTORY));
   401  
   402    // Make the buffer very small since we want to iterate.
   403    typename TestFixture::DirentBufferType dirents(
   404        2 * sizeof(typename TestFixture::LinuxDirentType));
   405    absl::node_hash_set<int> prev_fds;
   406    while (true) {
   407      dirents.Reset();
   408      int rv;
   409      ASSERT_THAT(rv = RetryEINTR(syscall)(this->SyscallNum(), proc_self_fd.get(),
   410                                           dirents.Data(), dirents.Size()),
   411                  SyscallSucceeds());
   412      if (rv == 0) {
   413        break;
   414      }
   415      for (auto* d = dirents.Start(rv); d; d = dirents.Next()) {
   416        int dfd;
   417        if (!absl::SimpleAtoi(d->d_name, &dfd)) continue;
   418        EXPECT_TRUE(prev_fds.insert(dfd).second)
   419            << "Repeated observation of /proc/self/fd/" << dfd;
   420        fds.erase(dfd);
   421      }
   422    }
   423  
   424    // Check that we closed every fd.
   425    EXPECT_THAT(fds, ::testing::IsEmpty());
   426  }
   427  
   428  // Test that getdents returns ENOTDIR when called on a file.
   429  TYPED_TEST(GetdentsTest, NotDir) {
   430    auto file = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile());
   431    auto fd = ASSERT_NO_ERRNO_AND_VALUE(Open(file.path(), O_RDONLY));
   432  
   433    typename TestFixture::DirentBufferType dirents(256);
   434    EXPECT_THAT(RetryEINTR(syscall)(this->SyscallNum(), fd.get(), dirents.Data(),
   435                                    dirents.Size()),
   436                SyscallFailsWithErrno(ENOTDIR));
   437  }
   438  
   439  // Test that getdents returns EBADF when called on an opath file.
   440  TYPED_TEST(GetdentsTest, OpathFile) {
   441    auto file = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile());
   442    auto fd = ASSERT_NO_ERRNO_AND_VALUE(Open(file.path(), O_PATH));
   443  
   444    typename TestFixture::DirentBufferType dirents(256);
   445    EXPECT_THAT(RetryEINTR(syscall)(this->SyscallNum(), fd.get(), dirents.Data(),
   446                                    dirents.Size()),
   447                SyscallFailsWithErrno(EBADF));
   448  }
   449  
   450  // Test that getdents returns EBADF when called on an opath directory.
   451  TYPED_TEST(GetdentsTest, OpathDirectory) {
   452    auto dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
   453    auto fd = ASSERT_NO_ERRNO_AND_VALUE(Open(dir.path(), O_PATH | O_DIRECTORY));
   454  
   455    typename TestFixture::DirentBufferType dirents(256);
   456    ASSERT_THAT(RetryEINTR(syscall)(this->SyscallNum(), fd.get(), dirents.Data(),
   457                                    dirents.Size()),
   458                SyscallFailsWithErrno(EBADF));
   459  }
   460  
   461  // Test that SEEK_SET to 0 causes getdents to re-read the entries.
   462  TYPED_TEST(GetdentsTest, SeekResetsCursor) {
   463    // . and .. should be in an otherwise empty directory.
   464    int expect = 2;
   465  
   466    // Add some files to the directory.
   467    this->FillDirectory(10);
   468    expect += 10;
   469  
   470    typename TestFixture::DirentBufferType dirents(256);
   471  
   472    // We should get all the expected entries.
   473    EXPECT_EQ(expect, this->ReadAndCountAllEntries(&dirents));
   474  
   475    // Seek back to 0.
   476    ASSERT_NO_ERRNO(this->SeekStart());
   477  
   478    // We should get all the expected entries again.
   479    EXPECT_EQ(expect, this->ReadAndCountAllEntries(&dirents));
   480  }
   481  
   482  // Test that getdents() after SEEK_END succeeds.
   483  // This is a regression test for #128.
   484  TYPED_TEST(GetdentsTest, Issue128ProcSeekEnd) {
   485    auto fd =
   486        ASSERT_NO_ERRNO_AND_VALUE(Open("/proc/self", O_RDONLY | O_DIRECTORY));
   487    typename TestFixture::DirentBufferType dirents(256);
   488  
   489    ASSERT_THAT(lseek(fd.get(), 0, SEEK_END), SyscallSucceeds());
   490    ASSERT_THAT(RetryEINTR(syscall)(this->SyscallNum(), fd.get(), dirents.Data(),
   491                                    dirents.Size()),
   492                SyscallSucceeds());
   493  }
   494  
   495  // Tests that getdents() fails when called with a zero-length buffer.
   496  TYPED_TEST(GetdentsTest, ZeroLengthOutBuffer) {
   497    auto dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
   498    auto fd = ASSERT_NO_ERRNO_AND_VALUE(Open(dir.path(), O_DIRECTORY));
   499  
   500    typename TestFixture::DirentBufferType dirents(0);
   501    ASSERT_THAT(RetryEINTR(syscall)(this->SyscallNum(), fd.get(), dirents.Data(),
   502                                    dirents.Size()),
   503                SyscallFailsWithErrno(EINVAL));
   504  }
   505  
   506  // Tests that getdents() fails when called with too large size.
   507  TYPED_TEST(GetdentsTest, TooLargeSize) {
   508    auto dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
   509    auto fd = ASSERT_NO_ERRNO_AND_VALUE(Open(dir.path(), O_DIRECTORY));
   510  
   511    typename TestFixture::DirentBufferType dirents(100);
   512    // Try one over the limit.
   513    EXPECT_THAT(RetryEINTR(syscall)(this->SyscallNum(), fd.get(), dirents.Data(),
   514                                    static_cast<uint32_t>(INT32_MAX) + 1),
   515                SyscallFailsWithErrno(EINVAL));
   516    // Try way over the limit.
   517    EXPECT_THAT(RetryEINTR(syscall)(this->SyscallNum(), fd.get(), dirents.Data(),
   518                                    static_cast<uint32_t>(-1)),
   519                SyscallFailsWithErrno(EINVAL));
   520  }
   521  
   522  // Some tests using the glibc readdir interface.
   523  TEST(ReaddirTest, OpenDir) {
   524    DIR* dev;
   525    ASSERT_THAT(dev = opendir("/dev"), NotNull());
   526    EXPECT_THAT(closedir(dev), SyscallSucceeds());
   527  }
   528  
   529  TEST(ReaddirTest, RootContainsBasicDirectories) {
   530    EXPECT_THAT(ListDir("/", true),
   531                IsPosixErrorOkAndHolds(IsSupersetOf(
   532                    {"bin", "dev", "etc", "lib", "proc", "sbin", "usr"})));
   533  }
   534  
   535  TEST(ReaddirTest, Bug24096713Dev) {
   536    auto contents = ASSERT_NO_ERRNO_AND_VALUE(ListDir("/dev", true));
   537    EXPECT_THAT(contents, Not(IsEmpty()));
   538  }
   539  
   540  TEST(ReaddirTest, Bug24096713ProcTid) {
   541    auto contents = ASSERT_NO_ERRNO_AND_VALUE(
   542        ListDir(absl::StrCat("/proc/", syscall(SYS_gettid), "/"), true));
   543    EXPECT_THAT(contents, Not(IsEmpty()));
   544  }
   545  
   546  TEST(ReaddirTest, Bug33429925Proc) {
   547    auto contents = ASSERT_NO_ERRNO_AND_VALUE(ListDir("/proc", true));
   548    EXPECT_THAT(contents, Not(IsEmpty()));
   549  }
   550  
   551  TEST(ReaddirTest, Bug35110122Root) {
   552    auto contents = ASSERT_NO_ERRNO_AND_VALUE(ListDir("/", true));
   553    EXPECT_THAT(contents, Not(IsEmpty()));
   554  }
   555  
   556  // Unlink should invalidate getdents cache.
   557  TEST(ReaddirTest, GoneAfterRemoveCache) {
   558    TempPath dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
   559    TempPath file = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileIn(dir.path()));
   560    std::string name = std::string(Basename(file.path()));
   561  
   562    auto contents = ASSERT_NO_ERRNO_AND_VALUE(ListDir(dir.path(), true));
   563    EXPECT_THAT(contents, Contains(name));
   564  
   565    file.reset();
   566  
   567    contents = ASSERT_NO_ERRNO_AND_VALUE(ListDir(dir.path(), true));
   568    EXPECT_THAT(contents, Not(Contains(name)));
   569  }
   570  
   571  // Regression test for b/137398511. Rename should invalidate getdents cache.
   572  TEST(ReaddirTest, GoneAfterRenameCache) {
   573    TempPath src = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
   574    TempPath dst = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
   575  
   576    TempPath file = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileIn(src.path()));
   577    std::string name = std::string(Basename(file.path()));
   578  
   579    auto contents = ASSERT_NO_ERRNO_AND_VALUE(ListDir(src.path(), true));
   580    EXPECT_THAT(contents, Contains(name));
   581  
   582    ASSERT_THAT(rename(file.path().c_str(), JoinPath(dst.path(), name).c_str()),
   583                SyscallSucceeds());
   584    // Release file since it was renamed. dst cleanup will ultimately delete it.
   585    file.release();
   586  
   587    contents = ASSERT_NO_ERRNO_AND_VALUE(ListDir(src.path(), true));
   588    EXPECT_THAT(contents, Not(Contains(name)));
   589  
   590    contents = ASSERT_NO_ERRNO_AND_VALUE(ListDir(dst.path(), true));
   591    EXPECT_THAT(contents, Contains(name));
   592  }
   593  
   594  }  // namespace
   595  
   596  }  // namespace testing
   597  }  // namespace gvisor