--- embedaddon/rsync/rsync.c 2016/11/01 09:54:32 1.1.1.3 +++ embedaddon/rsync/rsync.c 2021/03/17 00:32:36 1.1.1.4 @@ -3,7 +3,7 @@ * * Copyright (C) 1996 Andrew Tridgell * Copyright (C) 1996 Paul Mackerras - * Copyright (C) 2003-2015 Wayne Davison + * Copyright (C) 2003-2020 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 @@ -31,30 +31,45 @@ extern int dry_run; extern int preserve_acls; extern int preserve_xattrs; extern int preserve_perms; +extern int preserve_fileflags; extern int preserve_executability; extern int preserve_times; +extern int copy_devices; extern int am_root; extern int am_server; extern int am_daemon; extern int am_sender; extern int am_receiver; extern int am_generator; +extern int am_dbadmin; extern int am_starting_up; extern int allow_8bit_chars; extern int protocol_version; extern int got_kill_signal; +extern int called_from_signal_handler; extern int inc_recurse; extern int inplace; extern int flist_eof; extern int file_old_total; extern int keep_dirlinks; extern int make_backups; +extern char *link_by_hash_dir; +extern int sanitize_paths; extern struct file_list *cur_flist, *first_flist, *dir_flist; extern struct chmod_mode_struct *daemon_chmod_modes; #ifdef ICONV_OPTION extern char *iconv_opt; #endif +#define UPDATED_OWNER (1<<0) +#define UPDATED_GROUP (1<<1) +#define UPDATED_MTIME (1<<2) +#define UPDATED_ATIME (1<<3) +#define UPDATED_ACLS (1<<4) +#define UPDATED_MODE (1<<5) + +#define UPDATED_TIMES (UPDATED_MTIME|UPDATED_ATIME) + #ifdef ICONV_CONST iconv_t ic_chck = (iconv_t)-1; # ifdef ICONV_OPTION @@ -307,8 +322,7 @@ void send_protected_args(int fd, char *args[]) #endif } -int read_ndx_and_attrs(int f_in, int f_out, int *iflag_ptr, uchar *type_ptr, - char *buf, int *len_ptr) +int read_ndx_and_attrs(int f_in, int f_out, int *iflag_ptr, uchar *type_ptr, char *buf, int *len_ptr) { int len, iflags = 0; struct file_list *flist; @@ -396,6 +410,11 @@ int read_ndx_and_attrs(int f_in, int f_out, int *iflag if (iflags & ITEM_XNAME_FOLLOWS) { if ((len = read_vstring(f_in, buf, MAXPATHLEN)) < 0) exit_cleanup(RERR_PROTOCOL); + + if (sanitize_paths) { + sanitize_path(buf, buf, "", 0, SP_DEFAULT); + len = strlen(buf); + } } else { *buf = '\0'; len = -1; @@ -404,7 +423,8 @@ int read_ndx_and_attrs(int f_in, int f_out, int *iflag if (iflags & ITEM_TRANSFER) { int i = ndx - cur_flist->ndx_start; - if (i < 0 || !S_ISREG(cur_flist->files[i]->mode)) { + struct file_struct *file = cur_flist->files[i]; + if (i < 0 || !(S_ISREG(file->mode) || (copy_devices && IS_DEVICE(file->mode)))) { rprintf(FERROR, "received request to transfer non-regular file: %d [%s]\n", ndx, who_am_i()); @@ -452,6 +472,54 @@ mode_t dest_mode(mode_t flist_mode, mode_t stat_mode, return new_mode; } +#if defined SUPPORT_FILEFLAGS || defined SUPPORT_FORCE_CHANGE +/* Set a file's st_flags. */ +static int set_fileflags(const char *fname, uint32 fileflags) +{ + if (do_chflags(fname, fileflags) != 0) { + rsyserr(FERROR_XFER, errno, + "failed to set file flags on %s", + full_fname(fname)); + return 0; + } + + return 1; +} + +/* Remove immutable flags from an object, so it can be altered/removed. */ +int make_mutable(const char *fname, mode_t mode, uint32 fileflags, uint32 iflags) +{ + if (S_ISLNK(mode) || !(fileflags & iflags)) + return 0; + if (!set_fileflags(fname, fileflags & ~iflags)) + return -1; + return 1; +} + +/* Undo a prior make_mutable() call that returned a 1. */ +int undo_make_mutable(const char *fname, uint32 fileflags) +{ + if (!set_fileflags(fname, fileflags)) + return -1; + return 1; +} +#endif + +static int same_mtime(struct file_struct *file, STRUCT_STAT *st, int extra_accuracy) +{ +#ifdef ST_MTIME_NSEC + uint32 f1_nsec = F_MOD_NSEC_or_0(file); + uint32 f2_nsec = (uint32)st->ST_MTIME_NSEC; +#else + uint32 f1_nsec = 0, f2_nsec = 0; +#endif + + if (extra_accuracy) /* ignore modify_window when setting the time after a transfer or checksum check */ + return file->modtime == st->st_mtime && f1_nsec == f2_nsec; + + return same_time(file->modtime, f1_nsec, st->st_mtime , f2_nsec); +} + int set_file_attrs(const char *fname, struct file_struct *file, stat_x *sxp, const char *fnamecmp, int flags) { @@ -489,9 +557,11 @@ int set_file_attrs(const char *fname, struct file_stru get_acl(fname, sxp); #endif - change_uid = am_root && uid_ndx && sxp->st.st_uid != (uid_t)F_OWNER(file); + change_uid = am_root && uid_ndx && sxp->st.st_uid != (uid_t)F_OWNER(file) + && !(omit_dir_changes && S_ISDIR(sxp->st.st_mode)); change_gid = gid_ndx && !(file->flags & FLAG_SKIP_GROUP) - && sxp->st.st_gid != (gid_t)F_GROUP(file); + && sxp->st.st_gid != (gid_t)F_GROUP(file) + && !(omit_dir_changes && S_ISDIR(sxp->st.st_mode)); #ifndef CAN_CHOWN_SYMLINK if (S_ISLNK(sxp->st.st_mode)) { ; @@ -513,12 +583,12 @@ int set_file_attrs(const char *fname, struct file_stru if (am_root >= 0) { uid_t uid = change_uid ? (uid_t)F_OWNER(file) : sxp->st.st_uid; gid_t gid = change_gid ? (gid_t)F_GROUP(file) : sxp->st.st_gid; - if (do_lchown(fname, uid, gid) != 0) { + if (do_lchown(fname, uid, gid, sxp->st.st_mode, ST_FLAGS(sxp->st)) != 0) { /* We shouldn't have attempted to change uid * or gid unless have the privilege. */ rsyserr(FERROR_XFER, errno, "%s %s failed", - change_uid ? "chown" : "chgrp", - full_fname(fname)); + change_uid ? "chown" : "chgrp", + full_fname(fname)); goto cleanup; } if (uid == (uid_t)-1 && sxp->st.st_uid != (uid_t)-1) @@ -533,48 +603,76 @@ int set_file_attrs(const char *fname, struct file_stru keep_dirlinks && S_ISDIR(sxp->st.st_mode)); } } - updated = 1; + if (change_uid) + updated |= UPDATED_OWNER; + if (change_gid) + updated |= UPDATED_GROUP; } #ifdef SUPPORT_XATTRS if (am_root < 0) set_stat_xattr(fname, file, new_mode); - if (preserve_xattrs && fnamecmp) + if (preserve_xattrs && fnamecmp) { + uint32 tmpflags = sxp->st.st_flags; + sxp->st.st_flags = F_FFLAGS(file); /* set_xattr() needs to check UF_COMPRESSED */ set_xattr(fname, file, fnamecmp, sxp); + sxp->st.st_flags = tmpflags; + if (S_ISDIR(sxp->st.st_mode)) + link_stat(fname, &sx2.st, 0); + } #endif if (!preserve_times || (!(preserve_times & PRESERVE_DIR_TIMES) && S_ISDIR(sxp->st.st_mode)) || (!(preserve_times & PRESERVE_LINK_TIMES) && S_ISLNK(sxp->st.st_mode))) - flags |= ATTRS_SKIP_MTIME; + flags |= ATTRS_SKIP_MTIME | ATTRS_SKIP_ATIME; + else if (sxp != &sx2) + memcpy(&sx2.st, &sxp->st, sizeof (sx2.st)); + if (!atimes_ndx || S_ISDIR(sxp->st.st_mode)) + flags |= ATTRS_SKIP_ATIME; + /* Don't set the creation date on the root folder of an HFS+ volume. */ + if (sxp->st.st_ino == 2 && S_ISDIR(sxp->st.st_mode)) + flags |= ATTRS_SKIP_CRTIME; if (!(flags & ATTRS_SKIP_MTIME) - && (sxp->st.st_mtime != file->modtime +#ifdef SUPPORT_HFS_COMPRESSION + && !(sxp->st.st_flags & UF_COMPRESSED) /* setting this alters mtime, so defer to after set_fileflags */ +#endif + && !same_mtime(file, &sxp->st, flags & ATTRS_ACCURATE_TIME)) { + sx2.st.st_mtime = file->modtime; #ifdef ST_MTIME_NSEC - || (NSEC_BUMP(file) && (uint32)sxp->st.ST_MTIME_NSEC != F_MOD_NSEC(file)) + sx2.st.ST_MTIME_NSEC = F_MOD_NSEC_or_0(file); #endif - )) { - int ret = set_modtime(fname, file->modtime, F_MOD_NSEC(file), sxp->st.st_mode); + updated |= UPDATED_MTIME; + } + if (!(flags & ATTRS_SKIP_ATIME)) { + time_t file_atime = F_ATIME(file); + if (flags & ATTRS_ACCURATE_TIME || !same_time(sxp->st.st_atime, 0, file_atime, 0)) { + sx2.st.st_atime = file_atime; +#ifdef ST_ATIME_NSEC + sx2.st.ST_ATIME_NSEC = 0; +#endif + updated |= UPDATED_ATIME; + } + } + if (updated & UPDATED_TIMES) { + int ret = set_times(fname, &sx2.st); if (ret < 0) { rsyserr(FERROR_XFER, errno, "failed to set times on %s", full_fname(fname)); goto cleanup; } - if (ret == 0) /* ret == 1 if symlink could not be set */ - updated = 1; - else + if (ret > 0) { /* ret == 1 if symlink could not be set */ + updated &= ~UPDATED_TIMES; file->flags |= FLAG_TIME_FAILED; - } - -#ifdef HAVE_CHMOD - if (!BITS_EQUAL(sxp->st.st_mode, new_mode, CHMOD_BITS)) { - int ret = am_root < 0 ? 0 : do_chmod(fname, new_mode); - if (ret < 0) { - rsyserr(FERROR_XFER, errno, - "failed to set permissions on %s", - full_fname(fname)); - goto cleanup; } - if (ret == 0) /* ret == 1 if symlink could not be set */ + } +#ifdef SUPPORT_CRTIMES + if (crtimes_ndx && !(flags & ATTRS_SKIP_CRTIME)) { + time_t file_crtime = F_CRTIME(file); + if (sxp->crtime == 0) + sxp->crtime = get_create_time(fname); + if (!same_time(sxp->crtime, 0L, file_crtime, 0L) + && set_create_time(fname, file_crtime) == 0) updated = 1; } #endif @@ -588,10 +686,47 @@ int set_file_attrs(const char *fname, struct file_stru * need to chmod(). */ if (preserve_acls && !S_ISLNK(new_mode)) { if (set_acl(fname, file, sxp, new_mode) > 0) - updated = 1; + updated |= UPDATED_ACLS; } #endif +#ifdef HAVE_CHMOD + if (!BITS_EQUAL(sxp->st.st_mode, new_mode, CHMOD_BITS)) { + int ret = am_root < 0 ? 0 : do_chmod(fname, new_mode, ST_FLAGS(sxp->st)); + if (ret < 0) { + rsyserr(FERROR_XFER, errno, + "failed to set permissions on %s", + full_fname(fname)); + goto cleanup; + } + if (ret == 0) /* ret == 1 if symlink could not be set */ + updated |= UPDATED_MODE; + } +#endif + +#ifdef SUPPORT_FILEFLAGS + if (preserve_fileflags && !S_ISLNK(sxp->st.st_mode) + && sxp->st.st_flags != F_FFLAGS(file)) { + uint32 fileflags = F_FFLAGS(file); + if (flags & ATTRS_DELAY_IMMUTABLE) + fileflags &= ~ALL_IMMUTABLE; + if (sxp->st.st_flags != fileflags + && !set_fileflags(fname, fileflags)) + goto cleanup; + updated = 1; +#ifdef SUPPORT_HFS_COMPRESSION + int ret = set_modtime(fname, file->modtime, F_MOD_NSEC(file), new_mode, fileflags); + if (ret < 0) { + rsyserr(FERROR_XFER, errno, "failed to set times on %s", + full_fname(fname)); + goto cleanup; + } + if (ret != 0) + file->flags |= FLAG_TIME_FAILED; +#endif + } +#endif + if (INFO_GTE(NAME, 2) && flags & ATTRS_REPORT) { if (updated) rprintf(FCLIENT, "%s\n", fname); @@ -607,6 +742,8 @@ int set_file_attrs(const char *fname, struct file_stru /* This is only called for SIGINT, SIGHUP, and SIGTERM. */ void sig_int(int sig_num) { + called_from_signal_handler = 1; + /* KLUGE: if the user hits Ctrl-C while ssh is prompting * for a password, then our cleanup's sending of a SIGUSR1 * signal to all our children may kill ssh before it has a @@ -630,6 +767,7 @@ void sig_int(int sig_num) * we didn't already set the flag. */ if (!got_kill_signal && (am_server || am_receiver)) { got_kill_signal = sig_num; + called_from_signal_handler = 0; return; } @@ -640,7 +778,7 @@ void sig_int(int sig_num) * attributes (e.g. permissions, ownership, etc.). If the robust_rename() * call is forced to copy the temp file and partialptr is both non-NULL and * not an absolute path, we stage the file into the partial-dir and then - * rename it into place. This returns 1 on succcess or 0 on failure. */ + * rename it into place. This returns 1 on success or 0 on failure. */ int finish_transfer(const char *fname, const char *fnametmp, const char *fnamecmp, const char *partialptr, struct file_struct *file, int ok_to_set_time, @@ -656,17 +794,18 @@ int finish_transfer(const char *fname, const char *fna goto do_set_file_attrs; } - if (make_backups > 0 && overwriting_basis) { + if (make_backups > 1 && overwriting_basis) { int ok = make_backup(fname, False); if (!ok) - return 1; + exit_cleanup(RERR_FILEIO); if (ok == 1 && fnamecmp == fname) fnamecmp = get_backup_name(fname); } /* Change permissions before putting the file into place. */ set_file_attrs(fnametmp, file, NULL, fnamecmp, - ok_to_set_time ? 0 : ATTRS_SKIP_MTIME); + ATTRS_DELAY_IMMUTABLE + | (ok_to_set_time ? ATTRS_ACCURATE_TIME : ATTRS_SKIP_MTIME | ATTRS_SKIP_ATIME | ATTRS_SKIP_CRTIME)); /* move tmp file over real file */ if (DEBUG_GTE(RECV, 1)) @@ -683,6 +822,10 @@ int finish_transfer(const char *fname, const char *fna } if (ret == 0) { /* The file was moved into place (not copied), so it's done. */ +#ifdef SUPPORT_FILEFLAGS + if (preserve_fileflags && F_FFLAGS(file) & ALL_IMMUTABLE) + set_fileflags(fname, F_FFLAGS(file)); +#endif return 1; } /* The file was copied, so tweak the perms of the copied file. If it @@ -691,7 +834,7 @@ int finish_transfer(const char *fname, const char *fna do_set_file_attrs: set_file_attrs(fnametmp, file, NULL, fnamecmp, - ok_to_set_time ? 0 : ATTRS_SKIP_MTIME); + ok_to_set_time ? ATTRS_ACCURATE_TIME : ATTRS_SKIP_MTIME | ATTRS_SKIP_ATIME | ATTRS_SKIP_CRTIME); if (temp_copy_name) { if (do_rename(fnametmp, fname) < 0) { @@ -742,6 +885,8 @@ struct file_list *flist_for_ndx(int ndx, const char *f const char *who_am_i(void) { + if (am_dbadmin) + return "rsyncdb"; if (am_starting_up) return am_server ? "server" : "client"; return am_sender ? "sender"