Linux file watcher: do not dive into flat roots
authorRoman Shevchenko <roman.shevchenko@jetbrains.com>
Tue, 10 Apr 2012 15:00:21 +0000 (17:00 +0200)
committerRoman Shevchenko <roman.shevchenko@jetbrains.com>
Tue, 10 Apr 2012 17:54:39 +0000 (19:54 +0200)
bin/linux/fsnotifier
bin/linux/fsnotifier64
native/fsNotifier/linux/fsnotifier.h
native/fsNotifier/linux/inotify.c
native/fsNotifier/linux/main.c

index e248974f4a941feb95fe52f71338c24739812fb7..f7a73126a13e38a3b51fd93601b8594961195074 100755 (executable)
Binary files a/bin/linux/fsnotifier and b/bin/linux/fsnotifier differ
index efba253b08b3a52e22e1bc09f1d93e5bd1f6fca5..1fc4f32ff7effedcfc451430f228bdf99e76d15f 100755 (executable)
Binary files a/bin/linux/fsnotifier64 and b/bin/linux/fsnotifier64 differ
index 0ee04cd12639569ec49c893a5148a9061a79b687..f3234e2fde9d79285d26068b7853b6328e9b3133 100644 (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);
index ab605424d66c9e504fc5244e8161de74d1d8a8e4..04d749e48d83bd9be122cd15d47ec987b4f6c39a 100644 (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;
-    }
-    else if (errno == ENOTDIR) {  // flat root
-      return add_watch(path, parent);
+  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;
     }
-    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;
     }
index 3bef185211519d8d4b5a0242d75d84821cd57f9a..81dcdfead702b0169b494aef026465d7287dbde6 100644 (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);
     }
   }