X-Git-Url: https://mattmccutchen.net/rsync/rsync.git/blobdiff_plain/6db1db54883508cd572e24f93e7bee14e286967d..bc2337717e29f5bc2ea4b071a13d1026aa03957a:/util.c diff --git a/util.c b/util.c index 2afb63ec..634f9cf5 100644 --- a/util.c +++ b/util.c @@ -29,6 +29,7 @@ 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; @@ -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; } @@ -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) @@ -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,6 +1193,28 @@ int unsafe_symlink(const char *dest, const char *src) return (depth < 0); } +#define HUMANIFY(mult) \ + do { \ + if (num >= mult || num <= -mult) { \ + double dnum = (double)num / mult; \ + char units; \ + if (num < 0) \ + dnum = -dnum; \ + if (dnum < mult) \ + units = 'K'; \ + else if ((dnum /= mult) < mult) \ + units = 'M'; \ + else { \ + dnum /= mult; \ + units = 'G'; \ + } \ + if (num < 0) \ + dnum = -dnum; \ + snprintf(bufs[n], sizeof bufs[0], "%.2f%c", dnum, units); \ + return bufs[n]; \ + } \ + } while (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. */ @@ -1168,27 +1223,15 @@ char *human_num(int64 num) static char bufs[4][128]; /* more than enough room */ static unsigned int n; char *s; + int negated; 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]; - } + if (human_readable == 1) + HUMANIFY(1000); + else + HUMANIFY(1024); } s = bufs[n] + sizeof bufs[0] - 1; @@ -1196,10 +1239,23 @@ char *human_num(int64 num) if (!num) *--s = '0'; + if (num < 0) { + /* A maximum-size negated number can't fit as a positive, + * so do one digit in negated form to start us off. */ + *--s = (char)(-(num % 10)) + '0'; + num = -(num / 10); + negated = 1; + } else + negated = 0; + while (num) { *--s = (char)(num % 10) + '0'; num /= 10; } + + if (negated) + *--s = '-'; + return s; } @@ -1212,8 +1268,8 @@ char *human_dnum(double dnum, int decimal_digits) 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); + buf -= decimal_digits + 2; + snprintf(buf, len + decimal_digits + 3, "%.*f", decimal_digits, dnum); } return buf; }