summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLars Wirzenius <liw@liw.fi>2012-11-17 18:06:59 +0000
committerLars Wirzenius <liw@liw.fi>2012-11-17 18:06:59 +0000
commitc730d554a92cdf9e313006cff3fd227023fb848f (patch)
tree267681ea9cd58dc622e03e7d9a71b4f31183f8e7
parent4636212b3a1d8db5f7f8545a396145ffc59d9785 (diff)
parent5b0c891192ddeb8da579f83dfea8c5168597c8ba (diff)
downloadobnam-c730d554a92cdf9e313006cff3fd227023fb848f.tar.gz
Fix handling of value-less extended attributes
-rw-r--r--NEWS2
-rw-r--r--obnamlib/metadata.py30
-rw-r--r--obnamlib/vfs_local.py2
3 files changed, 32 insertions, 2 deletions
diff --git a/NEWS b/NEWS
index 178f3129..16750715 100644
--- a/NEWS
+++ b/NEWS
@@ -20,6 +20,8 @@ Bug fixes:
* Empty values for extended attributes are now backed up correctly.
Previously they would cause an infinite loop.
+* Extended attributes without values are now ignored. This is different
+ from attributes with empty values. Reported by Vladimir Elisseev.
* An empty port number in sftp URLs is now handled correctly. Found based
on report by Anton Shevtsov.
* A bad performance bug when backing up full systems (starting from the
diff --git a/obnamlib/metadata.py b/obnamlib/metadata.py
index be3a46c9..eaca40fb 100644
--- a/obnamlib/metadata.py
+++ b/obnamlib/metadata.py
@@ -14,11 +14,14 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
+import errno
import grp
+import logging
import os
import pwd
import stat
import struct
+import tracing
import obnamlib
@@ -127,10 +130,35 @@ def _cached_getgrgid(gid): # pragma: no cover
def get_xattrs_as_blob(fs, filename): # pragma: no cover
+ tracing.trace('filename=%s' % filename)
names = fs.llistxattr(filename)
+ tracing.trace('names=%s' % repr(names))
if not names:
return None
- values = [fs.lgetxattr(filename, name) for name in names]
+
+ values = []
+ for name in names[:]:
+ tracing.trace('trying name %s' % repr(name))
+ try:
+ value = fs.lgetxattr(filename, name)
+ except OSError, e:
+ # On btrfs, at least, this can happen: the filesystem returns
+ # a list of attribute names, but then fails when looking up
+ # the value for one or more of the names. We pretend that the
+ # name was never returned in that case.
+ #
+ # Obviously this can happen due to race conditions as well.
+ if e.errno == errno.ENODATA:
+ names.remove(name)
+ logging.warning(
+ '%s has extended attribute named %s without value, '
+ 'ignoring attribute' % (filename, name))
+ else:
+ raise
+ else:
+ tracing.trace('lgetxattr(%s)=%s' % (name, value))
+ values.append(value)
+ assert len(names) == len(values)
name_blob = ''.join('%s\0' % name for name in names)
diff --git a/obnamlib/vfs_local.py b/obnamlib/vfs_local.py
index e4b6b274..9b456f9f 100644
--- a/obnamlib/vfs_local.py
+++ b/obnamlib/vfs_local.py
@@ -168,7 +168,7 @@ class LocalFS(obnamlib.VirtualFileSystem):
def lgetxattr(self, filename, attrname): # pragma: no cover
ret = obnamlib._obnam.lgetxattr(self.join(filename), attrname)
if type(ret) is int:
- raise OSError((ret, os.strerror(ret), filename))
+ raise OSError(ret, os.strerror(ret), filename)
return ret
def lsetxattr(self, filename, attrname, attrvalue): # pragma: no cover