+#!/usr/bin/env bash
+
+# annex-ec: Use erasure codes for more efficient storage use in git-annex
+# Copyright (C) 2026 Scott Worley
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+
+set -euo pipefail
+
+die() {
+ echo "$*" >&2
+ exit 1
+}
+
+find_recovery_set_files() {
+ local found
+ found=false
+ recovery_set_files=()
+ while IFS= read -r line;do
+ if [[ "$line" == ' '* ]];then
+ recovery_set_files+=( "${line# }" )
+ if [[ "${line# }" == "$1" ]];then
+ found=true
+ fi
+ else
+ if $found;then
+ break
+ fi
+ recovery_set_name=$line
+ recovery_set_files=()
+ fi
+ done < ec/.meta
+ if ! $found;then
+ die "Could not find a recovery set containing file $1"
+ fi
+}
+
+while [[ "$1" == -- ]];do shift; done
+
+for target;do
+ if [[ -e "$target" ]];then continue; fi
+ set +e
+ git annex get "$target"
+ set -e
+ if [[ -e "$target" ]];then continue; fi
+
+ find_recovery_set_files "$target"
+
+ set +e
+ git annex get "${recovery_set_files[@]}" ec/"$recovery_set_name"*
+ set -e
+
+ # par2 doesn't like directory structure, so we work from a temp dir where we can flatten everything
+ srcdir=$PWD
+ flat="$(mktemp -d)"
+ pushd "$flat"
+
+ for f in "${recovery_set_files[@]}";do
+ ln -s "$srcdir"/"$f" .
+ done
+ ln -s "$srcdir"/ec/"$recovery_set_name"* .
+
+ # We have to remove the broken symlinks or par2 gets confused trying to write to them
+ find -L . -type l -exec rm -v {} +
+
+ par2 r -- *.par2
+
+ popd
+ for f in "${recovery_set_files[@]}";do
+ git annex reinject "$flat"/"$(basename "$f")" "$f"
+ done
+done