csync_excluded: Another speedup #3638
authorChristian Kamm <mail@ckamm.de>
Mon, 24 Aug 2015 09:09:34 +0000 (11:09 +0200)
committerChristian Kamm <mail@ckamm.de>
Mon, 24 Aug 2015 13:08:06 +0000 (15:08 +0200)
Build a list of path components outside of the exclude pattern loop.

csync/src/csync_exclude.c
csync/src/std/c_string.c
csync/src/std/c_string.h
csync/tests/csync_tests/check_csync_exclude.c

index baf14b70e1ce605ea3c0a105886a00d626f7b5c4..d5cee4368aae21af40ce546511105753d2bb243d 100644 (file)
 static
 #endif
 int _csync_exclude_add(c_strlist_t **inList, const char *string) {
-    c_strlist_t *list;
-
-    if (*inList == NULL) {
-        *inList = c_strlist_new(32);
-        if (*inList == NULL) {
-            return -1;
-        }
-    }
-
-    if ((*inList)->count == (*inList)->size) {
-        list = c_strlist_expand(*inList, 2 * (*inList)->size);
-        if (list == NULL) {
-            return -1;
-        }
-        *inList = list;
-    }
-
-    return c_strlist_add(*inList, string);
+    return c_strlist_add_grow(inList, string);
 }
 
 int csync_exclude_load(const char *fname, c_strlist_t **list) {
@@ -281,6 +264,31 @@ static CSYNC_EXCLUDE_TYPE _csync_excluded_common(c_strlist_t *excludes, const ch
         goto out;
     }
 
+    /* Build a list of path components to check. */
+    c_strlist_t *path_components = c_strlist_new(32);
+    char *path_split = strdup(path);
+    size_t len = strlen(path_split);
+    for (int j = len; ; --j) {
+        // read backwards until a path separator is found
+        if (j != 0 && path_split[j-1] != '/') {
+            continue;
+        }
+
+        // check 'basename', i.e. for "/foo/bar/fi" we'd check 'fi', 'bar', 'foo'
+        if (path_split[j] != 0) {
+            c_strlist_add_grow(&path_components, path_split + j);
+        }
+
+        if (j == 0 || !check_leading_dirs) {
+            break;
+        }
+
+        // check 'dirname', i.e. for "/foo/bar/fi" we'd check '/foo/bar', '/foo'
+        path_split[j-1] = '\0';
+        c_strlist_add_grow(&path_components, path_split);
+    }
+    SAFE_FREE(path_split);
+
     /* Loop over all exclude patterns and evaluate the given path */
     for (i = 0; match == CSYNC_NOT_EXCLUDED && i < excludes->count; i++) {
         bool match_dirs_only = false;
@@ -319,41 +327,21 @@ static CSYNC_EXCLUDE_TYPE _csync_excluded_common(c_strlist_t *excludes, const ch
 
         /* if still not excluded, check each component and leading directory of the path */
         if (match == CSYNC_NOT_EXCLUDED) {
-            char *segmented_path = strdup(path);
-            size_t len = strlen(segmented_path);
-            bool check_segname = !match_dirs_only || filetype != CSYNC_FTW_TYPE_FILE;
-            for (int j = len; ; --j) {
-                // read backwards until a path separator
-                if (j != 0 && segmented_path[j-1] != '/') {
-                    continue;
-                }
-
-                // check 'basename', i.e. for "/foo/bar/fi" we'd check 'fi', 'bar', 'foo'
-                if (check_segname && segmented_path[j] != 0) {
-                    rc = csync_fnmatch(pattern, segmented_path + j, 0);
-                    if (rc == 0) {
-                        match = type;
-                        break;
-                    }
-                }
-                check_segname = true;
-
-                if (j == 0 || !check_leading_dirs) {
-                    break;
-                }
-
-                // check 'dirname', i.e. for "/foo/bar/fi" we'd check '/foo/bar', '/foo'
-                segmented_path[j-1] = '\0';
-                rc = csync_fnmatch(pattern, segmented_path, 0);
+            size_t j = 0;
+            if (match_dirs_only && filetype == CSYNC_FTW_TYPE_FILE) {
+                j = 1; // skip the first entry, which is bname
+            }
+            for (; j < path_components->count; ++j) {
+                rc = csync_fnmatch(pattern, path_components->vector[j], 0);
                 if (rc == 0) {
                     match = type;
                     break;
                 }
             }
-            SAFE_FREE(segmented_path);
         }
         SAFE_FREE(pattern_stored);
     }
+    c_strlist_destroy(path_components);
 
   out:
 
index e248f6c7cf789a8fd27a42a2b69a0c0247ab1721..e21d4374e9453487db8cbf20e71b470831ed97fd 100644 (file)
@@ -215,6 +215,25 @@ int c_strlist_add(c_strlist_t *strlist, const char *string) {
   return 0;
 }
 
+int c_strlist_add_grow(c_strlist_t **strlist, const char *string) {
+  if (*strlist == NULL) {
+    *strlist = c_strlist_new(32);
+    if (*strlist == NULL) {
+      return -1;
+    }
+  }
+
+  if ((*strlist)->count == (*strlist)->size) {
+    c_strlist_t *list = c_strlist_expand(*strlist, 2 * (*strlist)->size);
+    if (list == NULL) {
+      return -1;
+    }
+    *strlist = list;
+  }
+
+  return c_strlist_add(*strlist, string);
+}
+
 void c_strlist_clear(c_strlist_t *strlist) {
   size_t i = 0;
 
index 640cb500ef64b6554b6c13f90fe7ee8d348ac665..60bc010da4b25ce104ec10286faa11e9d458ed43 100644 (file)
@@ -112,6 +112,19 @@ c_strlist_t *c_strlist_expand(c_strlist_t *strlist, size_t size);
  */
 int c_strlist_add(c_strlist_t *strlist, const char *string);
 
+/**
+ * @brief  Add a string to the stringlist, growing it if necessary
+ *
+ * Duplicates the string and stores it in the stringlist.
+ * It also initializes the stringlist if it starts out as null.
+ *
+ * @param strlist  Stringlist to add the string.
+ * @param string   String to add.
+ *
+ * @return  0 on success, less than 0 and errno set if an error occured.
+ */
+int c_strlist_add_grow(c_strlist_t **strlist, const char *string);
+
 /**
  * @brief Removes all strings from the list.
  *
index 0bcbda94f3f1c9e9d97050ce58b6446f818499fa..c73fe5f5c8a9e3799dead4038b4830565814bed8 100644 (file)
@@ -90,6 +90,11 @@ static void check_csync_excluded(void **state)
     CSYNC *csync = *state;
     int rc;
 
+    rc = csync_excluded(csync, "", CSYNC_FTW_TYPE_FILE);
+    assert_int_equal(rc, CSYNC_NOT_EXCLUDED);
+    rc = csync_excluded(csync, "/", CSYNC_FTW_TYPE_FILE);
+    assert_int_equal(rc, CSYNC_NOT_EXCLUDED);
+
     rc = csync_excluded(csync, "krawel_krawel", CSYNC_FTW_TYPE_FILE);
     assert_int_equal(rc, CSYNC_NOT_EXCLUDED);
     rc = csync_excluded(csync, ".kde/share/config/kwin.eventsrc", CSYNC_FTW_TYPE_FILE);