diff options
Diffstat (limited to 'modules/home.legacy/conf/lf/commands/scripts/cow_cp.sh')
-rwxr-xr-x | modules/home.legacy/conf/lf/commands/scripts/cow_cp.sh | 105 |
1 files changed, 105 insertions, 0 deletions
diff --git a/modules/home.legacy/conf/lf/commands/scripts/cow_cp.sh b/modules/home.legacy/conf/lf/commands/scripts/cow_cp.sh new file mode 100755 index 00000000..98675b9e --- /dev/null +++ b/modules/home.legacy/conf/lf/commands/scripts/cow_cp.sh @@ -0,0 +1,105 @@ +#!/usr/bin/env bash + +# shellcheck source=/dev/null +SHELL_LIBRARY_VERSION="2.1.2" . %SHELL_LIBRARY_PATH + +# shellcheck disable=SC2269 +f="$f" +# shellcheck disable=SC2269 +fx="$fx" +# shellcheck disable=SC2269 +fs="$fs" +# shellcheck disable=SC2269 +id="$id" + +# source: https://github.com/gokcehan/lf/wiki/Tips#use-copy-on-write-when-possible +# +# # FIXME: Add this. The hardest part is in checking, if a file can be reflinked, as fuse and bind mount are hard to +# backtrack <2023-08-29> + +# # This was very helpful for debugging: +# log_file="$HOME/lf-reflink-log-$(date +'%Y-%m-%d_%H-%M-%S')" +# [ -f "$log_file" ] || touch "$log_file" +# exec 1>> $log_file 2>&1 +# set -x + +# In theory, this may fail, +# but I tested it on selection with 10k files - everything worked (bash) +# FIXME: This will very likely fail on dash, when the file number > 255 <2023-08-29> +set -- "$(cat ~/.local/share/lf/files)" + +mode="$1" +shift + +if [ "$mode" = 'copy' ]; then + # Reflink if all items of selection and the destination are on the + # same mount point and it is CoW fs. + # (to make sure reflink never fails in first place, so we don't have to + # clean up) + + src_targets="$(df --output=target -- "$@" | sed '1d' | sort -u)" + + if [ "$(df --output=target -- "$PWD" | tail -n 1)" = \ + "$(echo "$src_targets" | tail -n 1)" ] && + (("$(echo "$src_targets" | wc -l)" == 1)) && + [[ "$(df --output=fstype -- "$PWD" | tail -n 1)" =~ ^(btrfs|xfs|zfs)$ ]]; then + + echo 'selected copy and cp reflink paste' + + start=$(date '+%s') + + # Handle same names in dst + # TODO parallelism, idk - but exit/return/break won't stop the loop from subshell... + for i in "$@"; do + name="${i##*/}" + original="$name" + + count=0 + while [ -w "$PWD/$name" ]; do + count=$((count + 1)) + name="$original.~$count~" + done + + set +e + cp_out="$(cp -rn --reflink=always -- "$i" "$PWD/$name" 2>&1)" + set -e + + if [ -n "$cp_out" ]; then + lf -remote "send $id echoerr $cp_out" + exit 0 + fi + done + + finish=$(($(date '+%s') - start)) + t='' + if ((finish > 2)); then + t="${finish}s" + fi + + # Or just skip a file when names are the same. + # (A LOT faster if you e.g. pasting selection of 10k files) + # cp -rn --reflink=always -- "$@" . + + lf -remote "send clear" + + green=$'\u001b[32m' + reset=$'\u001b[0m' + lf -remote "send $id echo ${green}reflinked!${reset} $t" + else + echo 'selected copy and lf native paste' + lf -remote "send $id paste" + lf -remote "send clear" + fi + +elif [ "$mode" = 'move' ]; then + echo 'selected move and lf native paste' + lf -remote "send $id paste" + lf -remote "send clear" +fi + +# # for debug +# set +x + +lf -remote "send load" + +# vim: ft=sh |