gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/test/syscalls/linux/inotify.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 <fcntl.h>
    16  #include <libgen.h>
    17  #include <sched.h>
    18  #include <sys/epoll.h>
    19  #include <sys/inotify.h>
    20  #include <sys/ioctl.h>
    21  #include <sys/sendfile.h>
    22  #include <sys/time.h>
    23  #include <sys/xattr.h>
    24  
    25  #include <atomic>
    26  #include <list>
    27  #include <string>
    28  #include <vector>
    29  
    30  #include "absl/strings/str_cat.h"
    31  #include "absl/strings/str_format.h"
    32  #include "absl/strings/str_join.h"
    33  #include "absl/synchronization/mutex.h"
    34  #include "absl/time/clock.h"
    35  #include "absl/time/time.h"
    36  #include "test/util/epoll_util.h"
    37  #include "test/util/file_descriptor.h"
    38  #include "test/util/fs_util.h"
    39  #include "test/util/multiprocess_util.h"
    40  #include "test/util/posix_error.h"
    41  #include "test/util/temp_path.h"
    42  #include "test/util/test_util.h"
    43  #include "test/util/thread_util.h"
    44  
    45  namespace gvisor {
    46  namespace testing {
    47  namespace {
    48  
    49  using ::absl::StreamFormat;
    50  using ::absl::StrFormat;
    51  
    52  constexpr int kBufSize = 1024;
    53  
    54  // C++-friendly version of struct inotify_event.
    55  struct Event {
    56    int32_t wd;
    57    uint32_t mask;
    58    uint32_t cookie;
    59    uint32_t len;
    60    std::string name;
    61  
    62    Event(uint32_t mask, int32_t wd, absl::string_view name, uint32_t cookie)
    63        : wd(wd),
    64          mask(mask),
    65          cookie(cookie),
    66          len(name.size()),
    67          name(std::string(name)) {}
    68    Event(uint32_t mask, int32_t wd, absl::string_view name)
    69        : Event(mask, wd, name, 0) {}
    70    Event(uint32_t mask, int32_t wd) : Event(mask, wd, "", 0) {}
    71    Event() : Event(0, 0, "", 0) {}
    72  };
    73  
    74  // Prints the symbolic name for a struct inotify_event's 'mask' field.
    75  std::string FlagString(uint32_t flags) {
    76    std::vector<std::string> names;
    77  
    78  #define EMIT(target)          \
    79    if (flags & target) {       \
    80      names.push_back(#target); \
    81      flags &= ~target;         \
    82    }
    83  
    84    EMIT(IN_ACCESS);
    85    EMIT(IN_ATTRIB);
    86    EMIT(IN_CLOSE_WRITE);
    87    EMIT(IN_CLOSE_NOWRITE);
    88    EMIT(IN_CREATE);
    89    EMIT(IN_DELETE);
    90    EMIT(IN_DELETE_SELF);
    91    EMIT(IN_MODIFY);
    92    EMIT(IN_MOVE_SELF);
    93    EMIT(IN_MOVED_FROM);
    94    EMIT(IN_MOVED_TO);
    95    EMIT(IN_OPEN);
    96  
    97    EMIT(IN_DONT_FOLLOW);
    98    EMIT(IN_EXCL_UNLINK);
    99    EMIT(IN_ONESHOT);
   100    EMIT(IN_ONLYDIR);
   101  
   102    EMIT(IN_IGNORED);
   103    EMIT(IN_ISDIR);
   104    EMIT(IN_Q_OVERFLOW);
   105    EMIT(IN_UNMOUNT);
   106  
   107  #undef EMIT
   108  
   109    // If we have anything left over at the end, print it as a hex value.
   110    if (flags) {
   111      names.push_back(absl::StrCat("0x", absl::Hex(flags)));
   112    }
   113  
   114    return absl::StrJoin(names, "|");
   115  }
   116  
   117  std::string DumpEvent(const Event& event) {
   118    return StrFormat(
   119        "%s, wd=%d%s%s", FlagString(event.mask), event.wd,
   120        (event.len > 0) ? StrFormat(", name=%s", event.name) : "",
   121        (event.cookie > 0) ? StrFormat(", cookie=%ud", event.cookie) : "");
   122  }
   123  
   124  std::string DumpEvents(const std::vector<Event>& events, int indent_level) {
   125    std::stringstream ss;
   126    ss << StreamFormat("%d event%s:\n", events.size(),
   127                       (events.size() > 1) ? "s" : "");
   128    int i = 0;
   129    for (const Event& ev : events) {
   130      ss << StreamFormat("%sevents[%d]: %s\n", std::string(indent_level, '\t'),
   131                         i++, DumpEvent(ev));
   132    }
   133    return ss.str();
   134  }
   135  
   136  // A matcher which takes an expected list of events to match against another
   137  // list of inotify events, in order. This is similar to the ElementsAre matcher,
   138  // but displays more informative messages on mismatch.
   139  class EventsAreMatcher
   140      : public ::testing::MatcherInterface<std::vector<Event>> {
   141   public:
   142    explicit EventsAreMatcher(std::vector<Event> references)
   143        : references_(std::move(references)) {}
   144  
   145    bool MatchAndExplain(
   146        std::vector<Event> events,
   147        ::testing::MatchResultListener* const listener) const override {
   148      if (references_.size() != events.size()) {
   149        *listener << StreamFormat("\n\tCount mismatch, got %s",
   150                                  DumpEvents(events, 2));
   151        return false;
   152      }
   153  
   154      bool success = true;
   155      for (unsigned int i = 0; i < references_.size(); ++i) {
   156        const Event& reference = references_[i];
   157        const Event& target = events[i];
   158  
   159        if (target.mask != reference.mask || target.wd != reference.wd ||
   160            target.name != reference.name || target.cookie != reference.cookie) {
   161          *listener << StreamFormat("\n\tMismatch at index %d, want %s, got %s,",
   162                                    i, DumpEvent(reference), DumpEvent(target));
   163          success = false;
   164        }
   165      }
   166  
   167      if (!success) {
   168        *listener << StreamFormat("\n\tIn total of %s", DumpEvents(events, 2));
   169      }
   170      return success;
   171    }
   172  
   173    void DescribeTo(::std::ostream* const os) const override {
   174      *os << StreamFormat("%s", DumpEvents(references_, 1));
   175    }
   176  
   177    void DescribeNegationTo(::std::ostream* const os) const override {
   178      *os << StreamFormat("mismatch from %s", DumpEvents(references_, 1));
   179    }
   180  
   181   private:
   182    std::vector<Event> references_;
   183  };
   184  
   185  ::testing::Matcher<std::vector<Event>> Are(std::vector<Event> events) {
   186    return MakeMatcher(new EventsAreMatcher(std::move(events)));
   187  }
   188  
   189  // Similar to the EventsAre matcher, but the order of events are ignored.
   190  class UnorderedEventsAreMatcher
   191      : public ::testing::MatcherInterface<std::vector<Event>> {
   192   public:
   193    explicit UnorderedEventsAreMatcher(std::vector<Event> references)
   194        : references_(std::move(references)) {}
   195  
   196    bool MatchAndExplain(
   197        std::vector<Event> events,
   198        ::testing::MatchResultListener* const listener) const override {
   199      if (references_.size() != events.size()) {
   200        *listener << StreamFormat("\n\tCount mismatch, got %s",
   201                                  DumpEvents(events, 2));
   202        return false;
   203      }
   204  
   205      std::vector<Event> unmatched(references_);
   206  
   207      for (const Event& candidate : events) {
   208        for (auto it = unmatched.begin(); it != unmatched.end();) {
   209          const Event& reference = *it;
   210          if (candidate.mask == reference.mask && candidate.wd == reference.wd &&
   211              candidate.name == reference.name &&
   212              candidate.cookie == reference.cookie) {
   213            it = unmatched.erase(it);
   214            break;
   215          } else {
   216            ++it;
   217          }
   218        }
   219      }
   220  
   221      // Anything left unmatched? If so, the matcher fails.
   222      if (!unmatched.empty()) {
   223        *listener << StreamFormat("\n\tFailed to match %s",
   224                                  DumpEvents(unmatched, 2));
   225        *listener << StreamFormat("\n\tIn total of %s", DumpEvents(events, 2));
   226        return false;
   227      }
   228  
   229      return true;
   230    }
   231  
   232    void DescribeTo(::std::ostream* const os) const override {
   233      *os << StreamFormat("unordered %s", DumpEvents(references_, 1));
   234    }
   235  
   236    void DescribeNegationTo(::std::ostream* const os) const override {
   237      *os << StreamFormat("mismatch from unordered %s",
   238                          DumpEvents(references_, 1));
   239    }
   240  
   241   private:
   242    std::vector<Event> references_;
   243  };
   244  
   245  ::testing::Matcher<std::vector<Event>> AreUnordered(std::vector<Event> events) {
   246    return MakeMatcher(new UnorderedEventsAreMatcher(std::move(events)));
   247  }
   248  
   249  // Reads events from an inotify fd until either EOF, or read returns EAGAIN.
   250  PosixErrorOr<std::vector<Event>> DrainEvents(int fd) {
   251    std::vector<Event> events;
   252    while (true) {
   253      int events_size = 0;
   254      if (ioctl(fd, FIONREAD, &events_size) < 0) {
   255        return PosixError(errno, "ioctl(FIONREAD) failed on inotify fd");
   256      }
   257      // Deliberately use a buffer that is larger than necessary, expecting to
   258      // only read events_size bytes.
   259      std::vector<char> buf(events_size + kBufSize, 0);
   260      const ssize_t readlen = read(fd, buf.data(), buf.size());
   261      MaybeSave();
   262      // Read error?
   263      if (readlen < 0) {
   264        if (errno == EAGAIN) {
   265          // If EAGAIN, no more events at the moment. Return what we have so far.
   266          return events;
   267        }
   268        // Some other read error. Return an error. Right now if we encounter this
   269        // after already reading some events, they get lost. However, we don't
   270        // expect to see any error, and the calling test will fail immediately if
   271        // we signal an error anyways, so this is acceptable.
   272        return PosixError(errno, "read() failed on inotify fd");
   273      }
   274      if (readlen < static_cast<int>(sizeof(struct inotify_event))) {
   275        // Impossibly short read.
   276        return PosixError(
   277            EIO,
   278            "read() didn't return enough data represent even a single event");
   279      }
   280      if (readlen != events_size) {
   281        return PosixError(EINVAL, absl::StrCat("read ", readlen,
   282                                               " bytes, expected ", events_size));
   283      }
   284      if (readlen == 0) {
   285        // EOF.
   286        return events;
   287      }
   288  
   289      // Normal read.
   290      const char* cursor = buf.data();
   291      while (cursor < (buf.data() + readlen)) {
   292        struct inotify_event event = {};
   293        memcpy(&event, cursor, sizeof(struct inotify_event));
   294  
   295        Event ev;
   296        ev.wd = event.wd;
   297        ev.mask = event.mask;
   298        ev.cookie = event.cookie;
   299        ev.len = event.len;
   300        if (event.len > 0) {
   301          TEST_CHECK(static_cast<int>(sizeof(struct inotify_event) + event.len) <=
   302                     readlen);
   303          ev.name = std::string(cursor +
   304                                offsetof(struct inotify_event, name));  // NOLINT
   305          // Name field should always be smaller than event.len, otherwise we have
   306          // a buffer overflow. The two sizes aren't equal because the string
   307          // constructor will stop at the first null byte, while event.name may be
   308          // padded up to event.len using multiple null bytes.
   309          TEST_CHECK(ev.name.size() <= event.len);
   310        }
   311  
   312        events.push_back(ev);
   313        cursor += sizeof(struct inotify_event) + event.len;
   314      }
   315    }
   316  }
   317  
   318  PosixErrorOr<FileDescriptor> InotifyInit1(int flags) {
   319    int fd = inotify_init1(flags);
   320    if (fd < 0) {
   321      return PosixError(errno, "inotify_init1() failed");
   322    }
   323    return FileDescriptor(fd);
   324  }
   325  
   326  PosixErrorOr<int> InotifyAddWatch(int fd, const std::string& path,
   327                                    uint32_t mask) {
   328    int wd = inotify_add_watch(fd, path.c_str(), mask);
   329    if (wd < 0) {
   330      return PosixError(errno, "inotify_add_watch() failed");
   331    }
   332    return wd;
   333  }
   334  
   335  TEST(Inotify, IllegalSeek) {
   336    // TODO: b/298787679 - this test fails on 6.0+ kernels.
   337    SKIP_IF(!IsRunningOnGvisor());
   338  
   339    const FileDescriptor fd = ASSERT_NO_ERRNO_AND_VALUE(InotifyInit1(0));
   340    EXPECT_THAT(lseek(fd.get(), 0, SEEK_SET), SyscallFailsWithErrno(ESPIPE));
   341  }
   342  
   343  TEST(Inotify, IllegalPread) {
   344    const FileDescriptor fd = ASSERT_NO_ERRNO_AND_VALUE(InotifyInit1(0));
   345    int val;
   346    EXPECT_THAT(pread(fd.get(), &val, sizeof(val), 0),
   347                SyscallFailsWithErrno(ESPIPE));
   348  }
   349  
   350  TEST(Inotify, IllegalPwrite) {
   351    const FileDescriptor fd = ASSERT_NO_ERRNO_AND_VALUE(InotifyInit1(0));
   352    EXPECT_THAT(pwrite(fd.get(), "x", 1, 0), SyscallFailsWithErrno(ESPIPE));
   353  }
   354  
   355  TEST(Inotify, IllegalWrite) {
   356    const FileDescriptor fd = ASSERT_NO_ERRNO_AND_VALUE(InotifyInit1(0));
   357    int val = 0;
   358    EXPECT_THAT(write(fd.get(), &val, sizeof(val)), SyscallFailsWithErrno(EBADF));
   359  }
   360  
   361  TEST(Inotify, InitFlags) {
   362    EXPECT_THAT(inotify_init1(IN_NONBLOCK | IN_CLOEXEC), SyscallSucceeds());
   363    EXPECT_THAT(inotify_init1(12345), SyscallFailsWithErrno(EINVAL));
   364  }
   365  
   366  TEST(Inotify, NonBlockingReadReturnsEagain) {
   367    const FileDescriptor fd =
   368        ASSERT_NO_ERRNO_AND_VALUE(InotifyInit1(IN_NONBLOCK));
   369    std::vector<char> buf(kBufSize, 0);
   370  
   371    // The read below should return fail with EAGAIN because there is no data to
   372    // read and we've specified IN_NONBLOCK. We're guaranteed that there is no
   373    // data to read because we haven't registered any watches yet.
   374    EXPECT_THAT(read(fd.get(), buf.data(), buf.size()),
   375                SyscallFailsWithErrno(EAGAIN));
   376  }
   377  
   378  TEST(Inotify, AddWatchOnInvalidFdFails) {
   379    // Garbage fd.
   380    EXPECT_THAT(
   381        inotify_add_watch(-1, GetAbsoluteTestTmpdir().c_str(), IN_ALL_EVENTS),
   382        SyscallFailsWithErrno(EBADF));
   383    EXPECT_THAT(
   384        inotify_add_watch(1337, GetAbsoluteTestTmpdir().c_str(), IN_ALL_EVENTS),
   385        SyscallFailsWithErrno(EBADF));
   386  
   387    // Non-inotify fds.
   388    EXPECT_THAT(
   389        inotify_add_watch(0, GetAbsoluteTestTmpdir().c_str(), IN_ALL_EVENTS),
   390        SyscallFailsWithErrno(EINVAL));
   391    EXPECT_THAT(
   392        inotify_add_watch(1, GetAbsoluteTestTmpdir().c_str(), IN_ALL_EVENTS),
   393        SyscallFailsWithErrno(EINVAL));
   394    EXPECT_THAT(
   395        inotify_add_watch(2, GetAbsoluteTestTmpdir().c_str(), IN_ALL_EVENTS),
   396        SyscallFailsWithErrno(EINVAL));
   397    const FileDescriptor fd = ASSERT_NO_ERRNO_AND_VALUE(
   398        Open(GetAbsoluteTestTmpdir().c_str(), O_RDONLY));
   399    EXPECT_THAT(inotify_add_watch(fd.get(), GetAbsoluteTestTmpdir().c_str(),
   400                                  IN_ALL_EVENTS),
   401                SyscallFailsWithErrno(EINVAL));
   402  }
   403  
   404  TEST(Inotify, RemovingWatchGeneratesEvent) {
   405    const TempPath root = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
   406    const FileDescriptor fd =
   407        ASSERT_NO_ERRNO_AND_VALUE(InotifyInit1(IN_NONBLOCK));
   408  
   409    const int wd = ASSERT_NO_ERRNO_AND_VALUE(
   410        InotifyAddWatch(fd.get(), root.path(), IN_ALL_EVENTS));
   411    EXPECT_THAT(inotify_rm_watch(fd.get(), wd), SyscallSucceeds());
   412  
   413    // Read events, ensure the first event is IN_IGNORED.
   414    const std::vector<Event> events =
   415        ASSERT_NO_ERRNO_AND_VALUE(DrainEvents(fd.get()));
   416    EXPECT_THAT(events, Are({Event(IN_IGNORED, wd)}));
   417  }
   418  
   419  TEST(Inotify, CanDeleteFileAfterRemovingWatch) {
   420    const TempPath root = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
   421    TempPath file1 =
   422        ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileIn(root.path()));
   423  
   424    const FileDescriptor fd =
   425        ASSERT_NO_ERRNO_AND_VALUE(InotifyInit1(IN_NONBLOCK));
   426    const int wd = ASSERT_NO_ERRNO_AND_VALUE(
   427        InotifyAddWatch(fd.get(), file1.path(), IN_ALL_EVENTS));
   428  
   429    EXPECT_THAT(inotify_rm_watch(fd.get(), wd), SyscallSucceeds());
   430    file1.reset();
   431  }
   432  
   433  TEST(Inotify, RemoveWatchAfterDeletingFileFails) {
   434    const TempPath root = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
   435    TempPath file1 =
   436        ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileIn(root.path()));
   437  
   438    const FileDescriptor fd =
   439        ASSERT_NO_ERRNO_AND_VALUE(InotifyInit1(IN_NONBLOCK));
   440    const int wd = ASSERT_NO_ERRNO_AND_VALUE(
   441        InotifyAddWatch(fd.get(), file1.path(), IN_ALL_EVENTS));
   442  
   443    file1.reset();
   444    const std::vector<Event> events =
   445        ASSERT_NO_ERRNO_AND_VALUE(DrainEvents(fd.get()));
   446    EXPECT_THAT(events, Are({Event(IN_ATTRIB, wd), Event(IN_DELETE_SELF, wd),
   447                             Event(IN_IGNORED, wd)}));
   448  
   449    EXPECT_THAT(inotify_rm_watch(fd.get(), wd), SyscallFailsWithErrno(EINVAL));
   450  }
   451  
   452  TEST(Inotify, DuplicateWatchRemovalFails) {
   453    const TempPath root = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
   454  
   455    const FileDescriptor fd =
   456        ASSERT_NO_ERRNO_AND_VALUE(InotifyInit1(IN_NONBLOCK));
   457    const int wd = ASSERT_NO_ERRNO_AND_VALUE(
   458        InotifyAddWatch(fd.get(), root.path(), IN_ALL_EVENTS));
   459  
   460    EXPECT_THAT(inotify_rm_watch(fd.get(), wd), SyscallSucceeds());
   461    EXPECT_THAT(inotify_rm_watch(fd.get(), wd), SyscallFailsWithErrno(EINVAL));
   462  }
   463  
   464  TEST(Inotify, ConcurrentFileDeletionAndWatchRemoval) {
   465    const TempPath root = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
   466  
   467    const FileDescriptor fd =
   468        ASSERT_NO_ERRNO_AND_VALUE(InotifyInit1(IN_NONBLOCK));
   469    const std::string filename = NewTempAbsPathInDir(root.path());
   470  
   471    auto file_create_delete = [filename]() {
   472      const DisableSave ds;  // Too expensive.
   473      for (int i = 0; i < 100; ++i) {
   474        FileDescriptor file_fd =
   475            ASSERT_NO_ERRNO_AND_VALUE(Open(filename, O_CREAT, S_IRUSR | S_IWUSR));
   476        // Close before unlinking (although S/R is disabled). Some filesystems
   477        // cannot restore an open fd on an unlinked file.
   478        file_fd.reset();
   479        EXPECT_THAT(unlink(filename.c_str()), SyscallSucceeds());
   480      }
   481    };
   482  
   483    const int shared_fd = fd.get();  // We need to pass it to the thread.
   484    auto add_remove_watch = [shared_fd, filename]() {
   485      for (int i = 0; i < 100; ++i) {
   486        int wd = inotify_add_watch(shared_fd, filename.c_str(), IN_ALL_EVENTS);
   487        MaybeSave();
   488        if (wd != -1) {
   489          // Watch added successfully, try removal.
   490          if (inotify_rm_watch(shared_fd, wd)) {
   491            // If removal fails, the only acceptable reason is if the wd
   492            // is invalid, which will be the case if we try to remove
   493            // the watch after the file has been deleted.
   494            EXPECT_EQ(errno, EINVAL);
   495          }
   496        } else {
   497          // Add watch failed, this should only fail if the target file doesn't
   498          // exist.
   499          EXPECT_EQ(errno, ENOENT);
   500        }
   501      }
   502    };
   503  
   504    ScopedThread t1(file_create_delete);
   505    ScopedThread t2(add_remove_watch);
   506  }
   507  
   508  TEST(Inotify, DeletingChildGeneratesEvents) {
   509    const TempPath root = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
   510    TempPath file1 =
   511        ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileIn(root.path()));
   512  
   513    const FileDescriptor fd =
   514        ASSERT_NO_ERRNO_AND_VALUE(InotifyInit1(IN_NONBLOCK));
   515    const int root_wd = ASSERT_NO_ERRNO_AND_VALUE(
   516        InotifyAddWatch(fd.get(), root.path(), IN_ALL_EVENTS));
   517    const int file1_wd = ASSERT_NO_ERRNO_AND_VALUE(
   518        InotifyAddWatch(fd.get(), file1.path(), IN_ALL_EVENTS));
   519  
   520    const std::string file1_path = file1.reset();
   521  
   522    const std::vector<Event> events =
   523        ASSERT_NO_ERRNO_AND_VALUE(DrainEvents(fd.get()));
   524    ASSERT_THAT(
   525        events,
   526        AreUnordered({Event(IN_ATTRIB, file1_wd), Event(IN_DELETE_SELF, file1_wd),
   527                      Event(IN_IGNORED, file1_wd),
   528                      Event(IN_DELETE, root_wd, Basename(file1_path))}));
   529  }
   530  
   531  // Creating a file in "parent/child" should generate events for child, but not
   532  // parent.
   533  TEST(Inotify, CreatingFileGeneratesEvents) {
   534    const TempPath parent = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
   535    const TempPath child =
   536        ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDirIn(parent.path()));
   537  
   538    const FileDescriptor fd =
   539        ASSERT_NO_ERRNO_AND_VALUE(InotifyInit1(IN_NONBLOCK));
   540    ASSERT_NO_ERRNO_AND_VALUE(
   541        InotifyAddWatch(fd.get(), parent.path(), IN_ALL_EVENTS));
   542    const int wd = ASSERT_NO_ERRNO_AND_VALUE(
   543        InotifyAddWatch(fd.get(), child.path(), IN_ALL_EVENTS));
   544  
   545    // Create a new file in the directory.
   546    const TempPath file1 =
   547        ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileIn(child.path()));
   548    const std::vector<Event> events =
   549        ASSERT_NO_ERRNO_AND_VALUE(DrainEvents(fd.get()));
   550  
   551    // The library function we use to create the new file opens it for writing to
   552    // create it and sets permissions on it, so we expect the three extra events.
   553    ASSERT_THAT(events, Are({Event(IN_CREATE, wd, Basename(file1.path())),
   554                             Event(IN_OPEN, wd, Basename(file1.path())),
   555                             Event(IN_CLOSE_WRITE, wd, Basename(file1.path())),
   556                             Event(IN_ATTRIB, wd, Basename(file1.path()))}));
   557  }
   558  
   559  TEST(Inotify, ReadingFileGeneratesAccessEvent) {
   560    const TempPath root = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
   561    const FileDescriptor fd =
   562        ASSERT_NO_ERRNO_AND_VALUE(InotifyInit1(IN_NONBLOCK));
   563    const TempPath file1 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileWith(
   564        root.path(), "some content", TempPath::kDefaultFileMode));
   565  
   566    const FileDescriptor file1_fd =
   567        ASSERT_NO_ERRNO_AND_VALUE(Open(file1.path(), O_RDONLY));
   568    const int wd = ASSERT_NO_ERRNO_AND_VALUE(
   569        InotifyAddWatch(fd.get(), root.path(), IN_ALL_EVENTS));
   570  
   571    char buf;
   572    EXPECT_THAT(read(file1_fd.get(), &buf, 1), SyscallSucceeds());
   573  
   574    const std::vector<Event> events =
   575        ASSERT_NO_ERRNO_AND_VALUE(DrainEvents(fd.get()));
   576    ASSERT_THAT(events, Are({Event(IN_ACCESS, wd, Basename(file1.path()))}));
   577  }
   578  
   579  TEST(Inotify, WritingFileGeneratesModifyEvent) {
   580    const TempPath root = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
   581    const FileDescriptor fd =
   582        ASSERT_NO_ERRNO_AND_VALUE(InotifyInit1(IN_NONBLOCK));
   583    const TempPath file1 =
   584        ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileIn(root.path()));
   585  
   586    const FileDescriptor file1_fd =
   587        ASSERT_NO_ERRNO_AND_VALUE(Open(file1.path(), O_WRONLY));
   588    const int wd = ASSERT_NO_ERRNO_AND_VALUE(
   589        InotifyAddWatch(fd.get(), root.path(), IN_ALL_EVENTS));
   590  
   591    const std::string data = "some content";
   592    EXPECT_THAT(write(file1_fd.get(), data.c_str(), data.length()),
   593                SyscallSucceeds());
   594  
   595    const std::vector<Event> events =
   596        ASSERT_NO_ERRNO_AND_VALUE(DrainEvents(fd.get()));
   597    ASSERT_THAT(events, Are({Event(IN_MODIFY, wd, Basename(file1.path()))}));
   598  }
   599  
   600  TEST(Inotify, SizeZeroReadWriteGeneratesNothing) {
   601    const TempPath root = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
   602    const FileDescriptor fd =
   603        ASSERT_NO_ERRNO_AND_VALUE(InotifyInit1(IN_NONBLOCK));
   604    const TempPath file1 =
   605        ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileIn(root.path()));
   606  
   607    const FileDescriptor file1_fd =
   608        ASSERT_NO_ERRNO_AND_VALUE(Open(file1.path(), O_RDWR));
   609    ASSERT_NO_ERRNO_AND_VALUE(
   610        InotifyAddWatch(fd.get(), root.path(), IN_ALL_EVENTS));
   611  
   612    // Read from the empty file.
   613    int val;
   614    ASSERT_THAT(read(file1_fd.get(), &val, sizeof(val)),
   615                SyscallSucceedsWithValue(0));
   616  
   617    // Write zero bytes.
   618    ASSERT_THAT(write(file1_fd.get(), "", 0), SyscallSucceedsWithValue(0));
   619  
   620    const std::vector<Event> events =
   621        ASSERT_NO_ERRNO_AND_VALUE(DrainEvents(fd.get()));
   622    ASSERT_THAT(events, Are({}));
   623  }
   624  
   625  TEST(Inotify, FailedFileCreationGeneratesNoEvents) {
   626    const TempPath dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
   627    const std::string dir_path = dir.path();
   628    const FileDescriptor fd =
   629        ASSERT_NO_ERRNO_AND_VALUE(InotifyInit1(IN_NONBLOCK));
   630    ASSERT_NO_ERRNO_AND_VALUE(InotifyAddWatch(fd.get(), dir_path, IN_ALL_EVENTS));
   631  
   632    const char* p = dir_path.c_str();
   633    ASSERT_THAT(mkdir(p, 0777), SyscallFails());
   634    ASSERT_THAT(mknod(p, S_IFIFO, 0777), SyscallFails());
   635    ASSERT_THAT(symlink(p, p), SyscallFails());
   636    ASSERT_THAT(link(p, p), SyscallFails());
   637    std::vector<Event> events = ASSERT_NO_ERRNO_AND_VALUE(DrainEvents(fd.get()));
   638    ASSERT_THAT(events, Are({}));
   639  }
   640  
   641  TEST(Inotify, WatchSetAfterOpenReportsCloseFdEvent) {
   642    const TempPath root = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
   643    const FileDescriptor fd =
   644        ASSERT_NO_ERRNO_AND_VALUE(InotifyInit1(IN_NONBLOCK));
   645    const TempPath file1 =
   646        ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileIn(root.path()));
   647  
   648    FileDescriptor file1_fd_writable =
   649        ASSERT_NO_ERRNO_AND_VALUE(Open(file1.path(), O_WRONLY));
   650    FileDescriptor file1_fd_not_writable =
   651        ASSERT_NO_ERRNO_AND_VALUE(Open(file1.path(), O_RDONLY));
   652    const int wd = ASSERT_NO_ERRNO_AND_VALUE(
   653        InotifyAddWatch(fd.get(), root.path(), IN_ALL_EVENTS));
   654  
   655    file1_fd_writable.reset();  // Close file1_fd_writable.
   656    std::vector<Event> events = ASSERT_NO_ERRNO_AND_VALUE(DrainEvents(fd.get()));
   657    ASSERT_THAT(events, Are({Event(IN_CLOSE_WRITE, wd, Basename(file1.path()))}));
   658  
   659    file1_fd_not_writable.reset();  // Close file1_fd_not_writable.
   660    events = ASSERT_NO_ERRNO_AND_VALUE(DrainEvents(fd.get()));
   661    ASSERT_THAT(events,
   662                Are({Event(IN_CLOSE_NOWRITE, wd, Basename(file1.path()))}));
   663  }
   664  
   665  TEST(Inotify, ChildrenDeletionInWatchedDirGeneratesEvent) {
   666    const TempPath root = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
   667    const FileDescriptor fd =
   668        ASSERT_NO_ERRNO_AND_VALUE(InotifyInit1(IN_NONBLOCK));
   669  
   670    TempPath file1 =
   671        ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileIn(root.path()));
   672    TempPath dir1 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDirIn(root.path()));
   673  
   674    const int wd = ASSERT_NO_ERRNO_AND_VALUE(
   675        InotifyAddWatch(fd.get(), root.path(), IN_ALL_EVENTS));
   676  
   677    const std::string file1_path = file1.reset();
   678    const std::string dir1_path = dir1.release();
   679    EXPECT_THAT(rmdir(dir1_path.c_str()), SyscallSucceeds());
   680  
   681    const std::vector<Event> events =
   682        ASSERT_NO_ERRNO_AND_VALUE(DrainEvents(fd.get()));
   683  
   684    ASSERT_THAT(events,
   685                Are({Event(IN_DELETE, wd, Basename(file1_path)),
   686                     Event(IN_DELETE | IN_ISDIR, wd, Basename(dir1_path))}));
   687  }
   688  
   689  TEST(Inotify, RmdirOnWatchedTargetGeneratesEvent) {
   690    const TempPath root = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
   691    const FileDescriptor fd =
   692        ASSERT_NO_ERRNO_AND_VALUE(InotifyInit1(IN_NONBLOCK));
   693  
   694    const int wd = ASSERT_NO_ERRNO_AND_VALUE(
   695        InotifyAddWatch(fd.get(), root.path(), IN_ALL_EVENTS));
   696  
   697    EXPECT_THAT(rmdir(root.path().c_str()), SyscallSucceeds());
   698    const std::vector<Event> events =
   699        ASSERT_NO_ERRNO_AND_VALUE(DrainEvents(fd.get()));
   700    ASSERT_THAT(events, Are({Event(IN_DELETE_SELF, wd), Event(IN_IGNORED, wd)}));
   701  }
   702  
   703  TEST(Inotify, MoveGeneratesEvents) {
   704    const TempPath root = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
   705    const FileDescriptor fd =
   706        ASSERT_NO_ERRNO_AND_VALUE(InotifyInit1(IN_NONBLOCK));
   707  
   708    TempPath file1 =
   709        ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileIn(root.path()));
   710  
   711    const TempPath dir1 =
   712        ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDirIn(root.path()));
   713    const TempPath dir2 =
   714        ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDirIn(root.path()));
   715  
   716    const int root_wd = ASSERT_NO_ERRNO_AND_VALUE(
   717        InotifyAddWatch(fd.get(), root.path(), IN_ALL_EVENTS));
   718    const int dir1_wd = ASSERT_NO_ERRNO_AND_VALUE(
   719        InotifyAddWatch(fd.get(), dir1.path(), IN_ALL_EVENTS));
   720    const int dir2_wd = ASSERT_NO_ERRNO_AND_VALUE(
   721        InotifyAddWatch(fd.get(), dir2.path(), IN_ALL_EVENTS));
   722    // Test move from root -> root.
   723    std::string newpath = NewTempAbsPathInDir(root.path());
   724    std::string oldpath = file1.release();
   725    EXPECT_THAT(rename(oldpath.c_str(), newpath.c_str()), SyscallSucceeds());
   726    file1.reset(newpath);
   727    std::vector<Event> events = ASSERT_NO_ERRNO_AND_VALUE(DrainEvents(fd.get()));
   728    ASSERT_THAT(
   729        events,
   730        Are({Event(IN_MOVED_FROM, root_wd, Basename(oldpath), events[0].cookie),
   731             Event(IN_MOVED_TO, root_wd, Basename(newpath), events[1].cookie)}));
   732    EXPECT_NE(events[0].cookie, 0);
   733    EXPECT_EQ(events[0].cookie, events[1].cookie);
   734    uint32_t last_cookie = events[0].cookie;
   735  
   736    // Test move from root -> root/dir1.
   737    newpath = NewTempAbsPathInDir(dir1.path());
   738    oldpath = file1.release();
   739    EXPECT_THAT(rename(oldpath.c_str(), newpath.c_str()), SyscallSucceeds());
   740    file1.reset(newpath);
   741    events = ASSERT_NO_ERRNO_AND_VALUE(DrainEvents(fd.get()));
   742    ASSERT_THAT(
   743        events,
   744        Are({Event(IN_MOVED_FROM, root_wd, Basename(oldpath), events[0].cookie),
   745             Event(IN_MOVED_TO, dir1_wd, Basename(newpath), events[1].cookie)}));
   746    // Cookies should be distinct between distinct rename events.
   747    EXPECT_NE(events[0].cookie, last_cookie);
   748    EXPECT_EQ(events[0].cookie, events[1].cookie);
   749    last_cookie = events[0].cookie;
   750  
   751    // Test move from root/dir1 -> root/dir2.
   752    newpath = NewTempAbsPathInDir(dir2.path());
   753    oldpath = file1.release();
   754    EXPECT_THAT(rename(oldpath.c_str(), newpath.c_str()), SyscallSucceeds());
   755    file1.reset(newpath);
   756    events = ASSERT_NO_ERRNO_AND_VALUE(DrainEvents(fd.get()));
   757    ASSERT_THAT(
   758        events,
   759        Are({Event(IN_MOVED_FROM, dir1_wd, Basename(oldpath), events[0].cookie),
   760             Event(IN_MOVED_TO, dir2_wd, Basename(newpath), events[1].cookie)}));
   761    EXPECT_NE(events[0].cookie, last_cookie);
   762    EXPECT_EQ(events[0].cookie, events[1].cookie);
   763    last_cookie = events[0].cookie;
   764  }
   765  
   766  TEST(Inotify, MoveWatchedTargetGeneratesEvents) {
   767    const TempPath root = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
   768    const FileDescriptor fd =
   769        ASSERT_NO_ERRNO_AND_VALUE(InotifyInit1(IN_NONBLOCK));
   770  
   771    TempPath file1 =
   772        ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileIn(root.path()));
   773  
   774    const int root_wd = ASSERT_NO_ERRNO_AND_VALUE(
   775        InotifyAddWatch(fd.get(), root.path(), IN_ALL_EVENTS));
   776    const int file1_wd = ASSERT_NO_ERRNO_AND_VALUE(
   777        InotifyAddWatch(fd.get(), file1.path(), IN_ALL_EVENTS));
   778  
   779    const std::string newpath = NewTempAbsPathInDir(root.path());
   780    const std::string oldpath = file1.release();
   781    EXPECT_THAT(rename(oldpath.c_str(), newpath.c_str()), SyscallSucceeds());
   782    file1.reset(newpath);
   783    const std::vector<Event> events =
   784        ASSERT_NO_ERRNO_AND_VALUE(DrainEvents(fd.get()));
   785    ASSERT_THAT(
   786        events,
   787        Are({Event(IN_MOVED_FROM, root_wd, Basename(oldpath), events[0].cookie),
   788             Event(IN_MOVED_TO, root_wd, Basename(newpath), events[1].cookie),
   789             // Self move events do not have a cookie.
   790             Event(IN_MOVE_SELF, file1_wd)}));
   791    EXPECT_NE(events[0].cookie, 0);
   792    EXPECT_EQ(events[0].cookie, events[1].cookie);
   793  }
   794  
   795  // Tests that close events are only emitted when a file description drops its
   796  // last reference.
   797  TEST(Inotify, DupFD) {
   798    const TempPath file = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile());
   799    const FileDescriptor inotify_fd =
   800        ASSERT_NO_ERRNO_AND_VALUE(InotifyInit1(IN_NONBLOCK));
   801  
   802    const int wd = ASSERT_NO_ERRNO_AND_VALUE(
   803        InotifyAddWatch(inotify_fd.get(), file.path(), IN_ALL_EVENTS));
   804  
   805    FileDescriptor fd = ASSERT_NO_ERRNO_AND_VALUE(Open(file.path(), O_RDONLY));
   806    FileDescriptor fd2 = ASSERT_NO_ERRNO_AND_VALUE(fd.Dup());
   807  
   808    std::vector<Event> events =
   809        ASSERT_NO_ERRNO_AND_VALUE(DrainEvents(inotify_fd.get()));
   810    EXPECT_THAT(events, Are({
   811                            Event(IN_OPEN, wd),
   812                        }));
   813  
   814    fd.reset();
   815    events = ASSERT_NO_ERRNO_AND_VALUE(DrainEvents(inotify_fd.get()));
   816    EXPECT_THAT(events, Are({}));
   817  
   818    fd2.reset();
   819    events = ASSERT_NO_ERRNO_AND_VALUE(DrainEvents(inotify_fd.get()));
   820    EXPECT_THAT(events, Are({
   821                            Event(IN_CLOSE_NOWRITE, wd),
   822                        }));
   823  }
   824  
   825  TEST(Inotify, CoalesceEvents) {
   826    const TempPath root = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
   827    const FileDescriptor fd =
   828        ASSERT_NO_ERRNO_AND_VALUE(InotifyInit1(IN_NONBLOCK));
   829  
   830    const TempPath file1 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileWith(
   831        root.path(), "some content", TempPath::kDefaultFileMode));
   832  
   833    FileDescriptor file1_fd =
   834        ASSERT_NO_ERRNO_AND_VALUE(Open(file1.path(), O_RDONLY));
   835    const int wd = ASSERT_NO_ERRNO_AND_VALUE(
   836        InotifyAddWatch(fd.get(), root.path(), IN_ALL_EVENTS));
   837  
   838    // Read the file a few times. This will would generate multiple IN_ACCESS
   839    // events but they should get coalesced to a single event.
   840    char buf;
   841    EXPECT_THAT(read(file1_fd.get(), &buf, 1), SyscallSucceeds());
   842    EXPECT_THAT(read(file1_fd.get(), &buf, 1), SyscallSucceeds());
   843    EXPECT_THAT(read(file1_fd.get(), &buf, 1), SyscallSucceeds());
   844    EXPECT_THAT(read(file1_fd.get(), &buf, 1), SyscallSucceeds());
   845  
   846    // Use the close event verify that we haven't simply left the additional
   847    // IN_ACCESS events unread.
   848    file1_fd.reset();  // Close file1_fd.
   849  
   850    const std::string file1_name = std::string(Basename(file1.path()));
   851    std::vector<Event> events = ASSERT_NO_ERRNO_AND_VALUE(DrainEvents(fd.get()));
   852    ASSERT_THAT(events, Are({Event(IN_ACCESS, wd, file1_name),
   853                             Event(IN_CLOSE_NOWRITE, wd, file1_name)}));
   854  
   855    // Now let's try interleaving other events into a stream of repeated events.
   856    file1_fd = ASSERT_NO_ERRNO_AND_VALUE(Open(file1.path(), O_RDWR));
   857  
   858    EXPECT_THAT(read(file1_fd.get(), &buf, 1), SyscallSucceeds());
   859    EXPECT_THAT(read(file1_fd.get(), &buf, 1), SyscallSucceeds());
   860    EXPECT_THAT(write(file1_fd.get(), "x", 1), SyscallSucceeds());
   861    EXPECT_THAT(write(file1_fd.get(), "x", 1), SyscallSucceeds());
   862    EXPECT_THAT(write(file1_fd.get(), "x", 1), SyscallSucceeds());
   863    EXPECT_THAT(read(file1_fd.get(), &buf, 1), SyscallSucceeds());
   864    EXPECT_THAT(read(file1_fd.get(), &buf, 1), SyscallSucceeds());
   865  
   866    file1_fd.reset();  // Close the file.
   867  
   868    events = ASSERT_NO_ERRNO_AND_VALUE(DrainEvents(fd.get()));
   869    ASSERT_THAT(
   870        events,
   871        Are({Event(IN_OPEN, wd, file1_name), Event(IN_ACCESS, wd, file1_name),
   872             Event(IN_MODIFY, wd, file1_name), Event(IN_ACCESS, wd, file1_name),
   873             Event(IN_CLOSE_WRITE, wd, file1_name)}));
   874  
   875    // Ensure events aren't coalesced if they are from different files.
   876    const TempPath file2 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileWith(
   877        root.path(), "some content", TempPath::kDefaultFileMode));
   878    // Discard events resulting from creation of file2.
   879    ASSERT_NO_ERRNO_AND_VALUE(DrainEvents(fd.get()));
   880  
   881    file1_fd = ASSERT_NO_ERRNO_AND_VALUE(Open(file1.path(), O_RDONLY));
   882    FileDescriptor file2_fd =
   883        ASSERT_NO_ERRNO_AND_VALUE(Open(file2.path(), O_RDONLY));
   884  
   885    EXPECT_THAT(read(file1_fd.get(), &buf, 1), SyscallSucceeds());
   886    EXPECT_THAT(read(file2_fd.get(), &buf, 1), SyscallSucceeds());
   887    EXPECT_THAT(read(file1_fd.get(), &buf, 1), SyscallSucceeds());
   888    EXPECT_THAT(read(file1_fd.get(), &buf, 1), SyscallSucceeds());
   889  
   890    // Close both files.
   891    file1_fd.reset();
   892    file2_fd.reset();
   893  
   894    events = ASSERT_NO_ERRNO_AND_VALUE(DrainEvents(fd.get()));
   895    const std::string file2_name = std::string(Basename(file2.path()));
   896    ASSERT_THAT(
   897        events,
   898        Are({Event(IN_OPEN, wd, file1_name), Event(IN_OPEN, wd, file2_name),
   899             Event(IN_ACCESS, wd, file1_name), Event(IN_ACCESS, wd, file2_name),
   900             Event(IN_ACCESS, wd, file1_name),
   901             Event(IN_CLOSE_NOWRITE, wd, file1_name),
   902             Event(IN_CLOSE_NOWRITE, wd, file2_name)}));
   903  }
   904  
   905  TEST(Inotify, ClosingInotifyFdWithoutRemovingWatchesWorks) {
   906    const TempPath root = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
   907    const FileDescriptor fd =
   908        ASSERT_NO_ERRNO_AND_VALUE(InotifyInit1(IN_NONBLOCK));
   909  
   910    const TempPath file1 =
   911        ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileIn(root.path()));
   912    const FileDescriptor file1_fd =
   913        ASSERT_NO_ERRNO_AND_VALUE(Open(file1.path(), O_RDONLY));
   914  
   915    ASSERT_NO_ERRNO_AND_VALUE(
   916        InotifyAddWatch(fd.get(), file1.path(), IN_ALL_EVENTS));
   917    // Note: The check on close will happen in FileDescriptor::~FileDescriptor().
   918  }
   919  
   920  TEST(Inotify, NestedWatches) {
   921    const TempPath root = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
   922    const FileDescriptor fd =
   923        ASSERT_NO_ERRNO_AND_VALUE(InotifyInit1(IN_NONBLOCK));
   924  
   925    const TempPath file1 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileWith(
   926        root.path(), "some content", TempPath::kDefaultFileMode));
   927    const FileDescriptor file1_fd =
   928        ASSERT_NO_ERRNO_AND_VALUE(Open(file1.path(), O_RDONLY));
   929  
   930    const int root_wd = ASSERT_NO_ERRNO_AND_VALUE(
   931        InotifyAddWatch(fd.get(), root.path(), IN_ALL_EVENTS));
   932    const int file1_wd = ASSERT_NO_ERRNO_AND_VALUE(
   933        InotifyAddWatch(fd.get(), file1.path(), IN_ALL_EVENTS));
   934  
   935    // Read from file1. This should generate an event for both watches.
   936    char buf;
   937    EXPECT_THAT(read(file1_fd.get(), &buf, 1), SyscallSucceeds());
   938  
   939    const std::vector<Event> events =
   940        ASSERT_NO_ERRNO_AND_VALUE(DrainEvents(fd.get()));
   941    ASSERT_THAT(events, Are({Event(IN_ACCESS, root_wd, Basename(file1.path())),
   942                             Event(IN_ACCESS, file1_wd)}));
   943  }
   944  
   945  TEST(Inotify, ConcurrentThreadsGeneratingEvents) {
   946    const TempPath root = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
   947    const FileDescriptor fd =
   948        ASSERT_NO_ERRNO_AND_VALUE(InotifyInit1(IN_NONBLOCK));
   949  
   950    std::vector<TempPath> files;
   951    files.reserve(10);
   952    for (int i = 0; i < 10; i++) {
   953      files.emplace_back(ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileWith(
   954          root.path(), "some content", TempPath::kDefaultFileMode)));
   955    }
   956  
   957    auto test_thread = [&files]() {
   958      uint32_t seed = time(nullptr);
   959      for (int i = 0; i < 20; i++) {
   960        const TempPath& file = files[rand_r(&seed) % files.size()];
   961        const FileDescriptor file_fd =
   962            ASSERT_NO_ERRNO_AND_VALUE(Open(file.path(), O_WRONLY));
   963        TEST_PCHECK(write(file_fd.get(), "x", 1) == 1);
   964      }
   965    };
   966  
   967    ASSERT_NO_ERRNO_AND_VALUE(
   968        InotifyAddWatch(fd.get(), root.path(), IN_ALL_EVENTS));
   969  
   970    std::list<ScopedThread> threads;
   971    for (int i = 0; i < 3; i++) {
   972      threads.emplace_back(test_thread);
   973    }
   974    for (auto& t : threads) {
   975      t.Join();
   976    }
   977  
   978    const std::vector<Event> events =
   979        ASSERT_NO_ERRNO_AND_VALUE(DrainEvents(fd.get()));
   980    // 3 threads doing 20 iterations, 3 events per iteration (open, write,
   981    // close). However, some events may be coalesced, and we can't reliably
   982    // predict how they'll be coalesced since the test threads aren't
   983    // synchronized. We can only check that we aren't getting unexpected events.
   984    for (const Event& ev : events) {
   985      EXPECT_NE(ev.mask & (IN_OPEN | IN_MODIFY | IN_CLOSE_WRITE), 0);
   986    }
   987  }
   988  
   989  TEST(Inotify, ReadWithTooSmallBufferFails) {
   990    const TempPath root = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
   991    const TempPath file1 =
   992        ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileIn(root.path()));
   993    const FileDescriptor fd =
   994        ASSERT_NO_ERRNO_AND_VALUE(InotifyInit1(IN_NONBLOCK));
   995  
   996    const int wd = ASSERT_NO_ERRNO_AND_VALUE(
   997        InotifyAddWatch(fd.get(), file1.path(), IN_ALL_EVENTS));
   998  
   999    // Open the file to queue an event. This event will not have a filename, so
  1000    // reading from the inotify fd should return sizeof(struct inotify_event)
  1001    // bytes of data.
  1002    FileDescriptor file1_fd =
  1003        ASSERT_NO_ERRNO_AND_VALUE(Open(file1.path(), O_RDONLY));
  1004    std::vector<char> buf(kBufSize, 0);
  1005    ssize_t readlen;
  1006  
  1007    // Try a buffer too small to hold any potential event. This is rejected
  1008    // outright without the event being dequeued.
  1009    EXPECT_THAT(read(fd.get(), buf.data(), sizeof(struct inotify_event) - 1),
  1010                SyscallFailsWithErrno(EINVAL));
  1011    // Try a buffer just large enough. This should succeeed.
  1012    EXPECT_THAT(
  1013        readlen = read(fd.get(), buf.data(), sizeof(struct inotify_event)),
  1014        SyscallSucceeds());
  1015    EXPECT_EQ(readlen, sizeof(struct inotify_event));
  1016    // Event queue is now empty, the next read should return EAGAIN.
  1017    EXPECT_THAT(read(fd.get(), buf.data(), sizeof(struct inotify_event)),
  1018                SyscallFailsWithErrno(EAGAIN));
  1019  
  1020    // Now put a watch on the directory, so that generated events contain a name.
  1021    EXPECT_THAT(inotify_rm_watch(fd.get(), wd), SyscallSucceeds());
  1022  
  1023    // Drain the event generated from the watch removal.
  1024    ASSERT_NO_ERRNO_AND_VALUE(DrainEvents(fd.get()));
  1025  
  1026    ASSERT_NO_ERRNO_AND_VALUE(
  1027        InotifyAddWatch(fd.get(), root.path(), IN_ALL_EVENTS));
  1028  
  1029    file1_fd.reset();  // Close file to generate an event.
  1030  
  1031    // Try a buffer too small to hold any event and one too small to hold an event
  1032    // with a name. These should both fail without consuming the event.
  1033    EXPECT_THAT(read(fd.get(), buf.data(), sizeof(struct inotify_event) - 1),
  1034                SyscallFailsWithErrno(EINVAL));
  1035    EXPECT_THAT(read(fd.get(), buf.data(), sizeof(struct inotify_event)),
  1036                SyscallFailsWithErrno(EINVAL));
  1037    // Now try with a large enough buffer. This should return the one event.
  1038    EXPECT_THAT(readlen = read(fd.get(), buf.data(), buf.size()),
  1039                SyscallSucceeds());
  1040    EXPECT_GE(readlen,
  1041              sizeof(struct inotify_event) + Basename(file1.path()).size());
  1042    // With the single event read, the queue should once again be empty.
  1043    EXPECT_THAT(read(fd.get(), buf.data(), sizeof(struct inotify_event)),
  1044                SyscallFailsWithErrno(EAGAIN));
  1045  }
  1046  
  1047  TEST(Inotify, BlockingReadOnInotifyFd) {
  1048    const TempPath root = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
  1049    const FileDescriptor fd = ASSERT_NO_ERRNO_AND_VALUE(InotifyInit1(0));
  1050    const TempPath file1 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileWith(
  1051        root.path(), "some content", TempPath::kDefaultFileMode));
  1052  
  1053    const FileDescriptor file1_fd =
  1054        ASSERT_NO_ERRNO_AND_VALUE(Open(file1.path(), O_RDONLY));
  1055  
  1056    ASSERT_NO_ERRNO_AND_VALUE(
  1057        InotifyAddWatch(fd.get(), root.path(), IN_ALL_EVENTS));
  1058  
  1059    // Spawn a thread performing a blocking read for new events on the inotify fd.
  1060    std::vector<char> buf(kBufSize, 0);
  1061    const int shared_fd = fd.get();  // The thread needs it.
  1062    ScopedThread t([shared_fd, &buf]() {
  1063      ssize_t readlen;
  1064      EXPECT_THAT(readlen = read(shared_fd, buf.data(), buf.size()),
  1065                  SyscallSucceeds());
  1066    });
  1067  
  1068    // Perform a read on the watched file, which should generate an IN_ACCESS
  1069    // event, unblocking the event_reader thread.
  1070    char c;
  1071    EXPECT_THAT(read(file1_fd.get(), &c, 1), SyscallSucceeds());
  1072  
  1073    // Wait for the thread to read the event and exit.
  1074    t.Join();
  1075  
  1076    // Make sure the event we got back is sane.
  1077    uint32_t event_mask;
  1078    memcpy(&event_mask, buf.data() + offsetof(struct inotify_event, mask),
  1079           sizeof(event_mask));
  1080    EXPECT_EQ(event_mask, IN_ACCESS);
  1081  }
  1082  
  1083  TEST(Inotify, WatchOnRelativePath) {
  1084    const TempPath root = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
  1085    const FileDescriptor fd =
  1086        ASSERT_NO_ERRNO_AND_VALUE(InotifyInit1(IN_NONBLOCK));
  1087    const TempPath file1 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileWith(
  1088        root.path(), "some content", TempPath::kDefaultFileMode));
  1089  
  1090    const FileDescriptor file1_fd =
  1091        ASSERT_NO_ERRNO_AND_VALUE(Open(file1.path(), O_RDONLY));
  1092  
  1093    // Change working directory to root.
  1094    const FileDescriptor cwd = ASSERT_NO_ERRNO_AND_VALUE(Open(".", O_PATH));
  1095    EXPECT_THAT(chdir(root.path().c_str()), SyscallSucceeds());
  1096  
  1097    // Add a watch on file1 with a relative path.
  1098    const int wd = ASSERT_NO_ERRNO_AND_VALUE(InotifyAddWatch(
  1099        fd.get(), std::string(Basename(file1.path())), IN_ALL_EVENTS));
  1100  
  1101    // Perform a read on file1, this should generate an IN_ACCESS event.
  1102    char c;
  1103    EXPECT_THAT(read(file1_fd.get(), &c, 1), SyscallSucceeds());
  1104  
  1105    const std::vector<Event> events =
  1106        ASSERT_NO_ERRNO_AND_VALUE(DrainEvents(fd.get()));
  1107    EXPECT_THAT(events, Are({Event(IN_ACCESS, wd)}));
  1108  
  1109    // Explicitly reset the working directory so that we don't continue to
  1110    // reference "root". Once the test ends, "root" will get unlinked. If we
  1111    // continue to hold a reference, random save/restore tests can fail if a save
  1112    // is triggered after "root" is unlinked; we can't save deleted fs objects
  1113    // with active references.
  1114    EXPECT_THAT(fchdir(cwd.get()), SyscallSucceeds());
  1115  }
  1116  
  1117  TEST(Inotify, ZeroLengthReadWriteDoesNotGenerateEvent) {
  1118    const TempPath root = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
  1119    const FileDescriptor fd =
  1120        ASSERT_NO_ERRNO_AND_VALUE(InotifyInit1(IN_NONBLOCK));
  1121  
  1122    const char kContent[] = "some content";
  1123    TempPath file1 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileWith(
  1124        root.path(), kContent, TempPath::kDefaultFileMode));
  1125    const int kContentSize = sizeof(kContent) - 1;
  1126  
  1127    const FileDescriptor file1_fd =
  1128        ASSERT_NO_ERRNO_AND_VALUE(Open(file1.path(), O_RDWR));
  1129  
  1130    const int wd = ASSERT_NO_ERRNO_AND_VALUE(
  1131        InotifyAddWatch(fd.get(), root.path(), IN_ALL_EVENTS));
  1132  
  1133    std::vector<char> buf(kContentSize, 0);
  1134    // Read all available data.
  1135    ssize_t readlen;
  1136    EXPECT_THAT(readlen = read(file1_fd.get(), buf.data(), kContentSize),
  1137                SyscallSucceeds());
  1138    EXPECT_EQ(readlen, kContentSize);
  1139    // Drain all events and make sure we got the IN_ACCESS for the read.
  1140    std::vector<Event> events = ASSERT_NO_ERRNO_AND_VALUE(DrainEvents(fd.get()));
  1141    EXPECT_THAT(events, Are({Event(IN_ACCESS, wd, Basename(file1.path()))}));
  1142  
  1143    // Now try read again. This should be a 0-length read, since we're at EOF.
  1144    char c;
  1145    EXPECT_THAT(readlen = read(file1_fd.get(), &c, 1), SyscallSucceeds());
  1146    EXPECT_EQ(readlen, 0);
  1147    // We should have no new events.
  1148    events = ASSERT_NO_ERRNO_AND_VALUE(DrainEvents(fd.get()));
  1149    EXPECT_TRUE(events.empty());
  1150  
  1151    // Try issuing a zero-length read.
  1152    EXPECT_THAT(readlen = read(file1_fd.get(), &c, 0), SyscallSucceeds());
  1153    EXPECT_EQ(readlen, 0);
  1154    // We should have no new events.
  1155    events = ASSERT_NO_ERRNO_AND_VALUE(DrainEvents(fd.get()));
  1156    EXPECT_TRUE(events.empty());
  1157  
  1158    // Try issuing a zero-length write.
  1159    ssize_t writelen;
  1160    EXPECT_THAT(writelen = write(file1_fd.get(), &c, 0), SyscallSucceeds());
  1161    EXPECT_EQ(writelen, 0);
  1162    // We should have no new events.
  1163    events = ASSERT_NO_ERRNO_AND_VALUE(DrainEvents(fd.get()));
  1164    EXPECT_TRUE(events.empty());
  1165  }
  1166  
  1167  TEST(Inotify, ChmodGeneratesAttribEvent) {
  1168    const TempPath root = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
  1169    const TempPath file1 =
  1170        ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileIn(root.path()));
  1171  
  1172    FileDescriptor root_fd =
  1173        ASSERT_NO_ERRNO_AND_VALUE(Open(root.path(), O_RDONLY));
  1174    FileDescriptor file1_fd =
  1175        ASSERT_NO_ERRNO_AND_VALUE(Open(file1.path(), O_RDWR));
  1176    FileDescriptor fd = ASSERT_NO_ERRNO_AND_VALUE(InotifyInit1(IN_NONBLOCK));
  1177  
  1178    const int root_wd = ASSERT_NO_ERRNO_AND_VALUE(
  1179        InotifyAddWatch(fd.get(), root.path(), IN_ALL_EVENTS));
  1180    const int file1_wd = ASSERT_NO_ERRNO_AND_VALUE(
  1181        InotifyAddWatch(fd.get(), file1.path(), IN_ALL_EVENTS));
  1182  
  1183    auto verify_chmod_events = [&]() {
  1184      std::vector<Event> events =
  1185          ASSERT_NO_ERRNO_AND_VALUE(DrainEvents(fd.get()));
  1186      ASSERT_THAT(events, Are({Event(IN_ATTRIB, root_wd, Basename(file1.path())),
  1187                               Event(IN_ATTRIB, file1_wd)}));
  1188    };
  1189  
  1190    // Don't do cooperative S/R tests for any of the {f}chmod* syscalls below, the
  1191    // test will always fail because nodes cannot be saved when they have stricter
  1192    // permissions than the original host node.
  1193    const DisableSave ds;
  1194  
  1195    // Chmod.
  1196    ASSERT_THAT(chmod(file1.path().c_str(), S_IWGRP), SyscallSucceeds());
  1197    verify_chmod_events();
  1198  
  1199    // Fchmod.
  1200    ASSERT_THAT(fchmod(file1_fd.get(), S_IRGRP | S_IWGRP), SyscallSucceeds());
  1201    verify_chmod_events();
  1202  
  1203    // Fchmodat.
  1204    const std::string file1_basename = std::string(Basename(file1.path()));
  1205    ASSERT_THAT(fchmodat(root_fd.get(), file1_basename.c_str(), S_IWGRP, 0),
  1206                SyscallSucceeds());
  1207    verify_chmod_events();
  1208  
  1209    // Make sure the chmod'ed file descriptors are destroyed before DisableSave
  1210    // is destructed.
  1211    root_fd.reset();
  1212    file1_fd.reset();
  1213  }
  1214  
  1215  TEST(Inotify, TruncateGeneratesModifyEvent) {
  1216    const TempPath root = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
  1217    const TempPath file1 =
  1218        ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileIn(root.path()));
  1219    const FileDescriptor file1_fd =
  1220        ASSERT_NO_ERRNO_AND_VALUE(Open(file1.path(), O_RDWR));
  1221  
  1222    const FileDescriptor fd =
  1223        ASSERT_NO_ERRNO_AND_VALUE(InotifyInit1(IN_NONBLOCK));
  1224    const int root_wd = ASSERT_NO_ERRNO_AND_VALUE(
  1225        InotifyAddWatch(fd.get(), root.path(), IN_ALL_EVENTS));
  1226    const int file1_wd = ASSERT_NO_ERRNO_AND_VALUE(
  1227        InotifyAddWatch(fd.get(), file1.path(), IN_ALL_EVENTS));
  1228  
  1229    auto verify_truncate_events = [&]() {
  1230      std::vector<Event> events =
  1231          ASSERT_NO_ERRNO_AND_VALUE(DrainEvents(fd.get()));
  1232      ASSERT_THAT(events, Are({Event(IN_MODIFY, root_wd, Basename(file1.path())),
  1233                               Event(IN_MODIFY, file1_wd)}));
  1234    };
  1235  
  1236    // Truncate.
  1237    EXPECT_THAT(truncate(file1.path().c_str(), 4096), SyscallSucceeds());
  1238    verify_truncate_events();
  1239  
  1240    // Ftruncate.
  1241    EXPECT_THAT(ftruncate(file1_fd.get(), 8192), SyscallSucceeds());
  1242    verify_truncate_events();
  1243  
  1244    // No events if truncate fails.
  1245    EXPECT_THAT(ftruncate(file1_fd.get(), -1), SyscallFailsWithErrno(EINVAL));
  1246    const std::vector<Event> events =
  1247        ASSERT_NO_ERRNO_AND_VALUE(DrainEvents(fd.get()));
  1248    ASSERT_THAT(events, Are({}));
  1249  }
  1250  
  1251  TEST(Inotify, GetdentsGeneratesAccessEvent) {
  1252    const TempPath root = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
  1253    const TempPath file1 =
  1254        ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileIn(root.path()));
  1255  
  1256    const FileDescriptor fd =
  1257        ASSERT_NO_ERRNO_AND_VALUE(InotifyInit1(IN_NONBLOCK));
  1258  
  1259    ASSERT_NO_ERRNO_AND_VALUE(
  1260        InotifyAddWatch(fd.get(), root.path(), IN_ALL_EVENTS));
  1261    ASSERT_NO_ERRNO_AND_VALUE(
  1262        InotifyAddWatch(fd.get(), file1.path(), IN_ALL_EVENTS));
  1263  
  1264    // This internally calls getdents(2). We also expect to see an open/close
  1265    // event for the dirfd.
  1266    ASSERT_NO_ERRNO_AND_VALUE(ListDir(root.path(), false));
  1267    const std::vector<Event> events =
  1268        ASSERT_NO_ERRNO_AND_VALUE(DrainEvents(fd.get()));
  1269  
  1270    // Linux only seems to generate access events on getdents() on some
  1271    // calls. Allow the test to pass even if it isn't generated. gVisor will
  1272    // always generate the IN_ACCESS event so the test will at least ensure gVisor
  1273    // behaves reasonably.
  1274    int i = 0;
  1275    EXPECT_EQ(events[i].mask, IN_OPEN | IN_ISDIR);
  1276    ++i;
  1277    if (IsRunningOnGvisor()) {
  1278      EXPECT_EQ(events[i].mask, IN_ACCESS | IN_ISDIR);
  1279      ++i;
  1280    } else {
  1281      if (events[i].mask == (IN_ACCESS | IN_ISDIR)) {
  1282        // Skip over the IN_ACCESS event on Linux, it only shows up some of the
  1283        // time so we can't assert its existence.
  1284        ++i;
  1285      }
  1286    }
  1287    EXPECT_EQ(events[i].mask, IN_CLOSE_NOWRITE | IN_ISDIR);
  1288  }
  1289  
  1290  TEST(Inotify, MknodGeneratesCreateEvent) {
  1291    const TempPath root = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
  1292    const FileDescriptor fd =
  1293        ASSERT_NO_ERRNO_AND_VALUE(InotifyInit1(IN_NONBLOCK));
  1294  
  1295    const int wd = ASSERT_NO_ERRNO_AND_VALUE(
  1296        InotifyAddWatch(fd.get(), root.path(), IN_ALL_EVENTS));
  1297  
  1298    const TempPath file1(root.path() + "/file1");
  1299    ASSERT_THAT(mknod(file1.path().c_str(), S_IFREG, 0), SyscallSucceeds());
  1300  
  1301    const std::vector<Event> events =
  1302        ASSERT_NO_ERRNO_AND_VALUE(DrainEvents(fd.get()));
  1303    ASSERT_THAT(events, Are({Event(IN_CREATE, wd, Basename(file1.path()))}));
  1304  }
  1305  
  1306  TEST(Inotify, SymlinkGeneratesCreateEvent) {
  1307    const TempPath root = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
  1308    const TempPath file1 =
  1309        ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileIn(root.path()));
  1310    const TempPath link1(NewTempAbsPathInDir(root.path()));
  1311    const FileDescriptor fd =
  1312        ASSERT_NO_ERRNO_AND_VALUE(InotifyInit1(IN_NONBLOCK));
  1313  
  1314    const int root_wd = ASSERT_NO_ERRNO_AND_VALUE(
  1315        InotifyAddWatch(fd.get(), root.path(), IN_ALL_EVENTS));
  1316    ASSERT_NO_ERRNO(InotifyAddWatch(fd.get(), file1.path(), IN_ALL_EVENTS));
  1317  
  1318    ASSERT_THAT(symlink(file1.path().c_str(), link1.path().c_str()),
  1319                SyscallSucceeds());
  1320  
  1321    const std::vector<Event> events =
  1322        ASSERT_NO_ERRNO_AND_VALUE(DrainEvents(fd.get()));
  1323  
  1324    ASSERT_THAT(events, Are({Event(IN_CREATE, root_wd, Basename(link1.path()))}));
  1325  }
  1326  
  1327  TEST(Inotify, SymlinkFollow) {
  1328    const TempPath file = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile());
  1329    const TempPath link(NewTempAbsPath());
  1330    ASSERT_THAT(symlink(file.path().c_str(), link.path().c_str()),
  1331                SyscallSucceeds());
  1332  
  1333    const FileDescriptor fd =
  1334        ASSERT_NO_ERRNO_AND_VALUE(InotifyInit1(IN_NONBLOCK));
  1335    const int file_wd = ASSERT_NO_ERRNO_AND_VALUE(
  1336        InotifyAddWatch(fd.get(), link.path(), IN_ALL_EVENTS));
  1337    const int link_wd = ASSERT_NO_ERRNO_AND_VALUE(
  1338        InotifyAddWatch(fd.get(), link.path(), IN_ALL_EVENTS | IN_DONT_FOLLOW));
  1339  
  1340    ASSERT_NO_ERRNO(Unlink(file.path()));
  1341    ASSERT_NO_ERRNO(Unlink(link.path()));
  1342  
  1343    const std::vector<Event> events =
  1344        ASSERT_NO_ERRNO_AND_VALUE(DrainEvents(fd.get()));
  1345  
  1346    ASSERT_THAT(
  1347        events,
  1348        Are({Event(IN_ATTRIB, file_wd), Event(IN_DELETE_SELF, file_wd),
  1349             Event(IN_IGNORED, file_wd), Event(IN_ATTRIB, link_wd),
  1350             Event(IN_DELETE_SELF, link_wd), Event(IN_IGNORED, link_wd)}));
  1351  }
  1352  
  1353  TEST(Inotify, LinkGeneratesAttribAndCreateEvents) {
  1354    // Inotify does not work properly with hard links in gofer and overlay fs.
  1355    SKIP_IF(IsRunningOnGvisor() &&
  1356            !ASSERT_NO_ERRNO_AND_VALUE(IsTmpfs(GetAbsoluteTestTmpdir())));
  1357  
  1358    const TempPath root = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
  1359    const TempPath file1 =
  1360        ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileIn(root.path()));
  1361    const TempPath link1(root.path() + "/link1");
  1362    const FileDescriptor fd =
  1363        ASSERT_NO_ERRNO_AND_VALUE(InotifyInit1(IN_NONBLOCK));
  1364  
  1365    const int root_wd = ASSERT_NO_ERRNO_AND_VALUE(
  1366        InotifyAddWatch(fd.get(), root.path(), IN_ALL_EVENTS));
  1367    const int file1_wd = ASSERT_NO_ERRNO_AND_VALUE(
  1368        InotifyAddWatch(fd.get(), file1.path(), IN_ALL_EVENTS));
  1369  
  1370    ASSERT_THAT(link(file1.path().c_str(), link1.path().c_str()),
  1371                SyscallSucceeds());
  1372  
  1373    const std::vector<Event> events =
  1374        ASSERT_NO_ERRNO_AND_VALUE(DrainEvents(fd.get()));
  1375    ASSERT_THAT(events, Are({Event(IN_ATTRIB, file1_wd),
  1376                             Event(IN_CREATE, root_wd, Basename(link1.path()))}));
  1377  }
  1378  
  1379  TEST(Inotify, UtimesGeneratesAttribEvent) {
  1380    const TempPath root = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
  1381    const FileDescriptor fd =
  1382        ASSERT_NO_ERRNO_AND_VALUE(InotifyInit1(IN_NONBLOCK));
  1383    const TempPath file1 =
  1384        ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileIn(root.path()));
  1385  
  1386    const FileDescriptor file1_fd =
  1387        ASSERT_NO_ERRNO_AND_VALUE(Open(file1.path(), O_RDWR));
  1388    const int wd = ASSERT_NO_ERRNO_AND_VALUE(
  1389        InotifyAddWatch(fd.get(), root.path(), IN_ALL_EVENTS));
  1390  
  1391    const struct timeval times[2] = {{1, 0}, {2, 0}};
  1392    EXPECT_THAT(futimes(file1_fd.get(), times), SyscallSucceeds());
  1393  
  1394    const std::vector<Event> events =
  1395        ASSERT_NO_ERRNO_AND_VALUE(DrainEvents(fd.get()));
  1396    ASSERT_THAT(events, Are({Event(IN_ATTRIB, wd, Basename(file1.path()))}));
  1397  }
  1398  
  1399  TEST(Inotify, HardlinksReuseSameWatch) {
  1400    // Inotify does not work properly with hard links in gofer and overlay fs.
  1401    SKIP_IF(IsRunningOnGvisor() &&
  1402            !ASSERT_NO_ERRNO_AND_VALUE(IsTmpfs(GetAbsoluteTestTmpdir())));
  1403  
  1404    const TempPath root = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
  1405    TempPath file =
  1406        ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileIn(root.path()));
  1407  
  1408    TempPath file2(root.path() + "/file2");
  1409    ASSERT_THAT(link(file.path().c_str(), file2.path().c_str()),
  1410                SyscallSucceeds());
  1411  
  1412    const FileDescriptor fd =
  1413        ASSERT_NO_ERRNO_AND_VALUE(InotifyInit1(IN_NONBLOCK));
  1414  
  1415    const int root_wd = ASSERT_NO_ERRNO_AND_VALUE(
  1416        InotifyAddWatch(fd.get(), root.path(), IN_ALL_EVENTS));
  1417    const int file_wd = ASSERT_NO_ERRNO_AND_VALUE(
  1418        InotifyAddWatch(fd.get(), file.path(), IN_ALL_EVENTS));
  1419    const int file2_wd = ASSERT_NO_ERRNO_AND_VALUE(
  1420        InotifyAddWatch(fd.get(), file2.path(), IN_ALL_EVENTS));
  1421  
  1422    // The watch descriptors for watches on different links to the same file
  1423    // should be identical.
  1424    EXPECT_NE(root_wd, file_wd);
  1425    EXPECT_EQ(file_wd, file2_wd);
  1426  
  1427    FileDescriptor file_fd =
  1428        ASSERT_NO_ERRNO_AND_VALUE(Open(file.path(), O_WRONLY));
  1429  
  1430    std::vector<Event> events = ASSERT_NO_ERRNO_AND_VALUE(DrainEvents(fd.get()));
  1431    ASSERT_THAT(events,
  1432                AreUnordered({Event(IN_OPEN, root_wd, Basename(file.path())),
  1433                              Event(IN_OPEN, file_wd)}));
  1434  
  1435    // For the next step, we want to ensure all fds to the file are closed. Do
  1436    // that now and drain the resulting events.
  1437    file_fd.reset();
  1438    events = ASSERT_NO_ERRNO_AND_VALUE(DrainEvents(fd.get()));
  1439    ASSERT_THAT(
  1440        events,
  1441        AreUnordered({Event(IN_CLOSE_WRITE, root_wd, Basename(file.path())),
  1442                      Event(IN_CLOSE_WRITE, file_wd)}));
  1443  
  1444    // Try removing the link and let's see what events show up. Note that after
  1445    // this, we still have a link to the file so the watch shouldn't be
  1446    // automatically removed.
  1447    const std::string file2_path = file2.reset();
  1448  
  1449    events = ASSERT_NO_ERRNO_AND_VALUE(DrainEvents(fd.get()));
  1450    ASSERT_THAT(events,
  1451                AreUnordered({Event(IN_ATTRIB, file2_wd),
  1452                              Event(IN_DELETE, root_wd, Basename(file2_path))}));
  1453  
  1454    // Now remove the other link. Since this is the last link to the file, the
  1455    // watch should be automatically removed.
  1456    const std::string file_path = file.reset();
  1457  
  1458    events = ASSERT_NO_ERRNO_AND_VALUE(DrainEvents(fd.get()));
  1459    ASSERT_THAT(
  1460        events,
  1461        AreUnordered({Event(IN_ATTRIB, file_wd), Event(IN_DELETE_SELF, file_wd),
  1462                      Event(IN_IGNORED, file_wd),
  1463                      Event(IN_DELETE, root_wd, Basename(file_path))}));
  1464  }
  1465  
  1466  // Calling mkdir within "parent/child" should generate an event for child, but
  1467  // not parent.
  1468  TEST(Inotify, MkdirGeneratesCreateEventWithDirFlag) {
  1469    const TempPath parent = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
  1470    const TempPath child =
  1471        ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDirIn(parent.path()));
  1472    const FileDescriptor fd =
  1473        ASSERT_NO_ERRNO_AND_VALUE(InotifyInit1(IN_NONBLOCK));
  1474    ASSERT_NO_ERRNO_AND_VALUE(
  1475        InotifyAddWatch(fd.get(), parent.path(), IN_ALL_EVENTS));
  1476    const int child_wd = ASSERT_NO_ERRNO_AND_VALUE(
  1477        InotifyAddWatch(fd.get(), child.path(), IN_ALL_EVENTS));
  1478  
  1479    const TempPath dir1(NewTempAbsPathInDir(child.path()));
  1480    ASSERT_THAT(mkdir(dir1.path().c_str(), 0777), SyscallSucceeds());
  1481  
  1482    const std::vector<Event> events =
  1483        ASSERT_NO_ERRNO_AND_VALUE(DrainEvents(fd.get()));
  1484    ASSERT_THAT(
  1485        events,
  1486        Are({Event(IN_CREATE | IN_ISDIR, child_wd, Basename(dir1.path()))}));
  1487  }
  1488  
  1489  TEST(Inotify, MultipleInotifyInstancesAndWatchesAllGetEvents) {
  1490    const TempPath root = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
  1491    const TempPath file1 =
  1492        ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileIn(root.path()));
  1493  
  1494    const FileDescriptor file1_fd =
  1495        ASSERT_NO_ERRNO_AND_VALUE(Open(file1.path(), O_WRONLY));
  1496    constexpr int kNumFds = 30;
  1497    std::vector<FileDescriptor> inotify_fds;
  1498  
  1499    for (int i = 0; i < kNumFds; ++i) {
  1500      const DisableSave ds;  // Too expensive.
  1501      inotify_fds.emplace_back(
  1502          ASSERT_NO_ERRNO_AND_VALUE(InotifyInit1(IN_NONBLOCK)));
  1503      const FileDescriptor& fd = inotify_fds[inotify_fds.size() - 1];  // Back.
  1504      ASSERT_NO_ERRNO_AND_VALUE(
  1505          InotifyAddWatch(fd.get(), root.path(), IN_ALL_EVENTS));
  1506      ASSERT_NO_ERRNO_AND_VALUE(
  1507          InotifyAddWatch(fd.get(), file1.path(), IN_ALL_EVENTS));
  1508    }
  1509  
  1510    const std::string data = "some content";
  1511    EXPECT_THAT(write(file1_fd.get(), data.c_str(), data.length()),
  1512                SyscallSucceeds());
  1513  
  1514    for (const FileDescriptor& fd : inotify_fds) {
  1515      const DisableSave ds;  // Too expensive.
  1516      const std::vector<Event> events =
  1517          ASSERT_NO_ERRNO_AND_VALUE(DrainEvents(fd.get()));
  1518      if (events.size() >= 2) {
  1519        EXPECT_EQ(events[0].mask, IN_MODIFY);
  1520        EXPECT_EQ(events[0].wd, 1);
  1521        EXPECT_EQ(events[0].name, Basename(file1.path()));
  1522        EXPECT_EQ(events[1].mask, IN_MODIFY);
  1523        EXPECT_EQ(events[1].wd, 2);
  1524        EXPECT_EQ(events[1].name, "");
  1525      }
  1526    }
  1527  }
  1528  
  1529  TEST(Inotify, EventsGoUpAtMostOneLevel) {
  1530    const TempPath root = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
  1531    const TempPath dir1 =
  1532        ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDirIn(root.path()));
  1533    TempPath file1 =
  1534        ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileIn(dir1.path()));
  1535    const FileDescriptor fd =
  1536        ASSERT_NO_ERRNO_AND_VALUE(InotifyInit1(IN_NONBLOCK));
  1537  
  1538    ASSERT_NO_ERRNO_AND_VALUE(
  1539        InotifyAddWatch(fd.get(), root.path(), IN_ALL_EVENTS));
  1540    const int dir1_wd = ASSERT_NO_ERRNO_AND_VALUE(
  1541        InotifyAddWatch(fd.get(), dir1.path(), IN_ALL_EVENTS));
  1542  
  1543    const std::string file1_path = file1.reset();
  1544  
  1545    const std::vector<Event> events =
  1546        ASSERT_NO_ERRNO_AND_VALUE(DrainEvents(fd.get()));
  1547    ASSERT_THAT(events, Are({Event(IN_DELETE, dir1_wd, Basename(file1_path))}));
  1548  }
  1549  
  1550  TEST(Inotify, DuplicateWatchReturnsSameWatchDescriptor) {
  1551    const TempPath root = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
  1552    const TempPath file1 =
  1553        ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileIn(root.path()));
  1554    const FileDescriptor fd =
  1555        ASSERT_NO_ERRNO_AND_VALUE(InotifyInit1(IN_NONBLOCK));
  1556  
  1557    const int wd1 = ASSERT_NO_ERRNO_AND_VALUE(
  1558        InotifyAddWatch(fd.get(), file1.path(), IN_ALL_EVENTS));
  1559    const int wd2 = ASSERT_NO_ERRNO_AND_VALUE(
  1560        InotifyAddWatch(fd.get(), file1.path(), IN_ALL_EVENTS));
  1561  
  1562    EXPECT_EQ(wd1, wd2);
  1563  
  1564    const FileDescriptor file1_fd =
  1565        ASSERT_NO_ERRNO_AND_VALUE(Open(file1.path(), O_WRONLY));
  1566    const std::vector<Event> events =
  1567        ASSERT_NO_ERRNO_AND_VALUE(DrainEvents(fd.get()));
  1568    // The watch shouldn't be duplicated, we only expect one event.
  1569    ASSERT_THAT(events, Are({Event(IN_OPEN, wd1)}));
  1570  }
  1571  
  1572  TEST(Inotify, UnmatchedEventsAreDiscarded) {
  1573    const TempPath root = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
  1574    TempPath file1 =
  1575        ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileIn(root.path()));
  1576    const FileDescriptor fd =
  1577        ASSERT_NO_ERRNO_AND_VALUE(InotifyInit1(IN_NONBLOCK));
  1578  
  1579    const int wd = ASSERT_NO_ERRNO_AND_VALUE(
  1580        InotifyAddWatch(fd.get(), file1.path(), IN_ACCESS));
  1581  
  1582    FileDescriptor file1_fd =
  1583        ASSERT_NO_ERRNO_AND_VALUE(Open(file1.path(), O_WRONLY));
  1584  
  1585    std::vector<Event> events = ASSERT_NO_ERRNO_AND_VALUE(DrainEvents(fd.get()));
  1586    // We only asked for access events, the open event should be discarded.
  1587    ASSERT_THAT(events, Are({}));
  1588  
  1589    // IN_IGNORED events are always generated, regardless of the mask.
  1590    file1_fd.reset();
  1591    file1.reset();
  1592    events = ASSERT_NO_ERRNO_AND_VALUE(DrainEvents(fd.get()));
  1593    ASSERT_THAT(events, Are({Event(IN_IGNORED, wd)}));
  1594  }
  1595  
  1596  TEST(Inotify, AddWatchWithInvalidEventMaskFails) {
  1597    const TempPath root = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
  1598    const FileDescriptor fd =
  1599        ASSERT_NO_ERRNO_AND_VALUE(InotifyInit1(IN_NONBLOCK));
  1600  
  1601    EXPECT_THAT(inotify_add_watch(fd.get(), root.path().c_str(), 0),
  1602                SyscallFailsWithErrno(EINVAL));
  1603  }
  1604  
  1605  TEST(Inotify, AddWatchOnInvalidPathFails) {
  1606    const TempPath nonexistent(NewTempAbsPath());
  1607    const FileDescriptor fd =
  1608        ASSERT_NO_ERRNO_AND_VALUE(InotifyInit1(IN_NONBLOCK));
  1609  
  1610    // Non-existent path.
  1611    EXPECT_THAT(
  1612        inotify_add_watch(fd.get(), nonexistent.path().c_str(), IN_CREATE),
  1613        SyscallFailsWithErrno(ENOENT));
  1614  
  1615    // Garbage path pointer.
  1616    EXPECT_THAT(inotify_add_watch(fd.get(), nullptr, IN_CREATE),
  1617                SyscallFailsWithErrno(EFAULT));
  1618  }
  1619  
  1620  TEST(Inotify, InOnlyDirFlagRespected) {
  1621    const TempPath root = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
  1622    const TempPath file1 =
  1623        ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileIn(root.path()));
  1624    const FileDescriptor fd =
  1625        ASSERT_NO_ERRNO_AND_VALUE(InotifyInit1(IN_NONBLOCK));
  1626  
  1627    EXPECT_THAT(
  1628        inotify_add_watch(fd.get(), root.path().c_str(), IN_ACCESS | IN_ONLYDIR),
  1629        SyscallSucceeds());
  1630  
  1631    EXPECT_THAT(
  1632        inotify_add_watch(fd.get(), file1.path().c_str(), IN_ACCESS | IN_ONLYDIR),
  1633        SyscallFailsWithErrno(ENOTDIR));
  1634  }
  1635  
  1636  TEST(Inotify, MaskAddMergesWithExistingEventMask) {
  1637    const TempPath root = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
  1638    const TempPath file1 =
  1639        ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileIn(root.path()));
  1640    const FileDescriptor fd =
  1641        ASSERT_NO_ERRNO_AND_VALUE(InotifyInit1(IN_NONBLOCK));
  1642  
  1643    FileDescriptor file1_fd =
  1644        ASSERT_NO_ERRNO_AND_VALUE(Open(file1.path(), O_WRONLY));
  1645  
  1646    const int wd = ASSERT_NO_ERRNO_AND_VALUE(
  1647        InotifyAddWatch(fd.get(), file1.path(), IN_OPEN | IN_CLOSE_WRITE));
  1648  
  1649    const std::string data = "some content";
  1650    EXPECT_THAT(write(file1_fd.get(), data.c_str(), data.length()),
  1651                SyscallSucceeds());
  1652  
  1653    // We shouldn't get any events, since IN_MODIFY wasn't in the event mask.
  1654    std::vector<Event> events = ASSERT_NO_ERRNO_AND_VALUE(DrainEvents(fd.get()));
  1655    ASSERT_THAT(events, Are({}));
  1656  
  1657    // Add IN_MODIFY to event mask.
  1658    ASSERT_NO_ERRNO_AND_VALUE(
  1659        InotifyAddWatch(fd.get(), file1.path(), IN_MODIFY | IN_MASK_ADD));
  1660  
  1661    EXPECT_THAT(write(file1_fd.get(), data.c_str(), data.length()),
  1662                SyscallSucceeds());
  1663  
  1664    // This time we should get the modify event.
  1665    events = ASSERT_NO_ERRNO_AND_VALUE(DrainEvents(fd.get()));
  1666    ASSERT_THAT(events, Are({Event(IN_MODIFY, wd)}));
  1667  
  1668    // Now close the fd. If the modify event was added to the event mask rather
  1669    // than replacing the event mask we won't get the close event.
  1670    file1_fd.reset();
  1671    events = ASSERT_NO_ERRNO_AND_VALUE(DrainEvents(fd.get()));
  1672    ASSERT_THAT(events, Are({Event(IN_CLOSE_WRITE, wd)}));
  1673  }
  1674  
  1675  // Test that control events bits are not considered when checking event mask.
  1676  TEST(Inotify, ControlEvents) {
  1677    const TempPath dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
  1678    const FileDescriptor fd =
  1679        ASSERT_NO_ERRNO_AND_VALUE(InotifyInit1(IN_NONBLOCK));
  1680  
  1681    const int wd = ASSERT_NO_ERRNO_AND_VALUE(
  1682        InotifyAddWatch(fd.get(), dir.path(), IN_ACCESS));
  1683  
  1684    // Check that events in the mask are dispatched and that control bits are
  1685    // part of the event mask.
  1686    std::vector<std::string> files =
  1687        ASSERT_NO_ERRNO_AND_VALUE(ListDir(dir.path(), false));
  1688    ASSERT_EQ(files.size(), 2);
  1689  
  1690    const std::vector<Event> events1 =
  1691        ASSERT_NO_ERRNO_AND_VALUE(DrainEvents(fd.get()));
  1692    ASSERT_THAT(events1, Are({Event(IN_ACCESS | IN_ISDIR, wd)}));
  1693  
  1694    // Check that events not in the mask are discarded.
  1695    const FileDescriptor dir_fd =
  1696        ASSERT_NO_ERRNO_AND_VALUE(Open(dir.path(), O_RDONLY | O_DIRECTORY));
  1697  
  1698    const std::vector<Event> events2 =
  1699        ASSERT_NO_ERRNO_AND_VALUE(DrainEvents(fd.get()));
  1700    ASSERT_THAT(events2, Are({}));
  1701  }
  1702  
  1703  // Regression test to ensure epoll and directory access doesn't deadlock.
  1704  TEST(Inotify, EpollNoDeadlock) {
  1705    const DisableSave ds;  // Too many syscalls.
  1706  
  1707    const FileDescriptor fd =
  1708        ASSERT_NO_ERRNO_AND_VALUE(InotifyInit1(IN_NONBLOCK));
  1709  
  1710    // Create lots of directories and watch all of them.
  1711    const TempPath root = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
  1712    std::vector<TempPath> children;
  1713    for (size_t i = 0; i < 1000; ++i) {
  1714      auto child = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDirIn(root.path()));
  1715      ASSERT_NO_ERRNO_AND_VALUE(
  1716          InotifyAddWatch(fd.get(), child.path(), IN_ACCESS));
  1717      children.emplace_back(std::move(child));
  1718    }
  1719  
  1720    // Run epoll_wait constantly in a separate thread.
  1721    std::atomic<bool> done(false);
  1722    ScopedThread th([&fd, &done] {
  1723      for (auto start = absl::Now(); absl::Now() - start < absl::Seconds(5);) {
  1724        FileDescriptor epoll_fd = ASSERT_NO_ERRNO_AND_VALUE(NewEpollFD());
  1725        ASSERT_NO_ERRNO(RegisterEpollFD(epoll_fd.get(), fd.get(),
  1726                                        EPOLLIN | EPOLLOUT | EPOLLET, 0));
  1727        struct epoll_event result[1];
  1728        EXPECT_THAT(RetryEINTR(epoll_wait)(epoll_fd.get(), result, 1, -1),
  1729                    SyscallSucceedsWithValue(1));
  1730  
  1731        sched_yield();
  1732      }
  1733      done = true;
  1734    });
  1735  
  1736    // While epoll thread is running, constantly access all directories to
  1737    // generate inotify events.
  1738    while (!done) {
  1739      std::vector<std::string> files =
  1740          ASSERT_NO_ERRNO_AND_VALUE(ListDir(root.path(), false));
  1741      ASSERT_EQ(files.size(), 1002);
  1742      for (const auto& child : files) {
  1743        if (child == "." || child == "..") {
  1744          continue;
  1745        }
  1746        ASSERT_NO_ERRNO_AND_VALUE(ListDir(JoinPath(root.path(), child), false));
  1747      }
  1748      sched_yield();
  1749    }
  1750  }
  1751  
  1752  TEST(Inotify, Fallocate) {
  1753    const TempPath file = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile());
  1754    const FileDescriptor fd =
  1755        ASSERT_NO_ERRNO_AND_VALUE(Open(file.path(), O_RDWR));
  1756  
  1757    const FileDescriptor inotify_fd =
  1758        ASSERT_NO_ERRNO_AND_VALUE(InotifyInit1(IN_NONBLOCK));
  1759    const int wd = ASSERT_NO_ERRNO_AND_VALUE(
  1760        InotifyAddWatch(inotify_fd.get(), file.path(), IN_ALL_EVENTS));
  1761  
  1762    // Do an arbitrary modification with fallocate.
  1763    ASSERT_THAT(RetryEINTR(fallocate)(fd.get(), 0, 0, 123), SyscallSucceeds());
  1764    std::vector<Event> events =
  1765        ASSERT_NO_ERRNO_AND_VALUE(DrainEvents(inotify_fd.get()));
  1766    EXPECT_THAT(events, Are({Event(IN_MODIFY, wd)}));
  1767  }
  1768  
  1769  TEST(Inotify, Utimensat) {
  1770    const TempPath file = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile());
  1771    const FileDescriptor fd =
  1772        ASSERT_NO_ERRNO_AND_VALUE(Open(file.path(), O_RDWR));
  1773  
  1774    const FileDescriptor inotify_fd =
  1775        ASSERT_NO_ERRNO_AND_VALUE(InotifyInit1(IN_NONBLOCK));
  1776    const int wd = ASSERT_NO_ERRNO_AND_VALUE(
  1777        InotifyAddWatch(inotify_fd.get(), file.path(), IN_ALL_EVENTS));
  1778  
  1779    // Just update the access time.
  1780    struct timespec times[2] = {};
  1781    times[0].tv_nsec = UTIME_NOW;
  1782    times[1].tv_nsec = UTIME_OMIT;
  1783    ASSERT_THAT(RetryEINTR(utimensat)(AT_FDCWD, file.path().c_str(), times, 0),
  1784                SyscallSucceeds());
  1785    std::vector<Event> events =
  1786        ASSERT_NO_ERRNO_AND_VALUE(DrainEvents(inotify_fd.get()));
  1787    EXPECT_THAT(events, Are({Event(IN_ACCESS, wd)}));
  1788  
  1789    // Just the modify time.
  1790    times[0].tv_nsec = UTIME_OMIT;
  1791    times[1].tv_nsec = UTIME_NOW;
  1792    ASSERT_THAT(utimensat(AT_FDCWD, file.path().c_str(), times, 0),
  1793                SyscallSucceeds());
  1794    events = ASSERT_NO_ERRNO_AND_VALUE(DrainEvents(inotify_fd.get()));
  1795    EXPECT_THAT(events, Are({Event(IN_MODIFY, wd)}));
  1796  
  1797    // Both together.
  1798    times[0].tv_nsec = UTIME_NOW;
  1799    times[1].tv_nsec = UTIME_NOW;
  1800    ASSERT_THAT(utimensat(AT_FDCWD, file.path().c_str(), times, 0),
  1801                SyscallSucceeds());
  1802    events = ASSERT_NO_ERRNO_AND_VALUE(DrainEvents(inotify_fd.get()));
  1803    EXPECT_THAT(events, Are({Event(IN_ATTRIB, wd)}));
  1804  }
  1805  
  1806  TEST(Inotify, Sendfile) {
  1807    const TempPath root = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
  1808    const TempPath in_file = ASSERT_NO_ERRNO_AND_VALUE(
  1809        TempPath::CreateFileWith(root.path(), "x", 0644));
  1810    const TempPath out_file = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile());
  1811    const FileDescriptor in =
  1812        ASSERT_NO_ERRNO_AND_VALUE(Open(in_file.path(), O_RDONLY));
  1813    const FileDescriptor out =
  1814        ASSERT_NO_ERRNO_AND_VALUE(Open(out_file.path(), O_WRONLY));
  1815  
  1816    // Create separate inotify instances for the in and out fds. If both watches
  1817    // were on the same instance, we would have discrepancies between Linux and
  1818    // gVisor (order of events, duplicate events), which is not that important
  1819    // since inotify is asynchronous anyway.
  1820    const FileDescriptor in_inotify =
  1821        ASSERT_NO_ERRNO_AND_VALUE(InotifyInit1(IN_NONBLOCK));
  1822    const FileDescriptor out_inotify =
  1823        ASSERT_NO_ERRNO_AND_VALUE(InotifyInit1(IN_NONBLOCK));
  1824    const int in_wd = ASSERT_NO_ERRNO_AND_VALUE(
  1825        InotifyAddWatch(in_inotify.get(), in_file.path(), IN_ALL_EVENTS));
  1826    const int out_wd = ASSERT_NO_ERRNO_AND_VALUE(
  1827        InotifyAddWatch(out_inotify.get(), out_file.path(), IN_ALL_EVENTS));
  1828  
  1829    ASSERT_THAT(sendfile(out.get(), in.get(), /*offset=*/nullptr, 1),
  1830                SyscallSucceeds());
  1831  
  1832    // Expect a single access event and a single modify event.
  1833    std::vector<Event> in_events =
  1834        ASSERT_NO_ERRNO_AND_VALUE(DrainEvents(in_inotify.get()));
  1835    std::vector<Event> out_events =
  1836        ASSERT_NO_ERRNO_AND_VALUE(DrainEvents(out_inotify.get()));
  1837    EXPECT_THAT(in_events, Are({Event(IN_ACCESS, in_wd)}));
  1838    EXPECT_THAT(out_events, Are({Event(IN_MODIFY, out_wd)}));
  1839  }
  1840  
  1841  TEST(Inotify, SpliceOnWatchTarget) {
  1842    int pipefds[2];
  1843    ASSERT_THAT(pipe2(pipefds, O_NONBLOCK), SyscallSucceeds());
  1844  
  1845    const TempPath dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
  1846    const FileDescriptor inotify_fd =
  1847        ASSERT_NO_ERRNO_AND_VALUE(InotifyInit1(IN_NONBLOCK));
  1848    const TempPath file = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileWith(
  1849        dir.path(), "some content", TempPath::kDefaultFileMode));
  1850  
  1851    const FileDescriptor fd =
  1852        ASSERT_NO_ERRNO_AND_VALUE(Open(file.path(), O_RDWR));
  1853    const int dir_wd = ASSERT_NO_ERRNO_AND_VALUE(
  1854        InotifyAddWatch(inotify_fd.get(), dir.path(), IN_ALL_EVENTS));
  1855    const int file_wd = ASSERT_NO_ERRNO_AND_VALUE(
  1856        InotifyAddWatch(inotify_fd.get(), file.path(), IN_ALL_EVENTS));
  1857  
  1858    EXPECT_THAT(splice(fd.get(), nullptr, pipefds[1], nullptr, 1, /*flags=*/0),
  1859                SyscallSucceedsWithValue(1));
  1860  
  1861    // Surprisingly, events may not be generated in Linux if we read from a file.
  1862    // fs/splice.c:generic_file_splice_read, which is used most often, does not
  1863    // generate events, whereas fs/splice.c:default_file_splice_read does.
  1864    std::vector<Event> events =
  1865        ASSERT_NO_ERRNO_AND_VALUE(DrainEvents(inotify_fd.get()));
  1866    if (IsRunningOnGvisor()) {
  1867      ASSERT_THAT(events, Are({Event(IN_ACCESS, dir_wd, Basename(file.path())),
  1868                               Event(IN_ACCESS, file_wd)}));
  1869    }
  1870  
  1871    EXPECT_THAT(splice(pipefds[0], nullptr, fd.get(), nullptr, 1, /*flags=*/0),
  1872                SyscallSucceedsWithValue(1));
  1873  
  1874    // On Linux, between 983652c69199 ("splice: report related fsnotify events")
  1875    // and d53471ba6f7a ("splice: remove permission hook from
  1876    // iter_file_splice_write()"), splice(2) generates two modification events in
  1877    // many cases, by calling fsnotify_modify() in both fs/splice.c:do_splice()
  1878    // and fs/splice.c:iter_file_splice_write() =>
  1879    // fs/read_write.c:vfs_iter_write() => do_iter_write().
  1880    events = ASSERT_NO_ERRNO_AND_VALUE(DrainEvents(inotify_fd.get()));
  1881    if (events.size() == 4) {
  1882      EXPECT_THAT(events, Are({
  1883                              Event(IN_MODIFY, dir_wd, Basename(file.path())),
  1884                              Event(IN_MODIFY, file_wd),
  1885                              Event(IN_MODIFY, dir_wd, Basename(file.path())),
  1886                              Event(IN_MODIFY, file_wd),
  1887                          }));
  1888    } else {
  1889      EXPECT_THAT(events, Are({
  1890                              Event(IN_MODIFY, dir_wd, Basename(file.path())),
  1891                              Event(IN_MODIFY, file_wd),
  1892                          }));
  1893    }
  1894  }
  1895  
  1896  // Watches on a parent should not be triggered by actions on a hard link to one
  1897  // of its children that has a different parent.
  1898  TEST(Inotify, LinkOnOtherParent) {
  1899    // Inotify does not work properly with hard links in gofer and overlay fs.
  1900    SKIP_IF(IsRunningOnGvisor() &&
  1901            !ASSERT_NO_ERRNO_AND_VALUE(IsTmpfs(GetAbsoluteTestTmpdir())));
  1902  
  1903    const TempPath dir1 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
  1904    const TempPath dir2 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
  1905    const TempPath file =
  1906        ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileIn(dir1.path()));
  1907    std::string link_path = NewTempAbsPathInDir(dir2.path());
  1908  
  1909    ASSERT_THAT(link(file.path().c_str(), link_path.c_str()), SyscallSucceeds());
  1910  
  1911    const FileDescriptor inotify_fd =
  1912        ASSERT_NO_ERRNO_AND_VALUE(InotifyInit1(IN_NONBLOCK));
  1913    ASSERT_NO_ERRNO_AND_VALUE(
  1914        InotifyAddWatch(inotify_fd.get(), dir1.path(), IN_ALL_EVENTS));
  1915  
  1916    // Perform various actions on the link outside of dir1, which should trigger
  1917    // no inotify events.
  1918    FileDescriptor fd =
  1919        ASSERT_NO_ERRNO_AND_VALUE(Open(link_path.c_str(), O_RDWR));
  1920    int val = 0;
  1921    ASSERT_THAT(write(fd.get(), &val, sizeof(val)), SyscallSucceeds());
  1922    ASSERT_THAT(read(fd.get(), &val, sizeof(val)), SyscallSucceeds());
  1923    ASSERT_THAT(ftruncate(fd.get(), 12345), SyscallSucceeds());
  1924  
  1925    // Close before unlinking; some filesystems cannot restore an open fd on an
  1926    // unlinked file.
  1927    fd.reset();
  1928    ASSERT_THAT(unlink(link_path.c_str()), SyscallSucceeds());
  1929  
  1930    const std::vector<Event> events =
  1931        ASSERT_NO_ERRNO_AND_VALUE(DrainEvents(inotify_fd.get()));
  1932    EXPECT_THAT(events, Are({}));
  1933  }
  1934  
  1935  TEST(Inotify, Xattr) {
  1936    // TODO(gvisor.dev/issue/1636): Support extended attributes in runsc gofer.
  1937    SKIP_IF(IsRunningOnGvisor());
  1938  
  1939    const TempPath file = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile());
  1940    const std::string path = file.path();
  1941    const FileDescriptor fd = ASSERT_NO_ERRNO_AND_VALUE(Open(path, O_RDWR));
  1942    const FileDescriptor inotify_fd =
  1943        ASSERT_NO_ERRNO_AND_VALUE(InotifyInit1(IN_NONBLOCK));
  1944    const int wd = ASSERT_NO_ERRNO_AND_VALUE(
  1945        InotifyAddWatch(inotify_fd.get(), path, IN_ALL_EVENTS));
  1946  
  1947    const char* cpath = path.c_str();
  1948    const char* name = "user.test";
  1949    int val = 123;
  1950    ASSERT_THAT(setxattr(cpath, name, &val, sizeof(val), /*flags=*/0),
  1951                SyscallSucceeds());
  1952    std::vector<Event> events =
  1953        ASSERT_NO_ERRNO_AND_VALUE(DrainEvents(inotify_fd.get()));
  1954    EXPECT_THAT(events, Are({Event(IN_ATTRIB, wd)}));
  1955  
  1956    ASSERT_THAT(getxattr(cpath, name, &val, sizeof(val)), SyscallSucceeds());
  1957    events = ASSERT_NO_ERRNO_AND_VALUE(DrainEvents(inotify_fd.get()));
  1958    EXPECT_THAT(events, Are({}));
  1959  
  1960    char list[100];
  1961    ASSERT_THAT(listxattr(cpath, list, sizeof(list)), SyscallSucceeds());
  1962    events = ASSERT_NO_ERRNO_AND_VALUE(DrainEvents(inotify_fd.get()));
  1963    EXPECT_THAT(events, Are({}));
  1964  
  1965    ASSERT_THAT(removexattr(cpath, name), SyscallSucceeds());
  1966    events = ASSERT_NO_ERRNO_AND_VALUE(DrainEvents(inotify_fd.get()));
  1967    EXPECT_THAT(events, Are({Event(IN_ATTRIB, wd)}));
  1968  
  1969    ASSERT_THAT(fsetxattr(fd.get(), name, &val, sizeof(val), /*flags=*/0),
  1970                SyscallSucceeds());
  1971    events = ASSERT_NO_ERRNO_AND_VALUE(DrainEvents(inotify_fd.get()));
  1972    EXPECT_THAT(events, Are({Event(IN_ATTRIB, wd)}));
  1973  
  1974    ASSERT_THAT(fgetxattr(fd.get(), name, &val, sizeof(val)), SyscallSucceeds());
  1975    events = ASSERT_NO_ERRNO_AND_VALUE(DrainEvents(inotify_fd.get()));
  1976    EXPECT_THAT(events, Are({}));
  1977  
  1978    ASSERT_THAT(flistxattr(fd.get(), list, sizeof(list)), SyscallSucceeds());
  1979    events = ASSERT_NO_ERRNO_AND_VALUE(DrainEvents(inotify_fd.get()));
  1980    EXPECT_THAT(events, Are({}));
  1981  
  1982    ASSERT_THAT(fremovexattr(fd.get(), name), SyscallSucceeds());
  1983    events = ASSERT_NO_ERRNO_AND_VALUE(DrainEvents(inotify_fd.get()));
  1984    EXPECT_THAT(events, Are({Event(IN_ATTRIB, wd)}));
  1985  }
  1986  
  1987  TEST(Inotify, Exec) {
  1988    const FileDescriptor fd =
  1989        ASSERT_NO_ERRNO_AND_VALUE(InotifyInit1(IN_NONBLOCK));
  1990    // Create a new executable file instead of using /bin/true directly in case
  1991    // the test suite uses it at any point and generates extra events.
  1992    TempPath p = ASSERT_NO_ERRNO_AND_VALUE(
  1993        TempPath::CreateFileWith(GetAbsoluteTestTmpdir(), "#!/bin/true", 0755));
  1994  
  1995    const int wd = ASSERT_NO_ERRNO_AND_VALUE(
  1996        InotifyAddWatch(fd.get(), p.path(), IN_ALL_EVENTS));
  1997    // Perform exec.
  1998    pid_t child = -1;
  1999    int execve_errno = -1;
  2000    auto kill = ASSERT_NO_ERRNO_AND_VALUE(
  2001        ForkAndExec(p.path(), {}, {}, nullptr, &child, &execve_errno));
  2002    ASSERT_EQ(0, execve_errno);
  2003  
  2004    int status;
  2005    ASSERT_THAT(RetryEINTR(waitpid)(child, &status, 0), SyscallSucceeds());
  2006    EXPECT_EQ(0, status);
  2007  
  2008    // Process cleanup no longer needed.
  2009    kill.Release();
  2010  
  2011    std::vector<Event> events = ASSERT_NO_ERRNO_AND_VALUE(DrainEvents(fd.get()));
  2012    EXPECT_THAT(events, Are({Event(IN_OPEN, wd), Event(IN_ACCESS, wd),
  2013                             Event(IN_CLOSE_NOWRITE, wd)}));
  2014  }
  2015  
  2016  // Watches without IN_EXCL_UNLINK, should continue to emit events for file
  2017  // descriptors after their corresponding files have been unlinked.
  2018  //
  2019  // We need to disable S/R because there are filesystems where we cannot re-open
  2020  // fds to an unlinked file across S/R, e.g. gofer-backed filesytems.
  2021  TEST(Inotify, IncludeUnlinkedFile) {
  2022    const DisableSave ds;
  2023  
  2024    const TempPath dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
  2025    const TempPath file = ASSERT_NO_ERRNO_AND_VALUE(
  2026        TempPath::CreateFileWith(dir.path(), "123", TempPath::kDefaultFileMode));
  2027    FileDescriptor fd = ASSERT_NO_ERRNO_AND_VALUE(Open(file.path(), O_RDWR));
  2028  
  2029    const FileDescriptor inotify_fd =
  2030        ASSERT_NO_ERRNO_AND_VALUE(InotifyInit1(IN_NONBLOCK));
  2031    const int dir_wd = ASSERT_NO_ERRNO_AND_VALUE(
  2032        InotifyAddWatch(inotify_fd.get(), dir.path(), IN_ALL_EVENTS));
  2033    const int file_wd = ASSERT_NO_ERRNO_AND_VALUE(
  2034        InotifyAddWatch(inotify_fd.get(), file.path(), IN_ALL_EVENTS));
  2035  
  2036    ASSERT_THAT(unlink(file.path().c_str()), SyscallSucceeds());
  2037    int val = 0;
  2038    ASSERT_THAT(read(fd.get(), &val, sizeof(val)), SyscallSucceeds());
  2039    ASSERT_THAT(write(fd.get(), &val, sizeof(val)), SyscallSucceeds());
  2040    std::vector<Event> events =
  2041        ASSERT_NO_ERRNO_AND_VALUE(DrainEvents(inotify_fd.get()));
  2042    EXPECT_THAT(events, AnyOf(Are({
  2043                                  Event(IN_ATTRIB, file_wd),
  2044                                  Event(IN_DELETE, dir_wd, Basename(file.path())),
  2045                                  Event(IN_ACCESS, dir_wd, Basename(file.path())),
  2046                                  Event(IN_ACCESS, file_wd),
  2047                                  Event(IN_MODIFY, dir_wd, Basename(file.path())),
  2048                                  Event(IN_MODIFY, file_wd),
  2049                              }),
  2050                              Are({
  2051                                  Event(IN_DELETE, dir_wd, Basename(file.path())),
  2052                                  Event(IN_ATTRIB, file_wd),
  2053                                  Event(IN_ACCESS, dir_wd, Basename(file.path())),
  2054                                  Event(IN_ACCESS, file_wd),
  2055                                  Event(IN_MODIFY, dir_wd, Basename(file.path())),
  2056                                  Event(IN_MODIFY, file_wd),
  2057                              })));
  2058  
  2059    fd.reset();
  2060    events = ASSERT_NO_ERRNO_AND_VALUE(DrainEvents(inotify_fd.get()));
  2061    EXPECT_THAT(events, Are({
  2062                            Event(IN_CLOSE_WRITE, dir_wd, Basename(file.path())),
  2063                            Event(IN_CLOSE_WRITE, file_wd),
  2064                            Event(IN_DELETE_SELF, file_wd),
  2065                            Event(IN_IGNORED, file_wd),
  2066                        }));
  2067  }
  2068  
  2069  // Watches created with IN_EXCL_UNLINK will stop emitting events on fds for
  2070  // children that have already been unlinked.
  2071  //
  2072  // We need to disable S/R because there are filesystems where we cannot re-open
  2073  // fds to an unlinked file across S/R, e.g. gofer-backed filesytems.
  2074  TEST(Inotify, ExcludeUnlink) {
  2075    const DisableSave ds;
  2076    const TempPath dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
  2077    const TempPath file =
  2078        ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileIn(dir.path()));
  2079  
  2080    FileDescriptor fd = ASSERT_NO_ERRNO_AND_VALUE(Open(file.path(), O_RDWR));
  2081  
  2082    const FileDescriptor inotify_fd =
  2083        ASSERT_NO_ERRNO_AND_VALUE(InotifyInit1(IN_NONBLOCK));
  2084    const int dir_wd = ASSERT_NO_ERRNO_AND_VALUE(InotifyAddWatch(
  2085        inotify_fd.get(), dir.path(), IN_ALL_EVENTS | IN_EXCL_UNLINK));
  2086    const int file_wd = ASSERT_NO_ERRNO_AND_VALUE(InotifyAddWatch(
  2087        inotify_fd.get(), file.path(), IN_ALL_EVENTS | IN_EXCL_UNLINK));
  2088  
  2089    // Unlink the child, which should cause further operations on the open file
  2090    // descriptor to be ignored.
  2091    ASSERT_THAT(unlink(file.path().c_str()), SyscallSucceeds());
  2092    int val = 0;
  2093    ASSERT_THAT(write(fd.get(), &val, sizeof(val)), SyscallSucceeds());
  2094    ASSERT_THAT(read(fd.get(), &val, sizeof(val)), SyscallSucceeds());
  2095    std::vector<Event> events =
  2096        ASSERT_NO_ERRNO_AND_VALUE(DrainEvents(inotify_fd.get()));
  2097    EXPECT_THAT(events, AreUnordered({
  2098                            Event(IN_ATTRIB, file_wd),
  2099                            Event(IN_DELETE, dir_wd, Basename(file.path())),
  2100                        }));
  2101  
  2102    fd.reset();
  2103    events = ASSERT_NO_ERRNO_AND_VALUE(DrainEvents(inotify_fd.get()));
  2104    ASSERT_THAT(events, Are({
  2105                            Event(IN_DELETE_SELF, file_wd),
  2106                            Event(IN_IGNORED, file_wd),
  2107                        }));
  2108  }
  2109  
  2110  // We need to disable S/R because there are filesystems where we cannot re-open
  2111  // fds to an unlinked file across S/R, e.g. gofer-backed filesytems.
  2112  TEST(Inotify, ExcludeUnlinkDirectory) {
  2113    const DisableSave ds;
  2114    const TempPath parent = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
  2115    TempPath dir =
  2116        ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDirIn(parent.path()));
  2117    std::string dirPath = dir.path();
  2118    const FileDescriptor inotify_fd =
  2119        ASSERT_NO_ERRNO_AND_VALUE(InotifyInit1(IN_NONBLOCK));
  2120  
  2121    FileDescriptor fd =
  2122        ASSERT_NO_ERRNO_AND_VALUE(Open(dirPath.c_str(), O_RDONLY | O_DIRECTORY));
  2123    const int parent_wd = ASSERT_NO_ERRNO_AND_VALUE(InotifyAddWatch(
  2124        inotify_fd.get(), parent.path(), IN_ALL_EVENTS | IN_EXCL_UNLINK));
  2125    const int self_wd = ASSERT_NO_ERRNO_AND_VALUE(InotifyAddWatch(
  2126        inotify_fd.get(), dir.path(), IN_ALL_EVENTS | IN_EXCL_UNLINK));
  2127  
  2128    // Unlink the dir, and then close the open fd.
  2129    ASSERT_THAT(rmdir(dirPath.c_str()), SyscallSucceeds());
  2130    dir.reset();
  2131  
  2132    std::vector<Event> events =
  2133        ASSERT_NO_ERRNO_AND_VALUE(DrainEvents(inotify_fd.get()));
  2134    // No close event should appear.
  2135    ASSERT_THAT(events,
  2136                Are({Event(IN_DELETE | IN_ISDIR, parent_wd, Basename(dirPath))}));
  2137  
  2138    fd.reset();
  2139    events = ASSERT_NO_ERRNO_AND_VALUE(DrainEvents(inotify_fd.get()));
  2140    ASSERT_THAT(events, Are({
  2141                            Event(IN_DELETE_SELF, self_wd),
  2142                            Event(IN_IGNORED, self_wd),
  2143                        }));
  2144  }
  2145  
  2146  // If "dir/child" and "dir/child2" are links to the same file, and "dir/child"
  2147  // is unlinked, a watch on "dir" with IN_EXCL_UNLINK will exclude future events
  2148  // for fds on "dir/child" but not "dir/child2".
  2149  //
  2150  // We need to disable S/R because there are filesystems where we cannot re-open
  2151  // fds to an unlinked file across S/R, e.g. gofer-backed filesytems.
  2152  TEST(Inotify, ExcludeUnlinkMultipleChildren) {
  2153    // Inotify does not work properly with hard links in gofer and overlay fs.
  2154    SKIP_IF(IsRunningOnGvisor() &&
  2155            !ASSERT_NO_ERRNO_AND_VALUE(IsTmpfs(GetAbsoluteTestTmpdir())));
  2156  
  2157    const DisableSave ds;
  2158  
  2159    const TempPath dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
  2160    const TempPath file =
  2161        ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileIn(dir.path()));
  2162    std::string path1 = file.path();
  2163    std::string path2 = NewTempAbsPathInDir(dir.path());
  2164    ASSERT_THAT(link(path1.c_str(), path2.c_str()), SyscallSucceeds());
  2165  
  2166    const FileDescriptor fd1 =
  2167        ASSERT_NO_ERRNO_AND_VALUE(Open(path1.c_str(), O_RDWR));
  2168    const FileDescriptor fd2 =
  2169        ASSERT_NO_ERRNO_AND_VALUE(Open(path2.c_str(), O_RDWR));
  2170  
  2171    const FileDescriptor inotify_fd =
  2172        ASSERT_NO_ERRNO_AND_VALUE(InotifyInit1(IN_NONBLOCK));
  2173    const int wd = ASSERT_NO_ERRNO_AND_VALUE(InotifyAddWatch(
  2174        inotify_fd.get(), dir.path(), IN_ALL_EVENTS | IN_EXCL_UNLINK));
  2175  
  2176    // After unlinking path1, only events on the fd for path2 should be generated.
  2177    ASSERT_THAT(unlink(path1.c_str()), SyscallSucceeds());
  2178    ASSERT_THAT(write(fd1.get(), "x", 1), SyscallSucceeds());
  2179    ASSERT_THAT(write(fd2.get(), "x", 1), SyscallSucceeds());
  2180  
  2181    const std::vector<Event> events =
  2182        ASSERT_NO_ERRNO_AND_VALUE(DrainEvents(inotify_fd.get()));
  2183    EXPECT_THAT(events, Are({
  2184                            Event(IN_DELETE, wd, Basename(path1)),
  2185                            Event(IN_MODIFY, wd, Basename(path2)),
  2186                        }));
  2187  }
  2188  
  2189  // On native Linux, actions of data type FSNOTIFY_EVENT_INODE are not affected
  2190  // by IN_EXCL_UNLINK (see
  2191  // fs/notify/inotify/inotify_fsnotify.c:inotify_handle_event). Inode-level
  2192  // events include changes to metadata and extended attributes.
  2193  //
  2194  // We need to disable S/R because there are filesystems where we cannot re-open
  2195  // fds to an unlinked file across S/R, e.g. gofer-backed filesytems.
  2196  TEST(Inotify, ExcludeUnlinkInodeEvents) {
  2197    // NOTE(gvisor.dev/issue/3654): In the gofer filesystem, we do not allow
  2198    // setting attributes through an fd if the file at the open path has been
  2199    // deleted.
  2200    SKIP_IF(IsRunningOnGvisor() &&
  2201            !ASSERT_NO_ERRNO_AND_VALUE(IsTmpfs(GetAbsoluteTestTmpdir())));
  2202  
  2203    const DisableSave ds;
  2204  
  2205    const TempPath dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
  2206    const TempPath file =
  2207        ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileIn(dir.path()));
  2208  
  2209    const FileDescriptor fd =
  2210        ASSERT_NO_ERRNO_AND_VALUE(Open(file.path().c_str(), O_RDWR));
  2211  
  2212    const FileDescriptor inotify_fd =
  2213        ASSERT_NO_ERRNO_AND_VALUE(InotifyInit1(IN_NONBLOCK));
  2214    const int dir_wd = ASSERT_NO_ERRNO_AND_VALUE(InotifyAddWatch(
  2215        inotify_fd.get(), dir.path(), IN_ALL_EVENTS | IN_EXCL_UNLINK));
  2216    const int file_wd = ASSERT_NO_ERRNO_AND_VALUE(InotifyAddWatch(
  2217        inotify_fd.get(), file.path(), IN_ALL_EVENTS | IN_EXCL_UNLINK));
  2218  
  2219    // Even after unlinking, inode-level operations will trigger events regardless
  2220    // of IN_EXCL_UNLINK.
  2221    ASSERT_THAT(unlink(file.path().c_str()), SyscallSucceeds());
  2222  
  2223    // Perform various actions on fd.
  2224    ASSERT_THAT(ftruncate(fd.get(), 12345), SyscallSucceeds());
  2225    std::vector<Event> events =
  2226        ASSERT_NO_ERRNO_AND_VALUE(DrainEvents(inotify_fd.get()));
  2227    EXPECT_THAT(events, AnyOf(Are({
  2228                                  Event(IN_ATTRIB, file_wd),
  2229                                  Event(IN_DELETE, dir_wd, Basename(file.path())),
  2230                                  Event(IN_MODIFY, dir_wd, Basename(file.path())),
  2231                                  Event(IN_MODIFY, file_wd),
  2232                              }),
  2233                              Are({
  2234                                  Event(IN_DELETE, dir_wd, Basename(file.path())),
  2235                                  Event(IN_ATTRIB, file_wd),
  2236                                  Event(IN_MODIFY, dir_wd, Basename(file.path())),
  2237                                  Event(IN_MODIFY, file_wd),
  2238                              })));
  2239  
  2240    const struct timeval times[2] = {{1, 0}, {2, 0}};
  2241    ASSERT_THAT(futimes(fd.get(), times), SyscallSucceeds());
  2242    events = ASSERT_NO_ERRNO_AND_VALUE(DrainEvents(inotify_fd.get()));
  2243    EXPECT_THAT(events, Are({
  2244                            Event(IN_ATTRIB, dir_wd, Basename(file.path())),
  2245                            Event(IN_ATTRIB, file_wd),
  2246                        }));
  2247  
  2248    // S/R is disabled on this entire test due to behavior with unlink; it must
  2249    // also be disabled after this point because of fchmod.
  2250    ASSERT_THAT(fchmod(fd.get(), 0777), SyscallSucceeds());
  2251    events = ASSERT_NO_ERRNO_AND_VALUE(DrainEvents(inotify_fd.get()));
  2252    EXPECT_THAT(events, Are({
  2253                            Event(IN_ATTRIB, dir_wd, Basename(file.path())),
  2254                            Event(IN_ATTRIB, file_wd),
  2255                        }));
  2256  }
  2257  
  2258  TEST(Inotify, OneShot) {
  2259    const TempPath file = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile());
  2260    const FileDescriptor inotify_fd =
  2261        ASSERT_NO_ERRNO_AND_VALUE(InotifyInit1(IN_NONBLOCK));
  2262  
  2263    const int wd = ASSERT_NO_ERRNO_AND_VALUE(
  2264        InotifyAddWatch(inotify_fd.get(), file.path(), IN_MODIFY | IN_ONESHOT));
  2265  
  2266    // Open an fd, write to it, and then close it.
  2267    FileDescriptor fd = ASSERT_NO_ERRNO_AND_VALUE(Open(file.path(), O_WRONLY));
  2268    ASSERT_THAT(write(fd.get(), "x", 1), SyscallSucceedsWithValue(1));
  2269    fd.reset();
  2270  
  2271    // We should get a single event followed by IN_IGNORED indicating removal
  2272    // of the one-shot watch. Prior activity (i.e. open) that is not in the mask
  2273    // should not trigger removal, and activity after removal (i.e. close) should
  2274    // not generate events.
  2275    std::vector<Event> events =
  2276        ASSERT_NO_ERRNO_AND_VALUE(DrainEvents(inotify_fd.get()));
  2277    EXPECT_THAT(events, Are({
  2278                            Event(IN_MODIFY, wd),
  2279                            Event(IN_IGNORED, wd),
  2280                        }));
  2281  
  2282    // The watch should already have been removed.
  2283    EXPECT_THAT(inotify_rm_watch(inotify_fd.get(), wd),
  2284                SyscallFailsWithErrno(EINVAL));
  2285  }
  2286  
  2287  // This test helps verify that the lock order of filesystem and inotify locks
  2288  // is respected when inotify instances and watch targets are concurrently being
  2289  // destroyed.
  2290  TEST(InotifyTest, InotifyAndTargetDestructionDoNotDeadlock) {
  2291    const DisableSave ds;  // Too many syscalls.
  2292  
  2293    // A file descriptor protected by a mutex. This ensures that while a
  2294    // descriptor is in use, it cannot be closed and reused for a different file
  2295    // description.
  2296    struct atomic_fd {
  2297      int fd;
  2298      absl::Mutex mu;
  2299    };
  2300  
  2301    // Set up initial inotify instances.
  2302    constexpr int num_fds = 3;
  2303    std::vector<atomic_fd> fds(num_fds);
  2304    for (int i = 0; i < num_fds; i++) {
  2305      int fd;
  2306      ASSERT_THAT(fd = inotify_init1(IN_NONBLOCK), SyscallSucceeds());
  2307      fds[i].fd = fd;
  2308    }
  2309  
  2310    // Set up initial watch targets.
  2311    std::vector<std::string> paths;
  2312    for (int i = 0; i < 3; i++) {
  2313      paths.push_back(NewTempAbsPath());
  2314      ASSERT_THAT(mknod(paths[i].c_str(), S_IFREG | 0600, 0), SyscallSucceeds());
  2315    }
  2316  
  2317    constexpr absl::Duration runtime = absl::Seconds(4);
  2318  
  2319    // Constantly replace each inotify instance with a new one.
  2320    auto replace_fds = [&] {
  2321      for (auto start = absl::Now(); absl::Now() - start < runtime;) {
  2322        for (auto& afd : fds) {
  2323          int new_fd;
  2324          ASSERT_THAT(new_fd = inotify_init1(IN_NONBLOCK), SyscallSucceeds());
  2325          absl::MutexLock l(&afd.mu);
  2326          ASSERT_THAT(close(afd.fd), SyscallSucceeds());
  2327          afd.fd = new_fd;
  2328          for (auto& p : paths) {
  2329            // inotify_add_watch may fail if the file at p was deleted.
  2330            ASSERT_THAT(inotify_add_watch(afd.fd, p.c_str(), IN_ALL_EVENTS),
  2331                        AnyOf(SyscallSucceeds(), SyscallFailsWithErrno(ENOENT)));
  2332          }
  2333        }
  2334        sched_yield();
  2335      }
  2336    };
  2337  
  2338    std::list<ScopedThread> ts;
  2339    for (int i = 0; i < 3; i++) {
  2340      ts.emplace_back(replace_fds);
  2341    }
  2342  
  2343    // Constantly replace each watch target with a new one.
  2344    for (auto start = absl::Now(); absl::Now() - start < runtime;) {
  2345      for (auto& p : paths) {
  2346        ASSERT_THAT(unlink(p.c_str()), SyscallSucceeds());
  2347        ASSERT_THAT(mknod(p.c_str(), S_IFREG | 0600, 0), SyscallSucceeds());
  2348      }
  2349      sched_yield();
  2350    }
  2351  }
  2352  
  2353  // This test helps verify that the lock order of filesystem and inotify locks
  2354  // is respected when adding/removing watches occurs concurrently with the
  2355  // removal of their targets.
  2356  TEST(InotifyTest, AddRemoveUnlinkDoNotDeadlock) {
  2357    const DisableSave ds;  // Too many syscalls.
  2358  
  2359    // Set up inotify instances.
  2360    constexpr int num_fds = 3;
  2361    std::vector<int> fds(num_fds);
  2362    for (int i = 0; i < num_fds; i++) {
  2363      ASSERT_THAT(fds[i] = inotify_init1(IN_NONBLOCK), SyscallSucceeds());
  2364    }
  2365  
  2366    // Set up initial watch targets.
  2367    std::vector<std::string> paths;
  2368    for (int i = 0; i < 3; i++) {
  2369      paths.push_back(NewTempAbsPath());
  2370      ASSERT_THAT(mknod(paths[i].c_str(), S_IFREG | 0600, 0), SyscallSucceeds());
  2371    }
  2372  
  2373    constexpr absl::Duration runtime = absl::Seconds(1);
  2374  
  2375    // Constantly add/remove watches for each inotify instance/watch target pair.
  2376    auto add_remove_watches = [&] {
  2377      for (auto start = absl::Now(); absl::Now() - start < runtime;) {
  2378        for (int fd : fds) {
  2379          for (auto& p : paths) {
  2380            // Do not assert on inotify_add_watch and inotify_rm_watch. They may
  2381            // fail if the file at p was deleted. inotify_add_watch may also fail
  2382            // if another thread beat us to adding a watch.
  2383            const int wd = inotify_add_watch(fd, p.c_str(), IN_ALL_EVENTS);
  2384            if (wd > 0) {
  2385              inotify_rm_watch(fd, wd);
  2386            }
  2387          }
  2388        }
  2389        sched_yield();
  2390      }
  2391    };
  2392  
  2393    std::list<ScopedThread> ts;
  2394    for (int i = 0; i < 15; i++) {
  2395      ts.emplace_back(add_remove_watches);
  2396    }
  2397  
  2398    // Constantly replace each watch target with a new one.
  2399    for (auto start = absl::Now(); absl::Now() - start < runtime;) {
  2400      for (auto& p : paths) {
  2401        ASSERT_THAT(unlink(p.c_str()), SyscallSucceeds());
  2402        ASSERT_THAT(mknod(p.c_str(), S_IFREG | 0600, 0), SyscallSucceeds());
  2403      }
  2404      sched_yield();
  2405    }
  2406  }
  2407  
  2408  // This test helps verify that the lock order of filesystem and inotify locks
  2409  // is respected when many inotify events and filesystem operations occur
  2410  // simultaneously.
  2411  TEST(InotifyTest, NotifyNoDeadlock) {
  2412    const DisableSave ds;  // Too many syscalls.
  2413  
  2414    const TempPath parent = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
  2415    const std::string dir = parent.path();
  2416  
  2417    // mu protects file, which will change on rename.
  2418    absl::Mutex mu;
  2419    std::string file = NewTempAbsPathInDir(dir);
  2420    ASSERT_THAT(mknod(file.c_str(), 0644 | S_IFREG, 0), SyscallSucceeds());
  2421  
  2422    const absl::Duration runtime = absl::Milliseconds(300);
  2423  
  2424    // Add/remove watches on dir and file.
  2425    ScopedThread add_remove_watches([&] {
  2426      const FileDescriptor ifd =
  2427          ASSERT_NO_ERRNO_AND_VALUE(InotifyInit1(IN_NONBLOCK));
  2428      int dir_wd = ASSERT_NO_ERRNO_AND_VALUE(
  2429          InotifyAddWatch(ifd.get(), dir, IN_ALL_EVENTS));
  2430      int file_wd;
  2431      {
  2432        absl::ReaderMutexLock l(&mu);
  2433        file_wd = ASSERT_NO_ERRNO_AND_VALUE(
  2434            InotifyAddWatch(ifd.get(), file, IN_ALL_EVENTS));
  2435      }
  2436      for (auto start = absl::Now(); absl::Now() - start < runtime;) {
  2437        ASSERT_THAT(inotify_rm_watch(ifd.get(), file_wd), SyscallSucceeds());
  2438        ASSERT_THAT(inotify_rm_watch(ifd.get(), dir_wd), SyscallSucceeds());
  2439        dir_wd = ASSERT_NO_ERRNO_AND_VALUE(
  2440            InotifyAddWatch(ifd.get(), dir, IN_ALL_EVENTS));
  2441        {
  2442          absl::ReaderMutexLock l(&mu);
  2443          file_wd = ASSERT_NO_ERRNO_AND_VALUE(
  2444              InotifyAddWatch(ifd.get(), file, IN_ALL_EVENTS));
  2445        }
  2446        sched_yield();
  2447      }
  2448    });
  2449  
  2450    // Modify attributes on dir and file.
  2451    ScopedThread stats([&] {
  2452      int fd, dir_fd;
  2453      {
  2454        absl::ReaderMutexLock l(&mu);
  2455        ASSERT_THAT(fd = open(file.c_str(), O_RDONLY), SyscallSucceeds());
  2456      }
  2457      ASSERT_THAT(dir_fd = open(dir.c_str(), O_RDONLY | O_DIRECTORY),
  2458                  SyscallSucceeds());
  2459      const struct timeval times[2] = {{1, 0}, {2, 0}};
  2460  
  2461      for (auto start = absl::Now(); absl::Now() - start < runtime;) {
  2462        {
  2463          absl::ReaderMutexLock l(&mu);
  2464          EXPECT_THAT(utimes(file.c_str(), times), SyscallSucceeds());
  2465        }
  2466        EXPECT_THAT(futimes(fd, times), SyscallSucceeds());
  2467        EXPECT_THAT(utimes(dir.c_str(), times), SyscallSucceeds());
  2468        EXPECT_THAT(futimes(dir_fd, times), SyscallSucceeds());
  2469        sched_yield();
  2470      }
  2471    });
  2472  
  2473    // Modify extended attributes on dir and file.
  2474    ScopedThread xattrs([&] {
  2475      // TODO(gvisor.dev/issue/1636): Support extended attributes in runsc gofer.
  2476      if (!IsRunningOnGvisor()) {
  2477        int fd;
  2478        {
  2479          absl::ReaderMutexLock l(&mu);
  2480          ASSERT_THAT(fd = open(file.c_str(), O_RDONLY), SyscallSucceeds());
  2481        }
  2482  
  2483        const char* name = "user.test";
  2484        int val = 123;
  2485        for (auto start = absl::Now(); absl::Now() - start < runtime;) {
  2486          {
  2487            absl::ReaderMutexLock l(&mu);
  2488            ASSERT_THAT(
  2489                setxattr(file.c_str(), name, &val, sizeof(val), /*flags=*/0),
  2490                SyscallSucceeds());
  2491            ASSERT_THAT(removexattr(file.c_str(), name), SyscallSucceeds());
  2492          }
  2493  
  2494          ASSERT_THAT(fsetxattr(fd, name, &val, sizeof(val), /*flags=*/0),
  2495                      SyscallSucceeds());
  2496          ASSERT_THAT(fremovexattr(fd, name), SyscallSucceeds());
  2497          sched_yield();
  2498        }
  2499      }
  2500    });
  2501  
  2502    // Read and write file's contents. Read and write dir's entries.
  2503    ScopedThread read_write([&] {
  2504      int fd;
  2505      {
  2506        absl::ReaderMutexLock l(&mu);
  2507        ASSERT_THAT(fd = open(file.c_str(), O_RDWR), SyscallSucceeds());
  2508      }
  2509      for (auto start = absl::Now(); absl::Now() - start < runtime;) {
  2510        int val = 123;
  2511        ASSERT_THAT(write(fd, &val, sizeof(val)), SyscallSucceeds());
  2512        ASSERT_THAT(read(fd, &val, sizeof(val)), SyscallSucceeds());
  2513        TempPath new_file =
  2514            ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileIn(dir));
  2515        ASSERT_NO_ERRNO(ListDir(dir, false));
  2516        new_file.reset();
  2517        sched_yield();
  2518      }
  2519    });
  2520  
  2521    // Rename file.
  2522    for (auto start = absl::Now(); absl::Now() - start < runtime;) {
  2523      const std::string new_path = NewTempAbsPathInDir(dir);
  2524      {
  2525        absl::WriterMutexLock l(&mu);
  2526        ASSERT_THAT(rename(file.c_str(), new_path.c_str()), SyscallSucceeds());
  2527        file = new_path;
  2528      }
  2529      sched_yield();
  2530    }
  2531  }
  2532  
  2533  // NOTE(b/239215242): Regression test.
  2534  TEST(Inotify, KernfsBasic) {
  2535    const FileDescriptor fd =
  2536        ASSERT_NO_ERRNO_AND_VALUE(InotifyInit1(IN_NONBLOCK));
  2537    const std::string procFile = "/proc/filesystems";
  2538  
  2539    const int wd = ASSERT_NO_ERRNO_AND_VALUE(
  2540        InotifyAddWatch(fd.get(), procFile, IN_ALL_EVENTS));
  2541    const FileDescriptor file1_fd =
  2542        ASSERT_NO_ERRNO_AND_VALUE(Open(procFile, O_RDONLY));
  2543  
  2544    char buf;
  2545    EXPECT_THAT(read(file1_fd.get(), &buf, 1), SyscallSucceeds());
  2546  
  2547    const std::vector<Event> events =
  2548        ASSERT_NO_ERRNO_AND_VALUE(DrainEvents(fd.get()));
  2549    ASSERT_THAT(events, Are({Event(IN_OPEN, wd), Event(IN_ACCESS, wd)}));
  2550  }
  2551  
  2552  }  // namespace
  2553  }  // namespace testing
  2554  }  // namespace gvisor