X-Git-Url: https://mattmccutchen.net/rsync/rsync.git/blobdiff_plain/29a89172f77ed76dcf53612e96dc35daf15d7362..5dd14f0c3388f69932d521915e039e32b9e6d970:/util.c diff --git a/util.c b/util.c index a40ce7b5..7569981d 100644 --- a/util.c +++ b/util.c @@ -22,13 +22,14 @@ #include "rsync.h" #include "ifuncs.h" +#include "itypes.h" +#include "inums.h" -extern int verbose; extern int dry_run; extern int module_id; extern int modify_window; extern int relative_paths; -extern int human_readable; +extern int preserve_xattrs; extern char *module_dir; extern unsigned int module_dirlen; extern mode_t orig_umask; @@ -129,7 +130,7 @@ int set_modtime(const char *fname, time_t modtime, mode_t mode) return 1; #endif - if (verbose > 2) { + if (DEBUG_GTE(TIME, 1)) { rprintf(FINFO, "set modtime of %s to (%ld) %s", fname, (long)modtime, asctime(localtime(&modtime))); @@ -264,6 +265,8 @@ static int safe_read(int desc, char *ptr, size_t len) /* Copy a file. If ofd < 0, copy_file unlinks and opens the "dest" file. * Otherwise, it just writes to and closes the provided file descriptor. + * In either case, if --xattrs are being preserved, the dest file will + * have its xattrs set from the source file. * * This is used in conjunction with the --temp-dir, --backup, and * --copy-dest options. */ @@ -275,38 +278,54 @@ int copy_file(const char *source, const char *dest, int ofd, int len; /* Number of bytes read into `buf'. */ if ((ifd = do_open(source, O_RDONLY, 0)) < 0) { + int save_errno = errno; rsyserr(FERROR_XFER, errno, "open %s", full_fname(source)); + errno = save_errno; return -1; } if (ofd < 0) { if (robust_unlink(dest) && errno != ENOENT) { + int save_errno = errno; rsyserr(FERROR_XFER, errno, "unlink %s", full_fname(dest)); + errno = save_errno; return -1; } - if ((ofd = do_open(dest, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, mode)) < 0 - && (!create_bak_dir || errno != ENOENT || make_bak_dir(dest) < 0 - || (ofd = do_open(dest, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, mode)) < 0)) { - rsyserr(FERROR_XFER, errno, "open %s", full_fname(dest)); - close(ifd); - return -1; + if ((ofd = do_open(dest, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, mode)) < 0) { + int save_errno = errno ? errno : EINVAL; /* 0 paranoia */ + if (create_bak_dir && errno == ENOENT && make_bak_dir(dest) == 0) { + if ((ofd = do_open(dest, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, mode)) < 0) + save_errno = errno ? errno : save_errno; + else + save_errno = 0; + } + if (save_errno) { + rsyserr(FERROR_XFER, save_errno, "open %s", full_fname(dest)); + close(ifd); + errno = save_errno; + return -1; + } } } while ((len = safe_read(ifd, buf, sizeof buf)) > 0) { if (full_write(ofd, buf, len) < 0) { + int save_errno = errno; rsyserr(FERROR_XFER, errno, "write %s", full_fname(dest)); close(ifd); close(ofd); + errno = save_errno; return -1; } } if (len < 0) { + int save_errno = errno; rsyserr(FERROR_XFER, errno, "read %s", full_fname(source)); close(ifd); close(ofd); + errno = save_errno; return -1; } @@ -316,11 +335,18 @@ int copy_file(const char *source, const char *dest, int ofd, } if (close(ofd) < 0) { + int save_errno = errno; rsyserr(FERROR_XFER, errno, "close failed on %s", full_fname(dest)); + errno = save_errno; return -1; } +#ifdef SUPPORT_XATTRS + if (preserve_xattrs) + copy_xattrs(source, dest); +#endif + return 0; } @@ -371,7 +397,7 @@ int robust_unlink(const char *fname) counter = 1; } while ((rc = access(path, 0)) == 0 && counter != start); - if (verbose > 0) { + if (INFO_GTE(MISC, 1)) { rprintf(FWARNING, "renaming %s to %s because of text busy\n", fname, path); } @@ -401,14 +427,17 @@ int robust_rename(const char *from, const char *to, const char *partialptr, switch (errno) { #ifdef ETXTBSY case ETXTBSY: - if (robust_unlink(to) != 0) + if (robust_unlink(to) != 0) { + errno = ETXTBSY; return -1; + } + errno = ETXTBSY; break; #endif case EXDEV: if (partialptr) { if (!handle_partial_dir(partialptr,PDIR_CREATE)) - return -1; + return -2; to = partialptr; } if (copy_file(from, to, -1, mode, 0) != 0) @@ -582,7 +611,7 @@ static inline void call_glob_match(const char *name, int len, int from_glob, } else use_buf = glob.arg_buf; - if (from_glob || arg) { + if (from_glob || (arg && len)) { STRUCT_STAT st; int is_dir; @@ -990,7 +1019,7 @@ int change_dir(const char *dir, int set_path_only) curr_dir_depth = count_dir_elements(curr_dir + module_dirlen); } - if (verbose >= 5 && !set_path_only) + if (DEBUG_GTE(CHDIR, 1) && !set_path_only) rprintf(FINFO, "[%s] change_dir(%s)\n", who_am_i(), curr_dir); return 1; @@ -1083,12 +1112,16 @@ int handle_partial_dir(const char *fname, int create) STRUCT_STAT st; int statret = do_lstat(dir, &st); if (statret == 0 && !S_ISDIR(st.st_mode)) { - if (do_unlink(dir) < 0) + if (do_unlink(dir) < 0) { + *fn = '/'; return 0; + } statret = -1; } - if (statret < 0 && do_mkdir(dir, 0700) < 0) + if (statret < 0 && do_mkdir(dir, 0700) < 0) { + *fn = '/'; return 0; + } } else do_rmdir(dir); *fn = '/'; @@ -1160,64 +1193,6 @@ 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 ? 1000 : 1024; - 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) { - snprintf(bufs[n], sizeof bufs[0], "%.2f%c", dnum, units); - return bufs[n]; - } - } - - s = bufs[n] + sizeof bufs[0] - 1; - *s = '\0'; - - if (!num) - *--s = '0'; - while (num) { - *--s = (char)(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(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. Some callers tweak returned buf. */ char *timestring(time_t t) { @@ -1329,7 +1304,7 @@ void *_new_array(unsigned long num, unsigned int size, int use_calloc) return use_calloc ? calloc(num, size) : malloc(num * size); } -void *_realloc_array(void *ptr, unsigned int size, unsigned long num) +void *_realloc_array(void *ptr, unsigned int size, size_t num) { if (num >= MALLOC_MAX/size) return NULL; @@ -1550,10 +1525,13 @@ void *expand_item_list(item_list *lp, size_t item_size, new_size += incr; else new_size *= 2; - new_ptr = realloc_array(lp->items, char, new_size * item_size); - if (verbose >= 4) { - rprintf(FINFO, "[%s] expand %s to %.0f bytes, did%s move\n", - who_am_i(), desc, (double)new_size * item_size, + if (new_size < lp->malloced) + overflow_exit("expand_item_list"); + /* Using _realloc_array() lets us pass the size, not a type. */ + new_ptr = _realloc_array(lp->items, item_size, new_size); + if (DEBUG_GTE(FLIST, 3)) { + rprintf(FINFO, "[%s] expand %s to %s bytes, did%s move\n", + who_am_i(), desc, big_num(new_size * item_size), new_ptr == lp->items ? " not" : ""); } if (!new_ptr)