My Blog

A classic static blog

zpaq script

#!/bin/bash

Corrected paths

ARCHIVE_PATH=“/sdcard/zpaq/sixpack.05.oct.2025.zpaq” MONITOR_ROOT=“/sdcard/ccrypt” # Root directory to monitor CHECK_INTERVAL=60 LOG_FILE=“/sdcard/Download/zpaq/backup.log”

Create necessary directories

mkdir -p “\((dirname "\)ARCHIVE_PATH”)” mkdir -p “\((dirname "\)LOG_FILE”)”

Logging function

log() { echo “[$(date ‘+%Y-%m-%d %H:%M:%S’)] \(1" | tee -a "\)LOG_FILE” }

Check if zpaq is available

check_dependencies() { if ! command -v zpaq &> /dev/null; then log “ERROR: zpaq command not found. Please install zpaq in Termux.” log “Install with: pkg install zpaq” exit 1 fi }

Initialize archive with complete directory structure

initialize_archive() { log “Initializing ZPAQ archive at $ARCHIVE_PATH” log “Monitoring root: $MONITOR_ROOT”

# Change to monitor root to preserve relative paths
cd "$MONITOR_ROOT" || {
    log "ERROR: Cannot change to directory $MONITOR_ROOT"
    exit 1
}

# Get all files and directories in /sdcard/ccrypt/
local all_items=()
while IFS= read -r -d '' item; do
    if [ -n "$item" ] && [ -e "$item" ]; then
        all_items+=("$item")
    fi
done < <(find . -print0 2>/dev/null)

if [ ${#all_items[@]} -gt 0 ]; then
    log "Found ${#all_items[@]} items for initial backup"
    
    # Add in batches to avoid command line length issues
    local batch_size=50
    for ((i=0; i<${#all_items[@]}; i+=batch_size)); do
        local batch=("${all_items[@]:i:batch_size}")
        if zpaq add "$ARCHIVE_PATH" "${batch[@]}" -method 4 2>> "$LOG_FILE"; then
            log "Successfully added batch of ${#batch[@]} items"
        else
            log "ERROR: Failed to add batch of items to archive"
        fi
    done
    log "Initial archive creation completed"
else
    log "No items found for initial backup"
fi

}

Update archive with new files and directories

update_archive() { local new_items=() local temp_file temp_file=$(mktemp)

# Change to monitor root
cd "$MONITOR_ROOT" || return

# Find new or modified files and directories
if [ -f "$ARCHIVE_PATH" ]; then
    # Find files modified since last backup
    find . -newer "$ARCHIVE_PATH" -print0 2>/dev/null > "$temp_file"
else
    # Find all files if archive doesn't exist
    find . -print0 2>/dev/null > "$temp_file"
fi

# Read null-separated items into array
if [ -s "$temp_file" ]; then
    while IFS= read -r -d '' item; do
        if [ -n "$item" ] && [ -e "$item" ]; then
            new_items+=("$item")
        fi
    done < "$temp_file"
fi

rm -f "$temp_file"

# Process new items
if [ ${#new_items[@]} -gt 0 ]; then
    log "Found ${#new_items[@]} new/modified items"
    
    # Log new directories specifically
    for item in "${new_items[@]}"; do
        if [ -d "$item" ]; then
            log "New directory detected: $item"
        fi
    done
    
    # Add items in batches to avoid command line length issues
    local batch_size=50
    for ((i=0; i<${#new_items[@]}; i+=batch_size)); do
        local batch=("${new_items[@]:i:batch_size}")
        if zpaq add "$ARCHIVE_PATH" "${batch[@]}" -method 4 2>> "$LOG_FILE"; then
            log "Successfully added batch of ${#batch[@]} items"
        else
            log "ERROR: Failed to add batch of items to archive"
        fi
    done
    
    # Update archive timestamp
    touch "$ARCHIVE_PATH"
fi

}

Function to verify archive contents

verify_archive() { if [ -f “\(ARCHIVE_PATH" ]; then log "Verifying archive contents..." zpaq list "\)ARCHIVE_PATH” | head -20 | tee -a “\(LOG_FILE" local total_count=\)(zpaq list”$ARCHIVE_PATH” | grep -c “^-”) log “Total items in archive: $total_count” fi }

Monitor function

monitor_directories() { log “Starting recursive directory monitoring service” log “Monitoring root: $MONITOR_ROOT” log “Archive: $ARCHIVE_PATH” log “Check interval: $CHECK_INTERVAL seconds”

# Initial verification
verify_archive

while true; do
    update_archive
    sleep "$CHECK_INTERVAL"
done

}

Signal handling for clean shutdown

cleanup() { log “Monitoring stopped by user” exit 0 }

trap cleanup SIGINT SIGTERM

One-time backup function

one_time_backup() { check_dependencies

if [ ! -f "$ARCHIVE_PATH" ]; then
    log "First run - creating initial archive"
    initialize_archive
else
    log "Updating existing archive with new changes"
    update_archive
fi

verify_archive

}

Main execution with monitoring

main() { check_dependencies

if [ ! -f "$ARCHIVE_PATH" ]; then
    log "First run - creating initial archive"
    initialize_archive
else
    log "Existing archive found, resuming monitoring"
fi

monitor_directories

}

Show usage

usage() { echo “Usage: $0 [option]” echo “Options:” echo ” (no option) - Start continuous monitoring” echo ” once - Run one-time backup and exit” echo ” verify - Verify archive contents and exit” echo ” help - Show this help message” }

Parse command line arguments

case “${1:-}” in “once”) one_time_backup ;; “verify”) verify_archive ;; “help”|“-h”|“–help”) usage ;; ““) main ;; *) echo “Unknown option: $1” usage exit 1 ;; esac