version 1.1.1.3, 2016/11/01 09:54:32
|
version 1.1.1.4, 2021/03/17 00:32:36
|
Line 3
|
Line 3
|
* |
* |
* Copyright (C) 1996 Andrew Tridgell |
* Copyright (C) 1996 Andrew Tridgell |
* Copyright (C) 1996 Paul Mackerras |
* 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 |
* 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 |
* it under the terms of the GNU General Public License as published by |
Line 31 extern int dry_run;
|
Line 31 extern int dry_run;
|
extern int preserve_acls; |
extern int preserve_acls; |
extern int preserve_xattrs; |
extern int preserve_xattrs; |
extern int preserve_perms; |
extern int preserve_perms; |
|
extern int preserve_fileflags; |
extern int preserve_executability; |
extern int preserve_executability; |
extern int preserve_times; |
extern int preserve_times; |
|
extern int copy_devices; |
extern int am_root; |
extern int am_root; |
extern int am_server; |
extern int am_server; |
extern int am_daemon; |
extern int am_daemon; |
extern int am_sender; |
extern int am_sender; |
extern int am_receiver; |
extern int am_receiver; |
extern int am_generator; |
extern int am_generator; |
|
extern int am_dbadmin; |
extern int am_starting_up; |
extern int am_starting_up; |
extern int allow_8bit_chars; |
extern int allow_8bit_chars; |
extern int protocol_version; |
extern int protocol_version; |
extern int got_kill_signal; |
extern int got_kill_signal; |
|
extern int called_from_signal_handler; |
extern int inc_recurse; |
extern int inc_recurse; |
extern int inplace; |
extern int inplace; |
extern int flist_eof; |
extern int flist_eof; |
extern int file_old_total; |
extern int file_old_total; |
extern int keep_dirlinks; |
extern int keep_dirlinks; |
extern int make_backups; |
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 file_list *cur_flist, *first_flist, *dir_flist; |
extern struct chmod_mode_struct *daemon_chmod_modes; |
extern struct chmod_mode_struct *daemon_chmod_modes; |
#ifdef ICONV_OPTION |
#ifdef ICONV_OPTION |
extern char *iconv_opt; |
extern char *iconv_opt; |
#endif |
#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 |
#ifdef ICONV_CONST |
iconv_t ic_chck = (iconv_t)-1; |
iconv_t ic_chck = (iconv_t)-1; |
# ifdef ICONV_OPTION |
# ifdef ICONV_OPTION |
Line 307 void send_protected_args(int fd, char *args[])
|
Line 322 void send_protected_args(int fd, char *args[])
|
#endif |
#endif |
} |
} |
|
|
int read_ndx_and_attrs(int f_in, int f_out, int *iflag_ptr, uchar *type_ptr, | int read_ndx_and_attrs(int f_in, int f_out, int *iflag_ptr, uchar *type_ptr, char *buf, int *len_ptr) |
char *buf, int *len_ptr) | |
{ |
{ |
int len, iflags = 0; |
int len, iflags = 0; |
struct file_list *flist; |
struct file_list *flist; |
Line 396 int read_ndx_and_attrs(int f_in, int f_out, int *iflag
|
Line 410 int read_ndx_and_attrs(int f_in, int f_out, int *iflag
|
if (iflags & ITEM_XNAME_FOLLOWS) { |
if (iflags & ITEM_XNAME_FOLLOWS) { |
if ((len = read_vstring(f_in, buf, MAXPATHLEN)) < 0) |
if ((len = read_vstring(f_in, buf, MAXPATHLEN)) < 0) |
exit_cleanup(RERR_PROTOCOL); |
exit_cleanup(RERR_PROTOCOL); |
|
|
|
if (sanitize_paths) { |
|
sanitize_path(buf, buf, "", 0, SP_DEFAULT); |
|
len = strlen(buf); |
|
} |
} else { |
} else { |
*buf = '\0'; |
*buf = '\0'; |
len = -1; |
len = -1; |
Line 404 int read_ndx_and_attrs(int f_in, int f_out, int *iflag
|
Line 423 int read_ndx_and_attrs(int f_in, int f_out, int *iflag
|
|
|
if (iflags & ITEM_TRANSFER) { |
if (iflags & ITEM_TRANSFER) { |
int i = ndx - cur_flist->ndx_start; |
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, |
rprintf(FERROR, |
"received request to transfer non-regular file: %d [%s]\n", |
"received request to transfer non-regular file: %d [%s]\n", |
ndx, who_am_i()); |
ndx, who_am_i()); |
Line 452 mode_t dest_mode(mode_t flist_mode, mode_t stat_mode,
|
Line 472 mode_t dest_mode(mode_t flist_mode, mode_t stat_mode,
|
return new_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, |
int set_file_attrs(const char *fname, struct file_struct *file, stat_x *sxp, |
const char *fnamecmp, int flags) |
const char *fnamecmp, int flags) |
{ |
{ |
Line 489 int set_file_attrs(const char *fname, struct file_stru
|
Line 557 int set_file_attrs(const char *fname, struct file_stru
|
get_acl(fname, sxp); |
get_acl(fname, sxp); |
#endif |
#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) |
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 |
#ifndef CAN_CHOWN_SYMLINK |
if (S_ISLNK(sxp->st.st_mode)) { |
if (S_ISLNK(sxp->st.st_mode)) { |
; |
; |
Line 513 int set_file_attrs(const char *fname, struct file_stru
|
Line 583 int set_file_attrs(const char *fname, struct file_stru
|
if (am_root >= 0) { |
if (am_root >= 0) { |
uid_t uid = change_uid ? (uid_t)F_OWNER(file) : sxp->st.st_uid; |
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; |
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 |
/* We shouldn't have attempted to change uid |
* or gid unless have the privilege. */ |
* or gid unless have the privilege. */ |
rsyserr(FERROR_XFER, errno, "%s %s failed", |
rsyserr(FERROR_XFER, errno, "%s %s failed", |
change_uid ? "chown" : "chgrp", | change_uid ? "chown" : "chgrp", |
full_fname(fname)); | full_fname(fname)); |
goto cleanup; |
goto cleanup; |
} |
} |
if (uid == (uid_t)-1 && sxp->st.st_uid != (uid_t)-1) |
if (uid == (uid_t)-1 && sxp->st.st_uid != (uid_t)-1) |
Line 533 int set_file_attrs(const char *fname, struct file_stru
|
Line 603 int set_file_attrs(const char *fname, struct file_stru
|
keep_dirlinks && S_ISDIR(sxp->st.st_mode)); |
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 |
#ifdef SUPPORT_XATTRS |
if (am_root < 0) |
if (am_root < 0) |
set_stat_xattr(fname, file, new_mode); |
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); |
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 |
#endif |
|
|
if (!preserve_times |
if (!preserve_times |
|| (!(preserve_times & PRESERVE_DIR_TIMES) && S_ISDIR(sxp->st.st_mode)) |
|| (!(preserve_times & PRESERVE_DIR_TIMES) && S_ISDIR(sxp->st.st_mode)) |
|| (!(preserve_times & PRESERVE_LINK_TIMES) && S_ISLNK(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) |
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 |
#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 |
#endif |
)) { | updated |= UPDATED_MTIME; |
int ret = set_modtime(fname, file->modtime, F_MOD_NSEC(file), sxp->st.st_mode); | } |
| 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) { |
if (ret < 0) { |
rsyserr(FERROR_XFER, errno, "failed to set times on %s", |
rsyserr(FERROR_XFER, errno, "failed to set times on %s", |
full_fname(fname)); |
full_fname(fname)); |
goto cleanup; |
goto cleanup; |
} |
} |
if (ret == 0) /* ret == 1 if symlink could not be set */ | if (ret > 0) { /* ret == 1 if symlink could not be set */ |
updated = 1; | updated &= ~UPDATED_TIMES; |
else | |
file->flags |= FLAG_TIME_FAILED; |
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; |
updated = 1; |
} |
} |
#endif |
#endif |
Line 588 int set_file_attrs(const char *fname, struct file_stru
|
Line 686 int set_file_attrs(const char *fname, struct file_stru
|
* need to chmod(). */ |
* need to chmod(). */ |
if (preserve_acls && !S_ISLNK(new_mode)) { |
if (preserve_acls && !S_ISLNK(new_mode)) { |
if (set_acl(fname, file, sxp, new_mode) > 0) |
if (set_acl(fname, file, sxp, new_mode) > 0) |
updated = 1; | updated |= UPDATED_ACLS; |
} |
} |
#endif |
#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 (INFO_GTE(NAME, 2) && flags & ATTRS_REPORT) { |
if (updated) |
if (updated) |
rprintf(FCLIENT, "%s\n", fname); |
rprintf(FCLIENT, "%s\n", fname); |
Line 607 int set_file_attrs(const char *fname, struct file_stru
|
Line 742 int set_file_attrs(const char *fname, struct file_stru
|
/* This is only called for SIGINT, SIGHUP, and SIGTERM. */ |
/* This is only called for SIGINT, SIGHUP, and SIGTERM. */ |
void sig_int(int sig_num) |
void sig_int(int sig_num) |
{ |
{ |
|
called_from_signal_handler = 1; |
|
|
/* KLUGE: if the user hits Ctrl-C while ssh is prompting |
/* KLUGE: if the user hits Ctrl-C while ssh is prompting |
* for a password, then our cleanup's sending of a SIGUSR1 |
* for a password, then our cleanup's sending of a SIGUSR1 |
* signal to all our children may kill ssh before it has a |
* signal to all our children may kill ssh before it has a |
Line 630 void sig_int(int sig_num)
|
Line 767 void sig_int(int sig_num)
|
* we didn't already set the flag. */ |
* we didn't already set the flag. */ |
if (!got_kill_signal && (am_server || am_receiver)) { |
if (!got_kill_signal && (am_server || am_receiver)) { |
got_kill_signal = sig_num; |
got_kill_signal = sig_num; |
|
called_from_signal_handler = 0; |
return; |
return; |
} |
} |
|
|
Line 640 void sig_int(int sig_num)
|
Line 778 void sig_int(int sig_num)
|
* attributes (e.g. permissions, ownership, etc.). If the robust_rename() |
* 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 |
* 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 |
* 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, |
int finish_transfer(const char *fname, const char *fnametmp, |
const char *fnamecmp, const char *partialptr, |
const char *fnamecmp, const char *partialptr, |
struct file_struct *file, int ok_to_set_time, |
struct file_struct *file, int ok_to_set_time, |
Line 656 int finish_transfer(const char *fname, const char *fna
|
Line 794 int finish_transfer(const char *fname, const char *fna
|
goto do_set_file_attrs; |
goto do_set_file_attrs; |
} |
} |
|
|
if (make_backups > 0 && overwriting_basis) { | if (make_backups > 1 && overwriting_basis) { |
int ok = make_backup(fname, False); |
int ok = make_backup(fname, False); |
if (!ok) |
if (!ok) |
return 1; | exit_cleanup(RERR_FILEIO); |
if (ok == 1 && fnamecmp == fname) |
if (ok == 1 && fnamecmp == fname) |
fnamecmp = get_backup_name(fname); |
fnamecmp = get_backup_name(fname); |
} |
} |
|
|
/* Change permissions before putting the file into place. */ |
/* Change permissions before putting the file into place. */ |
set_file_attrs(fnametmp, file, NULL, fnamecmp, |
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 */ |
/* move tmp file over real file */ |
if (DEBUG_GTE(RECV, 1)) |
if (DEBUG_GTE(RECV, 1)) |
Line 683 int finish_transfer(const char *fname, const char *fna
|
Line 822 int finish_transfer(const char *fname, const char *fna
|
} |
} |
if (ret == 0) { |
if (ret == 0) { |
/* The file was moved into place (not copied), so it's done. */ |
/* 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; |
return 1; |
} |
} |
/* The file was copied, so tweak the perms of the copied file. If it |
/* The file was copied, so tweak the perms of the copied file. If it |
Line 691 int finish_transfer(const char *fname, const char *fna
|
Line 834 int finish_transfer(const char *fname, const char *fna
|
|
|
do_set_file_attrs: |
do_set_file_attrs: |
set_file_attrs(fnametmp, file, NULL, fnamecmp, |
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 (temp_copy_name) { |
if (do_rename(fnametmp, fname) < 0) { |
if (do_rename(fnametmp, fname) < 0) { |
Line 742 struct file_list *flist_for_ndx(int ndx, const char *f
|
Line 885 struct file_list *flist_for_ndx(int ndx, const char *f
|
|
|
const char *who_am_i(void) |
const char *who_am_i(void) |
{ |
{ |
|
if (am_dbadmin) |
|
return "rsyncdb"; |
if (am_starting_up) |
if (am_starting_up) |
return am_server ? "server" : "client"; |
return am_server ? "server" : "client"; |
return am_sender ? "sender" |
return am_sender ? "sender" |