diff --git a/source/deletion_lists_update.h b/source/deletion_lists_update.h index 0048e3b..7beda98 100644 --- a/source/deletion_lists_update.h +++ b/source/deletion_lists_update.h @@ -122,9 +122,8 @@ static const char* config_dirs_to_delete[] = { }; // Switch directories to delete -// NOTE: .packages is intentionally excluded - UltraHand package cache, preserve during updates +// NOTE: .overlays and .packages excluded - preserve UltraHand .offload hide state during updates static const char* switch_dirs_to_delete[] = { - "sd:/switch/.overlays", "sd:/switch/90DNS_tester", "sd:/switch/aio-switch-updater", "sd:/switch/amsPLUS-downloader", diff --git a/source/install.c b/source/install.c index 015b5b6..8022b15 100644 --- a/source/install.c +++ b/source/install.c @@ -275,6 +275,167 @@ int folder_copy_with_progress_v2(const char *src, const char *dst, const char *d return res; } +// Copy one directory (e.g. .overlays or .packages) with .offload awareness: if the same +// name exists in dst_offload, copy pack's version into dst_offload (update in place); +// otherwise copy to dst_parent. Used only for update mode to preserve UltraHand hide state. +static int copy_dir_offload_aware(const char *src_parent, const char *dst_parent, const char *dst_offload, + const char *display_name, int *copied, int total, u32 start_x, u32 start_y, int *last_percent) +{ + DIR dir; + FILINFO fno; + int res; + char src_full[256]; + char dst_main[256]; + char dst_off[256]; + + res = f_opendir(&dir, src_parent); + if (res != FR_OK) + return res; + + while (1) { + res = f_readdir(&dir, &fno); + if (res != FR_OK || fno.fname[0] == 0) break; + if (fno.fname[0] == '.' && (fno.fname[1] == '\0' || (fno.fname[1] == '.' && fno.fname[2] == '\0'))) + continue; + if (strcmp(fno.fname, ".offload") == 0) + continue; + + install_combine_path(src_full, sizeof(src_full), src_parent, fno.fname); + install_combine_path(dst_off, sizeof(dst_off), dst_offload, fno.fname); + + if (install_path_exists(dst_off)) { + res = (fno.fattrib & AM_DIR) ? folder_copy(src_full, dst_offload) : file_copy(src_full, dst_off); + } else { + install_combine_path(dst_main, sizeof(dst_main), dst_parent, fno.fname); + res = (fno.fattrib & AM_DIR) ? folder_copy(src_full, dst_parent) : file_copy(src_full, dst_main); + } + (*copied)++; + if (total > 0) { + int percent = (*copied * 100) / total; + if (percent != *last_percent || *copied % 20 == 0) { + gfx_con_setpos(start_x, start_y); + install_set_color(COLOR_CYAN); + gfx_printf(" Kopiere: %s [%3d%%] (%d/%d)", display_name, percent, *copied, total); + install_set_color(COLOR_WHITE); + *last_percent = percent; + } + } + if (res != FR_OK) { + f_closedir(&dir); + return res; + } + } + f_closedir(&dir); + return FR_OK; +} + +// Copy switch/ folder for update mode only: preserve SD's .overlays/.offload and +// .packages/.offload; for items that exist there, update in place instead of main area. +int folder_copy_switch_update_offload_aware(const char *src_switch, const char *dst_base, const char *display_name) { + char dst_switch[256]; + char src_overlays[256], src_packages[256]; + char dst_overlays[256], dst_offload_ovl[256], dst_packages[256], dst_offload_pkg[256]; + DIR dir; + FILINFO fno; + int res; + int copied = 0; + int total; + int last_percent = -1; + u32 start_x, start_y; + + install_combine_path(dst_switch, sizeof(dst_switch), dst_base, "switch"); + + if (!install_path_exists(src_switch)) { + install_set_color(COLOR_ORANGE); + gfx_printf(" Ueberspringe: %s (nicht gefunden)\n", display_name); + install_set_color(COLOR_WHITE); + return FR_NO_FILE; + } + + total = install_count_directory_items(src_switch); + if (total == 0) { + f_mkdir(dst_switch); + return FR_OK; + } + + gfx_con_getpos(&start_x, &start_y); + install_set_color(COLOR_CYAN); + gfx_printf(" Kopiere: %s [ 0%%] (0/%d)", display_name, total); + install_set_color(COLOR_WHITE); + + res = f_mkdir(dst_switch); + if (res != FR_OK && res != FR_EXIST) return res; + + res = f_opendir(&dir, src_switch); + if (res != FR_OK) return res; + + while (1) { + res = f_readdir(&dir, &fno); + if (res != FR_OK || fno.fname[0] == 0) break; + if (fno.fname[0] == '.' && (fno.fname[1] == '\0' || (fno.fname[1] == '.' && fno.fname[2] == '\0'))) + continue; + + if (strcmp(fno.fname, ".overlays") == 0) { + install_combine_path(src_overlays, sizeof(src_overlays), src_switch, ".overlays"); + install_combine_path(dst_overlays, sizeof(dst_overlays), dst_switch, ".overlays"); + install_combine_path(dst_offload_ovl, sizeof(dst_offload_ovl), dst_overlays, ".offload"); + if (!install_path_exists(src_overlays)) { f_closedir(&dir); continue; } + f_mkdir(dst_overlays); + f_mkdir(dst_offload_ovl); + res = copy_dir_offload_aware(src_overlays, dst_overlays, dst_offload_ovl, display_name, + &copied, total, start_x, start_y, &last_percent); + } else if (strcmp(fno.fname, ".packages") == 0) { + install_combine_path(src_packages, sizeof(src_packages), src_switch, ".packages"); + install_combine_path(dst_packages, sizeof(dst_packages), dst_switch, ".packages"); + install_combine_path(dst_offload_pkg, sizeof(dst_offload_pkg), dst_packages, ".offload"); + if (!install_path_exists(src_packages)) { f_closedir(&dir); continue; } + f_mkdir(dst_packages); + f_mkdir(dst_offload_pkg); + { /* package.ini into main area */ + char src_ini[256], dst_ini[256]; + s_printf(src_ini, "%s/package.ini", src_packages); + s_printf(dst_ini, "%s/package.ini", dst_packages); + if (install_path_exists(src_ini)) { + res = file_copy(src_ini, dst_ini); + if (res == FR_OK) copied++; + } + } + res = copy_dir_offload_aware(src_packages, dst_packages, dst_offload_pkg, display_name, + &copied, total, start_x, start_y, &last_percent); + } else { + char src_full[256], dst_full[256]; + install_combine_path(src_full, sizeof(src_full), src_switch, fno.fname); + install_combine_path(dst_full, sizeof(dst_full), dst_switch, fno.fname); + if (fno.fattrib & AM_DIR) + res = folder_copy(src_full, dst_switch); + else + res = file_copy(src_full, dst_full); + copied++; + } + if (res != FR_OK) break; + if (total > 0 && (copied % 20 == 0 || copied == total)) { + int percent = (copied * 100) / total; + gfx_con_setpos(start_x, start_y); + install_set_color(COLOR_CYAN); + gfx_printf(" Kopiere: %s [%3d%%] (%d/%d)", display_name, percent, copied, total); + install_set_color(COLOR_WHITE); + } + } + f_closedir(&dir); + + gfx_con_setpos(start_x, start_y); + if (res == FR_OK) { + install_set_color(COLOR_GREEN); + gfx_printf(" Kopiere: %s [100%%] (%d/%d) - Fertig!\n", display_name, copied, total); + install_set_color(COLOR_WHITE); + } else { + install_set_color(COLOR_RED); + gfx_printf(" Kopiere: %s - Fehlgeschlagen!\n", display_name); + install_set_color(COLOR_WHITE); + } + return res; +} + // Recursive folder delete with progress tracking (shared implementation) int folder_delete_progress_recursive(const char *path, int *deleted, int total, u32 start_x, u32 start_y, const char *display_name, int *last_percent) { DIR dir; diff --git a/source/install.h b/source/install.h index d1a86a2..04f18b3 100644 --- a/source/install.h +++ b/source/install.h @@ -40,3 +40,5 @@ int delete_path_lists_grouped(const char *folder_display_name, ...); int folder_delete_single_with_progress(const char *path, const char *display_name); int folder_delete_progress_recursive(const char *path, int *deleted, int total, u32 start_x, u32 start_y, const char *display_name, int *last_percent); int folder_copy_with_progress_v2(const char *src, const char *dst, const char *display_name); +// Update-only: copy switch/ preserving .overlays/.offload and .packages/.offload (UltraHand hide state) +int folder_copy_switch_update_offload_aware(const char *src_switch, const char *dst_base, const char *display_name); diff --git a/source/install_update.c b/source/install_update.c index 3b1e662..cf04d52 100644 --- a/source/install_update.c +++ b/source/install_update.c @@ -103,7 +103,7 @@ int update_mode_install(omninx_variant_t variant) { if (res != FR_OK && res != FR_NO_FILE) return res; s_printf(src_path, "%s/switch", staging); - res = folder_copy_with_progress_v2(src_path, "sd:/", "switch/"); + res = folder_copy_switch_update_offload_aware(src_path, "sd:/", "switch/"); if (res != FR_OK && res != FR_NO_FILE) return res; s_printf(src_path, "%s/warmboot_mariko", staging);