Man page: Move the description of --info=progress2 to a better place.
[rsync/rsync.git] / util.c
diff --git a/util.c b/util.c
index 02085d4..abf0cd4 100644 (file)
--- a/util.c
+++ b/util.c
 #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;
@@ -93,6 +94,7 @@ int fd_pair(int fd[2])
 
 void print_child_argv(const char *prefix, char **cmd)
 {
+       int cnt = 0;
        rprintf(FCLIENT, "%s ", prefix);
        for (; *cmd; cmd++) {
                /* Look for characters that ought to be quoted.  This
@@ -106,8 +108,9 @@ void print_child_argv(const char *prefix, char **cmd)
                } else {
                        rprintf(FCLIENT, "%s ", *cmd);
                }
+               cnt++;
        }
-       rprintf(FCLIENT, "\n");
+       rprintf(FCLIENT, " (%d args)\n", cnt);
 }
 
 NORETURN void out_of_memory(const char *str)
@@ -122,12 +125,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 +137,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 +318,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;
@@ -329,6 +337,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));
@@ -338,6 +351,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;
@@ -347,6 +379,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) {
@@ -363,6 +398,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",
@@ -1019,8 +1064,9 @@ int change_dir(const char *dir, int set_path_only)
                        errno = ENAMETOOLONG;
                        return 0;
                }
-               curr_dir[curr_dir_len] = '/';
-               memcpy(curr_dir + curr_dir_len + 1, dir, len + 1);
+               if (!(curr_dir_len && curr_dir[curr_dir_len-1] == '/'))
+                       curr_dir[curr_dir_len++] = '/';
+               memcpy(curr_dir + curr_dir_len, dir, len + 1);
 
                if (!set_path_only && chdir(curr_dir)) {
                        curr_dir[curr_dir_len] = '\0';