#!/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 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 || 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 $size)" archive="$(generate_name)" log "NOTICE" "Packing '${input_file}' into archive '$archive' with password '${archive_pwd}'" create_archive \ "$input_file" \ "$archive_pwd" \ "$volumes" \ "$size" \ "$archive" log "NOTICE" "Archive created" } main "$@"