1
0
Fork 0
mirror of https://github.com/borgbackup/borg.git synced 2025-01-25 00:38:58 +00:00

Added xattr support

This commit is contained in:
Jonas Borgström 2010-10-31 20:31:56 +01:00
parent 68bd3d3e3d
commit fe663e3232
2 changed files with 35 additions and 9 deletions

View file

@ -5,6 +5,7 @@
import socket
import stat
import sys
from xattr import xattr, XATTR_NOFOLLOW
from . import NS_ARCHIVE_METADATA, NS_ARCHIVE_ITEMS, NS_ARCHIVE_CHUNKS, NS_CHUNK
from .chunkifier import chunkify
@ -144,6 +145,13 @@ def extract_item(self, item, dest=None):
raise Exception('Unknown archive item type %r' % item['mode'])
def restore_attrs(self, path, item, symlink=False):
if item['xattrs']:
try:
xa = xattr(path, XATTR_NOFOLLOW)
for k, v in item['xattrs'].items():
xa.set(k, v)
except IOError:
pass
if have_lchmod:
os.lchmod(path, item['mode'])
elif not symlink:
@ -179,28 +187,33 @@ def delete(self, cache):
self.store.commit()
cache.save()
def stat_attrs(self, st):
def stat_attrs(self, st, path):
try:
xattrs = dict(xattr(path, XATTR_NOFOLLOW))
except IOError:
xattrs = None
return {
'mode': st.st_mode,
'uid': st.st_uid, 'user': uid2user(st.st_uid),
'gid': st.st_gid, 'group': gid2group(st.st_gid),
'atime': st.st_atime, 'mtime': st.st_mtime,
'xattrs': xattrs,
}
def process_dir(self, path, st):
item = {'path': path.lstrip('/\\:')}
item.update(self.stat_attrs(st))
item.update(self.stat_attrs(st, path))
self.items.append(item)
def process_fifo(self, path, st):
item = {'path': path.lstrip('/\\:')}
item.update(self.stat_attrs(st))
item.update(self.stat_attrs(st, path))
self.items.append(item)
def process_symlink(self, path, st):
source = os.readlink(path)
item = {'path': path.lstrip('/\\:'), 'source': source}
item.update(self.stat_attrs(st))
item.update(self.stat_attrs(st, path))
self.items.append(item)
def process_file(self, path, st, cache):
@ -240,7 +253,7 @@ def process_file(self, path, st, cache):
size += len(chunk)
cache.memorize_file_chunks(path_hash, st, ids)
item = {'path': safe_path, 'chunks': chunks, 'size': size}
item.update(self.stat_attrs(st))
item.update(self.stat_attrs(st, path))
self.items.append(item)
def process_chunk2(self, id, cache):

View file

@ -6,6 +6,7 @@
import shutil
import tempfile
import unittest
from xattr import xattr, XATTR_NOFOLLOW
from . import store
from .archiver import Archiver
@ -57,25 +58,37 @@ def create_regual_file(self, name, size=0):
with open(filename, 'wb') as fd:
fd.write('X' * size)
def get_xattrs(self, path):
try:
return dict(xattr(path, XATTR_NOFOLLOW))
except IOError:
return {}
def diff_dirs(self, dir1, dir2):
diff = filecmp.dircmp(dir1, dir2)
self.assertEqual(diff.left_only, [])
self.assertEqual(diff.right_only, [])
self.assertEqual(diff.diff_files, [])
for filename in diff.common:
s1 = os.lstat(os.path.join(dir1, filename))
s2 = os.lstat(os.path.join(dir2, filename))
path1 = os.path.join(dir1, filename)
path2 = os.path.join(dir2, filename)
s1 = os.lstat(path1)
s2 = os.lstat(path2)
attrs = ['st_mode', 'st_uid', 'st_gid']
# We can't restore symlink atime/mtime right now
if not os.path.islink(os.path.join(dir1, filename)):
if not os.path.islink(path1):
attrs.append('st_mtime')
d1 = [filename] + [getattr(s1, a) for a in attrs]
d2 = [filename] + [getattr(s2, a) for a in attrs]
d1.append(self.get_xattrs(path1))
d2.append(self.get_xattrs(path2))
self.assertEqual(d1, d2)
def test_basic_functionality(self):
self.create_regual_file('file1', size=1024*80)
self.create_regual_file('dir2/file2', size=1024*80)
x = xattr(os.path.join(self.input_path, 'file1'))
x.set('user:foo', 'bar')
os.symlink('somewhere', os.path.join(self.input_path, 'link1'))
os.mkfifo(os.path.join(self.input_path, 'fifo1'))
self.darc('create', self.store_path + '::test', 'input')
@ -87,7 +100,7 @@ def test_corrupted_store(self):
self.create_src_archive('test')
self.darc('verify', self.store_path + '::test')
fd = open(os.path.join(self.tmpdir, 'store', 'bands', '0', '0'), 'r+')
fd.seek(1000)
fd.seek(100)
fd.write('X')
fd.close()
self.darc('verify', self.store_path + '::test', exit_code=1)