GCC Code Coverage Report


Directory: cvmfs/
File: cvmfs/file_watcher_inotify.cc
Date: 2024-04-28 02:33:07
Exec Total Coverage
Lines: 62 75 82.7%
Branches: 39 76 51.3%

Line Branch Exec Source
1 /**
2 * This file is part of the CernVM File System.
3 */
4
5 #include <errno.h>
6 #include <fcntl.h>
7 #include <linux/limits.h>
8 #include <poll.h>
9 #include <sys/inotify.h>
10 #include <sys/time.h>
11 #include <sys/types.h>
12 #include <unistd.h>
13
14 #include <cassert>
15 #include <string>
16 #include <vector>
17
18 #include "file_watcher_inotify.h"
19 #include "util/logging.h"
20 #include "util/posix.h"
21
22 namespace file_watcher {
23
24 4 FileWatcherInotify::FileWatcherInotify() {}
25
26 16 FileWatcherInotify::~FileWatcherInotify() {}
27
28 4 bool FileWatcherInotify::RunEventLoop(const FileWatcher::HandlerMap& handlers,
29 int read_pipe, int write_pipe) {
30 4 inotify_fd_ = inotify_init1(IN_NONBLOCK);
31
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 assert(inotify_fd_ >= 0);
32
33 4 for (FileWatcher::HandlerMap::const_iterator it = handlers.begin();
34
2/2
✓ Branch 3 taken 4 times.
✓ Branch 4 taken 4 times.
8 it != handlers.end(); ++it) {
35
1/2
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
4 RegisterFilter(it->first, it->second);
36 }
37
38 // Use the control pipe to signal readiness to the main thread,
39 // before continuing with the event loop.
40
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 WritePipe(write_pipe, "s", 1);
41
42 struct pollfd poll_set[2];
43
44 4 poll_set[0].fd = read_pipe;
45 4 poll_set[0].events = POLLHUP | POLLIN;
46 4 poll_set[0].revents = 0;
47 4 poll_set[1].fd = inotify_fd_;
48 4 poll_set[1].events = POLLIN;
49 4 poll_set[1].revents = 0;
50
51 4 bool stop = false;
52
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 4 times.
12 while (!stop) {
53
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 int ready = poll(poll_set, 2, -1);
54
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 if (ready == -1) {
55 if (errno == EINTR) {
56 4 continue;
57 }
58 LogCvmfs(kLogCvmfs, kLogSyslogErr,
59 "FileWatcherInotify - Could not poll events. Errno: %d", errno);
60 return false;
61 }
62
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 if (ready == 0) {
63 continue;
64 }
65
66
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 if (poll_set[0].revents & POLLHUP) {
67 LogCvmfs(kLogCvmfs, kLogDebug, "FileWatcherInotify - Stopping.\n");
68 stop = true;
69 continue;
70 }
71
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
8 if (poll_set[0].revents & POLLIN) {
72 char buffer[1];
73
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 ReadPipe(read_pipe, &buffer, 1);
74
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 LogCvmfs(kLogCvmfs, kLogDebug, "FileWatcherInotify - Stopping.\n");
75 4 stop = true;
76 4 continue;
77 4 }
78
79 4 const size_t event_size = sizeof(struct inotify_event);
80 // We need a large enough buffer for an event with the largest path name
81 4 const size_t buffer_size = event_size + PATH_MAX + 1;
82 char buffer[buffer_size];
83
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if (poll_set[1].revents & POLLIN) {
84
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 int len = read(inotify_fd_, buffer, buffer_size);
85
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 assert(len > 0);
86 4 int i = 0;
87
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 4 times.
12 while (i < len) {
88 8 struct inotify_event* inotify_event =
89 reinterpret_cast<struct inotify_event*>(&buffer[i]);
90 std::map<int, WatchRecord>::const_iterator it =
91
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 watch_records_.find(inotify_event->wd);
92
2/2
✓ Branch 3 taken 6 times.
✓ Branch 4 taken 2 times.
8 if (it != watch_records_.end()) {
93
1/2
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
6 WatchRecord current_record = it->second;
94 6 file_watcher::Event event = file_watcher::kInvalid;
95
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 4 times.
6 if (inotify_event->mask & IN_DELETE_SELF) {
96 2 event = file_watcher::kDeleted;
97
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
4 } else if (inotify_event->mask & IN_CLOSE_WRITE) {
98 // Modified
99 2 event = file_watcher::kModified;
100
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 } else if (inotify_event->mask & IN_MOVE_SELF) {
101 // Renamed
102 event = file_watcher::kRenamed;
103
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 } else if (inotify_event->mask & IN_ATTRIB) {
104 // Attributes
105 2 event = file_watcher::kAttributes;
106 } else if (inotify_event->mask & IN_IGNORED) {
107 // An IN_IGNORED event is generated after a file is deleted and the
108 // watch is removed
109 event = file_watcher::kIgnored;
110 }
111 6 bool clear_handler = true;
112
2/4
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
6 if (event != file_watcher::kInvalid &&
113 event != file_watcher::kIgnored) {
114
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 current_record.handler_->Handle(current_record.file_path_, event,
115 &clear_handler);
116 } else {
117 LogCvmfs(kLogCvmfs, kLogDebug,
118 "FileWatcherInotify - Unknown event 0x%x\n",
119 inotify_event->mask);
120 }
121
122 // Perform post-handling actions (i.e. remove, reset filter)
123
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 4 times.
6 if (event == file_watcher::kDeleted) {
124
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 watch_records_.erase(inotify_event->wd);
125
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!clear_handler) {
126 RegisterFilter(current_record.file_path_,
127 current_record.handler_);
128 }
129 }
130 6 } else {
131
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 LogCvmfs(kLogCvmfs, kLogDebug,
132 "FileWatcherInotify - Unknown event ident: %d",
133 inotify_event->wd);
134 }
135
136 8 i += event_size + inotify_event->len;
137 }
138 }
139 }
140
141 4 watch_records_.clear();
142
143
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 close(inotify_fd_);
144
145 4 return true;
146 }
147
148 4 int FileWatcherInotify::TryRegisterFilter(const std::string& file_path) {
149 4 return inotify_add_watch(
150 inotify_fd_, file_path.c_str(),
151 4 IN_ATTRIB | IN_CLOSE_WRITE | IN_DELETE_SELF | IN_MOVE_SELF);
152 }
153
154 } // namespace file_watcher
155