commit:     1032cbf4c218741df1c57767fead2d00cc6321d9
Author:     Zac Medico <zmedico <AT> gentoo <DOT> org>
AuthorDate: Sat May 23 05:53:26 2015 +0000
Commit:     Zac Medico <zmedico <AT> gentoo <DOT> org>
CommitDate: Tue May 26 19:07:20 2015 +0000
URL:        https://gitweb.gentoo.org/proj/portage.git/commit/?id=1032cbf4

quickpkg: support FEATURES=xattr (bug 550006)

The xattrs are preserved in pax headers, in the same way that GNU tar
preserves them.

X-Gentoo-Bug: 550006
X-Gentoo-Bug-url: https://bugs.gentoo.org/show_bug.cgi?id=550006
Acked-by: Brian Dolbec <dolsen <AT> gentoo.org>

 bin/quickpkg                 | 16 ++++++++++++++--
 pym/portage/dbapi/vartree.py | 18 +++++++++++++++---
 pym/portage/util/xattr.py    | 20 ++++++++++++++++++++
 3 files changed, 49 insertions(+), 5 deletions(-)

diff --git a/bin/quickpkg b/bin/quickpkg
index 8b71c3e..726abff 100755
--- a/bin/quickpkg
+++ b/bin/quickpkg
@@ -22,6 +22,7 @@ from portage.dep import Atom, use_reduce
 from portage.exception import (AmbiguousPackageName, InvalidAtom, InvalidData,
        InvalidDependString, PackageSetNotFound, PermissionDenied)
 from portage.util import ConfigProtect, ensure_dirs, shlex_split
+import portage.util.xattr as _xattr
 from portage.dbapi.vartree import dblink, tar_contents
 from portage.checksum import perform_md5
 from portage._sets import load_default_config, SETPREFIX
@@ -35,6 +36,7 @@ def quickpkg_atom(options, infos, arg, eout):
        vartree = trees["vartree"]
        vardb = vartree.dbapi
        bintree = trees["bintree"]
+       xattr = 'xattr' in settings.features
 
        include_config = options.include_config == "y"
        include_unmodified_config = options.include_unmodified_config == "y"
@@ -132,8 +134,11 @@ def quickpkg_atom(options, infos, arg, eout):
                        binpkg_tmpfile = os.path.join(bintree.pkgdir,
                                cpv + ".tbz2." + str(os.getpid()))
                        ensure_dirs(os.path.dirname(binpkg_tmpfile))
-                       tar = tarfile.open(binpkg_tmpfile, "w:bz2")
-                       tar_contents(contents, root, tar, protect=protect)
+                       # The tarfile module will write pax headers holding the
+                       # xattrs only if PAX_FORMAT is specified here.
+                       tar = tarfile.open(binpkg_tmpfile, "w:bz2",
+                               format=tarfile.PAX_FORMAT if xattr else 
tarfile.DEFAULT_FORMAT)
+                       tar_contents(contents, root, tar, protect=protect, 
xattr=xattr)
                        tar.close()
                        xpak.tbz2(binpkg_tmpfile).recompose_mem(xpdata)
                finally:
@@ -233,6 +238,13 @@ def quickpkg_main(options, args, eout):
                eout.eerror("No write access to '%s'" % bintree.pkgdir)
                return errno.EACCES
 
+       if 'xattr' in portage.settings.features and not hasattr(_xattr, 
'getxattr'):
+               eout.eerror("No xattr support library was found, "
+                       "so xattrs will not be preserved!")
+               portage.settings.unlock()
+               portage.settings.features.remove('xattr')
+               portage.settings.lock()
+
        infos = {}
        infos["successes"] = []
        infos["missing"] = []

diff --git a/pym/portage/dbapi/vartree.py b/pym/portage/dbapi/vartree.py
index a2fb325..62d880e 100644
--- a/pym/portage/dbapi/vartree.py
+++ b/pym/portage/dbapi/vartree.py
@@ -35,6 +35,7 @@ portage.proxy.lazyimport.lazyimport(globals(),
        'portage.util.movefile:movefile',
        'portage.util.path:first_existing,iter_parents',
        'portage.util.writeable_check:get_ro_checker',
+       'portage.util:xattr@_xattr',
        'portage.util._dyn_libs.PreservedLibsRegistry:PreservedLibsRegistry',
        'portage.util._dyn_libs.LinkageMapELF:LinkageMapELF@LinkageMap',
        'portage.util._async.SchedulerInterface:SchedulerInterface',
@@ -5266,7 +5267,8 @@ def write_contents(contents, root, f):
                        line = "%s %s\n" % (entry_type, relative_filename)
                f.write(line)
 
-def tar_contents(contents, root, tar, protect=None, onProgress=None):
+def tar_contents(contents, root, tar, protect=None, onProgress=None,
+       xattr=False):
        os = _os_merge
        encoding = _encodings['merge']
 
@@ -5384,9 +5386,19 @@ def tar_contents(contents, root, tar, protect=None, 
onProgress=None):
                                tar.addfile(tarinfo, f)
                                f.close()
                        else:
-                               with open(_unicode_encode(path,
+                               path_bytes = _unicode_encode(path,
                                        encoding=encoding,
-                                       errors='strict'), 'rb') as f:
+                                       errors='strict')
+
+                               if xattr:
+                                       # Compatible with GNU tar, which saves 
the xattrs
+                                       # under the SCHILY.xattr namespace.
+                                       for k in _xattr.listxattr(path_bytes):
+                                               
tarinfo.pax_headers['SCHILY.xattr.' +
+                                                       _unicode_decode(k)] = 
_unicode_decode(
+                                                       
_xattr.getxattr(path_bytes, _unicode_encode(k)))
+
+                               with open(path_bytes, 'rb') as f:
                                        tar.addfile(tarinfo, f)
 
                else:

diff --git a/pym/portage/util/xattr.py b/pym/portage/util/xattr.py
new file mode 100644
index 0000000..b8c4620
--- /dev/null
+++ b/pym/portage/util/xattr.py
@@ -0,0 +1,20 @@
+# Copyright 2015 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from __future__ import absolute_import
+
+import os as _os
+
+if hasattr(_os, "getxattr"):
+       getxattr = _os.getxattr
+       listxattr = _os.listxattr
+       setxattr = _os.setxattr
+else:
+       try:
+               import xattr as _xattr
+       except ImportError:
+               pass
+       else:
+               getxattr = _xattr.get
+               listxattr = _xattr.list
+               setxattr = _xattr.set

Reply via email to