From 8bf3bb1ca3630005c29929c0219d1c1b420714bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Borgstr=C3=B6m?= Date: Tue, 8 Apr 2014 21:52:26 +0200 Subject: [PATCH] Added support for backup and restore of bsdflags (OS X and FreeBSD) This improves our Backup-Bouncer score (#56) --- attic/archive.py | 9 +++++++++ attic/testsuite/__init__.py | 4 ++++ attic/testsuite/archiver.py | 4 ++++ 3 files changed, 17 insertions(+) diff --git a/attic/archive.py b/attic/archive.py index 862af7f2b..f3bbc4468 100644 --- a/attic/archive.py +++ b/attic/archive.py @@ -27,6 +27,7 @@ CHUNK_MASK = 0xffff utime_supports_fd = os.utime in getattr(os, 'supports_fd', {}) has_mtime_ns = sys.version >= '3.3' has_lchmod = hasattr(os, 'lchmod') +has_lchflags = hasattr(os, 'lchflags') class DownloadPipeline: @@ -315,6 +316,12 @@ class Archive: os.utime(path, None, ns=(item[b'mtime'], item[b'mtime']), follow_symlinks=False) elif not symlink: os.utime(path, (item[b'mtime'] / 10**9, item[b'mtime'] / 10**9)) + # Only available on OS X and FreeBSD + if has_lchflags and b'bsdflags' in item: + try: + os.lchflags(path, item[b'bsdflags']) + except OSError: + pass def delete(self, stats): unpacker = msgpack.Unpacker(use_list=False) @@ -341,6 +348,8 @@ class Archive: xattrs = xattr.get_all(path, follow_symlinks=False) if xattrs: item[b'xattrs'] = StableDict(xattrs) + if has_lchflags and st.st_flags: + item[b'bsdflags'] = st.st_flags return item def process_item(self, path, st): diff --git a/attic/testsuite/__init__.py b/attic/testsuite/__init__.py index b26e5ffd1..bdecaa989 100644 --- a/attic/testsuite/__init__.py +++ b/attic/testsuite/__init__.py @@ -15,6 +15,8 @@ try: except ImportError: have_fuse_mtime_ns = False +has_lchflags = hasattr(os, 'lchflags') + # The mtime get/set precison varies on different OS and Python versions if 'HAVE_FUTIMENS' in getattr(posix, '_have_functions', []): @@ -56,6 +58,8 @@ class AtticTestCase(unittest.TestCase): # Assume path2 is on FUSE if st_dev is different fuse = s1.st_dev != s2.st_dev attrs = ['st_mode', 'st_uid', 'st_gid', 'st_rdev'] + if has_lchflags: + attrs.append('st_flags') if not fuse or not os.path.isdir(path1): # dir nlink is always 1 on our fuse fileystem attrs.append('st_nlink') diff --git a/attic/testsuite/archiver.py b/attic/testsuite/archiver.py index 415b0e530..cdd39c797 100644 --- a/attic/testsuite/archiver.py +++ b/attic/testsuite/archiver.py @@ -24,6 +24,8 @@ try: except ImportError: has_llfuse = False +has_lchflags = hasattr(os, 'lchflags') + src_dir = os.path.join(os.getcwd(), os.path.dirname(__file__), '..') @@ -138,6 +140,8 @@ class ArchiverTestCase(ArchiverTestCaseBase): xattr.setxattr(os.path.join(self.input_path, 'link1'), 'user.foo_symlink', b'bar_symlink', follow_symlinks=False) # FIFO node os.mkfifo(os.path.join(self.input_path, 'fifo1')) + if has_lchflags: + os.lchflags(os.path.join(self.input_path, 'file1'), stat.UF_NODUMP) def test_basic_functionality(self): self.create_test_files()