diff --git a/Makefile.include b/Makefile.include index ceca2f2..84a7c56 100644 --- a/Makefile.include +++ b/Makefile.include @@ -25,7 +25,8 @@ obj-path = src/path.o $(obj-strbuf) obj-rbtree = src/rbtree.o $(obj-xalloc) obj-fscrawl = src/fscrawl.o $(obj-strbuf) $(obj-path) $(obj-log) obj-log = src/log.o $(obj-strbuf) $(obj-xalloc) -obj-notify = src/event.o src/queue.o src/inotify.o $(obj-xalloc) $(obj-fscrawl) $(obj-rbtree) +obj-inotify-map = src/inotify-map.o $(obj-rbtree) $(obj-str-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) obj-mysql = src/database/mysql.o $(obj-ini) $(obj-xalloc) diff --git a/src/inotify-map.c b/src/inotify-map.c new file mode 100644 index 0000000..df0b74a --- /dev/null +++ b/src/inotify-map.c @@ -0,0 +1,166 @@ +/* inotify-map.c + * + * (C) Copyright 2011 Henrik Hautakoski + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + */ + +#include "xalloc.h" +#include "rbtree.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 rbtree tree_wd_paths = RBTREE_INIT(wd_free, NULL, wd_cmp); +static rbtree tree_path_wd = RBTREE_INIT(xfree, NULL, path_cmp); + +static int wd_cmp(const void *a, const void *b) { + + return *((int*)a) - *((int*)b); +} + +static int path_cmp(const void *a, const void *b) { + + return strcmp(*((char**)a), *((char**)b)); +} + +static void wd_free(void *ptr) { + + struct map_wd *m = (struct map_wd*)ptr; + + str_list_clear(&m->paths); + xfree(m); +} + +static void map_path_wd(const char *path, int wd) { + + 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; +} + +static int unmap_path_wd(int wd, const char *path) { + + return rbtree_delete(&tree_path_wd, &path); +} + +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); + } + } +} + +/* + * 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) { + + char *path; + + while(path = str_list_reduce(&map->paths)) { + rbtree_delete(&tree_path_wd, &path); + xfree(path); + } +} + +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); + } + + if (!str_list_has(&m->paths, path)) { + int index = str_list_insert(&m->paths, xstrdup(path)); + map_path_wd(m->paths.items[index], wd); + } +} + +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); + } + 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); + return 1; + } + return 0; +} + +void inotify_unmap_all() { + + rbtree_free(&tree_path_wd); + rbtree_free(&tree_wd_paths); +} + +int inotify_map_get_wd(const char *path) { + + struct map_path *p = rbtree_search(&tree_path_wd, &path); + if (p) + return p->wd; + return 0; +} + +const struct str_list* inotify_map_lookup(int wd) { + + struct map_wd *m = rbtree_search(&tree_wd_paths, &wd); + return m ? &m->paths : NULL; +} + +const struct str_list* 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 inotify_map_isempty() { + + return rbtree_is_empty(&tree_wd_paths) + && rbtree_is_empty(&tree_path_wd); +} diff --git a/src/inotify-map.h b/src/inotify-map.h new file mode 100644 index 0000000..45b04db --- /dev/null +++ b/src/inotify-map.h @@ -0,0 +1,32 @@ +/* inotify-map.h + * + * (C) Copyright 2011 Henrik Hautakoski + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + */ + +#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); + +int inotify_unmap_path(const char *path); + +void inotify_unmap_all(); + +int inotify_map_get_wd(const char *path); + +const struct str_list* inotify_map_lookup(int wd); + +const struct str_list* inotify_map_lookup_by_path(const char *path); + +int inotify_map_isempty(); + +#endif /* __INOTIFY_MAP_H */ diff --git a/src/str-list.c b/src/str-list.c index 4616724..e47cbe4 100644 --- a/src/str-list.c +++ b/src/str-list.c @@ -23,7 +23,7 @@ static void resize(struct str_list *list) { list->items = xrealloc(list->items, sizeof(list->items) * list->nr); } -static int get_index(struct str_list *list, const char *str, int *match) { +static int get_index(const struct str_list *list, const char *str, int *match) { int min = -1, max = list->nr; @@ -134,13 +134,13 @@ char* str_list_reduce(struct str_list *list) { return item; } -int str_list_indexof(struct str_list *list, const char *str) { +int str_list_indexof(const struct str_list *list, const char *str) { int match, index = get_index(list, str, &match); return match ? index : -1; } -char* str_list_lookup(struct str_list *list, const char *str) { +char* str_list_lookup(const struct str_list *list, const char *str) { int match, index = get_index(list, str, &match); @@ -149,7 +149,7 @@ char* str_list_lookup(struct str_list *list, const char *str) { return list->items[index]; } -int str_list_has(struct str_list *list, const char *str) { +int str_list_has(const struct str_list *list, const char *str) { int rc; get_index(list, str, &rc); diff --git a/src/str-list.h b/src/str-list.h index d2f2b05..3e8f4e6 100644 --- a/src/str-list.h +++ b/src/str-list.h @@ -34,11 +34,11 @@ char* str_list_remove(struct str_list *list, const char *str); char* str_list_reduce(struct str_list *list); -int str_list_indexof(struct str_list *list, const char *str); +int str_list_indexof(const struct str_list *list, const char *str); -char* str_list_lookup(struct str_list *list, const char *str); +char* str_list_lookup(const struct str_list *list, const char *str); -int str_list_has(struct str_list *list, const char *str); +int str_list_has(const struct str_list *list, const char *str); #define str_list_foreach(i, l) \ for(i = (l)->items; i < (l)->items + (l)->nr; ++i) diff --git a/test/Makefile b/test/Makefile index e5e736d..05fc3ab 100644 --- a/test/Makefile +++ b/test/Makefile @@ -19,6 +19,7 @@ queue : $(ROOT)src/queue.o $(addprefix $(ROOT),$(obj-xalloc)) path : unit.c $(ROOT)src/path.o $(addprefix $(ROOT),$(obj-strbuf)) fscrawl : $(ROOT)src/fscrawl.o $(addprefix $(ROOT),$(obj-fscrawl)) notify : $(addprefix $(ROOT),$(obj-notify)) +inotify-map : $(addprefix $(ROOT),$(obj-inotify-map)) log : $(addprefix $(ROOT),$(obj-log)) str-list : unit.c $(addprefix $(ROOT),$(obj-str-list)) diff --git a/test/t_inotify-map.c b/test/t_inotify-map.c new file mode 100644 index 0000000..fa1d7c8 --- /dev/null +++ b/test/t_inotify-map.c @@ -0,0 +1,117 @@ + +#include +#include +#include "../src/inotify-map.h" + +int wdref[4] = { 1, 2, 1, 4 }; +char *pathref[4] = { "one", "two", "three", "four" }; + +static void setup() { + + int i; + + if (!inotify_map_isempty()) + return; + + for(i=0; i < 4; i++) + inotify_map(wdref[i], pathref[i]); +} + +static void teardown() { + + inotify_unmap_all(); +} + +static void validate_list(int refindex, const struct str_list *l) { + + int i; + + assert(l); + + for(i=0; i < 4; i++) { + + if (i != wdref[refindex]) + continue; + + assert(str_list_has(l, pathref[refindex])); + } +} + +void test_inotify_unmap_wd() { + + int i; + + setup(); + + 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_map_isempty()); + + teardown(); +} + +void test_inotify_unmap_path() { + + int i; + + setup(); + + for(i=0; i < 4; i++) + assert(inotify_unmap_path(pathref[i])); + + assert(inotify_map_isempty()); + + teardown(); +} + +void test_inotify_unmap_all() { + + setup(); + + inotify_unmap_all(); + assert(inotify_map_isempty()); + + teardown(); +} + +void test_inotify_map_lookup() { + + int i; + + setup(); + + for(i=0; i < 4; i++) + validate_list(i, inotify_map_lookup(wdref[i])); + + assert(inotify_map_lookup(25) == NULL); + + teardown(); +} + +void test_inotify_map_lookup_by_path() { + + int i; + + setup(); + + for(i=0; i < 4; i++) + validate_list(i, inotify_map_lookup_by_path(pathref[i])); + + assert(inotify_map_lookup(33) == NULL); + + teardown(); +} + +int main() { + + test_inotify_unmap_wd(); + test_inotify_unmap_path(); + test_inotify_unmap_all(); + test_inotify_map_lookup(); + test_inotify_map_lookup_by_path(); + + return 0; +}