X-Git-Url: https://mattmccutchen.net/rsync/rsync.git/blobdiff_plain/84a6379565735489e641877775cb00f592605eb0..10796f4b6e52593c64ace935357d8782cb57d4ee:/util.c diff --git a/util.c b/util.c index 43613e78..449b101e 100644 --- a/util.c +++ b/util.c @@ -362,8 +362,8 @@ int robust_unlink(char *fname) #endif } -/* Returns 0 on success, -1 on most errors, and -2 if we got an error - * trying to copy the file across file systems. */ +/* Returns 0 on successful rename, 1 if we successfully copied the file + * across filesystems, -2 if copy_file() failed, and -1 on other errors. */ int robust_rename(char *from, char *to, int mode) { int tries = 4; @@ -383,7 +383,7 @@ int robust_rename(char *from, char *to, int mode) if (copy_file(from, to, mode) != 0) return -2; do_unlink(from); - return 0; + return 1; default: return -1; } @@ -650,47 +650,56 @@ size_t stringjoin(char *dest, size_t destsize, ...) return ret; } -void clean_fname(char *name) +unsigned int clean_fname(char *name) { - char *p; - int l; - int modified = 1; + char *limit = name - 1, *t = name, *f = name; + int anchored; if (!name) - return; - - while (modified) { - modified = 0; + return 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 += 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 < name || *s == '/')) { + t = s + 1; + f += 2; + continue; + } + *t++ = *f++; + *t++ = *f++; + limit = t; } } + while (*f && (*t++ = *f++) != '/') {} + } - if (strncmp(p = name, "./", 2) == 0) { - modified = 1; - do { - p[0] = p[2]; - } while (*p++); - } + if (t > name+anchored && t[-1] == '/') + t--; + if (t == name) + *t++ = '.'; + *t = '\0'; - l = strlen(p = name); - if (l > 1 && p[l-1] == '/') { - modified = 1; - p[l-1] = 0; - } - } + return t - name; } /* Make path appear as if a chroot had occurred. This handles a leading @@ -860,7 +869,7 @@ int push_dir(char *dir) curr_dir_len += len; } - clean_fname(curr_dir); + curr_dir_len = clean_fname(curr_dir); return 1; }