#!/bin/bash # Note that even sh-emulation mode of bash won't do here because # of "builtin < subshell" redirection - it has to be full-fledged /bin/bash ## Init skip= recurse= decrypt= encrypt= files=( ) errors=( ) ## Process $0 (ccat, ccdecrypt, ccencrypt) name="$(basename "$0")" case "$name" in ccencrypt) encrypt=true ;; ccdecrypt) decrypt=true ;; ccat) decrypt=cat ;; esac unset name ## Process command line like ccrypt woud've done for arg in "$@"; do case "$arg" in -k) skip=true ;; -K) skip=true ;; -r) recurse=true ;; -d) decrypt=true ;; -c) decrypt=cat ;; -e) encrypt=true ;; *) if [[ $skip ]]; then skip= continue fi files=( "${files[@]}" "$arg" ) ;; esac done unset skip ## Recursive expansion if [[ $recurse ]]; then recurse=( ) name=( ) [[ $decrypt ]] && name=( '-name' '*.cpt' ) [[ $encrypt ]] && name=( '!' '-name' '*.cpt' ) while read -u3 name do recurse=( "${recurse[@]}" "$name" ) done 3< <(find "${files[@]}" -type f "${name[@]}") files=( "${recurse[@]}" ) unset recurse name fi ## Actual per-file operation loop for file in "${files[@]}"; do # Some assumptions about file name and existance [[ ! -f "$file" && $decrypt ]] && file="${file}.cpt" if [[ ! -f "$file" ]]; then errors=( "${errors[@]}" "File does not exists: $file" ) continue fi # Try to auto-determine applicable operation if [[ -z $encrypt && -z $decrypt ]]; then [[ -z $encrypt && "${file##*.}" = cpt ]] && decrypt=true [[ -z $decrypt ]] && encrypt=true fi # ...and perform a sanity check if [[ $encrypt && $decrypt ]] || [[ ! $encrypt && ! $decrypt ]]; then errors=( "${errors[@]}" 'One of encrypt or decrypt should be specified' ) break fi # Perform the requested op if [[ $encrypt ]] then # encryption dst="${file}.cpt" if [[ -e "$dst" ]]; then errors=( "${errors[@]}" "Destination path exists: $dst" ) continue fi if ! gpg --batch -q -e -r "$EMAIL" <"$file" >"$dst"; then rm -f "$dst" errors=( "${errors[@]}" "GnuPG failure on file encryption: $file (for: $EMAIL)" ) continue fi shred -u "$file" else # decryption if [[ $decrypt != cat && "$file" = "${file%.cpt}" ]] then # special case: explicitly specified file exists, but doesn't have ".cpt" tmp="$(mktemp "${file}.tmp.XXXXX")" if ! gpg --batch -q -d "$file" >"$tmp"; then rm -f "$tmp" errors=( "${errors[@]}" "GnuPG failure on file decryption: $file" ) continue fi mv "$tmp" "$file" else # normal file.cpt -> file operation or ccat if [[ $decrypt = cat ]] then dst= gpg --batch -q -d "$file" else dst="${file%.cpt}" if [[ -e "$dst" ]]; then errors=( "${errors[@]}" "Destination path exists: $dst" ) continue fi gpg --batch -q -d "$file" >"$dst" fi if [[ $? -gt 0 ]]; then [[ "$dst" ]] && rm -f "$dst" errors=( "${errors[@]}" "GnuPG failure on file decryption: $file" ) continue fi [[ "$dst" ]] && rm -f "$file" fi fi done ## Report errors, if any for error in "${errors[@]}"; do echo >&2 "ERROR: $error"; done exit ${#errors[@]}