X-Git-Url: https://mattmccutchen.net/rsync/rsync.git/blobdiff_plain/3b22184d4c61e6dc77ec15f93bb760046c40533e..28b519c93b6db30b6520d46f8cd65160213fddd2:/util.c diff --git a/util.c b/util.c index 9d5f1800..3f611d15 100644 --- a/util.c +++ b/util.c @@ -25,11 +25,12 @@ #include "itypes.h" #include "inums.h" -extern int dry_run; extern int module_id; extern int modify_window; extern int relative_paths; +extern int preserve_times; extern int preserve_xattrs; +extern int preallocate_files; extern char *module_dir; extern unsigned int module_dirlen; extern char *partial_dir; @@ -122,12 +123,11 @@ NORETURN void overflow_exit(const char *str) exit_cleanup(RERR_MALLOC); } +/* This returns 0 for success, 1 for a symlink if symlink time-setting + * is not possible, or -1 for any other error. */ int set_modtime(const char *fname, time_t modtime, uint32 mod_nsec, mode_t mode) { -#ifndef CAN_SET_SYMLINK_TIMES - if (S_ISLNK(mode)) - return 1; -#endif + static int switch_step = 0; if (DEBUG_GTE(TIME, 1)) { rprintf(FINFO, "set modtime of %s to (%ld) %s", @@ -135,46 +135,49 @@ int set_modtime(const char *fname, time_t modtime, uint32 mod_nsec, mode_t mode) asctime(localtime(&modtime))); } - if (dry_run) - return 0; - - { + switch (switch_step) { #ifdef HAVE_UTIMENSAT - struct timespec t[2]; - t[0].tv_sec = 0; - t[0].tv_nsec = UTIME_NOW; - t[1].tv_sec = modtime; - t[1].tv_nsec = mod_nsec; - if (utimensat(AT_FDCWD, fname, t, AT_SYMLINK_NOFOLLOW) < 0) - return S_ISLNK(mode) && errno == ENOSYS ? 1 : -1; - return 0; -#elif defined HAVE_UTIMES || defined HAVE_LUTIMES - struct timeval t[2]; - t[0].tv_sec = time(NULL); - t[0].tv_usec = 0; - t[1].tv_sec = modtime; - t[1].tv_usec = mod_nsec / 1000; -# ifdef HAVE_LUTIMES - if (lutimes(fname, t) < 0) - return S_ISLNK(mode) && errno == ENOSYS ? 1 : -1; - return 0; -# else - return utimes(fname, t); -# endif -#elif defined HAVE_STRUCT_UTIMBUF - struct utimbuf tbuf; - tbuf.actime = time(NULL); - tbuf.modtime = modtime; - return utime(fname,&tbuf); -#elif defined HAVE_UTIME - time_t t[2]; - t[0] = time(NULL); - t[1] = modtime; - return utime(fname,t); +#include "case_N.h" + if (do_utimensat(fname, modtime, mod_nsec) == 0) + break; + if (errno != ENOSYS) + return -1; + switch_step++; + /* FALLTHROUGH */ +#endif + +#ifdef HAVE_LUTIMES +#include "case_N.h" + if (do_lutimes(fname, modtime, mod_nsec) == 0) + break; + if (errno != ENOSYS) + return -1; + switch_step++; + /* FALLTHROUGH */ +#endif + +#include "case_N.h" + switch_step++; + if (preserve_times & PRESERVE_LINK_TIMES) { + preserve_times &= ~PRESERVE_LINK_TIMES; + if (S_ISLNK(mode)) + return 1; + } + /* FALLTHROUGH */ + +#include "case_N.h" +#ifdef HAVE_UTIMES + if (do_utimes(fname, modtime, mod_nsec) == 0) + break; #else -#error No file-time-modification routine found! + if (do_utime(fname, modtime, mod_nsec) == 0) + break; #endif + + return -1; } + + return 0; } /* Create any necessary directories in fname. Any missing directories are @@ -313,6 +316,9 @@ int copy_file(const char *source, const char *dest, int ofd, mode_t mode) int ifd; char buf[1024 * 8]; int len; /* Number of bytes read into `buf'. */ +#ifdef PREALLOCATE_NEEDS_TRUNCATE + OFF_T preallocated_len = 0, offset = 0; +#endif if ((ifd = do_open(source, O_RDONLY, 0)) < 0) { int save_errno = errno; @@ -343,6 +349,25 @@ int copy_file(const char *source, const char *dest, int ofd, mode_t mode) } } +#ifdef SUPPORT_PREALLOCATION + if (preallocate_files) { + STRUCT_STAT srcst; + + /* Try to preallocate enough space for file's eventual length. Can + * reduce fragmentation on filesystems like ext4, xfs, and NTFS. */ + if (do_fstat(ifd, &srcst) < 0) + rsyserr(FWARNING, errno, "fstat %s", full_fname(source)); + else if (srcst.st_size > 0) { + if (do_fallocate(ofd, 0, srcst.st_size) == 0) { +#ifdef PREALLOCATE_NEEDS_TRUNCATE + preallocated_len = srcst.st_size; +#endif + } else + rsyserr(FWARNING, errno, "do_fallocate %s", full_fname(dest)); + } + } +#endif + while ((len = safe_read(ifd, buf, sizeof buf)) > 0) { if (full_write(ofd, buf, len) < 0) { int save_errno = errno; @@ -352,6 +377,9 @@ int copy_file(const char *source, const char *dest, int ofd, mode_t mode) errno = save_errno; return -1; } +#ifdef PREALLOCATE_NEEDS_TRUNCATE + offset += len; +#endif } if (len < 0) { @@ -368,6 +396,16 @@ int copy_file(const char *source, const char *dest, int ofd, mode_t mode) full_fname(source)); } +#ifdef PREALLOCATE_NEEDS_TRUNCATE + /* Source file might have shrunk since we fstatted it. + * Cut off any extra preallocated zeros from dest file. */ + if (offset < preallocated_len && do_ftruncate(ofd, offset) < 0) { + /* If we fail to truncate, the dest file may be wrong, so we + * must trigger the "partial transfer" error. */ + rsyserr(FERROR_XFER, errno, "ftruncate %s", full_fname(dest)); + } +#endif + if (close(ofd) < 0) { int save_errno = errno; rsyserr(FERROR_XFER, errno, "close failed on %s",