* Copyright (C) 1996-2000 Andrew Tridgell
* Copyright (C) 1996 Paul Mackerras
* Copyright (C) 2002 Martin Pool <mbp@samba.org>
- * Copyright (C) 2003-2013 Wayne Davison
+ * Copyright (C) 2003-2018 Wayne Davison
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
extern int human_readable;
extern int ignore_existing;
extern int ignore_non_existing;
+extern int want_xattr_optim;
extern int inplace;
extern int append_mode;
extern int make_backups;
extern int file_total;
extern int fuzzy_basis;
extern int always_checksum;
-extern int checksum_len;
+extern int flist_csum_len;
extern char *partial_dir;
extern int compare_dest;
extern int copy_dest;
extern filter_rule_list filter_list, daemon_filter_list;
int maybe_ATTRS_REPORT = 0;
+int maybe_ATTRS_SET_NANO = 0;
static dev_t dev_zero;
static int deldelay_size = 0, deldelay_cnt = 0;
for (j = 0; j < cur_flist->used; j++) {
struct file_struct *file = cur_flist->sorted[j];
+ if (!F_IS_ACTIVE(file))
+ continue;
+
f_name(file, fbuf);
if (!(file->flags & FLAG_CONTENT_DIR)) {
rprintf(FINFO, " \r");
}
-static inline int time_differs(struct file_struct *file, stat_x *sxp)
+static inline int time_diff(STRUCT_STAT *stp, struct file_struct *file)
{
- return cmp_time(sxp->st.st_mtime, file->modtime);
+#ifdef ST_MTIME_NSEC
+ return cmp_time(stp->st_mtime, stp->ST_MTIME_NSEC, file->modtime, F_MOD_NSEC(file));
+#else
+ return cmp_time(stp->st_mtime, 0L, file->modtime, 0L);
+#endif
}
static inline int perms_differ(struct file_struct *file, stat_x *sxp)
{
if (S_ISLNK(file->mode)) {
#ifdef CAN_SET_SYMLINK_TIMES
- if (preserve_times & PRESERVE_LINK_TIMES && time_differs(file, sxp))
+ if (preserve_times & PRESERVE_LINK_TIMES && time_diff(&sxp->st, file))
return 0;
#endif
#ifdef CAN_CHMOD_SYMLINK
return 0;
#endif
} else {
- if (preserve_times && time_differs(file, sxp))
+ if (preserve_times && time_diff(&sxp->st, file))
return 0;
if (perms_differ(file, sxp))
return 0;
if (iflags & ITEM_LOCAL_CHANGE)
iflags |= symlink_timeset_failed_flags;
} else if (keep_time
- ? cmp_time(file->modtime, sxp->st.st_mtime) != 0
+ ? time_diff(&sxp->st, file)
: iflags & (ITEM_TRANSFER|ITEM_LOCAL_CHANGE) && !(iflags & ITEM_MATCHED)
&& (!(iflags & ITEM_XNAME_FOLLOWS) || *xname))
iflags |= ITEM_REPORT_TIME;
if (preserve_xattrs && do_xfers
&& iflags & (ITEM_REPORT_XATTR|ITEM_TRANSFER)) {
int fd = iflags & ITEM_REPORT_XATTR
- && (protocol_version < 31 || !BITS_SET(iflags, ITEM_XNAME_FOLLOWS|ITEM_LOCAL_CHANGE))
+ && !(want_xattr_optim && BITS_SET(iflags, ITEM_XNAME_FOLLOWS|ITEM_LOCAL_CHANGE))
? sock_f_out : -1;
send_xattr_request(NULL, file, fd);
}
of the file time to determine whether to sync */
if (always_checksum > 0 && S_ISREG(st->st_mode)) {
char sum[MAX_DIGEST_LEN];
- file_checksum(fn, sum, st->st_size);
- return memcmp(sum, F_SUM(file), checksum_len) == 0;
+ file_checksum(fn, st, sum);
+ return memcmp(sum, F_SUM(file), flist_csum_len) == 0;
}
if (size_only > 0)
if (ignore_times)
return 0;
- return cmp_time(st->st_mtime, file->modtime) == 0;
+ return time_diff(st, file) == 0;
}
for (j = 0; j < dirlist->used; j++) {
struct file_struct *fp = dirlist->files[j];
+ if (!F_IS_ACTIVE(fp))
+ continue;
+
if (!S_ISREG(fp->mode) || !F_LENGTH(fp) || fp->flags & FLAG_FILE_SENT)
continue;
- if (F_LENGTH(fp) == F_LENGTH(file) && cmp_time(fp->modtime, file->modtime) == 0) {
+ if (F_LENGTH(fp) == F_LENGTH(file) && cmp_time(fp->modtime, 0L, file->modtime, 0L) == 0) {
if (DEBUG_GTE(FUZZY, 2))
rprintf(FINFO, "fuzzy size/modtime match for %s\n", f_name(fp, NULL));
*fnamecmp_type_ptr = FNAMECMP_FUZZY + i;
int len, suf_len;
uint32 dist;
+ if (!F_IS_ACTIVE(fp))
+ continue;
+
if (!S_ISREG(fp->mode) || !F_LENGTH(fp) || fp->flags & FLAG_FILE_SENT)
continue;
} while (basis_dir[++j] != NULL);
if (!match_level)
- return -1;
+ goto got_nothing_for_ya;
if (j != best_match) {
j = best_match;
pathjoin(cmpbuf, MAXPATHLEN, basis_dir[j], fname);
if (link_stat(cmpbuf, &sxp->st, 0) < 0)
- return -1;
+ goto got_nothing_for_ya;
}
if (match_level == 3 && !copy_dest) {
if (find_exact_for_existing) {
if (link_dest && real_st.st_dev == sxp->st.st_dev && real_st.st_ino == sxp->st.st_ino)
return -1;
- if (do_unlink(fname) < 0 && errno != ENOENT) {
- sxp->st = real_st;
- return -1;
- }
+ if (do_unlink(fname) < 0 && errno != ENOENT)
+ goto got_nothing_for_ya;
}
#ifdef SUPPORT_HARD_LINKS
if (link_dest) {
return -2;
}
- if (find_exact_for_existing) {
- sxp->st = real_st;
- return -1;
- }
+ if (find_exact_for_existing)
+ goto got_nothing_for_ya;
if (match_level >= 2) {
#ifdef SUPPORT_HARD_LINKS
#endif
if (!dry_run && copy_altdest_file(cmpbuf, fname, file) < 0) {
if (find_exact_for_existing) /* Can get here via hard-link failure */
- sxp->st = real_st;
+ goto got_nothing_for_ya;
return -1;
}
if (itemizing)
}
return FNAMECMP_BASIS_DIR_LOW + j;
+
+got_nothing_for_ya:
+ sxp->st = real_st;
+ return -1;
}
/* This is only called for non-regular files. We return -2 if we've finished
int itemizing, enum logcode code, int f_out)
{
static const char *parent_dirname = "";
+ static struct file_struct *prior_dir_file = NULL;
/* Missing dir not created due to --dry-run; will still be scanned. */
static struct file_struct *dry_missing_dir = NULL;
/* Missing dir whose contents are skipped altogether due to
return;
}
+ maybe_ATTRS_SET_NANO = always_checksum ? ATTRS_SET_NANO : 0;
+
if (skip_dir) {
if (is_below(file, skip_dir)) {
if (is_dir)
const char *dn = file->dirname ? file->dirname : ".";
dry_missing_dir = NULL;
if (parent_dirname != dn && strcmp(parent_dirname, dn) != 0) {
+ /* Each parent dir must be in the file list or the flist data is bad.
+ * Optimization: most of the time the parent dir will be the last dir
+ * this function was asked to process in the file list. */
+ if (!inc_recurse
+ && (*dn != '.' || dn[1]) /* Avoid an issue with --relative and the "." dir. */
+ && (!prior_dir_file || strcmp(dn, f_name(prior_dir_file, NULL)) != 0)
+ && flist_find_name(cur_flist, dn, 1) < 0) {
+ rprintf(FERROR,
+ "ABORTING due to invalid path from sender: %s/%s\n",
+ dn, file->basename);
+ exit_cleanup(RERR_PROTOCOL);
+ }
if (relative_paths && !implied_dirs
&& do_stat(dn, &sx.st) < 0) {
if (dry_run)
} else
added_perms = 0;
if (is_dir < 0) {
+ if (!(preserve_times & PRESERVE_DIR_TIMES))
+ return;
/* In inc_recurse mode we want to make sure any missing
* directories get created while we're still processing
* the parent dir (which allows us to touch the parent
else
change_local_filter_dir(fname, strlen(fname), F_DEPTH(file));
}
+ prior_dir_file = file;
goto cleanup;
}
set_file_attrs(fname, file, &sx, NULL, maybe_ATTRS_REPORT);
if (itemizing)
itemize(fname, file, ndx, 0, &sx, 0, 0, NULL);
-#if defined SUPPORT_HARD_LINKS && defined CAN_HARDLINK_SYMLINK
+#ifdef SUPPORT_HARD_LINKS
if (preserve_hard_links && F_IS_HLINKED(file))
finish_hard_link(file, fname, ndx, &sx.st, itemizing, code, -1);
#endif
fnamecmp = fnamecmpbuf;
}
}
- if (atomic_create(file, fname, sl, MAKEDEV(0, 0), &sx, statret == 0 ? DEL_FOR_SYMLINK : 0)) {
+ if (atomic_create(file, fname, sl, NULL, MAKEDEV(0, 0), &sx, statret == 0 ? DEL_FOR_SYMLINK : 0)) {
set_file_attrs(fname, file, NULL, NULL, 0);
if (itemizing) {
if (statret == 0 && !S_ISLNK(sx.st.st_mode))
fname, (int)file->mode,
(long)major(rdev), (long)minor(rdev));
}
- if (atomic_create(file, fname, NULL, rdev, &sx, del_for_flag)) {
+ if (atomic_create(file, fname, NULL, NULL, rdev, &sx, del_for_flag)) {
set_file_attrs(fname, file, NULL, NULL, 0);
if (itemizing) {
itemize(fnamecmp, file, ndx, statret, &sx,
goto cleanup;
}
- if (update_only > 0 && statret == 0
- && cmp_time(sx.st.st_mtime, file->modtime) > 0) {
+ if (update_only > 0 && statret == 0 && time_diff(&sx.st, file) > 0) {
if (INFO_GTE(SKIP, 1))
rprintf(FINFO, "%s is newer\n", fname);
#ifdef SUPPORT_HARD_LINKS
if (fnamecmp_type <= FNAMECMP_BASIS_DIR_HIGH)
;
- else if (fnamecmp_type == FNAMECMP_FUZZY)
+ else if (fnamecmp_type >= FNAMECMP_FUZZY)
;
else if (unchanged_file(fnamecmp, file, &sx.st)) {
if (partialptr) {
do_unlink(partialptr);
handle_partial_dir(partialptr, PDIR_DELETE);
}
- set_file_attrs(fname, file, &sx, NULL, maybe_ATTRS_REPORT);
+ set_file_attrs(fname, file, &sx, NULL, maybe_ATTRS_REPORT | maybe_ATTRS_SET_NANO);
if (itemizing)
itemize(fnamecmp, file, ndx, statret, &sx, 0, 0, NULL);
#ifdef SUPPORT_HARD_LINKS
}
/* If we are replacing an existing hard link, symlink, device, or special file,
- * create a temp-name item and rename it into place. Only a symlink or hard
- * link puts a non-NULL value into the lnk arg. Only a device puts a non-0
- * value into the rdev arg. Specify 0 for the del_for_flag if there is not a
- * file to replace. This returns 1 on success and 0 on failure. */
-int atomic_create(struct file_struct *file, char *fname, const char *lnk,
+ * create a temp-name item and rename it into place. A symlimk specifies slnk,
+ * a hard link specifies hlnk, otherwise we create a device based on rdev.
+ * Specify 0 for the del_for_flag if there is not a file to replace. This
+ * returns 1 on success and 0 on failure. */
+int atomic_create(struct file_struct *file, char *fname, const char *slnk, const char *hlnk,
dev_t rdev, stat_x *sxp, int del_for_flag)
{
char tmpname[MAXPATHLEN];
create_name = skip_atomic ? fname : tmpname;
- if (lnk) {
+ if (slnk) {
#ifdef SUPPORT_LINKS
- if (S_ISLNK(file->mode)
-#ifdef SUPPORT_HARD_LINKS /* The first symlink in a hard-linked cluster is always created. */
- && (!F_IS_HLINKED(file) || file->flags & FLAG_HLINK_FIRST)
-#endif
- ) {
- if (do_symlink(lnk, create_name) < 0) {
- rsyserr(FERROR_XFER, errno, "symlink %s -> \"%s\" failed",
- full_fname(create_name), lnk);
- return 0;
- }
- } else
+ if (do_symlink(slnk, create_name) < 0) {
+ rsyserr(FERROR_XFER, errno, "symlink %s -> \"%s\" failed",
+ full_fname(create_name), slnk);
+ return 0;
+ }
+#else
+ return 0;
#endif
+ } else if (hlnk) {
#ifdef SUPPORT_HARD_LINKS
- if (!hard_link_one(file, create_name, lnk, 0))
+ if (!hard_link_one(file, create_name, hlnk, 0))
return 0;
+#else
+ return 0;
#endif
} else {
if (do_mknod(create_name, file->mode, rdev) < 0) {
* transfer and/or re-set any tweaked modified-time values. */
for (i = start; i <= end; i++, counter++) {
file = flist->files[i];
+ if (!F_IS_ACTIVE(file))
+ continue;
if (!S_ISDIR(file->mode)
|| (!implied_dirs && file->flags & FLAG_IMPLIED_DIR))
continue;
}
/* Be sure not to retouch permissions with --fake-super. */
fix_dir_perms = !am_root && !(file->mode & S_IWUSR);
- if (!F_IS_ACTIVE(file) || file->flags & FLAG_MISSING_DIR
- || !(need_retouch_dir_times || fix_dir_perms))
+ if (file->flags & FLAG_MISSING_DIR || !(need_retouch_dir_times || fix_dir_perms))
continue;
fname = f_name(file, NULL);
if (fix_dir_perms)
do_chmod(fname, file->mode);
if (need_retouch_dir_times) {
STRUCT_STAT st;
- if (link_stat(fname, &st, 0) == 0
- && cmp_time(st.st_mtime, file->modtime) != 0)
+ if (link_stat(fname, &st, 0) == 0 && time_diff(&st, file))
set_modtime(fname, file->modtime, F_MOD_NSEC(file), file->mode);
}
if (counter >= loopchk_limit) {