Fixed a failing hunk.
[rsync/rsync-patches.git] / flags.diff
CommitLineData
31611b92 1This patch provides --flags, which preserves the st_flags field.
9f62ddf8 2Modified from a patch that was written by Rolf Grossmann.
31611b92 3
03019e41 4To use this patch, run these commands for a successful build:
9f62ddf8 5
03019e41 6 patch -p1 <patches/flags.diff
9f62ddf8
WD
7 ./prepare-source
8 ./configure
9 make
31611b92 10
5bafda30
WD
11TODO: fix --delete-delay to work with --flags option.
12
fdf967c7
WD
13--- old/compat.c
14+++ new/compat.c
9c25eef5 15@@ -45,6 +45,7 @@ extern int prune_empty_dirs;
898a2112
WD
16 extern int protocol_version;
17 extern int preserve_uid;
18 extern int preserve_gid;
19+extern int preserve_fileflags;
20 extern int preserve_acls;
21 extern int preserve_xattrs;
9c25eef5 22 extern int need_messages_from_generator;
99650e0d 23@@ -58,7 +59,7 @@ extern char *dest_option;
898a2112
WD
24 extern struct filter_list_struct filter_list;
25
26 /* These index values are for the file-list's extra-attribute array. */
27-int uid_ndx, gid_ndx, acls_ndx, xattrs_ndx;
28+int uid_ndx, gid_ndx, fileflags_ndx, acls_ndx, xattrs_ndx;
29
30 /* The server makes sure that if either side only supports a pre-release
31 * version of a protocol, that both sides must speak a compatible version
790ba11a 32@@ -105,6 +106,8 @@ void setup_protocol(int f_out,int f_in)
898a2112 33 uid_ndx = ++file_extra_cnt;
fdf967c7 34 if (preserve_gid)
898a2112 35 gid_ndx = ++file_extra_cnt;
fdf967c7 36+ if (preserve_fileflags)
898a2112 37+ fileflags_ndx = ++file_extra_cnt;
ffc18846 38 if (preserve_acls && !am_sender)
898a2112 39 acls_ndx = ++file_extra_cnt;
5795bf59 40 if (preserve_xattrs)
31611b92
WD
41--- old/configure.in
42+++ new/configure.in
82c2230a 43@@ -560,7 +560,7 @@ AC_CHECK_FUNCS(waitpid wait4 getcwd strd
31611b92
WD
44 memmove lchown vsnprintf snprintf vasprintf asprintf setsid glob strpbrk \
45 strlcat strlcpy strtol mallinfo getgroups setgroups geteuid getegid \
46 setlocale setmode open64 lseek64 mkstemp64 mtrace va_copy __va_copy \
80c89075
WD
47- strerror putenv iconv_open locale_charset nl_langinfo getxattr \
48+ chflags strerror putenv iconv_open locale_charset nl_langinfo getxattr \
49 extattr_get_link sigaction sigprocmask)
31611b92
WD
50
51 AC_CHECK_FUNCS(getpgrp tcgetpgrp)
52--- old/flist.c
53+++ new/flist.c
790ba11a
WD
54@@ -50,6 +50,7 @@ extern int preserve_links;
55 extern int preserve_hard_links;
56 extern int preserve_devices;
31611b92 57 extern int preserve_specials;
790ba11a 58+extern int fileflags_ndx;
898a2112
WD
59 extern int uid_ndx;
60 extern int gid_ndx;
790ba11a
WD
61 extern int eol_nulls;
62@@ -362,6 +363,9 @@ static void send_file_entry(int f, struc
7e27b6c0 63 {
31611b92
WD
64 static time_t modtime;
65 static mode_t mode;
66+#ifdef SUPPORT_FLAGS
67+ static uint32 fileflags;
68+#endif
69 static int64 dev;
70 static dev_t rdev;
71 static uint32 rdev_major;
790ba11a 72@@ -410,6 +414,12 @@ static void send_file_entry(int f, struc
99650e0d 73 xflags |= XMIT_SAME_MODE;
31611b92
WD
74 else
75 mode = file->mode;
76+#ifdef SUPPORT_FLAGS
7d006b5b 77+ if (F_FFLAGS(file) == fileflags)
99650e0d 78+ xflags |= XMIT_SAME_FLAGS;
31611b92 79+ else
7d006b5b 80+ fileflags = F_FFLAGS(file);
31611b92 81+#endif
99650e0d
WD
82
83 if (protocol_version >= 30 && S_ISDIR(mode) && !(file->flags & FLAG_XFER_DIR))
84 xflags |= XMIT_NON_XFER_DIR;
790ba11a 85@@ -532,6 +542,10 @@ static void send_file_entry(int f, struc
82c2230a 86 }
99650e0d 87 if (!(xflags & XMIT_SAME_MODE))
31611b92
WD
88 write_int(f, to_wire_mode(mode));
89+#ifdef SUPPORT_FLAGS
99650e0d 90+ if (fileflags_ndx && !(xflags & XMIT_SAME_FLAGS))
31611b92
WD
91+ write_int(f, (int)fileflags);
92+#endif
99650e0d 93 if (uid_ndx && !(xflags & XMIT_SAME_UID)) {
caf38d8d
WD
94 if (protocol_version < 30)
95 write_int(f, uid);
790ba11a 96@@ -620,6 +634,9 @@ static struct file_struct *recv_file_ent
31611b92 97 {
82c2230a 98 static int64 modtime;
31611b92
WD
99 static mode_t mode;
100+#ifdef SUPPORT_FLAGS
101+ static uint32 fileflags;
102+#endif
103 static int64 dev;
104 static dev_t rdev;
105 static uint32 rdev_major;
790ba11a 106@@ -755,9 +772,12 @@ static struct file_struct *recv_file_ent
82c2230a 107 }
898a2112 108 if (!(xflags & XMIT_SAME_MODE))
31611b92
WD
109 mode = from_wire_mode(read_int(f));
110-
111 if (chmod_modes && !S_ISLNK(mode))
112 mode = tweak_mode(mode, chmod_modes);
113+#ifdef SUPPORT_FLAGS
898a2112 114+ if (fileflags_ndx && !(xflags & XMIT_SAME_FLAGS))
31611b92
WD
115+ fileflags = (uint32)read_int(f);
116+#endif
117
898a2112 118 if (uid_ndx && !(xflags & XMIT_SAME_UID)) {
caf38d8d 119 if (protocol_version < 30)
790ba11a 120@@ -877,6 +897,10 @@ static struct file_struct *recv_file_ent
1aa236e1
WD
121 OPT_EXTRA(file, 0)->unum = (uint32)(file_length >> 32);
122 }
31611b92
WD
123 file->mode = mode;
124+#ifdef SUPPORT_FLAGS
898a2112 125+ if (fileflags_ndx)
70891d26 126+ F_FFLAGS(file) = fileflags;
31611b92 127+#endif
898a2112 128 if (uid_ndx)
fc068916 129 F_OWNER(file) = uid;
898a2112 130 if (gid_ndx) {
790ba11a 131@@ -1194,6 +1218,10 @@ struct file_struct *make_file(const char
1aa236e1
WD
132 OPT_EXTRA(file, 0)->unum = (uint32)(st.st_size >> 32);
133 }
31611b92
WD
134 file->mode = st.st_mode;
135+#ifdef SUPPORT_FLAGS
898a2112 136+ if (fileflags_ndx)
70891d26 137+ F_FFLAGS(file) = st.st_flags;
31611b92 138+#endif
898a2112 139 if (uid_ndx)
fc068916 140 F_OWNER(file) = st.st_uid;
898a2112 141 if (gid_ndx)
31611b92
WD
142--- old/generator.c
143+++ new/generator.c
9c25eef5 144@@ -115,6 +115,14 @@ static int need_retouch_dir_times;
99650e0d 145 static int need_retouch_dir_perms;
ffc18846 146 static const char *solo_file = NULL;
f90a882e
WD
147
148+#ifdef SUPPORT_FLAGS
7d006b5b
WD
149+#define FF_PTR(p) F_FFLAGS(p)
150+#define FF_STAT(s) s.st_flags
f90a882e 151+#else
7d006b5b
WD
152+#define FF_PTR(p) 0
153+#define FF_STAT(s) 0
f90a882e
WD
154+#endif
155+
d16b5fd6 156 /* For calling delete_item() and delete_dir_contents(). */
87d0091c 157 #define DEL_RECURSE (1<<1) /* recurse */
d16b5fd6 158 #define DEL_DIR_IS_EMPTY (1<<2) /* internal delete_FUNCTIONS use only */
9c25eef5 159@@ -130,7 +138,6 @@ enum delret {
87d0091c
WD
160 /* Forward declaration for delete_item(). */
161 static enum delret delete_dir_contents(char *fname, int flags);
f90a882e 162
87d0091c
WD
163-
164 static int is_backup_file(char *fn)
165 {
166 int k = strlen(fn) - backup_suffix_len;
9c25eef5 167@@ -143,17 +150,20 @@ static int is_backup_file(char *fn)
f813befd 168 * Note that fbuf must point to a MAXPATHLEN buffer if the mode indicates it's
f90a882e
WD
169 * a directory! (The buffer is used for recursion, but returned unchanged.)
170 */
f813befd
WD
171-static enum delret delete_item(char *fbuf, int mode, char *replace, int flags)
172+static enum delret delete_item(char *fbuf, int mode, uint32 fileflags, char *replace, int flags)
f90a882e 173 {
87d0091c
WD
174 enum delret ret;
175 char *what;
176 int ok;
177
178 if (verbose > 2) {
179- rprintf(FINFO, "delete_item(%s) mode=%o flags=%d\n",
f813befd 180- fbuf, mode, flags);
87d0091c 181+ rprintf(FINFO, "delete_item(%s) mode=%o fileflags=%o flags=%d\n",
f813befd 182+ fbuf, mode, fileflags, flags);
87d0091c
WD
183 }
184
31611b92 185+#ifdef SUPPORT_FLAGS
f813befd 186+ make_mutable(fbuf, mode, fileflags);
31611b92 187+#endif
d16b5fd6
WD
188 if (S_ISDIR(mode) && !(flags & DEL_DIR_IS_EMPTY)) {
189 ignore_perishable = 1;
190 /* If DEL_RECURSE is not set, this just reports emptiness. */
9c25eef5 191@@ -265,7 +275,7 @@ static enum delret delete_dir_contents(c
d16b5fd6
WD
192 if (S_ISDIR(fp->mode)
193 && delete_dir_contents(fname, flags | DEL_RECURSE) != DR_SUCCESS)
194 ret = DR_NOT_EMPTY;
195- if (delete_item(fname, fp->mode, NULL, flags) != DR_SUCCESS)
7d006b5b 196+ if (delete_item(fname, fp->mode, FF_PTR(fp), NULL, flags) != DR_SUCCESS)
d16b5fd6 197 ret = DR_NOT_EMPTY;
f90a882e 198 }
d16b5fd6 199
9c25eef5 200@@ -321,8 +331,9 @@ static int remember_delete(struct file_s
ee76479d
WD
201
202 while (1) {
203 len = snprintf(deldelay_buf + deldelay_cnt,
204- deldelay_size - deldelay_cnt,
205- "%x %s%c", (int)file->mode, fname, '\0');
206+ deldelay_size - deldelay_cnt, "%x %x %s%c",
7d006b5b 207+ (int)file->mode, (int)FF_PTR(file),
ee76479d
WD
208+ fname, '\0');
209 if ((deldelay_cnt += len) <= deldelay_size)
210 break;
211 if (deldelay_fd < 0 && !start_delete_delay_temp())
9c25eef5 212@@ -335,7 +346,7 @@ static int remember_delete(struct file_s
ee76479d
WD
213 return 1;
214 }
215
216-static int read_delay_line(char *buf)
217+static int read_delay_line(char *buf, int *fileflags_p)
218 {
219 static int read_pos = 0;
220 int j, len, mode;
9c25eef5 221@@ -377,7 +388,7 @@ static int read_delay_line(char *buf)
ee76479d
WD
222
223 bp = deldelay_buf + read_pos;
224
225- if (sscanf(bp, "%x ", &mode) != 1) {
226+ if (sscanf(bp, "%x %x ", &mode, fileflags_p) != 2) {
227 invalid_data:
228 rprintf(FERROR, "ERROR: invalid data in delete-delay file.\n");
229 return -1;
9c25eef5 230@@ -400,15 +411,15 @@ static int read_delay_line(char *buf)
ee76479d
WD
231
232 static void do_delayed_deletions(char *delbuf)
233 {
234- int mode;
235+ int mode, fileflags;
236
237 if (deldelay_fd >= 0) {
238 if (deldelay_cnt && !flush_delete_delay())
239 return;
240 lseek(deldelay_fd, 0, 0);
241 }
242- while ((mode = read_delay_line(delbuf)) >= 0)
243- delete_item(delbuf, mode, NULL, DEL_RECURSE);
244+ while ((mode = read_delay_line(delbuf, &fileflags)) >= 0)
245+ delete_item(delbuf, mode, fileflags, NULL, DEL_RECURSE);
246 if (deldelay_fd >= 0)
247 close(deldelay_fd);
248 }
9c25eef5 249@@ -475,7 +486,7 @@ static void delete_in_dir(char *fbuf, st
ee76479d
WD
250 if (!remember_delete(fp, delbuf))
251 break;
252 } else
f813befd 253- delete_item(delbuf, fp->mode, NULL, DEL_RECURSE);
7d006b5b 254+ delete_item(delbuf, fp->mode, FF_PTR(fp), NULL, DEL_RECURSE);
f90a882e
WD
255 }
256 }
257
9c25eef5 258@@ -1219,7 +1230,7 @@ static void recv_generator(char *fname,
0461b869 259 * we need to delete it. If it doesn't exist, then
f90a882e 260 * (perhaps recursively) create it. */
ffc18846
WD
261 if (statret == 0 && !S_ISDIR(sx.st.st_mode)) {
262- if (delete_item(fname, sx.st.st_mode, "directory", del_opts) != 0)
7d006b5b 263+ if (delete_item(fname, sx.st.st_mode, FF_STAT(sx.st), "directory", del_opts) != 0)
99650e0d 264 goto skipping_dir_contents;
f90a882e
WD
265 statret = -1;
266 }
9c25eef5 267@@ -1351,7 +1362,7 @@ static void recv_generator(char *fname,
f90a882e
WD
268 }
269 /* Not the right symlink (or not a symlink), so
270 * delete it. */
ffc18846 271- if (delete_item(fname, sx.st.st_mode, "symlink", del_opts) != 0)
7d006b5b 272+ if (delete_item(fname, sx.st.st_mode, FF_STAT(sx.st), "symlink", del_opts) != 0)
ffc18846 273 goto cleanup;
05031682 274 } else if (basis_dir[0] != NULL) {
ffc18846 275 int j = try_dests_non(file, fname, ndx, fnamecmpbuf, &sx,
9c25eef5 276@@ -1430,7 +1441,7 @@ static void recv_generator(char *fname,
05031682 277 goto return_with_success;
ffc18846 278 goto cleanup;
05031682 279 }
ffc18846 280- if (delete_item(fname, sx.st.st_mode, t, del_opts) != 0)
7d006b5b 281+ if (delete_item(fname, sx.st.st_mode, FF_STAT(sx.st), t, del_opts) != 0)
ffc18846 282 goto cleanup;
05031682 283 } else if (basis_dir[0] != NULL) {
ffc18846 284 int j = try_dests_non(file, fname, ndx, fnamecmpbuf, &sx,
9c25eef5 285@@ -1521,7 +1532,7 @@ static void recv_generator(char *fname,
f90a882e
WD
286 fnamecmp_type = FNAMECMP_FNAME;
287
ffc18846
WD
288 if (statret == 0 && !S_ISREG(sx.st.st_mode)) {
289- if (delete_item(fname, sx.st.st_mode, "regular file", del_opts) != 0)
7d006b5b 290+ if (delete_item(fname, sx.st.st_mode, FF_STAT(sx.st), "regular file", del_opts) != 0)
ffc18846 291 goto cleanup;
f90a882e
WD
292 statret = -1;
293 stat_errno = ENOENT;
31611b92
WD
294--- old/options.c
295+++ new/options.c
99650e0d 296@@ -50,6 +50,7 @@ int preserve_hard_links = 0;
ffc18846 297 int preserve_acls = 0;
5795bf59 298 int preserve_xattrs = 0;
31611b92 299 int preserve_perms = 0;
5e3c6c93 300+int preserve_fileflags = 0;
31611b92
WD
301 int preserve_executability = 0;
302 int preserve_devices = 0;
303 int preserve_specials = 0;
790ba11a 304@@ -220,6 +221,7 @@ static void print_rsync_version(enum log
31611b92 305 char const *links = "no ";
58b399b9 306 char const *iconv = "no ";
31611b92 307 char const *ipv6 = "no ";
5e3c6c93 308+ char const *fileflags = "no ";
31611b92
WD
309 STRUCT_STAT *dumstat;
310
ac2da598 311 #if SUBPROTOCOL_VERSION != 0
790ba11a 312@@ -249,6 +251,9 @@ static void print_rsync_version(enum log
58b399b9
WD
313 #ifdef ICONV_OPTION
314 iconv = "";
31611b92 315 #endif
31611b92 316+#ifdef SUPPORT_FLAGS
5e3c6c93 317+ fileflags = "";
31611b92 318+#endif
ac2da598
WD
319
320 rprintf(f, "%s version %s protocol version %d%s\n",
321 RSYNC_NAME, RSYNC_VERSION, PROTOCOL_VERSION, subprotocol);
790ba11a 322@@ -262,8 +267,8 @@ static void print_rsync_version(enum log
5e3c6c93
WD
323 (int)(sizeof (int64) * 8));
324 rprintf(f, " %ssocketpairs, %shardlinks, %ssymlinks, %sIPv6, batchfiles, %sinplace,\n",
325 got_socketpair, hardlinks, links, ipv6, have_inplace);
58b399b9
WD
326- rprintf(f, " %sappend, %sACLs, %sxattrs, %siconv\n",
327- have_inplace, acls, xattrs, iconv);
328+ rprintf(f, " %sappend, %sACLs, %sxattrs, %siconv, %sfile-flags\n",
329+ have_inplace, acls, xattrs, iconv, fileflags);
5e3c6c93 330
31611b92 331 #ifdef MAINTAINER_MODE
5e3c6c93 332 rprintf(f, "Panic Action: \"%s\"\n", get_panic_action());
790ba11a 333@@ -330,6 +335,7 @@ void usage(enum logcode F)
31611b92
WD
334 rprintf(F," -K, --keep-dirlinks treat symlinked dir on receiver as dir\n");
335 rprintf(F," -H, --hard-links preserve hard links\n");
336 rprintf(F," -p, --perms preserve permissions\n");
5e3c6c93 337+ rprintf(F," --fileflags preserve file-flags\n");
31611b92 338 rprintf(F," -E, --executability preserve the file's executability\n");
063cf77b 339 rprintf(F," --chmod=CHMOD affect file and/or directory permissions\n");
ffc18846 340 #ifdef SUPPORT_ACLS
790ba11a 341@@ -469,6 +475,8 @@ static struct poptOption long_options[]
31611b92
WD
342 {"perms", 'p', POPT_ARG_VAL, &preserve_perms, 1, 0, 0 },
343 {"no-perms", 0, POPT_ARG_VAL, &preserve_perms, 0, 0, 0 },
344 {"no-p", 0, POPT_ARG_VAL, &preserve_perms, 0, 0, 0 },
5e3c6c93
WD
345+ {"fileflags", 0, POPT_ARG_VAL, &preserve_fileflags, 1, 0, 0 },
346+ {"no-fileflags", 0, POPT_ARG_VAL, &preserve_fileflags, 0, 0, 0 },
31611b92 347 {"executability", 'E', POPT_ARG_NONE, &preserve_executability, 0, 0, 0 },
ffc18846
WD
348 {"acls", 'A', POPT_ARG_NONE, 0, 'A', 0, 0 },
349 {"no-acls", 0, POPT_ARG_VAL, &preserve_acls, 0, 0, 0 },
790ba11a 350@@ -1279,6 +1287,15 @@ int parse_arguments(int *argc_p, const c
31611b92
WD
351 }
352 #endif
353
354+#ifndef SUPPORT_FLAGS
5e3c6c93 355+ if (preserve_fileflags) {
31611b92
WD
356+ snprintf(err_buf, sizeof err_buf,
357+ "file flags are not supported on this %s\n",
358+ am_server ? "server" : "client");
359+ return 0;
360+ }
361+#endif
362+
363 if (write_batch && read_batch) {
364 snprintf(err_buf, sizeof err_buf,
365 "--write-batch and --read-batch can not be used together\n");
790ba11a 366@@ -1770,6 +1787,9 @@ void server_options(char **args, int *ar
31611b92
WD
367 if (xfer_dirs && !recurse && delete_mode && am_sender)
368 args[ac++] = "--no-r";
369
5e3c6c93 370+ if (preserve_fileflags)
31611b92
WD
371+ args[ac++] = "--flags";
372+
373 if (do_compression && def_compress_level != Z_DEFAULT_COMPRESSION) {
374 if (asprintf(&arg, "--compress-level=%d", def_compress_level) < 0)
375 goto oom;
376--- old/rsync.c
377+++ new/rsync.c
58b399b9 378@@ -31,6 +31,7 @@ extern int dry_run;
ffc18846 379 extern int preserve_acls;
5795bf59 380 extern int preserve_xattrs;
31611b92 381 extern int preserve_perms;
5e3c6c93 382+extern int preserve_fileflags;
31611b92
WD
383 extern int preserve_executability;
384 extern int preserve_times;
9c25eef5
WD
385 extern int am_root;
386@@ -60,6 +61,16 @@ iconv_t ic_send = (iconv_t)-1, ic_recv =
58b399b9
WD
387 int ic_ndx;
388 #endif
ffc18846 389
9fa103b8
WD
390+#ifdef SUPPORT_FLAGS
391+#ifndef UF_NOUNLINK
392+#define UF_NOUNLINK 0
393+#endif
394+#ifndef SF_NOUNLINK
395+#define SF_NOUNLINK 0
396+#endif
ffc18846 397+#define NOCHANGE_FLAGS (UF_IMMUTABLE|UF_APPEND|UF_NOUNLINK|SF_IMMUTABLE|SF_APPEND|SF_NOUNLINK)
9fa103b8 398+#endif
ffc18846 399+
58b399b9
WD
400 static const char *default_charset(void)
401 {
402 #if defined HAVE_LIBCHARSET_H && defined HAVE_LOCALE_CHARSET
9c25eef5 403@@ -267,6 +278,41 @@ mode_t dest_mode(mode_t flist_mode, mode
f90a882e
WD
404 return new_mode;
405 }
406
407+#ifdef SUPPORT_FLAGS
408+/* Set a file's st_flags. */
409+static int set_fileflags(const char *fname, uint32 fileflags)
410+{
411+ if (do_chflags(fname, fileflags) != 0) {
412+ rsyserr(FERROR, errno,
413+ "failed to set file flags on %s",
414+ full_fname(fname));
415+ return 0;
416+ }
417+
418+ return 1;
419+}
420+
421+/* Remove immutable flags from an object, so it can be altered/removed. */
422+void make_mutable(char *fname, mode_t mode, uint32 fileflags)
423+{
5e3c6c93 424+ if (!preserve_fileflags && S_ISLNK(mode))
f90a882e
WD
425+ return;
426+
427+ if (fileflags & NOCHANGE_FLAGS)
428+ set_fileflags(fname, fileflags & ~NOCHANGE_FLAGS);
429+}
430+
431+/* Undo a prior make_mutable() call. */
432+void undo_make_mutable(char *fname, mode_t mode, uint32 fileflags)
433+{
5e3c6c93 434+ if (!preserve_fileflags && S_ISLNK(mode))
f90a882e
WD
435+ return;
436+
437+ if (fileflags & NOCHANGE_FLAGS)
438+ set_fileflags(fname, fileflags);
439+}
440+#endif
441+
5795bf59
WD
442 int set_file_attrs(const char *fname, struct file_struct *file, statx *sxp,
443 const char *fnamecmp, int flags)
f90a882e 444 {
9c25eef5 445@@ -395,6 +441,15 @@ int set_file_attrs(const char *fname, st
31611b92
WD
446 }
447 #endif
448
449+#ifdef SUPPORT_FLAGS
7d006b5b
WD
450+ if (preserve_fileflags && !S_ISLNK(sxp->st.st_mode)
451+ && sxp->st.st_flags != F_FFLAGS(file)) {
452+ if (!set_fileflags(fname, F_FFLAGS(file)))
31611b92 453+ return 0;
31611b92
WD
454+ updated = 1;
455+ }
456+#endif
457+
458 if (verbose > 1 && flags & ATTRS_REPORT) {
ff318e90
WD
459 if (updated)
460 rprintf(FCLIENT, "%s\n", fname);
9c25eef5 461@@ -454,6 +509,9 @@ void finish_transfer(const char *fname,
5795bf59 462 set_file_attrs(fnametmp, file, NULL, fnamecmp,
f90a882e 463 ok_to_set_time ? 0 : ATTRS_SKIP_MTIME);
31611b92
WD
464
465+#ifdef SUPPORT_FLAGS
7d006b5b 466+ make_mutable(fnametmp, file->mode, F_FFLAGS(file));
31611b92 467+#endif
f90a882e
WD
468 /* move tmp file over real file */
469 if (verbose > 2)
470 rprintf(FINFO, "renaming %s to %s\n", fnametmp, fname);
9c25eef5 471@@ -468,6 +526,9 @@ void finish_transfer(const char *fname,
f90a882e
WD
472 }
473 if (ret == 0) {
474 /* The file was moved into place (not copied), so it's done. */
31611b92 475+#ifdef SUPPORT_FLAGS
7d006b5b 476+ undo_make_mutable(fname, file->mode, F_FFLAGS(file));
31611b92 477+#endif
f90a882e
WD
478 return;
479 }
480 /* The file was copied, so tweak the perms of the copied file. If it
31611b92
WD
481--- old/rsync.h
482+++ new/rsync.h
99650e0d 483@@ -57,6 +57,7 @@
caf38d8d 484 #define XMIT_RDEV_MINOR_8_pre30 (1<<11) /* protocols 28 - 29 */
9c25eef5
WD
485 #define XMIT_GROUP_NAME_FOLLOWS (1<<11) /* protocols 30 - now */
486 #define XMIT_HLINK_FIRST (1<<12) /* protocols 30 - now (HLINKED files only) */
487+#define XMIT_SAME_FLAGS (1<<14) /* protocols ?? - now */
31611b92
WD
488
489 /* These flags are used in the live flist data. */
490
99650e0d 491@@ -406,6 +407,10 @@ enum msgcode {
7e27b6c0 492 #endif
6e6f514c
WD
493 #endif
494
495+#ifdef HAVE_CHFLAGS
496+#define SUPPORT_FLAGS 1
497+#endif
498+
499 /* Find a variable that is either exactly 32-bits or longer.
500 * If some code depends on 32-bit truncation, it will need to
501 * take special action in a "#if SIZEOF_INT32 > 4" section. */
9c25eef5
WD
502@@ -573,6 +578,7 @@ extern int file_extra_cnt;
503 extern int inc_recurse;
898a2112
WD
504 extern int uid_ndx;
505 extern int gid_ndx;
506+extern int fileflags_ndx;
507 extern int acls_ndx;
508 extern int xattrs_ndx;
fdf967c7 509
9c25eef5 510@@ -610,6 +616,7 @@ extern int xattrs_ndx;
1aa236e1 511 /* When the associated option is on, all entries will have these present: */
898a2112
WD
512 #define F_OWNER(f) REQ_EXTRA(f, uid_ndx)->unum
513 #define F_GROUP(f) REQ_EXTRA(f, gid_ndx)->unum
514+#define F_FFLAGS(f) REQ_EXTRA(f, fileflags_ndx)->unum
515 #define F_ACL(f) REQ_EXTRA(f, acls_ndx)->num
516 #define F_XATTR(f) REQ_EXTRA(f, xattrs_ndx)->num
58b399b9 517 #define F_NDX(f) REQ_EXTRA(f, ic_ndx)->num
31611b92
WD
518--- old/rsync.yo
519+++ new/rsync.yo
9c25eef5 520@@ -343,6 +343,7 @@ to the detailed description below for a
1ed0b5c9
WD
521 -K, --keep-dirlinks treat symlinked dir on receiver as dir
522 -H, --hard-links preserve hard links
31611b92 523 -p, --perms preserve permissions
31611b92 524+ --flags preserve file flags
1ed0b5c9 525 -E, --executability preserve executability
063cf77b 526 --chmod=CHMOD affect file and/or directory permissions
ffc18846 527 -A, --acls preserve ACLs (implies -p)
9c25eef5 528@@ -543,7 +544,9 @@ specified, in which case bf(-r) is not i
31611b92
WD
529
530 Note that bf(-a) bf(does not preserve hardlinks), because
531 finding multiply-linked files is expensive. You must separately
532-specify bf(-H).
533+specify bf(-H). Note also that for compatibility, bf(-a)
534+currently bf(does not include --flags) (see there) to include preserving
535+change file flags (if supported by the OS).
536
537 dit(--no-OPTION) You may turn off one or more implied options by prefixing
538 the option name with "no-". Not all options may be prefixed with a "no-":
790ba11a 539@@ -883,6 +886,13 @@ dit(bf(-X, --xattrs)) This option causes
99650e0d
WD
540 extended attributes to be the same as the local ones. This will work
541 only if the remote machine's rsync also supports this option.
31611b92
WD
542
543+dit(bf(--flags)) This option causes rsync to update the change file flags
f90a882e 544+to be the same as the source file, if your OS supports the bf(chflags)(2)
31611b92
WD
545+system call. In any case, an attempt is made to remove flags that would
546+prevent a file to be altered. Some flags can only be altered by the
547+super-user and can only be unset below a certain secure-level (usually
548+single-user mode).
549+
550 dit(bf(--chmod)) This option tells rsync to apply one or more
551 comma-separated "chmod" strings to the permission of the files in the
552 transfer. The resulting value is treated as though it was the permissions
553--- old/syscall.c
554+++ new/syscall.c
58b399b9 555@@ -162,6 +162,15 @@ int do_chmod(const char *path, mode_t mo
31611b92
WD
556 }
557 #endif
558
559+#ifdef SUPPORT_FLAGS
560+int do_chflags(const char *path, u_long flags)
561+{
562+ if (dry_run) return 0;
563+ RETURN_ERROR_IF_RO_OR_LO;
564+ return chflags(path, flags);
565+}
566+#endif
567+
568 int do_rename(const char *fname1, const char *fname2)
569 {
570 if (dry_run) return 0;