X-Git-Url: https://mattmccutchen.net/rsync/rsync.git/blobdiff_plain/25ff04417e4b4fa0aeb44e0b1576a01021aa1650..32cbfe7b17ba8ec661fc27fd773909709d100e8a:/util.c diff --git a/util.c b/util.c index 6887d67c..a43cfb0b 100644 --- a/util.c +++ b/util.c @@ -79,7 +79,7 @@ int fd_pair(int fd[2]) { int ret; -#if HAVE_SOCKETPAIR +#ifdef HAVE_SOCKETPAIR ret = socketpair(AF_UNIX, SOCK_STREAM, 0, fd); #else ret = pipe(fd); @@ -105,9 +105,9 @@ void print_child_argv(char **cmd) "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "0123456789" ",.-_=+@/") != strlen(*cmd)) { - rprintf(FINFO, "\"%s\" ", *cmd); + rprintf(FINFO, "\"%s\" ", safe_fname(*cmd)); } else { - rprintf(FINFO, "%s ", *cmd); + rprintf(FINFO, "%s ", safe_fname(*cmd)); } } rprintf(FINFO, "\n"); @@ -132,7 +132,7 @@ int set_modtime(char *fname, time_t modtime) { if (verbose > 2) { rprintf(FINFO, "set modtime of %s to (%ld) %s", - fname, (long)modtime, + safe_fname(fname), (long)modtime, asctime(localtime(&modtime))); } @@ -140,12 +140,12 @@ int set_modtime(char *fname, time_t modtime) return 0; { -#if HAVE_UTIMBUF +#ifdef HAVE_UTIMBUF struct utimbuf tbuf; tbuf.actime = time(NULL); tbuf.modtime = modtime; return utime(fname,&tbuf); -#elif HAVE_UTIME +#elif defined HAVE_UTIME time_t t[2]; t[0] = time(NULL); t[1] = modtime; @@ -350,7 +350,7 @@ int robust_unlink(char *fname) if (verbose > 0) { rprintf(FINFO,"renaming %s to %s because of text busy\n", - fname, path); + safe_fname(fname), safe_fname(path)); } /* maybe we should return rename()'s exit status? Nah. */ @@ -502,7 +502,7 @@ static void glob_expand_one(char *s, char ***argv_ptr, int *argc_ptr, char **argv = *argv_ptr; int argc = *argc_ptr; int maxargs = *maxargs_ptr; -#if !(HAVE_GLOB && HAVE_GLOB_H) +#if !defined HAVE_GLOB || !defined HAVE_GLOB_H if (argc == maxargs) { maxargs += MAX_ARGS; if (!(argv = realloc_array(argv, char *, maxargs))) @@ -876,28 +876,31 @@ int pop_dir(char *dir) return 1; } -/** - * Return the filename, turning any newlines into '?'s. This ensures that - * outputting it on a line of its own cannot generate an empty line. This - * function can handle only 2 names at a time! - **/ +/* Return the filename, turning any non-printable characters into '?'s. + * This ensures that outputting it on a line of its own cannot generate an + * empty line. This function can return only MAX_SAFE_NAMES values at a + * time! The returned value can be longer than MAXPATHLEN (because we + * may be trying to output an error about a too-long filename)! */ const char *safe_fname(const char *fname) { - static char fbuf1[MAXPATHLEN], fbuf2[MAXPATHLEN]; - static char *fbuf = fbuf2; - char *nl = strchr(fname, '\n'); - - if (!nl) - return fname; - - fbuf = fbuf == fbuf1 ? fbuf2 : fbuf1; - strlcpy(fbuf, fname, MAXPATHLEN); - nl = fbuf + (nl - (char *)fname); - do { - *nl = '?'; - } while ((nl = strchr(nl+1, '\n')) != NULL); +#define MAX_SAFE_NAMES 4 + static char fbuf[MAX_SAFE_NAMES][MAXPATHLEN*2]; + static int ndx = 0; + int limit = sizeof fbuf / MAX_SAFE_NAMES - 1; + char *t; + + ndx = (ndx + 1) % MAX_SAFE_NAMES; + for (t = fbuf[ndx]; *fname; fname++) { + if (!isprint(*(uchar*)fname)) + *t++ = '?'; + else + *t++ = *fname; + if (--limit == 0) + break; + } + *t = '\0'; - return fbuf; + return fbuf[ndx]; } /** @@ -919,25 +922,21 @@ char *full_fname(const char *fn) p1 = p2 = ""; else { p1 = curr_dir; - p2 = "/"; + for (p2 = p1; *p2 == '/'; p2++) {} + if (*p2) + p2 = "/"; } if (module_id >= 0) { m1 = " (in "; m2 = lp_name(module_id); m3 = ")"; - if (*p1) { + if (p1 == curr_dir) { if (!lp_use_chroot(module_id)) { char *p = lp_path(module_id); if (*p != '/' || p[1]) p1 += strlen(p); } - if (!*p1) - p2++; - else - p1++; } - else - fn++; } else m1 = m2 = m3 = ""; @@ -966,9 +965,17 @@ char *partial_dir_fname(const char *fname) fn = fname; if ((int)pathjoin(t, sz, partial_dir, fn) >= sz) return NULL; - if (server_filter_list.head - && check_filter(&server_filter_list, partial_fname, 0) < 0) - return NULL; + if (server_filter_list.head) { + static int len; + if (!len) + len = strlen(partial_dir); + t[len] = '\0'; + if (check_filter(&server_filter_list, partial_fname, 1) < 0) + return NULL; + t[len] = '/'; + if (check_filter(&server_filter_list, partial_fname, 0) < 0) + return NULL; + } return partial_fname; } @@ -1094,7 +1101,7 @@ char *timestring(time_t t) static char TimeBuf[200]; struct tm *tm = localtime(&t); -#if HAVE_STRFTIME +#ifdef HAVE_STRFTIME strftime(TimeBuf, sizeof TimeBuf - 1, "%Y/%m/%d %H:%M:%S", tm); #else strlcpy(TimeBuf, asctime(tm), sizeof TimeBuf); @@ -1213,3 +1220,110 @@ void *_realloc_array(void *ptr, unsigned int size, unsigned long num) return malloc(size * num); return realloc(ptr, size * num); } + +/* Take a filename and filename length and return the most significant + * filename suffix we can find. This ignores suffixes such as "~", + * ".bak", ".orig", ".~1~", etc. */ +const char *find_filename_suffix(const char *fn, int fn_len, int *len_ptr) +{ + const char *suf, *s; + BOOL had_tilde; + int s_len; + + /* One or more dots at the start aren't a suffix. */ + while (fn_len && *fn == '.') fn++, fn_len--; + + /* Ignore the ~ in a "foo~" filename. */ + if (fn_len > 1 && fn[fn_len-1] == '~') + fn_len--, had_tilde = True; + else + had_tilde = False; + + /* Assume we don't find an suffix. */ + suf = ""; + *len_ptr = 0; + + /* Find the last significant suffix. */ + for (s = fn + fn_len; fn_len > 1; ) { + while (*--s != '.' && s != fn) {} + if (s == fn) + break; + s_len = fn_len - (s - fn); + fn_len = s - fn; + if (s_len == 3) { + if (strcmp(s+1, "bak") == 0 + || strcmp(s+1, "old") == 0) + continue; + } else if (s_len == 4) { + if (strcmp(s+1, "orig") == 0) + continue; + } else if (s_len > 2 && had_tilde + && s[1] == '~' && isdigit(*(uchar*)(s+2))) + continue; + *len_ptr = s_len; + suf = s; + if (s_len == 1) + break; + /* Determine if the suffix is all digits. */ + for (s++, s_len--; s_len > 0; s++, s_len--) { + if (!isdigit(*(uchar*)s)) + return suf; + } + /* An all-digit suffix may not be that signficant. */ + s = suf; + } + + return suf; +} + +/* This is an implementation of the Levenshtein distance algorithm. It + * was implemented to avoid needing a two-dimensional matrix (to save + * memory). It was also tweaked to try to factor in the ASCII distance + * between changed characters as a minor distance quantity. The normal + * Levenshtein units of distance (each signifying a single change between + * the two strings) are defined as a "UNIT". */ + +#define UNIT (1 << 16) + +uint32 fuzzy_distance(const char *s1, int len1, const char *s2, int len2) +{ + uint32 a[MAXPATHLEN], diag, above, left, diag_inc, above_inc, left_inc; + int32 cost; + int i1, i2; + + if (!len1 || !len2) { + if (!len1) { + s1 = s2; + len1 = len2; + } + for (i1 = 0, cost = 0; i1 < len1; i1++) + cost += s1[i1]; + return (int32)len1 * UNIT + cost; + } + + for (i2 = 0; i2 < len2; i2++) + a[i2] = (i2+1) * UNIT; + + for (i1 = 0; i1 < len1; i1++) { + diag = i1 * UNIT; + above = (i1+1) * UNIT; + for (i2 = 0; i2 < len2; i2++) { + left = a[i2]; + if ((cost = *((uchar*)s1+i1) - *((uchar*)s2+i2)) != 0) { + if (cost < 0) + cost = UNIT - cost; + else + cost = UNIT + cost; + } + diag_inc = diag + cost; + left_inc = left + UNIT + *((uchar*)s1+i1); + above_inc = above + UNIT + *((uchar*)s2+i2); + a[i2] = above = left < above + ? (left_inc < diag_inc ? left_inc : diag_inc) + : (above_inc < diag_inc ? above_inc : diag_inc); + diag = left; + } + } + + return a[len2-1]; +}