IDEA-94524 (skip mount points under watch roots)
authorRoman Shevchenko <roman.shevchenko@jetbrains.com>
Mon, 12 Nov 2012 17:31:15 +0000 (18:31 +0100)
committerRoman Shevchenko <roman.shevchenko@jetbrains.com>
Mon, 12 Nov 2012 17:33:45 +0000 (18:33 +0100)
bin/linux/fsnotifier
bin/linux/fsnotifier64
native/fsNotifier/linux/fsnotifier.h
native/fsNotifier/linux/inotify.c
native/fsNotifier/linux/main.c
native/fsNotifier/linux/make.sh
native/fsNotifier/linux/util.c

index e4b7dcb6b24c89afa31a02863b43b067e6dafb24..3d90bedafc45cf7384ceb2832efbcb38e7963a24 100755 (executable)
Binary files a/bin/linux/fsnotifier and b/bin/linux/fsnotifier differ
index 8a73a32e167fac2120187db59b80aeedf615d6e7..6427e4b31599d80a4f3cbed8c9c97c67640aeb84 100755 (executable)
Binary files a/bin/linux/fsnotifier64 and b/bin/linux/fsnotifier64 differ
index b8dd17b388311bcc03184e276fc7456587405856..0b3e52705513c25c251987e9c1b061276ecbf86e 100644 (file)
@@ -61,14 +61,19 @@ void set_inotify_callback(void (* callback)(char*, int));
 int get_inotify_fd();
 int get_watch_count();
 bool watch_limit_reached();
-int watch(const char* root);
+int watch(const char* root, array* mounts);
 void unwatch(int id);
 bool process_inotify_input();
 void close_inotify();
 
 
 // reads one line from stream, trims trailing carriage return if any
-// returns pointer to the internal buffer (will be overwriten on next call)
+// returns pointer to the internal buffer (will be overwritten on next call)
 char* read_line(FILE* stream);
 
+
+// path comparison
+bool is_parent_path(const char* parent_path, const char* child_path);
+
+
 #endif
index 443c67a13d97be6807e1cb1d067c5ab7244a7966..bfb117d513478a74e5e08d0980978b07b7cf2207 100644 (file)
@@ -216,7 +216,15 @@ static void rm_watch(int wd, bool update_parent) {
 }
 
 
-static int walk_tree(const char* path, watch_node* parent, bool recursive) {
+static int walk_tree(const char* path, watch_node* parent, bool recursive, array* mounts) {
+  for (int j=0; j<array_size(mounts); j++) {
+    char* mount = array_get(mounts, j);
+    if (strncmp(path, mount, strlen(mount)) == 0) {
+      userlog(LOG_DEBUG, "watch path '%s' crossed mount point '%s' - skipping", path, mount);
+      return ERR_IGNORE;
+    }
+  }
+
   DIR* dir = NULL;
   if (recursive) {
     if ((dir = opendir(path)) == NULL) {
@@ -257,7 +265,7 @@ static int walk_tree(const char* path, watch_node* parent, bool recursive) {
 
     strcpy(p, entry->d_name);
 
-    int subdir_id = walk_tree(subdir, table_get(watches, id), recursive);
+    int subdir_id = walk_tree(subdir, table_get(watches, id), recursive, mounts);
     if (subdir_id < 0 && subdir_id != ERR_IGNORE) {
       rm_watch(id, true);
       id = subdir_id;
@@ -270,7 +278,7 @@ static int walk_tree(const char* path, watch_node* parent, bool recursive) {
 }
 
 
-int watch(const char* root) {
+int watch(const char* root, array* mounts) {
   bool recursive = true;
   if (root[0] == '|') {
     root++;
@@ -297,7 +305,7 @@ int watch(const char* root) {
     return ERR_IGNORE;
   }
 
-  return walk_tree(root, NULL, recursive);
+  return walk_tree(root, NULL, recursive, mounts);
 }
 
 
@@ -326,7 +334,7 @@ static bool process_inotify_event(struct inotify_event* event) {
   }
 
   if (is_dir && ((event->mask & IN_CREATE) == IN_CREATE || (event->mask & IN_MOVED_TO) == IN_MOVED_TO)) {
-    int result = walk_tree(path, node, true);
+    int result = walk_tree(path, node, true, NULL);
     if (result < 0 && result != ERR_IGNORE) {
       return false;
     }
index 4bd2727c224c495089a3a6de99a2fc72d5228ec9..381c6826de1e20a2d5c24ef3523f121611ff505b 100644 (file)
@@ -320,23 +320,31 @@ static bool register_roots(array* new_roots, array* unwatchable, array* mounts)
       continue;
     }
 
-    char* skip = NULL;
+    array* inner_mounts = array_create(5);
+    CHECK_NULL(inner_mounts, false);
+
+    bool skip = false;
     for (int j=0; j<array_size(mounts); j++) {
       char* mount = array_get(mounts, j);
-      if (strncmp(mount, unflattened, strlen(mount)) == 0) {
-        userlog(LOG_DEBUG, "path %s is under unwatchable %s - ignoring", unflattened, mount);
-        skip = strdup(unflattened);
-        CHECK_NULL(skip, false);
+      if (is_parent_path(mount, unflattened)) {
+        userlog(LOG_DEBUG, "watch root '%s' is under mount point '%s' - skipping", unflattened, mount);
+        CHECK_NULL(array_push(unwatchable, strdup(unflattened)), false);
+        skip = true;
         break;
       }
+      else if (is_parent_path(unflattened, mount)) {
+        userlog(LOG_DEBUG, "watch root '%s' contains mount point '%s' - partial watch", unflattened, mount);
+        char* copy = strdup(mount);
+        CHECK_NULL(array_push(unwatchable, copy), false);
+        CHECK_NULL(array_push(inner_mounts, copy), false);
+      }
     }
-    if (skip != NULL) {
-      CHECK_NULL(array_push(unwatchable, skip), false);
+    if (skip) {
       continue;
     }
 
-    // todo: consider a mount point under a watch root?
-    int id = watch(new_root);
+    int id = watch(new_root, inner_mounts);
+    array_delete(inner_mounts);
 
     if (id >= 0) {
       watch_root* root = malloc(sizeof(watch_root));
index 9d6ffc01ea8757af566daea044b4162afde2cc70..4dc3657ab7773eaf4373302774ca03c7fcaa3899 100755 (executable)
@@ -4,4 +4,7 @@ clang -m32 -O2 -Wall -std=c99 -D_BSD_SOURCE -D_XOPEN_SOURCE=500 -o fsnotifier ma
 if [ $? -eq 0 ] ; then
   echo "compiling 64-bit version"
   clang -m64 -O2 -Wall -std=c99 -D_BSD_SOURCE -D_XOPEN_SOURCE=500 -o fsnotifier64 main.c inotify.c util.c
+  if [ $? -eq 0 ] ; then
+    chmod 755 fsnotifier fsnotifier64
+  fi
 fi
index 6e09a9053d8090f676ee08691a8c1850bfbc8c23..179b3105a4229b80fcf707892ac79e27006b8b53 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.
@@ -188,3 +188,10 @@ char* read_line(FILE* stream) {
   }
   return input_buf;
 }
+
+
+bool is_parent_path(const char* parent_path, const char* child_path) {
+  size_t parent_len = strlen(parent_path);
+  return strncmp(parent_path, child_path, parent_len) == 0 &&
+         (parent_len == strlen(child_path) || child_path[parent_len] == '/');
+}