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