From 514a91b52ec6824cbb19d9d8a7d781309b234673 Mon Sep 17 00:00:00 2001 From: Henrik Hautakoski Date: Wed, 16 Feb 2011 16:07:31 +0100 Subject: [PATCH] inotify-map: use inotify-watch to keep track of the filesystem hirarchy. --- Makefile.include | 4 +- src/inotify-map.c | 226 +++++++++++++++++++++++++++---------------- src/inotify-map.h | 2 - test/t_inotify-map.c | 15 +-- 4 files changed, 155 insertions(+), 92 deletions(-) diff --git a/Makefile.include b/Makefile.include index b41fb54..3c8a293 100644 --- a/Makefile.include +++ b/Makefile.include @@ -24,9 +24,11 @@ obj-str-list = src/str-list.o $(obj-xalloc) obj-strbuf = src/strbuf.o $(obj-xalloc) src/die.o obj-path = src/path.o $(obj-strbuf) obj-rbtree = src/rbtree.o $(obj-xalloc) +obj-tree = src/tree.o $(obj-xalloc) obj-fscrawl = src/fscrawl.o $(obj-strbuf) $(obj-path) $(obj-log) obj-log = src/log.o $(obj-strbuf) $(obj-xalloc) -obj-inotify-map = src/inotify-map.o $(obj-rbtree) $(obj-str-list) +obj-inotify-watch = src/inotify-watch.o $(obj-tree) +obj-inotify-map = src/inotify-map.o $(obj-inotify-watch) $(obj-path) $(obj-rbtree) $(obj-list) obj-notify = src/event.o src/queue.o src/inotify.o $(obj-inotify-map) $(obj-xalloc) $(obj-fscrawl) $(obj-rbtree) obj-ini = lib/ini/iniparser.o lib/ini/dictionary.o obj-mongo = src/database/mongo.o $(obj-path) $(obj-ini) diff --git a/src/inotify-map.c b/src/inotify-map.c index 390d1fb..968065b 100644 --- a/src/inotify-map.c +++ b/src/inotify-map.c @@ -8,127 +8,166 @@ * (at your option) any later version. */ +#include #include #include "xalloc.h" #include "rbtree.h" +#include "list.h" +#include "path.h" +#include "inotify-watch.h" #include "inotify-map.h" -/* - * IMPORTANT: always have the member used for comparison as the first member - * to make it possible to cast a struct pointer to the first member type. - */ -struct map_wd { - int wd; - struct str_list paths; -}; - -struct map_path { - const char *path; - int wd; -}; - static void wd_free(void *ptr); static int wd_cmp(const void *a, const void *b); static int path_cmp(const void *a, const void *b); +static struct watch watch_root; + +/* wd -> list of struct watch* */ static rbtree tree_wd_paths = RBTREE_INIT(wd_cmp); + +/* path -> struct watch* */ static rbtree tree_path_wd = RBTREE_INIT(path_cmp); static int wd_cmp(const void *a, const void *b) { - return *((int*)a) - *((int*)b); + struct watch *n1 = ((struct list*)a)->items[0]; + struct watch *n2 = ((struct list*)b)->items[0]; + + return n1->wd - n2->wd; } static int path_cmp(const void *a, const void *b) { - return strcmp(*((char**)a), *((char**)b)); + return strcmp(((struct watch*)a)->path, ((struct watch*)b)->path); } -static void wd_free(void *ptr) { +static void wd_free(void *list) { - struct map_wd *m = (struct map_wd*)ptr; - - str_list_clear(&m->paths); - xfree(m); + list_destroy(list); } -static void map_path_wd(const char *path, int wd) { +static struct watch* new_node(int wd, const char *path) { - struct map_path *p = rbtree_search(&tree_path_wd, &path); - if (!p) { - p = xmalloc(sizeof(struct map_path)); - p->path = path; - rbtree_insert(&tree_path_wd, p); - } - p->wd = wd; -} + struct watch s, *p; -static int unmap_path_wd(int wd, const char *path) { + s.path = path; - return rbtree_delete(&tree_path_wd, &path) != NULL; -} - -static void unmap_wd_path(int wd, const char *path) { - - struct map_wd *m = rbtree_search(&tree_wd_paths, &wd); - - if (m) { - char *p = str_list_remove(&m->paths, path); - if (p) { - xfree(p); - if (str_list_isempty(&m->paths)) - rbtree_delete(&tree_wd_paths, m); + /* find parent */ + for(;;) { + s.path = dirname_s(s.path, 1); + p = rbtree_search(&tree_path_wd, &s); + if (p) + break; + if (!strcmp(s.path, "/") || + !strcmp(s.path, "./")) { + p = &watch_root; + break; } } + return inotify_watch_add(p, inotify_watch_new(wd, path)); } -/* - * unmaps all paths from the 'struct map_wd' and from the search tree 'tree_path_wd'. - */ -static void unmap_all_paths(struct map_wd *map) { +static struct list* wd_lookup(int wd) { - char *path; + struct watch n, *np = &n; + struct list s = { (void**)&np, 1 }; + n.wd = wd; + return rbtree_search(&tree_wd_paths, &s); +} - while(path = str_list_reduce(&map->paths)) { - rbtree_delete(&tree_path_wd, &path); - xfree(path); +static void map_path(struct watch *w) { + + rbtree_insert(&tree_path_wd, w); +} + +static void map_wd(struct watch *w) { + + struct list s = { (void**)&w, 1 }; + struct list *l = rbtree_search(&tree_wd_paths, &s); + + if (l) { + list_insert(l, w); + } else { + l = list_create(); + list_insert(l, w); + rbtree_insert(&tree_wd_paths, l); } } void inotify_map(int wd, const char *path) { - struct map_wd *m = rbtree_search(&tree_wd_paths, &wd); - if (!m) { - m = xmalloc(sizeof(struct map_wd)); - m->wd = wd; - str_list_init(&m->paths); - rbtree_insert(&tree_wd_paths, m); - } + struct watch s, *n; - if (!str_list_has(&m->paths, path)) { - int index = str_list_insert(&m->paths, xstrdup(path)); - map_path_wd(m->paths.items[index], wd); + s.path = path; + n = rbtree_search(&tree_path_wd, &s); + + if (!n) { + n = new_node(wd, path); + map_path(n); + map_wd(n); } } +static void unmap_path(struct watch *watch) { + + rbtree_delete(&tree_path_wd, watch); +} + +static void unmap_wd(struct watch *watch) { + + int index; + struct list s = { (void**)&watch, 1 }, *list; + + list = rbtree_search(&tree_wd_paths, &s); + if (!list) + return; + + index = list_indexof(list, watch); + if (index >= 0) { + if (list_size(list) == 1) { + list = rbtree_delete(&tree_wd_paths, list); + list_destroy(list); + } else { + list_remove(list, index); + } + } +} + +static void unmap(struct watch *w) { + + unmap_wd(w); + unmap_path(w); +} + int inotify_unmap_wd(int wd) { - - struct map_wd *m = rbtree_search(&tree_wd_paths, &wd); - if (m) { - unmap_all_paths(m); - return rbtree_delete(&tree_wd_paths, &wd) != NULL; + + struct list *l = wd_lookup(wd); + if (l) { + int i; + + rbtree_delete(&tree_wd_paths, l); + for(i=0; i < l->nr; i++) { + struct watch *w = l->items[i]; + unmap_path(w); + inotify_watch_destroy(w, unmap); + } + list_destroy(l); + return 1; } return 0; } int inotify_unmap_path(const char *path) { - struct map_path *m = rbtree_search(&tree_path_wd, &path); - - if (m) { - int wd = m->wd; - unmap_path_wd(wd, path); - unmap_wd_path(wd, path); + struct watch *w, s; + + s.path = path; + w = rbtree_search(&tree_path_wd, &s); + if (w) { + unmap_wd(w); + unmap_path(w); + inotify_watch_destroy(w, unmap); return 1; } return 0; @@ -136,32 +175,53 @@ int inotify_unmap_path(const char *path) { void inotify_unmap_all() { - rbtree_free(&tree_path_wd, xfree); + rbtree_free(&tree_path_wd, NULL); rbtree_free(&tree_wd_paths, wd_free); + inotify_watch_destroy((struct watch*)watch_root.tree.child, NULL); + watch_root.tree.child = NULL; } int inotify_map_get_wd(const char *path) { - struct map_path *p = rbtree_search(&tree_path_wd, &path); - if (p) - return p->wd; + struct watch s, *n; + + s.path = path; + n = rbtree_search(&tree_path_wd, &s); + if (n) + return n->wd; return 0; } char** inotify_map_lookup(int wd) { - - struct map_wd *m = rbtree_search(&tree_wd_paths, &wd); - return m ? str_list_export(&m->paths) : NULL; + + char **out = NULL; + struct list *list; + + list = wd_lookup(wd); + if (list && list->nr) { + int i; + + out = xmalloc(list->nr + 1); + for(i=0; i < list->nr; i++) { + struct watch *w = list->items[i]; + out[i] = (char *)w->path; + } + out[list->nr] = NULL; + } + return out; } char** inotify_map_lookup_by_path(const char *path) { - struct map_path *p = rbtree_search(&tree_path_wd, &path); - return p ? inotify_map_lookup(p->wd) : NULL; + int wd = inotify_map_get_wd(path); + if (wd) + return inotify_map_lookup(wd); + return NULL; } int inotify_map_isempty() { return rbtree_is_empty(&tree_wd_paths) - && rbtree_is_empty(&tree_path_wd); + && rbtree_is_empty(&tree_path_wd) + && watch_root.tree.child == NULL; } diff --git a/src/inotify-map.h b/src/inotify-map.h index 8e0b22e..ad333ac 100644 --- a/src/inotify-map.h +++ b/src/inotify-map.h @@ -11,8 +11,6 @@ #ifndef __INOTIFY_MAP_H #define __INOTIFY_MAP_H -#include "str-list.h" - void inotify_map(int wd, const char *path); int inotify_unmap_wd(int wd); diff --git a/test/t_inotify-map.c b/test/t_inotify-map.c index 08d6273..edfedb7 100644 --- a/test/t_inotify-map.c +++ b/test/t_inotify-map.c @@ -4,7 +4,7 @@ #include "../src/inotify-map.h" int wdref[4] = { 1, 2, 1, 4 }; -char *pathref[4] = { "one", "two", "three", "four" }; +char *pathref[4] = { "/one/", "/two/", "/three/", "/two/subdir/another/" }; static void setup() { @@ -20,6 +20,7 @@ static void setup() { static void teardown() { inotify_unmap_all(); + assert(inotify_map_isempty()); } static void validate_list(int index, char **list) { @@ -51,7 +52,7 @@ void test_inotify_unmap_wd() { assert(inotify_unmap_wd(wdref[0])); assert(inotify_unmap_wd(wdref[1])); assert(inotify_unmap_wd(wdref[2]) == 0); - assert(inotify_unmap_wd(wdref[3])); + assert(inotify_unmap_wd(wdref[3]) == 0); assert(inotify_map_isempty()); @@ -64,9 +65,11 @@ void test_inotify_unmap_path() { setup(); - for(i=0; i < 4; i++) - assert(inotify_unmap_path(pathref[i])); - + assert(inotify_unmap_path(pathref[0])); + assert(inotify_unmap_path(pathref[1])); + assert(inotify_unmap_path(pathref[2])); + assert(inotify_unmap_path(pathref[3]) == 0); + assert(inotify_map_isempty()); teardown(); @@ -124,8 +127,8 @@ void test_inotify_map_lookup_by_path() { int main() { - test_inotify_unmap_wd(); test_inotify_unmap_path(); + test_inotify_unmap_wd(); test_inotify_unmap_all(); test_inotify_map_get_wd(); test_inotify_map_lookup();