Franz Schwartau
2012-May-07 14:52 UTC
Solved problem with hard links and schg flag under FreeBSD
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);
