autoshare/modules/archive.sh

118 lines
2.8 KiB
Bash
Executable file

#!/bin/bash
# This script packs a file or directory into a 7z archive with the given password.
# It can (optionally) split the archives into volumes of a fixed size in megabytes.
source functions.sh
set -euo pipefail
trap 'cleanup' ERR INT
cleanup() {
if [[ -n "$archive" ]]; then
rm -f "${archive}"*
log "INFO" "Cleaning up $(basename $archive) remains before exit"
fi
}
check_input() {
local input_file="$1"
local archive_pwd="$2"
local size="$3"
[[ -e "$input_file" ]] || { log "ERROR" "Input file '${input_file}' does not exist" && exit 2 ;}
[[ -n "${archive_pwd}" ]] || { log "ERROR" "No password given" && exit 2 ;}
if [[ ! "$size" =~ ^([1-9][0-9]*)?$ ]]; then
log "ERROR" "Invalid size $size, must be empty or a positive number"
exit 2
fi
log "INFO" "Archiving '${input_file}' with password '${archive_pwd}' and size '$size'"
}
calc_smart_volumes() {
# Calculates a "smart" volume size so that each volume (including the final part)
# will be approximately the same size
local input_file="$1"
local size="$2"
total_size=$(du -s -BM "${input_file}" | grep -oP '^\d+') || return 1
# If total file size is smaller than volume size, don't pack it into volumes
(( total_size < size )) && return 1
num_volumes=$(( (total_size + size - 1) / size ))
smart_size=$(( (total_size + num_volumes - 1) / num_volumes ))
log "INFO" "Calculated smart volume size '$size'"
echo "$smart_size"
}
set_volumes() {
local input_file="$1"
local size="${2:-}"
local volumes=""
if [[ -n "$size" ]]; then
smart_size="$(calc_smart_volumes $input_file $size || echo -n)"
volumes="-v${smart_size}m"
fi
log "INFO" "Volumes set to '$volumes'"
echo "$volumes"
}
# Generates a random archive name of 20 alphanumeric characters
generate_name() {
archive="$archive_dir/$(tr -dc [:alnum:] < /dev/urandom | head -c 20).7z"
log "INFO" "Generated archive name '$archive'"
echo "$archive"
}
create_archive() {
local input_file="$1"
local archive_pwd="$2"
local volumes="$3"
local size="$4"
local archive="$5"
[[ -n "$volumes" ]] && log "INFO" "Volumes size is set to $size MB"
7z a -mhe=on "-p${archive_pwd}" "$volumes" "$archive" "${input_file}"
}
main() {
local input_file="${1:-}"
local archive_pwd="${2:-}"
local size="${3:-}"
local volumes archive archive_dir
archive_dir="$(dirname "$0")/../archives"
check_dependencies "7z"
check_input "$input_file" "$archive_pwd" "$size"
if ! mkdir -p "$archive_dir"; then
log "ERROR" "Unable to create archive directory"
exit 1
fi
volumes="$(set_volumes $input_file $size)"
archive="$(generate_name)"
log "INFO" "Packing '${input_file}' into archive '$archive' with password '${archive_pwd}'"
create_archive \
"$input_file" \
"$archive_pwd" \
"$volumes" \
"$size" \
"$archive"
log "NOTICE" "Archive created"
}
main "$@"