#!/bin/bash # Archive extraction handler for torrent-mover # extract_single_archive: Extract a single archive with proper error handling extract_single_archive() { local archive="$1" local target_dir="$2" local archive_type="${archive##*.}" local extract_success=1 local tmp_marker="${target_dir}/.extraction_in_progress" # Create extraction marker to indicate incomplete extraction touch "${tmp_marker}" # Ensure proper permissions for extraction directory chmod 775 "${target_dir}" chown ${TORRENT_USER:-debian-transmission}:${TORRENT_GROUP:-debian-transmission} "${target_dir}" # Extract based on archive type case "${archive_type,,}" in # Use lowercase comparison rar) log_debug "Extracting RAR archive: ${archive}" # Check which unrar variant is available if command -v unrar-free &>/dev/null; then # unrar-free has different syntax retry_command "unrar-free x \"${archive}\" \"${target_dir}\"" 3 10 else retry_command "unrar x -o- \"${archive}\" \"${target_dir}\"" 3 10 fi extract_success=$? ;; zip) log_debug "Extracting ZIP archive: ${archive}" retry_command "unzip -o \"${archive}\" -d \"${target_dir}\"" 3 10 extract_success=$? ;; 7z|7zip) log_debug "Extracting 7Z archive: ${archive}" retry_command "7z x \"${archive}\" -o\"${target_dir}\"" 3 10 extract_success=$? ;; *) log_error "Unknown archive type: ${archive_type}" extract_success=1 ;; esac # Apply consistent permissions to all extracted files and directories if [[ ${extract_success} -eq 0 ]]; then log_debug "Setting permissions for extracted files in ${target_dir}" find "${target_dir}" -type d -exec chmod 775 {} \; find "${target_dir}" -type f -exec chmod 664 {} \; find "${target_dir}" -exec chown ${TORRENT_USER:-debian-transmission}:${TORRENT_GROUP:-debian-transmission} {} \; # Remove the extraction marker to indicate successful completion rm -f "${tmp_marker}" return 0 else log_error "Extraction failed for ${archive}" # Keep marker to indicate failed extraction return 1 fi } # handle_archives: Process all archives in a source directory # Returns: 0 if all archives extracted successfully or no archives found, 1 if any failed handle_archives() { local src="$1" dst="$2" local overall_success=0 local archive_found=0 local extraction_errors=0 # Check if source and destination are valid if [[ ! -d "${src}" ]]; then log_error "Source directory missing: ${src}" return 1 fi if [[ ! -d "${dst}" ]]; then log_error "Destination directory missing: ${dst}" return 1 fi # Find all archives and extract them find "${src}" -type f \( -iname "*.rar" -o -iname "*.zip" -o -iname "*.7z" \) | while read -r arch; do archive_found=1 log_info "Processing archive: ${arch}" # Create extraction subdirectory local base base=$(basename "${arch}") local subdir="${dst}/${base%.*}" if ! mkdir -p "${subdir}"; then log_error "Failed to create subdirectory ${subdir} for archive extraction" extraction_errors=$((extraction_errors + 1)) continue fi # Extract the archive if ! extract_single_archive "${arch}" "${subdir}"; then log_error "Extraction failed for ${arch}" extraction_errors=$((extraction_errors + 1)) else log_info "Archive ${arch} extracted successfully to ${subdir}" log_info "Archive ${arch} retained in source until ratio limits are reached." fi done # Check for cleanup of any incomplete extractions from previous runs find "${dst}" -name ".extraction_in_progress" | while read -r marker; do local problem_dir=$(dirname "${marker}") log_warn "Found incomplete extraction in ${problem_dir} from previous run" # Option 1: Remove incomplete directory # rm -rf "${problem_dir}" # Option 2: Mark as incomplete but leave content touch "${problem_dir}/.incomplete_extraction" rm -f "${marker}" done # Return success if no archives found or all extracted successfully if [[ ${archive_found} -eq 0 ]]; then log_debug "No archives found in ${src}" return 0 elif [[ ${extraction_errors} -eq 0 ]]; then log_info "All archives extracted successfully" return 0 else log_warn "${extraction_errors} archives failed to extract properly" return 1 fi }