Revised flags patch

Rolf Grossmann grossman at progtech.net
Fri Feb 15 20:04:48 GMT 2008


Hi,

first of all, sorry for taking so long. Unfortunately, some other tasks
kept coming up. Anyway, attached is the version of the flags patch, that
is based on the one I'm using with 2.6.9. It is against the rsync-3.0.0pre9
release.

I've included the option name change from the repository, so the
option is now called --fileflags.  Improved from the previously
distributed version is the handling of hard links and (probably, since
I'm not using them) backup files. It also fixes some bitrot that would
have crept into the version for 3.0 without this update. ;)

I hope you'll like it and include it with the 3.0 release.

Thanks, Rolf

PS: Please CC me on any comments, since I'm not on the list.
-------------- next part --------------
diff -brpu rsync-3.0.0pre9/backup.c rsync-3.0.0pre9-flags/backup.c
--- rsync-3.0.0pre9/backup.c	Mon Sep 24 00:19:55 2007
+++ rsync-3.0.0pre9-flags/backup.c	Fri Feb 15 19:33:09 2008
@@ -61,7 +61,17 @@ static int make_simple_backup(const char
 		return 0;
 
 	while (1) {
-		if (do_rename(fname, fnamebak) == 0) {
+#ifdef SUPPORT_FLAGS
+		STRUCT_STAT st2;
+		
+		link_stat(fname, &st2, 0);
+		make_mutable(fname, st2.st_mode, st2.st_flags);		
+#endif
+		if (do_rename(fname, fnamebak) == 0)
+		{
+#ifdef SUPPORT_FLAGS
+			undo_make_mutable(fnamebak, st2.st_mode, st2.st_flags);		
+#endif
 			if (verbose > 1) {
 				rprintf(FINFO, "backed up %s to %s\n",
 					fname, fnamebak);
diff -brpu rsync-3.0.0pre9/compat.c rsync-3.0.0pre9-flags/compat.c
--- rsync-3.0.0pre9/compat.c	Sat Jan 26 20:58:17 2008
+++ rsync-3.0.0pre9-flags/compat.c	Fri Feb 15 19:33:09 2008
@@ -44,6 +44,7 @@ extern int protocol_version;
 extern int protect_args;
 extern int preserve_uid;
 extern int preserve_gid;
+extern int preserve_fileflags;
 extern int preserve_acls;
 extern int preserve_xattrs;
 extern int need_messages_from_generator;
@@ -60,7 +61,7 @@ extern iconv_t ic_send, ic_recv;
 #endif
 
 /* These index values are for the file-list's extra-attribute array. */
-int uid_ndx, gid_ndx, acls_ndx, xattrs_ndx, unsort_ndx;
+int uid_ndx, gid_ndx, fileflags_ndx, acls_ndx, xattrs_ndx, unsort_ndx;
 
 #ifdef ICONV_OPTION
 int filesfrom_convert = 0;
@@ -124,6 +125,8 @@ void setup_protocol(int f_out,int f_in)
 		uid_ndx = ++file_extra_cnt;
 	if (preserve_gid)
 		gid_ndx = ++file_extra_cnt;
+	if (preserve_fileflags)
+		fileflags_ndx = ++file_extra_cnt;
 	if (preserve_acls && !am_sender)
 		acls_ndx = ++file_extra_cnt;
 	if (preserve_xattrs)
diff -brpu rsync-3.0.0pre9/config.h.in rsync-3.0.0pre9-flags/config.h.in
--- rsync-3.0.0pre9/config.h.in	Mon Feb 11 05:16:36 2008
+++ rsync-3.0.0pre9-flags/config.h.in	Fri Feb 15 19:33:09 2008
@@ -64,6 +64,9 @@
 /* Define to 1 if vsprintf has a C99-compatible return value */
 #undef HAVE_C99_VSNPRINTF
 
+/* Define to 1 if you have the `chflags' function. */
+#undef HAVE_CHFLAGS
+
 /* Define to 1 if you have the `chmod' function. */
 #undef HAVE_CHMOD
 
diff -brpu rsync-3.0.0pre9/configure.in rsync-3.0.0pre9-flags/configure.in
--- rsync-3.0.0pre9/configure.in	Mon Feb 11 05:16:25 2008
+++ rsync-3.0.0pre9-flags/configure.in	Fri Feb 15 19:33:09 2008
@@ -551,7 +551,7 @@ AC_CHECK_FUNCS(waitpid wait4 getcwd strd
     memmove lchown vsnprintf snprintf vasprintf asprintf setsid glob strpbrk \
     strlcat strlcpy strtol mallinfo getgroups setgroups geteuid getegid \
     setlocale setmode open64 lseek64 mkstemp64 mtrace va_copy __va_copy \
-    strerror putenv iconv_open locale_charset nl_langinfo getxattr \
+    chflags strerror putenv iconv_open locale_charset nl_langinfo getxattr \
     extattr_get_link sigaction sigprocmask setattrlist)
 
 dnl cygwin iconv.h defines iconv_open as libiconv_open
diff -brpu rsync-3.0.0pre9/configure.sh rsync-3.0.0pre9-flags/configure.sh
--- rsync-3.0.0pre9/configure.sh	Mon Feb 11 05:16:36 2008
+++ rsync-3.0.0pre9-flags/configure.sh	Fri Feb 15 20:15:52 2008
@@ -14794,7 +14794,7 @@ for ac_func in waitpid wait4 getcwd strd
     memmove lchown vsnprintf snprintf vasprintf asprintf setsid glob strpbrk \
     strlcat strlcpy strtol mallinfo getgroups setgroups geteuid getegid \
     setlocale setmode open64 lseek64 mkstemp64 mtrace va_copy __va_copy \
-    strerror putenv iconv_open locale_charset nl_langinfo getxattr \
+    chflags strerror putenv iconv_open locale_charset nl_langinfo getxattr \
     extattr_get_link sigaction sigprocmask setattrlist
 do
 as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
diff -brpu rsync-3.0.0pre9/flist.c rsync-3.0.0pre9-flags/flist.c
--- rsync-3.0.0pre9/flist.c	Sun Feb 10 06:41:50 2008
+++ rsync-3.0.0pre9-flags/flist.c	Fri Feb 15 19:33:09 2008
@@ -50,6 +50,7 @@ extern int preserve_links;
 extern int preserve_hard_links;
 extern int preserve_devices;
 extern int preserve_specials;
+extern int fileflags_ndx;
 extern int uid_ndx;
 extern int gid_ndx;
 extern int eol_nulls;
@@ -344,6 +345,9 @@ static void send_file_entry(int f, struc
 {
 	static time_t modtime;
 	static mode_t mode;
+#ifdef SUPPORT_FLAGS
+	static uint32 fileflags;
+#endif
 #ifdef SUPPORT_HARD_LINKS
 	static int64 dev;
 #endif
@@ -403,6 +407,12 @@ static void send_file_entry(int f, struc
 		xflags |= XMIT_SAME_MODE;
 	else
 		mode = file->mode;
+#ifdef SUPPORT_FLAGS
+	if (F_FFLAGS(file) == fileflags)
+		xflags |= XMIT_SAME_FLAGS;
+	else
+		fileflags = F_FFLAGS(file);
+#endif
 
 	if ((preserve_devices && IS_DEVICE(mode))
 	 || (preserve_specials && IS_SPECIAL(mode))) {
@@ -522,6 +532,10 @@ static void send_file_entry(int f, struc
 	}
 	if (!(xflags & XMIT_SAME_MODE))
 		write_int(f, to_wire_mode(mode));
+#ifdef SUPPORT_FLAGS
+	if (fileflags_ndx && !(xflags & XMIT_SAME_FLAGS))
+		write_int(f, (int)fileflags);
+#endif
 	if (uid_ndx && !(xflags & XMIT_SAME_UID)) {
 		if (protocol_version < 30)
 			write_int(f, uid);
@@ -610,6 +624,9 @@ static struct file_struct *recv_file_ent
 {
 	static int64 modtime;
 	static mode_t mode;
+#ifdef SUPPORT_FLAGS
+	static uint32 fileflags;
+#endif
 #ifdef SUPPORT_HARD_LINKS
 	static int64 dev;
 #endif
@@ -745,6 +762,11 @@ static struct file_struct *recv_file_ent
 	if (chmod_modes && !S_ISLNK(mode))
 		mode = tweak_mode(mode, chmod_modes);
 
+#ifdef SUPPORT_FLAGS
+	if (fileflags_ndx && !(xflags & XMIT_SAME_FLAGS))
+		fileflags = (uint32)read_int(f);
+#endif
+
 	if (uid_ndx && !(xflags & XMIT_SAME_UID)) {
 		if (protocol_version < 30)
 			uid = (uid_t)read_int(f);
@@ -865,6 +887,10 @@ static struct file_struct *recv_file_ent
 		OPT_EXTRA(file, 0)->unum = (uint32)(file_length >> 32);
 	}
 	file->mode = mode;
+#ifdef SUPPORT_FLAGS
+	if (fileflags_ndx)
+		F_FFLAGS(file) = fileflags;
+#endif
 	if (uid_ndx)
 		F_OWNER(file) = uid;
 	if (gid_ndx) {
@@ -1199,6 +1225,10 @@ struct file_struct *make_file(const char
 		OPT_EXTRA(file, 0)->unum = (uint32)(st.st_size >> 32);
 	}
 	file->mode = st.st_mode;
+#ifdef SUPPORT_FLAGS
+	if (fileflags_ndx)
+		F_FFLAGS(file) = st.st_flags;
+#endif
 	if (uid_ndx)
 		F_OWNER(file) = st.st_uid;
 	if (gid_ndx)
diff -brpu rsync-3.0.0pre9/hlink.c rsync-3.0.0pre9-flags/hlink.c
--- rsync-3.0.0pre9/hlink.c	Thu Feb  7 01:06:33 2008
+++ rsync-3.0.0pre9-flags/hlink.c	Fri Feb 15 19:35:16 2008
@@ -389,6 +389,12 @@ int hard_link_check(struct file_struct *
 int hard_link_one(struct file_struct *file, const char *fname,
 		  const char *oldname, int terse)
 {
+#if SUPPORT_FLAGS
+	STRUCT_STAT st2;
+	
+	link_stat(oldname, &st2, 0);
+	make_mutable(oldname, st2.st_mode, st2.st_flags);
+#endif
 	if (do_link(oldname, fname) < 0) {
 		enum logcode code;
 		if (terse) {
@@ -401,6 +407,9 @@ int hard_link_one(struct file_struct *fi
 			full_fname(fname), oldname);
 		return 0;
 	}
+#if SUPPORT_FLAGS
+	undo_make_mutable(oldname, st2.st_mode, st2.st_flags);
+#endif
 
 	file->flags |= FLAG_HLINK_DONE;
 
diff -brpu rsync-3.0.0pre9/options.c rsync-3.0.0pre9-flags/options.c
--- rsync-3.0.0pre9/options.c	Sat Jan 19 20:20:17 2008
+++ rsync-3.0.0pre9-flags/options.c	Fri Feb 15 19:35:16 2008
@@ -52,6 +52,7 @@ int preserve_hard_links = 0;
 int preserve_acls = 0;
 int preserve_xattrs = 0;
 int preserve_perms = 0;
+int preserve_fileflags = 0;
 int preserve_executability = 0;
 int preserve_devices = 0;
 int preserve_specials = 0;
@@ -223,6 +224,7 @@ static void print_rsync_version(enum log
 	char const *links = "no ";
 	char const *iconv = "no ";
 	char const *ipv6 = "no ";
+	char const *fileflags = "no ";
 	STRUCT_STAT *dumstat;
 
 #if SUBPROTOCOL_VERSION != 0
@@ -252,6 +254,9 @@ static void print_rsync_version(enum log
 #ifdef ICONV_OPTION
 	iconv = "";
 #endif
+#ifdef SUPPORT_FLAGS
+	fileflags = "";
+#endif
 
 	rprintf(f, "%s  version %s  protocol version %d%s\n",
 		RSYNC_NAME, RSYNC_VERSION, PROTOCOL_VERSION, subprotocol);
@@ -265,8 +270,8 @@ static void print_rsync_version(enum log
 		(int)(sizeof (int64) * 8));
 	rprintf(f, "    %ssocketpairs, %shardlinks, %ssymlinks, %sIPv6, batchfiles, %sinplace,\n",
 		got_socketpair, hardlinks, links, ipv6, have_inplace);
-	rprintf(f, "    %sappend, %sACLs, %sxattrs, %siconv\n",
-		have_inplace, acls, xattrs, iconv);
+	rprintf(f, "    %sappend, %sACLs, %sxattrs, %siconv, %sfile-flags\n",
+		have_inplace, acls, xattrs, iconv, fileflags);
 
 #ifdef MAINTAINER_MODE
 	rprintf(f, "Panic Action: \"%s\"\n", get_panic_action());
@@ -333,6 +338,7 @@ void usage(enum logcode F)
   rprintf(F," -K, --keep-dirlinks         treat symlinked dir on receiver as dir\n");
   rprintf(F," -H, --hard-links            preserve hard links\n");
   rprintf(F," -p, --perms                 preserve permissions\n");
+  rprintf(F,"     --fileflags             preserve file-flags\n");
   rprintf(F," -E, --executability         preserve the file's executability\n");
   rprintf(F,"     --chmod=CHMOD           affect file and/or directory permissions\n");
 #ifdef SUPPORT_ACLS
@@ -473,6 +479,8 @@ static struct poptOption long_options[] 
   {"perms",           'p', POPT_ARG_VAL,    &preserve_perms, 1, 0, 0 },
   {"no-perms",         0,  POPT_ARG_VAL,    &preserve_perms, 0, 0, 0 },
   {"no-p",             0,  POPT_ARG_VAL,    &preserve_perms, 0, 0, 0 },
+  {"fileflags",        0,  POPT_ARG_VAL,    &preserve_fileflags, 1, 0, 0 },
+  {"no-fileflags",     0,  POPT_ARG_VAL,    &preserve_fileflags, 0, 0, 0 },
   {"executability",   'E', POPT_ARG_NONE,   &preserve_executability, 0, 0, 0 },
   {"acls",            'A', POPT_ARG_NONE,   0, 'A', 0, 0 },
   {"no-acls",          0,  POPT_ARG_VAL,    &preserve_acls, 0, 0, 0 },
@@ -1289,6 +1297,15 @@ int parse_arguments(int *argc_p, const c
 	}
 #endif
 
+#ifndef SUPPORT_FLAGS
+	if (preserve_fileflags) {
+		snprintf(err_buf, sizeof err_buf,
+			 "file flags are not supported on this %s\n",
+			 am_server ? "server" : "client");
+		return 0;
+	}
+#endif
+
 	if (write_batch && read_batch) {
 		snprintf(err_buf, sizeof err_buf,
 			"--write-batch and --read-batch can not be used together\n");
@@ -1803,6 +1820,9 @@ void server_options(char **args, int *ar
 	 * sans -r because the --no-r option was added at the same time. */
 	if (xfer_dirs && !recurse && delete_mode && am_sender)
 		args[ac++] = "--no-r";
+
+	if (preserve_fileflags)
+		args[ac++] = "--fileflags";
 
 	if (do_compression && def_compress_level != Z_DEFAULT_COMPRESSION) {
 		if (asprintf(&arg, "--compress-level=%d", def_compress_level) < 0)
diff -brpu rsync-3.0.0pre9/proto.h rsync-3.0.0pre9-flags/proto.h
--- rsync-3.0.0pre9/proto.h	Mon Feb 11 05:12:39 2008
+++ rsync-3.0.0pre9-flags/proto.h	Fri Feb 15 19:35:16 2008
@@ -267,6 +267,8 @@ int read_ndx_and_attrs(int f_in, int *if
 void free_sums(struct sum_struct *s);
 mode_t dest_mode(mode_t flist_mode, mode_t stat_mode, int dflt_perms,
 		 int exists);
+void make_mutable(const char *fname, mode_t mode, uint32 fileflags);
+void undo_make_mutable(const char *fname, mode_t mode, uint32 fileflags);
 int set_file_attrs(const char *fname, struct file_struct *file, stat_x *sxp,
 		   const char *fnamecmp, int flags);
 RETSIGTYPE sig_int(UNUSED(int val));
@@ -296,6 +298,7 @@ int do_mknod(const char *pathname, mode_
 int do_rmdir(const char *pathname);
 int do_open(const char *pathname, int flags, mode_t mode);
 int do_chmod(const char *path, mode_t mode);
+int do_chflags(const char *path, u_long flags);
 int do_rename(const char *fname1, const char *fname2);
 void trim_trailing_slashes(char *name);
 int do_mkdir(char *fname, mode_t mode);
diff -brpu rsync-3.0.0pre9/rsync.1 rsync-3.0.0pre9-flags/rsync.1
--- rsync-3.0.0pre9/rsync.1	Mon Feb 11 05:16:37 2008
+++ rsync-3.0.0pre9-flags/rsync.1	Fri Feb 15 20:25:34 2008
@@ -413,6 +413,7 @@ to the detailed description below for a 
  \-K, \-\-keep\-dirlinks         treat symlinked dir on receiver as dir
  \-H, \-\-hard\-links            preserve hard links
  \-p, \-\-perms                 preserve permissions
+      \-\-fileflags             preserve file flags
  \-E, \-\-executability         preserve executability
      \-\-chmod=CHMOD           affect file and/or directory permissions
  \-A, \-\-acls                  preserve ACLs (implies \-p)
@@ -631,7 +632,9 @@ specified, in which case \fB\-r\fP is no
 .IP 
 Note that \fB\-a\fP \fBdoes not preserve hardlinks\fP, because
 finding multiply-linked files is expensive.  You must separately
-specify \fB\-H\fP.
+specify \fB\-H\fP.  Note also that for compatibility, \fB\-a\fP
+currently \fBdoes not include \-\-fileflags\fP (see there) to include preserving
+file flags (if supported by the OS)\&.
 .IP 
 .IP "\-\-no\-OPTION"
 You may turn off one or more implied options by prefixing
@@ -1061,6 +1064,14 @@ For systems that support extended-attrib
 super-user copies all namespaces except system.*.  A normal user only copies
 the user.* namespace.  To be able to backup and restore non-user namespaces as
 a normal user, see the \fB\-\-fake\-super\fP option.
+.IP 
+.IP "\fB\-\-fileflags\fP"
+This option causes rsync to update the file flags
+to be the same as the source file, if your OS supports the \fBchflags\fP(2)
+system call\&.  In any case, an attempt is made to remove flags that would
+prevent a file to be altered\&.  Some flags can only be altered by the
+super-user and can only be unset below a certain secure-level (usually
+single-user mode)\&.
 .IP 
 .IP "\fB\-\-chmod\fP"
 This option tells rsync to apply one or more
diff -brpu rsync-3.0.0pre9/rsync.c rsync-3.0.0pre9-flags/rsync.c
--- rsync-3.0.0pre9/rsync.c	Thu Feb  7 16:24:58 2008
+++ rsync-3.0.0pre9-flags/rsync.c	Fri Feb 15 19:39:33 2008
@@ -32,6 +32,7 @@ extern int dry_run;
 extern int preserve_acls;
 extern int preserve_xattrs;
 extern int preserve_perms;
+extern int preserve_fileflags;
 extern int preserve_executability;
 extern int preserve_times;
 extern int am_root;
@@ -60,6 +61,16 @@ iconv_t ic_chck = (iconv_t)-1;
 iconv_t ic_send = (iconv_t)-1, ic_recv = (iconv_t)-1;
 # endif
 
+#ifdef SUPPORT_FLAGS
+#ifndef UF_NOUNLINK
+#define UF_NOUNLINK 0
+#endif
+#ifndef SF_NOUNLINK
+#define SF_NOUNLINK 0
+#endif
+#define NOCHANGE_FLAGS (UF_IMMUTABLE|UF_APPEND|UF_NOUNLINK|SF_IMMUTABLE|SF_APPEND|SF_NOUNLINK)
+#endif
+
 static const char *default_charset(void)
 {
 # if defined HAVE_LIBCHARSET_H && defined HAVE_LOCALE_CHARSET
@@ -338,6 +349,41 @@ mode_t dest_mode(mode_t flist_mode, mode
 	return new_mode;
 }
 
+#ifdef SUPPORT_FLAGS
+/* Set a file's st_flags. */
+static int set_fileflags(const char *fname, uint32 fileflags)
+{
+	if (do_chflags(fname, fileflags) != 0) {
+		rsyserr(FERROR_XFER, errno,
+			"failed to set file flags on %s",
+			full_fname(fname));
+		return 0;
+	}
+
+	return 1;
+}
+
+/* Remove immutable flags from an object, so it can be altered/removed. */
+void make_mutable(const char *fname, mode_t mode, uint32 fileflags)
+{
+	if (!preserve_fileflags || S_ISLNK(mode))
+		return;
+
+	if (fileflags & NOCHANGE_FLAGS)
+		set_fileflags(fname, fileflags & ~NOCHANGE_FLAGS);
+}
+
+/* Undo a prior make_mutable() call. */
+void undo_make_mutable(const char *fname, mode_t mode, uint32 fileflags)
+{
+	if (!preserve_fileflags || S_ISLNK(mode))
+		return;
+
+	if (fileflags & NOCHANGE_FLAGS)
+		set_fileflags(fname, fileflags);
+}
+#endif
+
 int set_file_attrs(const char *fname, struct file_struct *file, stat_x *sxp,
 		   const char *fnamecmp, int flags)
 {
@@ -391,6 +437,9 @@ int set_file_attrs(const char *fname, st
 		flags |= ATTRS_SKIP_MTIME;
 	if (!(flags & ATTRS_SKIP_MTIME)
 	    && cmp_time(sxp->st.st_mtime, file->modtime) != 0) {
+#ifdef SUPPORT_FLAGS
+		make_mutable(fname, sxp->st.st_mode, sxp->st.st_flags);
+#endif
 		int ret = set_modtime(fname, file->modtime, sxp->st.st_mode);
 		if (ret < 0) {
 			rsyserr(FERROR_XFER, errno, "failed to set times on %s",
@@ -423,6 +472,9 @@ int set_file_attrs(const char *fname, st
 			}
 		}
 		if (am_root >= 0) {
+#ifdef SUPPORT_FLAGS
+			make_mutable(fname, sxp->st.st_mode, sxp->st.st_flags);
+#endif
 			if (do_lchown(fname,
 			    change_uid ? (uid_t)F_OWNER(file) : sxp->st.st_uid,
 			    change_gid ? (gid_t)F_GROUP(file) : sxp->st.st_gid) != 0) {
@@ -457,7 +509,13 @@ int set_file_attrs(const char *fname, st
 
 #ifdef HAVE_CHMOD
 	if (!BITS_EQUAL(sxp->st.st_mode, new_mode, CHMOD_BITS)) {
-		int ret = am_root < 0 ? 0 : do_chmod(fname, new_mode);
+		int ret = 0;
+		if (am_root >= 0) {
+#ifdef SUPPORT_FLAGS
+			make_mutable(fname, sxp->st.st_mode, sxp->st.st_flags);
+#endif
+			ret = do_chmod(fname, new_mode);
+		}
 		if (ret < 0) {
 			rsyserr(FERROR_XFER, errno,
 				"failed to set permissions on %s",
@@ -469,6 +527,17 @@ int set_file_attrs(const char *fname, st
 	}
 #endif
 
+#ifdef SUPPORT_FLAGS
+	if ((preserve_fileflags || updated)
+		&& !S_ISLNK(sxp->st.st_mode)
+		&& (sxp->st.st_flags != F_FFLAGS(file)
+			|| (updated && F_FFLAGS(file) != 0))) {
+		if (!set_fileflags(fname, F_FFLAGS(file)))
+			goto cleanup;
+		updated = 1;
+	}
+#endif
+
 	if (verbose > 1 && flags & ATTRS_REPORT) {
 		if (updated)
 			rprintf(FCLIENT, "%s\n", fname);
@@ -530,6 +599,9 @@ int finish_transfer(const char *fname, c
 	set_file_attrs(fnametmp, file, NULL, fnamecmp,
 		       ok_to_set_time ? 0 : ATTRS_SKIP_MTIME);
 
+#ifdef SUPPORT_FLAGS
+	make_mutable(fnametmp, file->mode, F_FFLAGS(file));
+#endif
 	/* move tmp file over real file */
 	if (verbose > 2)
 		rprintf(FINFO, "renaming %s to %s\n", fnametmp, fname);
@@ -547,6 +619,9 @@ int finish_transfer(const char *fname, c
 	}
 	if (ret == 0) {
 		/* The file was moved into place (not copied), so it's done. */
+#ifdef SUPPORT_FLAGS
+		undo_make_mutable(fname, file->mode, F_FFLAGS(file));
+#endif
 		return 1;
 	}
 	/* The file was copied, so tweak the perms of the copied file.  If it
diff -brpu rsync-3.0.0pre9/rsync.h rsync-3.0.0pre9-flags/rsync.h
--- rsync-3.0.0pre9/rsync.h	Mon Feb  4 16:29:22 2008
+++ rsync-3.0.0pre9-flags/rsync.h	Fri Feb 15 20:29:08 2008
@@ -60,6 +60,7 @@
 #define XMIT_RDEV_MINOR_8_pre30 (1<<11)	/* protocols 28 - 29  */
 #define XMIT_GROUP_NAME_FOLLOWS (1<<11) /* protocols 30 - now */
 #define XMIT_HLINK_FIRST (1<<12)	/* protocols 30 - now (HLINKED files only) */
+#define XMIT_SAME_FLAGS (1<<14)		/* protocols ?? - now */
 
 /* These flags are used in the live flist data. */
 
@@ -451,6 +452,10 @@ typedef unsigned int size_t;
 #endif
 #endif
 
+#ifdef HAVE_CHFLAGS
+#define SUPPORT_FLAGS 1
+#endif
+
 /* Find a variable that is either exactly 32-bits or longer.
  * If some code depends on 32-bit truncation, it will need to
  * take special action in a "#if SIZEOF_INT32 > 4" section. */
@@ -619,6 +624,7 @@
 extern int inc_recurse;
 extern int uid_ndx;
 extern int gid_ndx;
+extern int fileflags_ndx;
 extern int acls_ndx;
 extern int xattrs_ndx;
 
@@ -656,6 +664,7 @@ extern int xattrs_ndx;
 /* When the associated option is on, all entries will have these present: */
 #define F_OWNER(f) REQ_EXTRA(f, uid_ndx)->unum
 #define F_GROUP(f) REQ_EXTRA(f, gid_ndx)->unum
+#define F_FFLAGS(f) REQ_EXTRA(f, fileflags_ndx)->unum
 #define F_ACL(f) REQ_EXTRA(f, acls_ndx)->num
 #define F_XATTR(f) REQ_EXTRA(f, xattrs_ndx)->num
 #define F_NDX(f) REQ_EXTRA(f, unsort_ndx)->num
diff -brpu rsync-3.0.0pre9/rsync.yo rsync-3.0.0pre9-flags/rsync.yo
--- rsync-3.0.0pre9/rsync.yo	Mon Feb 11 05:16:25 2008
+++ rsync-3.0.0pre9-flags/rsync.yo	Fri Feb 15 20:25:44 2008
@@ -338,6 +338,7 @@ to the detailed description below for a 
  -K, --keep-dirlinks         treat symlinked dir on receiver as dir
  -H, --hard-links            preserve hard links
  -p, --perms                 preserve permissions
+     --fileflags             preserve file flags
  -E, --executability         preserve executability
      --chmod=CHMOD           affect file and/or directory permissions
  -A, --acls                  preserve ACLs (implies -p)
@@ -540,7 +541,9 @@ specified, in which case bf(-r) is not i
 
 Note that bf(-a) bf(does not preserve hardlinks), because
 finding multiply-linked files is expensive.  You must separately
-specify bf(-H).
+specify bf(-H).  Note also that for compatibility, bf(-a)
+currently bf(does not include --fileflags) (see there) to include preserving
+file flags (if supported by the OS).
 
 dit(--no-OPTION) You may turn off one or more implied options by prefixing
 the option name with "no-".  Not all options may be prefixed with a "no-":
@@ -921,6 +924,13 @@ For systems that support extended-attrib
 super-user copies all namespaces except system.*.  A normal user only copies
 the user.* namespace.  To be able to backup and restore non-user namespaces as
 a normal user, see the bf(--fake-super) option.
+
+dit(bf(--fileflags)) This option causes rsync to update the file flags
+to be the same as the source file, if your OS supports the bf(chflags)(2)
+system call.  In any case, an attempt is made to remove flags that would
+prevent a file to be altered.  Some flags can only be altered by the
+super-user and can only be unset below a certain secure-level (usually
+single-user mode).
 
 dit(bf(--chmod)) This option tells rsync to apply one or more
 comma-separated "chmod" strings to the permission of the files in the
diff -brpu rsync-3.0.0pre9/syscall.c rsync-3.0.0pre9-flags/syscall.c
--- rsync-3.0.0pre9/syscall.c	Sat Jan 26 01:57:02 2008
+++ rsync-3.0.0pre9-flags/syscall.c	Fri Feb 15 19:35:16 2008
@@ -50,6 +50,9 @@ int do_unlink(const char *fname)
 {
 	if (dry_run) return 0;
 	RETURN_ERROR_IF_RO_OR_LO;
+#if SUPPORT_FLAGS
+	chflags(fname, 0);
+#endif
 	return unlink(fname);
 }
 
@@ -133,6 +136,9 @@ int do_rmdir(const char *pathname)
 {
 	if (dry_run) return 0;
 	RETURN_ERROR_IF_RO_OR_LO;
+#if SUPPORT_FLAGS
+	chflags(pathname, 0);
+#endif
 	return rmdir(pathname);
 }
 
@@ -174,10 +180,22 @@ int do_chmod(const char *path, mode_t mo
 }
 #endif
 
+#ifdef SUPPORT_FLAGS
+int do_chflags(const char *path, u_long flags)
+{
+	if (dry_run) return 0;
+	RETURN_ERROR_IF_RO_OR_LO;
+	return chflags(path, flags);
+}
+#endif
+
 int do_rename(const char *fname1, const char *fname2)
 {
 	if (dry_run) return 0;
 	RETURN_ERROR_IF_RO_OR_LO;
+#if SUPPORT_FLAGS
+	chflags(fname2, 0);
+#endif
 	return rename(fname1, fname2);
 }
 


More information about the rsync mailing list