From a750aa29c29ba60b3d848c56482059c556374fa6 Mon Sep 17 00:00:00 2001 From: Lars Wirzenius Date: Wed, 23 May 2012 12:15:56 +0200 Subject: Add xattrs support --- summain | 2 +- summainlib.py | 23 ++++++++++++++++++++++- summainlib_tests.py | 6 ++++-- tests/xattrs.script | 10 ++++++++++ tests/xattrs.stdout | 8 ++++++++ 5 files changed, 45 insertions(+), 4 deletions(-) create mode 100755 tests/xattrs.script create mode 100644 tests/xattrs.stdout diff --git a/summain b/summain index 55bb855..278eca8 100755 --- a/summain +++ b/summain @@ -27,7 +27,7 @@ import summainlib class OutputFormat(object): keys = ['Mtime', 'Mode', 'Ino', 'Dev', 'Nlink', 'Size', - 'Uid', 'Username', 'Gid', 'Group', 'Target'] + 'Uid', 'Username', 'Gid', 'Group', 'Target', 'Xattrs'] def __init__(self, output, checksums, objects): self.output = output diff --git a/summainlib.py b/summainlib.py index 784efe5..93d3737 100644 --- a/summainlib.py +++ b/summainlib.py @@ -136,7 +136,8 @@ class FilesystemObject(object): def __init__(self, filename, nn, pn, exclude, stat_result=None, sha1=None, sha224=None, sha256=None, sha384=None, sha512=None, - md5=None, open_file=None, readlink=None): + md5=None, open_file=None, readlink=None, + xattrs=None): self.filename = filename self.relative = None self._exclude = set(self._normalize_key(k) for k in exclude) @@ -149,6 +150,8 @@ class FilesystemObject(object): self._sha384 = sha384 or hashlib.sha384() self._sha512 = sha512 or hashlib.sha512() self._stat_result = stat_result or _summain.lstat(filename) + self._xattrs = (xattrs if xattrs is not None + else self.get_xattrs(filename)) self.open_file = open_file or file self.readlink = readlink or os.readlink self.values = dict() @@ -214,6 +217,12 @@ class FilesystemObject(object): if stat.S_ISLNK(self._stat_result[RESULT_MODE]): return self.readlink(self.filename) + def _compute_xattrs(self): # pragma: no cover + if len(self._xattrs) == 0: + return '' + parts = [' %s=%s' % (k, self._xattrs[k]) for k in self._xattrs] + return '\n' + '\n'.join(parts) + def format_time(self, secs, nsecs): s = time.strftime('%Y-%m-%d %H:%M:%S', time.gmtime(secs)) s += '.%09d' % nsecs @@ -261,3 +270,15 @@ class FilesystemObject(object): '''Is this a directory?''' return stat.S_ISDIR(int(self['Mode'], 8)) + def get_xattrs(self, filename): # pragma: no cover + ret = _summain.llistxattr(filename) + if type(ret) is int: + raise OSError((ret, os.strerror(ret), filename)) + + names = [s for s in ret.split('\0') if s] + + xattrs = {} + for name in names: + xattrs[name] = _summain.lgetxattr(filename, name) + return xattrs + diff --git a/summainlib_tests.py b/summainlib_tests.py index f8bcc27..e2a3c0f 100644 --- a/summainlib_tests.py +++ b/summainlib_tests.py @@ -95,7 +95,8 @@ class FilesystemObjectTests(unittest.TestCase): sha512=FakeChecksummer(), md5=FakeChecksummer(), open_file=FakeOpenFile(), - readlink=FakeReadlink(self)) + readlink=FakeReadlink(self), + xattrs={}) def test_raises_keyerror_for_unknown_field(self): self.assertRaises(KeyError, self.new('foo').__getitem__, @@ -207,7 +208,8 @@ class FilesystemObjectNormalizedNumbersTests(unittest.TestCase): sha512=FakeChecksummer(), md5=FakeChecksummer(), open_file=FakeOpenFile(), - readlink=FakeReadlink(self)) + readlink=FakeReadlink(self), + xattrs={}) def test_inode_numbers_are_repeatable(self): a1 = self.new('foo') diff --git a/tests/xattrs.script b/tests/xattrs.script new file mode 100755 index 0000000..383cf6e --- /dev/null +++ b/tests/xattrs.script @@ -0,0 +1,10 @@ +#!/bin/sh + +set -e + +mkdir -m 0775 "$DATADIR/xattrs" +touch "$DATADIR/xattrs/file" +setfattr -n user.foo -v bar "$DATADIR/xattrs/file" +./summain --exclude=mtime --exclude=uid --exclude=username \ + --exclude=gid --exclude=group --exclude=ino --exclude=dev \ + --exclude=nlink --exclude=size --exclude=sha1 --relative "$DATADIR/xattrs" diff --git a/tests/xattrs.stdout b/tests/xattrs.stdout new file mode 100644 index 0000000..60984f8 --- /dev/null +++ b/tests/xattrs.stdout @@ -0,0 +1,8 @@ +Name: . +Mode: 40775 + +Name: file +Mode: 100664 +Xattrs: + user.foo=bar + -- cgit v1.2.1