X-Git-Url: https://mattmccutchen.net/rsync/rsync.git/blobdiff_plain/af9f56a09df90e07bd3ba33e2583b30fd77f3e0f..63cf5ae72cc8f844bb8b478de0343f862db40a41:/util.c diff --git a/util.c b/util.c index b20cdb64..3d88b15c 100644 --- a/util.c +++ b/util.c @@ -31,6 +31,8 @@ extern int verbose; extern int dry_run; extern int module_id; extern int modify_window; +extern int relative_paths; +extern int human_readable; extern char *partial_dir; extern struct filter_list_struct server_filter_list; @@ -105,9 +107,9 @@ void print_child_argv(char **cmd) "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "0123456789" ",.-_=+@/") != strlen(*cmd)) { - rprintf(FINFO, "\"%s\" ", safe_fname(*cmd)); + rprintf(FINFO, "\"%s\" ", *cmd); } else { - rprintf(FINFO, "%s ", safe_fname(*cmd)); + rprintf(FINFO, "%s ", *cmd); } } rprintf(FINFO, "\n"); @@ -120,7 +122,7 @@ void out_of_memory(char *str) exit_cleanup(RERR_MALLOC); } -void overflow(char *str) +void overflow_exit(char *str) { rprintf(FERROR, "ERROR: buffer overflow in %s\n", str); exit_cleanup(RERR_MALLOC); @@ -128,11 +130,16 @@ void overflow(char *str) -int set_modtime(char *fname, time_t modtime) +int set_modtime(char *fname, time_t modtime, mode_t mode) { +#if !defined HAVE_LUTIMES || !defined HAVE_UTIMES + if (S_ISLNK(mode)) + return 1; +#endif + if (verbose > 2) { rprintf(FINFO, "set modtime of %s to (%ld) %s", - safe_fname(fname), (long)modtime, + fname, (long)modtime, asctime(localtime(&modtime))); } @@ -140,7 +147,18 @@ int set_modtime(char *fname, time_t modtime) return 0; { -#ifdef HAVE_UTIMBUF +#ifdef HAVE_UTIMES + struct timeval t[2]; + t[0].tv_sec = time(NULL); + t[0].tv_usec = 0; + t[1].tv_sec = modtime; + t[1].tv_usec = 0; +# ifdef HAVE_LUTIMES + if (S_ISLNK(mode)) + return lutimes(fname, t); +# endif + return utimes(fname, t); +#elif defined HAVE_UTIMBUF struct utimbuf tbuf; tbuf.actime = time(NULL); tbuf.modtime = modtime; @@ -151,12 +169,7 @@ int set_modtime(char *fname, time_t modtime) t[1] = modtime; return utime(fname,t); #else - struct timeval t[2]; - t[0].tv_sec = time(NULL); - t[0].tv_usec = 0; - t[1].tv_sec = modtime; - t[1].tv_usec = 0; - return utimes(fname,t); +#error No file-time-modification routine found! #endif } } @@ -247,7 +260,7 @@ static int safe_read(int desc, char *ptr, size_t len) * * This is used in conjunction with the --temp-dir, --backup, and * --copy-dest options. */ -int copy_file(char *source, char *dest, mode_t mode) +int copy_file(const char *source, const char *dest, mode_t mode) { int ifd; int ofd; @@ -316,7 +329,7 @@ int copy_file(char *source, char *dest, mode_t mode) * --delete trying to remove old .rsyncNNN files, hence it renames it * each time. **/ -int robust_unlink(char *fname) +int robust_unlink(const char *fname) { #ifndef ETXTBSY return do_unlink(fname); @@ -351,7 +364,7 @@ int robust_unlink(char *fname) if (verbose > 0) { rprintf(FINFO,"renaming %s to %s because of text busy\n", - safe_fname(fname), safe_fname(path)); + fname, path); } /* maybe we should return rename()'s exit status? Nah. */ @@ -365,7 +378,7 @@ int robust_unlink(char *fname) /* 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 robust_rename(const char *from, const char *to, int mode) { int tries = 4; @@ -517,7 +530,6 @@ static void glob_expand_one(char *s, char ***argv_ptr, int *argc_ptr, filter_server_path(s); #else glob_t globbuf; - int i; if (maxargs <= argc) return; @@ -542,9 +554,9 @@ static void glob_expand_one(char *s, char ***argv_ptr, int *argc_ptr, if (globbuf.gl_pathc == 0) argv[argc++] = s; else { - int j = globbuf.gl_pathc; + int i; free(s); - for (i = 0; i < j; i++) { + for (i = 0; i < (int)globbuf.gl_pathc; i++) { if (!(argv[argc++] = strdup(globbuf.gl_pathv[i]))) out_of_memory("glob_expand_one"); } @@ -745,7 +757,7 @@ unsigned int clean_fname(char *name, BOOL collapse_dot_dot) char *sanitize_path(char *dest, const char *p, const char *rootdir, int depth) { char *start, *sanp; - int rlen = 0; + int rlen = 0, leave_one_dotdir = relative_paths; if (dest != p) { int plen = strlen(p); @@ -780,9 +792,13 @@ char *sanitize_path(char *dest, const char *p, const char *rootdir, int depth) * always be left pointing after a slash */ if (*p == '.' && (p[1] == '/' || p[1] == '\0')) { - /* skip "." component */ - p++; - continue; + if (leave_one_dotdir && p[1]) + leave_one_dotdir = 0; + else { + /* skip "." component */ + p++; + continue; + } } if (*p == '.' && p[1] == '.' && (p[2] == '/' || p[2] == '\0')) { /* ".." component followed by slash or end */ @@ -877,33 +893,6 @@ int pop_dir(char *dir) return 1; } -/* 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)! */ -char *safe_fname(const char *fname) -{ -#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[ndx]; -} - /** * Return a quoted string with the full pathname of the indicated filename. * The string " (in MODNAME)" may also be appended. The returned pointer @@ -918,7 +907,6 @@ char *full_fname(const char *fn) if (result) free(result); - fn = safe_fname(fn); if (*fn == '/') p1 = p2 = ""; else { @@ -1013,22 +1001,6 @@ int handle_partial_dir(const char *fname, int create) return 1; } -/** We need to supply our own strcmp function for file list comparisons - to ensure that signed/unsigned usage is consistent between machines. */ -int u_strcmp(const char *cs1, const char *cs2) -{ - const uchar *s1 = (const uchar *)cs1; - const uchar *s2 = (const uchar *)cs2; - - while (*s1 && *s2 && (*s1 == *s2)) { - s1++; s2++; - } - - return (int)*s1 - (int)*s2; -} - - - /** * Determine if a symlink points outside the current directory tree. * This is considered "unsafe" because e.g. when mirroring somebody @@ -1093,6 +1065,63 @@ int unsafe_symlink(const char *dest, const char *src) return (depth < 0); } +/* Return the int64 number as a string. If the --human-readable option was + * specified, we may output the number in K, M, or G units. We can return + * up to 4 buffers at a time. */ +char *human_num(int64 num) +{ + static char bufs[4][128]; /* more than enough room */ + static unsigned int n; + char *s; + + n = (n + 1) % (sizeof bufs / sizeof bufs[0]); + + if (human_readable) { + char units = '\0'; + int mult = human_readable == 1 ? 1024 : 1000; + double dnum = 0; + if (num > mult*mult*mult) { + dnum = (double)num / (mult*mult*mult); + units = 'G'; + } else if (num > mult*mult) { + dnum = (double)num / (mult*mult); + units = 'M'; + } else if (num > mult) { + dnum = (double)num / mult; + units = 'K'; + } + if (units) { + sprintf(bufs[n], "%.2f%c", dnum, units); + return bufs[n]; + } + } + + s = bufs[n] + sizeof bufs[0] - 1; + *s = '\0'; + + if (!num) + *--s = '0'; + while (num) { + *--s = (num % 10) + '0'; + num /= 10; + } + return s; +} + +/* Return the double number as a string. If the --human-readable option was + * specified, we may output the number in K, M, or G units. We use a buffer + * from human_num() to return our result. */ +char *human_dnum(double dnum, int decimal_digits) +{ + char *buf = human_num(dnum); + int len = strlen(buf); + if (isdigit(*(uchar*)(buf+len-1))) { + /* There's extra room in buf prior to the start of the num. */ + buf -= decimal_digits + 1; + snprintf(buf, len + decimal_digits + 2, "%.*f", decimal_digits, dnum); + } + return buf; +} /** * Return the date and time as a string