[xattr] Enhance error handling to catch ENOSPC

Fixes #5589
This commit is contained in:
Yen Chi Hsuan 2015-05-14 14:26:47 +08:00
parent 62bd6589c7
commit 86c7fdb17c

View File

@ -3,18 +3,32 @@
import os import os
import subprocess import subprocess
import sys import sys
import errno
from .common import PostProcessor from .common import PostProcessor
from ..compat import (
subprocess_check_output
)
from ..utils import ( from ..utils import (
check_executable, check_executable,
hyphenate_date, hyphenate_date,
version_tuple, version_tuple,
PostProcessingError,
encodeArgument,
encodeFilename,
) )
class XAttrMetadataError(PostProcessingError):
def __init__(self, code=None, msg='Unknown error'):
super(XAttrMetadataError, self).__init__(msg)
self.code = code
# Parsing code and msg
if (self.code in (errno.ENOSPC, errno.EDQUOT) or
'No space left' in self.msg or 'Disk quota excedded' in self.msg):
self.reason = 'NO_SPACE'
else:
self.reason = 'NOT_SUPPORTED'
class XAttrMetadataPP(PostProcessor): class XAttrMetadataPP(PostProcessor):
# #
@ -51,7 +65,10 @@ def run(self, info):
raise ImportError raise ImportError
def write_xattr(path, key, value): def write_xattr(path, key, value):
return xattr.setxattr(path, key, value) try:
xattr.set(path, key, value)
except EnvironmentError as e:
raise XAttrMetadataError(e.errno, e.strerror)
except ImportError: except ImportError:
if os.name == 'nt': if os.name == 'nt':
@ -62,8 +79,11 @@ def write_xattr(path, key, value):
assert os.path.exists(path) assert os.path.exists(path)
ads_fn = path + ":" + key ads_fn = path + ":" + key
with open(ads_fn, "wb") as f: try:
f.write(value) with open(ads_fn, "wb") as f:
f.write(value)
except EnvironmentError as e:
raise XAttrMetadataError(e.errno, e.strerror)
else: else:
user_has_setfattr = check_executable("setfattr", ['--version']) user_has_setfattr = check_executable("setfattr", ['--version'])
user_has_xattr = check_executable("xattr", ['-h']) user_has_xattr = check_executable("xattr", ['-h'])
@ -71,12 +91,24 @@ def write_xattr(path, key, value):
if user_has_setfattr or user_has_xattr: if user_has_setfattr or user_has_xattr:
def write_xattr(path, key, value): def write_xattr(path, key, value):
value = value.decode('utf-8')
if user_has_setfattr: if user_has_setfattr:
cmd = ['setfattr', '-n', key, '-v', value, path] executable = 'setfattr'
opts = ['-n', key, '-v', value]
elif user_has_xattr: elif user_has_xattr:
cmd = ['xattr', '-w', key, value, path] executable = 'xattr'
opts = ['-w', key, value]
subprocess_check_output(cmd) cmd = ([encodeFilename(executable, True)] +
[encodeArgument(o) for o in opts] +
[encodeFilename(path, True)])
p = subprocess.Popen(
cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)
stdout, stderr = p.communicate()
stderr = stderr.decode('utf-8', 'replace')
if p.returncode != 0:
raise XAttrMetadataError(p.returncode, stderr)
else: else:
# On Unix, and can't find pyxattr, setfattr, or xattr. # On Unix, and can't find pyxattr, setfattr, or xattr.
@ -121,6 +153,13 @@ def write_xattr(path, key, value):
return [], info return [], info
except (subprocess.CalledProcessError, OSError): except XAttrMetadataError as e:
self._downloader.report_error("This filesystem doesn't support extended attributes. (You may have to enable them in your /etc/fstab)") if e.reason == 'NO_SPACE':
self._downloader.report_warning(
'There\'s no disk space left or disk quota exceeded. ' +
'Extended attributes are not written.')
else:
self._downloader.report_error(
'This filesystem doesn\'t support extended attributes. ' +
'(You may have to enable them in your /etc/fstab)')
return [], info return [], info