From ebdd24d6d08bc4ffd632a64b3781f48cc8a46eb0 Mon Sep 17 00:00:00 2001 From: Wayne Davison Date: Fri, 6 Aug 2004 21:24:14 +0000 Subject: [PATCH] An improved clean_fname() routine that is more efficient and will also collapse ".." dirs that aren't at the start of the path. Care was taken to ensure that the cleaning of a name that goes over the socket is done in the same way as the old code (because both sides call clean_fname() on those file-list names). This ensures compatibility with older rsync versions. --- util.c | 69 ++++++++++++++++++++++++++++++++-------------------------- 1 file changed, 38 insertions(+), 31 deletions(-) diff --git a/util.c b/util.c index 43613e78..96b7ac4f 100644 --- a/util.c +++ b/util.c @@ -652,45 +652,52 @@ size_t stringjoin(char *dest, size_t destsize, ...) void clean_fname(char *name) { - char *p; - int l; - int modified = 1; + char *limit = name, *t = name, *f = name; + int anchored; if (!name) return; - while (modified) { - modified = 0; - - if ((p = strstr(name,"/./")) != NULL) { - modified = 1; - while (*p) { - p[0] = p[2]; - p++; - } + if ((anchored = *f == '/') != 0) + *t++ = *f++; + while (*f) { + /* discard extra slashes */ + if (*f == '/') { + f++; + continue; } - - if ((p = strstr(name,"//")) != NULL) { - modified = 1; - while (*p) { - p[0] = p[1]; - p++; + if (*f == '.') { + /* discard "." dirs (but NOT a trailing '.'!) */ + if (f[1] == '/') { + f++; /* not += 2! */ + continue; + } + /* collapse ".." dirs */ + if (f[1] == '.' && (f[2] == '/' || !f[2])) { + char *s = t - 1; + if (s == name && anchored) { + f += 2; + continue; + } + while (s > limit && *--s != '/') {} + if (s != t - 1 && *s == '/') { + t = s + 1; + f += 2; + continue; + } + *t++ = *f++; + *t++ = *f++; + limit = t; } } - - if (strncmp(p = name, "./", 2) == 0) { - modified = 1; - do { - p[0] = p[2]; - } while (*p++); - } - - l = strlen(p = name); - if (l > 1 && p[l-1] == '/') { - modified = 1; - p[l-1] = 0; - } + while (*f && (*t++ = *f++) != '/') {} } + + if (t > name+anchored && t[-1] == '/') + t--; + if (t == name) + *t++ = '.'; + *t = '\0'; } /* Make path appear as if a chroot had occurred. This handles a leading -- 2.34.1