Improved the build rule for getfsdev and added getfsdev.o to the
[rsync/rsync.git] / util.c
diff --git a/util.c b/util.c
index 829bad6..e18f991 100644 (file)
--- a/util.c
+++ b/util.c
@@ -665,10 +665,10 @@ int count_dir_elements(const char *p)
 }
 
 /* Turns multiple adjacent slashes into a single slash, gets rid of "./"
- * elements, collapses ".." elements except for those at the start of
- * the string. If the resulting path would be empty, change it into a
- * ".". */
-unsigned int clean_fname(char *name)
+ * elements (but not a trailing dot dir), removes a trailing slash, and
+ * optionally collapses ".." elements (except for those at the start of the
+ * string).  If the resulting name would be empty, change it into a ".". */
+unsigned int clean_fname(char *name, BOOL collapse_dot_dot)
 {
        char *limit = name - 1, *t = name, *f = name;
        int anchored;
@@ -691,7 +691,8 @@ unsigned int clean_fname(char *name)
                                continue;
                        }
                        /* collapse ".." dirs */
-                       if (f[1] == '.' && (f[2] == '/' || !f[2])) {
+                       if (collapse_dot_dot
+                           && f[1] == '.' && (f[2] == '/' || !f[2])) {
                                char *s = t - 1;
                                if (s == name && anchored) {
                                        f += 2;
@@ -734,13 +735,17 @@ unsigned int clean_fname(char *name)
  * If depth is > 0, it is a count of how many '..'s to allow at the start
  * of the path.
  *
- * We call clean_fname() to clean up the path, but we preserve a trailing
- * slash because that is sometimes significant on command-line arguments.
- */
+ * We also clean the path in a manner similar to clean_fname() but with a
+ * few differences: 
+ *
+ * Turns multiple adjacent slashes into a single slash, gets rid of "." dir
+ * elements (INCLUDING a trailing dot dir), PRESERVES a trailing slash, and
+ * ALWAYS collapses ".." elements (except for those at the start of the
+ * string up to "depth" deep).  If the resulting name would be empty,
+ * change it into a ".". */
 char *sanitize_path(char *dest, const char *p, const char *rootdir, int depth)
 {
        char *start, *sanp;
-       int allowdotdot = 0;
        int rlen = 0;
 
        if (dest != p) {
@@ -765,33 +770,25 @@ char *sanitize_path(char *dest, const char *p, const char *rootdir, int depth)
        }
 
        start = sanp = dest + rlen;
-       while (*p == '/') {
-               /* remove leading slashes */
-               p++;
-       }
        while (*p != '\0') {
+               /* discard leading or extra slashes */
+               if (*p == '/') {
+                       p++;
+                       continue;
+               }
                /* this loop iterates once per filename component in p.
                 * both p (and sanp if the original had a slash) should
                 * always be left pointing after a slash
                 */
                if (*p == '.' && (p[1] == '/' || p[1] == '\0')) {
                        /* skip "." component */
-                       while (*++p == '/') {
-                               /* skip following slashes */
-                               ;
-                       }
+                       p++;
                        continue;
                }
-               allowdotdot = 0;
                if (*p == '.' && p[1] == '.' && (p[2] == '/' || p[2] == '\0')) {
                        /* ".." component followed by slash or end */
-                       if (depth > 0 && sanp == start) {
-                               /* allow depth levels of .. at the beginning */
-                               --depth;
-                               allowdotdot = 1;
-                       } else {
+                       if (depth <= 0 || sanp != start) {
                                p += 2;
-                               while (*p == '/') p++;
                                if (sanp != start) {
                                        /* back up sanp one level */
                                        --sanp; /* now pointing at slash */
@@ -802,22 +799,13 @@ char *sanitize_path(char *dest, const char *p, const char *rootdir, int depth)
                                }
                                continue;
                        }
-               }
-               while (1) {
-                       /* copy one component through next slash */
-                       *sanp++ = *p++;
-                       if (*p == '\0' || p[-1] == '/') {
-                               while (*p == '/') {
-                                       /* skip multiple slashes */
-                                       p++;
-                               }
-                               break;
-                       }
-               }
-               if (allowdotdot) {
+                       /* allow depth levels of .. at the beginning */
+                       depth--;
                        /* move the virtual beginning to leave the .. alone */
-                       start = sanp;
+                       start = sanp + 3;
                }
+               /* copy one component through next slash */
+               while (*p && (*sanp++ = *p++) != '/') {}
        }
        if (sanp == dest) {
                /* ended up with nothing, so put in "." component */
@@ -869,7 +857,7 @@ int push_dir(char *dir)
                curr_dir_len += len;
        }
 
-       curr_dir_len = clean_fname(curr_dir);
+       curr_dir_len = clean_fname(curr_dir, 1);
 
        return 1;
 }