diff options
author | Soispha <soispha@vhack.eu> | 2023-08-29 13:17:27 +0200 |
---|---|---|
committer | Soispha <soispha@vhack.eu> | 2023-08-29 13:17:27 +0200 |
commit | 6a77c319f661ed5d6d6570768f78a4a2f93c04db (patch) | |
tree | d5e901003c7ad593ee2df0b91c41f382c8321d4a | |
parent | Docs(hm/conf/lf/commads/trash): Add fixme about the implementation (diff) | |
download | nixos-config-6a77c319f661ed5d6d6570768f78a4a2f93c04db.tar.gz nixos-config-6a77c319f661ed5d6d6570768f78a4a2f93c04db.zip |
Chore(hm/conf/lf/commads): Add initial draft of a reflinking cp in lf
Diffstat (limited to '')
-rwxr-xr-x | hm/soispha/conf/lf/commands/scripts/cow_cp | 96 |
1 files changed, 96 insertions, 0 deletions
diff --git a/hm/soispha/conf/lf/commands/scripts/cow_cp b/hm/soispha/conf/lf/commands/scripts/cow_cp new file mode 100755 index 00000000..9a12e5db --- /dev/null +++ b/hm/soispha/conf/lf/commands/scripts/cow_cp @@ -0,0 +1,96 @@ +#!/usr/bin/env dash + +# shellcheck source=/dev/null +SHELL_LIBRARY_VERSION="1.1.4" . %SHELL_LIBRARY_PATH + +# 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 [ ! -z "$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 |