#!/bin/bash # Copyright 1999-2013 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 source "${PORTAGE_BIN_PATH:-/usr/lib/portage/bin}"/isolated-functions.sh __getxattrs() { # Global variables. # # Note the mapping between file, namespace, xattr value is as follows. # Suppose our array of source files looks like: # # ${__source_files[@]}=( 'aaa', 'bbb', 'ccc', 'ddd' ) # # Since 'aaa' is at index 0, its xattr names and values look like # # ${__xattr_names_0_['n1']}='v1' # ${__xattr_names_0_['n2']}='v2' # ... # # and similarly for bbb, ccc and ddd, with _0_ replaced by _1_, _2_ and _3_. # __source_files=() __target="" __target_is_directory="no" local arg args=() local ignored_flags=( "-b" "--backup" "-c" "-C" "--compare" "-D" "-o" "--owner" "-g" "--group" "-m" "--mode" "-p" "--preserve-timestamps" "-s" "--strip" "--strip-program" "-S" "--suffix" "-T" "--no-target-directory" "-Z" "--context" "--preserve-context" "-v" "--verbose" "--help" "--version" ) local skip="no" for arg in "$@"; do # Nothing to do if the -d/--directory flag is given # Zero what we've already gotten and return if [[ "$arg" == -d || "$arg" == --directory ]]; then __source_files=() __target="" __target_is_directory="no" return 0 fi # We may be asked to skip this argument because we know it is # the target directory --- see where we set skip="yes" below if [[ "$skip" == "yes" ]]; then skip="no" __target="$arg" fi # Skip flags that we don't need to parse out source/destination local ignore="no" for flag in "${ignored_flags[@]}"; do if [[ "$arg" == "$flag"* ]]; then ignore="yes" break fi done [[ "$ignore" == "yes" ]] && continue # If the --target-directory= flag is given then the target is a diretory # Note: there can be no space before or after the = if [[ "$arg" == --target-directory=* ]] ; then __target_is_directory="yes" $__target="${arg/--target-directory=/}" fi # If the -t flag is given then the target is a diretory if [[ "$arg" == -t* ]]; then __target_is_directory="yes" # There may be zero or more spaces between -t and the target directory. If # there is one or more, then we'll get the target directory on the next iteration. if [[ -z "${arg/-t/}" ]]; then skip="yes" continue else __target="${arg#-t}" fi fi __source_files+=( "$arg" ) done # If we haven't found a target yet, then the last in the remaining list is the target if [[ -z "$__target" ]]; then local last="${#__source_files[@]}" (( last -= 1 )) __target="${__source_files[$last]}" unset __source_files[$last] # Is the target a directory? [[ -d $__target ]] && __target_is_directory="yes" fi local file local index=0 for file in "${__source_files[@]}"; do local narray="__xattr_names_${index}_" (( index++ )) # Note: attr only get/sets the user.* namespace! # This is exactly what we want to protect security.* trusted.* local names=$(attr -ql ${file}) for name in $names; do value=$(attr -qg $name $file) eval "${narray}[\"$name\"]=$value" done done return 0 } __setxattrs() { local file if [[ "$__target_is_directory" == "no" ]]; then # No need to loop over one source file! for name in "${!__xattr_names_0_[@]}"; do attr -q -s $name -V ${__xattr_names_0_[$name]} $__target done else local index=0 for file in "${__source_files[@]}"; do local f=${file##*/} local narray="__xattr_names_${index}_" (( index++ )) eval "for name in "\${!${narray}[@]}"; do attr -q -s \$name -V \${${narray}[\$name]} ${__target}/${f} ; done" done fi } if [[ -x /bin/attr ]]; then # We need to declare all the associative arrays we'll use globally # We can't possibly need more than there are parameters -- overkill! index=0 for i in "$@"; do narray="__xattr_names_${index}_" (( index++ )) eval "declare -A ${narray}" done __getxattrs "$@" fi # Use the full path to the real install to avoid calling ourselves /usr/bin/install "$@" if [[ -x /bin/attr ]]; then __setxattrs fi