@@ -336,8 +336,11 @@ run_preflight_checks() {
336336 if [[ " $test_mode " == " true" ]]; then printf " ${C_GREEN} ✅ Local disk space OK.${C_RESET} \n" ; fi
337337 fi
338338}
339+ print_header () {
340+ printf " \n%b--- %s ---%b\n" " ${C_BOLD} " " $1 " " ${C_RESET} "
341+ }
339342run_restore_mode () {
340- printf " ${C_BOLD}${C_CYAN} --- RESTORE MODE ACTIVATED --- ${C_RESET} \n "
343+ print_header " RESTORE MODE ACTIVATED"
341344 run_preflight_checks " restore"
342345 local DIRS_ARRAY; read -ra DIRS_ARRAY <<< " $BACKUP_DIRS"
343346 local RECYCLE_OPTION=" [ Restore from Recycle Bin ]"
@@ -347,40 +350,46 @@ run_restore_mode() {
347350 fi
348351 all_options+=(" Cancel" )
349352 printf " ${C_YELLOW} Available backup sets to restore from:${C_RESET} \n"
353+ PS3=" Your choice: "
350354 select dir_choice in " ${all_options[@]} " ; do
351355 if [[ -n " $dir_choice " ]]; then break ;
352356 else echo " Invalid selection. Please try again." ; fi
353357 done
358+ PS3=" #? "
354359 local full_remote_source=" "
355360 local default_local_dest=" "
356361 local item_for_display=" "
357362 local restore_path=" "
358363 local is_full_directory_restore=false
359364 if [[ " $dir_choice " == " $RECYCLE_OPTION " ]]; then
360- printf " ${C_BOLD}${C_CYAN} --- Browse Recycle Bin --- ${C_RESET} \n "
365+ print_header " Browse Recycle Bin"
361366 local remote_recycle_path=" ${BOX_DIR%/ } /${RECYCLE_BIN_DIR%/ } "
362367 local date_folders; date_folders=$( ssh " ${SSH_OPTS_ARRAY[@]} " " ${SSH_DIRECT_OPTS[@]} " " $BOX_ADDR " " ls -1 \" $remote_recycle_path \" " 2> /dev/null) || true
363368 local valid_folders=()
364369 for f in $date_folders ; do
365- if [[ " $f " =~ ^[0-9]{4}-[0-9]{2}-[0-9]{2}_[0-9]{6}$ ]]; then
366- valid_folders+=( " $f " )
367- fi
370+ case " $f " in
371+ [0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]_[0-9][0-9][0-9][0-9][0-9][0-9])
372+ valid_folders+=( " $f " )
373+ ;;
374+ esac
368375 done
369376 date_folders=(" ${valid_folders[@]} " )
370377 if [[ ${# date_folders[@]} -eq 0 ]]; then
371378 echo " ❌ No validly-named backup folders found in the recycle bin." >&2 ; return 1
372379 fi
373380 printf " ${C_YELLOW} Select a backup run (date_time) to browse:${C_RESET} \n"
381+ PS3=" Your choice: "
374382 select date_choice in " ${date_folders[@]} " " Cancel" ; do
375383 if [[ " $date_choice " == " Cancel" ]]; then echo " Restore cancelled." ; return 0;
376384 elif [[ -n " $date_choice " ]]; then break ;
377385 else echo " Invalid selection. Please try again." ; fi
378386 done
387+ PS3=" #? "
379388 local remote_date_path=" ${remote_recycle_path} /${date_choice} "
380- printf " ${C_BOLD} --- Files available from ${date_choice} (showing first 20) --- ${C_RESET} \n "
389+ print_header " Files available from ${date_choice} (showing first 20)"
381390 local remote_listing_source=" ${BOX_ADDR} :${remote_date_path} /"
382391 rsync -r -n --out-format=' %n' -e " $SSH_CMD " " $remote_listing_source " . 2> /dev/null | head -n 20 || echo " No files found for this date."
383- printf " ${C_BOLD} --------------------------------------------------------${ C_RESET}\n "
392+ printf " %b --------------------------------------------------------%b\n " " ${C_BOLD} " " ${ C_RESET}"
384393 printf " ${C_YELLOW} Enter the full original path of the item to restore (e.g., home/user/file.txt): ${C_RESET} " ; read -r specific_path
385394 if [[ " $specific_path " == /* || " $specific_path " =~ (^| /)\.\. (/| $) ]]; then
386395 echo " ❌ Invalid restore path: must be relative and contain no '..'" >&2 ; return 1
@@ -401,7 +410,7 @@ run_restore_mode() {
401410 case " $choice " in
402411 entire) is_full_directory_restore=true; break ;;
403412 specific)
404- printf -v specific_path_prompt " Enter the path relative to '%s' to restore: " " $dir_choice " ; printf " ${C_YELLOW} %s${C_RESET} " " $specific_path_prompt " ; read -er specific_path
413+ printf -v specific_path_prompt " Enter the path relative to '%s' to restore (e.g., subfolder/file.txt) : " " $dir_choice " ; printf " ${C_YELLOW} %s${C_RESET} " " $specific_path_prompt " ; read -er specific_path
405414 if [[ " $specific_path " == /* || " $specific_path " =~ (^| /)\.\. (/| $) ]]; then
406415 echo " ❌ Invalid restore path: must be relative and contain no '..'" >&2 ; return 1
407416 fi
@@ -427,13 +436,11 @@ run_restore_mode() {
427436 fi
428437 fi
429438 local final_dest
430- echo -e " \n${C_BOLD} --------------------------------------------------------"
431- echo -e " Restore Destination"
432- echo -e " --------------------------------------------------------${C_RESET} "
433- echo -e " Enter the absolute destination path for the restore.\n"
434- echo -e " ${C_YELLOW} Default (original location):${C_RESET} "
435- echo -e " ${C_CYAN}${default_local_dest}${C_RESET} \n"
436- echo -e " Press [Enter] to use the default path, or enter a new one."
439+ print_header " Restore Destination"
440+ printf " Enter the absolute destination path for the restore.\n\n"
441+ printf " %bDefault (original location):%b\n" " ${C_YELLOW} " " ${C_RESET} "
442+ printf " %b%s%b\n\n" " ${C_CYAN} " " $default_local_dest " " ${C_RESET} "
443+ printf " Press [Enter] to use the default path, or enter a new one.\n"
437444 read -rp " > " final_dest
438445 : " ${final_dest:= $default_local_dest } "
439446 local path_validation_attempts=0
@@ -502,17 +509,17 @@ run_restore_mode() {
502509 dest_user=" "
503510 fi
504511 fi
505- printf " \n ${C_BOLD} Restore Summary: ${C_RESET} \n "
512+ print_header " Restore Summary"
506513 printf " Source: %s\n" " $item_for_display "
507- printf " Destination: ${C_BOLD} %s ${C_RESET} \n " " $final_dest "
508- printf " \n ${C_BOLD}${C_YELLOW} --- PERFORMING DRY RUN (NO CHANGES MADE) --- ${C_RESET} \n "
514+ printf " Destination: %b%s%b\n " " ${C_BOLD} " " $final_dest " " ${C_RESET} "
515+ print_header " PERFORMING DRY RUN (NO CHANGES MADE)"
509516 log_message " Starting restore dry-run of ${item_for_display} from ${full_remote_source} to ${final_dest} "
510517 local rsync_restore_opts=(-avhi --safe-links --progress --exclude-from=" $EXCLUDE_FILE_TMP " -e " $SSH_CMD " )
511518 if ! rsync " ${rsync_restore_opts[@]} " " ${extra_rsync_opts[@]} " --dry-run " $full_remote_source " " $final_dest " ; then
512519 printf " ${C_RED} ❌ DRY RUN FAILED. Rsync reported an error. Check connectivity and permissions.${C_RESET} \n" >&2
513520 log_message " Restore dry-run failed for ${item_for_display} " ; return 1
514521 fi
515- printf " ${C_BOLD}${C_GREEN} --- DRY RUN COMPLETE --- ${C_RESET} \n "
522+ print_header " DRY RUN COMPLETE"
516523 while true ; do
517524 printf " \n${C_YELLOW} Proceed with restoring %s to '%s'? [yes/no]: ${C_RESET} " " $item_for_display " " $final_dest " ; read -r confirmation
518525 case " ${confirmation,,} " in
@@ -521,7 +528,7 @@ run_restore_mode() {
521528 * ) echo " Please answer 'yes' or 'no'." ;;
522529 esac
523530 done
524- printf " \n ${C_BOLD} --- EXECUTING RESTORE --- ${C_RESET} \n "
531+ print_header " EXECUTING RESTORE"
525532 log_message " Starting actual restore of ${item_for_display} from ${full_remote_source} to ${final_dest} "
526533 if rsync " ${rsync_restore_opts[@]} " " ${extra_rsync_opts[@]} " " $full_remote_source " " $final_dest " ; then
527534 log_message " Restore completed successfully."
0 commit comments