nixpkgs mirror (for testing) github.com/NixOS/nixpkgs
nix
at python-updates 288 lines 10 kB view raw
1diff --git a/fsnotifier.h b/fsnotifier.h 2index e7b2a42456bc..9dfb61d8d5d0 100644 3--- a/fsnotifier.h 4+++ b/fsnotifier.h 5@@ -61,7 +61,7 @@ bool init_inotify(void); 6 void set_inotify_callback(void (*callback)(const char *, uint32_t)); 7 int get_inotify_fd(void); 8 int watch(const char* root, array* mounts); 9-void unwatch(int id); 10+void unwatch(int id, char* path, unsigned int path_len); 11 bool process_inotify_input(void); 12 void close_inotify(void); 13 14diff --git a/inotify.c b/inotify.c 15index a42846379476..0a33eded78bf 100644 16--- a/inotify.c 17+++ b/inotify.c 18@@ -22,6 +22,8 @@ typedef struct watch_node_str { 19 struct watch_node_str* parent; 20 array* kids; 21 unsigned int path_len; 22+ struct watch_node_str* prev; 23+ struct watch_node_str* next; 24 char path[]; 25 } watch_node; 26 27@@ -102,7 +104,7 @@ int get_inotify_fd(void) { 28 29 #define EVENT_MASK (IN_MODIFY | IN_ATTRIB | IN_CREATE | IN_DELETE | IN_MOVE | IN_DELETE_SELF | IN_MOVE_SELF) 30 31-static int add_watch(unsigned int path_len, watch_node* parent) { 32+static int add_watch(unsigned int path_len, watch_node* parent, watch_node** out) { 33 int wd = inotify_add_watch(inotify_fd, path_buf, EVENT_MASK); 34 if (wd < 0) { 35 if (errno == EACCES || errno == ENOENT) { 36@@ -123,36 +125,39 @@ static int add_watch(unsigned int path_len, watch_node* parent) { 37 userlog(LOG_INFO, "watching %s: %d", path_buf, wd); 38 } 39 40- watch_node* node = table_get(watches, wd); 41- if (node != NULL) { 42- if (node->wd != wd) { 43- userlog(LOG_ERR, "table error: corruption at %d:%s / %d:%s / %d", wd, path_buf, node->wd, node->path, watch_count); 44- return ERR_ABORT; 45- } 46- else if (strcmp(node->path, path_buf) != 0) { 47- char buf1[PATH_MAX], buf2[PATH_MAX]; 48- const char* normalized1 = realpath(node->path, buf1); 49- const char* normalized2 = realpath(path_buf, buf2); 50- if (normalized1 == NULL || normalized2 == NULL || strcmp(normalized1, normalized2) != 0) { 51- userlog(LOG_ERR, "table error: collision at %d (new %s, existing %s)", wd, path_buf, node->path); 52- return ERR_ABORT; 53- } 54- else { 55- userlog(LOG_INFO, "intersection at %d: (new %s, existing %s, real %s)", wd, path_buf, node->path, normalized1); 56- return ERR_IGNORE; 57- } 58- } 59- 60- return wd; 61- } 62- 63- node = malloc(sizeof(watch_node) + path_len + 1); 64+ watch_node* existing = table_get(watches, wd); 65+ if (existing != NULL) { 66+ for (;;) { 67+ if (existing->wd != wd) { 68+ userlog(LOG_ERR, "table error: corruption at %d:%s / %d:%s / %d", wd, path_buf, existing->wd, existing->path, watch_count); 69+ return ERR_ABORT; 70+ } 71+ if (existing->path_len == path_len && strncmp(existing->path, path_buf, path_len) == 0) { 72+ return wd; 73+ } 74+ char buf1[PATH_MAX], buf2[PATH_MAX]; 75+ const char* normalized1 = realpath(existing->path, buf1); 76+ const char* normalized2 = realpath(path_buf, buf2); 77+ if (normalized1 != NULL && normalized2 != NULL && strcmp(normalized1, normalized2) == 0) { 78+ userlog(LOG_INFO, "intersection at %d: (new %s, existing %s, real %s)", wd, path_buf, existing->path, normalized1); 79+ return ERR_IGNORE; 80+ } 81+ if (existing->next == NULL) { 82+ break; 83+ } 84+ existing = existing->next; 85+ } 86+ } 87+ 88+ watch_node* node = malloc(sizeof(watch_node) + path_len + 1); 89 CHECK_NULL(node, ERR_ABORT) 90 memcpy(node->path, path_buf, path_len + 1); 91 node->path_len = path_len; 92 node->wd = wd; 93 node->parent = parent; 94 node->kids = NULL; 95+ node->prev = existing; 96+ node->next = NULL; 97 98 if (parent != NULL) { 99 if (parent->kids == NULL) { 100@@ -162,11 +167,15 @@ static int add_watch(unsigned int path_len, watch_node* parent) { 101 CHECK_NULL(array_push(parent->kids, node), ERR_ABORT) 102 } 103 104- if (table_put(watches, wd, node) == NULL) { 105+ if (existing != NULL) { 106+ existing->next = node; 107+ } 108+ else if (table_put(watches, wd, node) == NULL) { 109 userlog(LOG_ERR, "table error: unable to put (%d:%s)", wd, path_buf); 110 return ERR_ABORT; 111 } 112 113+ *out = node; 114 return wd; 115 } 116 117@@ -177,22 +186,27 @@ static void watch_limit_reached(void) { 118 } 119 } 120 121-static void rm_watch(int wd, bool update_parent) { 122- watch_node* node = table_get(watches, wd); 123- if (node == NULL) { 124- return; 125+static void rm_watch(watch_node* node, bool update_parent) { 126+ if (node->prev != NULL) { 127+ node->prev->next = node->next; 128+ node->next->prev = node->prev; 129 } 130- 131- userlog(LOG_INFO, "unwatching %s: %d (%p)", node->path, node->wd, node); 132- 133- if (inotify_rm_watch(inotify_fd, node->wd) < 0) { 134- userlog(LOG_INFO, "inotify_rm_watch(%d:%s): %s", node->wd, node->path, strerror(errno)); 135+ else if (node->next != NULL) { 136+ table_put(watches, node->wd, node->next); 137+ node->next->prev = NULL; 138+ } 139+ else { 140+ userlog(LOG_INFO, "unwatching %s: %d (%p)", node->path, node->wd, node); 141+ if (inotify_rm_watch(inotify_fd, node->wd) < 0) { 142+ userlog(LOG_INFO, "inotify_rm_watch(%d:%s): %s", node->wd, node->path, strerror(errno)); 143+ } 144+ table_put(watches, node->wd, NULL); 145 } 146 147 for (int i = 0; i < array_size(node->kids); i++) { 148 watch_node* kid = array_get(node->kids, i); 149 if (kid != NULL) { 150- rm_watch(kid->wd, false); 151+ rm_watch(kid, false); 152 } 153 } 154 155@@ -207,7 +221,6 @@ static void rm_watch(int wd, bool update_parent) { 156 157 array_delete(node->kids); 158 free(node); 159- table_put(watches, wd, NULL); 160 } 161 162 163@@ -234,7 +247,9 @@ static int walk_tree(unsigned int path_len, watch_node* parent, bool recursive, 164 } 165 } 166 167- int id = add_watch(path_len, parent); 168+ 169+ watch_node* node; 170+ int id = add_watch(path_len, parent, &node); 171 172 if (dir == NULL) { 173 return id; 174@@ -271,7 +286,7 @@ static int walk_tree(unsigned int path_len, watch_node* parent, bool recursive, 175 176 int subdir_id = walk_tree(path_len + 1 + name_len, table_get(watches, id), recursive, mounts); 177 if (subdir_id < 0 && subdir_id != ERR_IGNORE) { 178- rm_watch(id, true); 179+ rm_watch(node, true); 180 id = subdir_id; 181 break; 182 } 183@@ -323,47 +338,49 @@ int watch(const char* root, array* mounts) { 184 } 185 186 187-void unwatch(int id) { 188- rm_watch(id, true); 189+void unwatch(int wd, char* path, unsigned int path_len) { 190+ for (watch_node* node = table_get(watches, wd); node != NULL; node = node->next) { 191+ if (node->path_len == path_len && strncmp(node->path, path, path_len) == 0) { 192+ rm_watch(node, true); 193+ return; 194+ } 195+ } 196 } 197 198 199 static bool process_inotify_event(struct inotify_event* event) { 200- watch_node* node = table_get(watches, event->wd); 201- if (node == NULL) { 202- return true; 203- } 204- 205- bool is_dir = (event->mask & IN_ISDIR) == IN_ISDIR; 206- userlog(LOG_INFO, "inotify: wd=%d mask=%d dir=%d name=%s", event->wd, event->mask & (~IN_ISDIR), is_dir, node->path); 207- 208- unsigned int path_len = node->path_len; 209- memcpy(path_buf, node->path, path_len + 1); 210- if (event->len > 0) { 211- path_buf[path_len] = '/'; 212- unsigned int name_len = strlen(event->name); 213- memcpy(path_buf + path_len + 1, event->name, name_len + 1); 214- path_len += name_len + 1; 215- } 216+ for (watch_node* node = table_get(watches, event->wd); node != NULL; node = node->next) { 217+ bool is_dir = (event->mask & IN_ISDIR) == IN_ISDIR; 218+ userlog(LOG_INFO, "inotify: wd=%d mask=%d dir=%d name=%s", event->wd, event->mask & (~IN_ISDIR), is_dir, node->path); 219+ 220+ unsigned int path_len = node->path_len; 221+ memcpy(path_buf, node->path, path_len + 1); 222+ if (event->len > 0) { 223+ path_buf[path_len] = '/'; 224+ unsigned int name_len = strlen(event->name); 225+ memcpy(path_buf + path_len + 1, event->name, name_len + 1); 226+ path_len += name_len + 1; 227+ } 228 229- if (callback != NULL) { 230- (*callback)(path_buf, event->mask); 231- } 232+ if (callback != NULL) { 233+ (*callback)(path_buf, event->mask); 234+ } 235 236- if (is_dir && event->mask & (IN_CREATE | IN_MOVED_TO)) { 237- int result = walk_tree(path_len, node, true, NULL); 238- if (result < 0 && result != ERR_IGNORE && result != ERR_CONTINUE) { 239- return false; 240+ if (is_dir && event->mask & (IN_CREATE | IN_MOVED_TO)) { 241+ int result = walk_tree(path_len, node, true, NULL); 242+ if (result < 0 && result != ERR_IGNORE && result != ERR_CONTINUE) { 243+ return false; 244+ } 245 } 246- } 247 248- if (is_dir && event->mask & (IN_DELETE | IN_MOVED_FROM)) { 249- for (int i = 0; i < array_size(node->kids); i++) { 250- watch_node* kid = array_get(node->kids, i); 251- if (kid != NULL && strncmp(path_buf, kid->path, kid->path_len) == 0) { 252- rm_watch(kid->wd, false); 253- array_put(node->kids, i, NULL); 254- break; 255+ if (is_dir && event->mask & (IN_DELETE | IN_MOVED_FROM)) { 256+ for (int i = 0; i < array_size(node->kids); i++) { 257+ watch_node* kid = array_get(node->kids, i); 258+ if (kid != NULL && strncmp(path_buf, kid->path, kid->path_len) == 0) { 259+ rm_watch(kid, false); 260+ array_put(node->kids, i, NULL); 261+ break; 262+ } 263 } 264 } 265 } 266diff --git a/main.c b/main.c 267index b6b2e6fdb5b0..32cc8efe7856 100644 268--- a/main.c 269+++ b/main.c 270@@ -246,7 +246,7 @@ static void unregister_roots(void) { 271 watch_root* root; 272 while ((root = array_pop(roots)) != NULL) { 273 userlog(LOG_INFO, "unregistering root: %s", root->path); 274- unwatch(root->id); 275+ unwatch(root->id, root->path, strlen(root->path)); 276 free(root->path); 277 free(root); 278 } 279@@ -422,7 +422,7 @@ static void check_root_removal(const char* path) { 280 for (int i = 0; i < array_size(roots); i++) { 281 watch_root* root = array_get(roots, i); 282 if (root->id >= 0 && strcmp(path, UNFLATTEN(root->path)) == 0) { 283- unwatch(root->id); 284+ unwatch(root->id, root->path, strlen(root->path)); 285 root->id = -1; 286 userlog(LOG_INFO, "root deleted: %s\n", root->path); 287 report_event("DELETE", path); 288