Linux file watcher: do not dive into flat roots

This commit is contained in:
Roman Shevchenko
2012-04-10 19:54:39 +02:00
parent 1f63ce03a5
commit 8487c658e4
5 changed files with 44 additions and 38 deletions
Binary file not shown.
Binary file not shown.
+4 -2
View File
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2010 JetBrains s.r.o.
* Copyright 2000-2012 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -24,6 +24,8 @@
// logging
void userlog(int priority, const char* format, ...);
#define CHECK_NULL(p, r) if (p == NULL) { userlog(LOG_ERR, "out of memory"); return r; }
// variable-length array
typedef struct __array array;
@@ -38,7 +40,7 @@ void array_delete(array* a);
void array_delete_vs_data(array* a);
// key/value pairs table
// poor man's hash table
typedef struct __table table;
table* table_create(int capacity);
+31 -21
View File
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2011 JetBrains s.r.o.
* Copyright 2000-2012 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -32,8 +32,6 @@
#define DEFAULT_SUBDIR_COUNT 5
#define CHECK_NULL(p) if (p == NULL) { userlog(LOG_ERR, "out of memory"); return ERR_ABORT; }
typedef struct __watch_node {
char* name;
int wd;
@@ -153,9 +151,9 @@ static int add_watch(const char* path, watch_node* parent) {
node = malloc(sizeof(watch_node));
CHECK_NULL(node);
CHECK_NULL(node, ERR_ABORT);
node->name = strdup(path);
CHECK_NULL(node->name);
CHECK_NULL(node->name, ERR_ABORT);
node->wd = wd;
node->parent = parent;
node->kids = NULL;
@@ -163,9 +161,9 @@ static int add_watch(const char* path, watch_node* parent) {
if (parent != NULL) {
if (parent->kids == NULL) {
parent->kids = array_create(DEFAULT_SUBDIR_COUNT);
CHECK_NULL(parent->kids);
CHECK_NULL(parent->kids, ERR_ABORT);
}
CHECK_NULL(array_push(parent->kids, node));
CHECK_NULL(array_push(parent->kids, node), ERR_ABORT);
}
if (table_put(watches, wd, node) == NULL) {
@@ -238,25 +236,31 @@ static bool is_ignored(const char* path, array* ignores) {
return false;
}
static int walk_tree(const char* path, watch_node* parent, array* ignores) {
static int walk_tree(const char* path, watch_node* parent, array* ignores, bool recursive) {
if (is_ignored(path, ignores)) {
return ERR_IGNORE;
}
DIR* dir = opendir(path);
if (dir == NULL) {
if (errno == EACCES) {
return ERR_IGNORE;
DIR* dir;
if (recursive) {
dir = opendir(path);
if (dir == NULL) {
if (errno == EACCES) {
return ERR_IGNORE;
}
else if (errno == ENOTDIR) { // "future" root
return add_watch(path, parent);
}
userlog(LOG_ERR, "opendir(%s): %s", path, strerror(errno));
return ERR_CONTINUE;
}
else if (errno == ENOTDIR) { // flat root
return add_watch(path, parent);
}
userlog(LOG_ERR, "opendir(%s): %s", path, strerror(errno));
return ERR_CONTINUE;
}
int id = add_watch(path, parent);
if (id < 0) {
if (!recursive) {
return id;
}
else if (id < 0) {
closedir(dir);
return id;
}
@@ -279,7 +283,7 @@ static int walk_tree(const char* path, watch_node* parent, array* ignores) {
continue;
}
int subdir_id = walk_tree(subdir, table_get(watches, id), ignores);
int subdir_id = walk_tree(subdir, table_get(watches, id), ignores, recursive);
if (subdir_id < 0 && subdir_id != ERR_IGNORE) {
rm_watch(id, true);
id = subdir_id;
@@ -293,9 +297,15 @@ static int walk_tree(const char* path, watch_node* parent, array* ignores) {
int watch(const char* root, array* ignores) {
bool recursive = true;
if (root[0] == '|') {
root++;
recursive = false;
}
char buf[PATH_MAX];
const char* normalized = realpath(root, buf);
return walk_tree((normalized != NULL ? normalized : root), NULL, ignores);
return walk_tree((normalized != NULL ? normalized : root), NULL, ignores, recursive);
}
@@ -323,7 +333,7 @@ static bool process_inotify_event(struct inotify_event* event) {
}
if ((event->mask & IN_CREATE || event->mask & IN_MOVED_TO) && event->mask & IN_ISDIR) {
int result = walk_tree(path, node, NULL);
int result = walk_tree(path, node, NULL, true);
if (result < 0 && result != ERR_IGNORE) {
return false;
}
+9 -15
View File
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2011 JetBrains s.r.o.
* Copyright 2000-2012 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -33,7 +33,7 @@
#define LOG_ENV_ERROR "error"
#define LOG_ENV_OFF "off"
#define VERSION "1.0"
#define VERSION "1.1"
#define VERSION_MSG "fsnotifier " VERSION "\n"
#define USAGE_MSG \
@@ -58,11 +58,8 @@ typedef struct {
static array* roots = NULL;
static bool show_warning = true;
static bool self_test = false;
#define CHECK_NULL(p) if (p == NULL) { userlog(LOG_ERR, "out of memory"); return false; }
static void init_log();
static void run_self_test();
static void main_loop();
@@ -223,7 +220,7 @@ static bool read_input() {
if (strcmp(line, "ROOTS") == 0) {
array* new_roots = array_create(20);
CHECK_NULL(new_roots);
CHECK_NULL(new_roots, false);
while (1) {
line = read_line(stdin);
@@ -235,12 +232,9 @@ static bool read_input() {
break;
}
else {
if (line[0] == '|') line++; // flat roots will be differentiated later
int l = strlen(line);
if (l > 1 && line[l-1] == '/') line[l-1] = '\0';
CHECK_NULL(array_push(new_roots, strdup(line)));
CHECK_NULL(array_push(new_roots, strdup(line)), false);
}
}
@@ -266,7 +260,7 @@ static bool update_roots(array* new_roots) {
}
array* unwatchable = array_create(20);
CHECK_NULL(unwatchable);
CHECK_NULL(unwatchable, false);
if (!unwatchable_mounts(unwatchable)) {
return false;
}
@@ -312,10 +306,10 @@ static bool register_roots(array* new_roots, array* unwatchable) {
}
else if (id >= 0) {
watch_root* root = malloc(sizeof(watch_root));
CHECK_NULL(root);
CHECK_NULL(root, false);
root->id = id;
root->name = new_root;
CHECK_NULL(array_push(roots, root));
CHECK_NULL(array_push(roots, root), false);
}
else {
if (show_warning && watch_limit_reached()) {
@@ -324,7 +318,7 @@ static bool register_roots(array* new_roots, array* unwatchable) {
output("MESSAGE\n" INOTIFY_LIMIT_MSG, limit);
show_warning = false; // warn only once
}
CHECK_NULL(array_push(unwatchable, new_root));
CHECK_NULL(array_push(unwatchable, new_root), false);
}
}
@@ -362,7 +356,7 @@ static bool unwatchable_mounts(array* mounts) {
}
if (!is_watchable(dev, point, fs)) {
CHECK_NULL(array_push(mounts, strdup(point)));
CHECK_NULL(array_push(mounts, strdup(point)), false);
}
}