From 62683eb4bf2bcf155c460113be09915f452e9ce6 Mon Sep 17 00:00:00 2001 From: Patrick Gartung Date: Wed, 4 Mar 2020 19:21:15 -0600 Subject: Add function replace_prefix_nullterm for use on mach-o rpaths. (#15347) This recovers the old behavior of replace_prefix_bin that was modified to work with elf binaries by prefixing os.sep to new prefix until length is the same as old prefix. --- lib/spack/spack/relocate.py | 37 ++++++++++++++++++++++++++++++++++--- 1 file changed, 34 insertions(+), 3 deletions(-) diff --git a/lib/spack/spack/relocate.py b/lib/spack/spack/relocate.py index fb4ff18fae..56fc993b5f 100644 --- a/lib/spack/spack/relocate.py +++ b/lib/spack/spack/relocate.py @@ -398,10 +398,43 @@ def replace_prefix_text(path_name, old_dir, new_dir): def replace_prefix_bin(path_name, old_dir, new_dir): + """ + Attempt to replace old install prefix with new install prefix + in binary files by prefixing new install prefix with os.sep + until the lengths of the prefixes are the same. + """ + + def replace(match): + occurances = match.group().count(old_dir.encode('utf-8')) + olen = len(old_dir.encode('utf-8')) + nlen = len(new_dir.encode('utf-8')) + padding = (olen - nlen) * occurances + if padding < 0: + return data + return match.group().replace(old_dir.encode('utf-8'), + new_dir.encode('utf-8')) + b'\0' * padding + + with open(path_name, 'rb+') as f: + data = f.read() + f.seek(0) + original_data_len = len(data) + pat = re.compile(old_dir.encode('utf-8') + b'([^\0]*?)\0') + if not pat.search(data): + return + ndata = pat.sub(replace, data) + if not len(ndata) == original_data_len: + raise BinaryStringReplacementException( + path_name, original_data_len, len(ndata)) + f.write(ndata) + f.truncate() + + +def replace_prefix_nullterm(path_name, old_dir, new_dir): """ Attempt to replace old install prefix with new install prefix in binary files by replacing with null terminated string that is the same length unless the old path is shorter + Used on linux to replace mach-o rpaths """ def replace(match): @@ -413,7 +446,6 @@ def replace_prefix_bin(path_name, old_dir, new_dir): return data return match.group().replace(old_dir.encode('utf-8'), new_dir.encode('utf-8')) + b'\0' * padding - with open(path_name, 'rb+') as f: data = f.read() f.seek(0) @@ -466,8 +498,7 @@ def relocate_macho_binaries(path_names, old_dir, new_dir, allow_root): modify_object_macholib(path_name, placeholder, new_dir) modify_object_macholib(path_name, old_dir, new_dir) if len(new_dir) <= len(old_dir): - replace_prefix_bin(path_name, old_dir, - new_dir) + replace_prefix_nullterm(path_name, old_dir, new_dir) else: tty.warn('Cannot do a binary string replacement' ' with padding for %s' -- cgit v1.2.3-60-g2f50