diff options
Diffstat (limited to 'pre-copy-rclone-hardlink.sh')
| -rwxr-xr-x | pre-copy-rclone-hardlink.sh | 80 |
1 files changed, 80 insertions, 0 deletions
diff --git a/pre-copy-rclone-hardlink.sh b/pre-copy-rclone-hardlink.sh new file mode 100755 index 0000000..01f7b6e --- /dev/null +++ b/pre-copy-rclone-hardlink.sh @@ -0,0 +1,80 @@ +#!/usr/bin/env bash +# +# Copyright 2023 David Vazgenovich Shakaryan + +qargs() { + local arg str= + + for arg; do + [[ "${arg:-*}" =~ [^A-Za-z0-9%+./:=@_-] ]] && arg="${arg@Q}" + str+=" ${arg}" + done + printf '%s\n' "${str:1}" +} + +temp_dest="${1}" +link_dest="${2}" +[[ -n "${link_dest}" ]] || exit 0 + +[[ "${temp_dest}" =~ ^(rclone://([^:]+):)(.+) ]] || exit 1 +prefix="${BASH_REMATCH[1]}" +remote="${BASH_REMATCH[2]}" +path="${BASH_REMATCH[3]}" +[[ "${link_dest}" == "${prefix}"* ]] || exit 1 +link="${link_dest#"${prefix}"}" + +conf="$(rclone config dump)" || exit 1 +read -rd '' JQ <<'EOF' +.[$k] +| select(.type == "crypt" or .type == "sftp") // error("not crypt or sftp") +| [.type, .remote] +| @tsv +EOF +IFS=$'\t' read -r r_type r_remote < <( + jq -rc --arg k "${remote}" "${JQ}" <<<"${conf}") || exit 1 + +if [[ "${r_type}" == 'crypt' ]]; then + crypt="${remote}" + + [[ "${r_remote}" =~ ^([^:]+):(.*) ]] || exit 1 + remote="${BASH_REMATCH[1]}" + base="${BASH_REMATCH[2]:+${BASH_REMATCH[2]}/}" + + upath=0 + ulink=0 + while IFS=$'\t' read -r k v; do + [[ "${k% }" == "${path}" ]] && path="${base}${v# }" && upath=1 + [[ "${k% }" == "${link}" ]] && link="${base}${v# }" && ulink=1 + done < <(rclone cryptdecode --reverse "${crypt}:" "${path}" "${link}") + wait "$!" || exit 1 + ((ulink && upath)) || exit 1 +fi + +read -rd '' JQ <<'EOF' +.[$k] +| select(.type == "sftp") // error("not sftp") +| select(.key_file_pass | not) // error("key uses passphrase") +| [ + (.key_file | select(.) // error("missing key") + | "-i", (sub("^~"; env.HOME) | @sh)), + (.known_hosts_file | select(.) + | "-o", ("UserKnownHostsFile=\(sub("^~"; env.HOME))" | @sh)), + (.port | select(.) | "-p", @sh), + ("\(.user // error("missing user"))@\(.host // error("missing host"))" + | @sh) +] +| join(" ") +EOF +mapfile -td '' args < <( + jq -rc --arg k "${remote}" "${JQ}" <<<"${conf}" | \ + xargs -r printf '%s\0' + [[ "${PIPESTATUS[0]}" -eq 0 && "${PIPESTATUS[1]}" -eq 0 ]]) +wait "$!" || exit 1 + +ssh_cmd=(ssh -o BatchMode=yes "${args[@]}") +cmd=("${ssh_cmd[@]}" + "cp -al $(printf '%q' "${link}") $(printf '%q' "${path}")") +echo "* $(qargs "${cmd[@]}")" +"${cmd[@]}" || exit 1 +"${ssh_cmd[@]}" "touch -c ${path@Q}" +exit 0 |
