summaryrefslogtreecommitdiffstats
path: root/bin
diff options
context:
space:
mode:
authorZac Medico <zmedico@gentoo.org>2012-12-11 01:00:25 -0800
committerZac Medico <zmedico@gentoo.org>2012-12-11 01:01:03 -0800
commit3464e5ace3ef520344a330601e0aac69bcdef222 (patch)
tree52400017002b8cf1016ca0b7dafb7759ecdff194 /bin
parentd08f5efd56c19afab3e4538baf91fe4d6d7ecb1b (diff)
downloadportage-3464e5ace3ef520344a330601e0aac69bcdef222.tar.gz
portage-3464e5ace3ef520344a330601e0aac69bcdef222.tar.bz2
portage-3464e5ace3ef520344a330601e0aac69bcdef222.zip
prepstrip: preserve xattrs, bug #446420
Diffstat (limited to 'bin')
-rwxr-xr-xbin/ebuild-helpers/prepstrip36
-rwxr-xr-xbin/xattr-helper.py173
2 files changed, 206 insertions, 3 deletions
diff --git a/bin/ebuild-helpers/prepstrip b/bin/ebuild-helpers/prepstrip
index 6a09ff457..fb20777e8 100755
--- a/bin/ebuild-helpers/prepstrip
+++ b/bin/ebuild-helpers/prepstrip
@@ -15,7 +15,7 @@ exp_tf() {
eval ${var}_${flag}=$(tf has ${flag} ${!var})
done
}
-exp_tf FEATURES compressdebug installsources nostrip splitdebug
+exp_tf FEATURES compressdebug installsources nostrip splitdebug xattr
exp_tf RESTRICT binchecks installsources strip
if ! ___eapi_has_prefix_variables; then
@@ -30,6 +30,28 @@ if ${RESTRICT_strip} || ${FEATURES_nostrip} ; then
${FEATURES_installsources} || exit 0
fi
+PRESERVE_XATTR=false
+if [[ ${KERNEL} == linux ]] && ${FEATURES_xattr} ; then
+ PRESERVE_XATTR=true
+ if type -P getfattr >/dev/null && type -P setfattr >/dev/null ; then
+ dump_xattrs() {
+ getfattr -d --absolute-names "$1"
+ }
+ restore_xattrs() {
+ setfattr --restore=-
+ }
+ else
+ dump_xattrs() {
+ "${PORTAGE_PYTHON:-/usr/bin/python}" \
+ "${PORTAGE_BIN_PATH}/xattr-helper.py" --dump < <(echo -n "$1")
+ }
+ restore_xattrs() {
+ "${PORTAGE_PYTHON:-/usr/bin/python}" \
+ "${PORTAGE_BIN_PATH}/xattr-helper.py" --restore
+ }
+ fi
+fi
+
# look up the tools we might be using
for t in STRIP:strip OBJCOPY:objcopy READELF:readelf ; do
v=${t%:*} # STRIP
@@ -152,7 +174,7 @@ save_elf_debug() {
# Usage: process_elf <elf>
process_elf() {
local x=$1 inode_link=$2 strip_flags=${*:3}
- local already_stripped lockfile
+ local already_stripped lockfile xt_data
__vecho " ${x:${#ED}}"
@@ -171,7 +193,12 @@ process_elf() {
[ -f "${inode_link}_stripped" ] && already_stripped=true || already_stripped=false
- ${already_stripped} || save_elf_sources "${x}"
+ if ! ${already_stripped} ; then
+ if ${PRESERVE_XATTR} ; then
+ xt_data=$(dump_xattrs "${x}")
+ fi
+ save_elf_sources "${x}"
+ fi
if ${strip_this} ; then
@@ -197,6 +224,9 @@ process_elf() {
ln "${inode_link}_stripped" "${x}" || die "ln failed unexpectedly"
else
ln "${x}" "${inode_link}_stripped" || die "ln failed unexpectedly"
+ if [[ ${xt_data} ]] ; then
+ restore_xattrs <<< "${xt_data}"
+ fi
fi
[[ -n ${lockfile} ]] && rm -f "${lockfile}"
diff --git a/bin/xattr-helper.py b/bin/xattr-helper.py
new file mode 100755
index 000000000..d40217c9a
--- /dev/null
+++ b/bin/xattr-helper.py
@@ -0,0 +1,173 @@
+#!/usr/bin/python
+# Copyright 2012 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+import array
+import optparse
+import os
+import re
+import sys
+
+if hasattr(os, "getxattr"):
+
+ class xattr(object):
+ get = os.getxattr
+ set = os.setxattr
+ list = os.listxattr
+
+else:
+ import xattr
+
+_unquote_re = re.compile(br'\\[0-7]{3}')
+_fs_encoding = sys.getfilesystemencoding()
+
+if sys.hexversion < 0x3000000:
+
+ def octal_quote_byte(b):
+ return b'\\%03o' % ord(b)
+
+ def unicode_encode(s):
+ if isinstance(s, unicode):
+ s = s.encode(_fs_encoding)
+ return s
+else:
+
+ def octal_quote_byte(b):
+ return ('\\%03o' % ord(b)).encode('ascii')
+
+ def unicode_encode(s):
+ if isinstance(s, str):
+ s = s.encode(_fs_encoding)
+ return s
+
+def quote(s, quote_chars):
+
+ quote_re = re.compile(b'[' + quote_chars + b']')
+ result = []
+ pos = 0
+ s_len = len(s)
+
+ while pos < s_len:
+ m = quote_re.search(s, pos=pos)
+ if m is None:
+ result.append(s[pos:])
+ pos = s_len
+ else:
+ start = m.start()
+ result.append(s[pos:start])
+ result.append(octal_quote_byte(s[start:start+1]))
+ pos = start + 1
+
+ return b"".join(result)
+
+def unquote(s):
+
+ result = []
+ pos = 0
+ s_len = len(s)
+
+ while pos < s_len:
+ m = _unquote_re.search(s, pos=pos)
+ if m is None:
+ result.append(s[pos:])
+ pos = s_len
+ else:
+ start = m.start()
+ result.append(s[pos:start])
+ pos = start + 4
+ a = array.array('B')
+ a.append(int(s[start + 1:pos], 8))
+ try:
+ # Python >= 3.2
+ result.append(a.tobytes())
+ except AttributeError:
+ result.append(a.tostring())
+
+ return b"".join(result)
+
+def dump_xattrs(file_in, file_out):
+
+ for pathname in file_in.read().split(b'\0'):
+ if not pathname:
+ continue
+
+ attrs = xattr.list(pathname)
+ if not attrs:
+ continue
+ file_out.write(b'# file: ' + quote(pathname, b'\n\r') + b'\n')
+ for attr in attrs:
+ attr = unicode_encode(attr)
+ file_out.write(quote(attr, b'=\n\r') + b'="' +
+ quote(xattr.get(pathname, attr), b'\\\0\n\r"') + b'"\n')
+
+def restore_xattrs(file_in):
+
+ pathname = None
+ for i, line in enumerate(file_in):
+ if line.startswith(b'# file: '):
+ pathname = unquote(line.rstrip(b'\n')[8:])
+ else:
+ parts = line.split(b'=', 1)
+ if len(parts) == 2:
+ if pathname is None:
+ raise AssertionError('line %d: missing pathname' % i + 1)
+ attr = unquote(parts[0])
+ # strip trailing newline and quotes
+ value = unquote(parts[1].rstrip(b'\n')[1:-1])
+ xattr.set(pathname, attr, value)
+ elif line.strip():
+ raise AssertionError("line %d: malformed entry" % i + 1)
+
+def main(argv):
+
+ description = "Dump and restore extended attributes," \
+ " using format like that used by getfattr --dump."
+ usage = "usage: %s [--dump | --restore]\n" % \
+ os.path.basename(argv[0])
+
+ parser = optparse.OptionParser(description=description, usage=usage)
+
+ actions = optparse.OptionGroup(parser, 'Actions')
+ actions.add_option("--dump",
+ action="store_true",
+ help="Dump the values of all extended "
+ "attributes associated with null-separated"
+ " paths read from stdin.")
+ actions.add_option("--restore",
+ action="store_true",
+ help="Restore extended attributes using"
+ " a dump read from stdin.")
+ parser.add_option_group(actions)
+
+ options, args = parser.parse_args(argv[1:])
+
+ if len(args) != 0:
+ parser.error("expected zero arguments, "
+ "got %s" % len(args))
+
+ if sys.hexversion >= 0x3000000:
+ file_in = sys.stdin.buffer.raw
+ else:
+ file_in = sys.stdin
+
+ if options.dump:
+
+ if sys.hexversion >= 0x3000000:
+ file_out = sys.stdout.buffer
+ else:
+ file_out = sys.stdout
+
+ dump_xattrs(file_in, file_out)
+
+ elif options.restore:
+
+ restore_xattrs(file_in)
+
+ else:
+ parser.error("available actions: --dump, --restore")
+
+ return os.EX_OK
+
+if __name__ == "__main__":
+ rval = main(sys.argv[:])
+ sys.exit(rval)