#!/bin/bash # ----------------------------------------------------------------------------------------------- # --------------------------------- Bulk Permissions Repair ------------------------------------ # ----------------------------------------------------------------------------------------------- # Applies correct permissions to a single share or specific path. # Faster than running media_shares_permissions.sh which processes all shares. # Use when a specific share has wrong ownership or permissions after: # - A failed transfer that left files owned by wrong user # - A container writing files as root instead of nobody:users # - Manual file operations that bypassed normal permission handling # - A new share that needs permissions applied before the next nightly run # # Usage: # bulk_permissions_repair.sh /mnt/user/Movies # bulk_permissions_repair.sh /mnt/user/Movies --dry-run # bulk_permissions_repair.sh /mnt/user/Movies /mnt/user/Tv_Shows # # Uses PERMISSIONS_MODE and PERMISSIONS_OWNER from Master.conf. # Supports --dry-run to show what would be changed without applying. # ----------------------------------------------------------------------------------------------- SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" source "$SCRIPT_DIR/../Master.conf" source "$SCRIPT_DIR/../common.sh" parse_args "$@" # ----------------------------------------------------------------------------------------------- # ━━━ $ICON_GEAR Setup ━━━ # ----------------------------------------------------------------------------------------------- echo "" echo "━━━ $ICON_GEAR Setup ━━━" if [[ "$EUID" -ne 0 ]]; then error "Must be run as root" exit 1 fi success "Running as root" if [[ ${#PARSED_ARGS[@]} -eq 0 ]]; then error "No paths specified" error "Usage: bulk_permissions_repair.sh /path/to/share [/another/path]" error " bulk_permissions_repair.sh /mnt/user/Movies --dry-run" exit 1 fi info "Mode: $PERMISSIONS_MODE" info "Owner: $PERMISSIONS_OWNER" [[ "$DRY_RUN" == true ]] && warn "DRY RUN — no permissions will be changed" # ----------------------------------------------------------------------------------------------- # ━━━ $ICON_PERMS Apply Permissions ━━━ # ----------------------------------------------------------------------------------------------- echo "" echo "━━━ $ICON_PERMS Permissions Repair ━━━" START=$(date +%s) PASS=() FAIL=() for share_path in "${PARSED_ARGS[@]}"; do [[ -z "$share_path" ]] && continue echo "" echo "━━━ $ICON_PERMS $(basename "$share_path") ━━━" if [[ ! -d "$share_path" ]]; then error "$share_path — not found" FAIL+=("$share_path") continue fi # Count files for progress context FILE_COUNT=$(find "$share_path" -type f 2>/dev/null | wc -l) DIR_COUNT=$(find "$share_path" -type d 2>/dev/null | wc -l) SIZE=$(du -sh "$share_path" 2>/dev/null | cut -f1) info "$share_path — $FILE_COUNT files, $DIR_COUNT dirs ($SIZE)" if [[ "$DRY_RUN" == true ]]; then warn "DRY RUN — would apply: chmod -R $PERMISSIONS_MODE $share_path" warn "DRY RUN — would apply: chown -R $PERMISSIONS_OWNER $share_path" PASS+=("$(basename "$share_path")") continue fi # Apply ownership first — chmod after so files are owned correctly before mode change info "Applying ownership: $PERMISSIONS_OWNER..." chown -R "$PERMISSIONS_OWNER" "$share_path" 2>/dev/null CHOWN_EXIT=$? info "Applying permissions: $PERMISSIONS_MODE..." chmod -R "$PERMISSIONS_MODE" "$share_path" 2>/dev/null CHMOD_EXIT=$? if [[ "$CHOWN_EXIT" -eq 0 && "$CHMOD_EXIT" -eq 0 ]]; then success "$ICON_UNLOCKED $(basename "$share_path") — permissions applied" PASS+=("$(basename "$share_path")") else error "$(basename "$share_path") — permission repair failed" FAIL+=("$(basename "$share_path")") fi done END=$(date +%s) # ----------------------------------------------------------------------------------------------- # ━━━ $ICON_SUMMARY Summary ━━━ # ----------------------------------------------------------------------------------------------- echo "" echo "━━━━━ $ICON_SUMMARY PERMISSIONS REPAIR SUMMARY ━━━━━" echo "$ICON_PERMS Mode: $PERMISSIONS_MODE" echo "$ICON_PERMS Owner: $PERMISSIONS_OWNER" echo "$ICON_TIME Duration: $(format_duration $((END - START)))" echo "" echo " $ICON_SUCCESS Pass: ${#PASS[@]} $ICON_ERROR Fail: ${#FAIL[@]}" echo "" [[ ${#PASS[@]} -gt 0 ]] && for p in "${PASS[@]}"; do echo " $ICON_UNLOCKED $p"; done [[ ${#FAIL[@]} -gt 0 ]] && for f in "${FAIL[@]}"; do echo " $ICON_ERROR $f"; done echo "" if [[ "$DRY_RUN" == true ]]; then echo "$ICON_WARN Status: DRY RUN — no changes made" elif [[ ${#FAIL[@]} -gt 0 ]]; then echo "$ICON_ERROR Status: SOME REPAIRS FAILED" notify "Permissions repair failed on $(hostname) — failed shares: ${FAIL[*]}" "Permissions Repair" "warning" else echo "$ICON_DONE Status: $ICON_SUCCESS DONE" notify "Permissions repair complete on $(hostname) — ${#PASS[@]} share(s) repaired" "Permissions Repair" "normal" fi echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"