Ticket #44117: rsync-3.1.1-final.patch
File rsync-3.1.1-final.patch, 119.8 KB (added by jimjag (Jim Jagielski), 10 years ago) |
---|
-
rsync/Portfile
diff --git a/rsync/Portfile b/rsync/Portfile index cc6131e..0ac93be 100644
a b 4 4 PortSystem 1.0 5 5 6 6 name rsync 7 version 3. 0.98 revision 27 version 3.1.1 8 revision 0 9 9 categories net 10 10 license GPL-3+ 11 11 installs_libs no … … homepage http://samba.org/rsync/ 21 21 master_sites http://rsync.samba.org/ftp/rsync/ \ 22 22 http://rsync.samba.org/ftp/rsync/src/ 23 23 24 checksums md5 5ee72266fe2c1822333c407e1761b92b\25 sha1 c 64c8341984aea647506eb504496999fd968ddfc\26 rmd160 e5ee8d786defb0d8f937c8d027466f418c63c97e\27 sha256 30f10f8dd5490d28240d4271bb652b1da7a60b22ed2b9ae28090668de9247c0524 checksums md5 43bd6676f0b404326eee2d63be3cdcfe \ 25 sha1 c84faba04f721d393feccfa0476bfeed9b5b5250 \ 26 rmd160 de7ad955cb05d481a963aa30423790f3d82efe7b \ 27 sha256 7de4364fcf5fe42f3bdb514417f1c40d10bbca896abe7e7f2c581c6ea08a2621 28 28 29 29 depends_lib port:popt port:libiconv 30 30 31 # these come from http://rsync.samba.org/ftp/rsync/rsync-patches-3. 0.9.tar.gz31 # these come from http://rsync.samba.org/ftp/rsync/rsync-patches-3.1.1.tar.gz 32 32 # and need to be updated with each release 33 33 patchfiles patch-fileflags.diff \ 34 34 patch-crtimes.diff \ … … patchfiles patch-fileflags.diff \ 38 38 patch.pre_args -p1 39 39 40 40 configure.args --with-rsyncd-conf=${prefix}/etc/rsyncd.conf 41 configure.cflags "-Os -I${prefix}/include"42 41 43 42 pre-configure { 44 43 system "cd ${worksrcpath}; ./prepare-source" -
rsync/files/patch-crtimes.diff
diff --git a/rsync/files/patch-crtimes.diff b/rsync/files/patch-crtimes.diff index b0db0fd..33d0a44 100644
a b To use this patch, run these commands for a successful build: 9 9 ./configure 10 10 make 11 11 12 based-on: patch/ b3.0.x/fileflags12 based-on: patch/master/fileflags 13 13 diff --git a/compat.c b/compat.c 14 14 --- a/compat.c 15 15 +++ b/compat.c 16 @@ -4 7,6 +47,7 @@ extern int force_change;16 @@ -48,6 +48,7 @@ extern int force_change; 17 17 extern int protect_args; 18 18 extern int preserve_uid; 19 19 extern int preserve_gid; … … diff --git a/compat.c b/compat.c 21 21 extern int preserve_fileflags; 22 22 extern int preserve_acls; 23 23 extern int preserve_xattrs; 24 @@ -6 5,7 +66,7 @@ extern char *iconv_opt;24 @@ -66,7 +67,7 @@ extern char *iconv_opt; 25 25 #endif 26 26 27 27 /* These index values are for the file-list's extra-attribute array. */ … … diff --git a/compat.c b/compat.c 30 30 31 31 int receiver_symlink_times = 0; /* receiver can set the time on a symlink */ 32 32 int sender_symlink_iconv = 0; /* sender should convert symlink content */ 33 @@ -14 2,6 +143,8 @@ void setup_protocol(int f_out,int f_in)33 @@ -144,6 +145,8 @@ void setup_protocol(int f_out,int f_in) 34 34 uid_ndx = ++file_extra_cnt; 35 35 if (preserve_gid) 36 36 gid_ndx = ++file_extra_cnt; … … diff --git a/compat.c b/compat.c 42 42 diff --git a/flist.c b/flist.c 43 43 --- a/flist.c 44 44 +++ b/flist.c 45 @@ -54,6 +54,7 @@ extern int preserve_specials; 46 extern int preserve_fileflags; 45 @@ -54,6 +54,7 @@ extern int preserve_fileflags; 47 46 extern int delete_during; 47 extern int missing_args; 48 48 extern int eol_nulls; 49 49 +extern int crtimes_ndx; 50 50 extern int relative_paths; 51 51 extern int implied_dirs; 52 52 extern int ignore_perishable; 53 @@ -39 3,7 +394,7 @@ static void send_file_entry(int f, const char *fname, struct file_struct *file,53 @@ -398,7 +399,7 @@ static void send_file_entry(int f, const char *fname, struct file_struct *file, 54 54 #endif 55 55 int ndx, int first_ndx) 56 56 { … … diff --git a/flist.c b/flist.c 59 59 static mode_t mode; 60 60 #ifdef SUPPORT_FILEFLAGS 61 61 static uint32 fileflags; 62 @@ -488,6 +489,13 @@ static void send_file_entry(int f, const char *fname, struct file_struct *file, 63 xflags |= XMIT_SAME_TIME; 64 else 62 @@ -509,6 +510,13 @@ static void send_file_entry(int f, const char *fname, struct file_struct *file, 65 63 modtime = file->modtime; 64 if (NSEC_BUMP(file) && protocol_version >= 31) 65 xflags |= XMIT_MOD_NSEC; 66 66 + if (crtimes_ndx) { 67 67 + time_t file_crtime = f_crtime(file); 68 68 + if (file_crtime == modtime) … … diff --git a/flist.c b/flist.c 73 73 74 74 #ifdef SUPPORT_HARD_LINKS 75 75 if (tmp_dev != -1) { 76 @@ -557,6 +565,8 @@ static void send_file_entry(int f, const char *fname, struct file_struct *file, 77 else 78 write_int(f, modtime); 76 @@ -593,6 +601,8 @@ static void send_file_entry(int f, const char *fname, struct file_struct *file, 79 77 } 78 if (xflags & XMIT_MOD_NSEC) 79 write_varint(f, F_MOD_NSEC(file)); 80 80 + if (crtimes_ndx && !(xflags & XMIT_CRTIME_EQ_MTIME)) 81 81 + write_varlong(f, crtime, 4); 82 82 if (!(xflags & XMIT_SAME_MODE)) 83 83 write_int(f, to_wire_mode(mode)); 84 84 #ifdef SUPPORT_FILEFLAGS 85 @@ -6 48,7 +658,7 @@ static void send_file_entry(int f, const char *fname, struct file_struct *file,85 @@ -686,7 +696,7 @@ static void send_file_entry(int f, const char *fname, struct file_struct *file, 86 86 87 87 static struct file_struct *recv_file_entry(int f, struct file_list *flist, int xflags) 88 88 { … … diff --git a/flist.c b/flist.c 91 91 static mode_t mode; 92 92 #ifdef SUPPORT_FILEFLAGS 93 93 static uint32 fileflags; 94 @@ -758,6 +768,8 @@ static struct file_struct *recv_file_entry(int f, struct file_list *flist, int x 95 uid = F_OWNER(first); 96 if (preserve_gid) 97 gid = F_GROUP(first); 98 + if (crtimes_ndx) 99 + crtime = f_crtime(first); 100 if (preserve_devices && IS_DEVICE(mode)) { 101 uint32 *devp = F_RDEV_P(first); 102 rdev = MAKEDEV(DEV_MAJOR(devp), DEV_MINOR(devp)); 103 @@ -786,6 +798,19 @@ static struct file_struct *recv_file_entry(int f, struct file_list *flist, int x 104 } else 105 modtime = read_int(f); 106 } 94 @@ -838,6 +848,19 @@ static struct file_struct *recv_file_entry(int f, struct file_list *flist, int x 95 modtime_nsec = read_varint(f); 96 else 97 modtime_nsec = 0; 107 98 + if (crtimes_ndx) { 108 99 + if (!(xflags & XMIT_CRTIME_EQ_MTIME)) { 109 100 + crtime = read_varlong(f, 4); … … diff --git a/flist.c b/flist.c 120 111 if (!(xflags & XMIT_SAME_MODE)) 121 112 mode = from_wire_mode(read_int(f)); 122 113 123 @@ - 946,6 +971,8 @@ static struct file_struct *recv_file_entry(int f, struct file_list *flist, int x114 @@ -1015,6 +1038,8 @@ static struct file_struct *recv_file_entry(int f, struct file_list *flist, int x 124 115 F_GROUP(file) = gid; 125 116 file->flags |= gid_flags; 126 117 } … … diff --git a/flist.c b/flist.c 129 120 if (unsort_ndx) 130 121 F_NDX(file) = flist->used + flist->ndx_start; 131 122 132 @@ -1 324,6 +1351,8 @@ struct file_struct *make_file(const char *fname, struct file_list *flist,123 @@ -1416,6 +1441,8 @@ struct file_struct *make_file(const char *fname, struct file_list *flist, 133 124 F_GROUP(file) = st.st_gid; 134 125 if (am_generator && st.st_uid == our_uid) 135 126 file->flags |= FLAG_OWNED_BY_US; … … diff --git a/flist.c b/flist.c 141 132 diff --git a/generator.c b/generator.c 142 133 --- a/generator.c 143 134 +++ b/generator.c 144 @@ -21,6 +21,7 @@ 145 */ 146 147 #include "rsync.h" 148 +#include "ifuncs.h" 149 150 extern int verbose; 151 extern int dry_run; 152 @@ -41,6 +42,7 @@ extern int preserve_xattrs; 135 @@ -40,6 +40,7 @@ extern int preserve_xattrs; 153 136 extern int preserve_links; 154 137 extern int preserve_devices; 155 138 extern int preserve_specials; … … diff --git a/generator.c b/generator.c 157 140 extern int preserve_hard_links; 158 141 extern int preserve_executability; 159 142 extern int preserve_fileflags; 160 @@ - 576,8 +578,15 @@ static void do_delete_pass(void)143 @@ -384,8 +385,15 @@ static void do_delete_pass(void) 161 144 rprintf(FINFO, " \r"); 162 145 } 163 146 … … diff --git a/generator.c b/generator.c 174 157 return cmp_time(sxp->st.st_mtime, file->modtime); 175 158 } 176 159 177 @@ - 635,7 +644,7 @@ int unchanged_attrs(const char *fname, struct file_struct *file, stat_x *sxp)160 @@ -443,7 +451,7 @@ int unchanged_attrs(const char *fname, struct file_struct *file, stat_x *sxp) 178 161 { 179 162 if (S_ISLNK(file->mode)) { 180 163 #ifdef CAN_SET_SYMLINK_TIMES … … diff --git a/generator.c b/generator.c 183 166 return 0; 184 167 #endif 185 168 #ifdef CAN_CHMOD_SYMLINK 186 @@ - 655,7 +664,7 @@ int unchanged_attrs(const char *fname, struct file_struct *file, stat_x *sxp)169 @@ -463,7 +471,7 @@ int unchanged_attrs(const char *fname, struct file_struct *file, stat_x *sxp) 187 170 return 0; 188 171 #endif 189 172 } else { … … diff --git a/generator.c b/generator.c 192 175 return 0; 193 176 if (perms_differ(file, sxp)) 194 177 return 0; 195 @@ - 698,6 +707,12 @@ void itemize(const char *fnamecmp, struct file_struct *file, int ndx, int statre178 @@ -506,6 +514,12 @@ void itemize(const char *fnamecmp, struct file_struct *file, int ndx, int statre 196 179 : iflags & (ITEM_TRANSFER|ITEM_LOCAL_CHANGE) && !(iflags & ITEM_MATCHED) 197 180 && (!(iflags & ITEM_XNAME_FOLLOWS) || *xname)) 198 181 iflags |= ITEM_REPORT_TIME; … … diff --git a/generator.c b/generator.c 205 188 #if !defined HAVE_LCHMOD && !defined HAVE_SETATTRLIST 206 189 if (S_ISLNK(file->mode)) { 207 190 ; 208 @@ -1263,7 +1278,7 @@ static int try_dests_non(struct file_struct *file, char *fname, int ndx, 209 191 @@ -1130,6 +1144,7 @@ static int try_dests_non(struct file_struct *file, char *fname, int ndx, 210 192 static void list_file_entry(struct file_struct *f) 211 193 { 212 - char permbuf[PERMSTRING_SIZE]; 213 + char permbuf[PERMSTRING_SIZE], crtime_buf[32]; 214 double len; 215 216 if (!F_IS_ACTIVE(f)) { 217 @@ -1274,19 +1289,24 @@ static void list_file_entry(struct file_struct *f) 218 permstring(permbuf, f->mode); 219 len = F_LENGTH(f); 194 char permbuf[PERMSTRING_SIZE]; 195 + time_t crtime = crtimes_ndx ? f_crtime(f) : 0; 196 int64 len; 197 int colwidth = human_readable ? 14 : 11; 220 198 221 + if (crtimes_ndx) 222 + snprintf(crtime_buf, sizeof crtime_buf, " %s", timestring(f_crtime(f))); 223 + else 224 + *crtime_buf = '\0'; 225 + 226 /* TODO: indicate '+' if the entry has an ACL. */ 199 @@ -1145,10 +1160,12 @@ static void list_file_entry(struct file_struct *f) 227 200 228 201 #ifdef SUPPORT_LINKS 229 202 if (preserve_links && S_ISLNK(f->mode)) { 230 - rprintf(FINFO, "%s %11.0f %s %s -> %s\n", 231 + rprintf(FINFO, "%s %11.0f %s%s %s -> %s\n", 232 permbuf, len, timestring(f->modtime), 233 - f_name(f, NULL), F_SYMLINK(f)); 234 + crtime_buf, f_name(f, NULL), F_SYMLINK(f)); 203 - rprintf(FINFO, "%s %*s %s %s -> %s\n", 204 + rprintf(FINFO, "%s %*s %s%s%s %s -> %s\n", 205 permbuf, colwidth, human_num(len), 206 - timestring(f->modtime), f_name(f, NULL), 207 - F_SYMLINK(f)); 208 + timestring(f->modtime), 209 + crtimes_ndx ? " " : "", 210 + crtimes_ndx ? timestring(crtime) : "", 211 + f_name(f, NULL), F_SYMLINK(f)); 235 212 } else 236 213 #endif 237 { 238 - rprintf(FINFO, "%s %11.0f %s %s\n", 239 + rprintf(FINFO, "%s %11.0f %s%s %s\n", 240 permbuf, len, timestring(f->modtime), 241 - f_name(f, NULL)); 242 + crtime_buf, f_name(f, NULL)); 214 if (missing_args == 2 && f->mode == 0) { 215 @@ -1156,9 +1173,12 @@ static void list_file_entry(struct file_struct *f) 216 colwidth + 31, "*missing", 217 f_name(f, NULL)); 218 } else { 219 - rprintf(FINFO, "%s %*s %s %s\n", 220 + rprintf(FINFO, "%s %*s %s%s%s %s\n", 221 permbuf, colwidth, human_num(len), 222 - timestring(f->modtime), f_name(f, NULL)); 223 + timestring(f->modtime), 224 + crtimes_ndx ? " " : "", 225 + crtimes_ndx ? timestring(crtime) : "", 226 + f_name(f, NULL)); 243 227 } 244 228 } 245 229 246 @@ -1 383,6 +1403,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,230 @@ -1250,6 +1270,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx, 247 231 return; 248 232 } 249 233 } 250 234 + sx.crtime = 0; 251 235 252 236 if (dry_run > 1 || (dry_missing_dir && is_below(file, dry_missing_dir))) { 253 parent_is_dry_missing: 254 diff --git a/hlink.c b/hlink.c 255 --- a/hlink.c 256 +++ b/hlink.c 257 @@ -371,6 +371,7 @@ int hard_link_check(struct file_struct *file, int ndx, const char *fname, 258 char cmpbuf[MAXPATHLEN]; 259 stat_x alt_sx; 260 int j = 0; 261 + alt_sx.crtime = 0; 262 #ifdef SUPPORT_ACLS 263 alt_sx.acc_acl = alt_sx.def_acl = NULL; 264 #endif 265 @@ -499,6 +500,7 @@ void finish_hard_link(struct file_struct *file, const char *fname, int fin_ndx, 266 } else 267 our_name = fname; 268 269 + prev_sx.crtime = 0; 270 #ifdef SUPPORT_ACLS 271 prev_sx.acc_acl = prev_sx.def_acl = NULL; 272 #endif 237 int i; 273 238 diff --git a/ifuncs.h b/ifuncs.h 274 239 --- a/ifuncs.h 275 240 +++ b/ifuncs.h 276 @@ - 67,6 +67,28 @@ d_name(struct dirent *di)277 #endif241 @@ -43,6 +43,28 @@ free_xbuf(xbuf *xb) 242 memset(xb, 0, sizeof (xbuf)); 278 243 } 279 244 280 245 +static inline time_t … … diff --git a/ifuncs.h b/ifuncs.h 300 265 +} 301 266 + 302 267 static inline int 303 isDigit(const char *ptr)268 to_wire_mode(mode_t mode) 304 269 { 305 270 diff --git a/log.c b/log.c 306 271 --- a/log.c 307 272 +++ b/log.c 308 @@ - 661,7 +661,8 @@ static void log_formatted(enum logcode code, const char *format, const char *op,273 @@ -723,7 +723,8 @@ static void log_formatted(enum logcode code, const char *format, const char *op, 309 274 c[8] = !(iflags & ITEM_REPORT_FFLAGS) ? '.' : 'f'; 310 275 c[9] = !(iflags & ITEM_REPORT_ACL) ? '.' : 'a'; 311 276 c[10] = !(iflags & ITEM_REPORT_XATTR) ? '.' : 'x'; … … diff --git a/log.c b/log.c 318 283 diff --git a/options.c b/options.c 319 284 --- a/options.c 320 285 +++ b/options.c 321 @@ -6 0,6 +60,7 @@ int preserve_specials = 0;286 @@ -62,6 +62,7 @@ int preserve_specials = 0; 322 287 int preserve_uid = 0; 323 288 int preserve_gid = 0; 324 289 int preserve_times = 0; … … diff --git a/options.c b/options.c 326 291 int update_only = 0; 327 292 int cvs_exclude = 0; 328 293 int dry_run = 0; 329 @@ -361,6 +362,7 @@ void usage(enum logcode F) 294 @@ -718,6 +719,7 @@ void usage(enum logcode F) 295 rprintf(F," --specials preserve special files\n"); 330 296 rprintf(F," -D same as --devices --specials\n"); 331 297 rprintf(F," -t, --times preserve modification times\n"); 332 rprintf(F," -O, --omit-dir-times omit directories from --times\n");333 298 + rprintf(F," -N, --crtimes preserve create times (newness)\n"); 299 rprintf(F," -O, --omit-dir-times omit directories from --times\n"); 300 rprintf(F," -J, --omit-link-times omit symlinks from --times\n"); 334 301 rprintf(F," --super receiver attempts super-user activities\n"); 335 #ifdef SUPPORT_XATTRS 336 rprintf(F," --fake-super store/recover privileged attrs using xattrs\n"); 337 @@ -507,6 +509,9 @@ static struct poptOption long_options[] = { 302 @@ -885,6 +887,9 @@ static struct poptOption long_options[] = { 338 303 {"times", 't', POPT_ARG_VAL, &preserve_times, 1, 0, 0 }, 339 304 {"no-times", 0, POPT_ARG_VAL, &preserve_times, 0, 0, 0 }, 340 305 {"no-t", 0, POPT_ARG_VAL, &preserve_times, 0, 0, 0 }, … … diff --git a/options.c b/options.c 344 309 {"omit-dir-times", 'O', POPT_ARG_VAL, &omit_dir_times, 1, 0, 0 }, 345 310 {"no-omit-dir-times",0, POPT_ARG_VAL, &omit_dir_times, 0, 0, 0 }, 346 311 {"no-O", 0, POPT_ARG_VAL, &omit_dir_times, 0, 0, 0 }, 347 @@ - 1810,6 +1815,8 @@ void server_options(char **args, int *argc_p)312 @@ -2465,6 +2470,8 @@ void server_options(char **args, int *argc_p) 348 313 argstr[x++] = 'D'; 349 314 if (preserve_times) 350 315 argstr[x++] = 't'; … … diff --git a/options.c b/options.c 356 321 diff --git a/rsync.c b/rsync.c 357 322 --- a/rsync.c 358 323 +++ b/rsync.c 359 @@ -464,6 +464,7 @@ int set_file_attrs(const char *fname, struct file_struct *file, stat_x *sxp, 360 full_fname(fname)); 361 return 0; 362 } 363 + sx2.crtime = 0; 364 #ifdef SUPPORT_ACLS 365 sx2.acc_acl = sx2.def_acl = NULL; 366 #endif 367 @@ -505,6 +506,9 @@ int set_file_attrs(const char *fname, struct file_struct *file, stat_x *sxp, 324 @@ -581,6 +581,9 @@ int set_file_attrs(const char *fname, struct file_struct *file, stat_x *sxp, 368 325 || (!(preserve_times & PRESERVE_DIR_TIMES) && S_ISDIR(sxp->st.st_mode)) 369 326 || (!(preserve_times & PRESERVE_LINK_TIMES) && S_ISLNK(sxp->st.st_mode))) 370 327 flags |= ATTRS_SKIP_MTIME; … … diff --git a/rsync.c b/rsync.c 373 330 + flags |= ATTRS_SKIP_CRTIME; 374 331 if (!(flags & ATTRS_SKIP_MTIME) 375 332 && cmp_time(sxp->st.st_mtime, file->modtime) != 0) { 376 int ret = set_modtime(fname, file->modtime, sxp->st.st_mode, ST_FLAGS(sxp->st));377 @@ -5 18,6 +522,14 @@ int set_file_attrs(const char *fname, struct file_struct *file, stat_x *sxp,333 int ret = set_modtime(fname, file->modtime, F_MOD_NSEC(file), sxp->st.st_mode, ST_FLAGS(sxp->st)); 334 @@ -594,6 +597,14 @@ int set_file_attrs(const char *fname, struct file_struct *file, stat_x *sxp, 378 335 else 379 336 file->flags |= FLAG_TIME_FAILED; 380 337 } … … diff --git a/rsync.c b/rsync.c 387 344 + updated = 1; 388 345 + } 389 346 390 change_uid = am_root && uid_ndx && sxp->st.st_uid != (uid_t)F_OWNER(file);391 change_gid = gid_ndx && !(file->flags & FLAG_SKIP_GROUP)392 @@ - 675,7 +687,7 @@ int finish_transfer(const char *fname, const char *fnametmp,347 #ifdef SUPPORT_ACLS 348 /* It's OK to call set_acl() now, even for a dir, as the generator 349 @@ -710,7 +721,7 @@ int finish_transfer(const char *fname, const char *fnametmp, 393 350 /* Change permissions before putting the file into place. */ 394 351 set_file_attrs(fnametmp, file, NULL, fnamecmp, 395 352 ATTRS_DELAY_IMMUTABLE … … diff --git a/rsync.c b/rsync.c 397 354 + | (ok_to_set_time ? 0 : ATTRS_SKIP_MTIME | ATTRS_SKIP_CRTIME)); 398 355 399 356 /* move tmp file over real file */ 400 if ( verbose > 2)401 @@ -7 06,7 +718,7 @@ int finish_transfer(const char *fname, const char *fnametmp,357 if (DEBUG_GTE(RECV, 1)) 358 @@ -739,7 +750,7 @@ int finish_transfer(const char *fname, const char *fnametmp, 402 359 403 360 do_set_file_attrs: 404 361 set_file_attrs(fnametmp, file, NULL, fnamecmp, … … diff --git a/rsync.c b/rsync.c 410 367 diff --git a/rsync.h b/rsync.h 411 368 --- a/rsync.h 412 369 +++ b/rsync.h 413 @@ -61,6 +61,7 @@ 414 #define XMIT_GROUP_NAME_FOLLOWS (1<<11) /* protocols 30 - now */ 370 @@ -62,7 +62,8 @@ 415 371 #define XMIT_HLINK_FIRST (1<<12) /* protocols 30 - now (HLINKED files only) */ 416 372 #define XMIT_IO_ERROR_ENDLIST (1<<12) /* protocols 31*- now (w/XMIT_EXTENDED_FLAGS) (also protocol 30 w/'f' compat flag) */ 417 +#define XMIT_CRTIME_EQ_MTIME (1<<13) /* protocols ?? - now */ 418 #define XMIT_SAME_FLAGS (1<<14) /* protocols ?? - now */ 373 #define XMIT_MOD_NSEC (1<<13) /* protocols 31 - now */ 374 -#define XMIT_SAME_FLAGS (1<<14) /* protocols ?? - now */ 375 +#define XMIT_CRTIME_EQ_MTIME (1<<14) /* protocols ?? - now */ 376 +#define XMIT_SAME_FLAGS (1<<15) /* protocols ?? - now */ 419 377 420 378 /* These flags are used in the live flist data. */ 421 @@ -162,6 +163,7 @@ 379 380 @@ -167,6 +168,7 @@ 422 381 #define ATTRS_REPORT (1<<0) 423 382 #define ATTRS_SKIP_MTIME (1<<1) 424 383 #define ATTRS_DELAY_IMMUTABLE (1<<2) … … diff --git a/rsync.h b/rsync.h 426 385 427 386 #define FULL_FLUSH 1 428 387 #define NORMAL_FLUSH 0 429 @@ -1 78,7 +180,7 @@388 @@ -183,7 +185,7 @@ 430 389 #define FNAMECMP_FUZZY 0x83 431 390 432 391 /* For use by the itemize_changes code */ … … diff --git a/rsync.h b/rsync.h 435 394 #define ITEM_REPORT_CHANGE (1<<1) 436 395 #define ITEM_REPORT_SIZE (1<<2) /* regular files only */ 437 396 #define ITEM_REPORT_TIMEFAIL (1<<2) /* symlinks only */ 438 @@ - 677,6 +679,7 @@ extern int file_extra_cnt;397 @@ -734,6 +736,7 @@ extern int file_extra_cnt; 439 398 extern int inc_recurse; 440 399 extern int uid_ndx; 441 400 extern int gid_ndx; … … diff --git a/rsync.h b/rsync.h 443 402 extern int fileflags_ndx; 444 403 extern int acls_ndx; 445 404 extern int xattrs_ndx; 446 @@ - 684,6 +687,7 @@ extern int xattrs_ndx;405 @@ -741,6 +744,7 @@ extern int xattrs_ndx; 447 406 #define FILE_STRUCT_LEN (offsetof(struct file_struct, basename)) 448 407 #define EXTRA_LEN (sizeof (union file_extras)) 449 408 #define PTR_EXTRA_CNT ((sizeof (char *) + EXTRA_LEN - 1) / EXTRA_LEN) … … diff --git a/rsync.h b/rsync.h 451 410 #define DEV_EXTRA_CNT 2 452 411 #define DIRNODE_EXTRA_CNT 3 453 412 #define SUM_EXTRA_CNT ((MAX_DIGEST_LEN + EXTRA_LEN - 1) / EXTRA_LEN) 454 @@ - 951,6 +955,7 @@ typedef struct {413 @@ -1022,6 +1026,7 @@ typedef struct { 455 414 456 415 typedef struct { 457 416 STRUCT_STAT st; … … diff --git a/rsync.h b/rsync.h 462 421 diff --git a/rsync.yo b/rsync.yo 463 422 --- a/rsync.yo 464 423 +++ b/rsync.yo 465 @@ -367,6 +367,7 @@ to the detailed description below for a complete description. verb( 424 @@ -373,6 +373,7 @@ to the detailed description below for a complete description. verb( 425 --specials preserve special files 466 426 -D same as --devices --specials 467 427 -t, --times preserve modification times 468 -O, --omit-dir-times omit directories from --times469 428 + -N, --crtimes preserve create times (newness) 429 -O, --omit-dir-times omit directories from --times 430 -J, --omit-link-times omit symlinks from --times 470 431 --super receiver attempts super-user activities 471 --fake-super store/recover privileged attrs using xattrs 472 -S, --sparse handle sparse files efficiently 473 @@ -1105,6 +1106,9 @@ it is preserving modification times (see bf(--times)). If NFS is sharing 474 the directories on the receiving side, it is a good idea to use bf(-O). 475 This option is inferred if you use bf(--backup) without bf(--backup-dir). 432 @@ -1201,6 +1202,9 @@ cause the next transfer to behave as if it used bf(-I), causing all files to be 433 updated (though rsync's delta-transfer algorithm will make the update fairly efficient 434 if the files haven't actually changed, you're much better off using bf(-t)). 476 435 477 436 +dit(bf(-N, --crtimes)) This tells rsync to set the create times (newness) of 478 437 +the destination files to the same value as the source files. 479 438 + 480 dit(bf(- -super)) This tells the receiving side to attempt super-user481 activities even if the receiving rsync wasn't run by the super-user. These482 activities include: preserving users via the bf(--owner) option, preserving483 @@ - 1811,7 +1815,7 @@ with older versions of rsync, but that also turns on the output of other439 dit(bf(-O, --omit-dir-times)) This tells rsync to omit directories when 440 it is preserving modification times (see bf(--times)). If NFS is sharing 441 the directories on the receiving side, it is a good idea to use bf(-O). 442 @@ -2103,7 +2107,7 @@ with older versions of rsync, but that also turns on the output of other 484 443 verbose messages). 485 444 486 445 The "%i" escape has a cryptic output that is 11 letters long. The general … … diff --git a/rsync.yo b/rsync.yo 489 448 type of update being done, bf(X) is replaced by the file-type, and the 490 449 other letters represent attributes that may be output if they are being 491 450 modified. 492 @@ - 1870,6 +1874,8 @@ quote(itemization(451 @@ -2162,6 +2166,8 @@ quote(itemization( 493 452 it() The bf(f) means that the fileflags information changed. 494 453 it() The bf(a) means that the ACL information changed. 495 454 it() The bf(x) means that the extended attribute information changed. … … diff --git a/rsync.yo b/rsync.yo 501 460 diff --git a/syscall.c b/syscall.c 502 461 --- a/syscall.c 503 462 +++ b/syscall.c 504 @@ - 37,6 +37,13 @@ extern int force_change;463 @@ -42,6 +42,13 @@ extern int force_change; 505 464 extern int preserve_perms; 506 465 extern int preserve_executability; 507 466 … … diff --git a/syscall.c b/syscall.c 515 474 #define RETURN_ERROR_IF(x,e) \ 516 475 do { \ 517 476 if (x) { \ 518 @@ - 529,6 +536,36 @@ OFF_T do_lseek(int fd, OFF_T offset, int whence)477 @@ -460,6 +467,36 @@ OFF_T do_lseek(int fd, OFF_T offset, int whence) 519 478 #endif 520 479 } 521 480 … … diff --git a/syscall.c b/syscall.c 550 509 +} 551 510 + 552 511 #ifdef HAVE_UTIMENSAT 553 int do_utimensat(const char *fname, time_t modtime, uint32 mod_nsec , mode_t mode, uint32 fileflags)512 int do_utimensat(const char *fname, time_t modtime, uint32 mod_nsec) 554 513 { 555 514 diff --git a/testsuite/crtimes.test b/testsuite/crtimes.test 556 515 new file mode 100644 … … new file mode 100644 584 543 diff --git a/testsuite/rsync.fns b/testsuite/rsync.fns 585 544 --- a/testsuite/rsync.fns 586 545 +++ b/testsuite/rsync.fns 587 @@ -2 4,9 +24,9 @@ todir="$tmpdir/to"546 @@ -23,9 +23,9 @@ todir="$tmpdir/to" 588 547 chkdir="$tmpdir/chk" 589 548 590 549 # For itemized output: … … diff --git a/testsuite/rsync.fns b/testsuite/rsync.fns 600 559 diff --git a/tls.c b/tls.c 601 560 --- a/tls.c 602 561 +++ b/tls.c 603 @@ -10 7,6 +107,8 @@ static int stat_xattr(const char *fname, STRUCT_STAT *fst)562 @@ -109,6 +109,8 @@ static int stat_xattr(const char *fname, STRUCT_STAT *fst) 604 563 605 564 #endif 606 565 … … diff --git a/tls.c b/tls.c 609 568 static void failed(char const *what, char const *where) 610 569 { 611 570 fprintf(stderr, PROGRAM ": %s %s: %s\n", 612 @@ -11 4,16 +116,36@@ static void failed(char const *what, char const *where)571 @@ -116,16 +118,44 @@ static void failed(char const *what, char const *where) 613 572 exit(1); 614 573 } 615 574 616 +static void storetime(char *dest, time_t t, size_t destsize)575 +static void storetime(char *dest, size_t destsize, time_t t, int nsecs) 617 576 +{ 618 577 + if (t) { 578 + int len; 619 579 + struct tm *mt = gmtime(&t); 620 580 + 621 + snprintf(dest, destsize,622 + "%04d-%02d-%02d %02d:%02d:%02d 581 + len = snprintf(dest, destsize, 582 + "%04d-%02d-%02d %02d:%02d:%02d", 623 583 + (int)mt->tm_year + 1900, 624 584 + (int)mt->tm_mon + 1, 625 585 + (int)mt->tm_mday, 626 586 + (int)mt->tm_hour, 627 587 + (int)mt->tm_min, 628 588 + (int)mt->tm_sec); 629 + } else 630 + strlcpy(dest, " ", destsize); 589 + if (nsecs >= 0 && len >= 0) 590 + snprintf(dest + len, destsize - len, ".%09d", nsecs); 591 + } else { 592 + int has_nsecs = nsecs >= 0 ? 1 : 0; 593 + int len = MIN(19 + 9*has_nsecs, (int)destsize - 1); 594 + memset(dest, ' ', len); 595 + dest[len] = '\0'; 596 + } 631 597 +} 632 598 + 633 599 static void list_file(const char *fname) … … diff --git a/tls.c b/tls.c 640 606 + char mtimebuf[50]; 641 607 + char crtimebuf[50]; 642 608 char linkbuf[4096]; 609 + int nsecs; 643 610 644 611 if (do_lstat(fname, &buf) < 0) 645 612 failed("stat", fname); … … diff --git a/tls.c b/tls.c 648 615 #ifdef SUPPORT_XATTRS 649 616 if (am_root < 0) 650 617 stat_xattr(fname, &buf); 651 @@ -158,19 +180,11 @@ static void list_file(const char *fname) 618 @@ -159,30 +189,17 @@ static void list_file(const char *fname) 619 } 652 620 653 621 permstring(permbuf, buf.st_mode); 654 622 - 655 623 - if (buf.st_mtime) { 624 - int len; 656 625 - mt = gmtime(&buf.st_mtime); 657 626 - 658 - snprintf(datebuf, sizeof datebuf,627 - len = snprintf(datebuf, sizeof datebuf, 659 628 - "%04d-%02d-%02d %02d:%02d:%02d", 660 629 - (int)mt->tm_year + 1900, 661 630 - (int)mt->tm_mon + 1, … … diff --git a/tls.c b/tls.c 663 632 - (int)mt->tm_hour, 664 633 - (int)mt->tm_min, 665 634 - (int)mt->tm_sec); 666 - } else 667 - strlcpy(datebuf, " ", sizeof datebuf); 668 + storetime(mtimebuf, buf.st_mtime, sizeof mtimebuf); 635 #ifdef ST_MTIME_NSEC 636 - if (nsec_times) { 637 - snprintf(datebuf + len, sizeof datebuf - len, 638 - ".%09d", (int)buf.ST_MTIME_NSEC); 639 - } 640 + if (nsec_times) 641 + nsecs = (int)buf.ST_MTIME_NSEC; 642 + else 643 #endif 644 - } else { 645 - int len = MIN(19 + 9*nsec_times, (int)sizeof datebuf - 1); 646 - memset(datebuf, ' ', len); 647 - datebuf[len] = '\0'; 648 - } 649 + nsecs = -1; 650 + storetime(mtimebuf, sizeof mtimebuf, buf.st_mtime, nsecs); 669 651 + if (display_crtimes) 670 + storetime(crtimebuf, crtime, sizeof crtimebuf);652 + storetime(crtimebuf, sizeof crtimebuf, crtime, -1); 671 653 + else 672 654 + crtimebuf[0] = '\0'; 673 655 674 656 /* TODO: Perhaps escape special characters in fname? */ 675 657 676 @@ -1 81,13 +195,14 @@ static void list_file(const char *fname)658 @@ -193,13 +210,14 @@ static void list_file(const char *fname) 677 659 (long)minor(buf.st_rdev)); 678 } else /* NB: use double for size since it might not fit in a long. */679 printf("%1 2.0f", (double)buf.st_size);660 } else 661 printf("%15s", do_big_num(buf.st_size, 1, NULL)); 680 662 - printf(" %6ld.%-6ld %6ld %s %s%s\n", 681 663 + printf(" %6ld.%-6ld %6ld %s%s%s%s\n", 682 664 (long)buf.st_uid, (long)buf.st_gid, (long)buf.st_nlink, … … diff --git a/tls.c b/tls.c 690 672 {"link-times", 'l', POPT_ARG_NONE, &link_times, 0, 0, 0 }, 691 673 {"link-owner", 'L', POPT_ARG_NONE, &link_owner, 0, 0, 0 }, 692 674 #ifdef SUPPORT_XATTRS 693 @@ -2 03,6 +218,7 @@ static void tls_usage(int ret)675 @@ -218,6 +236,7 @@ static void tls_usage(int ret) 694 676 fprintf(F,"usage: " PROGRAM " [OPTIONS] FILE ...\n"); 695 677 fprintf(F,"Trivial file listing program for portably checking rsync\n"); 696 678 fprintf(F,"\nOptions:\n"); … … diff --git a/tls.c b/tls.c 698 680 fprintf(F," -l, --link-times display the time on a symlink\n"); 699 681 fprintf(F," -L, --link-owner display the owner+group on a symlink\n"); 700 682 #ifdef SUPPORT_XATTRS 701 diff - up a/proto.h b/proto.h683 diff -Nurp a/proto.h b/proto.h 702 684 --- a/proto.h 703 685 +++ b/proto.h 704 @@ -3 15,6 +315,8 @@ int do_stat(const char *fname, STRUCT_ST686 @@ -327,6 +327,8 @@ int do_stat(const char *fname, STRUCT_ST 705 687 int do_lstat(const char *fname, STRUCT_STAT *st); 706 688 int do_fstat(int fd, STRUCT_STAT *st); 707 689 OFF_T do_lseek(int fd, OFF_T offset, int whence); 708 690 +time_t get_create_time(const char *path); 709 691 +int set_create_time(const char *path, time_t crtime); 710 int do_utimensat(const char *fname, time_t modtime, uint32 mod_nsec , mode_t mode, uint32 fileflags);711 int do_lutimes(const char *fname, time_t modtime, uint32 mod_nsec , mode_t mode, uint32 fileflags);712 int do_utimes(const char *fname, time_t modtime, uint32 mod_nsec , mode_t mode, uint32 fileflags);713 diff - up a/rsync.1 b/rsync.1692 int do_utimensat(const char *fname, time_t modtime, uint32 mod_nsec); 693 int do_lutimes(const char *fname, time_t modtime, uint32 mod_nsec); 694 int do_utimes(const char *fname, time_t modtime, uint32 mod_nsec); 695 diff -Nurp a/rsync.1 b/rsync.1 714 696 --- a/rsync.1 715 697 +++ b/rsync.1 716 @@ -443,6 +443,7 @@ to the detailed description below for a 698 @@ -449,6 +449,7 @@ to the detailed description below for a 699 \-\-specials preserve special files 717 700 \-D same as \-\-devices \-\-specials 718 701 \-t, \-\-times preserve modification times 719 \-O, \-\-omit\-dir\-times omit directories from \-\-times720 702 + \-N, \-\-crtimes preserve create times (newness) 703 \-O, \-\-omit\-dir\-times omit directories from \-\-times 704 \-J, \-\-omit\-link\-times omit symlinks from \-\-times 721 705 \-\-super receiver attempts super\-user activities 722 \-\-fake\-super store/recover privileged attrs using xattrs 723 \-S, \-\-sparse handle sparse files efficiently 724 @@ -1273,6 +1274,10 @@ it is preserving modification times (see 725 the directories on the receiving side, it is a good idea to use \fB\-O\fP. 726 This option is inferred if you use \fB\-\-backup\fP without \fB\-\-backup\-dir\fP. 706 @@ -1379,6 +1380,10 @@ cause the next transfer to behave as if 707 updated (though rsync\(cq\&s delta\-transfer algorithm will make the update fairly efficient 708 if the files haven\(cq\&t actually changed, you\(cq\&re much better off using \fB\-t\fP). 727 709 .IP 728 710 +.IP "\fB\-N, \-\-crtimes\fP" 729 711 +This tells rsync to set the create times (newness) of 730 712 +the destination files to the same value as the source files. 731 713 +.IP 732 .IP "\fB\- \-super\fP"733 This tells the receiving side to attempt super\-user734 activities even if the receiving rsync wasn\(cq\&t run by the super\-user. These735 @@ -2 067,7 +2072,7 @@ with older versions of rsync, but that a714 .IP "\fB\-O, \-\-omit\-dir\-times\fP" 715 This tells rsync to omit directories when 716 it is preserving modification times (see \fB\-\-times\fP). If NFS is sharing 717 @@ -2390,7 +2395,7 @@ with older versions of rsync, but that a 736 718 verbose messages). 737 719 .IP 738 720 The \(dq\&%i\(dq\& escape has a cryptic output that is 11 letters long. The general … … diff -up a/rsync.1 b/rsync.1 741 723 type of update being done, \fBX\fP is replaced by the file\-type, and the 742 724 other letters represent attributes that may be output if they are being 743 725 modified. 744 @@ -2 142,6 +2147,9 @@ The \fBf\fP means that the fileflags inf726 @@ -2465,6 +2470,9 @@ The \fBf\fP means that the fileflags inf 745 727 The \fBa\fP means that the ACL information changed. 746 728 .IP o 747 729 The \fBx\fP means that the extended attribute information changed. -
rsync/files/patch-fileflags.diff
diff --git a/rsync/files/patch-fileflags.diff b/rsync/files/patch-fileflags.diff index 2b307ff..2bf570c 100644
a b To use this patch, run these commands for a successful build: 8 8 ./configure 9 9 make 10 10 11 based-on: 40afd365cc8ca968fd16e161d24df5b8a8a520cc11 based-on: 7cb0de6326c915a72253fd103dae93308031ec3f 12 12 diff --git a/Makefile.in b/Makefile.in 13 13 --- a/Makefile.in 14 14 +++ b/Makefile.in 15 @@ -4 2,7 +42,7 @@ popt_OBJS=popt/findme.o popt/popt.o popt/poptconfig.o \15 @@ -45,7 +45,7 @@ popt_OBJS=popt/findme.o popt/popt.o popt/poptconfig.o \ 16 16 popt/popthelp.o popt/poptparse.o 17 OBJS=$(OBJS1) $(OBJS2) $(OBJS3) $(DAEMON_OBJ) $(LIBOBJ) $(ZLIBOBJ)@BUILD_POPT@17 OBJS=$(OBJS1) $(OBJS2) $(OBJS3) $(DAEMON_OBJ) $(LIBOBJ) @BUILD_ZLIB@ @BUILD_POPT@ 18 18 19 19 -TLS_OBJ = tls.o syscall.o lib/compat.o lib/snprintf.o lib/permstring.o lib/sysxattrs.o @BUILD_POPT@ 20 20 +TLS_OBJ = tls.o syscall.o t_stub.o lib/compat.o lib/snprintf.o lib/permstring.o lib/sysxattrs.o @BUILD_POPT@ 21 21 22 22 # Programs we must have to run the test cases 23 23 CHECK_PROGS = rsync$(EXEEXT) tls$(EXEEXT) getgroups$(EXEEXT) getfsdev$(EXEEXT) \ 24 @@ -1 07,7 +107,7 @@ getgroups$(EXEEXT): getgroups.o24 @@ -127,7 +127,7 @@ getgroups$(EXEEXT): getgroups.o 25 25 getfsdev$(EXEEXT): getfsdev.o 26 26 $(CC) $(CFLAGS) $(LDFLAGS) -o $@ getfsdev.o $(LIBS) 27 27 … … diff --git a/Makefile.in b/Makefile.in 33 33 diff --git a/compat.c b/compat.c 34 34 --- a/compat.c 35 35 +++ b/compat.c 36 @@ -4 3,9 +43,11 @@ extern int checksum_seed;36 @@ -44,9 +44,11 @@ extern int checksum_seed; 37 37 extern int basis_dir_cnt; 38 38 extern int prune_empty_dirs; 39 39 extern int protocol_version; … … diff --git a/compat.c b/compat.c 45 45 extern int preserve_acls; 46 46 extern int preserve_xattrs; 47 47 extern int need_messages_from_generator; 48 @@ -6 3,7 +65,7 @@ extern char *iconv_opt;48 @@ -64,7 +66,7 @@ extern char *iconv_opt; 49 49 #endif 50 50 51 51 /* These index values are for the file-list's extra-attribute array. */ … … diff --git a/compat.c b/compat.c 54 54 55 55 int receiver_symlink_times = 0; /* receiver can set the time on a symlink */ 56 56 int sender_symlink_iconv = 0; /* sender should convert symlink content */ 57 @@ -14 0,6 +142,8 @@ void setup_protocol(int f_out,int f_in)57 @@ -142,6 +144,8 @@ void setup_protocol(int f_out,int f_in) 58 58 uid_ndx = ++file_extra_cnt; 59 59 if (preserve_gid) 60 60 gid_ndx = ++file_extra_cnt; … … diff --git a/compat.c b/compat.c 66 66 diff --git a/configure.ac b/configure.ac 67 67 --- a/configure.ac 68 68 +++ b/configure.ac 69 @@ -5 69,6 +569,7 @@ AC_FUNC_UTIME_NULL69 @@ -597,6 +597,7 @@ AC_FUNC_UTIME_NULL 70 70 AC_FUNC_ALLOCA 71 71 AC_CHECK_FUNCS(waitpid wait4 getcwd strdup chown chmod lchmod mknod mkfifo \ 72 72 fchmod fstat ftruncate strchr readlink link utime utimes lutimes strftime \ … … diff --git a/configure.ac b/configure.ac 74 74 memmove lchown vsnprintf snprintf vasprintf asprintf setsid strpbrk \ 75 75 strlcat strlcpy strtol mallinfo getgroups setgroups geteuid getegid \ 76 76 setlocale setmode open64 lseek64 mkstemp64 mtrace va_copy __va_copy \ 77 diff --git a/delete.c b/delete.c 78 --- a/delete.c 79 +++ b/delete.c 80 @@ -25,6 +25,7 @@ 81 extern int am_root; 82 extern int make_backups; 83 extern int max_delete; 84 +extern int force_change; 85 extern char *backup_dir; 86 extern char *backup_suffix; 87 extern int backup_suffix_len; 88 @@ -97,8 +98,12 @@ static enum delret delete_dir_contents(char *fname, uint16 flags) 89 } 90 91 strlcpy(p, fp->basename, remainder); 92 +#ifdef SUPPORT_FORCE_CHANGE 93 + if (force_change) 94 + make_mutable(fname, fp->mode, F_FFLAGS(fp), force_change); 95 +#endif 96 if (!(fp->mode & S_IWUSR) && !am_root && fp->flags & FLAG_OWNED_BY_US) 97 - do_chmod(fname, fp->mode | S_IWUSR); 98 + do_chmod(fname, fp->mode | S_IWUSR, NO_FFLAGS); 99 /* Save stack by recursing to ourself directly. */ 100 if (S_ISDIR(fp->mode)) { 101 if (delete_dir_contents(fname, flags | DEL_RECURSE) != DR_SUCCESS) 102 @@ -139,11 +144,18 @@ enum delret delete_item(char *fbuf, uint16 mode, uint16 flags) 103 } 104 105 if (flags & DEL_NO_UID_WRITE) 106 - do_chmod(fbuf, mode | S_IWUSR); 107 + do_chmod(fbuf, mode | S_IWUSR, NO_FFLAGS); 108 109 if (S_ISDIR(mode) && !(flags & DEL_DIR_IS_EMPTY)) { 110 /* This only happens on the first call to delete_item() since 111 * delete_dir_contents() always calls us w/DEL_DIR_IS_EMPTY. */ 112 +#ifdef SUPPORT_FORCE_CHANGE 113 + if (force_change) { 114 + STRUCT_STAT st; 115 + if (x_lstat(fbuf, &st, NULL) == 0) 116 + make_mutable(fbuf, st.st_mode, st.st_flags, force_change); 117 + } 118 +#endif 119 ignore_perishable = 1; 120 /* If DEL_RECURSE is not set, this just reports emptiness. */ 121 ret = delete_dir_contents(fbuf, flags); 77 122 diff --git a/flist.c b/flist.c 78 123 --- a/flist.c 79 124 +++ b/flist.c 80 @@ -5 1,6 +51,7 @@ extern int preserve_links;125 @@ -50,6 +50,7 @@ extern int preserve_links; 81 126 extern int preserve_hard_links; 82 127 extern int preserve_devices; 83 128 extern int preserve_specials; 84 129 +extern int preserve_fileflags; 85 130 extern int delete_during; 131 extern int missing_args; 86 132 extern int eol_nulls; 87 extern int relative_paths; 88 @@ -394,6 +395,9 @@ static void send_file_entry(int f, const char *fname, struct file_struct *file, 133 @@ -399,6 +400,9 @@ static void send_file_entry(int f, const char *fname, struct file_struct *file, 89 134 { 90 135 static time_t modtime; 91 136 static mode_t mode; … … diff --git a/flist.c b/flist.c 95 140 #ifdef SUPPORT_HARD_LINKS 96 141 static int64 dev; 97 142 #endif 98 @@ -4 23,6 +427,14 @@ static void send_file_entry(int f, const char *fname, struct file_struct *file,143 @@ -442,6 +446,14 @@ static void send_file_entry(int f, const char *fname, struct file_struct *file, 99 144 xflags |= XMIT_SAME_MODE; 100 145 else 101 146 mode = file->mode; … … diff --git a/flist.c b/flist.c 110 155 111 156 if (preserve_devices && IS_DEVICE(mode)) { 112 157 if (protocol_version < 28) { 113 @@ -5 47,6 +559,10 @@ static void send_file_entry(int f, const char *fname, struct file_struct *file,114 }158 @@ -583,6 +595,10 @@ static void send_file_entry(int f, const char *fname, struct file_struct *file, 159 write_varint(f, F_MOD_NSEC(file)); 115 160 if (!(xflags & XMIT_SAME_MODE)) 116 161 write_int(f, to_wire_mode(mode)); 117 162 +#ifdef SUPPORT_FILEFLAGS … … diff --git a/flist.c b/flist.c 121 166 if (preserve_uid && !(xflags & XMIT_SAME_UID)) { 122 167 if (protocol_version < 30) 123 168 write_int(f, uid); 124 @@ -6 34,6 +650,9 @@ static struct file_struct *recv_file_entry(int f, struct file_list *flist, int x169 @@ -672,6 +688,9 @@ static struct file_struct *recv_file_entry(int f, struct file_list *flist, int x 125 170 { 126 171 static int64 modtime; 127 172 static mode_t mode; … … diff --git a/flist.c b/flist.c 131 176 #ifdef SUPPORT_HARD_LINKS 132 177 static int64 dev; 133 178 #endif 134 @@ -731,6 +750,10 @@ static struct file_struct *recv_file_entry(int f, struct file_list *flist, int x 135 file_length = F_LENGTH(first); 179 @@ -779,6 +798,10 @@ static struct file_struct *recv_file_entry(int f, struct file_list *flist, int x 136 180 modtime = first->modtime; 181 modtime_nsec = F_MOD_NSEC(first); 137 182 mode = first->mode; 138 183 +#ifdef SUPPORT_FILEFLAGS 139 184 + if (preserve_fileflags) … … diff --git a/flist.c b/flist.c 142 187 if (preserve_uid) 143 188 uid = F_OWNER(first); 144 189 if (preserve_gid) 145 @@ - 768,6 +791,10 @@ static struct file_struct *recv_file_entry(int f, struct file_list *flist, int x190 @@ -820,6 +843,10 @@ static struct file_struct *recv_file_entry(int f, struct file_list *flist, int x 146 191 147 if (chmod_modes && !S_ISLNK(mode) )192 if (chmod_modes && !S_ISLNK(mode) && mode) 148 193 mode = tweak_mode(mode, chmod_modes); 149 194 +#ifdef SUPPORT_FILEFLAGS 150 195 + if (preserve_fileflags && !(xflags & XMIT_SAME_FLAGS)) … … diff --git a/flist.c b/flist.c 153 198 154 199 if (preserve_uid && !(xflags & XMIT_SAME_UID)) { 155 200 if (protocol_version < 30) 156 @@ -9 09,6 +936,10 @@ static struct file_struct *recv_file_entry(int f, struct file_list *flist, int x201 @@ -978,6 +1005,10 @@ static struct file_struct *recv_file_entry(int f, struct file_list *flist, int x 157 202 } 158 203 #endif 159 204 file->mode = mode; 160 205 +#ifdef SUPPORT_FILEFLAGS 161 + if ( fileflags_ndx) /* check the ndx for force_change w/o preserve_fileflags */206 + if (preserve_fileflags) 162 207 + F_FFLAGS(file) = fileflags; 163 208 +#endif 164 209 if (preserve_uid) 165 210 F_OWNER(file) = uid; 166 211 if (preserve_gid) { 167 @@ -1 283,6 +1314,10 @@ struct file_struct *make_file(const char *fname, struct file_list *flist,212 @@ -1375,6 +1406,10 @@ struct file_struct *make_file(const char *fname, struct file_list *flist, 168 213 } 169 214 #endif 170 215 file->mode = st.st_mode; … … diff --git a/flist.c b/flist.c 175 220 if (preserve_uid) 176 221 F_OWNER(file) = st.st_uid; 177 222 if (preserve_gid) 178 @@ -1429,6 +1464,9 @@ static struct file_struct *send_file_name(int f, struct file_list *flist,179 #ifdef SUPPORT_XATTRS180 if (preserve_xattrs) {181 sx.st.st_mode = file->mode;182 +#ifdef SUPPORT_FILEFLAGS183 + sx.st.st_flags = preserve_fileflags ? F_FFLAGS(file) : 0;184 +#endif185 sx.xattr = NULL;186 if (get_xattr(fname, &sx) < 0) {187 io_error |= IOERR_GENERAL;188 223 diff --git a/generator.c b/generator.c 189 224 --- a/generator.c 190 225 +++ b/generator.c 191 @@ -35,6 +35,7 @@ extern int do_progress; 192 extern int relative_paths; 193 extern int implied_dirs; 194 extern int keep_dirlinks; 195 +extern int force_change; 196 extern int preserve_acls; 197 extern int preserve_xattrs; 198 extern int preserve_links; 199 @@ -42,6 +43,7 @@ extern int preserve_devices; 226 @@ -42,8 +42,10 @@ extern int preserve_devices; 200 227 extern int preserve_specials; 201 228 extern int preserve_hard_links; 202 229 extern int preserve_executability; 203 230 +extern int preserve_fileflags; 204 231 extern int preserve_perms; 205 232 extern int preserve_times; 233 +extern int force_change; 206 234 extern int delete_mode; 207 @@ -164,11 +166,15 @@ static enum delret delete_item(char *fbuf, uint16 mode, uint16 flags) 208 } 209 210 if (flags & DEL_NO_UID_WRITE) 211 - do_chmod(fbuf, mode | S_IWUSR); 212 + do_chmod(fbuf, mode | S_IWUSR, NO_FFLAGS); 213 214 if (S_ISDIR(mode) && !(flags & DEL_DIR_IS_EMPTY)) { 215 /* This only happens on the first call to delete_item() since 216 * delete_dir_contents() always calls us w/DEL_DIR_IS_EMPTY. */ 217 +#ifdef SUPPORT_FORCE_CHANGE 218 + if (force_change) 219 + make_mutable(fbuf, NULL, NO_FFLAGS, force_change); 220 +#endif 221 ignore_perishable = 1; 222 /* If DEL_RECURSE is not set, this just reports emptiness. */ 223 ret = delete_dir_contents(fbuf, flags); 224 @@ -285,8 +291,14 @@ static enum delret delete_dir_contents(char *fname, uint16 flags) 225 } 226 227 strlcpy(p, fp->basename, remainder); 228 +#ifdef SUPPORT_FORCE_CHANGE 229 + if (force_change) { 230 + mode_t mode = fp->mode; 231 + make_mutable(fname, &mode, F_FFLAGS(fp), force_change); 232 + } 233 +#endif 234 if (!(fp->mode & S_IWUSR) && !am_root && fp->flags & FLAG_OWNED_BY_US) 235 - do_chmod(fname, fp->mode | S_IWUSR); 236 + do_chmod(fname, fp->mode | S_IWUSR, NO_FFLAGS); 237 /* Save stack by recursing to ourself directly. */ 238 if (S_ISDIR(fp->mode)) { 239 if (delete_dir_contents(fname, flags | DEL_RECURSE) != DR_SUCCESS) 240 @@ -647,6 +659,10 @@ int unchanged_attrs(const char *fname, struct file_struct *file, stat_x *sxp) 235 extern int delete_before; 236 extern int delete_during; 237 @@ -465,6 +467,10 @@ int unchanged_attrs(const char *fname, struct file_struct *file, stat_x *sxp) 241 238 return 0; 242 239 if (perms_differ(file, sxp)) 243 240 return 0; … … diff --git a/generator.c b/generator.c 248 245 if (ownership_differs(file, sxp)) 249 246 return 0; 250 247 #ifdef SUPPORT_ACLS 251 @@ - 698,6 +714,11 @@ void itemize(const char *fnamecmp, struct file_struct *file, int ndx, int statre248 @@ -516,6 +522,11 @@ void itemize(const char *fnamecmp, struct file_struct *file, int ndx, int statre 252 249 if (gid_ndx && !(file->flags & FLAG_SKIP_GROUP) 253 250 && sxp->st.st_gid != (gid_t)F_GROUP(file)) 254 251 iflags |= ITEM_REPORT_GROUP; … … diff --git a/generator.c b/generator.c 260 257 #ifdef SUPPORT_ACLS 261 258 if (preserve_acls && !S_ISLNK(file->mode)) { 262 259 if (!ACL_READY(*sxp)) 263 @@ -1 491,6 +1512,10 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,260 @@ -1395,6 +1406,10 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx, 264 261 file->mode = dest_mode(file->mode, sx.st.st_mode, 265 262 dflt_perms, statret == 0); 266 263 } … … diff --git a/generator.c b/generator.c 271 268 if (statret != 0 && basis_dir[0] != NULL) { 272 269 int j = try_dests_non(file, fname, ndx, fnamecmpbuf, &sx, 273 270 itemizing, code); 274 @@ -1 535,10 +1560,17@@ static void recv_generator(char *fname, struct file_struct *file, int ndx,271 @@ -1439,10 +1454,15 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx, 275 272 * readable and writable permissions during the time we are 276 273 * putting files within them. This is then restored to the 277 274 * former permissions after the transfer is done. */ 278 275 +#ifdef SUPPORT_FORCE_CHANGE 279 + if (force_change && F_FFLAGS(file) & force_change) { 280 + mode_t mode = file->mode; 281 + if (make_mutable(fname, &mode, F_FFLAGS(file), force_change)) 282 + need_retouch_dir_perms = 1; 283 + } 276 + if (force_change && F_FFLAGS(file) & force_change 277 + && make_mutable(fname, file->mode, F_FFLAGS(file), force_change)) 278 + need_retouch_dir_perms = 1; 284 279 +#endif 285 280 #ifdef HAVE_CHMOD 286 281 if (!am_root && (file->mode & S_IRWXU) != S_IRWXU && dir_tweaking) { … … diff --git a/generator.c b/generator.c 290 285 rsyserr(FERROR_XFER, errno, 291 286 "failed to modify permissions on %s", 292 287 full_fname(fname)); 293 @@ -1 573,6 +1605,10 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,288 @@ -1477,6 +1497,10 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx, 294 289 file->mode = dest_mode(file->mode, sx.st.st_mode, dflt_perms, 295 290 exists); 296 291 } … … diff --git a/generator.c b/generator.c 301 296 302 297 #ifdef SUPPORT_HARD_LINKS 303 298 if (preserve_hard_links && F_HLINK_NOT_FIRST(file) 304 @@ -2 116,13 +2152,17 @@ static void touch_up_dirs(struct file_list *flist, int ndx)299 @@ -2045,13 +2069,17 @@ static void touch_up_dirs(struct file_list *flist, int ndx) 305 300 continue; 306 301 fname = f_name(file, NULL); 307 302 if (fix_dir_perms) … … diff --git a/generator.c b/generator.c 311 306 STRUCT_STAT st; 312 307 if (link_stat(fname, &st, 0) == 0 313 308 && cmp_time(st.st_mtime, file->modtime) != 0) 314 - set_modtime(fname, file->modtime, file->mode);315 + set_modtime(fname, file->modtime, file->mode, 0);309 - set_modtime(fname, file->modtime, F_MOD_NSEC(file), file->mode); 310 + set_modtime(fname, file->modtime, F_MOD_NSEC(file), file->mode, 0); 316 311 } 317 312 +#ifdef SUPPORT_FORCE_CHANGE 318 313 + if (force_change && F_FFLAGS(file) & force_change) … … diff --git a/generator.c b/generator.c 320 315 +#endif 321 316 if (counter >= loopchk_limit) { 322 317 if (allowed_lull) 323 maybe_send_keepalive( );318 maybe_send_keepalive(time(NULL), MSK_ALLOW_FLUSH); 324 319 diff --git a/log.c b/log.c 325 320 --- a/log.c 326 321 +++ b/log.c 327 @@ - 658,7 +658,7 @@ static void log_formatted(enum logcode code, const char *format, const char *op,322 @@ -720,7 +720,7 @@ static void log_formatted(enum logcode code, const char *format, const char *op, 328 323 c[5] = !(iflags & ITEM_REPORT_PERMS) ? '.' : 'p'; 329 324 c[6] = !(iflags & ITEM_REPORT_OWNER) ? '.' : 'o'; 330 325 c[7] = !(iflags & ITEM_REPORT_GROUP) ? '.' : 'g'; … … diff --git a/main.c b/main.c 344 339 +#include <sys/sysctl.h> 345 340 +#endif 346 341 347 extern int verbose;348 342 extern int dry_run; 349 @@ -51,6 +54,7 @@ extern int protocol_version; 343 extern int list_only; 344 @@ -51,6 +54,7 @@ extern int copy_unsafe_links; 345 extern int keep_dirlinks; 346 extern int preserve_hard_links; 347 extern int protocol_version; 348 +extern int force_change; 350 349 extern int file_total; 351 350 extern int recurse; 352 351 extern int xfer_dirs; 353 +extern int force_change; 354 extern int protect_args; 355 extern int relative_paths; 356 extern int sanitize_paths; 357 @@ -753,6 +757,22 @@ static int do_recv(int f_in, int f_out, char *local_name) 352 @@ -839,6 +843,22 @@ static int do_recv(int f_in, int f_out, char *local_name) 358 353 * points to an identical file won't be replaced by the referent. */ 359 354 copy_links = copy_dirlinks = copy_unsafe_links = 0; 360 355 … … diff --git a/main.c b/main.c 380 375 diff --git a/options.c b/options.c 381 376 --- a/options.c 382 377 +++ b/options.c 383 @@ -5 3,6 +53,7 @@ int preserve_hard_links = 0;378 @@ -55,6 +55,7 @@ int preserve_hard_links = 0; 384 379 int preserve_acls = 0; 385 380 int preserve_xattrs = 0; 386 381 int preserve_perms = 0; … … diff --git a/options.c b/options.c 388 383 int preserve_executability = 0; 389 384 int preserve_devices = 0; 390 385 int preserve_specials = 0; 391 @@ -8 4,6 +85,7 @@ int implied_dirs = 1;392 int numeric_ids= 0;386 @@ -89,6 +90,7 @@ int numeric_ids = 0; 387 int msgs2stderr = 0; 393 388 int allow_8bit_chars = 0; 394 389 int force_delete = 0; 395 390 +int force_change = 0; 396 391 int io_timeout = 0; 397 392 int prune_empty_dirs = 0; 398 393 int use_qsort = 0; 399 @@ - 223,6 +225,7 @@ static void print_rsync_version(enum logcode f)394 @@ -574,6 +576,7 @@ static void print_rsync_version(enum logcode f) 400 395 char const *links = "no "; 401 396 char const *iconv = "no "; 402 397 char const *ipv6 = "no "; … … diff --git a/options.c b/options.c 404 399 STRUCT_STAT *dumstat; 405 400 406 401 #if SUBPROTOCOL_VERSION != 0 407 @@ - 256,6 +259,9 @@ static void print_rsync_version(enum logcode f)402 @@ -610,6 +613,9 @@ static void print_rsync_version(enum logcode f) 408 403 #ifdef CAN_SET_SYMLINK_TIMES 409 404 symtimes = ""; 410 405 #endif … … diff --git a/options.c b/options.c 414 409 415 410 rprintf(f, "%s version %s protocol version %d%s\n", 416 411 RSYNC_NAME, RSYNC_VERSION, PROTOCOL_VERSION, subprotocol); 417 @@ - 269,8 +275,8 @@ static void print_rsync_version(enum logcode f)412 @@ -623,8 +629,8 @@ static void print_rsync_version(enum logcode f) 418 413 (int)(sizeof (int64) * 8)); 419 414 rprintf(f, " %ssocketpairs, %shardlinks, %ssymlinks, %sIPv6, batchfiles, %sinplace,\n", 420 415 got_socketpair, hardlinks, links, ipv6, have_inplace); 421 - rprintf(f, " %sappend, %sACLs, %sxattrs, %siconv, %ssymtimes \n",422 - have_inplace, acls, xattrs, iconv, symtimes );423 + rprintf(f, " %sappend, %sACLs, %sxattrs, %siconv, %ssymtimes, %s file-flags\n",424 + have_inplace, acls, xattrs, iconv, symtimes, fileflags);416 - rprintf(f, " %sappend, %sACLs, %sxattrs, %siconv, %ssymtimes, %sprealloc\n", 417 - have_inplace, acls, xattrs, iconv, symtimes, prealloc); 418 + rprintf(f, " %sappend, %sACLs, %sxattrs, %siconv, %ssymtimes, %sprealloc, %sfile-flags\n", 419 + have_inplace, acls, xattrs, iconv, symtimes, prealloc, fileflags); 425 420 426 421 #ifdef MAINTAINER_MODE 427 422 rprintf(f, "Panic Action: \"%s\"\n", get_panic_action()); 428 @@ - 337,6 +343,9 @@ void usage(enum logcode F)423 @@ -695,6 +701,9 @@ void usage(enum logcode F) 429 424 rprintf(F," -K, --keep-dirlinks treat symlinked dir on receiver as dir\n"); 430 425 rprintf(F," -H, --hard-links preserve hard links\n"); 431 426 rprintf(F," -p, --perms preserve permissions\n"); … … diff --git a/options.c b/options.c 435 430 rprintf(F," -E, --executability preserve the file's executability\n"); 436 431 rprintf(F," --chmod=CHMOD affect file and/or directory permissions\n"); 437 432 #ifdef SUPPORT_ACLS 438 @@ - 374,7 +383,12 @@ void usage(enum logcode F)439 rprintf(F," -- delete-after receiver deletes after transfer, not during\n");440 rprintf(F," --delete- excluded also delete excluded files from destination dirs\n");433 @@ -740,7 +749,12 @@ void usage(enum logcode F) 434 rprintf(F," --ignore-missing-args ignore missing source args without error\n"); 435 rprintf(F," --delete-missing-args delete missing source args from destination\n"); 441 436 rprintf(F," --ignore-errors delete even if there are I/O errors\n"); 442 437 - rprintf(F," --force force deletion of directories even if not empty\n"); 443 438 + rprintf(F," --force-delete force deletion of directories even if not empty\n"); … … diff --git a/options.c b/options.c 449 444 rprintf(F," --max-delete=NUM don't delete more than NUM files\n"); 450 445 rprintf(F," --max-size=SIZE don't transfer any file larger than SIZE\n"); 451 446 rprintf(F," --min-size=SIZE don't transfer any file smaller than SIZE\n"); 452 @@ - 479,6 +493,10 @@ static struct poptOption long_options[] = {447 @@ -857,6 +871,10 @@ static struct poptOption long_options[] = { 453 448 {"perms", 'p', POPT_ARG_VAL, &preserve_perms, 1, 0, 0 }, 454 449 {"no-perms", 0, POPT_ARG_VAL, &preserve_perms, 0, 0, 0 }, 455 450 {"no-p", 0, POPT_ARG_VAL, &preserve_perms, 0, 0, 0 }, … … diff --git a/options.c b/options.c 460 455 {"executability", 'E', POPT_ARG_NONE, &preserve_executability, 0, 0, 0 }, 461 456 {"acls", 'A', POPT_ARG_NONE, 0, 'A', 0, 0 }, 462 457 {"no-acls", 0, POPT_ARG_VAL, &preserve_acls, 0, 0, 0 }, 463 @@ - 557,6 +575,14 @@ static struct poptOption long_options[] = {458 @@ -943,6 +961,14 @@ static struct poptOption long_options[] = { 464 459 {"remove-source-files",0,POPT_ARG_VAL, &remove_source_files, 1, 0, 0 }, 465 460 {"force", 0, POPT_ARG_VAL, &force_delete, 1, 0, 0 }, 466 461 {"no-force", 0, POPT_ARG_VAL, &force_delete, 0, 0, 0 }, … … diff --git a/options.c b/options.c 475 470 {"ignore-errors", 0, POPT_ARG_VAL, &ignore_errors, 1, 0, 0 }, 476 471 {"no-ignore-errors", 0, POPT_ARG_VAL, &ignore_errors, 0, 0, 0 }, 477 472 {"max-delete", 0, POPT_ARG_INT, &max_delete, 0, 0, 0 }, 478 @@ - 1879,6 +1905,9 @@ void server_options(char **args, int *argc_p)473 @@ -2537,6 +2563,9 @@ void server_options(char **args, int *argc_p) 479 474 if (xfer_dirs && !recurse && delete_mode && am_sender) 480 475 args[ac++] = "--no-r"; 481 476 … … diff --git a/options.c b/options.c 485 480 if (do_compression && def_compress_level != Z_DEFAULT_COMPRESSION) { 486 481 if (asprintf(&arg, "--compress-level=%d", def_compress_level) < 0) 487 482 goto oom; 488 @@ - 1966,6 +1995,16 @@ void server_options(char **args, int *argc_p)483 @@ -2624,6 +2653,16 @@ void server_options(char **args, int *argc_p) 489 484 args[ac++] = "--delete-excluded"; 490 485 if (force_delete) 491 486 args[ac++] = "--force"; … … diff --git a/options.c b/options.c 505 500 diff --git a/rsync.c b/rsync.c 506 501 --- a/rsync.c 507 502 +++ b/rsync.c 508 @@ -29,9 +29,11 @@ 509 510 extern int verbose; 511 extern int dry_run; 512 +extern int force_change; 503 @@ -31,6 +31,7 @@ extern int dry_run; 513 504 extern int preserve_acls; 514 505 extern int preserve_xattrs; 515 506 extern int preserve_perms; … … diff --git a/rsync.c b/rsync.c 517 508 extern int preserve_executability; 518 509 extern int preserve_times; 519 510 extern int am_root; 520 @@ - 374,6 +376,74@@ mode_t dest_mode(mode_t flist_mode, mode_t stat_mode, int dflt_perms,511 @@ -452,6 +453,39 @@ mode_t dest_mode(mode_t flist_mode, mode_t stat_mode, int dflt_perms, 521 512 return new_mode; 522 513 } 523 514 … … diff --git a/rsync.c b/rsync.c 527 518 +{ 528 519 + if (do_chflags(fname, fileflags) != 0) { 529 520 + rsyserr(FERROR_XFER, errno, 530 + "failed to set file flags (%x)on %s",531 + f ileflags, full_fname(fname));521 + "failed to set file flags on %s", 522 + full_fname(fname)); 532 523 + return 0; 533 524 + } 534 525 + 535 526 + return 1; 536 527 +} 537 528 + 538 +/* Remove immutable flags from an object, so it can be altered/removed. 539 + * Returns the fileflags if flags were removed, otherwise 0. If the 540 + * fileflags value is NO_FFLAGS, we will stat the fname to figure out 541 + * what the flags are, and return the mode via *mode_ptr (if non-NULL). */ 542 +uint32 make_mutable(const char *fname, mode_t *mode_ptr, uint32 fileflags, uint32 iflags) 529 +/* Remove immutable flags from an object, so it can be altered/removed. */ 530 +int make_mutable(const char *fname, mode_t mode, uint32 fileflags, uint32 iflags) 543 531 +{ 544 + if (fileflags == NO_FFLAGS) { 545 + STRUCT_STAT st; 546 + if (x_lstat(fname, &st, NULL) < 0) 547 + return 0; 548 + fileflags = st.st_flags; 549 + if (mode_ptr) 550 + *mode_ptr = st.st_mode; 551 + else 552 + mode_ptr = &st.st_mode; 553 + } 554 + 555 + if ((mode_ptr && S_ISLNK(*mode_ptr)) || !(fileflags & iflags)) 532 + if (S_ISLNK(mode) || !(fileflags & iflags)) 556 533 + return 0; 557 +558 534 + if (!set_fileflags(fname, fileflags & ~iflags)) 559 + return 0; 560 + 561 + return fileflags; 535 + return -1; 536 + return 1; 562 537 +} 563 538 + 564 539 +/* Undo a prior make_mutable() call that returned a 1. */ 565 540 +int undo_make_mutable(const char *fname, uint32 fileflags) 566 541 +{ 567 + if (!set_fileflags(fname, fileflags)) { 568 + rsyserr(FINFO, errno, "failed to relock %s", full_fname(fname)); 542 + if (!set_fileflags(fname, fileflags)) 569 543 + return -1; 570 + }571 544 + return 1; 572 545 +} 573 +574 +/* This returns the st_flags value if the parent directory was made mutable, otherwise 0.575 + * It stores the parent directory path into parent_dirbuf. */576 +int make_parentdir_mutable(const char *fname, uint32 iflags, char *parent_dirbuf, int parent_dirbuf_size)577 +{578 + char *slash = strrchr(fname, '/');579 +580 + if (slash) {581 + int len = slash - fname;582 + if (len >= parent_dirbuf_size)583 + return 0;584 + strlcpy(parent_dirbuf, fname, len+1);585 + } else586 + strlcpy(parent_dirbuf, ".", parent_dirbuf_size);587 +588 + return make_mutable(parent_dirbuf, NULL, NO_FFLAGS, iflags);589 +}590 546 +#endif 591 547 + 592 548 int set_file_attrs(const char *fname, struct file_struct *file, stat_x *sxp, 593 549 const char *fnamecmp, int flags) 594 550 { 595 @@ -382,6 +452,9 @@ int set_file_attrs(const char *fname, struct file_struct *file, stat_x *sxp, 596 int change_uid, change_gid; 597 mode_t new_mode = file->mode; 598 int inherit; 599 +#ifdef SUPPORT_FORCE_CHANGE 600 + int became_mutable = 0; 601 +#endif 602 603 if (!sxp) { 604 if (dry_run) 605 @@ -411,6 +484,11 @@ int set_file_attrs(const char *fname, struct file_struct *file, stat_x *sxp, 606 if (daemon_chmod_modes && !S_ISLNK(new_mode)) 607 new_mode = tweak_mode(new_mode, daemon_chmod_modes); 608 609 +#ifdef SUPPORT_FORCE_CHANGE 610 + if (force_change) 611 + became_mutable = make_mutable(fname, &sxp->st.st_mode, sxp->st.st_flags, force_change); 612 +#endif 613 + 614 #ifdef SUPPORT_ACLS 615 if (preserve_acls && !S_ISLNK(file->mode) && !ACL_READY(*sxp)) 616 get_acl(fname, sxp); 617 @@ -429,7 +507,7 @@ int set_file_attrs(const char *fname, struct file_struct *file, stat_x *sxp, 618 flags |= ATTRS_SKIP_MTIME; 619 if (!(flags & ATTRS_SKIP_MTIME) 620 && cmp_time(sxp->st.st_mtime, file->modtime) != 0) { 621 - int ret = set_modtime(fname, file->modtime, sxp->st.st_mode); 622 + int ret = set_modtime(fname, file->modtime, sxp->st.st_mode, ST_FLAGS(sxp->st)); 623 if (ret < 0) { 624 rsyserr(FERROR_XFER, errno, "failed to set times on %s", 625 full_fname(fname)); 626 @@ -465,7 +543,7 @@ int set_file_attrs(const char *fname, struct file_struct *file, stat_x *sxp, 551 @@ -513,7 +547,7 @@ int set_file_attrs(const char *fname, struct file_struct *file, stat_x *sxp, 627 552 if (am_root >= 0) { 628 553 uid_t uid = change_uid ? (uid_t)F_OWNER(file) : sxp->st.st_uid; 629 554 gid_t gid = change_gid ? (gid_t)F_GROUP(file) : sxp->st.st_gid; … … diff --git a/rsync.c b/rsync.c 632 557 /* We shouldn't have attempted to change uid 633 558 * or gid unless have the privilege. */ 634 559 rsyserr(FERROR_XFER, errno, "%s %s failed", 635 @@ -503,7 +581,7 @@ int set_file_attrs(const char *fname, struct file_struct *file, stat_x *sxp, 560 @@ -549,7 +583,7 @@ int set_file_attrs(const char *fname, struct file_struct *file, stat_x *sxp, 561 flags |= ATTRS_SKIP_MTIME; 562 if (!(flags & ATTRS_SKIP_MTIME) 563 && cmp_time(sxp->st.st_mtime, file->modtime) != 0) { 564 - int ret = set_modtime(fname, file->modtime, F_MOD_NSEC(file), sxp->st.st_mode); 565 + int ret = set_modtime(fname, file->modtime, F_MOD_NSEC(file), sxp->st.st_mode, ST_FLAGS(sxp->st)); 566 if (ret < 0) { 567 rsyserr(FERROR_XFER, errno, "failed to set times on %s", 568 full_fname(fname)); 569 @@ -576,7 +610,7 @@ int set_file_attrs(const char *fname, struct file_struct *file, stat_x *sxp, 636 570 637 571 #ifdef HAVE_CHMOD 638 572 if (!BITS_EQUAL(sxp->st.st_mode, new_mode, CHMOD_BITS)) { … … diff --git a/rsync.c b/rsync.c 641 575 if (ret < 0) { 642 576 rsyserr(FERROR_XFER, errno, 643 577 "failed to set permissions on %s", 644 @@ -5 15,6 +593,24@@ int set_file_attrs(const char *fname, struct file_struct *file, stat_x *sxp,578 @@ -588,6 +622,19 @@ int set_file_attrs(const char *fname, struct file_struct *file, stat_x *sxp, 645 579 } 646 580 #endif 647 581 648 +#ifdef SUPPORT_FORCE_CHANGE649 + if (became_mutable)650 + undo_make_mutable(fname, sxp->st.st_flags);651 +#endif652 +653 582 +#ifdef SUPPORT_FILEFLAGS 654 583 + if (preserve_fileflags && !S_ISLNK(sxp->st.st_mode) 655 584 + && sxp->st.st_flags != F_FFLAGS(file)) { … … diff --git a/rsync.c b/rsync.c 663 592 + } 664 593 +#endif 665 594 + 666 if ( verbose > 1&& flags & ATTRS_REPORT) {595 if (INFO_GTE(NAME, 2) && flags & ATTRS_REPORT) { 667 596 if (updated) 668 597 rprintf(FCLIENT, "%s\n", fname); 669 @@ - 578,7 +674,8 @@ int finish_transfer(const char *fname, const char *fnametmp,598 @@ -662,7 +709,8 @@ int finish_transfer(const char *fname, const char *fnametmp, 670 599 671 600 /* Change permissions before putting the file into place. */ 672 601 set_file_attrs(fnametmp, file, NULL, fnamecmp, … … diff --git a/rsync.c b/rsync.c 675 604 + | (ok_to_set_time ? 0 : ATTRS_SKIP_MTIME)); 676 605 677 606 /* move tmp file over real file */ 678 if ( verbose > 2)679 @@ - 597,6 +694,10 @@ int finish_transfer(const char *fname, const char *fnametmp,607 if (DEBUG_GTE(RECV, 1)) 608 @@ -679,6 +727,10 @@ int finish_transfer(const char *fname, const char *fnametmp, 680 609 } 681 610 if (ret == 0) { 682 611 /* The file was moved into place (not copied), so it's done. */ … … diff --git a/rsync.c b/rsync.c 690 619 diff --git a/rsync.h b/rsync.h 691 620 --- a/rsync.h 692 621 +++ b/rsync.h 693 @@ -61,6 +61,7 @@ 694 #define XMIT_GROUP_NAME_FOLLOWS (1<<11) /* protocols 30 - now */ 622 @@ -62,6 +62,7 @@ 695 623 #define XMIT_HLINK_FIRST (1<<12) /* protocols 30 - now (HLINKED files only) */ 696 624 #define XMIT_IO_ERROR_ENDLIST (1<<12) /* protocols 31*- now (w/XMIT_EXTENDED_FLAGS) (also protocol 30 w/'f' compat flag) */ 625 #define XMIT_MOD_NSEC (1<<13) /* protocols 31 - now */ 697 626 +#define XMIT_SAME_FLAGS (1<<14) /* protocols ?? - now */ 698 627 699 628 /* These flags are used in the live flist data. */ 700 629 701 @@ -16 0,6 +161,7 @@630 @@ -165,6 +166,7 @@ 702 631 703 632 #define ATTRS_REPORT (1<<0) 704 633 #define ATTRS_SKIP_MTIME (1<<1) … … diff --git a/rsync.h b/rsync.h 706 635 707 636 #define FULL_FLUSH 1 708 637 #define NORMAL_FLUSH 0 709 @@ -1 86,6 +188,7 @@638 @@ -191,6 +193,7 @@ 710 639 #define ITEM_REPORT_GROUP (1<<6) 711 640 #define ITEM_REPORT_ACL (1<<7) 712 641 #define ITEM_REPORT_XATTR (1<<8) … … diff --git a/rsync.h b/rsync.h 714 643 #define ITEM_BASIS_TYPE_FOLLOWS (1<<11) 715 644 #define ITEM_XNAME_FOLLOWS (1<<12) 716 645 #define ITEM_IS_NEW (1<<13) 717 @@ - 482,6 +485,28 @@ typedef unsigned int size_t;646 @@ -522,6 +525,28 @@ typedef unsigned int size_t; 718 647 #endif 719 648 #endif 720 649 … … diff --git a/rsync.h b/rsync.h 743 672 /* Find a variable that is either exactly 32-bits or longer. 744 673 * If some code depends on 32-bit truncation, it will need to 745 674 * take special action in a "#if SIZEOF_INT32 > 4" section. */ 746 @@ - 652,6 +677,7 @@ extern int file_extra_cnt;675 @@ -709,6 +734,7 @@ extern int file_extra_cnt; 747 676 extern int inc_recurse; 748 677 extern int uid_ndx; 749 678 extern int gid_ndx; … … diff --git a/rsync.h b/rsync.h 751 680 extern int acls_ndx; 752 681 extern int xattrs_ndx; 753 682 754 @@ - 689,6 +715,11 @@ extern int xattrs_ndx;683 @@ -750,6 +776,11 @@ extern int xattrs_ndx; 755 684 /* When the associated option is on, all entries will have these present: */ 756 685 #define F_OWNER(f) REQ_EXTRA(f, uid_ndx)->unum 757 686 #define F_GROUP(f) REQ_EXTRA(f, gid_ndx)->unum … … diff --git a/rsync.h b/rsync.h 766 695 diff --git a/rsync.yo b/rsync.yo 767 696 --- a/rsync.yo 768 697 +++ b/rsync.yo 769 @@ -3 55,6 +355,7 @@ to the detailed description below for a complete description. verb(698 @@ -362,6 +362,7 @@ to the detailed description below for a complete description. verb( 770 699 -K, --keep-dirlinks treat symlinked dir on receiver as dir 771 700 -H, --hard-links preserve hard links 772 701 -p, --perms preserve permissions … … diff --git a/rsync.yo b/rsync.yo 774 703 -E, --executability preserve executability 775 704 --chmod=CHMOD affect file and/or directory permissions 776 705 -A, --acls preserve ACLs (implies -p) 777 @@ -3 86,7 +387,10 @@ to the detailed description below for a complete description. verb(778 -- delete-after receiver deletes after transfer, not during779 --delete- excluded also delete excluded files from dest dirs706 @@ -397,7 +398,10 @@ to the detailed description below for a complete description. verb( 707 --ignore-missing-args ignore missing source args without error 708 --delete-missing-args delete missing source args from destination 780 709 --ignore-errors delete even if there are I/O errors 781 710 - --force force deletion of dirs even if not empty 782 711 + --force-delete force deletion of dirs even if not empty … … diff --git a/rsync.yo b/rsync.yo 786 715 --max-delete=NUM don't delete more than NUM files 787 716 --max-size=SIZE don't transfer any file larger than SIZE 788 717 --min-size=SIZE don't transfer any file smaller than SIZE 789 @@ - 566,7 +570,8 @@ specified, in which case bf(-r) is not implied.718 @@ -644,7 +648,8 @@ specified, in which case bf(-r) is not implied. 790 719 791 720 Note that bf(-a) bf(does not preserve hardlinks), because 792 721 finding multiply-linked files is expensive. You must separately … … diff --git a/rsync.yo b/rsync.yo 796 725 797 726 dit(--no-OPTION) You may turn off one or more implied options by prefixing 798 727 the option name with "no-". Not all options may be prefixed with a "no-": 799 @@ - 846,7 +851,7 @@ they would be using bf(--copy-links).728 @@ -943,7 +948,7 @@ they would be using bf(--copy-links). 800 729 Without this option, if the sending side has replaced a directory with a 801 730 symlink to a directory, the receiving side will delete anything that is in 802 731 the way of the new symlink, including a directory hierarchy (as long as … … diff --git a/rsync.yo b/rsync.yo 805 734 806 735 See also bf(--keep-dirlinks) for an analogous option for the receiving 807 736 side. 808 @@ -1 009,6 +1014,29 @@ Note that this option does not copy rsyncs special xattr values (e.g. those737 @@ -1106,6 +1111,29 @@ Note that this option does not copy rsyncs special xattr values (e.g. those 809 738 used by bf(--fake-super)) unless you repeat the option (e.g. -XX). This 810 739 "copy all xattrs" mode cannot be used with bf(--fake-super). 811 740 … … diff --git a/rsync.yo b/rsync.yo 830 759 +dit(bf(--force-schange)) This option causes rsync to disable system-immutable 831 760 +flags on files and directories that are being updated or deleted on the 832 761 +receiving side. It does not try to affect user flags. This option overrides 833 +bf(--force-change) and bf(--force- schange).762 +bf(--force-change) and bf(--force-uchange). 834 763 + 835 764 dit(bf(--chmod)) This option tells rsync to apply one or more 836 765 comma-separated "chmod" modes to the permission of the files in the 837 766 transfer. The resulting value is treated as though it were the permissions 838 @@ -1 289,12 +1317,13 @@ See bf(--delete) (which is implied) for more details on file-deletion.767 @@ -1435,12 +1463,13 @@ display as a "*missing" entry in the bf(--list-only) output. 839 768 dit(bf(--ignore-errors)) Tells bf(--delete) to go ahead and delete files 840 769 even when there are I/O errors. 841 770 … … diff --git a/rsync.yo b/rsync.yo 852 781 bf(--recursive) option was also enabled. 853 782 854 783 dit(bf(--max-delete=NUM)) This tells rsync not to delete more than NUM 855 @@ - 1782,7 +1811,7 @@ with older versions of rsync, but that also turns on the output of other784 @@ -2074,7 +2103,7 @@ with older versions of rsync, but that also turns on the output of other 856 785 verbose messages). 857 786 858 787 The "%i" escape has a cryptic output that is 11 letters long. The general … … diff --git a/rsync.yo b/rsync.yo 861 790 type of update being done, bf(X) is replaced by the file-type, and the 862 791 other letters represent attributes that may be output if they are being 863 792 modified. 864 @@ - 1838,7 +1867,7 @@ quote(itemization(793 @@ -2130,7 +2159,7 @@ quote(itemization( 865 794 sender's value (requires bf(--owner) and super-user privileges). 866 795 it() A bf(g) means the group is different and is being updated to the 867 796 sender's value (requires bf(--group) and the authority to set the group). … … diff --git a/rsync.yo b/rsync.yo 873 802 diff --git a/syscall.c b/syscall.c 874 803 --- a/syscall.c 875 804 +++ b/syscall.c 876 @@ -3 3,6 +33,7 @@ extern int dry_run;877 extern int am_ root;805 @@ -38,6 +38,7 @@ extern int am_root; 806 extern int am_sender; 878 807 extern int read_only; 879 808 extern int list_only; 880 809 +extern int force_change; 881 810 extern int preserve_perms; 882 811 extern int preserve_executability; 883 812 884 @@ -5 0,14 +51,56@@ int do_unlink(const char *fname)813 @@ -55,7 +56,23 @@ int do_unlink(const char *fname) 885 814 { 886 815 if (dry_run) return 0; 887 816 RETURN_ERROR_IF_RO_OR_LO; 888 817 - return unlink(fname); 889 818 + if (unlink(fname) == 0) 890 819 + return 0; 891 +892 820 +#ifdef SUPPORT_FORCE_CHANGE 893 + if (force_change && (errno == EPERM || errno == EACCES)) { 894 + char parent[MAXPATHLEN]; 895 + int parent_flags; 896 + int saved_errno = errno; 897 + int file_flags = make_mutable(fname, NULL, NO_FFLAGS, force_change); 898 + if (file_flags && unlink(fname) == 0) 899 + return 0; 900 + parent_flags = make_parentdir_mutable(fname, force_change, parent, sizeof parent); 901 + if (parent_flags) { 902 + int ret = unlink(fname); 903 + undo_make_mutable(parent, parent_flags); 904 + if (ret == 0) 905 + return 0; 906 + } 907 + if (file_flags) 908 + undo_make_mutable(fname, file_flags); 909 + errno = saved_errno; 910 + } 911 +#endif 912 + 913 + return -1; 914 } 915 916 int do_symlink(const char *fname1, const char *fname2) 917 { 918 if (dry_run) return 0; 919 RETURN_ERROR_IF_RO_OR_LO; 920 - return symlink(fname1, fname2); 921 + if (symlink(fname1, fname2) == 0) 922 + return 0; 821 + if (force_change && errno == EPERM) { 822 + STRUCT_STAT st; 923 823 + 924 +#ifdef SUPPORT_FORCE_CHANGE 925 + if (force_change && (errno == EPERM || errno == EACCES)) { 926 + char parent[MAXPATHLEN]; 927 + int saved_errno = errno; 928 + int parent_flags = make_parentdir_mutable(fname2, force_change, parent, sizeof parent); 929 + if (parent_flags) { 930 + int ret = symlink(fname1, fname2); 931 + undo_make_mutable(parent, parent_flags); 932 + if (ret == 0) 824 + if (x_lstat(fname, &st, NULL) == 0 825 + && make_mutable(fname, st.st_mode, st.st_flags, force_change) > 0) { 826 + if (unlink(fname) == 0) 933 827 + return 0; 828 + undo_make_mutable(fname, st.st_flags); 934 829 + } 935 + errno = saved_errno; 830 + /* TODO: handle immutable directories */ 831 + errno = EPERM; 936 832 + } 937 833 +#endif 938 +939 834 + return -1; 940 835 } 941 836 942 #ifdef HAVE_LINK 943 @@ -65,18 +108,55 @@ int do_link(const char *fname1, const char *fname2) 944 { 945 if (dry_run) return 0; 946 RETURN_ERROR_IF_RO_OR_LO; 947 - return link(fname1, fname2); 948 + if (link(fname1, fname2) == 0) 949 + return 0; 950 + 951 +#ifdef SUPPORT_FORCE_CHANGE 952 + if (force_change && (errno == EPERM || errno == EACCES)) { 953 + char parent[MAXPATHLEN]; 954 + int saved_errno = errno; 955 + int parent_flags = make_parentdir_mutable(fname2, force_change, parent, sizeof parent); 956 + if (parent_flags) { 957 + int ret = link(fname1, fname2); 958 + undo_make_mutable(parent, parent_flags); 959 + if (ret == 0) 960 + return 0; 961 + } 962 + errno = saved_errno; 963 + } 964 +#endif 965 + 966 + return -1; 837 #ifdef SUPPORT_LINKS 838 @@ -116,14 +133,37 @@ int do_link(const char *fname1, const char *fname2) 967 839 } 968 840 #endif 969 841 … … diff --git a/syscall.c b/syscall.c 978 850 - return lchown(path, owner, group); 979 851 + if (lchown(path, owner, group) == 0) 980 852 + return 0; 981 +982 853 +#ifdef SUPPORT_FORCE_CHANGE 983 + if (force_change && (errno == EPERM || errno == EACCES)) { 984 + int saved_errno = errno; 985 + fileflags = make_mutable(path, &mode, fileflags, force_change); 986 + if (fileflags) { 854 + if (force_change && errno == EPERM) { 855 + if (fileflags == NO_FFLAGS) { 856 + STRUCT_STAT st; 857 + if (x_lstat(path, &st, NULL) == 0) { 858 + mode = st.st_mode; 859 + fileflags = st.st_flags; 860 + } 861 + } 862 + if (fileflags != NO_FFLAGS 863 + && make_mutable(path, mode, fileflags, force_change) > 0) { 987 864 + int ret = lchown(path, owner, group); 988 865 + undo_make_mutable(path, fileflags); 989 866 + if (ret == 0) 990 867 + return 0; 991 868 + } 992 + errno = saved_errno;869 + errno = EPERM; 993 870 + } 994 871 +#else 995 872 + mode = fileflags = 0; /* avoid compiler warning */ 996 873 +#endif 997 +998 874 + return -1; 999 875 } 1000 876 1001 877 int do_mknod(const char *pathname, mode_t mode, dev_t dev) 1002 @@ -1 16,7 +196,7 @@ int do_mknod(const char *pathname, mode_t mode, dev_t dev)878 @@ -163,7 +203,7 @@ int do_mknod(const char *pathname, mode_t mode, dev_t dev) 1003 879 return -1; 1004 880 close(sock); 1005 881 #ifdef HAVE_CHMOD … … diff --git a/syscall.c b/syscall.c 1008 884 #else 1009 885 return 0; 1010 886 #endif 1011 @@ -1 33,21 +213,63@@ int do_rmdir(const char *pathname)887 @@ -180,7 +220,22 @@ int do_rmdir(const char *pathname) 1012 888 { 1013 889 if (dry_run) return 0; 1014 890 RETURN_ERROR_IF_RO_OR_LO; 1015 891 - return rmdir(pathname); 1016 892 + if (rmdir(pathname) == 0) 1017 893 + return 0; 1018 +1019 894 +#ifdef SUPPORT_FORCE_CHANGE 1020 + if (force_change && (errno == EPERM || errno == EACCES)) { 1021 + char parent[MAXPATHLEN]; 1022 + int parent_flags; 1023 + int saved_errno = errno; 1024 + int file_flags = make_mutable(pathname, NULL, NO_FFLAGS, force_change); 1025 + if (file_flags && rmdir(pathname) == 0) 1026 + return 0; 1027 + parent_flags = make_parentdir_mutable(pathname, force_change, parent, sizeof parent); 1028 + if (parent_flags) { 1029 + int ret = rmdir(pathname); 1030 + undo_make_mutable(parent, parent_flags); 1031 + if (ret == 0) 895 + if (force_change && errno == EPERM) { 896 + STRUCT_STAT st; 897 + 898 + if (x_lstat(pathname, &st, NULL) == 0 899 + && make_mutable(pathname, st.st_mode, st.st_flags, force_change) > 0) { 900 + if (rmdir(pathname) == 0) 1032 901 + return 0; 902 + undo_make_mutable(pathname, st.st_flags); 1033 903 + } 1034 + if (file_flags) 1035 + undo_make_mutable(pathname, file_flags); 1036 + errno = saved_errno; 904 + errno = EPERM; 1037 905 + } 1038 906 +#endif 1039 +1040 907 + return -1; 1041 908 } 1042 909 1043 910 int do_open(const char *pathname, int flags, mode_t mode) 1044 { 1045 + int fd; 1046 if (flags != O_RDONLY) { 1047 RETURN_ERROR_IF(dry_run, 0); 1048 RETURN_ERROR_IF_RO_OR_LO; 1049 } 1050 + if ((fd = open(pathname, flags | O_BINARY, mode)) >= 0) 1051 + return fd; 1052 + 1053 +#ifdef SUPPORT_FORCE_CHANGE 1054 + if (force_change && (errno == EPERM || errno == EACCES)) { 1055 + char parent[MAXPATHLEN]; 1056 + int saved_errno = errno; 1057 + int parent_flags = make_parentdir_mutable(pathname, force_change, parent, sizeof parent); 1058 + if (parent_flags) { 1059 + fd = open(pathname, flags | O_BINARY, mode); 1060 + undo_make_mutable(parent, parent_flags); 1061 + if (fd >= 0) 1062 + return fd; 1063 + } 1064 + errno = saved_errno; 1065 + } 1066 +#endif 1067 1068 - return open(pathname, flags | O_BINARY, mode); 1069 + return -1; 911 @@ -194,7 +249,7 @@ int do_open(const char *pathname, int flags, mode_t mode) 1070 912 } 1071 913 1072 914 #ifdef HAVE_CHMOD … … diff --git a/syscall.c b/syscall.c 1075 917 { 1076 918 int code; 1077 919 if (dry_run) return 0; 1078 @@ - 170,17 +292,93@@ int do_chmod(const char *path, mode_t mode)920 @@ -217,17 +272,74 @@ int do_chmod(const char *path, mode_t mode) 1079 921 } else 1080 922 code = chmod(path, mode & CHMOD_BITS); /* DISCOURAGED FUNCTION */ 1081 923 #endif /* !HAVE_LCHMOD */ 1082 924 +#ifdef SUPPORT_FORCE_CHANGE 1083 + if (code < 0 && force_change && (errno == EPERM || errno == EACCES) && !S_ISLNK(mode)) { 1084 + int saved_errno = errno; 1085 + fileflags = make_mutable(path, &mode, fileflags, force_change); 1086 + if (fileflags) { 1087 +#ifdef HAVE_LCHMOD 1088 + code = lchmod(path, mode & CHMOD_BITS); 1089 +#else 925 + if (code < 0 && force_change && errno == EPERM && !S_ISLNK(mode)) { 926 + if (fileflags == NO_FFLAGS) { 927 + STRUCT_STAT st; 928 + if (x_lstat(path, &st, NULL) == 0) 929 + fileflags = st.st_flags; 930 + } 931 + if (fileflags != NO_FFLAGS 932 + && make_mutable(path, mode, fileflags, force_change) > 0) { 1090 933 + code = chmod(path, mode & CHMOD_BITS); 1091 +#endif1092 934 + undo_make_mutable(path, fileflags); 1093 935 + if (code == 0) 1094 936 + return 0; 1095 937 + } 1096 + errno = saved_errno;938 + errno = EPERM; 1097 939 + } 1098 940 +#else 1099 941 + fileflags = 0; /* avoid compiler warning */ … … diff --git a/syscall.c b/syscall.c 1120 962 - return rename(fname1, fname2); 1121 963 + if (rename(fname1, fname2) == 0) 1122 964 + return 0; 1123 +1124 965 +#ifdef SUPPORT_FORCE_CHANGE 1125 + if (force_change && (errno == EPERM || errno == EACCES)) { 1126 + int saved_errno = errno; 1127 + int ret = -1, file2_flags = 0; 1128 + int file1_flags = make_mutable(fname1, NULL, NO_FFLAGS, force_change); 1129 + if (file1_flags && rename(fname1, fname2) == 0) 1130 + ret = 0; 1131 + else { 1132 + file2_flags = make_mutable(fname2, NULL, NO_FFLAGS, force_change); 1133 + if (file2_flags && rename(fname1, fname2) == 0) 1134 + ret = 0; 1135 + else { 1136 + char parent1[MAXPATHLEN]; 1137 + int parent1_flags = make_parentdir_mutable(fname1, force_change, 1138 + parent1, sizeof parent1); 1139 + if (parent1_flags && rename(fname1, fname2) == 0) 1140 + ret = 0; 1141 + else { 1142 + char parent2[MAXPATHLEN]; 1143 + int parent2_flags = make_parentdir_mutable(fname2, force_change, 1144 + parent2, sizeof parent2); 1145 + if (parent2_flags) { 1146 + if (rename(fname1, fname2) == 0) 1147 + ret = 0; 1148 + undo_make_mutable(parent2, parent2_flags); 1149 + } 1150 + } 1151 + if (parent1_flags) 1152 + undo_make_mutable(parent1, parent1_flags); 1153 + } 1154 + } 1155 + 1156 + if (ret == 0) 1157 + file2_flags = file1_flags; /* file1 is now file2 */ 1158 + else if (file1_flags) 1159 + undo_make_mutable(fname1, file1_flags); 1160 + if (file2_flags) 1161 + undo_make_mutable(fname2, file2_flags); 1162 + if (ret == 0) 1163 + return 0; 1164 + 1165 + errno = saved_errno; 1166 + } 1167 +#endif 966 + if (force_change && errno == EPERM) { 967 + STRUCT_STAT st1, st2; 968 + int became_mutable; 1168 969 + 1169 + return -1; 1170 } 1171 1172 #ifdef HAVE_FTRUNCATE 1173 @@ -222,7 +420,25 @@ int do_mkdir(char *fname, mode_t mode) 1174 if (dry_run) return 0; 1175 RETURN_ERROR_IF_RO_OR_LO; 1176 trim_trailing_slashes(fname); 1177 - return mkdir(fname, mode); 1178 + if (mkdir(fname, mode) == 0) 1179 + return 0; 1180 + 1181 +#ifdef SUPPORT_FORCE_CHANGE 1182 + if (force_change && (errno == EPERM || errno == EACCES)) { 1183 + char parent[MAXPATHLEN]; 1184 + int saved_errno = errno; 1185 + int parent_flags = make_parentdir_mutable(fname, force_change, parent, sizeof parent); 1186 + if (parent_flags) { 1187 + int ret = mkdir(fname, mode); 1188 + undo_make_mutable(parent, parent_flags); 1189 + if (ret == 0) 970 + if (x_lstat(fname1, &st1, NULL) != 0) 971 + goto failed; 972 + became_mutable = make_mutable(fname1, st1.st_mode, st1.st_flags, force_change) > 0; 973 + if (became_mutable && rename(fname1, fname2) == 0) 974 + goto success; 975 + if (x_lstat(fname2, &st2, NULL) == 0 976 + && make_mutable(fname2, st2.st_mode, st2.st_flags, force_change) > 0) { 977 + if (rename(fname1, fname2) == 0) { 978 + success: 979 + if (became_mutable) /* Yes, use fname2 and st1! */ 980 + undo_make_mutable(fname2, st1.st_flags); 1190 981 + return 0; 1191 + }1192 + errno = saved_errno;1193 + }1194 +#endif1195 +1196 + return -1;1197 }1198 1199 /* like mkstemp but forces permissions */1200 @@ -235,7 +451,19 @@ int do_mkstemp(char *template, mode_t perms)1201 #if defined HAVE_SECURE_MKSTEMP && defined HAVE_FCHMOD && (!defined HAVE_OPEN64 || defined HAVE_MKSTEMP64)1202 {1203 int fd = mkstemp(template);1204 - if (fd == -1)1205 +#ifdef SUPPORT_FORCE_CHANGE1206 + if (fd < 0 && force_change) {1207 + char parent[MAXPATHLEN];1208 + int saved_errno = errno;1209 + int parent_flags = make_parentdir_mutable(template, force_change, parent, sizeof parent);1210 + if (parent_flags) {1211 + fd = mkstemp(template);1212 + undo_make_mutable(parent, parent_flags);1213 982 + } 1214 + errno = saved_errno;983 + undo_make_mutable(fname2, st2.st_flags); 1215 984 + } 1216 +#endif 1217 + if (fd < 0) 1218 return -1; 1219 if (fchmod(fd, perms) != 0 && preserve_perms) { 1220 int errno_save = errno; 1221 @@ -302,7 +530,7 @@ OFF_T do_lseek(int fd, OFF_T offset, int whence) 1222 } 1223 1224 #ifdef HAVE_UTIMENSAT 1225 -int do_utimensat(const char *fname, time_t modtime, uint32 mod_nsec) 1226 +int do_utimensat(const char *fname, time_t modtime, uint32 mod_nsec, mode_t mode, uint32 fileflags) 1227 { 1228 struct timespec t[2]; 1229 1230 @@ -313,12 +541,26 @@ int do_utimensat(const char *fname, time_t modtime, uint32 mod_nsec) 1231 t[0].tv_nsec = UTIME_NOW; 1232 t[1].tv_sec = modtime; 1233 t[1].tv_nsec = mod_nsec; 1234 - return utimensat(AT_FDCWD, fname, t, AT_SYMLINK_NOFOLLOW); 1235 + if (utimensat(AT_FDCWD, fname, t, AT_SYMLINK_NOFOLLOW) == 0) 1236 + return 0; 1237 + 1238 +#ifdef SUPPORT_FORCE_CHANGE 1239 + fileflags = make_mutable(fname, &mode, fileflags, force_change); 1240 + if (fileflags) { 1241 + if (utimensat(AT_FDCWD, fname, t, AT_SYMLINK_NOFOLLOW) == 0) 1242 + return 0; 1243 + undo_make_mutable(fname, fileflags); 1244 + } 1245 +#else 1246 + mode = fileflags; /* avoid compiler warning */ 1247 +#endif 1248 + 1249 + return -1; 1250 } 1251 #endif 1252 1253 #ifdef HAVE_LUTIMES 1254 -int do_lutimes(const char *fname, time_t modtime, uint32 mod_nsec) 1255 +int do_lutimes(const char *fname, time_t modtime, uint32 mod_nsec, mode_t mode, uint32 fileflags) 1256 { 1257 struct timeval t[2]; 1258 1259 @@ -329,12 +571,26 @@ int do_lutimes(const char *fname, time_t modtime, uint32 mod_nsec) 1260 t[0].tv_usec = 0; 1261 t[1].tv_sec = modtime; 1262 t[1].tv_usec = mod_nsec / 1000; 1263 - return lutimes(fname, t); 1264 + if (lutimes(fname, t) == 0) 1265 + return 0; 1266 + 1267 +#ifdef SUPPORT_FORCE_CHANGE 1268 + fileflags = make_mutable(fname, &mode, fileflags, force_change); 1269 + if (fileflags) { 1270 + if (lutimes(fname, t) == 0) 1271 + return 0; 1272 + undo_make_mutable(fname, fileflags); 1273 + } 1274 +#else 1275 + mode = fileflags; /* avoid compiler warning */ 1276 +#endif 1277 + 1278 + return -1; 1279 } 1280 #endif 1281 1282 #ifdef HAVE_UTIMES 1283 -int do_utimes(const char *fname, time_t modtime, uint32 mod_nsec) 1284 +int do_utimes(const char *fname, time_t modtime, uint32 mod_nsec, mode_t mode, uint32 fileflags) 1285 { 1286 struct timeval t[2]; 1287 1288 @@ -345,14 +601,28 @@ int do_utimes(const char *fname, time_t modtime, uint32 mod_nsec) 1289 t[0].tv_usec = 0; 1290 t[1].tv_sec = modtime; 1291 t[1].tv_usec = mod_nsec / 1000; 1292 - return utimes(fname, t); 1293 + if (utimes(fname, t) == 0) 1294 + return 0; 1295 + 1296 +#ifdef SUPPORT_FORCE_CHANGE 1297 + fileflags = make_mutable(fname, &mode, fileflags, force_change); 1298 + if (fileflags) { 1299 + if (utimes(fname, t) == 0) 1300 + return 0; 1301 + undo_make_mutable(fname, fileflags); 985 + /* TODO: handle immutable directories */ 986 + if (became_mutable) 987 + undo_make_mutable(fname1, st1.st_flags); 988 + failed: 989 + errno = EPERM; 1302 990 + } 1303 +#else1304 + mode = fileflags; /* avoid compiler warning */1305 991 +#endif 1306 +1307 992 + return -1; 1308 993 } 1309 994 1310 #elif defined HAVE_UTIME 1311 -int do_utime(const char *fname, time_t modtime, UNUSED(uint32 mod_nsec)) 1312 +int do_utime(const char *fname, time_t modtime, UNUSED(uint32 mod_nsec), mode_t mode, uint32 fileflags) 1313 { 1314 #ifdef HAVE_STRUCT_UTIMBUF 1315 - struct utimbuf tbuf; 1316 + struct utimbuf tbuf, *t = &tbuf; 1317 #else 1318 time_t t[2]; 1319 #endif 1320 @@ -360,15 +630,28 @@ int do_utime(const char *fname, time_t modtime, UNUSED(uint32 mod_nsec)) 1321 if (dry_run) return 0; 1322 RETURN_ERROR_IF_RO_OR_LO; 1323 1324 -# ifdef HAVE_STRUCT_UTIMBUF 1325 +#ifdef HAVE_STRUCT_UTIMBUF 1326 tbuf.actime = time(NULL); 1327 tbuf.modtime = modtime; 1328 - return utime(fname, &tbuf); 1329 -# else 1330 +#else 1331 t[0] = time(NULL); 1332 t[1] = modtime; 1333 - return utime(fname, t); 1334 -# endif 1335 +#endif 1336 + if (utime(fname, t) == 0) 1337 + return 0; 1338 + 1339 +#ifdef SUPPORT_FORCE_CHANGE 1340 + fileflags = make_mutable(fname, &mode, fileflags, force_change); 1341 + if (fileflags) { 1342 + if (utime(fname, t) == 0) 1343 + return 0; 1344 + undo_make_mutable(fname, fileflags); 1345 + } 1346 +#else 1347 + mode = fileflags; /* avoid compiler warning */ 1348 +#endif 1349 + 1350 + return -1; 1351 } 1352 1353 #else 995 #ifdef HAVE_FTRUNCATE 1354 996 diff --git a/t_stub.c b/t_stub.c 1355 997 --- a/t_stub.c 1356 998 +++ b/t_stub.c 1357 @@ -26,6 +26,7 @@ int module_id = -1; 999 @@ -28,6 +28,7 @@ int module_id = -1; 1000 int checksum_len = 0; 1358 1001 int relative_paths = 0; 1359 int human_readable = 0;1360 1002 int module_dirlen = 0; 1361 1003 +int force_change = 0; 1004 int preserve_acls = 0; 1362 1005 int preserve_times = 0; 1363 1006 int preserve_xattrs = 0; 1364 mode_t orig_umask = 002; 1365 @@ -90,3 +91,27 @@ struct filter_list_struct daemon_filter_list; 1007 @@ -97,3 +98,23 @@ filter_rule_list daemon_filter_list; 1366 1008 { 1367 1009 return "tester"; 1368 1010 } 1369 1011 + 1370 1012 +#if defined SUPPORT_FILEFLAGS || defined SUPPORT_FORCE_CHANGE 1371 + uint32 make_mutable(UNUSED(const char *fname), UNUSED(mode_t *mode), UNUSED(uint32 fileflags), UNUSED(uint32 iflags))1013 + int make_mutable(UNUSED(const char *fname), UNUSED(mode_t mode), UNUSED(uint32 fileflags), UNUSED(uint32 iflags)) 1372 1014 +{ 1373 1015 + return 0; 1374 1016 +} 1375 1017 + 1018 +/* Undo a prior make_mutable() call that returned a 1. */ 1376 1019 + int undo_make_mutable(UNUSED(const char *fname), UNUSED(uint32 fileflags)) 1377 1020 +{ 1378 1021 + return 0; 1379 1022 +} 1380 +1381 + int make_parentdir_mutable(UNUSED(const char *fname), UNUSED(uint32 iflags), UNUSED(char *parent_dirbuf), UNUSED(int parent_dirbuf_size))1382 +{1383 + return 0;1384 +}1385 1023 +#endif 1386 1024 + 1387 1025 +#ifdef SUPPORT_XATTRS … … diff --git a/t_stub.c b/t_stub.c 1393 1031 diff --git a/util.c b/util.c 1394 1032 --- a/util.c 1395 1033 +++ b/util.c 1396 @@ -125,7 +125,7 @@ NORETURN void overflow_exit(const char *str) 1034 @@ -33,6 +33,7 @@ extern int relative_paths; 1035 extern int preserve_times; 1036 extern int preserve_xattrs; 1037 extern int preallocate_files; 1038 +extern int force_change; 1039 extern char *module_dir; 1040 extern unsigned int module_dirlen; 1041 extern char *partial_dir; 1042 @@ -115,9 +116,36 @@ void print_child_argv(const char *prefix, char **cmd) 1043 rprintf(FCLIENT, " (%d args)\n", cnt); 1044 } 1397 1045 1046 +#ifdef SUPPORT_FORCE_CHANGE 1047 +static int try_a_force_change(const char *fname, time_t modtime, uint32 mod_nsec, mode_t mode, uint32 fileflags) 1048 +{ 1049 + if (fileflags == NO_FFLAGS) { 1050 + STRUCT_STAT st; 1051 + if (x_lstat(fname, &st, NULL) == 0) 1052 + fileflags = st.st_flags; 1053 + } 1054 + 1055 + if (fileflags != NO_FFLAGS && make_mutable(fname, mode, fileflags, force_change) > 0) { 1056 + int ret, save_force_change = force_change; 1057 + 1058 + force_change = 0; /* Make certain we can't come back here. */ 1059 + ret = set_modtime(fname, modtime, mod_nsec, mode, fileflags); 1060 + force_change = save_force_change; 1061 + 1062 + undo_make_mutable(fname, fileflags); 1063 + 1064 + return ret; 1065 + } 1066 + 1067 + errno = EPERM; 1068 + 1069 + return -1; 1070 +} 1071 +#endif 1072 + 1398 1073 /* This returns 0 for success, 1 for a symlink if symlink time-setting 1399 1074 * is not possible, or -1 for any other error. */ 1400 -int set_modtime(const char *fname, time_t modtime, mode_t mode)1401 +int set_modtime(const char *fname, time_t modtime, mode_t mode, uint32 fileflags)1075 -int set_modtime(const char *fname, time_t modtime, uint32 mod_nsec, mode_t mode) 1076 +int set_modtime(const char *fname, time_t modtime, uint32 mod_nsec, mode_t mode, uint32 fileflags) 1402 1077 { 1403 1078 static int switch_step = 0; 1404 1079 1405 @@ -138,7 +138,7 @@ int set_modtime(const char *fname, time_t modtime, mode_t mode) 1406 switch (switch_step) { 1407 #ifdef HAVE_UTIMENSAT 1080 @@ -132,6 +160,11 @@ int set_modtime(const char *fname, time_t modtime, uint32 mod_nsec, mode_t mode) 1408 1081 #include "case_N.h" 1409 - if (do_utimensat(fname, modtime, 0) == 0) 1410 + if (do_utimensat(fname, modtime, 0, mode, fileflags) == 0) 1082 if (do_utimensat(fname, modtime, mod_nsec) == 0) 1411 1083 break; 1084 +#ifdef SUPPORT_FORCE_CHANGE 1085 + if (force_change && errno == EPERM 1086 + && try_a_force_change(fname, modtime, mod_nsec, mode, fileflags) == 0) 1087 + break; 1088 +#endif 1412 1089 if (errno != ENOSYS) 1413 1090 return -1; 1414 @@ -148,7 +148,7 @@ int set_modtime(const char *fname, time_t modtime, mode_t mode) 1415 1416 #ifdef HAVE_LUTIMES 1091 switch_step++; 1092 @@ -142,6 +175,11 @@ int set_modtime(const char *fname, time_t modtime, uint32 mod_nsec, mode_t mode) 1417 1093 #include "case_N.h" 1418 - if (do_lutimes(fname, modtime, 0) == 0) 1419 + if (do_lutimes(fname, modtime, 0, mode, fileflags) == 0) 1094 if (do_lutimes(fname, modtime, mod_nsec) == 0) 1420 1095 break; 1096 +#ifdef SUPPORT_FORCE_CHANGE 1097 + if (force_change && errno == EPERM 1098 + && try_a_force_change(fname, modtime, mod_nsec, mode, fileflags) == 0) 1099 + break; 1100 +#endif 1421 1101 if (errno != ENOSYS) 1422 1102 return -1; 1423 @@ -167,10 +167,10 @@ int set_modtime(const char *fname, time_t modtime, mode_t mode) 1424 1425 #include "case_N.h" 1426 #ifdef HAVE_UTIMES 1427 - if (do_utimes(fname, modtime, 0) == 0) 1428 + if (do_utimes(fname, modtime, 0, mode, fileflags) == 0) 1429 break; 1430 #else 1431 - if (do_utime(fname, modtime, 0) == 0) 1432 + if (do_utime(fname, modtime, 0, mode, fileflags) == 0) 1103 switch_step++; 1104 @@ -165,6 +203,13 @@ int set_modtime(const char *fname, time_t modtime, uint32 mod_nsec, mode_t mode) 1105 if (do_utime(fname, modtime, mod_nsec) == 0) 1433 1106 break; 1434 1107 #endif 1108 +#ifdef SUPPORT_FORCE_CHANGE 1109 + if (force_change && errno == EPERM 1110 + && try_a_force_change(fname, modtime, mod_nsec, mode, fileflags) == 0) 1111 + break; 1112 +#else 1113 + fileflags = 0; /* avoid compiler warning */ 1114 +#endif 1435 1115 1116 return -1; 1117 } 1436 1118 diff --git a/xattrs.c b/xattrs.c 1437 1119 --- a/xattrs.c 1438 1120 +++ b/xattrs.c 1439 @@ -104 2,7 +1042,7 @@ int set_stat_xattr(const char *fname, struct file_struct *file, mode_t new_mode)1121 @@ -1045,7 +1045,7 @@ int set_stat_xattr(const char *fname, struct file_struct *file, mode_t new_mode) 1440 1122 mode = (fst.st_mode & _S_IFMT) | (fmode & ACCESSPERMS) 1441 1123 | (S_ISDIR(fst.st_mode) ? 0700 : 0600); 1442 1124 if (fst.st_mode != mode) … … diff --git a/xattrs.c b/xattrs.c 1445 1127 if (!IS_DEVICE(fst.st_mode)) 1446 1128 fst.st_rdev = 0; /* just in case */ 1447 1129 1448 diff - up a/config.h.in b/config.h.in1130 diff -Nurp a/config.h.in b/config.h.in 1449 1131 --- a/config.h.in 1450 1132 +++ b/config.h.in 1451 @@ -7 0,6 +70,9 @@1133 @@ -76,6 +76,9 @@ 1452 1134 /* Define to 1 if vsprintf has a C99-compatible return value */ 1453 1135 #undef HAVE_C99_VSNPRINTF 1454 1136 … … diff -up a/config.h.in b/config.h.in 1458 1140 /* Define to 1 if you have the `chmod' function. */ 1459 1141 #undef HAVE_CHMOD 1460 1142 1461 diff - up a/configure.sh b/configure.sh1143 diff -Nurp a/configure.sh b/configure.sh 1462 1144 --- a/configure.sh 1463 1145 +++ b/configure.sh 1464 @@ -7 444,6 +7444,7 @@ fi1146 @@ -7652,6 +7652,7 @@ fi 1465 1147 1466 1148 for ac_func in waitpid wait4 getcwd strdup chown chmod lchmod mknod mkfifo \ 1467 1149 fchmod fstat ftruncate strchr readlink link utime utimes lutimes strftime \ … … diff -up a/configure.sh b/configure.sh 1469 1151 memmove lchown vsnprintf snprintf vasprintf asprintf setsid strpbrk \ 1470 1152 strlcat strlcpy strtol mallinfo getgroups setgroups geteuid getegid \ 1471 1153 setlocale setmode open64 lseek64 mkstemp64 mtrace va_copy __va_copy \ 1472 diff - up a/proto.h b/proto.h1154 diff -Nurp a/proto.h b/proto.h 1473 1155 --- a/proto.h 1474 1156 +++ b/proto.h 1475 @@ -2 74,6 +274,9 @@ int read_ndx_and_attrs(int f_in, int *if1157 @@ -286,6 +286,8 @@ int read_ndx_and_attrs(int f_in, int f_o 1476 1158 void free_sums(struct sum_struct *s); 1477 1159 mode_t dest_mode(mode_t flist_mode, mode_t stat_mode, int dflt_perms, 1478 1160 int exists); 1479 + uint32 make_mutable(const char *fname, mode_t *mode_ptr, uint32 fileflags, uint32 iflags);1161 +int make_mutable(const char *fname, mode_t mode, uint32 fileflags, uint32 iflags); 1480 1162 +int undo_make_mutable(const char *fname, uint32 fileflags); 1481 +int make_parentdir_mutable(const char *fname, uint32 iflags, char *parent_dirbuf, int parent_dirbuf_size);1482 1163 int set_file_attrs(const char *fname, struct file_struct *file, stat_x *sxp, 1483 1164 const char *fnamecmp, int flags); 1484 RETSIGTYPE sig_int( UNUSED(int val));1485 @@ - 297,11 +300,12 @@ void set_socket_options(int fd, char *op1486 int do_ unlink(const char *fname);1487 int do_symlink(const char *fname1, const char *fname2);1165 RETSIGTYPE sig_int(int sig_num); 1166 @@ -310,11 +312,12 @@ int do_unlink(const char *fname); 1167 int do_symlink(const char *lnk, const char *fname); 1168 ssize_t do_readlink(const char *path, char *buf, size_t bufsiz); 1488 1169 int do_link(const char *fname1, const char *fname2); 1489 1170 -int do_lchown(const char *path, uid_t owner, gid_t group); 1490 1171 +int do_lchown(const char *path, uid_t owner, gid_t group, mode_t mode, uint32 fileflags); … … diff -up a/proto.h b/proto.h 1497 1178 int do_rename(const char *fname1, const char *fname2); 1498 1179 int do_ftruncate(int fd, OFF_T size); 1499 1180 void trim_trailing_slashes(char *name); 1500 @@ -311,10 +315,10 @@ int do_stat(const char *fname, STRUCT_ST 1501 int do_lstat(const char *fname, STRUCT_STAT *st); 1502 int do_fstat(int fd, STRUCT_STAT *st); 1503 OFF_T do_lseek(int fd, OFF_T offset, int whence); 1504 -int do_utimensat(const char *fname, time_t modtime, uint32 mod_nsec); 1505 -int do_lutimes(const char *fname, time_t modtime, uint32 mod_nsec); 1506 -int do_utimes(const char *fname, time_t modtime, uint32 mod_nsec); 1507 -int do_utime(const char *fname, time_t modtime, UNUSED(uint32 mod_nsec)); 1508 +int do_utimensat(const char *fname, time_t modtime, uint32 mod_nsec, mode_t mode, uint32 fileflags); 1509 +int do_lutimes(const char *fname, time_t modtime, uint32 mod_nsec, mode_t mode, uint32 fileflags); 1510 +int do_utimes(const char *fname, time_t modtime, uint32 mod_nsec, mode_t mode, uint32 fileflags); 1511 +int do_utime(const char *fname, time_t modtime, UNUSED(uint32 mod_nsec), mode_t mode, uint32 fileflags); 1512 void set_compression(const char *fname); 1513 void send_token(int f, int32 token, struct map_struct *buf, OFF_T offset, 1514 int32 n, int32 toklen); 1515 @@ -334,7 +338,7 @@ int fd_pair(int fd[2]); 1181 @@ -353,7 +356,7 @@ void set_nonblocking(int fd); 1182 void set_blocking(int fd); 1183 int fd_pair(int fd[2]); 1516 1184 void print_child_argv(const char *prefix, char **cmd); 1517 NORETURN void out_of_memory(const char *str); 1518 NORETURN void overflow_exit(const char *str); 1519 -int set_modtime(const char *fname, time_t modtime, mode_t mode); 1520 +int set_modtime(const char *fname, time_t modtime, mode_t mode, uint32 fileflags); 1521 int mkdir_defmode(char *fname); 1522 int create_directory_path(char *fname); 1185 -int set_modtime(const char *fname, time_t modtime, uint32 mod_nsec, mode_t mode); 1186 +int set_modtime(const char *fname, time_t modtime, uint32 mod_nsec, mode_t mode, uint32 fileflags); 1187 int make_path(char *fname, int flags); 1523 1188 int full_write(int desc, const char *ptr, size_t len); 1524 diff -up a/rsync.1 b/rsync.1 1189 int copy_file(const char *source, const char *dest, int ofd, mode_t mode); 1190 diff -Nurp a/rsync.1 b/rsync.1 1525 1191 --- a/rsync.1 1526 1192 +++ b/rsync.1 1527 @@ -43 1,6 +431,7 @@ to the detailed description below for a1193 @@ -438,6 +438,7 @@ to the detailed description below for a 1528 1194 \-K, \-\-keep\-dirlinks treat symlinked dir on receiver as dir 1529 1195 \-H, \-\-hard\-links preserve hard links 1530 1196 \-p, \-\-perms preserve permissions … … diff -up a/rsync.1 b/rsync.1 1532 1198 \-E, \-\-executability preserve executability 1533 1199 \-\-chmod=CHMOD affect file and/or directory permissions 1534 1200 \-A, \-\-acls preserve ACLs (implies \-p) 1535 @@ -4 62,7 +463,10 @@ to the detailed description below for a1536 \-\- delete\-after receiver deletes after transfer, not during1537 \-\-delete\- excluded also delete excluded files from dest dirs1201 @@ -473,7 +474,10 @@ to the detailed description below for a 1202 \-\-ignore\-missing\-args ignore missing source args without error 1203 \-\-delete\-missing\-args delete missing source args from destination 1538 1204 \-\-ignore\-errors delete even if there are I/O errors 1539 1205 - \-\-force force deletion of dirs even if not empty 1540 1206 + \-\-force\-delete force deletion of dirs even if not empty … … diff -up a/rsync.1 b/rsync.1 1544 1210 \-\-max\-delete=NUM don'\&t delete more than NUM files 1545 1211 \-\-max\-size=SIZE don'\&t transfer any file larger than SIZE 1546 1212 \-\-min\-size=SIZE don'\&t transfer any file smaller than SIZE 1547 @@ - 658,7 +662,8 @@ specified, in which case \fB\-r\fP is no1213 @@ -743,7 +747,8 @@ specified, in which case \fB\-r\fP is no 1548 1214 .IP 1549 1215 Note that \fB\-a\fP \fBdoes not preserve hardlinks\fP, because 1550 1216 finding multiply\-linked files is expensive. You must separately … … diff -up a/rsync.1 b/rsync.1 1554 1220 .IP 1555 1221 .IP "\-\-no\-OPTION" 1556 1222 You may turn off one or more implied options by prefixing 1557 @@ - 975,7 +980,7 @@ they would be using \fB\-\-copy\-links\f1223 @@ -1080,7 +1085,7 @@ they would be using \fB\-\-copy\-links\f 1558 1224 Without this option, if the sending side has replaced a directory with a 1559 1225 symlink to a directory, the receiving side will delete anything that is in 1560 1226 the way of the new symlink, including a directory hierarchy (as long as … … diff -up a/rsync.1 b/rsync.1 1563 1229 .IP 1564 1230 See also \fB\-\-keep\-dirlinks\fP for an analogous option for the receiving 1565 1231 side. 1566 @@ -1 162,6 +1167,33 @@ Note that this option does not copy rsyn1232 @@ -1267,6 +1272,33 @@ Note that this option does not copy rsyn 1567 1233 used by \fB\-\-fake\-super\fP) unless you repeat the option (e.g. \-XX). This 1568 1234 \(dq\© all xattrs\(dq\& mode cannot be used with \fB\-\-fake\-super\fP. 1569 1235 .IP … … diff -up a/rsync.1 b/rsync.1 1592 1258 +This option causes rsync to disable system\-immutable 1593 1259 +flags on files and directories that are being updated or deleted on the 1594 1260 +receiving side. It does not try to affect user flags. This option overrides 1595 +\fB\-\-force\-change\fP and \fB\-\-force\- schange\fP.1261 +\fB\-\-force\-change\fP and \fB\-\-force\-uchange\fP. 1596 1262 +.IP 1597 1263 .IP "\fB\-\-chmod\fP" 1598 1264 This option tells rsync to apply one or more 1599 1265 comma\-separated \(dq\&chmod\(dq\& modes to the permission of the files in the 1600 @@ -1 472,13 +1504,14 @@ See \fB\-\-delete\fP (which is implied)1266 @@ -1633,13 +1665,14 @@ display as a \(dq\&*missing\(dq\& entry 1601 1267 Tells \fB\-\-delete\fP to go ahead and delete files 1602 1268 even when there are I/O errors. 1603 1269 .IP … … diff -up a/rsync.1 b/rsync.1 1615 1281 \fB\-\-recursive\fP option was also enabled. 1616 1282 .IP 1617 1283 .IP "\fB\-\-max\-delete=NUM\fP" 1618 @@ -2 034,7 +2067,7 @@ with older versions of rsync, but that a1284 @@ -2357,7 +2390,7 @@ with older versions of rsync, but that a 1619 1285 verbose messages). 1620 1286 .IP 1621 1287 The \(dq\&%i\(dq\& escape has a cryptic output that is 11 letters long. The general … … diff -up a/rsync.1 b/rsync.1 1624 1290 type of update being done, \fBX\fP is replaced by the file\-type, and the 1625 1291 other letters represent attributes that may be output if they are being 1626 1292 modified. 1627 @@ -2 104,7 +2137,7 @@ sender\(cq\&s value (requires \fB\-\-own1293 @@ -2427,7 +2460,7 @@ sender\(cq\&s value (requires \fB\-\-own 1628 1294 A \fBg\fP means the group is different and is being updated to the 1629 1295 sender\(cq\&s value (requires \fB\-\-group\fP and the authority to set the group). 1630 1296 .IP o -
rsync/files/patch-hfs-compression-options.diff
diff --git a/rsync/files/patch-hfs-compression-options.diff b/rsync/files/patch-hfs-compression-options.diff index 55198b4..89b535d 100644
a b 1 This patch adds support for HFS+ compression status to be2 shown during options display.3 4 To use this patch, run these commands for a successful build:5 6 patch -p1 <patches/fileflags.diff7 patch -p1 <patches/crtimes.diff8 patch -p1 <patches/hfs-compression.diff9 patch -p1 <patches/hfs-compression-options.diff10 ./prepare-source11 ./configure12 make13 14 TODO:15 - Should rsync try to treat the compressed data as file data and use the16 rsync algorithm on the data transfer?17 18 1 diff --git a/options.c b/options.c 19 2 --- a/options.c 20 3 +++ b/options.c 21 @@ - 228,6 +228,7 @@4 @@ -579,6 +579,7 @@ 22 5 char const *iconv = "no "; 23 6 char const *ipv6 = "no "; 24 7 char const *fileflags = "no "; … … diff --git a/options.c b/options.c 26 9 STRUCT_STAT *dumstat; 27 10 28 11 #if SUBPROTOCOL_VERSION != 0 29 @@ - 264,6 +265,9 @@12 @@ -618,6 +619,9 @@ 30 13 #ifdef SUPPORT_FILEFLAGS 31 14 fileflags = ""; 32 15 #endif … … diff --git a/options.c b/options.c 36 19 37 20 rprintf(f, "%s version %s protocol version %d%s\n", 38 21 RSYNC_NAME, RSYNC_VERSION, PROTOCOL_VERSION, subprotocol); 39 @@ - 277,8 +281,10 @@22 @@ -631,8 +635,10 @@ 40 23 (int)(sizeof (int64) * 8)); 41 24 rprintf(f, " %ssocketpairs, %shardlinks, %ssymlinks, %sIPv6, batchfiles, %sinplace,\n", 42 25 got_socketpair, hardlinks, links, ipv6, have_inplace); 43 - rprintf(f, " %sappend, %sACLs, %sxattrs, %siconv, %ssymtimes, %s file-flags\n",44 + rprintf(f, " %sappend, %sACLs, %sxattrs, %siconv, %ssymtimes, %s file-flags,\n",45 have_inplace, acls, xattrs, iconv, symtimes, fileflags);46 + rprintf(f, " %sHFS-compression\n",47 + hfscomp);26 - rprintf(f, " %sappend, %sACLs, %sxattrs, %siconv, %ssymtimes, %sprealloc, %sfile-flags\n", 27 + rprintf(f, " %sappend, %sACLs, %sxattrs, %siconv, %ssymtimes, %sprealloc, %sfile-flags,\n", 28 have_inplace, acls, xattrs, iconv, symtimes, prealloc, fileflags); 29 + rprintf(f, " %sHFS-compression\n", 30 + hfscomp); 48 31 49 32 #ifdef MAINTAINER_MODE 50 33 rprintf(f, "Panic Action: \"%s\"\n", get_panic_action()); -
rsync/files/patch-hfs-compression.diff
diff --git a/rsync/files/patch-hfs-compression.diff b/rsync/files/patch-hfs-compression.diff index 1275a92..77a04ea 100644
a b TODO: 18 18 - Should rsync try to treat the compressed data as file data and use the 19 19 rsync algorithm on the data transfer? 20 20 21 based-on: patch/ b3.0.x/crtimes21 based-on: patch/master/crtimes 22 22 diff --git a/flist.c b/flist.c 23 23 --- a/flist.c 24 24 +++ b/flist.c 25 @@ -1496,6 +1496,7 @@ static struct file_struct *send_file_name(int f, struct file_list *flist, 26 #ifdef SUPPORT_FILEFLAGS 27 sx.st.st_flags = preserve_fileflags ? F_FFLAGS(file) : 0; 28 #endif 25 @@ -1583,6 +1583,9 @@ static struct file_struct *send_file_name(int f, struct file_list *flist, 26 #ifdef SUPPORT_XATTRS 27 if (preserve_xattrs) { 28 sx.st.st_mode = file->mode; 29 + if (preserve_fileflags) 30 + sx.st.st_flags = F_FFLAGS(file); 29 31 + sx.st.st_mtime = file->modtime; /* get_xattr needs mtime for decmpfs xattrs */ 30 sx.xattr = NULL;31 32 if (get_xattr(fname, &sx) < 0) { 32 33 io_error |= IOERR_GENERAL; 34 return NULL; 33 35 diff --git a/generator.c b/generator.c 34 36 --- a/generator.c 35 37 +++ b/generator.c 36 @@ -3 9,6 +39,7 @@ extern int keep_dirlinks;37 extern int force_change;38 @@ -37,6 +37,7 @@ extern int implied_dirs; 39 extern int keep_dirlinks; 38 40 extern int preserve_acls; 39 41 extern int preserve_xattrs; 40 42 +extern int preserve_hfs_compression; 41 43 extern int preserve_links; 42 44 extern int preserve_devices; 43 45 extern int preserve_specials; 44 @@ -1 888,6 +1889,14 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,46 @@ -1762,6 +1763,14 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx, 45 47 fname, fnamecmpbuf); 46 48 } 47 49 sx.st.st_size = F_LENGTH(fuzzy_file); … … diff --git a/generator.c b/generator.c 55 57 +#endif 56 58 statret = 0; 57 59 fnamecmp = fnamecmpbuf; 58 fnamecmp_type = FNAMECMP_FUZZY;59 @@ - 2072,6 +2081,18 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,60 } 61 @@ -1929,6 +1938,18 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx, 60 62 if (read_batch) 61 63 goto cleanup; 62 64 … … diff --git a/generator.c b/generator.c 78 80 diff --git a/lib/sysxattrs.c b/lib/sysxattrs.c 79 81 --- a/lib/sysxattrs.c 80 82 +++ b/lib/sysxattrs.c 81 @@ -22, 6+22,17 @@83 @@ -22,10 +22,17 @@ 82 84 #include "rsync.h" 83 85 #include "sysxattrs.h" 84 86 85 87 +extern int preserve_hfs_compression; 86 88 + 87 +#ifdef HAVE_OSX_XATTRS 89 #ifdef SUPPORT_XATTRS 90 91 #ifdef HAVE_OSX_XATTRS 88 92 +#ifndef XATTR_SHOWCOMPRESSION 89 93 +#define XATTR_SHOWCOMPRESSION 0x0020 90 94 +#endif 91 +#define GETXATTR_FETCH_LIMIT (64*1024*1024)95 #define GETXATTR_FETCH_LIMIT (64*1024*1024) 92 96 + 93 97 +int xattr_options = XATTR_NOFOLLOW; 94 +#endif 95 + 96 #ifdef SUPPORT_XATTRS 98 #endif 97 99 98 100 #if defined HAVE_LINUX_XATTRS 99 @@ -5 5,7 +66,27@@ ssize_t sys_llistxattr(const char *path, char *list, size_t size)101 @@ -59,7 +66,12 @@ ssize_t sys_llistxattr(const char *path, char *list, size_t size) 100 102 101 103 ssize_t sys_lgetxattr(const char *path, const char *name, void *value, size_t size) 102 104 { 103 - returngetxattr(path, name, value, size, 0, XATTR_NOFOLLOW);105 - ssize_t len = getxattr(path, name, value, size, 0, XATTR_NOFOLLOW); 104 106 + ssize_t len; 105 107 + 106 108 + if (preserve_hfs_compression) 107 109 + xattr_options |= XATTR_SHOWCOMPRESSION; 108 110 + 109 111 + len = getxattr(path, name, value, size, 0, xattr_options); 110 +111 + /* If we're retrieving data, handle resource forks > 64MB specially */112 + if (value != NULL && strcmp(name, XATTR_RESOURCEFORK_NAME) == 0 && len == GETXATTR_FETCH_LIMIT) {113 + /* getxattr will only return 64MB of data at a time, need to call again with a new offset */114 + u_int32_t offset = GETXATTR_FETCH_LIMIT;115 + ssize_t data_retrieved = len;116 + while (data_retrieved < (ssize_t)size) {117 + len = getxattr(path, name, value + offset, size - data_retrieved, offset, xattr_options);118 + data_retrieved += len;119 + offset += (u_int32_t)len;120 + }121 + len = data_retrieved;122 + }123 +124 + return len;125 }126 112 127 ssize_t sys_fgetxattr(int filedes, const char *name, void *value, size_t size) 128 @@ -70,12 +101,16 @@ int sys_lsetxattr(const char *path, const char *name, const void *value, size_t 113 /* If we're retrieving data, handle resource forks > 64MB specially */ 114 if (value != NULL && len == GETXATTR_FETCH_LIMIT && (size_t)len < size) { 115 @@ -67,7 +79,7 @@ ssize_t sys_lgetxattr(const char *path, const char *name, void *value, size_t si 116 u_int32_t offset = len; 117 size_t data_retrieved = len; 118 while (data_retrieved < size) { 119 - len = getxattr(path, name, value + offset, size - data_retrieved, offset, XATTR_NOFOLLOW); 120 + len = getxattr(path, name, value + offset, size - data_retrieved, offset, xattr_options); 121 if (len <= 0) 122 break; 123 data_retrieved += len; 124 @@ -91,12 +103,16 @@ int sys_lsetxattr(const char *path, const char *name, const void *value, size_t 129 125 130 126 int sys_lremovexattr(const char *path, const char *name) 131 127 { … … diff --git a/main.c b/main.c 156 152 +#include <sys/mount.h> /* For statfs() */ 157 153 +#endif 158 154 159 extern int verbose;160 155 extern int dry_run; 161 @@ -50,7 +54,9 @@ extern int copy_dirlinks; 156 extern int list_only; 157 @@ -53,6 +57,7 @@ extern int copy_dirlinks; 162 158 extern int copy_unsafe_links; 163 159 extern int keep_dirlinks; 164 160 extern int preserve_hard_links; 165 161 +extern int preserve_hfs_compression; 166 162 extern int protocol_version; 167 +extern int force_change;163 extern int force_change; 168 164 extern int file_total; 169 extern int recurse; 170 extern int xfer_dirs; 171 @@ -490,6 +496,43 @@ static pid_t do_cmd(char *cmd, char *machine, char *user, char **remote_argv, in 165 @@ -107,6 +112,7 @@ int daemon_over_rsh = 0; 166 mode_t orig_umask = 0; 167 int batch_gen_fd = -1; 168 int sender_keeps_checksum = 0; 169 +int fs_supports_hfs_compression = 0; 170 171 /* There's probably never more than at most 2 outstanding child processes, 172 * but set it higher, just in case. */ 173 @@ -559,6 +565,43 @@ static pid_t do_cmd(char *cmd, char *machine, char *user, char **remote_argv, in 172 174 return 0; /* not reached */ 173 175 } 174 176 … … diff --git a/main.c b/main.c 212 214 /* The receiving side operates in one of two modes: 213 215 * 214 216 * 1. it receives any number of files into a destination directory, 215 @@ - 548,6 +591,9 @@ static char *get_local_name(struct file_list *flist, char *dest_path)217 @@ -617,6 +660,9 @@ static char *get_local_name(struct file_list *flist, char *dest_path) 216 218 exit_cleanup(RERR_FILESELECT); 217 219 } 218 220 filesystem_dev = st.st_dev; /* ensures --force works right w/-x */ … … diff --git a/main.c b/main.c 222 224 return NULL; 223 225 } 224 226 if (file_total > 1) { 225 @@ -6 08,7 +654,9 @@ static char *get_local_name(struct file_list *flist, char *dest_path)227 @@ -677,7 +723,9 @@ static char *get_local_name(struct file_list *flist, char *dest_path) 226 228 full_fname(dest_path)); 227 229 exit_cleanup(RERR_FILESELECT); 228 230 } … … diff --git a/main.c b/main.c 233 235 return NULL; 234 236 } 235 237 236 @@ -6 28,6 +676,9 @@ static char *get_local_name(struct file_list *flist, char *dest_path)238 @@ -697,6 +745,9 @@ static char *get_local_name(struct file_list *flist, char *dest_path) 237 239 full_fname(dest_path)); 238 240 exit_cleanup(RERR_FILESELECT); 239 241 } … … diff --git a/main.c b/main.c 243 245 *cp = '/'; 244 246 245 247 return cp + 1; 246 @@ -981,7 +1032,6 @@ int child_main(int argc, char *argv[])247 return 0;248 }249 250 -251 void start_server(int f_in, int f_out, int argc, char *argv[])252 {253 set_nonblocking(f_in);254 248 diff --git a/options.c b/options.c 255 249 --- a/options.c 256 250 +++ b/options.c 257 @@ -5 2,6 +52,7 @@ int preserve_links = 0;251 @@ -54,6 +54,7 @@ int preserve_links = 0; 258 252 int preserve_hard_links = 0; 259 253 int preserve_acls = 0; 260 254 int preserve_xattrs = 0; … … diff --git a/options.c b/options.c 262 256 int preserve_perms = 0; 263 257 int preserve_fileflags = 0; 264 258 int preserve_executability = 0; 265 @@ - 355,6 +356,10 @@ void usage(enum logcode F)259 @@ -713,6 +714,10 @@ void usage(enum logcode F) 266 260 #ifdef SUPPORT_XATTRS 267 261 rprintf(F," -X, --xattrs preserve extended attributes\n"); 268 262 #endif … … diff --git a/options.c b/options.c 273 267 rprintf(F," -o, --owner preserve owner (super-user only)\n"); 274 268 rprintf(F," -g, --group preserve group\n"); 275 269 rprintf(F," --devices preserve device files (super-user only)\n"); 276 @@ - 588,6 +593,12 @@ static struct poptOption long_options[] = {270 @@ -974,6 +979,12 @@ static struct poptOption long_options[] = { 277 271 {"force-uchange", 0, POPT_ARG_VAL, &force_change, USR_IMMUTABLE, 0, 0 }, 278 272 {"force-schange", 0, POPT_ARG_VAL, &force_change, SYS_IMMUTABLE, 0, 0 }, 279 273 #endif … … diff --git a/options.c b/options.c 286 280 {"ignore-errors", 0, POPT_ARG_VAL, &ignore_errors, 1, 0, 0 }, 287 281 {"no-ignore-errors", 0, POPT_ARG_VAL, &ignore_errors, 0, 0, 0 }, 288 282 {"max-delete", 0, POPT_ARG_INT, &max_delete, 0, 0, 0 }, 289 @@ -1 362,6 +1373,15 @@ int parse_arguments(int *argc_p, const char ***argv_p)283 @@ -1974,6 +1985,15 @@ int parse_arguments(int *argc_p, const char ***argv_p) 290 284 } 291 285 #endif 292 286 … … diff --git a/options.c b/options.c 299 293 + } 300 294 +#endif 301 295 + 302 if ( write_batch && read_batch) {296 if (block_size > MAX_BLOCK_SIZE) { 303 297 snprintf(err_buf, sizeof err_buf, 304 "--write-batch and --read-batch can not be used together\n");305 @@ - 1915,6 +1935,11 @@ void server_options(char **args, int *argc_p)298 "--block-size=%lu is too large (max: %u)\n", block_size, MAX_BLOCK_SIZE); 299 @@ -2573,6 +2593,11 @@ void server_options(char **args, int *argc_p) 306 300 if (preserve_fileflags) 307 301 args[ac++] = "--fileflags"; 308 302 … … diff --git a/options.c b/options.c 317 311 diff --git a/rsync.c b/rsync.c 318 312 --- a/rsync.c 319 313 +++ b/rsync.c 320 @@ - 498,8 +498,14 @@ int set_file_attrs(const char *fname, struct file_struct *file, stat_x *sxp,314 @@ -573,8 +573,14 @@ int set_file_attrs(const char *fname, struct file_struct *file, stat_x *sxp, 321 315 #ifdef SUPPORT_XATTRS 322 316 if (am_root < 0) 323 317 set_stat_xattr(fname, file, new_mode); … … diff --git a/rsync.c b/rsync.c 333 327 #endif 334 328 335 329 if (!preserve_times 336 @@ -5 10,6 +516,9 @@ int set_file_attrs(const char *fname, struct file_struct *file, stat_x *sxp,330 @@ -585,6 +591,9 @@ int set_file_attrs(const char *fname, struct file_struct *file, stat_x *sxp, 337 331 if (sxp->st.st_ino == 2 && S_ISDIR(sxp->st.st_mode)) 338 332 flags |= ATTRS_SKIP_CRTIME; 339 333 if (!(flags & ATTRS_SKIP_MTIME) … … diff --git a/rsync.c b/rsync.c 341 335 + && !(sxp->st.st_flags & UF_COMPRESSED) /* setting this alters mtime, so defer to after set_fileflags */ 342 336 +#endif 343 337 && cmp_time(sxp->st.st_mtime, file->modtime) != 0) { 344 int ret = set_modtime(fname, file->modtime, sxp->st.st_mode, ST_FLAGS(sxp->st));338 int ret = set_modtime(fname, file->modtime, F_MOD_NSEC(file), sxp->st.st_mode, ST_FLAGS(sxp->st)); 345 339 if (ret < 0) { 346 @@ -6 20,6 +629,16 @@ int set_file_attrs(const char *fname, struct file_struct *file, stat_x *sxp,340 @@ -643,6 +652,16 @@ int set_file_attrs(const char *fname, struct file_struct *file, stat_x *sxp, 347 341 && !set_fileflags(fname, fileflags)) 348 342 goto cleanup; 349 343 updated = 1; 350 344 +#ifdef SUPPORT_HFS_COMPRESSION 351 + int ret = set_modtime(fname, file->modtime, new_mode, fileflags);345 + int ret = set_modtime(fname, file->modtime, F_MOD_NSEC(file), new_mode, fileflags); 352 346 + if (ret < 0) { 353 347 + rsyserr(FERROR_XFER, errno, "failed to set times on %s", 354 348 + full_fname(fname)); … … diff --git a/rsync.c b/rsync.c 363 357 diff --git a/rsync.h b/rsync.h 364 358 --- a/rsync.h 365 359 +++ b/rsync.h 366 @@ -5 09,6 +509,17 @@ typedef unsigned int size_t;360 @@ -549,6 +549,17 @@ typedef unsigned int size_t; 367 361 #define ST_FLAGS(st) NO_FFLAGS 368 362 #endif 369 363 … … diff --git a/rsync.h b/rsync.h 384 378 diff --git a/rsync.yo b/rsync.yo 385 379 --- a/rsync.yo 386 380 +++ b/rsync.yo 387 @@ -36 0,6 +360,8 @@ to the detailed description below for a complete description. verb(381 @@ -367,6 +367,8 @@ to the detailed description below for a complete description. verb( 388 382 --chmod=CHMOD affect file and/or directory permissions 389 383 -A, --acls preserve ACLs (implies -p) 390 384 -X, --xattrs preserve extended attributes … … diff --git a/rsync.yo b/rsync.yo 393 387 -o, --owner preserve owner (super-user only) 394 388 -g, --group preserve group 395 389 --devices preserve device files (super-user only) 396 @@ -1 038,6 +1040,42 @@ flags on files and directories that are being updated or deleted on the390 @@ -1135,6 +1137,42 @@ flags on files and directories that are being updated or deleted on the 397 391 receiving side. It does not try to affect user flags. This option overrides 398 bf(--force-change) and bf(--force- schange).392 bf(--force-change) and bf(--force-uchange). 399 393 400 394 +dit(bf(--hfs-compression)) This option causes rsync to preserve HFS+ 401 395 +compression if the destination filesystem supports it. If the destination … … diff --git a/rsync.yo b/rsync.yo 439 433 diff --git a/t_stub.c b/t_stub.c 440 434 --- a/t_stub.c 441 435 +++ b/t_stub.c 442 @@ - 29,6 +29,7 @@ int module_dirlen= 0;443 int force_change= 0;436 @@ -32,6 +32,7 @@ int force_change = 0; 437 int preserve_acls = 0; 444 438 int preserve_times = 0; 445 439 int preserve_xattrs = 0; 446 440 +int preserve_hfs_compression = 0; 447 mode_t orig_umask = 002;448 441 char *partial_dir; 449 442 char *module_dir; 443 filter_rule_list daemon_filter_list; 450 444 diff --git a/xattrs.c b/xattrs.c 451 445 --- a/xattrs.c 452 446 +++ b/xattrs.c 453 @@ -3 2,6 +32,7 @@ extern int am_generator;447 @@ -33,6 +33,7 @@ extern int am_generator; 454 448 extern int read_only; 455 449 extern int list_only; 456 450 extern int preserve_xattrs; … … diff --git a/xattrs.c b/xattrs.c 458 452 extern int preserve_links; 459 453 extern int preserve_devices; 460 454 extern int preserve_specials; 461 @@ -4 0,6 +41,10 @@ extern int checksum_seed;455 @@ -41,6 +42,10 @@ extern int checksum_seed; 462 456 #define RSYNC_XAL_INITIAL 5 463 457 #define RSYNC_XAL_LIST_INITIAL 100 464 458 … … diff --git a/xattrs.c b/xattrs.c 469 463 #define MAX_FULL_DATUM 32 470 464 471 465 #define HAS_PREFIX(str, prfx) (*(str) == *(prfx) \ 472 @@ -7 2,6 +77,17 @@ extern int checksum_seed;466 @@ -73,6 +78,17 @@ extern int checksum_seed; 473 467 #define XDEF_ACL_SUFFIX "dacl" 474 468 #define XDEF_ACL_ATTR RSYNC_PREFIX "%" XDEF_ACL_SUFFIX 475 469 … … diff --git a/xattrs.c b/xattrs.c 487 481 typedef struct { 488 482 char *datum, *name; 489 483 size_t datum_len, name_len; 490 @@ -16 6,8 +182,7 @@ static ssize_t get_xattr_names(const char *fname)484 @@ -167,8 +183,7 @@ static ssize_t get_xattr_names(const char *fname) 491 485 /* On entry, the *len_ptr parameter contains the size of the extra space we 492 486 * should allocate when we create a buffer for the data. On exit, it contains 493 487 * the length of the datum. */ … … diff --git a/xattrs.c b/xattrs.c 497 491 { 498 492 size_t datum_len = sys_lgetxattr(fname, name, NULL, 0); 499 493 size_t extra_len = *len_ptr; 500 @@ -17 6,7 +191,7 @@ static char *get_xattr_data(const char *fname, const char *name, size_t *len_ptr494 @@ -177,7 +192,7 @@ static char *get_xattr_data(const char *fname, const char *name, size_t *len_ptr 501 495 *len_ptr = datum_len; 502 496 503 497 if (datum_len == (size_t)-1) { … … diff --git a/xattrs.c b/xattrs.c 506 500 return NULL; 507 501 rsyserr(FERROR_XFER, errno, 508 502 "get_xattr_data: lgetxattr(\"%s\",\"%s\",0) failed", 509 @@ -18 4,6 +199,15 @@ static char *get_xattr_data(const char *fname, const char *name, size_t *len_ptr503 @@ -185,6 +200,15 @@ static char *get_xattr_data(const char *fname, const char *name, size_t *len_ptr 510 504 return NULL; 511 505 } 512 506 … … diff --git a/xattrs.c b/xattrs.c 522 516 if (!datum_len && !extra_len) 523 517 extra_len = 1; /* request non-zero amount of memory */ 524 518 if (datum_len + extra_len < datum_len) 525 @@ -21 2,7 +236,29 @@ static char *get_xattr_data(const char *fname, const char *name, size_t *len_ptr519 @@ -213,7 +237,29 @@ static char *get_xattr_data(const char *fname, const char *name, size_t *len_ptr 526 520 return ptr; 527 521 } 528 522 … … diff --git a/xattrs.c b/xattrs.c 553 547 { 554 548 ssize_t list_len, name_len; 555 549 size_t datum_len, name_offset; 556 @@ -22 1,7 +267,8 @@ static int rsync_xal_get(const char *fname, item_list *xalp)557 int user_only = am_sender ? 0 : am_root <= 0;550 @@ -222,7 +268,8 @@ static int rsync_xal_get(const char *fname, item_list *xalp) 551 int user_only = am_sender ? 0 : !am_root; 558 552 #endif 559 553 rsync_xa *rxa; 560 554 - int count; … … diff --git a/xattrs.c b/xattrs.c 563 557 564 558 /* This puts the name list into the "namebuf" buffer. */ 565 559 if ((list_len = get_xattr_names(fname)) < 0) 566 @@ -25 1,20 +298,22 @@ static int rsync_xal_get(const char *fname, item_list *xalp)560 @@ -252,20 +299,22 @@ static int rsync_xal_get(const char *fname, item_list *xalp) 567 561 } 568 562 569 563 datum_len = name_len; /* Pass extra size to get_xattr_data() */ … … diff --git a/xattrs.c b/xattrs.c 592 586 } else 593 587 name_offset = datum_len; 594 588 595 @@ -3 09,7 +358,7 @@ int get_xattr(const char *fname, stat_x *sxp)596 return 0;597 }589 @@ -311,7 +360,7 @@ int get_xattr(const char *fname, stat_x *sxp) 590 } else if (IS_MISSING_FILE(sxp->st)) 591 return 0; 598 592 599 593 - if (rsync_xal_get(fname, sxp->xattr) < 0) { 600 594 + if (rsync_xal_get(fname, sxp) < 0) { 601 595 free_xattr(sxp); 602 596 return -1; 603 597 } 604 @@ -34 4,6 +393,8 @@ int copy_xattrs(const char *source, const char *dest)598 @@ -346,6 +395,8 @@ int copy_xattrs(const char *source, const char *dest) 605 599 datum_len = 0; 606 600 if (!(ptr = get_xattr_data(source, name, &datum_len, 0))) 607 601 return -1; … … diff --git a/xattrs.c b/xattrs.c 610 604 if (sys_lsetxattr(dest, name, ptr, datum_len) < 0) { 611 605 int save_errno = errno ? errno : EINVAL; 612 606 rsyserr(FERROR_XFER, errno, 613 @@ -36 0,6 +411,10 @@ int copy_xattrs(const char *source, const char *dest)607 @@ -362,6 +413,10 @@ int copy_xattrs(const char *source, const char *dest) 614 608 615 609 static int find_matching_xattr(item_list *xalp) 616 610 { … … diff --git a/xattrs.c b/xattrs.c 621 615 size_t i, j; 622 616 item_list *lst = rsync_xal_l.items; 623 617 624 @@ -39 3,6 +448,7 @@ static int find_matching_xattr(item_list *xalp)618 @@ -395,6 +450,7 @@ static int find_matching_xattr(item_list *xalp) 625 619 } 626 620 627 621 return -1; … … diff --git a/xattrs.c b/xattrs.c 629 623 } 630 624 631 625 /* Store *xalp on the end of rsync_xal_l */ 632 @@ -57 2,11 +628,13 @@ void send_xattr_request(const char *fname, struct file_struct *file, int f_out)626 @@ -574,11 +630,13 @@ void send_xattr_request(const char *fname, struct file_struct *file, int f_out) 633 627 634 628 /* Re-read the long datum. */ 635 629 if (!(ptr = get_xattr_data(fname, rxa->name, &len, 0))) { … … diff --git a/xattrs.c b/xattrs.c 642 636 643 637 + assert(ptr != UNREAD_DATA); 644 638 write_varint(f_out, len); /* length might have changed! */ 645 write_b uf(f_out, ptr, len);639 write_bigbuf(f_out, ptr, len); 646 640 free(ptr); 647 @@ -79 2,7 +850,7 @@ static int rsync_xal_set(const char *fname, item_list *xalp,641 @@ -795,7 +853,7 @@ static int rsync_xal_set(const char *fname, item_list *xalp, 648 642 int user_only = am_root <= 0; 649 643 #endif 650 644 size_t name_len; … … diff --git a/xattrs.c b/xattrs.c 653 647 654 648 /* This puts the current name list into the "namebuf" buffer. */ 655 649 if ((list_len = get_xattr_names(fname)) < 0) 656 @@ -80 4,7 +862,10 @@ static int rsync_xal_set(const char *fname, item_list *xalp,650 @@ -807,7 +865,10 @@ static int rsync_xal_set(const char *fname, item_list *xalp, 657 651 if (XATTR_ABBREV(rxas[i])) { 658 652 /* See if the fnamecmp version is identical. */ 659 653 len = name_len = rxas[i].name_len; … … diff --git a/xattrs.c b/xattrs.c 665 659 still_abbrev: 666 660 if (am_generator) 667 661 continue; 668 @@ -81 3,14 +874,14 @@ static int rsync_xal_set(const char *fname, item_list *xalp,662 @@ -816,14 +877,14 @@ static int rsync_xal_set(const char *fname, item_list *xalp, 669 663 ret = -1; 670 664 continue; 671 665 } … … diff --git a/xattrs.c b/xattrs.c 683 677 if (memcmp(sum, rxas[i].datum + 1, MAX_DIGEST_LEN) != 0) { 684 678 free(ptr); 685 679 goto still_abbrev; 686 @@ -8 89,6 +950,10 @@ static int rsync_xal_set(const char *fname, item_list *xalp,680 @@ -892,6 +953,10 @@ static int rsync_xal_set(const char *fname, item_list *xalp, 687 681 } 688 682 } 689 683 … … diff --git a/xattrs.c b/xattrs.c 694 688 return ret; 695 689 } 696 690 697 @@ -93 5,7 +1000,7 @@ char *get_xattr_acl(const char *fname, int is_access_acl, size_t *len_p)691 @@ -938,7 +1003,7 @@ char *get_xattr_acl(const char *fname, int is_access_acl, size_t *len_p) 698 692 { 699 693 const char *name = is_access_acl ? XACC_ACL_ATTR : XDEF_ACL_ATTR; 700 694 *len_p = 0; /* no extra data alloc needed from get_xattr_data() */ … … diff --git a/xattrs.c b/xattrs.c 703 697 } 704 698 705 699 int set_xattr_acl(const char *fname, int is_access_acl, const char *buf, size_t buf_len) 706 @@ -10 78,11 +1143,33 @@ int set_stat_xattr(const char *fname, struct file_struct *file, mode_t new_mode)700 @@ -1081,11 +1146,33 @@ int set_stat_xattr(const char *fname, struct file_struct *file, mode_t new_mode) 707 701 return 0; 708 702 } 709 703 … … diff --git a/xattrs.c b/xattrs.c 737 731 return ret; 738 732 } 739 733 740 @@ -109 1,6 +1178,9 @@ int x_lstat(const char *fname, STRUCT_STAT *fst, STRUCT_STAT *xst)734 @@ -1094,6 +1181,9 @@ int x_lstat(const char *fname, STRUCT_STAT *fst, STRUCT_STAT *xst) 741 735 int ret = do_lstat(fname, fst); 742 736 if ((ret < 0 || get_stat_xattr(fname, -1, fst, xst) < 0) && xst) 743 737 xst->st_mode = 0; … … diff --git a/xattrs.c b/xattrs.c 747 741 return ret; 748 742 } 749 743 750 @@ -1 099,6 +1189,9 @@ int x_fstat(int fd, STRUCT_STAT *fst, STRUCT_STAT *xst)744 @@ -1102,6 +1192,9 @@ int x_fstat(int fd, STRUCT_STAT *fst, STRUCT_STAT *xst) 751 745 int ret = do_fstat(fd, fst); 752 746 if ((ret < 0 || get_stat_xattr(NULL, fd, fst, xst) < 0) && xst) 753 747 xst->st_mode = 0; … … diff --git a/xattrs.c b/xattrs.c 757 751 return ret; 758 752 } 759 753 760 diff - up a/rsync.1 b/rsync.1754 diff -Nurp a/rsync.1 b/rsync.1 761 755 --- a/rsync.1 762 756 +++ b/rsync.1 763 @@ -4 36,6 +436,8 @@ to the detailed description below for a757 @@ -443,6 +443,8 @@ to the detailed description below for a 764 758 \-\-chmod=CHMOD affect file and/or directory permissions 765 759 \-A, \-\-acls preserve ACLs (implies \-p) 766 760 \-X, \-\-xattrs preserve extended attributes … … diff -up a/rsync.1 b/rsync.1 769 763 \-o, \-\-owner preserve owner (super\-user only) 770 764 \-g, \-\-group preserve group 771 765 \-\-devices preserve device files (super\-user only) 772 @@ -1 195,6 +1197,44 @@ flags on files and directories that are766 @@ -1300,6 +1302,44 @@ flags on files and directories that are 773 767 receiving side. It does not try to affect user flags. This option overrides 774 \fB\-\-force\-change\fP and \fB\-\-force\- schange\fP.768 \fB\-\-force\-change\fP and \fB\-\-force\-uchange\fP. 775 769 .IP 776 770 +.IP "\fB\-\-hfs\-compression\fP" 777 771 +This option causes rsync to preserve HFS+