Solved problem with hard links and schg flag under FreeBSD

Franz Schwartau franz at electromail.org
Mon May 7 08:52:42 MDT 2012


Hi!

Using rsync under FreeBSD with hard links and files having schg set 
result in EPERM "Operation not permitted". This behavior can be observed 
if rsyncing /usr/bin/.

The patch fileflags.diff tries to deal with this situation but changes 
the flags of the parent directory only. It doesn't change the flags of 
the files itself.

do_link() in syscall.c has to be fixed. The attached 
syscall-do_link.c.txt contains the complete function do_link(). 
patch-syscall.c.txt is a patch which have the be applied after 
fileflags.diff.

Please have a look at the changes.

What is the "official" way of asking for inclusion in the rsync 
distribution? Reporting a bug via bugzilla?

	Best regards
		Franz
-------------- next part --------------
#ifdef HAVE_LINK
int do_link(const char *fname1, const char *fname2)
{
	if (dry_run) return 0;
	RETURN_ERROR_IF_RO_OR_LO;
	if (link(fname1, fname2) == 0)
		return 0;

#ifdef SUPPORT_FORCE_CHANGE
	if (force_change && (errno == EPERM || errno == EACCES)) {
		char parent[MAXPATHLEN];
		int parent_flags;
		int saved_errno = errno;
		int file_flags = make_mutable(fname1, NULL, NO_FFLAGS, force_change);
		if (file_flags) {
		       	int ret = link(fname1, fname2);
			undo_make_mutable(fname1, file_flags);
			if (ret == 0)
				return 0;
		}
		parent_flags = make_parentdir_mutable(fname2, force_change, parent, sizeof parent);
		if (parent_flags) {
			int ret = link(fname1, fname2);
			undo_make_mutable(parent, parent_flags);
			if (ret == 0)
				return 0;
		}
		errno = saved_errno;
	}
#endif

	return -1;
}
#endif
-------------- next part --------------
--- syscall.c.orig	2012-05-07 16:30:28.000000000 +0200
+++ syscall.c	2012-05-07 16:30:44.000000000 +0200
@@ -114,8 +114,16 @@
 #ifdef SUPPORT_FORCE_CHANGE
 	if (force_change && (errno == EPERM || errno == EACCES)) {
 		char parent[MAXPATHLEN];
+		int parent_flags;
 		int saved_errno = errno;
-		int parent_flags = make_parentdir_mutable(fname2, force_change, parent, sizeof parent);
+		int file_flags = make_mutable(fname1, NULL, NO_FFLAGS, force_change);
+		if (file_flags) {
+		       	int ret = link(fname1, fname2);
+			undo_make_mutable(fname1, file_flags);
+			if (ret == 0)
+				return 0;
+		}
+		parent_flags = make_parentdir_mutable(fname2, force_change, parent, sizeof parent);
 		if (parent_flags) {
 			int ret = link(fname1, fname2);
 			undo_make_mutable(parent, parent_flags);


More information about the rsync mailing list