Revision: 80017 http://trac.macports.org/changeset/80017 Author: blair@macports.org Date: 2011-07-01 21:52:41 -0700 (Fri, 01 Jul 2011) Log Message: ----------- rsync: update to 3.0.8. Modified Paths: -------------- trunk/dports/net/rsync/Portfile trunk/dports/net/rsync/files/patch-crtimes.diff trunk/dports/net/rsync/files/patch-fileflags.diff Modified: trunk/dports/net/rsync/Portfile =================================================================== --- trunk/dports/net/rsync/Portfile 2011-07-02 00:29:46 UTC (rev 80016) +++ trunk/dports/net/rsync/Portfile 2011-07-02 04:52:41 UTC (rev 80017) @@ -3,8 +3,7 @@ PortSystem 1.0 name rsync -version 3.0.7 -revision 1 +version 3.0.8 categories net platforms darwin freebsd sunos maintainers nomaintainer @@ -22,13 +21,13 @@ master_sites http://rsync.samba.org/ftp/rsync/ \ http://rsync.samba.org/ftp/rsync/src/ -checksums md5 b53525900817cf1ba7ad3a516ab5bfe9 \ - sha1 63426a1bc71991d93159cd522521fbacdafb7a61 \ - rmd160 aa3bdec0d7692ac1de52f2efc925e9a34bbd917b +checksums md5 0ee8346ce16bdfe4c88a236e94c752b4 \ + sha1 10e80173c7e9ed8b8a4dc9e8fdab08402da5f08d \ + rmd160 f00c5ba42e33a1745976c9af5e770c220a6fa4a6 depends_lib port:popt port:libiconv -# these come from http://rsync.samba.org/ftp/rsync/rsync-patches-3.0.7.tar.gz +# these come from http://rsync.samba.org/ftp/rsync/rsync-patches-3.0.8.tar.gz # and need to be updated with each release patchfiles patch-fileflags.diff \ patch-crtimes.diff Modified: trunk/dports/net/rsync/files/patch-crtimes.diff =================================================================== --- trunk/dports/net/rsync/files/patch-crtimes.diff 2011-07-02 00:29:46 UTC (rev 80016) +++ trunk/dports/net/rsync/files/patch-crtimes.diff 2011-07-02 04:52:41 UTC (rev 80017) @@ -5,14 +5,15 @@ patch -p1 <patches/fileflags.diff patch -p1 <patches/crtimes.diff - ./configure (optional if already run) + ./prepare-source + ./configure make based-on: patch/b3.0.x/fileflags diff --git a/compat.c b/compat.c --- a/compat.c +++ b/compat.c -@@ -46,6 +46,7 @@ extern int force_change; +@@ -47,6 +47,7 @@ extern int force_change; extern int protect_args; extern int preserve_uid; extern int preserve_gid; @@ -20,7 +21,7 @@ extern int preserve_fileflags; extern int preserve_acls; extern int preserve_xattrs; -@@ -64,7 +65,7 @@ extern char *iconv_opt; +@@ -65,7 +66,7 @@ extern char *iconv_opt; #endif /* These index values are for the file-list's extra-attribute array. */ @@ -29,7 +30,7 @@ int receiver_symlink_times = 0; /* receiver can set the time on a symlink */ int sender_symlink_iconv = 0; /* sender should convert symlink content */ -@@ -141,6 +142,8 @@ void setup_protocol(int f_out,int f_in) +@@ -142,6 +143,8 @@ void setup_protocol(int f_out,int f_in) uid_ndx = ++file_extra_cnt; if (preserve_gid) gid_ndx = ++file_extra_cnt; @@ -41,15 +42,15 @@ diff --git a/flist.c b/flist.c --- a/flist.c +++ b/flist.c -@@ -56,6 +56,7 @@ extern int delete_during; - extern int uid_ndx; - extern int gid_ndx; +@@ -54,6 +54,7 @@ extern int preserve_specials; + extern int preserve_fileflags; + extern int delete_during; extern int eol_nulls; +extern int crtimes_ndx; extern int relative_paths; extern int implied_dirs; - extern int file_extra_cnt; -@@ -395,7 +396,7 @@ static void send_file_entry(int f, const char *fname, struct file_struct *file, + extern int ignore_perishable; +@@ -393,7 +394,7 @@ static void send_file_entry(int f, const char *fname, struct file_struct *file, #endif int ndx, int first_ndx) { @@ -58,7 +59,7 @@ static mode_t mode; #ifdef SUPPORT_FILEFLAGS static uint32 fileflags; -@@ -490,6 +491,13 @@ static void send_file_entry(int f, const char *fname, struct file_struct *file, +@@ -488,6 +489,13 @@ static void send_file_entry(int f, const char *fname, struct file_struct *file, xflags |= XMIT_SAME_TIME; else modtime = file->modtime; @@ -71,8 +72,8 @@ + } #ifdef SUPPORT_HARD_LINKS - if (tmp_dev != 0) { -@@ -559,6 +567,8 @@ static void send_file_entry(int f, const char *fname, struct file_struct *file, + if (tmp_dev != -1) { +@@ -557,6 +565,8 @@ static void send_file_entry(int f, const char *fname, struct file_struct *file, else write_int(f, modtime); } @@ -81,16 +82,16 @@ if (!(xflags & XMIT_SAME_MODE)) write_int(f, to_wire_mode(mode)); #ifdef SUPPORT_FILEFLAGS -@@ -649,7 +659,7 @@ static void send_file_entry(int f, const char *fname, struct file_struct *file, - static struct file_struct *recv_file_entry(struct file_list *flist, - int xflags, int f) +@@ -648,7 +658,7 @@ static void send_file_entry(int f, const char *fname, struct file_struct *file, + + static struct file_struct *recv_file_entry(int f, struct file_list *flist, int xflags) { - static int64 modtime; + static int64 modtime, crtime; static mode_t mode; #ifdef SUPPORT_FILEFLAGS static uint32 fileflags; -@@ -755,6 +765,8 @@ static struct file_struct *recv_file_entry(struct file_list *flist, +@@ -758,6 +768,8 @@ static struct file_struct *recv_file_entry(int f, struct file_list *flist, int x uid = F_OWNER(first); if (preserve_gid) gid = F_GROUP(first); @@ -99,7 +100,7 @@ if (preserve_devices && IS_DEVICE(mode)) { uint32 *devp = F_RDEV_P(first); rdev = MAKEDEV(DEV_MAJOR(devp), DEV_MINOR(devp)); -@@ -783,6 +795,19 @@ static struct file_struct *recv_file_entry(struct file_list *flist, +@@ -786,6 +798,19 @@ static struct file_struct *recv_file_entry(int f, struct file_list *flist, int x } else modtime = read_int(f); } @@ -119,7 +120,7 @@ if (!(xflags & XMIT_SAME_MODE)) mode = from_wire_mode(read_int(f)); -@@ -943,6 +968,8 @@ static struct file_struct *recv_file_entry(struct file_list *flist, +@@ -946,6 +971,8 @@ static struct file_struct *recv_file_entry(int f, struct file_list *flist, int x F_GROUP(file) = gid; file->flags |= gid_flags; } @@ -128,10 +129,10 @@ if (unsort_ndx) F_NDX(file) = flist->used + flist->ndx_start; -@@ -1319,6 +1346,8 @@ struct file_struct *make_file(const char *fname, struct file_list *flist, - F_OWNER(file) = st.st_uid; - if (gid_ndx) /* Check gid_ndx instead of preserve_gid for del support */ +@@ -1324,6 +1351,8 @@ struct file_struct *make_file(const char *fname, struct file_list *flist, F_GROUP(file) = st.st_gid; + if (am_generator && st.st_uid == our_uid) + file->flags |= FLAG_OWNED_BY_US; + if (crtimes_ndx) + f_crtime_set(file, get_create_time(fname)); @@ -148,7 +149,7 @@ extern int verbose; extern int dry_run; -@@ -40,6 +41,7 @@ extern int preserve_xattrs; +@@ -41,6 +42,7 @@ extern int preserve_xattrs; extern int preserve_links; extern int preserve_devices; extern int preserve_specials; @@ -156,21 +157,42 @@ extern int preserve_hard_links; extern int preserve_executability; extern int preserve_fileflags; -@@ -623,6 +625,13 @@ int unchanged_attrs(const char *fname, struct file_struct *file, stat_x *sxp) - if (gid_ndx && !(file->flags & FLAG_SKIP_GROUP) && sxp->st.st_gid != (gid_t)F_GROUP(file)) - return 0; +@@ -576,8 +578,15 @@ static void do_delete_pass(void) + rprintf(FINFO, " \r"); + } +-static inline int time_differs(struct file_struct *file, stat_x *sxp) ++static inline int time_differs(struct file_struct *file, stat_x *sxp, const char *fname) + { + if (crtimes_ndx) { + if (sxp->crtime == 0) + sxp->crtime = get_create_time(fname); + if (cmp_time(sxp->crtime, f_crtime(file)) != 0) -+ return 0; ++ return 1; + } + - #ifdef SUPPORT_ACLS - if (preserve_acls && !S_ISLNK(file->mode)) { - if (!ACL_READY(*sxp)) -@@ -666,6 +675,12 @@ void itemize(const char *fnamecmp, struct file_struct *file, int ndx, int statre + return cmp_time(sxp->st.st_mtime, file->modtime); + } + +@@ -635,7 +644,7 @@ int unchanged_attrs(const char *fname, 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_differs(file, sxp, fname)) + return 0; + #endif + #ifdef CAN_CHMOD_SYMLINK +@@ -655,7 +664,7 @@ int unchanged_attrs(const char *fname, struct file_struct *file, stat_x *sxp) + return 0; + #endif + } else { +- if (preserve_times && time_differs(file, sxp)) ++ if (preserve_times && time_differs(file, sxp, fname)) + return 0; + if (perms_differ(file, sxp)) + return 0; +@@ -698,6 +707,12 @@ void itemize(const char *fnamecmp, struct file_struct *file, int ndx, int statre : iflags & (ITEM_TRANSFER|ITEM_LOCAL_CHANGE) && !(iflags & ITEM_MATCHED) && (!(iflags & ITEM_XNAME_FOLLOWS) || *xname)) iflags |= ITEM_REPORT_TIME; @@ -183,7 +205,7 @@ #if !defined HAVE_LCHMOD && !defined HAVE_SETATTRLIST if (S_ISLNK(file->mode)) { ; -@@ -1225,7 +1240,7 @@ static int try_dests_non(struct file_struct *file, char *fname, int ndx, +@@ -1263,7 +1278,7 @@ static int try_dests_non(struct file_struct *file, char *fname, int ndx, static void list_file_entry(struct file_struct *f) { @@ -192,7 +214,7 @@ double len; if (!F_IS_ACTIVE(f)) { -@@ -1236,19 +1251,24 @@ static void list_file_entry(struct file_struct *f) +@@ -1274,19 +1289,24 @@ static void list_file_entry(struct file_struct *f) permstring(permbuf, f->mode); len = F_LENGTH(f); @@ -221,18 +243,18 @@ } } -@@ -1339,6 +1359,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx, +@@ -1383,6 +1403,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx, return; } } + sx.crtime = 0; - #ifdef SUPPORT_ACLS - sx.acc_acl = sx.def_acl = NULL; + if (dry_run > 1 || (dry_missing_dir && is_below(file, dry_missing_dir))) { + parent_is_dry_missing: diff --git a/hlink.c b/hlink.c --- a/hlink.c +++ b/hlink.c -@@ -370,6 +370,7 @@ int hard_link_check(struct file_struct *file, int ndx, const char *fname, +@@ -371,6 +371,7 @@ int hard_link_check(struct file_struct *file, int ndx, const char *fname, char cmpbuf[MAXPATHLEN]; stat_x alt_sx; int j = 0; @@ -240,7 +262,7 @@ #ifdef SUPPORT_ACLS alt_sx.acc_acl = alt_sx.def_acl = NULL; #endif -@@ -498,6 +499,7 @@ void finish_hard_link(struct file_struct *file, const char *fname, int fin_ndx, +@@ -499,6 +500,7 @@ void finish_hard_link(struct file_struct *file, const char *fname, int fin_ndx, } else our_name = fname; @@ -283,7 +305,7 @@ diff --git a/log.c b/log.c --- a/log.c +++ b/log.c -@@ -663,7 +663,8 @@ static void log_formatted(enum logcode code, const char *format, const char *op, +@@ -661,7 +661,8 @@ static void log_formatted(enum logcode code, const char *format, const char *op, c[8] = !(iflags & ITEM_REPORT_FFLAGS) ? '.' : 'f'; c[9] = !(iflags & ITEM_REPORT_ACL) ? '.' : 'a'; c[10] = !(iflags & ITEM_REPORT_XATTR) ? '.' : 'x'; @@ -304,7 +326,7 @@ int update_only = 0; int cvs_exclude = 0; int dry_run = 0; -@@ -362,6 +363,7 @@ void usage(enum logcode F) +@@ -361,6 +362,7 @@ void usage(enum logcode F) rprintf(F," -D same as --devices --specials\n"); rprintf(F," -t, --times preserve modification times\n"); rprintf(F," -O, --omit-dir-times omit directories from --times\n"); @@ -312,8 +334,8 @@ rprintf(F," --super receiver attempts super-user activities\n"); #ifdef SUPPORT_XATTRS rprintf(F," --fake-super store/recover privileged attrs using xattrs\n"); -@@ -508,6 +510,9 @@ static struct poptOption long_options[] = { - {"times", 't', POPT_ARG_VAL, &preserve_times, 2, 0, 0 }, +@@ -507,6 +509,9 @@ static struct poptOption long_options[] = { + {"times", 't', POPT_ARG_VAL, &preserve_times, 1, 0, 0 }, {"no-times", 0, POPT_ARG_VAL, &preserve_times, 0, 0, 0 }, {"no-t", 0, POPT_ARG_VAL, &preserve_times, 0, 0, 0 }, + {"crtimes", 'N', POPT_ARG_VAL, &preserve_crtimes, 1, 0, 0 }, @@ -322,7 +344,7 @@ {"omit-dir-times", 'O', POPT_ARG_VAL, &omit_dir_times, 1, 0, 0 }, {"no-omit-dir-times",0, POPT_ARG_VAL, &omit_dir_times, 0, 0, 0 }, {"no-O", 0, POPT_ARG_VAL, &omit_dir_times, 0, 0, 0 }, -@@ -1805,6 +1810,8 @@ void server_options(char **args, int *argc_p) +@@ -1810,6 +1815,8 @@ void server_options(char **args, int *argc_p) argstr[x++] = 'D'; if (preserve_times) argstr[x++] = 't'; @@ -334,7 +356,7 @@ diff --git a/rsync.c b/rsync.c --- a/rsync.c +++ b/rsync.c -@@ -427,6 +427,7 @@ int set_file_attrs(const char *fname, struct file_struct *file, stat_x *sxp, +@@ -464,6 +464,7 @@ int set_file_attrs(const char *fname, struct file_struct *file, stat_x *sxp, full_fname(fname)); return 0; } @@ -342,7 +364,17 @@ #ifdef SUPPORT_ACLS sx2.acc_acl = sx2.def_acl = NULL; #endif -@@ -474,6 +475,14 @@ int set_file_attrs(const char *fname, struct file_struct *file, stat_x *sxp, +@@ -505,6 +506,9 @@ int set_file_attrs(const char *fname, struct file_struct *file, stat_x *sxp, + || (!(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; ++ /* 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) + && cmp_time(sxp->st.st_mtime, file->modtime) != 0) { + int ret = set_modtime(fname, file->modtime, sxp->st.st_mode, ST_FLAGS(sxp->st)); +@@ -518,6 +522,14 @@ int set_file_attrs(const char *fname, struct file_struct *file, stat_x *sxp, else file->flags |= FLAG_TIME_FAILED; } @@ -357,7 +389,7 @@ change_uid = am_root && uid_ndx && sxp->st.st_uid != (uid_t)F_OWNER(file); change_gid = gid_ndx && !(file->flags & FLAG_SKIP_GROUP) -@@ -621,7 +630,7 @@ int finish_transfer(const char *fname, const char *fnametmp, +@@ -675,7 +687,7 @@ int finish_transfer(const char *fname, const char *fnametmp, /* Change permissions before putting the file into place. */ set_file_attrs(fnametmp, file, NULL, fnamecmp, ATTRS_DELAY_IMMUTABLE @@ -366,7 +398,7 @@ /* move tmp file over real file */ if (verbose > 2) -@@ -652,7 +661,7 @@ int finish_transfer(const char *fname, const char *fnametmp, +@@ -706,7 +718,7 @@ int finish_transfer(const char *fname, const char *fnametmp, do_set_file_attrs: set_file_attrs(fnametmp, file, NULL, fnamecmp, @@ -386,7 +418,7 @@ #define XMIT_SAME_FLAGS (1<<14) /* protocols ?? - now */ /* These flags are used in the live flist data. */ -@@ -157,6 +158,7 @@ +@@ -162,6 +163,7 @@ #define ATTRS_REPORT (1<<0) #define ATTRS_SKIP_MTIME (1<<1) #define ATTRS_DELAY_IMMUTABLE (1<<2) @@ -394,7 +426,7 @@ #define FULL_FLUSH 1 #define NORMAL_FLUSH 0 -@@ -173,7 +175,7 @@ +@@ -178,7 +180,7 @@ #define FNAMECMP_FUZZY 0x83 /* For use by the itemize_changes code */ @@ -403,7 +435,7 @@ #define ITEM_REPORT_CHANGE (1<<1) #define ITEM_REPORT_SIZE (1<<2) /* regular files only */ #define ITEM_REPORT_TIMEFAIL (1<<2) /* symlinks only */ -@@ -658,6 +660,7 @@ extern int file_extra_cnt; +@@ -677,6 +679,7 @@ extern int file_extra_cnt; extern int inc_recurse; extern int uid_ndx; extern int gid_ndx; @@ -411,7 +443,7 @@ extern int fileflags_ndx; extern int acls_ndx; extern int xattrs_ndx; -@@ -665,6 +668,7 @@ extern int xattrs_ndx; +@@ -684,6 +687,7 @@ extern int xattrs_ndx; #define FILE_STRUCT_LEN (offsetof(struct file_struct, basename)) #define EXTRA_LEN (sizeof (union file_extras)) #define PTR_EXTRA_CNT ((sizeof (char *) + EXTRA_LEN - 1) / EXTRA_LEN) @@ -419,7 +451,7 @@ #define DEV_EXTRA_CNT 2 #define DIRNODE_EXTRA_CNT 3 #define SUM_EXTRA_CNT ((MAX_DIGEST_LEN + EXTRA_LEN - 1) / EXTRA_LEN) -@@ -932,6 +936,7 @@ typedef struct { +@@ -951,6 +955,7 @@ typedef struct { typedef struct { STRUCT_STAT st; @@ -438,7 +470,7 @@ --super receiver attempts super-user activities --fake-super store/recover privileged attrs using xattrs -S, --sparse handle sparse files efficiently -@@ -1039,6 +1040,9 @@ it is preserving modification times (see bf(--times)). If NFS is sharing +@@ -1086,6 +1087,9 @@ it is preserving modification times (see bf(--times)). If NFS is sharing the directories on the receiving side, it is a good idea to use bf(-O). This option is inferred if you use bf(--backup) without bf(--backup-dir). @@ -448,7 +480,7 @@ dit(bf(--super)) This tells the receiving side to attempt super-user activities even if the receiving rsync wasn't run by the super-user. These activities include: preserving users via the bf(--owner) option, preserving -@@ -1717,7 +1721,7 @@ with older versions of rsync, but that also turns on the output of other +@@ -1782,7 +1786,7 @@ with older versions of rsync, but that also turns on the output of other verbose messages). The "%i" escape has a cryptic output that is 11 letters long. The general @@ -457,7 +489,7 @@ type of update being done, bf(X) is replaced by the file-type, and the other letters represent attributes that may be output if they are being modified. -@@ -1776,6 +1780,8 @@ quote(itemization( +@@ -1841,6 +1845,8 @@ quote(itemization( it() The bf(f) means that the fileflags information changed. it() The bf(a) means that the ACL information changed. it() The bf(x) means that the extended attribute information changed. @@ -469,12 +501,11 @@ diff --git a/syscall.c b/syscall.c --- a/syscall.c +++ b/syscall.c -@@ -37,6 +37,14 @@ extern int force_change; +@@ -37,6 +37,13 @@ extern int force_change; extern int preserve_perms; extern int preserve_executability; -+#pragma pack(push) -+#pragma pack(4) ++#pragma pack(push, 4) +struct create_time { + uint32 length; + struct timespec crtime; @@ -484,11 +515,10 @@ #define RETURN_ERROR_IF(x,e) \ do { \ if (x) { \ -@@ -394,3 +399,33 @@ OFF_T do_lseek(int fd, OFF_T offset, int whence) - return lseek(fd, offset, whence); +@@ -529,6 +536,36 @@ OFF_T do_lseek(int fd, OFF_T offset, int whence) #endif } -+ + +time_t get_create_time(const char *path) +{ + static struct create_time attrBuf; @@ -518,6 +548,10 @@ + attrList.commonattr = ATTR_CMN_CRTIME; + return setattrlist(path, &attrList, &ts, sizeof ts, FSOPT_NOFOLLOW); +} ++ + #ifdef HAVE_UTIMENSAT + int do_utimensat(const char *fname, time_t modtime, uint32 mod_nsec, mode_t mode, uint32 fileflags) + { diff --git a/testsuite/crtimes.test b/testsuite/crtimes.test new file mode 100644 --- /dev/null @@ -560,9 +594,9 @@ +all_plus='++++++++++' +allspace=' ' +dots='......' # trailing dots after changes + tab_ch=' ' # a single tab character # Berkley's nice. - PATH="$PATH:/usr/ucb" diff --git a/tls.c b/tls.c --- a/tls.c +++ b/tls.c @@ -667,27 +701,27 @@ diff -up a/proto.h b/proto.h --- a/proto.h +++ b/proto.h -@@ -314,6 +314,8 @@ int do_stat(const char *fname, STRUCT_ST +@@ -315,6 +315,8 @@ int do_stat(const char *fname, STRUCT_ST int do_lstat(const char *fname, STRUCT_STAT *st); int do_fstat(int fd, STRUCT_STAT *st); OFF_T do_lseek(int fd, OFF_T offset, int whence); +time_t get_create_time(const char *path); +int set_create_time(const char *path, time_t crtime); - void set_compression(const char *fname); - void send_token(int f, int32 token, struct map_struct *buf, OFF_T offset, - int32 n, int32 toklen); + int do_utimensat(const char *fname, time_t modtime, uint32 mod_nsec, mode_t mode, uint32 fileflags); + int do_lutimes(const char *fname, time_t modtime, uint32 mod_nsec, mode_t mode, uint32 fileflags); + int do_utimes(const char *fname, time_t modtime, uint32 mod_nsec, mode_t mode, uint32 fileflags); diff -up a/rsync.1 b/rsync.1 --- a/rsync.1 +++ b/rsync.1 -@@ -429,6 +429,7 @@ to the detailed description below for a +@@ -429,6 +429,7 @@ to the detailed description below for a \-D same as \-\-devices \-\-specials \-t, \-\-times preserve modification times \-O, \-\-omit\-dir\-times omit directories from \-\-times + \-N, \-\-crtimes preserve create times (newness) - \-\-super receiver attempts super-user activities + \-\-super receiver attempts super\-user activities \-\-fake\-super store/recover privileged attrs using xattrs \-S, \-\-sparse handle sparse files efficiently -@@ -1194,6 +1195,10 @@ it is preserving modification times (see +@@ -1253,6 +1254,10 @@ it is preserving modification times (see the directories on the receiving side, it is a good idea to use \fB\-O\fP. This option is inferred if you use \fB\-\-backup\fP without \fB\-\-backup\-dir\fP. .IP @@ -696,18 +730,18 @@ +the destination files to the same value as the source files. +.IP .IP "\fB\-\-super\fP" - This tells the receiving side to attempt super-user - activities even if the receiving rsync wasn\(cq\&t run by the super-user. These -@@ -1963,7 +1968,7 @@ with older versions of rsync, but that a + This tells the receiving side to attempt super\-user + activities even if the receiving rsync wasn\(cq\&t run by the super\-user. These +@@ -2037,7 +2042,7 @@ with older versions of rsync, but that a verbose messages). .IP The \(dq\&%i\(dq\& escape has a cryptic output that is 11 letters long. The general -format is like the string \fBYXcstpogfax\fP, where \fBY\fP is replaced by the +format is like the string \fBYXcstpogfaxn\fP, where \fBY\fP is replaced by the - type of update being done, \fBX\fP is replaced by the file-type, and the + type of update being done, \fBX\fP is replaced by the file\-type, and the other letters represent attributes that may be output if they are being modified. -@@ -2038,6 +2043,9 @@ The \fBf\fP means that the fileflags inf +@@ -2112,6 +2117,9 @@ The \fBf\fP means that the fileflags inf The \fBa\fP means that the ACL information changed. .IP o The \fBx\fP means that the extended attribute information changed. Modified: trunk/dports/net/rsync/files/patch-fileflags.diff =================================================================== --- trunk/dports/net/rsync/files/patch-fileflags.diff 2011-07-02 00:29:46 UTC (rev 80016) +++ trunk/dports/net/rsync/files/patch-fileflags.diff 2011-07-02 04:52:41 UTC (rev 80017) @@ -8,7 +8,7 @@ ./configure make -based-on: 54f00c3f89fc147f2f9cba89d26a5bb1d20e783b +based-on: 1ddcdaf3f6808ba53aef9e19f630a18808de22ac diff --git a/Makefile.in b/Makefile.in --- a/Makefile.in +++ b/Makefile.in @@ -33,7 +33,7 @@ diff --git a/compat.c b/compat.c --- a/compat.c +++ b/compat.c -@@ -42,9 +42,11 @@ extern int checksum_seed; +@@ -43,9 +43,11 @@ extern int checksum_seed; extern int basis_dir_cnt; extern int prune_empty_dirs; extern int protocol_version; @@ -45,7 +45,7 @@ extern int preserve_acls; extern int preserve_xattrs; extern int need_messages_from_generator; -@@ -62,7 +64,7 @@ extern char *iconv_opt; +@@ -63,7 +65,7 @@ extern char *iconv_opt; #endif /* These index values are for the file-list's extra-attribute array. */ @@ -54,7 +54,7 @@ int receiver_symlink_times = 0; /* receiver can set the time on a symlink */ int sender_symlink_iconv = 0; /* sender should convert symlink content */ -@@ -139,6 +141,8 @@ void setup_protocol(int f_out,int f_in) +@@ -140,6 +142,8 @@ void setup_protocol(int f_out,int f_in) uid_ndx = ++file_extra_cnt; if (preserve_gid) gid_ndx = ++file_extra_cnt; @@ -63,10 +63,10 @@ if (preserve_acls && !am_sender) acls_ndx = ++file_extra_cnt; if (preserve_xattrs) -diff --git a/configure.in b/configure.in ---- a/configure.in -+++ b/configure.in -@@ -567,6 +567,7 @@ AC_FUNC_UTIME_NULL +diff --git a/configure.ac b/configure.ac +--- a/configure.ac ++++ b/configure.ac +@@ -569,6 +569,7 @@ AC_FUNC_UTIME_NULL AC_FUNC_ALLOCA AC_CHECK_FUNCS(waitpid wait4 getcwd strdup chown chmod lchmod mknod mkfifo \ fchmod fstat ftruncate strchr readlink link utime utimes lutimes strftime \ @@ -83,9 +83,9 @@ extern int preserve_specials; +extern int preserve_fileflags; extern int delete_during; - extern int uid_ndx; - extern int gid_ndx; -@@ -396,6 +397,9 @@ static void send_file_entry(int f, const char *fname, struct file_struct *file, + extern int eol_nulls; + extern int relative_paths; +@@ -394,6 +395,9 @@ static void send_file_entry(int f, const char *fname, struct file_struct *file, { static time_t modtime; static mode_t mode; @@ -95,7 +95,7 @@ #ifdef SUPPORT_HARD_LINKS static int64 dev; #endif -@@ -425,6 +429,14 @@ static void send_file_entry(int f, const char *fname, struct file_struct *file, +@@ -423,6 +427,14 @@ static void send_file_entry(int f, const char *fname, struct file_struct *file, xflags |= XMIT_SAME_MODE; else mode = file->mode; @@ -110,7 +110,7 @@ if (preserve_devices && IS_DEVICE(mode)) { if (protocol_version < 28) { -@@ -549,6 +561,10 @@ static void send_file_entry(int f, const char *fname, struct file_struct *file, +@@ -547,6 +559,10 @@ static void send_file_entry(int f, const char *fname, struct file_struct *file, } if (!(xflags & XMIT_SAME_MODE)) write_int(f, to_wire_mode(mode)); @@ -121,7 +121,7 @@ if (preserve_uid && !(xflags & XMIT_SAME_UID)) { if (protocol_version < 30) write_int(f, uid); -@@ -635,6 +651,9 @@ static struct file_struct *recv_file_entry(struct file_list *flist, +@@ -634,6 +650,9 @@ static struct file_struct *recv_file_entry(int f, struct file_list *flist, int x { static int64 modtime; static mode_t mode; @@ -131,7 +131,18 @@ #ifdef SUPPORT_HARD_LINKS static int64 dev; #endif -@@ -769,6 +788,10 @@ static struct file_struct *recv_file_entry(struct file_list *flist, +@@ -731,6 +750,10 @@ static struct file_struct *recv_file_entry(int f, struct file_list *flist, int x + file_length = F_LENGTH(first); + modtime = first->modtime; + mode = first->mode; ++#ifdef SUPPORT_FILEFLAGS ++ if (preserve_fileflags) ++ fileflags = F_FFLAGS(first); ++#endif + if (preserve_uid) + uid = F_OWNER(first); + if (preserve_gid) +@@ -768,6 +791,10 @@ static struct file_struct *recv_file_entry(int f, struct file_list *flist, int x if (chmod_modes && !S_ISLNK(mode)) mode = tweak_mode(mode, chmod_modes); @@ -142,18 +153,18 @@ if (preserve_uid && !(xflags & XMIT_SAME_UID)) { if (protocol_version < 30) -@@ -910,6 +933,10 @@ static struct file_struct *recv_file_entry(struct file_list *flist, +@@ -909,6 +936,10 @@ static struct file_struct *recv_file_entry(int f, struct file_list *flist, int x } #endif file->mode = mode; +#ifdef SUPPORT_FILEFLAGS -+ if (preserve_fileflags) ++ if (fileflags_ndx) /* check the ndx for force_change w/o preserve_fileflags */ + F_FFLAGS(file) = fileflags; +#endif if (preserve_uid) F_OWNER(file) = uid; if (preserve_gid) { -@@ -1284,6 +1311,10 @@ struct file_struct *make_file(const char *fname, struct file_list *flist, +@@ -1283,6 +1314,10 @@ struct file_struct *make_file(const char *fname, struct file_list *flist, } #endif file->mode = st.st_mode; @@ -161,32 +172,39 @@ + if (fileflags_ndx) + F_FFLAGS(file) = st.st_flags; +#endif - if (uid_ndx) /* Check uid_ndx instead of preserve_uid for del support */ + if (preserve_uid) F_OWNER(file) = st.st_uid; - if (gid_ndx) /* Check gid_ndx instead of preserve_gid for del support */ -@@ -1427,6 +1458,7 @@ static struct file_struct *send_file_name(int f, struct file_list *flist, - #endif + if (preserve_gid) +@@ -1429,6 +1464,9 @@ static struct file_struct *send_file_name(int f, struct file_list *flist, #ifdef SUPPORT_XATTRS if (preserve_xattrs) { -+ sx.st.st_mode = file->mode; + sx.st.st_mode = file->mode; ++#ifdef SUPPORT_FILEFLAGS ++ sx.st.st_flags = preserve_fileflags ? F_FFLAGS(file) : 0; ++#endif sx.xattr = NULL; if (get_xattr(fname, &sx) < 0) { io_error |= IOERR_GENERAL; diff --git a/generator.c b/generator.c --- a/generator.c +++ b/generator.c -@@ -42,8 +42,10 @@ extern int preserve_devices; +@@ -35,6 +35,7 @@ extern int do_progress; + extern int relative_paths; + extern int implied_dirs; + extern int keep_dirlinks; ++extern int force_change; + extern int preserve_acls; + extern int preserve_xattrs; + extern int preserve_links; +@@ -42,6 +43,7 @@ extern int preserve_devices; extern int preserve_specials; extern int preserve_hard_links; extern int preserve_executability; +extern int preserve_fileflags; extern int preserve_perms; extern int preserve_times; -+extern int force_change; - extern int uid_ndx; - extern int gid_ndx; extern int delete_mode; -@@ -166,7 +168,7 @@ static enum delret delete_item(char *fbuf, uint16 mode, uint16 flags) +@@ -164,11 +166,15 @@ static enum delret delete_item(char *fbuf, uint16 mode, uint16 flags) } if (flags & DEL_NO_UID_WRITE) @@ -194,48 +212,43 @@ + do_chmod(fbuf, mode | S_IWUSR, NO_FFLAGS); if (S_ISDIR(mode) && !(flags & DEL_DIR_IS_EMPTY)) { - int save_uid_ndx = uid_ndx; -@@ -174,6 +176,13 @@ static enum delret delete_item(char *fbuf, uint16 mode, uint16 flags) + /* This only happens on the first call to delete_item() since * delete_dir_contents() always calls us w/DEL_DIR_IS_EMPTY. */ - if (!uid_ndx) - uid_ndx = ++file_extra_cnt; +#ifdef SUPPORT_FORCE_CHANGE -+ if (force_change) { -+ STRUCT_STAT st; -+ if (x_lstat(fbuf, &st, NULL) == 0) -+ make_mutable(fbuf, st.st_mode, st.st_flags, force_change); -+ } ++ if (force_change) ++ make_mutable(fbuf, NULL, NO_FFLAGS, force_change); +#endif ignore_perishable = 1; /* If DEL_RECURSE is not set, this just reports emptiness. */ ret = delete_dir_contents(fbuf, flags); -@@ -294,8 +303,12 @@ static enum delret delete_dir_contents(char *fname, uint16 flags) +@@ -285,8 +291,14 @@ static enum delret delete_dir_contents(char *fname, uint16 flags) } strlcpy(p, fp->basename, remainder); +#ifdef SUPPORT_FORCE_CHANGE -+ if (force_change) -+ make_mutable(fname, fp->mode, F_FFLAGS(fp), force_change); ++ if (force_change) { ++ mode_t mode = fp->mode; ++ make_mutable(fname, &mode, F_FFLAGS(fp), force_change); ++ } +#endif - if (!(fp->mode & S_IWUSR) && !am_root && (uid_t)F_OWNER(fp) == our_uid) + if (!(fp->mode & S_IWUSR) && !am_root && fp->flags & FLAG_OWNED_BY_US) - do_chmod(fname, fp->mode | S_IWUSR); + do_chmod(fname, fp->mode | S_IWUSR, NO_FFLAGS); /* Save stack by recursing to ourself directly. */ if (S_ISDIR(fp->mode)) { if (delete_dir_contents(fname, flags | DEL_RECURSE) != DR_SUCCESS) -@@ -599,6 +612,11 @@ int unchanged_attrs(const char *fname, struct file_struct *file, stat_x *sxp) - && ((sxp->st.st_mode & 0111 ? 1 : 0) ^ (file->mode & 0111 ? 1 : 0))) - return 0; - +@@ -647,6 +659,10 @@ int unchanged_attrs(const char *fname, struct file_struct *file, stat_x *sxp) + return 0; + if (perms_differ(file, sxp)) + return 0; +#ifdef SUPPORT_FILEFLAGS -+ if (preserve_fileflags && !S_ISLNK(file->mode) && sxp->st.st_flags != F_FFLAGS(file)) -+ return 0; ++ if (preserve_fileflags && sxp->st.st_flags != F_FFLAGS(file)) ++ return 0; +#endif -+ - if (am_root && uid_ndx && sxp->st.st_uid != (uid_t)F_OWNER(file)) - return 0; - -@@ -664,6 +682,11 @@ void itemize(const char *fnamecmp, struct file_struct *file, int ndx, int statre + if (ownership_differs(file, sxp)) + return 0; + #ifdef SUPPORT_ACLS +@@ -698,6 +714,11 @@ void itemize(const char *fnamecmp, struct file_struct *file, int ndx, int statre if (gid_ndx && !(file->flags & FLAG_SKIP_GROUP) && sxp->st.st_gid != (gid_t)F_GROUP(file)) iflags |= ITEM_REPORT_GROUP; @@ -247,7 +260,7 @@ #ifdef SUPPORT_ACLS if (preserve_acls && !S_ISLNK(file->mode)) { if (!ACL_READY(*sxp)) -@@ -1442,6 +1465,10 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx, +@@ -1491,6 +1512,10 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx, file->mode = dest_mode(file->mode, sx.st.st_mode, dflt_perms, statret == 0); } @@ -258,14 +271,16 @@ if (statret != 0 && basis_dir[0] != NULL) { int j = try_dests_non(file, fname, ndx, fnamecmpbuf, &sx, itemizing, code); -@@ -1482,10 +1509,15 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx, +@@ -1526,10 +1551,17 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx, /* We need to ensure that the dirs in the transfer have writable * permissions during the time we are putting files within them. * This is then fixed after the transfer is done. */ +#ifdef SUPPORT_FORCE_CHANGE -+ if (force_change && F_FFLAGS(file) & force_change -+ && make_mutable(fname, file->mode, F_FFLAGS(file), force_change)) -+ need_retouch_dir_perms = 1; ++ if (force_change && F_FFLAGS(file) & force_change) { ++ mode_t mode = file->mode; ++ if (make_mutable(fname, &mode, F_FFLAGS(file), force_change)) ++ need_retouch_dir_perms = 1; ++ } +#endif #ifdef HAVE_CHMOD if (!am_root && !(file->mode & S_IWUSR) && dir_tweaking) { @@ -275,7 +290,7 @@ rsyserr(FERROR_XFER, errno, "failed to modify permissions on %s", full_fname(fname)); -@@ -1520,6 +1552,10 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx, +@@ -1572,6 +1604,10 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx, file->mode = dest_mode(file->mode, sx.st.st_mode, dflt_perms, exists); } @@ -286,7 +301,7 @@ #ifdef SUPPORT_HARD_LINKS if (preserve_hard_links && F_HLINK_NOT_FIRST(file) -@@ -2061,13 +2097,17 @@ static void touch_up_dirs(struct file_list *flist, int ndx) +@@ -2115,13 +2151,17 @@ static void touch_up_dirs(struct file_list *flist, int ndx) continue; fname = f_name(file, NULL); if (fix_dir_perms) @@ -309,7 +324,7 @@ diff --git a/log.c b/log.c --- a/log.c +++ b/log.c -@@ -660,7 +660,7 @@ static void log_formatted(enum logcode code, const char *format, const char *op, +@@ -658,7 +658,7 @@ static void log_formatted(enum logcode code, const char *format, const char *op, c[5] = !(iflags & ITEM_REPORT_PERMS) ? '.' : 'p'; c[6] = !(iflags & ITEM_REPORT_OWNER) ? '.' : 'o'; c[7] = !(iflags & ITEM_REPORT_GROUP) ? '.' : 'g'; @@ -318,6 +333,50 @@ c[9] = !(iflags & ITEM_REPORT_ACL) ? '.' : 'a'; c[10] = !(iflags & ITEM_REPORT_XATTR) ? '.' : 'x'; c[11] = '\0'; +diff --git a/main.c b/main.c +--- a/main.c ++++ b/main.c +@@ -26,6 +26,9 @@ + #if defined CONFIG_LOCALE && defined HAVE_LOCALE_H + #include <locale.h> + #endif ++#ifdef SUPPORT_FORCE_CHANGE ++#include <sys/sysctl.h> ++#endif + + extern int verbose; + extern int dry_run; +@@ -51,6 +54,7 @@ extern int protocol_version; + extern int file_total; + extern int recurse; + extern int xfer_dirs; ++extern int force_change; + extern int protect_args; + extern int relative_paths; + extern int sanitize_paths; +@@ -753,6 +757,22 @@ static int do_recv(int f_in, int f_out, char *local_name) + * points to an identical file won't be replaced by the referent. */ + copy_links = copy_dirlinks = copy_unsafe_links = 0; + ++#ifdef SUPPORT_FORCE_CHANGE ++ if (force_change & SYS_IMMUTABLE) { ++ /* Determine whether we'll be able to unlock a system immutable item. */ ++ int mib[2]; ++ int securityLevel = 0; ++ size_t len = sizeof securityLevel; ++ ++ mib[0] = CTL_KERN; ++ mib[1] = KERN_SECURELVL; ++ if (sysctl(mib, 2, &securityLevel, &len, NULL, 0) == 0 && securityLevel > 0) { ++ rprintf(FERROR, "System security level is too high to force mutability on system immutable files and directories.\n"); ++ exit_cleanup(RERR_UNSUPPORTED); ++ } ++ } ++#endif ++ + #ifdef SUPPORT_HARD_LINKS + if (preserve_hard_links && !inc_recurse) + match_hard_links(first_flist); diff --git a/options.c b/options.c --- a/options.c +++ b/options.c @@ -335,9 +394,9 @@ int force_delete = 0; +int force_change = 0; int io_timeout = 0; - int allowed_lull = 0; int prune_empty_dirs = 0; -@@ -224,6 +226,7 @@ static void print_rsync_version(enum logcode f) + int use_qsort = 0; +@@ -223,6 +225,7 @@ static void print_rsync_version(enum logcode f) char const *links = "no "; char const *iconv = "no "; char const *ipv6 = "no "; @@ -345,8 +404,8 @@ STRUCT_STAT *dumstat; #if SUBPROTOCOL_VERSION != 0 -@@ -257,6 +260,9 @@ static void print_rsync_version(enum logcode f) - #if defined HAVE_LUTIMES && defined HAVE_UTIMES +@@ -256,6 +259,9 @@ static void print_rsync_version(enum logcode f) + #ifdef CAN_SET_SYMLINK_TIMES symtimes = ""; #endif +#ifdef SUPPORT_FILEFLAGS @@ -355,7 +414,7 @@ rprintf(f, "%s version %s protocol version %d%s\n", RSYNC_NAME, RSYNC_VERSION, PROTOCOL_VERSION, subprotocol); -@@ -270,8 +276,8 @@ static void print_rsync_version(enum logcode f) +@@ -269,8 +275,8 @@ static void print_rsync_version(enum logcode f) (int)(sizeof (int64) * 8)); rprintf(f, " %ssocketpairs, %shardlinks, %ssymlinks, %sIPv6, batchfiles, %sinplace,\n", got_socketpair, hardlinks, links, ipv6, have_inplace); @@ -366,7 +425,7 @@ #ifdef MAINTAINER_MODE rprintf(f, "Panic Action: \"%s\"\n", get_panic_action()); -@@ -338,6 +344,9 @@ void usage(enum logcode F) +@@ -337,6 +343,9 @@ void usage(enum logcode F) rprintf(F," -K, --keep-dirlinks treat symlinked dir on receiver as dir\n"); rprintf(F," -H, --hard-links preserve hard links\n"); rprintf(F," -p, --perms preserve permissions\n"); @@ -376,7 +435,7 @@ rprintf(F," -E, --executability preserve the file's executability\n"); rprintf(F," --chmod=CHMOD affect file and/or directory permissions\n"); #ifdef SUPPORT_ACLS -@@ -375,7 +384,12 @@ void usage(enum logcode F) +@@ -374,7 +383,12 @@ void usage(enum logcode F) rprintf(F," --delete-after receiver deletes after transfer, not during\n"); rprintf(F," --delete-excluded also delete excluded files from destination dirs\n"); rprintf(F," --ignore-errors delete even if there are I/O errors\n"); @@ -390,7 +449,7 @@ rprintf(F," --max-delete=NUM don't delete more than NUM files\n"); rprintf(F," --max-size=SIZE don't transfer any file larger than SIZE\n"); rprintf(F," --min-size=SIZE don't transfer any file smaller than SIZE\n"); -@@ -480,6 +494,10 @@ static struct poptOption long_options[] = { +@@ -479,6 +493,10 @@ static struct poptOption long_options[] = { {"perms", 'p', POPT_ARG_VAL, &preserve_perms, 1, 0, 0 }, {"no-perms", 0, POPT_ARG_VAL, &preserve_perms, 0, 0, 0 }, {"no-p", 0, POPT_ARG_VAL, &preserve_perms, 0, 0, 0 }, @@ -401,7 +460,7 @@ {"executability", 'E', POPT_ARG_NONE, &preserve_executability, 0, 0, 0 }, {"acls", 'A', POPT_ARG_NONE, 0, 'A', 0, 0 }, {"no-acls", 0, POPT_ARG_VAL, &preserve_acls, 0, 0, 0 }, -@@ -558,6 +576,14 @@ static struct poptOption long_options[] = { +@@ -557,6 +575,14 @@ static struct poptOption long_options[] = { {"remove-source-files",0,POPT_ARG_VAL, &remove_source_files, 1, 0, 0 }, {"force", 0, POPT_ARG_VAL, &force_delete, 1, 0, 0 }, {"no-force", 0, POPT_ARG_VAL, &force_delete, 0, 0, 0 }, @@ -416,7 +475,7 @@ {"ignore-errors", 0, POPT_ARG_VAL, &ignore_errors, 1, 0, 0 }, {"no-ignore-errors", 0, POPT_ARG_VAL, &ignore_errors, 0, 0, 0 }, {"max-delete", 0, POPT_ARG_INT, &max_delete, 0, 0, 0 }, -@@ -1874,6 +1900,9 @@ void server_options(char **args, int *argc_p) +@@ -1879,6 +1905,9 @@ void server_options(char **args, int *argc_p) if (xfer_dirs && !recurse && delete_mode && am_sender) args[ac++] = "--no-r"; @@ -426,7 +485,7 @@ if (do_compression && def_compress_level != Z_DEFAULT_COMPRESSION) { if (asprintf(&arg, "--compress-level=%d", def_compress_level) < 0) goto oom; -@@ -1961,6 +1990,16 @@ void server_options(char **args, int *argc_p) +@@ -1966,6 +1995,16 @@ void server_options(char **args, int *argc_p) args[ac++] = "--delete-excluded"; if (force_delete) args[ac++] = "--force"; @@ -446,7 +505,11 @@ diff --git a/rsync.c b/rsync.c --- a/rsync.c +++ b/rsync.c -@@ -32,6 +32,7 @@ extern int dry_run; +@@ -29,9 +29,11 @@ + + extern int verbose; + extern int dry_run; ++extern int force_change; extern int preserve_acls; extern int preserve_xattrs; extern int preserve_perms; @@ -454,7 +517,7 @@ extern int preserve_executability; extern int preserve_times; extern int am_root; -@@ -376,6 +377,39 @@ mode_t dest_mode(mode_t flist_mode, mode_t stat_mode, int dflt_perms, +@@ -374,6 +376,74 @@ mode_t dest_mode(mode_t flist_mode, mode_t stat_mode, int dflt_perms, return new_mode; } @@ -464,37 +527,94 @@ +{ + if (do_chflags(fname, fileflags) != 0) { + rsyserr(FERROR_XFER, errno, -+ "failed to set file flags on %s", -+ full_fname(fname)); ++ "failed to set fileflags (%x) on %s", ++ fileflags, 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) ++/* Remove immutable flags from an object, so it can be altered/removed. ++ * Returns the fileflags if flags were removed, otherwise 0. If the ++ * fileflags value is NO_FFLAGS, we will stat the fname to figure out ++ * what the flags are, and return the mode via *mode_ptr (if non-NULL). */ ++uint32 make_mutable(const char *fname, mode_t *mode_ptr, uint32 fileflags, uint32 iflags) +{ -+ if (S_ISLNK(mode) || !(fileflags & iflags)) ++ if (fileflags == NO_FFLAGS) { ++ STRUCT_STAT st; ++ if (x_lstat(fname, &st, NULL) < 0) ++ return 0; ++ fileflags = st.st_flags; ++ if (mode_ptr) ++ *mode_ptr = st.st_mode; ++ else ++ mode_ptr = &st.st_mode; ++ } ++ ++ if ((mode_ptr && S_ISLNK(*mode_ptr)) || !(fileflags & iflags)) + return 0; ++ + if (!set_fileflags(fname, fileflags & ~iflags)) -+ return -1; -+ return 1; ++ return 0; ++ ++ return fileflags; +} + +/* Undo a prior make_mutable() call that returned a 1. */ +int undo_make_mutable(const char *fname, uint32 fileflags) +{ -+ if (!set_fileflags(fname, fileflags)) ++ if (!set_fileflags(fname, fileflags)) { ++ rsyserr(FINFO, errno, "failed to relock %s", full_fname(fname)); + return -1; ++ } + return 1; +} ++ ++/* This returns the st_flags value if the parent directory was made mutable, otherwise 0. ++ * It stores the parent directory path into parent_dirbuf. */ ++int make_parentdir_mutable(const char *fname, uint32 iflags, char *parent_dirbuf, int parent_dirbuf_size) ++{ ++ char *slash = strrchr(fname, '/'); ++ ++ if (slash) { ++ int len = slash - fname; ++ if (len >= parent_dirbuf_size) ++ return 0; ++ strlcpy(parent_dirbuf, fname, len+1); ++ } else ++ strlcpy(parent_dirbuf, ".", parent_dirbuf_size); ++ ++ return make_mutable(parent_dirbuf, NULL, NO_FFLAGS, iflags); ++} +#endif + int set_file_attrs(const char *fname, struct file_struct *file, stat_x *sxp, const char *fnamecmp, int flags) { -@@ -429,7 +463,7 @@ int set_file_attrs(const char *fname, struct file_struct *file, stat_x *sxp, +@@ -382,6 +452,9 @@ int set_file_attrs(const char *fname, struct file_struct *file, stat_x *sxp, + int change_uid, change_gid; + mode_t new_mode = file->mode; + int inherit; ++#ifdef SUPPORT_FORCE_CHANGE ++ int became_mutable = 0; ++#endif + + if (!sxp) { + if (dry_run) +@@ -411,6 +484,11 @@ int set_file_attrs(const char *fname, struct file_struct *file, stat_x *sxp, + if (daemon_chmod_modes && !S_ISLNK(new_mode)) + new_mode = tweak_mode(new_mode, daemon_chmod_modes); + ++#ifdef SUPPORT_FORCE_CHANGE ++ if (force_change) ++ became_mutable = make_mutable(fname, &sxp->st.st_mode, sxp->st.st_flags, force_change); ++#endif ++ + #ifdef SUPPORT_ACLS + if (preserve_acls && !S_ISLNK(file->mode) && !ACL_READY(*sxp)) + get_acl(fname, sxp); +@@ -429,7 +507,7 @@ int set_file_attrs(const char *fname, struct file_struct *file, stat_x *sxp, flags |= ATTRS_SKIP_MTIME; if (!(flags & ATTRS_SKIP_MTIME) && cmp_time(sxp->st.st_mtime, file->modtime) != 0) { @@ -503,17 +623,16 @@ if (ret < 0) { rsyserr(FERROR_XFER, errno, "failed to set times on %s", full_fname(fname)); -@@ -465,7 +499,8 @@ int set_file_attrs(const char *fname, struct file_struct *file, stat_x *sxp, +@@ -465,7 +543,7 @@ int set_file_attrs(const char *fname, struct file_struct *file, stat_x *sxp, if (am_root >= 0) { - if (do_lchown(fname, - change_uid ? (uid_t)F_OWNER(file) : sxp->st.st_uid, -- change_gid ? (gid_t)F_GROUP(file) : sxp->st.st_gid) != 0) { -+ change_gid ? (gid_t)F_GROUP(file) : sxp->st.st_gid, -+ sxp->st.st_mode, ST_FLAGS(sxp->st)) != 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", -@@ -497,7 +532,7 @@ int set_file_attrs(const char *fname, struct file_struct *file, stat_x *sxp, +@@ -503,7 +581,7 @@ int set_file_attrs(const char *fname, struct file_struct *file, stat_x *sxp, #ifdef HAVE_CHMOD if (!BITS_EQUAL(sxp->st.st_mode, new_mode, CHMOD_BITS)) { @@ -522,10 +641,15 @@ if (ret < 0) { rsyserr(FERROR_XFER, errno, "failed to set permissions on %s", -@@ -509,6 +544,19 @@ int set_file_attrs(const char *fname, struct file_struct *file, stat_x *sxp, +@@ -515,6 +593,24 @@ int set_file_attrs(const char *fname, struct file_struct *file, stat_x *sxp, } #endif ++#ifdef SUPPORT_FORCE_CHANGE ++ if (became_mutable) ++ undo_make_mutable(fname, sxp->st.st_flags); ++#endif ++ +#ifdef SUPPORT_FILEFLAGS + if (preserve_fileflags && !S_ISLNK(sxp->st.st_mode) + && sxp->st.st_flags != F_FFLAGS(file)) { @@ -542,7 +666,7 @@ if (verbose > 1 && flags & ATTRS_REPORT) { if (updated) rprintf(FCLIENT, "%s\n", fname); -@@ -572,7 +620,8 @@ int finish_transfer(const char *fname, const char *fnametmp, +@@ -578,7 +674,8 @@ int finish_transfer(const char *fname, const char *fnametmp, /* Change permissions before putting the file into place. */ set_file_attrs(fnametmp, file, NULL, fnamecmp, @@ -552,7 +676,7 @@ /* move tmp file over real file */ if (verbose > 2) -@@ -591,6 +640,10 @@ int finish_transfer(const char *fname, const char *fnametmp, +@@ -597,6 +694,10 @@ int finish_transfer(const char *fname, const char *fnametmp, } if (ret == 0) { /* The file was moved into place (not copied), so it's done. */ @@ -574,7 +698,7 @@ /* These flags are used in the live flist data. */ -@@ -155,6 +156,7 @@ +@@ -160,6 +161,7 @@ #define ATTRS_REPORT (1<<0) #define ATTRS_SKIP_MTIME (1<<1) @@ -582,7 +706,7 @@ #define FULL_FLUSH 1 #define NORMAL_FLUSH 0 -@@ -181,6 +183,7 @@ +@@ -186,6 +188,7 @@ #define ITEM_REPORT_GROUP (1<<6) #define ITEM_REPORT_ACL (1<<7) #define ITEM_REPORT_XATTR (1<<8) @@ -590,7 +714,7 @@ #define ITEM_BASIS_TYPE_FOLLOWS (1<<11) #define ITEM_XNAME_FOLLOWS (1<<12) #define ITEM_IS_NEW (1<<13) -@@ -463,6 +466,28 @@ typedef unsigned int size_t; +@@ -482,6 +485,28 @@ typedef unsigned int size_t; #endif #endif @@ -619,7 +743,7 @@ /* Find a variable that is either exactly 32-bits or longer. * If some code depends on 32-bit truncation, it will need to * take special action in a "#if SIZEOF_INT32 > 4" section. */ -@@ -633,6 +658,7 @@ extern int file_extra_cnt; +@@ -652,6 +677,7 @@ extern int file_extra_cnt; extern int inc_recurse; extern int uid_ndx; extern int gid_ndx; @@ -627,7 +751,7 @@ extern int acls_ndx; extern int xattrs_ndx; -@@ -670,6 +696,11 @@ extern int xattrs_ndx; +@@ -689,6 +715,11 @@ extern int xattrs_ndx; /* When the associated option is on, all entries will have these present: */ #define F_OWNER(f) REQ_EXTRA(f, uid_ndx)->unum #define F_GROUP(f) REQ_EXTRA(f, gid_ndx)->unum @@ -672,7 +796,7 @@ dit(--no-OPTION) You may turn off one or more implied options by prefixing the option name with "no-". Not all options may be prefixed with a "no-": -@@ -809,7 +814,7 @@ they would be using bf(--copy-links). +@@ -827,7 +832,7 @@ they would be using bf(--copy-links). Without this option, if the sending side has replaced a directory with a symlink to a directory, the receiving side will delete anything that is in the way of the new symlink, including a directory hierarchy (as long as @@ -681,9 +805,9 @@ See also bf(--keep-dirlinks) for an analogous option for the receiving side. -@@ -946,6 +951,29 @@ super-user copies all namespaces except system.*. A normal user only copies - the user.* namespace. To be able to backup and restore non-user namespaces as - a normal user, see the bf(--fake-super) option. +@@ -990,6 +995,29 @@ Note that this option does not copy rsyncs special xattr values (e.g. those + used by bf(--fake-super)) unless you repeat the option (e.g. -XX). This + "copy all xattrs" mode cannot be used with bf(--fake-super). +dit(bf(--fileflags)) This option causes rsync to update the file-flags to be +the same as the source files and directories (if your OS supports the @@ -711,7 +835,7 @@ dit(bf(--chmod)) This option tells rsync to apply one or more comma-separated "chmod" strings to the permission of the files in the transfer. The resulting value is treated as though it were the permissions -@@ -1217,12 +1245,13 @@ See bf(--delete) (which is implied) for more details on file-deletion. +@@ -1260,12 +1288,13 @@ See bf(--delete) (which is implied) for more details on file-deletion. dit(bf(--ignore-errors)) Tells bf(--delete) to go ahead and delete files even when there are I/O errors. @@ -728,7 +852,7 @@ bf(--recursive) option was also enabled. dit(bf(--max-delete=NUM)) This tells rsync not to delete more than NUM -@@ -1688,7 +1717,7 @@ with older versions of rsync, but that also turns on the output of other +@@ -1753,7 +1782,7 @@ with older versions of rsync, but that also turns on the output of other verbose messages). The "%i" escape has a cryptic output that is 11 letters long. The general @@ -737,7 +861,7 @@ type of update being done, bf(X) is replaced by the file-type, and the other letters represent attributes that may be output if they are being modified. -@@ -1744,7 +1773,7 @@ quote(itemization( +@@ -1809,7 +1838,7 @@ quote(itemization( sender's value (requires bf(--owner) and super-user privileges). it() A bf(g) means the group is different and is being updated to the sender's value (requires bf(--group) and the authority to set the group). @@ -757,33 +881,90 @@ extern int preserve_perms; extern int preserve_executability; -@@ -50,7 +51,23 @@ int do_unlink(const char *fname) +@@ -50,14 +51,56 @@ int do_unlink(const char *fname) { if (dry_run) return 0; RETURN_ERROR_IF_RO_OR_LO; - return unlink(fname); + if (unlink(fname) == 0) + return 0; ++ +#ifdef SUPPORT_FORCE_CHANGE -+ if (force_change && errno == EPERM) { -+ STRUCT_STAT st; -+ -+ if (x_lstat(fname, &st, NULL) == 0 -+ && make_mutable(fname, st.st_mode, st.st_flags, force_change) > 0) { -+ if (unlink(fname) == 0) ++ if (force_change && (errno == EPERM || errno == EACCES)) { ++ char parent[MAXPATHLEN]; ++ int parent_flags; ++ int saved_errno = errno; ++ int file_flags = make_mutable(fname, NULL, NO_FFLAGS, force_change); ++ if (file_flags && unlink(fname) == 0) ++ return 0; ++ parent_flags = make_parentdir_mutable(fname, force_change, parent, sizeof parent); ++ if (parent_flags) { ++ int ret = unlink(fname); ++ undo_make_mutable(parent, parent_flags); ++ if (ret == 0) + return 0; -+ undo_make_mutable(fname, st.st_flags); + } -+ /* TODO: handle immutable directories */ -+ errno = EPERM; ++ if (file_flags) ++ undo_make_mutable(fname, file_flags); ++ errno = saved_errno; + } +#endif ++ + return -1; } int do_symlink(const char *fname1, const char *fname2) -@@ -69,14 +86,37 @@ int do_link(const char *fname1, const char *fname2) + { + if (dry_run) return 0; + RETURN_ERROR_IF_RO_OR_LO; +- return symlink(fname1, fname2); ++ if (symlink(fname1, fname2) == 0) ++ return 0; ++ ++#ifdef SUPPORT_FORCE_CHANGE ++ if (force_change && (errno == EPERM || errno == EACCES)) { ++ char parent[MAXPATHLEN]; ++ int saved_errno = errno; ++ int parent_flags = make_parentdir_mutable(fname2, force_change, parent, sizeof parent); ++ if (parent_flags) { ++ int ret = symlink(fname1, fname2); ++ undo_make_mutable(parent, parent_flags); ++ if (ret == 0) ++ return 0; ++ } ++ errno = saved_errno; ++ } ++#endif ++ ++ return -1; } + + #ifdef HAVE_LINK +@@ -65,18 +108,55 @@ int do_link(const char *fname1, const char *fname2) + { + if (dry_run) return 0; + RETURN_ERROR_IF_RO_OR_LO; +- return link(fname1, fname2); ++ if (link(fname1, fname2) == 0) ++ return 0; ++ ++#ifdef SUPPORT_FORCE_CHANGE ++ if (force_change && (errno == EPERM || errno == EACCES)) { ++ char parent[MAXPATHLEN]; ++ int saved_errno = errno; ++ int parent_flags = make_parentdir_mutable(fname2, force_change, parent, sizeof parent); ++ if (parent_flags) { ++ int ret = link(fname1, fname2); ++ undo_make_mutable(parent, parent_flags); ++ if (ret == 0) ++ return 0; ++ } ++ errno = saved_errno; ++ } ++#endif ++ ++ return -1; + } #endif -int do_lchown(const char *path, uid_t owner, gid_t group) @@ -797,32 +978,28 @@ - return lchown(path, owner, group); + if (lchown(path, owner, group) == 0) + return 0; ++ +#ifdef SUPPORT_FORCE_CHANGE -+ if (force_change && errno == EPERM) { -+ if (fileflags == NO_FFLAGS) { -+ STRUCT_STAT st; -+ if (x_lstat(path, &st, NULL) == 0) { -+ mode = st.st_mode; -+ fileflags = st.st_flags; -+ } -+ } -+ if (fileflags != NO_FFLAGS -+ && make_mutable(path, mode, fileflags, force_change) > 0) { ++ if (force_change && (errno == EPERM || errno == EACCES)) { ++ int saved_errno = errno; ++ fileflags = make_mutable(path, &mode, fileflags, force_change); ++ if (fileflags) { + int ret = lchown(path, owner, group); + undo_make_mutable(path, fileflags); + if (ret == 0) + return 0; + } -+ errno = EPERM; ++ errno = saved_errno; + } +#else + mode = fileflags = 0; /* avoid compiler warning */ +#endif ++ + return -1; } int do_mknod(const char *pathname, mode_t mode, dev_t dev) -@@ -116,7 +156,7 @@ int do_mknod(const char *pathname, mode_t mode, dev_t dev) +@@ -116,7 +196,7 @@ int do_mknod(const char *pathname, mode_t mode, dev_t dev) return -1; close(sock); #ifdef HAVE_CHMOD @@ -831,31 +1008,65 @@ #else return 0; #endif -@@ -133,7 +173,22 @@ int do_rmdir(const char *pathname) +@@ -133,21 +213,63 @@ int do_rmdir(const char *pathname) { if (dry_run) return 0; RETURN_ERROR_IF_RO_OR_LO; - return rmdir(pathname); + if (rmdir(pathname) == 0) + return 0; ++ +#ifdef SUPPORT_FORCE_CHANGE -+ if (force_change && errno == EPERM) { -+ STRUCT_STAT st; -+ -+ if (x_lstat(pathname, &st, NULL) == 0 -+ && make_mutable(pathname, st.st_mode, st.st_flags, force_change) > 0) { -+ if (rmdir(pathname) == 0) ++ if (force_change && (errno == EPERM || errno == EACCES)) { ++ char parent[MAXPATHLEN]; ++ int parent_flags; ++ int saved_errno = errno; ++ int file_flags = make_mutable(pathname, NULL, NO_FFLAGS, force_change); ++ if (file_flags && rmdir(pathname) == 0) ++ return 0; ++ parent_flags = make_parentdir_mutable(pathname, force_change, parent, sizeof parent); ++ if (parent_flags) { ++ int ret = rmdir(pathname); ++ undo_make_mutable(parent, parent_flags); ++ if (ret == 0) + return 0; -+ undo_make_mutable(pathname, st.st_flags); + } -+ errno = EPERM; ++ if (file_flags) ++ undo_make_mutable(pathname, file_flags); ++ errno = saved_errno; + } +#endif ++ + return -1; } int do_open(const char *pathname, int flags, mode_t mode) -@@ -147,7 +202,7 @@ int do_open(const char *pathname, int flags, mode_t mode) + { ++ int fd; + if (flags != O_RDONLY) { + RETURN_ERROR_IF(dry_run, 0); + RETURN_ERROR_IF_RO_OR_LO; + } ++ if ((fd = open(pathname, flags | O_BINARY, mode)) >= 0) ++ return fd; ++ ++#ifdef SUPPORT_FORCE_CHANGE ++ if (force_change && (errno == EPERM || errno == EACCES)) { ++ char parent[MAXPATHLEN]; ++ int saved_errno = errno; ++ int parent_flags = make_parentdir_mutable(pathname, force_change, parent, sizeof parent); ++ if (parent_flags) { ++ fd = open(pathname, flags | O_BINARY, mode); ++ undo_make_mutable(parent, parent_flags); ++ if (fd >= 0) ++ return fd; ++ } ++ errno = saved_errno; ++ } ++#endif + +- return open(pathname, flags | O_BINARY, mode); ++ return -1; } #ifdef HAVE_CHMOD @@ -864,25 +1075,25 @@ { int code; if (dry_run) return 0; -@@ -168,17 +223,74 @@ int do_chmod(const char *path, mode_t mode) - #endif +@@ -170,17 +292,93 @@ int do_chmod(const char *path, mode_t mode) } else code = chmod(path, mode & CHMOD_BITS); /* DISCOURAGED FUNCTION */ + #endif /* !HAVE_LCHMOD */ +#ifdef SUPPORT_FORCE_CHANGE -+ if (code < 0 && force_change && errno == EPERM && !S_ISLNK(mode)) { -+ if (fileflags == NO_FFLAGS) { -+ STRUCT_STAT st; -+ if (x_lstat(path, &st, NULL) == 0) -+ fileflags = st.st_flags; -+ } -+ if (fileflags != NO_FFLAGS -+ && make_mutable(path, mode, fileflags, force_change) > 0) { ++ if (code < 0 && force_change && (errno == EPERM || errno == EACCES) && !S_ISLNK(mode)) { ++ int saved_errno = errno; ++ fileflags = make_mutable(path, &mode, fileflags, force_change); ++ if (fileflags) { ++#ifdef HAVE_LCHMOD ++ code = lchmod(path, mode & CHMOD_BITS); ++#else + code = chmod(path, mode & CHMOD_BITS); ++#endif + undo_make_mutable(path, fileflags); + if (code == 0) + return 0; + } -+ errno = EPERM; ++ errno = saved_errno; + } +#else + fileflags = 0; /* avoid compiler warning */ @@ -909,37 +1120,237 @@ - return rename(fname1, fname2); + if (rename(fname1, fname2) == 0) + return 0; ++ +#ifdef SUPPORT_FORCE_CHANGE -+ if (force_change && errno == EPERM) { -+ STRUCT_STAT st1, st2; -+ int became_mutable; ++ if (force_change && (errno == EPERM || errno == EACCES)) { ++ int saved_errno = errno; ++ int ret = -1, file2_flags = 0; ++ int file1_flags = make_mutable(fname1, NULL, NO_FFLAGS, force_change); ++ if (file1_flags && rename(fname1, fname2) == 0) ++ ret = 0; ++ else { ++ file2_flags = make_mutable(fname2, NULL, NO_FFLAGS, force_change); ++ if (file2_flags && rename(fname1, fname2) == 0) ++ ret = 0; ++ else { ++ char parent1[MAXPATHLEN]; ++ int parent1_flags = make_parentdir_mutable(fname1, force_change, ++ parent1, sizeof parent1); ++ if (parent1_flags && rename(fname1, fname2) == 0) ++ ret = 0; ++ else { ++ char parent2[MAXPATHLEN]; ++ int parent2_flags = make_parentdir_mutable(fname2, force_change, ++ parent2, sizeof parent2); ++ if (parent2_flags) { ++ if (rename(fname1, fname2) == 0) ++ ret = 0; ++ undo_make_mutable(parent2, parent2_flags); ++ } ++ } ++ if (parent1_flags) ++ undo_make_mutable(parent1, parent1_flags); ++ } ++ } + -+ if (x_lstat(fname1, &st1, NULL) != 0) -+ goto failed; -+ became_mutable = make_mutable(fname1, st1.st_mode, st1.st_flags, force_change) > 0; -+ if (became_mutable && rename(fname1, fname2) == 0) -+ goto success; -+ if (x_lstat(fname2, &st2, NULL) == 0 -+ && make_mutable(fname2, st2.st_mode, st2.st_flags, force_change) > 0) { -+ if (rename(fname1, fname2) == 0) { -+ success: -+ if (became_mutable) /* Yes, use fname2 and st1! */ -+ undo_make_mutable(fname2, st1.st_flags); ++ if (ret == 0) ++ file2_flags = file1_flags; /* file1 is now file2 */ ++ else if (file1_flags) ++ undo_make_mutable(fname1, file1_flags); ++ if (file2_flags) ++ undo_make_mutable(fname2, file2_flags); ++ if (ret == 0) ++ return 0; ++ ++ errno = saved_errno; ++ } ++#endif ++ ++ return -1; + } + + #ifdef HAVE_FTRUNCATE +@@ -222,7 +420,25 @@ int do_mkdir(char *fname, mode_t mode) + if (dry_run) return 0; + RETURN_ERROR_IF_RO_OR_LO; + trim_trailing_slashes(fname); +- return mkdir(fname, mode); ++ if (mkdir(fname, mode) == 0) ++ return 0; ++ ++#ifdef SUPPORT_FORCE_CHANGE ++ if (force_change && (errno == EPERM || errno == EACCES)) { ++ char parent[MAXPATHLEN]; ++ int saved_errno = errno; ++ int parent_flags = make_parentdir_mutable(fname, force_change, parent, sizeof parent); ++ if (parent_flags) { ++ int ret = mkdir(fname, mode); ++ undo_make_mutable(parent, parent_flags); ++ if (ret == 0) + return 0; ++ } ++ errno = saved_errno; ++ } ++#endif ++ ++ return -1; + } + + /* like mkstemp but forces permissions */ +@@ -235,7 +451,19 @@ int do_mkstemp(char *template, mode_t perms) + #if defined HAVE_SECURE_MKSTEMP && defined HAVE_FCHMOD && (!defined HAVE_OPEN64 || defined HAVE_MKSTEMP64) + { + int fd = mkstemp(template); +- if (fd == -1) ++#ifdef SUPPORT_FORCE_CHANGE ++ if (fd < 0 && force_change) { ++ char parent[MAXPATHLEN]; ++ int saved_errno = errno; ++ int parent_flags = make_parentdir_mutable(template, force_change, parent, sizeof parent); ++ if (parent_flags) { ++ fd = mkstemp(template); ++ undo_make_mutable(parent, parent_flags); + } -+ undo_make_mutable(fname2, st2.st_flags); ++ errno = saved_errno; + } -+ /* TODO: handle immutable directories */ -+ if (became_mutable) -+ undo_make_mutable(fname1, st1.st_flags); -+ failed: -+ errno = EPERM; ++#endif ++ if (fd < 0) + return -1; + if (fchmod(fd, perms) != 0 && preserve_perms) { + int errno_save = errno; +@@ -302,7 +530,7 @@ OFF_T do_lseek(int fd, OFF_T offset, int whence) + } + + #ifdef HAVE_UTIMENSAT +-int do_utimensat(const char *fname, time_t modtime, uint32 mod_nsec) ++int do_utimensat(const char *fname, time_t modtime, uint32 mod_nsec, mode_t mode, uint32 fileflags) + { + struct timespec t[2]; + +@@ -313,12 +541,26 @@ int do_utimensat(const char *fname, time_t modtime, uint32 mod_nsec) + t[0].tv_nsec = UTIME_NOW; + t[1].tv_sec = modtime; + t[1].tv_nsec = mod_nsec; +- return utimensat(AT_FDCWD, fname, t, AT_SYMLINK_NOFOLLOW); ++ if (utimensat(AT_FDCWD, fname, t, AT_SYMLINK_NOFOLLOW) == 0) ++ return 0; ++ ++#ifdef SUPPORT_FORCE_CHANGE ++ fileflags = make_mutable(fname, &mode, fileflags, force_change); ++ if (fileflags) { ++ if (utimensat(AT_FDCWD, fname, t, AT_SYMLINK_NOFOLLOW) == 0) ++ return 0; ++ undo_make_mutable(fname, fileflags); + } ++#else ++ mode = fileflags; /* avoid compiler warning */ +#endif ++ + return -1; } + #endif - void trim_trailing_slashes(char *name) + #ifdef HAVE_LUTIMES +-int do_lutimes(const char *fname, time_t modtime, uint32 mod_nsec) ++int do_lutimes(const char *fname, time_t modtime, uint32 mod_nsec, mode_t mode, uint32 fileflags) + { + struct timeval t[2]; + +@@ -329,12 +571,26 @@ int do_lutimes(const char *fname, time_t modtime, uint32 mod_nsec) + t[0].tv_usec = 0; + t[1].tv_sec = modtime; + t[1].tv_usec = mod_nsec / 1000; +- return lutimes(fname, t); ++ if (lutimes(fname, t) == 0) ++ return 0; ++ ++#ifdef SUPPORT_FORCE_CHANGE ++ fileflags = make_mutable(fname, &mode, fileflags, force_change); ++ if (fileflags) { ++ if (lutimes(fname, t) == 0) ++ return 0; ++ undo_make_mutable(fname, fileflags); ++ } ++#else ++ mode = fileflags; /* avoid compiler warning */ ++#endif ++ ++ return -1; + } + #endif + + #ifdef HAVE_UTIMES +-int do_utimes(const char *fname, time_t modtime, uint32 mod_nsec) ++int do_utimes(const char *fname, time_t modtime, uint32 mod_nsec, mode_t mode, uint32 fileflags) + { + struct timeval t[2]; + +@@ -345,14 +601,28 @@ int do_utimes(const char *fname, time_t modtime, uint32 mod_nsec) + t[0].tv_usec = 0; + t[1].tv_sec = modtime; + t[1].tv_usec = mod_nsec / 1000; +- return utimes(fname, t); ++ if (utimes(fname, t) == 0) ++ return 0; ++ ++#ifdef SUPPORT_FORCE_CHANGE ++ fileflags = make_mutable(fname, &mode, fileflags, force_change); ++ if (fileflags) { ++ if (utimes(fname, t) == 0) ++ return 0; ++ undo_make_mutable(fname, fileflags); ++ } ++#else ++ mode = fileflags; /* avoid compiler warning */ ++#endif ++ ++ return -1; + } + + #elif defined HAVE_UTIME +-int do_utime(const char *fname, time_t modtime, UNUSED(uint32 mod_nsec)) ++int do_utime(const char *fname, time_t modtime, UNUSED(uint32 mod_nsec), mode_t mode, uint32 fileflags) + { + #ifdef HAVE_STRUCT_UTIMBUF +- struct utimbuf tbuf; ++ struct utimbuf tbuf, *t = &tbuf; + #else + time_t t[2]; + #endif +@@ -360,15 +630,28 @@ int do_utime(const char *fname, time_t modtime, UNUSED(uint32 mod_nsec)) + if (dry_run) return 0; + RETURN_ERROR_IF_RO_OR_LO; + +-# ifdef HAVE_STRUCT_UTIMBUF ++#ifdef HAVE_STRUCT_UTIMBUF + tbuf.actime = time(NULL); + tbuf.modtime = modtime; +- return utime(fname, &tbuf); +-# else ++#else + t[0] = time(NULL); + t[1] = modtime; +- return utime(fname, t); +-# endif ++#endif ++ if (utime(fname, t) == 0) ++ return 0; ++ ++#ifdef SUPPORT_FORCE_CHANGE ++ fileflags = make_mutable(fname, &mode, fileflags, force_change); ++ if (fileflags) { ++ if (utime(fname, t) == 0) ++ return 0; ++ undo_make_mutable(fname, fileflags); ++ } ++#else ++ mode = fileflags; /* avoid compiler warning */ ++#endif ++ ++ return -1; + } + + #else diff --git a/t_stub.c b/t_stub.c --- a/t_stub.c +++ b/t_stub.c @@ -948,25 +1359,29 @@ int human_readable = 0; int module_dirlen = 0; +int force_change = 0; + int preserve_times = 0; int preserve_xattrs = 0; mode_t orig_umask = 002; - char *partial_dir; -@@ -89,3 +90,23 @@ struct filter_list_struct daemon_filter_list; +@@ -90,3 +91,27 @@ struct filter_list_struct daemon_filter_list; { return "tester"; } + +#if defined SUPPORT_FILEFLAGS || defined SUPPORT_FORCE_CHANGE -+ int make_mutable(UNUSED(const char *fname), UNUSED(mode_t mode), UNUSED(uint32 fileflags), UNUSED(uint32 iflags)) ++ uint32 make_mutable(UNUSED(const char *fname), UNUSED(mode_t *mode), UNUSED(uint32 fileflags), UNUSED(uint32 iflags)) +{ + return 0; +} + -+/* Undo a prior make_mutable() call that returned a 1. */ + int undo_make_mutable(UNUSED(const char *fname), UNUSED(uint32 fileflags)) +{ + return 0; +} ++ ++ int make_parentdir_mutable(UNUSED(const char *fname), UNUSED(uint32 iflags), UNUSED(char *parent_dirbuf), UNUSED(int parent_dirbuf_size)) ++{ ++ return 0; ++} +#endif + +#ifdef SUPPORT_XATTRS @@ -978,101 +1393,50 @@ diff --git a/util.c b/util.c --- a/util.c +++ b/util.c -@@ -29,6 +29,7 @@ extern int module_id; - extern int modify_window; - extern int relative_paths; - extern int human_readable; -+extern int force_change; - extern int preserve_xattrs; - extern char *module_dir; - extern unsigned int module_dirlen; -@@ -123,7 +124,7 @@ NORETURN void overflow_exit(const char *str) - exit_cleanup(RERR_MALLOC); - } +@@ -125,7 +125,7 @@ NORETURN void overflow_exit(const char *str) + /* 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, mode_t mode) +int set_modtime(const char *fname, time_t modtime, mode_t mode, uint32 fileflags) { - #if !defined HAVE_LUTIMES || !defined HAVE_UTIMES - if (S_ISLNK(mode)) -@@ -140,6 +141,7 @@ int set_modtime(const char *fname, time_t modtime, mode_t mode) - return 0; + static int switch_step = 0; - { -+ int ret; +@@ -138,7 +138,7 @@ int set_modtime(const char *fname, time_t modtime, mode_t mode) + switch (switch_step) { + #ifdef HAVE_UTIMENSAT + #include "case_N.h" +- if (do_utimensat(fname, modtime, 0) == 0) ++ if (do_utimensat(fname, modtime, 0, mode, fileflags) == 0) + break; + if (errno != ENOSYS) + return -1; +@@ -148,7 +148,7 @@ int set_modtime(const char *fname, time_t modtime, mode_t mode) + + #ifdef HAVE_LUTIMES + #include "case_N.h" +- if (do_lutimes(fname, modtime, 0) == 0) ++ if (do_lutimes(fname, modtime, 0, mode, fileflags) == 0) + break; + if (errno != ENOSYS) + return -1; +@@ -167,10 +167,10 @@ int set_modtime(const char *fname, time_t modtime, mode_t mode) + + #include "case_N.h" #ifdef HAVE_UTIMES - struct timeval t[2]; - t[0].tv_sec = time(NULL); -@@ -153,20 +155,39 @@ int set_modtime(const char *fname, time_t modtime, mode_t mode) - return 0; - } - # endif -- return utimes(fname, t); -+#define SET_THE_TIME(fn) utimes(fn, t) - #elif defined HAVE_STRUCT_UTIMBUF - struct utimbuf tbuf; - tbuf.actime = time(NULL); - tbuf.modtime = modtime; -- return utime(fname,&tbuf); -+#define SET_THE_TIME(fn) utime(fn, &tbuf) - #elif defined HAVE_UTIME - time_t t[2]; - t[0] = time(NULL); - t[1] = modtime; -- return utime(fname,t); -+#define SET_THE_TIME(fn) utime(fn, t) +- if (do_utimes(fname, modtime, 0) == 0) ++ if (do_utimes(fname, modtime, 0, mode, fileflags) == 0) + break; #else - #error No file-time-modification routine found! +- if (do_utime(fname, modtime, 0) == 0) ++ if (do_utime(fname, modtime, 0, mode, fileflags) == 0) + break; #endif -+ ret = SET_THE_TIME(fname); -+#ifdef SUPPORT_FORCE_CHANGE -+ if (ret != 0 && force_change && errno == EPERM) { -+ if (fileflags == NO_FFLAGS) { -+ STRUCT_STAT st; -+ if (x_lstat(fname, &st, NULL) == 0) -+ fileflags = st.st_flags; -+ } -+ if (fileflags != NO_FFLAGS -+ && make_mutable(fname, mode, fileflags, force_change) > 0) { -+ ret = SET_THE_TIME(fname); -+ undo_make_mutable(fname, fileflags); -+ } -+ errno = EPERM; -+ } -+#else -+ fileflags = 0; /* avoid compiler warning */ -+#endif -+ return ret; - } - } diff --git a/xattrs.c b/xattrs.c --- a/xattrs.c +++ b/xattrs.c -@@ -283,6 +283,10 @@ int get_xattr(const char *fname, stat_x *sxp) - { - sxp->xattr = new(item_list); - *sxp->xattr = empty_xattr; -+ -+ if (IS_SPECIAL(sxp->st.st_mode) || IS_DEVICE(sxp->st.st_mode)) -+ return 0; -+ - if (rsync_xal_get(fname, sxp->xattr) < 0) { - free_xattr(sxp); - return -1; -@@ -883,6 +887,11 @@ int set_xattr(const char *fname, const struct file_struct *file, - return -1; - } - -+ if (IS_SPECIAL(sxp->st.st_mode) || IS_DEVICE(sxp->st.st_mode)) { -+ errno = ENOTSUP; -+ return -1; -+ } -+ - ndx = F_XATTR(file); - return rsync_xal_set(fname, lst + ndx, fnamecmp, sxp); - } -@@ -999,7 +1008,7 @@ int set_stat_xattr(const char *fname, struct file_struct *file, mode_t new_mode) +@@ -1041,7 +1041,7 @@ int set_stat_xattr(const char *fname, struct file_struct *file, mode_t new_mode) mode = (fst.st_mode & _S_IFMT) | (fmode & ACCESSPERMS) | (S_ISDIR(fst.st_mode) ? 0700 : 0600); if (fst.st_mode != mode) @@ -1097,7 +1461,7 @@ diff -up a/configure.sh b/configure.sh --- a/configure.sh +++ b/configure.sh -@@ -7351,6 +7351,7 @@ fi +@@ -7425,6 +7425,7 @@ fi for ac_func in waitpid wait4 getcwd strdup chown chmod lchmod mknod mkfifo \ fchmod fstat ftruncate strchr readlink link utime utimes lutimes strftime \ @@ -1108,16 +1472,17 @@ diff -up a/proto.h b/proto.h --- a/proto.h +++ b/proto.h -@@ -274,6 +274,8 @@ int read_ndx_and_attrs(int f_in, int *if +@@ -274,6 +274,9 @@ int read_ndx_and_attrs(int f_in, int *if void free_sums(struct sum_struct *s); mode_t dest_mode(mode_t flist_mode, mode_t stat_mode, int dflt_perms, int exists); -+int make_mutable(const char *fname, mode_t mode, uint32 fileflags, uint32 iflags); ++uint32 make_mutable(const char *fname, mode_t *mode_ptr, uint32 fileflags, uint32 iflags); +int undo_make_mutable(const char *fname, uint32 fileflags); ++int make_parentdir_mutable(const char *fname, uint32 iflags, char *parent_dirbuf, int parent_dirbuf_size); int set_file_attrs(const char *fname, struct file_struct *file, stat_x *sxp, const char *fnamecmp, int flags); RETSIGTYPE sig_int(UNUSED(int val)); -@@ -298,11 +300,12 @@ int sock_exec(const char *prog); +@@ -297,11 +300,12 @@ void set_socket_options(int fd, char *op int do_unlink(const char *fname); int do_symlink(const char *fname1, const char *fname2); int do_link(const char *fname1, const char *fname2); @@ -1130,9 +1495,24 @@ +int do_chmod(const char *path, mode_t mode, uint32 fileflags); +int do_chflags(const char *path, uint32 fileflags); int do_rename(const char *fname1, const char *fname2); + int do_ftruncate(int fd, OFF_T size); void trim_trailing_slashes(char *name); - int do_mkdir(char *fname, mode_t mode); -@@ -330,7 +333,7 @@ int fd_pair(int fd[2]); +@@ -311,10 +315,10 @@ int do_stat(const char *fname, STRUCT_ST + int do_lstat(const char *fname, STRUCT_STAT *st); + int do_fstat(int fd, STRUCT_STAT *st); + OFF_T do_lseek(int fd, OFF_T offset, int whence); +-int do_utimensat(const char *fname, time_t modtime, uint32 mod_nsec); +-int do_lutimes(const char *fname, time_t modtime, uint32 mod_nsec); +-int do_utimes(const char *fname, time_t modtime, uint32 mod_nsec); +-int do_utime(const char *fname, time_t modtime, UNUSED(uint32 mod_nsec)); ++int do_utimensat(const char *fname, time_t modtime, uint32 mod_nsec, mode_t mode, uint32 fileflags); ++int do_lutimes(const char *fname, time_t modtime, uint32 mod_nsec, mode_t mode, uint32 fileflags); ++int do_utimes(const char *fname, time_t modtime, uint32 mod_nsec, mode_t mode, uint32 fileflags); ++int do_utime(const char *fname, time_t modtime, UNUSED(uint32 mod_nsec), mode_t mode, uint32 fileflags); + void set_compression(const char *fname); + void send_token(int f, int32 token, struct map_struct *buf, OFF_T offset, + int32 n, int32 toklen); +@@ -334,7 +338,7 @@ int fd_pair(int fd[2]); void print_child_argv(const char *prefix, char **cmd); NORETURN void out_of_memory(const char *str); NORETURN void overflow_exit(const char *str); @@ -1144,37 +1524,37 @@ diff -up a/rsync.1 b/rsync.1 --- a/rsync.1 +++ b/rsync.1 -@@ -417,6 +417,7 @@ to the detailed description below for a +@@ -417,6 +417,7 @@ to the detailed description below for a \-K, \-\-keep\-dirlinks treat symlinked dir on receiver as dir \-H, \-\-hard\-links preserve hard links \-p, \-\-perms preserve permissions -+ \-\-fileflags preserve file-flags (aka chflags) ++ \-\-fileflags preserve file\-flags (aka chflags) \-E, \-\-executability preserve executability \-\-chmod=CHMOD affect file and/or directory permissions \-A, \-\-acls preserve ACLs (implies \-p) -@@ -448,7 +449,10 @@ to the detailed description below for a +@@ -448,7 +449,10 @@ to the detailed description below for a \-\-delete\-after receiver deletes after transfer, not before \-\-delete\-excluded also delete excluded files from dest dirs \-\-ignore\-errors delete even if there are I/O errors - \-\-force force deletion of dirs even if not empty + \-\-force\-delete force deletion of dirs even if not empty + \-\-force\-change affect user/system immutable files/dirs -+ \-\-force\-uchange affect user-immutable files/dirs -+ \-\-force\-schange affect system-immutable files/dirs ++ \-\-force\-uchange affect user\-immutable files/dirs ++ \-\-force\-schange affect system\-immutable files/dirs \-\-max\-delete=NUM don'\&t delete more than NUM files \-\-max\-size=SIZE don'\&t transfer any file larger than SIZE \-\-min\-size=SIZE don'\&t transfer any file smaller than SIZE @@ -638,7 +642,8 @@ specified, in which case \fB\-r\fP is no .IP Note that \fB\-a\fP \fBdoes not preserve hardlinks\fP, because - finding multiply-linked files is expensive. You must separately + finding multiply\-linked files is expensive. You must separately -specify \fB\-H\fP. +specify \fB\-H\fP. Note also that for backward compatibility, \fB\-a\fP +currently does \fBnot\fP imply the \fB\-\-fileflags\fP option. .IP .IP "\-\-no\-OPTION" You may turn off one or more implied options by prefixing -@@ -931,7 +936,7 @@ they would be using \fB\-\-copy\-links\f +@@ -955,7 +960,7 @@ they would be using \fB\-\-copy\-links\f Without this option, if the sending side has replaced a directory with a symlink to a directory, the receiving side will delete anything that is in the way of the new symlink, including a directory hierarchy (as long as @@ -1183,68 +1563,68 @@ .IP See also \fB\-\-keep\-dirlinks\fP for an analogous option for the receiving side. -@@ -1086,6 +1091,33 @@ super-user copies all namespaces except - the user.* namespace. To be able to backup and restore non-user namespaces as - a normal user, see the \fB\-\-fake\-super\fP option. +@@ -1142,6 +1147,33 @@ Note that this option does not copy rsyn + used by \fB\-\-fake\-super\fP) unless you repeat the option (e.g. \-XX). This + \(dq\© all xattrs\(dq\& mode cannot be used with \fB\-\-fake\-super\fP. .IP +.IP "\fB\-\-fileflags\fP" -+This option causes rsync to update the file-flags to be ++This option causes rsync to update the file\-flags to be +the same as the source files and directories (if your OS supports the -+\fBchflags\fP(2) system call). Some flags can only be altered by the super-user -+and some might only be unset below a certain secure-level (usually single-user ++\fBchflags\fP(2) system call). Some flags can only be altered by the super\-user ++and some might only be unset below a certain secure\-level (usually single\-user +mode). It will not make files alterable that are set to immutable on the +receiver. To do that, see \fB\-\-force\-change\fP, \fB\-\-force\-uchange\fP, and +\fB\-\-force\-schange\fP. +.IP +.IP "\fB\-\-force\-change\fP" -+This option causes rsync to disable both user-immutable -+and system-immutable flags on files and directories that are being updated or ++This option causes rsync to disable both user\-immutable ++and system\-immutable flags on files and directories that are being updated or +deleted on the receiving side. This option overrides \fB\-\-force\-uchange\fP and +\fB\-\-force\-schange\fP. +.IP +.IP "\fB\-\-force\-uchange\fP" -+This option causes rsync to disable user-immutable ++This option causes rsync to disable user\-immutable +flags on files and directories that are being updated or deleted on the +receiving side. It does not try to affect system flags. This option overrides +\fB\-\-force\-change\fP and \fB\-\-force\-schange\fP. +.IP +.IP "\fB\-\-force\-schange\fP" -+This option causes rsync to disable system-immutable ++This option causes rsync to disable system\-immutable +flags on files and directories that are being updated or deleted on the +receiving side. It does not try to affect user flags. This option overrides +\fB\-\-force\-change\fP and \fB\-\-force\-schange\fP. +.IP .IP "\fB\-\-chmod\fP" This option tells rsync to apply one or more - comma-separated \(dq\&chmod\(dq\& strings to the permission of the files in the -@@ -1387,13 +1419,14 @@ See \fB\-\-delete\fP (which is implied) + comma\-separated \(dq\&chmod\(dq\& strings to the permission of the files in the +@@ -1442,13 +1474,14 @@ See \fB\-\-delete\fP (which is implied) Tells \fB\-\-delete\fP to go ahead and delete files even when there are I/O errors. .IP -.IP "\fB\-\-force\fP" +.IP "\fB\-\-force\-delete\fP" - This option tells rsync to delete a non-empty directory - when it is to be replaced by a non-directory. This is only relevant if + This option tells rsync to delete a non\-empty directory + when it is to be replaced by a non\-directory. This is only relevant if deletions are not active (see \fB\-\-delete\fP for details). .IP -Note for older rsync versions: \fB\-\-force\fP used to still be required when --using \fB\-\-delete\-after\fP, and it used to be non-functional unless the +-using \fB\-\-delete\-after\fP, and it used to be non\-functional unless the +This option can be abbreviated \fB\-\-force\fP for backward compatibility. +Note that some older rsync versions used to still require \fB\-\-force\fP -+when using \fB\-\-delete\-after\fP, and it used to be non-functional unless the ++when using \fB\-\-delete\-after\fP, and it used to be non\-functional unless the \fB\-\-recursive\fP option was also enabled. .IP .IP "\fB\-\-max\-delete=NUM\fP" -@@ -1930,7 +1963,7 @@ with older versions of rsync, but that a +@@ -2004,7 +2037,7 @@ with older versions of rsync, but that a verbose messages). .IP The \(dq\&%i\(dq\& escape has a cryptic output that is 11 letters long. The general -format is like the string \fBYXcstpoguax\fP, where \fBY\fP is replaced by the +format is like the string \fBYXcstpogfax\fP, where \fBY\fP is replaced by the - type of update being done, \fBX\fP is replaced by the file-type, and the + type of update being done, \fBX\fP is replaced by the file\-type, and the other letters represent attributes that may be output if they are being modified. -@@ -2000,7 +2033,7 @@ sender\(cq\&s value (requires \fB\-\-own +@@ -2074,7 +2107,7 @@ sender\(cq\&s value (requires \fB\-\-own A \fBg\fP means the group is different and is being updated to the sender\(cq\&s value (requires \fB\-\-group\fP and the authority to set the group). .IP o