rdiff-backup-users
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[rdiff-backup-users] Mac OS X extended attributes support


From: Andrew Ferguson
Subject: [rdiff-backup-users] Mac OS X extended attributes support
Date: Sat, 29 Apr 2006 16:38:54 -0400
User-agent: Thunderbird 1.5.0.2 (Macintosh/20060308)

Hi,

I just sent this patch to Ben Escoto, but I wanted to get it out there
for comments and more testing.

Mac OS X 10.4 introduced generic extended attributes to the HFS+
filesystem. By using the xattr Python module from
http://undefined.org/python/ and the attached patch, rdiff-backup can
handle backing up these new attributes. The patch is against the CVS
version, but should work with 1.1.5.

Extended attributes can be backed-up between:
- Mac <-> Mac -- preserves all EAs on restore and in backup repository
- Mac <-> Unix -- preserves all EAs on restore and (some) in repository
- Unix <-> Unix -- preserves all EAs on restore in in repository

Why are only some preserved in the repository from Mac to Unix? The HFS+
Extended Attributes are more flexible than ext3 ones. Thus, if I backup
a Mac EA file to Unix, the file in the remote repository may be missing
some. However, rdiff-backup keeps all non-system (reserved) EAs in the
rdiff-backup-data dir so no EAs are ever lost, even when backing up Mac
to Unix.

I have tested this in all three cases above, but not with strict SELinux
 enabled on the Linux side. However, that should not cause any dataloss,
but may further hinder the repository from matching the source.

This also works if the backup repository does not have EAs enabled. In
that case, no EAs are set in the repository, but are still preserved on
restore.

Enjoy,

Andrew

PS - The new Mac OS X 10.4 ACL's, although implemented in HFS+ EAs,
cannot be backed-up in this way. Furthermore, they are not compatible
with the Linux/FreeBSD ACL's and the pylibacl module.

-- 
Andrew Ferguson - address@hidden

diff -Nur rdiff-backup-CVS/rdiff_backup/eas_acls.py 
rdiff-backup-LOCAL/rdiff_backup/eas_acls.py
--- rdiff-backup-CVS/rdiff_backup/eas_acls.py   2005-12-11 20:15:22.000000000 
-0500
+++ rdiff-backup-LOCAL/rdiff_backup/eas_acls.py 2006-04-29 16:01:21.000000000 
-0400
@@ -64,8 +64,11 @@
                                return
                        raise
                for attr in attr_list:
-                       if not attr.startswith('user.'):
-                               # Only preserve user extended attributes
+                       if attr.startswith('system.'):
+                               # Do not preserve system extended attributes
+                               continue
+                       if attr == 'com.apple.FinderInfo' or attr == 
'come.apple.ResourceFork':
+                               # FinderInfo and Resource Fork handled elsewhere
                                continue
                        try: self.attr_dict[attr] = 
rp.conn.xattr.getxattr(rp.path, attr)
                        except IOError, exc:
@@ -92,7 +95,14 @@
                """Write extended attributes to rpath rp"""
                self.clear_rp(rp)
                for (name, value) in self.attr_dict.iteritems():
-                       rp.conn.xattr.setxattr(rp.path, name, value)
+                       try:
+                               rp.conn.xattr.setxattr(rp.path, name, value)
+                       except IOError, exc:
+                               # Mac and Linux attributes have different 
namespaces, so
+                               # fail gracefully if can't call setxattr
+                               if exc[0] == errno.EOPNOTSUPP or exc[0] == 
errno.EACCES:
+                                       continue
+                               else: raise
 
        def get(self, name):
                """Return attribute attached to given name"""
diff -Nur rdiff-backup-CVS/rdiff_backup/rpath.py 
rdiff-backup-LOCAL/rdiff_backup/rpath.py
--- rdiff-backup-CVS/rdiff_backup/rpath.py      2006-01-13 00:29:47.000000000 
-0500
+++ rdiff-backup-LOCAL/rdiff_backup/rpath.py    2006-04-29 15:57:30.000000000 
-0400
@@ -160,13 +160,13 @@
        if Globals.change_ownership:
                rpout.chown(*rpout.conn.user_group.map_rpath(rpin))
        if rpin.issym(): return # symlinks don't have times or perms
+       if Globals.eas_write: rpout.write_ea(rpin.get_ea())
        if (Globals.resource_forks_write and rpin.isreg() and
                rpin.has_resource_fork()):
                rpout.write_resource_fork(rpin.get_resource_fork())
        if (Globals.carbonfile_write and rpin.isreg() and
                rpin.has_carbonfile()):
                rpout.write_carbonfile(rpin.get_carbonfile())
-       if Globals.eas_write: rpout.write_ea(rpin.get_ea())
        rpout.chmod(rpin.getperms())
        if Globals.acls_write: rpout.write_acl(rpin.get_acl())
        if not rpin.isdev(): rpout.setmtime(rpin.getmtime())
@@ -183,13 +183,13 @@
        check_for_files(rpin, rpout)
        if Globals.change_ownership: apply(rpout.chown, rpin.getuidgid())
        if rpin.issym(): return # symlinks don't have times or perms
+       if Globals.eas_write: rpout.write_ea(rpin.get_ea())
        if (Globals.resource_forks_write and rpin.isreg() and
                rpin.has_resource_fork() and rpout.isreg()):
                rpout.write_resource_fork(rpin.get_resource_fork())
        if (Globals.carbonfile_write and rpin.isreg() and
                rpin.has_carbonfile() and rpout.isreg()):
                rpout.write_carbonfile(rpin.get_carbonfile())
-       if Globals.eas_write: rpout.write_ea(rpin.get_ea())
        if rpin.isdir() and not rpout.isdir():
                rpout.chmod(rpin.getperms() & 0777)
        else: rpout.chmod(rpin.getperms())

reply via email to

[Prev in Thread] Current Thread [Next in Thread]