#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 filter_rule_list daemon_filter_list;
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
} else {
rprintf(FCLIENT, "%s ", *cmd);
}
+ cnt++;
}
- rprintf(FCLIENT, "\n");
+ rprintf(FCLIENT, " (%d args)\n", cnt);
}
NORETURN void out_of_memory(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",
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);
-#else
-#error No file-time-modification routine found!
+#include "case_N.h"
+ if (do_utimensat(fname, modtime, mod_nsec) == 0)
+ break;
+ if (errno != ENOSYS)
+ return -1;
+ switch_step++;
+ /* FALLTHROUGH */
#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;
+#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
- umask(orig_umask);
- ret = do_mkdir(fname, ACCESSPERMS);
- umask(0);
+#include "case_N.h"
+ switch_step++;
+ if (preserve_times & PRESERVE_LINK_TIMES) {
+ preserve_times &= ~PRESERVE_LINK_TIMES;
+ if (S_ISLNK(mode))
+ return 1;
+ }
+ /* FALLTHROUGH */
- return ret;
+#include "case_N.h"
+#ifdef HAVE_UTIMES
+ if (do_utimes(fname, modtime, mod_nsec) == 0)
+ break;
+#else
+ if (do_utime(fname, modtime, mod_nsec) == 0)
+ break;
+#endif
+
+ return -1;
+ }
+
+ return 0;
}
/* Create any necessary directories in fname. Any missing directories are
} 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) {
ret++;
}
- umask(0);
-
if (flags & MKP_DROP_NAME)
*end = '/';
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;
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));
}
}
+#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;
errno = save_errno;
return -1;
}
+#ifdef PREALLOCATE_NEEDS_TRUNCATE
+ offset += len;
+#endif
}
if (len < 0) {
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",
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';