X-Git-Url: https://mattmccutchen.net/rsync/rsync.git/blobdiff_plain/3696674bc62b0c1250027dbeedafdd7ebafdcf8b..28b519c93b6db30b6520d46f8cd65160213fddd2:/util.c diff --git a/util.c b/util.c index bad2faed..3f611d15 100644 --- a/util.c +++ b/util.c @@ -25,16 +25,16 @@ #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 mode_t orig_umask; extern char *partial_dir; -extern struct filter_list_struct daemon_filter_list; +extern filter_rule_list daemon_filter_list; int sanitize_paths = 0; @@ -123,12 +123,11 @@ NORETURN void overflow_exit(const char *str) exit_cleanup(RERR_MALLOC); } -int set_modtime(const char *fname, time_t modtime, mode_t mode) +/* 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) { -#if !defined HAVE_LUTIMES || !defined HAVE_UTIMES - 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", @@ -136,52 +135,49 @@ int set_modtime(const char *fname, time_t modtime, mode_t mode) asctime(localtime(&modtime))); } - if (dry_run) - return 0; + switch (switch_step) { +#ifdef HAVE_UTIMENSAT +#include "case_N.h" + if (do_utimensat(fname, modtime, mod_nsec) == 0) + break; + if (errno != ENOSYS) + return -1; + switch_step++; + /* FALLTHROUGH */ +#endif - { -#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)) { - if (lutimes(fname, t) < 0) - return errno == ENOSYS ? 1 : -1; - return 0; +#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; } -# endif - return utimes(fname, t); -#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); + /* 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 - } -} -/* This creates a new directory with default permissions. Since there - * might be some directory-default permissions affecting this, we can't - * force the permissions directly using the original umask and mkdir(). */ -int mkdir_defmode(char *fname) -{ - int ret; - - umask(orig_umask); - ret = do_mkdir(fname, ACCESSPERMS); - umask(0); + return -1; + } - return ret; + return 0; } /* Create any necessary directories in fname. Any missing directories are @@ -208,8 +204,6 @@ int make_path(char *fname, int flags) } else end = fname + strlen(fname); - umask(orig_umask); /* NOTE: don't return before setting this back to 0! */ - /* Try to find an existing dir, starting from the deepest dir. */ for (p = end; ; ) { if (do_mkdir(fname, ACCESSPERMS) == 0) { @@ -250,8 +244,6 @@ int make_path(char *fname, int flags) ret++; } - umask(0); - if (flags & MKP_DROP_NAME) *end = '/'; @@ -324,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; @@ -340,6 +335,11 @@ int copy_file(const char *source, const char *dest, int ofd, mode_t mode) return -1; } +#ifdef SUPPORT_XATTRS + if (preserve_xattrs) + mode |= S_IWUSR; +#endif + mode &= INITACCESSPERMS; if ((ofd = do_open(dest, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, mode)) < 0) { int save_errno = errno; rsyserr(FERROR_XFER, save_errno, "open %s", full_fname(dest)); @@ -349,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; @@ -358,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) { @@ -374,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", @@ -534,30 +566,6 @@ void kill_all(int sig) } } -/** Turn a user name into a uid */ -int name_to_uid(const char *name, uid_t *uid_p) -{ - struct passwd *pass; - if (!name || !*name) - return 0; - if (!(pass = getpwnam(name))) - return 0; - *uid_p = pass->pw_uid; - return 1; -} - -/** Turn a group name into a gid */ -int name_to_gid(const char *name, gid_t *gid_p) -{ - struct group *grp; - if (!name || !*name) - return 0; - if (!(grp = getgrnam(name))) - return 0; - *gid_p = grp->gr_gid; - return 1; -} - /** Lock a byte range in a open file */ int lock_range(int fd, int offset, int len) { @@ -1451,11 +1459,11 @@ const char *find_filename_suffix(const char *fn, int fn_len, int *len_ptr) #define UNIT (1 << 16) -uint32 fuzzy_distance(const char *s1, int len1, const char *s2, int len2) +uint32 fuzzy_distance(const char *s1, unsigned len1, const char *s2, unsigned len2) { uint32 a[MAXPATHLEN], diag, above, left, diag_inc, above_inc, left_inc; int32 cost; - int i1, i2; + unsigned i1, i2; if (!len1 || !len2) { if (!len1) {