Compare commits

..

24 Commits

Author SHA1 Message Date
Niklas080208
31aeeaabbb Disabled build on push 2026-02-15 16:34:38 +01:00
89994995af Add pre-update/clean backup feature
All checks were successful
Build / Build (push) Successful in 12s
- Backup deletion paths before update to sd:/backup/OmniNX/{version}
- Backup deletion paths before clean install to sd:/backup/OmniNX/pre-omninx
- Best-effort backup: continue install even if some copies fail
- Fix directory creation: ensure parent dirs exist before folder_copy
- Step 1 for update: Backup; Step 1-2 for clean: user data + pre-omninx backup

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-14 16:05:57 +01:00
15b7cb1f4c Add battery run protection: require charger below 10%
All checks were successful
Build / Build (push) Successful in 10s
- Add bq24193_charger_connected() for charger detection
- Block install when battery < 10% and charger not plugged in
- Show clear screen after charger detected before continuing
- User can cancel with + and - to return to Hekate

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-14 15:12:06 +01:00
4b124a9998 Add + and - simultaneously to cancel and return to Hekate before install
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-14 15:03:58 +01:00
89279e27d5 Updated CI
All checks were successful
Build / Build (push) Successful in 10s
2026-02-13 22:13:29 +01:00
4ae286d21a Updated CI
All checks were successful
Build / Build (push) Successful in 11s
2026-02-13 22:11:42 +01:00
880a9af105 Updated CI
Some checks failed
Build / build (push) Failing after 3s
2026-02-13 22:09:31 +01:00
7fac0e50bb Updated CI
Some checks failed
Build / build (push) Failing after 3s
2026-02-13 22:08:40 +01:00
2c32f19262 Removed .packages from Update to be deleted 2026-02-11 17:58:32 +01:00
4effcf513b Updated Notice 2026-02-11 17:56:31 +01:00
6b04eb5d89 Fixed typo 2026-02-11 17:47:00 +01:00
ed93c32131 Updated Readme
- Added notice for proper use of this payload\n- Fixed some explenations
2026-02-11 17:17:37 +01:00
bae5ecebf1 Updated CI
All checks were successful
Build and Release / build-and-release (push) Successful in 10s
2026-02-11 17:11:18 +01:00
ef16df416b Updated CI
All checks were successful
Build and Release / build-and-release (push) Successful in 9s
2026-02-11 17:09:04 +01:00
f81cd8e381 Updated CI
Some checks failed
Build and Release / build-and-release (push) Failing after 13s
2026-02-11 17:07:40 +01:00
04362c6e0c Added CI 2026-02-11 17:06:19 +01:00
8457cdd5a6 Keeping UltraHand packages on Update 2026-02-11 17:06:09 +01:00
d1f78968a4 Added wait warning 2026-02-11 16:50:22 +01:00
b2c245d6ab removed .vscode folder 2026-02-11 16:21:21 +01:00
50618d4607 Changed logging and credits 2026-02-11 16:20:56 +01:00
Niklas080208
4d43ddf1e5 Cleanup UX: slim logging, DBI keep config, no manifest overwrite
- Slim cleanup: one progress line per section (Bereinige: X [p%] (n/n))
  via delete_path_lists_grouped() in clean and update mode
- DBI: remove folder entries from deletion lists; only .nro deleted,
  folder and config preserved
- Remove redundant manifest.ini creation; use manifest from pack config/

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-08 00:00:22 +01:00
Niklas080208
4a4147686e Added detection if multiple packs found 2026-02-03 22:15:17 +01:00
Niklas080208
fdad061616 Capitalized Variants 2026-02-03 21:22:37 +01:00
Niklas080208
3d3489f1e6 Removed HATS leftovers 2026-02-03 20:40:39 +01:00
21 changed files with 1632 additions and 1154 deletions

32
.github/workflows/build.yml vendored Normal file
View File

@@ -0,0 +1,32 @@
name: Build
on:
#push:
workflow_dispatch:
jobs:
build:
name: Build
runs-on: ubuntu-latest
container: devkitpro/devkitarm:latest
steps:
- name: Install dependencies
run: apt-get update && apt-get install -y nodejs
- name: Checkout latest code
uses: actions/checkout@v5
with:
clean: true
- name: Build
run: |
export DEVKITPRO=/opt/devkitpro
export DEVKITARM=/opt/devkitpro/devkitARM
make -j4
- name: Upload artifact
uses: actions/upload-artifact@v3
with:
name: OmniNX-Installer.bin
path: output/OmniNX-Installer.bin

17
.vscode/settings.json vendored
View File

@@ -1,17 +0,0 @@
{
"claudeCode.disableLoginPrompt": false,
"claudeCode.environmentVariables": [
{
"name": "ANTHROPIC_BASE_URL",
"value": "https://api.z.ai/api/anthropic"
},
{
"name": "ANTHROPIC_AUTH_TOKEN",
"value": "caceb12fd1a740c68631842764f1b38a.kBX5z6hfW95z8QHj"
},
{
"name": "CLAUDE_CODE_SKIP_AUTH_LOGIN",
"value": "true"
}
]
}

View File

@@ -272,7 +272,7 @@ Creates/overwrites `sd:/config/omninx/manifest.ini`:
**Content Structure**: **Content Structure**:
```ini ```ini
[OmniNX] [OmniNX]
current_pack={variant} # "standard", "light", or "oc" current_pack={variant} # "Standard", "Light", or "OC"
version={VERSION} # e.g., "1.0.0" version={VERSION} # e.g., "1.0.0"
update_channel={0|1|2} # light=0, oc=1, standard=2 update_channel={0|1|2} # light=0, oc=1, standard=2
channel_pack={variant} # Same as current_pack channel_pack={variant} # Same as current_pack

View File

@@ -1,5 +1,7 @@
# OmniNX Installer Payload # OmniNX Installer Payload
> **To properly use this payload, download the latest OmniNX Release:** [https://git.niklascfw.de/OmniNX/OmniNX/releases](https://git.niklascfw.de/OmniNX/OmniNX/releases)
A minimal payload for installing OmniNX CFW Pack files on Nintendo Switch outside of Horizon OS. A minimal payload for installing OmniNX CFW Pack files on Nintendo Switch outside of Horizon OS.
Based on [TegraExplorer](https://github.com/shchmue/TegraExplorer) and [hekate](https://github.com/CTCaer/hekate) by CTCaer, naehrwert, and shchmue. Based on [TegraExplorer](https://github.com/shchmue/TegraExplorer) and [hekate](https://github.com/CTCaer/hekate) by CTCaer, naehrwert, and shchmue.
@@ -52,7 +54,11 @@ make clean
make make
``` ```
The built payload will be output to `output/omninx-installer.bin`. The built payload will be output to `output/OmniNX-Installer.bin`.
### CI / GitHub Actions
Every push triggers a build. The `.bin` file is produced and attached as a workflow artifact (Actions tab → select run → Artifacts).
## Usage ## Usage
@@ -111,11 +117,11 @@ Use hekate or another bootloader to launch the payload:
The payload supports three OmniNX variants: The payload supports three OmniNX variants:
- **Standard** (`1.0.0s`): Full CFW pack - **Standard** `sd:/OmniNX Standard/`
- **Light** (`1.0.0l`): Lightweight CFW pack - **Light** `sd:/OmniNX Light/`
- **OC** (`1.0.0oc`): Overclock-enabled CFW pack (includes SaltySD) - **OC** `sd:/OmniNX OC/`
The payload automatically detects which variant is present on the SD card and installs accordingly. The payload detects the pack variant from the staging directory presence and detects the current installation (variant + version) from `sd:/config/omninx/manifest.ini` (`current_pack` and `version` keys).
## Project Structure ## Project Structure

View File

@@ -164,6 +164,12 @@ void bq24193_enable_charger()
i2c_send_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_PORConfig, reg); i2c_send_byte(I2C_1, BQ24193_I2C_ADDR, BQ24193_PORConfig, reg);
} }
bool bq24193_charger_connected()
{
u8 status = bq24193_get_reg(BQ24193_Status);
return (status & BQ24193_STATUS_PG_MASK) != 0;
}
void bq24193_fake_battery_removal() void bq24193_fake_battery_removal()
{ {
// Disable watchdog to keep BATFET disabled. // Disable watchdog to keep BATFET disabled.

View File

@@ -19,6 +19,8 @@
#ifndef __BQ24193_H_ #ifndef __BQ24193_H_
#define __BQ24193_H_ #define __BQ24193_H_
#include <utils/types.h>
#define BQ24193_I2C_ADDR 0x6B #define BQ24193_I2C_ADDR 0x6B
// REG 0 masks. // REG 0 masks.
@@ -117,5 +119,6 @@ enum BQ24193_reg_prop {
int bq24193_get_property(enum BQ24193_reg_prop prop, int *value); int bq24193_get_property(enum BQ24193_reg_prop prop, int *value);
void bq24193_enable_charger(); void bq24193_enable_charger();
void bq24193_fake_battery_removal(); void bq24193_fake_battery_removal();
bool bq24193_charger_connected();
#endif /* __BQ24193_H_ */ #endif /* __BQ24193_H_ */

View File

@@ -1,13 +0,0 @@
# HATS Tools Universal Config
# Location: sd:/config/hats-tools/config.ini
# Shared between HATS Tools GUI and hats-installer payload
[hats]
install_mode=default ; options: replace, default, clean
# Mode descriptions:
# replace - Only replace files, no deletion (old files may remain)
# default - Delete /atmosphere only, keep /bootloader and /switch
# clean - Delete /atmosphere, /bootloader, and /switch (fresh install)
#
# All modes will remove HATS-*.txt version files from SD root

View File

@@ -6,14 +6,97 @@
#include "fs.h" #include "fs.h"
#include <libs/fatfs/ff.h> #include <libs/fatfs/ff.h>
#include <string.h> #include <string.h>
#include <stdarg.h>
#include <utils/sprintf.h> #include <utils/sprintf.h>
#define BACKUP_PATH_MAX 270
// Check if file/directory exists // Check if file/directory exists
static bool path_exists(const char *path) { static bool path_exists(const char *path) {
FILINFO fno; FILINFO fno;
return (f_stat(path, &fno) == FR_OK); return (f_stat(path, &fno) == FR_OK);
} }
// Create all parent directories for a path (mkdir -p style)
static void ensure_parent_dirs(const char *full_path) {
char buf[BACKUP_PATH_MAX];
int n = (int)strlen(full_path);
if (n >= BACKUP_PATH_MAX) return;
memcpy(buf, full_path, n + 1);
for (int i = 4; i < n; i++) {
if (buf[i] == '/') {
buf[i] = '\0';
f_mkdir(buf);
buf[i] = '/';
}
}
}
// Copy a single path (file or dir) to backup base, preserving SD structure
static int backup_single_path(const char *src_path, const char *backup_base) {
FILINFO fno;
if (f_stat(src_path, &fno) != FR_OK)
return FR_OK;
const char *relative = src_path;
if (strncmp(relative, "sd:/", 4) == 0)
relative += 4;
if (fno.fattrib & AM_DIR) {
const char *last_slash = strrchr(relative, '/');
char parent[BACKUP_PATH_MAX];
if (last_slash && last_slash > relative) {
s_printf(parent, "%s/%.*s", backup_base, (int)(last_slash - relative), relative);
/* Create full parent hierarchy (e.g. atmosphere, atmosphere/contents) */
ensure_parent_dirs(parent);
f_mkdir(parent); /* Ensure parent exists; FR_EXIST is fine */
return folder_copy(src_path, parent);
} else {
ensure_parent_dirs(backup_base);
return folder_copy(src_path, backup_base);
}
} else {
char dst_path[BACKUP_PATH_MAX];
s_printf(dst_path, "%s/%s", backup_base, relative);
ensure_parent_dirs(dst_path);
return file_copy(src_path, dst_path);
}
}
// Backup all paths from varargs lists (same structure as delete_path_lists_grouped)
int backup_deletion_lists(const char *backup_base, ...) {
va_list ap;
const char **list;
int res = FR_OK;
/* FatFS f_mkdir only creates the last component; parent must exist first */
ensure_parent_dirs(BACKUP_BASE_PATH);
res = f_mkdir(BACKUP_BASE_PATH);
if (res != FR_OK && res != FR_EXIST)
return res;
ensure_parent_dirs(backup_base);
res = f_mkdir(backup_base);
if (res != FR_OK && res != FR_EXIST)
return res;
va_start(ap, backup_base);
while ((list = va_arg(ap, const char **)) != NULL) {
for (int i = 0; list[i] != NULL; i++) {
if (path_exists(list[i])) {
int copy_res = backup_single_path(list[i], backup_base);
if (copy_res != FR_OK && res == FR_OK)
res = copy_res; // Remember first error but keep going
}
}
}
va_end(ap);
/* Best-effort: return FR_OK so install continues even if some copies failed */
return FR_OK;
}
// Backup user data before clean install // Backup user data before clean install
int backup_user_data(void) { int backup_user_data(void) {
int res; int res;

View File

@@ -7,6 +7,8 @@
#include <utils/types.h> #include <utils/types.h>
#define TEMP_BACKUP_PATH "sd:/temp_backup" #define TEMP_BACKUP_PATH "sd:/temp_backup"
#define BACKUP_BASE_PATH "sd:/backup/OmniNX"
#define PRE_OMNINX_LABEL "pre-omninx"
// Backup user data (DBI, Tinfoil, prod.keys) before clean install // Backup user data (DBI, Tinfoil, prod.keys) before clean install
int backup_user_data(void); int backup_user_data(void);
@@ -16,3 +18,6 @@ int restore_user_data(void);
// Clean up temporary backup directory // Clean up temporary backup directory
int cleanup_backup(void); int cleanup_backup(void);
// Backup paths from varargs lists to backup_base (pass path arrays, terminate with NULL)
int backup_deletion_lists(const char *backup_base, ...);

View File

@@ -138,11 +138,6 @@ static const char* clean_switch_dirs_to_delete[] = {
"sd:/switch/ChoiDujourNX", "sd:/switch/ChoiDujourNX",
"sd:/switch/crash_ams", "sd:/switch/crash_ams",
"sd:/switch/Daybreak", "sd:/switch/Daybreak",
"sd:/switch/DBI_658_EN",
"sd:/switch/DBI_810",
"sd:/switch/DBI_810_DE",
"sd:/switch/DBI_810_EN",
"sd:/switch/DBI_RU",
"sd:/switch/DNS_mitm Tester", "sd:/switch/DNS_mitm Tester",
"sd:/switch/EdiZon", "sd:/switch/EdiZon",
"sd:/switch/Fizeau", "sd:/switch/Fizeau",
@@ -208,6 +203,8 @@ static const char* clean_switch_files_to_delete[] = {
"sd:/switch/DBI_810_DE/DBI_810_DE.nro", "sd:/switch/DBI_810_DE/DBI_810_DE.nro",
"sd:/switch/DBI_810_EN/DBI_810_EN.nro", "sd:/switch/DBI_810_EN/DBI_810_EN.nro",
"sd:/switch/DBI_RU/DBI_RU.nro", "sd:/switch/DBI_RU/DBI_RU.nro",
"sd:/switch/DBI/DBI_EN.nro",
"sd:/switch/DBI_DE/DBI_DE.nro",
"sd:/switch/DNS_mitm Tester.nro", "sd:/switch/DNS_mitm Tester.nro",
"sd:/switch/EdiZon.nro", "sd:/switch/EdiZon.nro",
"sd:/switch/Fizeau.nro", "sd:/switch/Fizeau.nro",

View File

@@ -1,284 +1,281 @@
/* /*
* OmniNX Installer - Deletion Lists for Update Mode * OmniNX Installer - Deletion Lists for Update Mode
* Selective deletion when OmniNX is already installed. * Selective deletion when OmniNX is already installed.
*/ */
#pragma once #pragma once
// Atmosphere subdirectories to delete // Atmosphere subdirectories to delete
static const char* atmosphere_dirs_to_delete[] = { static const char* atmosphere_dirs_to_delete[] = {
"sd:/atmosphere/config", "sd:/atmosphere/config",
"sd:/atmosphere/crash_reports", "sd:/atmosphere/crash_reports",
"sd:/atmosphere/erpt_reports", "sd:/atmosphere/erpt_reports",
"sd:/atmosphere/exefs_patches/CrunchPatch", "sd:/atmosphere/exefs_patches/CrunchPatch",
"sd:/atmosphere/exefs_patches/Crunchyroll Patch 1.10.0", "sd:/atmosphere/exefs_patches/Crunchyroll Patch 1.10.0",
"sd:/atmosphere/exefs_patches/bluetooth_patches", "sd:/atmosphere/exefs_patches/bluetooth_patches",
"sd:/atmosphere/exefs_patches/bootlogo", "sd:/atmosphere/exefs_patches/bootlogo",
"sd:/atmosphere/exefs_patches/btm_patches", "sd:/atmosphere/exefs_patches/btm_patches",
"sd:/atmosphere/exefs_patches/es_patches", "sd:/atmosphere/exefs_patches/es_patches",
"sd:/atmosphere/exefs_patches/hid_patches", "sd:/atmosphere/exefs_patches/hid_patches",
"sd:/atmosphere/exefs_patches/logo1", "sd:/atmosphere/exefs_patches/logo1",
"sd:/atmosphere/exefs_patches/nfim_ctest", "sd:/atmosphere/exefs_patches/nfim_ctest",
"sd:/atmosphere/exefs_patches/nim_ctest", "sd:/atmosphere/exefs_patches/nim_ctest",
"sd:/atmosphere/exefs_patches/nvnflinger_cmu", "sd:/atmosphere/exefs_patches/nvnflinger_cmu",
"sd:/atmosphere/extrazz", "sd:/atmosphere/extrazz",
"sd:/atmosphere/fatal_errors", "sd:/atmosphere/fatal_errors",
"sd:/atmosphere/fatal_reports", "sd:/atmosphere/fatal_reports",
"sd:/atmosphere/flags", "sd:/atmosphere/flags",
"sd:/atmosphere/hbl_html", "sd:/atmosphere/hbl_html",
"sd:/atmosphere/hosts", "sd:/atmosphere/hosts",
"sd:/atmosphere/kips", "sd:/atmosphere/kips",
"sd:/atmosphere/kip1", "sd:/atmosphere/kip1",
"sd:/atmosphere/kip_patches", "sd:/atmosphere/kip_patches",
"sd:/atmosphere/logs", "sd:/atmosphere/logs",
NULL NULL
}; };
// Atmosphere contents directories (title IDs; only under atmosphere/contents/) // Atmosphere contents directories (title IDs; only under atmosphere/contents/)
static const char* atmosphere_contents_dirs_to_delete[] = { static const char* atmosphere_contents_dirs_to_delete[] = {
"sd:/atmosphere/contents/0000000000534C56", "sd:/atmosphere/contents/0000000000534C56",
"sd:/atmosphere/contents/00FF0000B378D640", "sd:/atmosphere/contents/00FF0000B378D640",
"sd:/atmosphere/contents/00FF0000636C6BFF", "sd:/atmosphere/contents/00FF0000636C6BFF",
"sd:/atmosphere/contents/00FF0000A53BB665", "sd:/atmosphere/contents/00FF0000A53BB665",
"sd:/atmosphere/contents/0100000000000008", "sd:/atmosphere/contents/0100000000000008",
"sd:/atmosphere/contents/010000000000000D", "sd:/atmosphere/contents/010000000000000D",
"sd:/atmosphere/contents/010000000000002B", "sd:/atmosphere/contents/010000000000002B",
"sd:/atmosphere/contents/0100000000000032", "sd:/atmosphere/contents/0100000000000032",
"sd:/atmosphere/contents/0100000000000034", "sd:/atmosphere/contents/0100000000000034",
"sd:/atmosphere/contents/0100000000000036", "sd:/atmosphere/contents/0100000000000036",
"sd:/atmosphere/contents/0100000000000037", "sd:/atmosphere/contents/0100000000000037",
"sd:/atmosphere/contents/010000000000003C", "sd:/atmosphere/contents/010000000000003C",
"sd:/atmosphere/contents/0100000000000042", "sd:/atmosphere/contents/0100000000000042",
"sd:/atmosphere/contents/0100000000000895", "sd:/atmosphere/contents/0100000000000895",
"sd:/atmosphere/contents/0100000000000F12", "sd:/atmosphere/contents/0100000000000F12",
"sd:/atmosphere/contents/0100000000001000", "sd:/atmosphere/contents/0100000000001000",
"sd:/atmosphere/contents/0100000000001007", "sd:/atmosphere/contents/0100000000001007",
"sd:/atmosphere/contents/0100000000001013", "sd:/atmosphere/contents/0100000000001013",
"sd:/atmosphere/contents/010000000000DA7A", "sd:/atmosphere/contents/010000000000DA7A",
"sd:/atmosphere/contents/010000000000bd00", "sd:/atmosphere/contents/010000000000bd00",
"sd:/atmosphere/contents/01006a800016e000", "sd:/atmosphere/contents/01006a800016e000",
"sd:/atmosphere/contents/01009D901BC56000", "sd:/atmosphere/contents/01009D901BC56000",
"sd:/atmosphere/contents/0100A3900C3E2000", "sd:/atmosphere/contents/0100A3900C3E2000",
"sd:/atmosphere/contents/0100F43008C44000", "sd:/atmosphere/contents/0100F43008C44000",
"sd:/atmosphere/contents/050000BADDAD0000", "sd:/atmosphere/contents/050000BADDAD0000",
"sd:/atmosphere/contents/4200000000000000", "sd:/atmosphere/contents/4200000000000000",
"sd:/atmosphere/contents/420000000000000B", "sd:/atmosphere/contents/420000000000000B",
"sd:/atmosphere/contents/420000000000000E", "sd:/atmosphere/contents/420000000000000E",
"sd:/atmosphere/contents/4200000000000010", "sd:/atmosphere/contents/4200000000000010",
"sd:/atmosphere/contents/4200000000000FFF", "sd:/atmosphere/contents/4200000000000FFF",
"sd:/atmosphere/contents/420000000007E51A", "sd:/atmosphere/contents/420000000007E51A",
"sd:/atmosphere/contents/420000000007E51B", "sd:/atmosphere/contents/420000000007E51B",
"sd:/atmosphere/contents/690000000000000D", "sd:/atmosphere/contents/690000000000000D",
NULL NULL
}; };
// Atmosphere files to delete // Atmosphere files to delete
static const char* atmosphere_files_to_delete[] = { static const char* atmosphere_files_to_delete[] = {
"sd:/atmosphere/config/exosphere.ini", "sd:/atmosphere/config/exosphere.ini",
"sd:/atmosphere/config/stratosphere.ini", "sd:/atmosphere/config/stratosphere.ini",
"sd:/atmosphere/hbl.nsp", "sd:/atmosphere/hbl.nsp",
"sd:/atmosphere/package3", "sd:/atmosphere/package3",
"sd:/atmosphere/reboot_payload.bin", "sd:/atmosphere/reboot_payload.bin",
"sd:/atmosphere/stratosphere.romfs", "sd:/atmosphere/stratosphere.romfs",
NULL NULL
}; };
// Bootloader directories to delete // Bootloader directories to delete
static const char* bootloader_dirs_to_delete[] = { static const char* bootloader_dirs_to_delete[] = {
"sd:/bootloader/boot", "sd:/bootloader/boot",
"sd:/bootloader/bootlogo", "sd:/bootloader/bootlogo",
"sd:/bootloader/ini2", "sd:/bootloader/ini2",
"sd:/bootloader/payloads", "sd:/bootloader/payloads",
"sd:/bootloader/reboot", "sd:/bootloader/reboot",
"sd:/bootloader/res", "sd:/bootloader/res",
"sd:/bootloader/sys", "sd:/bootloader/sys",
NULL NULL
}; };
// Bootloader files to delete // Bootloader files to delete
static const char* bootloader_files_to_delete[] = { static const char* bootloader_files_to_delete[] = {
"sd:/bootloader/ArgonNX.bin", "sd:/bootloader/ArgonNX.bin",
"sd:/bootloader/bootlogo.bmp", "sd:/bootloader/bootlogo.bmp",
"sd:/bootloader/hekate_ipl.ini", "sd:/bootloader/hekate_ipl.ini",
"sd:/bootloader/nyx.ini", "sd:/bootloader/nyx.ini",
"sd:/bootloader/patches.ini", "sd:/bootloader/patches.ini",
"sd:/bootloader/update.bin", "sd:/bootloader/update.bin",
"sd:/bootloader/ini/EmuMMC ohne Mods.ini", "sd:/bootloader/ini/EmuMMC ohne Mods.ini",
NULL NULL
}; };
// Config directories to delete // Config directories to delete
static const char* config_dirs_to_delete[] = { static const char* config_dirs_to_delete[] = {
"sd:/config/aio-switch-updater", "sd:/config/aio-switch-updater",
"sd:/config/blue_pack_updater", "sd:/config/blue_pack_updater",
"sd:/config/kefir-updater", "sd:/config/kefir-updater",
"sd:/config/nx-hbmenu", "sd:/config/nx-hbmenu",
"sd:/config/quickntp", "sd:/config/quickntp",
"sd:/config/sys-con", "sd:/config/sys-con",
"sd:/config/sys-patch", "sd:/config/sys-patch",
"sd:/config/uberhand", "sd:/config/uberhand",
"sd:/config/ultrahand", "sd:/config/ultrahand",
NULL NULL
}; };
// Switch directories to delete // Switch directories to delete
static const char* switch_dirs_to_delete[] = { // NOTE: .packages is intentionally excluded - UltraHand package cache, preserve during updates
"sd:/switch/.overlays", static const char* switch_dirs_to_delete[] = {
"sd:/switch/.packages", "sd:/switch/.overlays",
"sd:/switch/90DNS_tester", "sd:/switch/90DNS_tester",
"sd:/switch/aio-switch-updater", "sd:/switch/aio-switch-updater",
"sd:/switch/amsPLUS-downloader", "sd:/switch/amsPLUS-downloader",
"sd:/switch/appstore", "sd:/switch/appstore",
"sd:/switch/AtmoXL-Titel-Installer", "sd:/switch/AtmoXL-Titel-Installer",
"sd:/switch/breeze", "sd:/switch/breeze",
"sd:/switch/checkpoint", "sd:/switch/checkpoint",
"sd:/switch/cheats-updater", "sd:/switch/cheats-updater",
"sd:/switch/chiaki", "sd:/switch/chiaki",
"sd:/switch/ChoiDujourNX", "sd:/switch/ChoiDujourNX",
"sd:/switch/crash_ams", "sd:/switch/crash_ams",
"sd:/switch/Daybreak", "sd:/switch/Daybreak",
"sd:/switch/DBI_658_EN", "sd:/switch/DNS_mitm Tester",
"sd:/switch/DBI_810", "sd:/switch/EdiZon",
"sd:/switch/DBI_810_DE", "sd:/switch/Fizeau",
"sd:/switch/DBI_810_EN", "sd:/switch/FTPD",
"sd:/switch/DBI_RU", "sd:/switch/fw-downloader",
"sd:/switch/DNS_mitm Tester", "sd:/switch/gamecard_installer",
"sd:/switch/EdiZon", "sd:/switch/Goldleaf",
"sd:/switch/Fizeau", "sd:/switch/haze",
"sd:/switch/FTPD", "sd:/switch/JKSV",
"sd:/switch/fw-downloader", "sd:/switch/kefir-updater",
"sd:/switch/gamecard_installer", "sd:/switch/ldnmitm_config",
"sd:/switch/Goldleaf", "sd:/switch/Linkalho",
"sd:/switch/haze", "sd:/switch/Moonlight-Switch",
"sd:/switch/JKSV", "sd:/switch/Neumann",
"sd:/switch/kefir-updater", "sd:/switch/NX-Activity-Log",
"sd:/switch/ldnmitm_config", "sd:/switch/NX-Save-Sync",
"sd:/switch/Linkalho", "sd:/switch/NX-Shell",
"sd:/switch/Moonlight-Switch", "sd:/switch/NX-Update-Checker ",
"sd:/switch/Neumann", "sd:/switch/NXGallery",
"sd:/switch/NX-Activity-Log", "sd:/switch/NXRemoteLauncher",
"sd:/switch/NX-Save-Sync", "sd:/switch/NXThemesInstaller",
"sd:/switch/NX-Shell", "sd:/switch/nxdumptool",
"sd:/switch/NX-Update-Checker ", "sd:/switch/nxmtp",
"sd:/switch/NXGallery", "sd:/switch/Payload_launcher",
"sd:/switch/NXRemoteLauncher", "sd:/switch/Reboot",
"sd:/switch/NXThemesInstaller", "sd:/switch/reboot_to_argonNX",
"sd:/switch/nxdumptool", "sd:/switch/reboot_to_hekate",
"sd:/switch/nxmtp", "sd:/switch/Shutdown_System",
"sd:/switch/Payload_launcher", "sd:/switch/SimpleModDownloader",
"sd:/switch/Reboot", "sd:/switch/SimpleModManager",
"sd:/switch/reboot_to_argonNX", "sd:/switch/sphaira",
"sd:/switch/reboot_to_hekate", "sd:/switch/studious-pancake",
"sd:/switch/Shutdown_System", "sd:/switch/Switch-Time",
"sd:/switch/SimpleModDownloader", "sd:/switch/SwitchIdent",
"sd:/switch/SimpleModManager", "sd:/switch/Switch_themes_Installer",
"sd:/switch/sphaira", "sd:/switch/Switchfin",
"sd:/switch/studious-pancake", "sd:/switch/Sys-Clk Manager",
"sd:/switch/Switch-Time", "sd:/switch/Sys-Con",
"sd:/switch/SwitchIdent", "sd:/switch/sys-clk-manager",
"sd:/switch/Switch_themes_Installer", "sd:/switch/themezer-nx",
"sd:/switch/Switchfin", "sd:/switch/themezernx",
"sd:/switch/Sys-Clk Manager", "sd:/switch/tinwoo",
"sd:/switch/Sys-Con", NULL
"sd:/switch/sys-clk-manager", };
"sd:/switch/themezer-nx",
"sd:/switch/themezernx", // Switch files (NRO) to delete
"sd:/switch/tinwoo", static const char* switch_files_to_delete[] = {
NULL "sd:/switch/90DNS_tester/90DNS_tester.nro",
}; "sd:/switch/breeze.nro",
"sd:/switch/cheats-updater.nro",
// Switch files (NRO) to delete "sd:/switch/chiaki.nro",
static const char* switch_files_to_delete[] = { "sd:/switch/ChoiDujourNX.nro",
"sd:/switch/90DNS_tester/90DNS_tester.nro", "sd:/switch/daybreak.nro",
"sd:/switch/breeze.nro", "sd:/switch/DBI.nro",
"sd:/switch/cheats-updater.nro", "sd:/switch/DBI/DBI.nro",
"sd:/switch/chiaki.nro", "sd:/switch/DBI/DBI_810_DE.nro",
"sd:/switch/ChoiDujourNX.nro", "sd:/switch/DBI/DBI_810_EN.nro",
"sd:/switch/daybreak.nro", "sd:/switch/DBI/DBI_845_DE.nro",
"sd:/switch/DBI.nro", "sd:/switch/DBI/DBI_845_EN.nro",
"sd:/switch/DBI/DBI.nro", "sd:/switch/DBI/DBI_849_DE.nro",
"sd:/switch/DBI/DBI_810_DE.nro", "sd:/switch/DBI/DBI_849_EN.nro",
"sd:/switch/DBI/DBI_810_EN.nro", "sd:/switch/DBI_810_DE/DBI_810.nro",
"sd:/switch/DBI/DBI_845_DE.nro", "sd:/switch/DBI_810_DE/DBI_810_DE.nro",
"sd:/switch/DBI/DBI_845_EN.nro", "sd:/switch/DBI_810_EN/DBI_810_EN.nro",
"sd:/switch/DBI/DBI_849_DE.nro", "sd:/switch/DBI_RU/DBI_RU.nro",
"sd:/switch/DBI/DBI_849_EN.nro", "sd:/switch/DBI/DBI_EN.nro",
"sd:/switch/DBI_810_DE/DBI_810.nro", "sd:/switch/DBI_DE/DBI_DE.nro",
"sd:/switch/DBI_810_DE/DBI_810_DE.nro", "sd:/switch/DNS_mitm Tester.nro",
"sd:/switch/DBI_810_EN/DBI_810_EN.nro", "sd:/switch/EdiZon.nro",
"sd:/switch/DBI_RU/DBI_RU.nro", "sd:/switch/Fizeau.nro",
"sd:/switch/DNS_mitm Tester.nro", "sd:/switch/Goldleaf.nro",
"sd:/switch/EdiZon.nro", "sd:/switch/haze.nro",
"sd:/switch/Fizeau.nro", "sd:/switch/JKSV.nro",
"sd:/switch/Goldleaf.nro", "sd:/switch/ldnmitm_config.nro",
"sd:/switch/haze.nro", "sd:/switch/linkalho.nro",
"sd:/switch/JKSV.nro", "sd:/switch/Moonlight-Switch.nro",
"sd:/switch/ldnmitm_config.nro", "sd:/switch/Neumann.nro",
"sd:/switch/linkalho.nro", "sd:/switch/NX-Shell.nro",
"sd:/switch/Moonlight-Switch.nro", "sd:/switch/NXGallery.nro",
"sd:/switch/Neumann.nro", "sd:/switch/NXThemesInstaller.nro",
"sd:/switch/NX-Shell.nro", "sd:/switch/nxdumptool.nro",
"sd:/switch/NXGallery.nro", "sd:/switch/nxtc.bin",
"sd:/switch/NXThemesInstaller.nro", "sd:/switch/reboot_to_payload.nro",
"sd:/switch/nxdumptool.nro", "sd:/switch/SimpleModDownloader.nro",
"sd:/switch/nxtc.bin", "sd:/switch/SimpleModManager.nro",
"sd:/switch/reboot_to_payload.nro", "sd:/switch/sphaira.nro",
"sd:/switch/SimpleModDownloader.nro", "sd:/switch/SwitchIdent.nro",
"sd:/switch/SimpleModManager.nro", "sd:/switch/Switch_themes_Installer/NXThemesInstaller.nro",
"sd:/switch/sphaira.nro", "sd:/switch/Switchfin.nro",
"sd:/switch/SwitchIdent.nro", "sd:/switch/Sys-Clk Manager/sys-clk-manager.nro",
"sd:/switch/Switch_themes_Installer/NXThemesInstaller.nro", "sd:/switch/Sys-Con.nro",
"sd:/switch/Switchfin.nro", "sd:/switch/sys-clk-manager.nro",
"sd:/switch/Sys-Clk Manager/sys-clk-manager.nro", "sd:/switch/tinfoil.nro",
"sd:/switch/Sys-Con.nro", "sd:/switch/tinfoil/tinfoil.nro",
"sd:/switch/sys-clk-manager.nro", "sd:/switch/tinwoo.nro",
"sd:/switch/tinfoil.nro", "sd:/switch/tinwoo/tinwoo.nro",
"sd:/switch/tinfoil/tinfoil.nro", NULL
"sd:/switch/tinwoo.nro", };
"sd:/switch/tinwoo/tinwoo.nro",
NULL // Root CFW files to delete
}; static const char* root_files_to_delete[] = {
"sd:/boot.dat",
// Root CFW files to delete "sd:/boot.ini",
static const char* root_files_to_delete[] = { "sd:/exosphere.bin",
"sd:/boot.dat", "sd:/exosphere.ini",
"sd:/boot.ini", "sd:/hbmenu.nro",
"sd:/exosphere.bin", "sd:/install.bat",
"sd:/exosphere.ini", "sd:/license",
"sd:/hbmenu.nro", "sd:/loader.bin",
"sd:/install.bat", "sd:/mc-mitm.log",
"sd:/license", "sd:/payload.bin",
"sd:/loader.bin", "sd:/update.bin",
"sd:/mc-mitm.log", "sd:/version",
"sd:/payload.bin", NULL
"sd:/update.bin", };
"sd:/version",
NULL // Miscellaneous directories to delete
}; static const char* misc_dirs_to_delete[] = {
"sd:/argon",
// Miscellaneous directories to delete "sd:/games",
static const char* misc_dirs_to_delete[] = { "sd:/NSPs (Tools)",
"sd:/argon", "sd:/Patched Apps",
"sd:/games", "sd:/SaltySD/flags",
"sd:/NSPs (Tools)", "sd:/scripts",
"sd:/Patched Apps", "sd:/switch/tinfoil/db",
"sd:/SaltySD/flags", "sd:/tools",
"sd:/scripts", "sd:/warmboot_mariko",
"sd:/switch/tinfoil/db", NULL
"sd:/tools", };
"sd:/warmboot_mariko",
NULL // Miscellaneous files to delete
}; static const char* misc_files_to_delete[] = {
"sd:/fusee-primary.bin",
// Miscellaneous files to delete "sd:/fusee.bin",
static const char* misc_files_to_delete[] = { "sd:/SaltySD/exceptions.txt",
"sd:/fusee-primary.bin", "sd:/SaltySD/saltysd_bootstrap.elf",
"sd:/fusee.bin", "sd:/SaltySD/saltysd_bootstrap32_3k.elf",
"sd:/SaltySD/exceptions.txt", "sd:/SaltySD/saltysd_bootstrap32_5k.elf",
"sd:/SaltySD/saltysd_bootstrap.elf", "sd:/SaltySD/saltysd_core.elf",
"sd:/SaltySD/saltysd_bootstrap32_3k.elf", "sd:/SaltySD/saltysd_core32.elf",
"sd:/SaltySD/saltysd_bootstrap32_5k.elf", NULL
"sd:/SaltySD/saltysd_core.elf", };
"sd:/SaltySD/saltysd_core32.elf",
NULL
};

View File

@@ -1,5 +1,6 @@
/* /*
* HATS Installer - Filesystem operations with file logging * OmniNX Installer - Filesystem operations with file logging
* Based on HATS Installer
*/ */
#include "fs.h" #include "fs.h"
@@ -23,7 +24,7 @@ void log_init(const char *path) {
int res = f_open(&log_file, path, FA_WRITE | FA_CREATE_ALWAYS); int res = f_open(&log_file, path, FA_WRITE | FA_CREATE_ALWAYS);
if (res == FR_OK) { if (res == FR_OK) {
log_enabled = true; log_enabled = true;
log_write("=== HATS Installer Log ===\n\n"); log_write("=== OmniNX Installer Log ===\n\n");
} }
} }

View File

@@ -1,5 +1,6 @@
/* /*
* HATS Installer - Filesystem operations * OmniNX Installer - Filesystem operations
* Based on HATS Installer
*/ */
#pragma once #pragma once

View File

@@ -7,9 +7,12 @@
#include "version.h" #include "version.h"
#include "gfx.h" #include "gfx.h"
#include <libs/fatfs/ff.h> #include <libs/fatfs/ff.h>
#include <stdarg.h>
#include <string.h> #include <string.h>
#include <utils/sprintf.h> #include <utils/sprintf.h>
#define GROUPED_DELETE_MAX_ENTRIES 512
#ifndef VERSION #ifndef VERSION
#define VERSION "1.0.0" #define VERSION "1.0.0"
#endif #endif
@@ -395,6 +398,89 @@ int folder_delete_single_with_progress(const char *path, const char *display_nam
} }
// Delete a list of paths with progress tracking // Delete a list of paths with progress tracking
// Delete multiple path lists under one label; one progress line "Bereinige: folder/ [p%] (d/t)".
// Varargs: path lists (const char**), terminated by NULL.
int delete_path_lists_grouped(const char *folder_display_name, ...) {
va_list ap;
const char *entries[GROUPED_DELETE_MAX_ENTRIES];
int n_entries = 0;
int deleted = 0;
int failed = 0;
u32 start_x, start_y;
int last_percent = -1;
int res;
va_start(ap, folder_display_name);
const char **list;
while (n_entries < GROUPED_DELETE_MAX_ENTRIES && (list = va_arg(ap, const char **)) != NULL) {
for (int i = 0; list[i] != NULL && n_entries < GROUPED_DELETE_MAX_ENTRIES; i++) {
if (install_path_exists(list[i]))
entries[n_entries++] = list[i];
}
}
va_end(ap);
if (n_entries == 0)
return FR_OK;
int total_paths = n_entries;
gfx_con_getpos(&start_x, &start_y);
install_set_color(COLOR_CYAN);
gfx_printf(" Bereinige: %s [ 0%%] (0/%d)", folder_display_name, total_paths);
install_set_color(COLOR_WHITE);
for (int i = 0; i < n_entries; i++) {
const char *path = entries[i];
FILINFO fno;
if (f_stat(path, &fno) != FR_OK)
continue;
const char *item_name = strrchr(path, '/');
if (item_name) item_name++;
else item_name = path;
if (fno.fattrib & AM_DIR) {
int item_count = install_count_directory_items(path);
if (item_count > 50) {
gfx_printf("\n");
res = folder_delete_single_with_progress(path, item_name);
} else {
res = folder_delete(path);
}
} else {
if (fno.fattrib & AM_RDO)
f_chmod(path, fno.fattrib & ~AM_RDO, AM_RDO);
res = f_unlink(path);
}
if (res == FR_OK || res == FR_NO_FILE)
deleted++;
else
failed++;
int percent = (deleted * 100) / total_paths;
if (percent != last_percent || deleted % 5 == 0) {
gfx_con_setpos(start_x, start_y);
install_set_color(COLOR_CYAN);
gfx_printf(" Bereinige: %s [%3d%%] (%d/%d)", folder_display_name, percent, deleted, total_paths);
install_set_color(COLOR_WHITE);
last_percent = percent;
}
}
gfx_con_setpos(start_x, start_y);
if (failed == 0) {
install_set_color(COLOR_GREEN);
gfx_printf(" Bereinige: %s [100%%] (%d/%d) - Fertig!\n", folder_display_name, deleted, total_paths);
install_set_color(COLOR_WHITE);
} else {
install_set_color(COLOR_ORANGE);
gfx_printf(" Bereinige: %s [%3d%%] (%d/%d) - %d Fehler\n", folder_display_name, last_percent, deleted, total_paths, failed);
install_set_color(COLOR_WHITE);
}
return (failed == 0) ? FR_OK : FR_DISK_ERR;
}
int delete_path_list(const char* paths[], const char* description) { int delete_path_list(const char* paths[], const char* description) {
int res; int res;
int deleted = 0; int deleted = 0;
@@ -505,9 +591,29 @@ int perform_installation(omninx_variant_t pack_variant, install_mode_t mode) {
int res; int res;
if (mode == INSTALL_MODE_UPDATE) { if (mode == INSTALL_MODE_UPDATE) {
// Update mode: selective cleanup then install // Update mode: backup, selective cleanup, then install
omninx_status_t status = detect_omninx_installation();
const char *version = (status.version_file[0] != '\0') ? status.version_file : "unknown";
install_set_color(COLOR_YELLOW); install_set_color(COLOR_YELLOW);
gfx_printf("Schritt 1: Bereinigung...\n"); gfx_printf("Schritt 1: Backup vor Update (%s)...\n", version);
install_set_color(COLOR_WHITE);
res = backup_before_update(version);
/* Backup is best-effort; continue install even on failure */
if (res == FR_OK) {
install_set_color(COLOR_GREEN);
gfx_printf(" [OK] Sicherung nach sd:/backup/OmniNX/%s/\n", version);
install_set_color(COLOR_WHITE);
} else {
install_set_color(COLOR_ORANGE);
gfx_printf(" [WARN] Backup fehlgeschlagen, fahre trotzdem fort...\n");
install_set_color(COLOR_WHITE);
}
install_check_and_clear_screen_if_needed();
gfx_printf("\n");
install_set_color(COLOR_YELLOW);
gfx_printf("Schritt 2: Bereinigung...\n");
install_set_color(COLOR_WHITE); install_set_color(COLOR_WHITE);
res = update_mode_cleanup(pack_variant); res = update_mode_cleanup(pack_variant);
if (res != FR_OK) return res; if (res != FR_OK) return res;
@@ -515,17 +621,20 @@ int perform_installation(omninx_variant_t pack_variant, install_mode_t mode) {
install_check_and_clear_screen_if_needed(); install_check_and_clear_screen_if_needed();
gfx_printf("\n"); gfx_printf("\n");
install_set_color(COLOR_YELLOW); install_set_color(COLOR_YELLOW);
gfx_printf("Schritt 2: Dateien kopieren...\n"); gfx_printf("Schritt 3: Dateien kopieren...\n");
install_set_color(COLOR_WHITE); install_set_color(COLOR_WHITE);
res = update_mode_install(pack_variant); res = update_mode_install(pack_variant);
if (res != FR_OK) return res; if (res != FR_OK) return res;
install_check_and_clear_screen_if_needed(); install_check_and_clear_screen_if_needed();
// Remove staging directory // Remove staging directory (installed pack)
res = cleanup_staging_directory(pack_variant); res = cleanup_staging_directory(pack_variant);
if (res != FR_OK) return res;
// Remove other detected install directories (Standard/Light/OC) that were on SD
res = cleanup_other_staging_directories(pack_variant);
return res; return res;
} else { } else {
// Clean mode: backup, wipe, restore, install // Clean mode: backup user data, backup pre-omninx, wipe, restore, install
install_set_color(COLOR_YELLOW); install_set_color(COLOR_YELLOW);
gfx_printf("Schritt 1: Sichere Benutzerdaten...\n"); gfx_printf("Schritt 1: Sichere Benutzerdaten...\n");
install_set_color(COLOR_WHITE); install_set_color(COLOR_WHITE);
@@ -535,7 +644,23 @@ int perform_installation(omninx_variant_t pack_variant, install_mode_t mode) {
install_check_and_clear_screen_if_needed(); install_check_and_clear_screen_if_needed();
gfx_printf("\n"); gfx_printf("\n");
install_set_color(COLOR_YELLOW); install_set_color(COLOR_YELLOW);
gfx_printf("Schritt 2: Bereinige alte Installation...\n"); gfx_printf("Schritt 2: Backup alter CFW-Dateien (pre-omninx)...\n");
install_set_color(COLOR_WHITE);
res = backup_before_clean();
if (res == FR_OK) {
install_set_color(COLOR_GREEN);
gfx_printf(" [OK] Sicherung nach sd:/backup/OmniNX/pre-omninx/\n");
install_set_color(COLOR_WHITE);
} else {
install_set_color(COLOR_ORANGE);
gfx_printf(" [WARN] Backup fehlgeschlagen, fahre trotzdem fort...\n");
install_set_color(COLOR_WHITE);
}
install_check_and_clear_screen_if_needed();
gfx_printf("\n");
install_set_color(COLOR_YELLOW);
gfx_printf("Schritt 3: Bereinige alte Installation...\n");
install_set_color(COLOR_WHITE); install_set_color(COLOR_WHITE);
res = clean_mode_wipe(); res = clean_mode_wipe();
if (res != FR_OK) return res; if (res != FR_OK) return res;
@@ -543,7 +668,7 @@ int perform_installation(omninx_variant_t pack_variant, install_mode_t mode) {
install_check_and_clear_screen_if_needed(); install_check_and_clear_screen_if_needed();
gfx_printf("\n"); gfx_printf("\n");
install_set_color(COLOR_YELLOW); install_set_color(COLOR_YELLOW);
gfx_printf("Schritt 3: Stelle Benutzerdaten wieder her...\n"); gfx_printf("Schritt 4: Stelle Benutzerdaten wieder her...\n");
install_set_color(COLOR_WHITE); install_set_color(COLOR_WHITE);
res = clean_mode_restore(); res = clean_mode_restore();
if (res != FR_OK) return res; if (res != FR_OK) return res;
@@ -551,14 +676,17 @@ int perform_installation(omninx_variant_t pack_variant, install_mode_t mode) {
install_check_and_clear_screen_if_needed(); install_check_and_clear_screen_if_needed();
gfx_printf("\n"); gfx_printf("\n");
install_set_color(COLOR_YELLOW); install_set_color(COLOR_YELLOW);
gfx_printf("Schritt 4: Dateien kopieren...\n"); gfx_printf("Schritt 5: Dateien kopieren...\n");
install_set_color(COLOR_WHITE); install_set_color(COLOR_WHITE);
res = clean_mode_install(pack_variant); res = clean_mode_install(pack_variant);
if (res != FR_OK) return res; if (res != FR_OK) return res;
install_check_and_clear_screen_if_needed(); install_check_and_clear_screen_if_needed();
// Remove staging directory // Remove staging directory (installed pack)
res = cleanup_staging_directory(pack_variant); res = cleanup_staging_directory(pack_variant);
if (res != FR_OK) return res;
// Remove other detected install directories (Standard/Light/OC) that were on SD
res = cleanup_other_staging_directories(pack_variant);
return res; return res;
} }
} }

View File

@@ -17,11 +17,15 @@ typedef enum {
int perform_installation(omninx_variant_t pack_variant, install_mode_t mode); int perform_installation(omninx_variant_t pack_variant, install_mode_t mode);
// Update mode operations (install_update.c) // Update mode operations (install_update.c)
int backup_before_update(const char *version);
int update_mode_cleanup(omninx_variant_t variant); int update_mode_cleanup(omninx_variant_t variant);
int update_mode_install(omninx_variant_t variant); int update_mode_install(omninx_variant_t variant);
int cleanup_staging_directory(omninx_variant_t pack_variant); int cleanup_staging_directory(omninx_variant_t pack_variant);
// Remove other OmniNX staging directories (Standard/Light/OC) that exist, except the one just installed
int cleanup_other_staging_directories(omninx_variant_t installed_variant);
// Clean install operations (install_clean.c) // Clean install operations (install_clean.c)
int backup_before_clean(void);
int clean_mode_backup(void); int clean_mode_backup(void);
int clean_mode_wipe(void); int clean_mode_wipe(void);
int clean_mode_restore(void); int clean_mode_restore(void);
@@ -34,6 +38,7 @@ bool install_path_exists(const char *path);
int install_count_directory_items(const char *path); int install_count_directory_items(const char *path);
void install_combine_path(char *result, size_t size, const char *base, const char *add); void install_combine_path(char *result, size_t size, const char *base, const char *add);
int delete_path_list(const char* paths[], const char* description); int delete_path_list(const char* paths[], const char* description);
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_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_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); int folder_copy_with_progress_v2(const char *src, const char *dst, const char *display_name);

View File

@@ -1,111 +1,186 @@
/* /*
* OmniNX Installer - Clean Install Mode * OmniNX Installer - Clean Install Mode
* Backup, selective cleanup from list, restore, then install when no OmniNX found. * Backup, selective cleanup from list, restore, then install when no OmniNX found.
* Does not wipe whole card; only paths in deletion_lists_clean.h are removed. * Does not wipe whole card; only paths in deletion_lists_clean.h are removed.
*/ */
#include "install.h" #include "install.h"
#include "backup.h" #include "backup.h"
#include "deletion_lists_clean.h" #include "deletion_lists_clean.h"
#include "fs.h" #include "fs.h"
#include "gfx.h" #include "gfx.h"
#include <libs/fatfs/ff.h> #include "version.h"
#include <libs/fatfs/ff.h>
#undef COLOR_CYAN #include <utils/sprintf.h>
#undef COLOR_WHITE #include <string.h>
#undef COLOR_GREEN
#undef COLOR_RED #undef COLOR_CYAN
#define COLOR_CYAN 0xFF00FFFF #undef COLOR_WHITE
#define COLOR_WHITE 0xFFFFFFFF #undef COLOR_GREEN
#define COLOR_GREEN 0xFF00FF00 #undef COLOR_RED
#define COLOR_RED 0xFFFF0000 #undef COLOR_YELLOW
#undef COLOR_ORANGE
#define set_color install_set_color #define COLOR_CYAN 0xFF00FFFF
#define check_and_clear_screen_if_needed install_check_and_clear_screen_if_needed #define COLOR_WHITE 0xFFFFFFFF
#define path_exists install_path_exists #define COLOR_GREEN 0xFF00FF00
#define COLOR_RED 0xFFFF0000
// Clean mode: Backup user data #define COLOR_YELLOW 0xFFFFDD00
int clean_mode_backup(void) { #define COLOR_ORANGE 0xFF00A5FF
set_color(COLOR_CYAN);
gfx_printf(" Sichere: DBI, Tinfoil, prod.keys\n"); #define set_color install_set_color
set_color(COLOR_WHITE); #define check_and_clear_screen_if_needed install_check_and_clear_screen_if_needed
int res = backup_user_data(); #define path_exists install_path_exists
if (res == FR_OK) { #define count_directory_items install_count_directory_items
set_color(COLOR_GREEN);
gfx_printf(" [OK] Sicherung abgeschlossen\n"); // Backup paths before clean install (sd:/backup/OmniNX/pre-omninx)
set_color(COLOR_WHITE); int backup_before_clean(void) {
} char backup_base[270];
return res; s_printf(backup_base, "%s/%s", BACKUP_BASE_PATH, PRE_OMNINX_LABEL);
} return backup_deletion_lists(backup_base,
clean_atmosphere_dirs_to_delete,
// Clean mode: Wipe using selective deletion list (does not wipe whole card) clean_atmosphere_contents_dirs_to_delete,
int clean_mode_wipe(void) { clean_atmosphere_files_to_delete,
check_and_clear_screen_if_needed(); clean_bootloader_dirs_to_delete,
clean_bootloader_files_to_delete,
set_color(COLOR_CYAN); clean_config_dirs_to_delete,
gfx_printf(" Bereinige: atmosphere/\n"); clean_switch_dirs_to_delete,
set_color(COLOR_WHITE); clean_switch_files_to_delete,
delete_path_list(clean_atmosphere_dirs_to_delete, "atmosphere subdirs"); clean_root_files_to_delete,
delete_path_list(clean_atmosphere_contents_dirs_to_delete, "atmosphere contents dirs"); clean_misc_dirs_to_delete,
delete_path_list(clean_atmosphere_files_to_delete, "atmosphere files"); clean_misc_files_to_delete,
old_version_files_to_delete,
set_color(COLOR_CYAN); NULL);
gfx_printf(" Bereinige: bootloader/\n"); }
set_color(COLOR_WHITE);
delete_path_list(clean_bootloader_dirs_to_delete, "bootloader dirs"); // Clean mode: Backup user data
delete_path_list(clean_bootloader_files_to_delete, "bootloader files"); int clean_mode_backup(void) {
set_color(COLOR_CYAN);
set_color(COLOR_CYAN); gfx_printf(" Sichere: DBI, Tinfoil, prod.keys\n");
gfx_printf(" Bereinige: config/\n"); set_color(COLOR_WHITE);
set_color(COLOR_WHITE); int res = backup_user_data();
delete_path_list(clean_config_dirs_to_delete, "config dirs"); if (res == FR_OK) {
set_color(COLOR_GREEN);
set_color(COLOR_CYAN); gfx_printf(" [OK] Sicherung abgeschlossen\n");
gfx_printf(" Bereinige: switch/\n"); set_color(COLOR_WHITE);
set_color(COLOR_WHITE); }
delete_path_list(clean_switch_dirs_to_delete, "switch dirs"); return res;
delete_path_list(clean_switch_files_to_delete, "switch files"); }
set_color(COLOR_CYAN); // Clean mode: Wipe using selective deletion list (does not wipe whole card)
gfx_printf(" Bereinige: Root-Dateien\n"); int clean_mode_wipe(void) {
set_color(COLOR_WHITE); check_and_clear_screen_if_needed();
delete_path_list(clean_root_files_to_delete, "root files");
delete_path_list(clean_misc_dirs_to_delete, "misc dirs"); set_color(COLOR_WHITE);
delete_path_list(clean_misc_files_to_delete, "misc files"); delete_path_lists_grouped("atmosphere/",
clean_atmosphere_dirs_to_delete,
set_color(COLOR_CYAN); clean_atmosphere_contents_dirs_to_delete,
gfx_printf(" Bereinige: Alte Versionsmarker\n"); clean_atmosphere_files_to_delete,
set_color(COLOR_WHITE); NULL);
delete_path_list(old_version_files_to_delete, "old version markers");
delete_path_lists_grouped("bootloader/",
set_color(COLOR_CYAN); clean_bootloader_dirs_to_delete,
gfx_printf(" Erstelle: switch/\n"); clean_bootloader_files_to_delete,
set_color(COLOR_WHITE); NULL);
f_mkdir("sd:/switch");
delete_path_lists_grouped("config/",
set_color(COLOR_GREEN); clean_config_dirs_to_delete,
gfx_printf(" Bereinigung abgeschlossen!\n"); NULL);
set_color(COLOR_WHITE);
delete_path_lists_grouped("switch/",
return FR_OK; clean_switch_dirs_to_delete,
} clean_switch_files_to_delete,
NULL);
// Clean mode: Restore user data
int clean_mode_restore(void) { delete_path_lists_grouped("Root-Dateien",
set_color(COLOR_CYAN); clean_root_files_to_delete,
gfx_printf(" Stelle wieder her: DBI, Tinfoil, prod.keys\n"); clean_misc_dirs_to_delete,
set_color(COLOR_WHITE); clean_misc_files_to_delete,
int res = restore_user_data(); NULL);
if (res == FR_OK) {
set_color(COLOR_GREEN); delete_path_lists_grouped("Alte Versionsmarker",
gfx_printf(" [OK] Wiederherstellung abgeschlossen\n"); old_version_files_to_delete,
set_color(COLOR_WHITE); NULL);
}
cleanup_backup(); set_color(COLOR_CYAN);
return res; gfx_printf(" Erstelle: switch/\n");
} set_color(COLOR_WHITE);
f_mkdir("sd:/switch");
// Clean mode: Install files (reuse update mode install)
int clean_mode_install(omninx_variant_t variant) { set_color(COLOR_GREEN);
return update_mode_install(variant); gfx_printf(" Bereinigung abgeschlossen!\n");
} set_color(COLOR_WHITE);
return FR_OK;
}
// Clean mode: Restore user data
int clean_mode_restore(void) {
set_color(COLOR_CYAN);
gfx_printf(" Stelle wieder her: DBI, Tinfoil, prod.keys\n");
set_color(COLOR_WHITE);
int res = restore_user_data();
if (res == FR_OK) {
set_color(COLOR_GREEN);
gfx_printf(" [OK] Wiederherstellung abgeschlossen\n");
set_color(COLOR_WHITE);
}
cleanup_backup();
return res;
}
// Clean mode: Install files (reuse update mode install)
int clean_mode_install(omninx_variant_t variant) {
return update_mode_install(variant);
}
// Remove other staging directories (OmniNX Standard/Light/OC) that exist on SD
int cleanup_other_staging_directories(omninx_variant_t installed_variant) {
static const omninx_variant_t all_variants[] = { VARIANT_STANDARD, VARIANT_LIGHT, VARIANT_OC };
const int n = sizeof(all_variants) / sizeof(all_variants[0]);
int last_res = FR_OK;
for (int i = 0; i < n; i++) {
omninx_variant_t v = all_variants[i];
if (v == installed_variant)
continue;
const char *staging = get_staging_path(v);
if (!staging || !path_exists(staging))
continue;
check_and_clear_screen_if_needed();
set_color(COLOR_YELLOW);
gfx_printf("\nEntferne weiteren Installationsordner...\n");
set_color(COLOR_WHITE);
int total = count_directory_items(staging);
u32 start_x, start_y;
gfx_con_getpos(&start_x, &start_y);
const char *folder_name = strrchr(staging, '/');
if (folder_name) folder_name++;
else folder_name = staging;
set_color(COLOR_CYAN);
gfx_printf(" Loesche: %s [ 0%%] (0/%d)", folder_name, total);
set_color(COLOR_WHITE);
int deleted = 0;
int last_percent = -1;
int res = folder_delete_progress_recursive(staging, &deleted, total, start_x, start_y, folder_name, &last_percent);
gfx_con_setpos(start_x, start_y);
if (res == FR_OK) {
set_color(COLOR_GREEN);
gfx_printf(" Loesche: %s [100%%] (%d/%d) - Fertig!\n", folder_name, deleted, total);
set_color(COLOR_WHITE);
} else {
set_color(COLOR_ORANGE);
gfx_printf(" Loesche: %s - Fehlgeschlagen!\n", folder_name);
gfx_printf(" [WARN] Ordner konnte nicht entfernt werden (err=%d)\n", res);
set_color(COLOR_WHITE);
}
last_res = res;
}
return last_res;
}

View File

@@ -1,237 +1,219 @@
/* /*
* OmniNX Installer - Update Mode * OmniNX Installer - Update Mode
* Selective cleanup and install when OmniNX is already installed. * Selective cleanup and install when OmniNX is already installed.
*/ */
#include "install.h" #include "install.h"
#include "deletion_lists_update.h" #include "backup.h"
#include "fs.h" #include "deletion_lists_update.h"
#include "version.h" #include "fs.h"
#include "gfx.h" #include "version.h"
#include <libs/fatfs/ff.h> #include "gfx.h"
#include <string.h> #include <libs/fatfs/ff.h>
#include <utils/sprintf.h> #include <string.h>
#include <utils/sprintf.h>
#ifndef VERSION
#define VERSION "1.0.0" #ifndef VERSION
#endif #define VERSION "1.0.0"
#endif
#undef COLOR_CYAN
#undef COLOR_WHITE #undef COLOR_CYAN
#undef COLOR_GREEN #undef COLOR_WHITE
#undef COLOR_YELLOW #undef COLOR_GREEN
#undef COLOR_ORANGE #undef COLOR_YELLOW
#undef COLOR_RED #undef COLOR_ORANGE
#define COLOR_CYAN 0xFF00FFFF #undef COLOR_RED
#define COLOR_WHITE 0xFFFFFFFF #define COLOR_CYAN 0xFF00FFFF
#define COLOR_GREEN 0xFF00FF00 #define COLOR_WHITE 0xFFFFFFFF
#define COLOR_YELLOW 0xFFFFDD00 #define COLOR_GREEN 0xFF00FF00
#define COLOR_ORANGE 0xFF00A5FF #define COLOR_YELLOW 0xFFFFDD00
#define COLOR_RED 0xFFFF0000 #define COLOR_ORANGE 0xFF00A5FF
#define COLOR_RED 0xFFFF0000
#define set_color install_set_color
#define check_and_clear_screen_if_needed install_check_and_clear_screen_if_needed #define set_color install_set_color
#define path_exists install_path_exists #define check_and_clear_screen_if_needed install_check_and_clear_screen_if_needed
#define count_directory_items install_count_directory_items #define path_exists install_path_exists
#define count_directory_items install_count_directory_items
// Update mode: Cleanup specific directories/files
int update_mode_cleanup(omninx_variant_t variant) { // Backup paths before update (sd:/backup/OmniNX/{version})
(void)variant; int backup_before_update(const char *version) {
check_and_clear_screen_if_needed(); char backup_base[270];
s_printf(backup_base, "%s/%s", BACKUP_BASE_PATH, version);
set_color(COLOR_CYAN); return backup_deletion_lists(backup_base,
gfx_printf(" Bereinige: atmosphere/\n"); atmosphere_dirs_to_delete,
set_color(COLOR_WHITE); atmosphere_contents_dirs_to_delete,
delete_path_list(atmosphere_dirs_to_delete, "atmosphere subdirs"); atmosphere_files_to_delete,
delete_path_list(atmosphere_contents_dirs_to_delete, "atmosphere contents dirs"); bootloader_dirs_to_delete,
delete_path_list(atmosphere_files_to_delete, "atmosphere files"); bootloader_files_to_delete,
config_dirs_to_delete,
set_color(COLOR_CYAN); switch_dirs_to_delete,
gfx_printf(" Bereinige: bootloader/\n"); switch_files_to_delete,
set_color(COLOR_WHITE); root_files_to_delete,
delete_path_list(bootloader_dirs_to_delete, "bootloader dirs"); misc_dirs_to_delete,
delete_path_list(bootloader_files_to_delete, "bootloader files"); misc_files_to_delete,
NULL);
set_color(COLOR_CYAN); }
gfx_printf(" Bereinige: config/\n");
set_color(COLOR_WHITE); // Update mode: Cleanup specific directories/files
delete_path_list(config_dirs_to_delete, "config dirs"); int update_mode_cleanup(omninx_variant_t variant) {
(void)variant;
set_color(COLOR_CYAN); check_and_clear_screen_if_needed();
gfx_printf(" Bereinige: switch/\n");
set_color(COLOR_WHITE); set_color(COLOR_WHITE);
delete_path_list(switch_dirs_to_delete, "switch dirs"); delete_path_lists_grouped("atmosphere/",
delete_path_list(switch_files_to_delete, "switch files"); atmosphere_dirs_to_delete,
atmosphere_contents_dirs_to_delete,
set_color(COLOR_CYAN); atmosphere_files_to_delete,
gfx_printf(" Bereinige: Root-Dateien\n"); NULL);
set_color(COLOR_WHITE);
delete_path_list(root_files_to_delete, "root files"); delete_path_lists_grouped("bootloader/",
delete_path_list(misc_dirs_to_delete, "misc dirs"); bootloader_dirs_to_delete,
delete_path_list(misc_files_to_delete, "misc files"); bootloader_files_to_delete,
NULL);
set_color(COLOR_GREEN);
gfx_printf(" Bereinigung abgeschlossen!\n"); delete_path_lists_grouped("config/",
set_color(COLOR_WHITE); config_dirs_to_delete,
NULL);
return FR_OK;
} delete_path_lists_grouped("switch/",
switch_dirs_to_delete,
// Update mode: Copy files from staging switch_files_to_delete,
int update_mode_install(omninx_variant_t variant) { NULL);
int res;
const char* staging = get_staging_path(variant); delete_path_lists_grouped("Root-Dateien",
char src_path[256]; root_files_to_delete,
char dst_path[256]; misc_dirs_to_delete,
misc_files_to_delete,
if (!staging) { NULL);
return FR_INVALID_PARAMETER;
} set_color(COLOR_GREEN);
gfx_printf(" Bereinigung abgeschlossen!\n");
check_and_clear_screen_if_needed(); set_color(COLOR_WHITE);
set_color(COLOR_YELLOW); return FR_OK;
gfx_printf("Dateien werden kopiert...\n"); }
set_color(COLOR_WHITE);
// Update mode: Copy files from staging
s_printf(src_path, "%s/atmosphere", staging); int update_mode_install(omninx_variant_t variant) {
res = folder_copy_with_progress_v2(src_path, "sd:/", "atmosphere/"); int res;
if (res != FR_OK && res != FR_NO_FILE) return res; const char* staging = get_staging_path(variant);
char src_path[256];
s_printf(src_path, "%s/bootloader", staging); char dst_path[256];
res = folder_copy_with_progress_v2(src_path, "sd:/", "bootloader/");
if (res != FR_OK && res != FR_NO_FILE) return res; if (!staging) {
return FR_INVALID_PARAMETER;
s_printf(src_path, "%s/config", staging); }
res = folder_copy_with_progress_v2(src_path, "sd:/", "config/");
if (res != FR_OK && res != FR_NO_FILE) return res; check_and_clear_screen_if_needed();
s_printf(src_path, "%s/switch", staging); set_color(COLOR_YELLOW);
res = folder_copy_with_progress_v2(src_path, "sd:/", "switch/"); gfx_printf("Dateien werden kopiert...\n");
if (res != FR_OK && res != FR_NO_FILE) return res; set_color(COLOR_WHITE);
s_printf(src_path, "%s/warmboot_mariko", staging); s_printf(src_path, "%s/atmosphere", staging);
res = folder_copy_with_progress_v2(src_path, "sd:/", "warmboot_mariko/"); res = folder_copy_with_progress_v2(src_path, "sd:/", "atmosphere/");
if (res != FR_OK && res != FR_NO_FILE) return res; if (res != FR_OK && res != FR_NO_FILE) return res;
if (variant == VARIANT_OC) { s_printf(src_path, "%s/bootloader", staging);
s_printf(src_path, "%s/SaltySD", staging); res = folder_copy_with_progress_v2(src_path, "sd:/", "bootloader/");
res = folder_copy_with_progress_v2(src_path, "sd:/", "SaltySD/"); if (res != FR_OK && res != FR_NO_FILE) return res;
if (res != FR_OK && res != FR_NO_FILE) return res;
} s_printf(src_path, "%s/config", staging);
res = folder_copy_with_progress_v2(src_path, "sd:/", "config/");
set_color(COLOR_CYAN); if (res != FR_OK && res != FR_NO_FILE) return res;
gfx_printf(" Kopiere Root-Dateien...\n");
set_color(COLOR_WHITE); s_printf(src_path, "%s/switch", staging);
res = folder_copy_with_progress_v2(src_path, "sd:/", "switch/");
s_printf(src_path, "%s/boot.dat", staging); if (res != FR_OK && res != FR_NO_FILE) return res;
s_printf(dst_path, "sd:/boot.dat");
if (path_exists(src_path)) file_copy(src_path, dst_path); s_printf(src_path, "%s/warmboot_mariko", staging);
res = folder_copy_with_progress_v2(src_path, "sd:/", "warmboot_mariko/");
s_printf(src_path, "%s/boot.ini", staging); if (res != FR_OK && res != FR_NO_FILE) return res;
s_printf(dst_path, "sd:/boot.ini");
if (path_exists(src_path)) file_copy(src_path, dst_path); if (variant == VARIANT_OC) {
s_printf(src_path, "%s/SaltySD", staging);
s_printf(src_path, "%s/exosphere.ini", staging); res = folder_copy_with_progress_v2(src_path, "sd:/", "SaltySD/");
s_printf(dst_path, "sd:/exosphere.ini"); if (res != FR_OK && res != FR_NO_FILE) return res;
if (path_exists(src_path)) file_copy(src_path, dst_path); }
s_printf(src_path, "%s/hbmenu.nro", staging); set_color(COLOR_CYAN);
s_printf(dst_path, "sd:/hbmenu.nro"); gfx_printf(" Kopiere Root-Dateien...\n");
if (path_exists(src_path)) file_copy(src_path, dst_path); set_color(COLOR_WHITE);
s_printf(src_path, "%s/loader.bin", staging); s_printf(src_path, "%s/boot.dat", staging);
s_printf(dst_path, "sd:/loader.bin"); s_printf(dst_path, "sd:/boot.dat");
if (path_exists(src_path)) file_copy(src_path, dst_path); if (path_exists(src_path)) file_copy(src_path, dst_path);
s_printf(src_path, "%s/payload.bin", staging); s_printf(src_path, "%s/boot.ini", staging);
s_printf(dst_path, "sd:/payload.bin"); s_printf(dst_path, "sd:/boot.ini");
if (path_exists(src_path)) file_copy(src_path, dst_path); if (path_exists(src_path)) file_copy(src_path, dst_path);
set_color(COLOR_CYAN); s_printf(src_path, "%s/exosphere.ini", staging);
gfx_printf(" Erstelle manifest.ini...\n"); s_printf(dst_path, "sd:/exosphere.ini");
set_color(COLOR_WHITE); if (path_exists(src_path)) file_copy(src_path, dst_path);
s_printf(dst_path, "sd:/config/omninx"); s_printf(src_path, "%s/hbmenu.nro", staging);
f_mkdir(dst_path); s_printf(dst_path, "sd:/hbmenu.nro");
if (path_exists(src_path)) file_copy(src_path, dst_path);
const char* pack_name;
int update_channel; s_printf(src_path, "%s/loader.bin", staging);
switch (variant) { s_printf(dst_path, "sd:/loader.bin");
case VARIANT_STANDARD: pack_name = "standard"; update_channel = 2; break; if (path_exists(src_path)) file_copy(src_path, dst_path);
case VARIANT_LIGHT: pack_name = "light"; update_channel = 0; break;
case VARIANT_OC: pack_name = "oc"; update_channel = 1; break; s_printf(src_path, "%s/payload.bin", staging);
default: pack_name = "unknown"; update_channel = 0; break; s_printf(dst_path, "sd:/payload.bin");
} if (path_exists(src_path)) file_copy(src_path, dst_path);
s_printf(dst_path, "sd:/config/omninx/manifest.ini"); set_color(COLOR_GREEN);
FIL fp; gfx_printf(" Kopie abgeschlossen!\n");
if (f_open(&fp, dst_path, FA_WRITE | FA_CREATE_ALWAYS) == FR_OK) { set_color(COLOR_WHITE);
f_printf(&fp, "[OmniNX]\n");
f_printf(&fp, "current_pack=%s\n", pack_name); return FR_OK;
f_printf(&fp, "version=%s\n", VERSION); }
f_printf(&fp, "update_channel=%d\n", update_channel);
f_printf(&fp, "channel_pack=%s\n", pack_name); // Remove staging directory after installation
f_close(&fp); int cleanup_staging_directory(omninx_variant_t pack_variant) {
set_color(COLOR_GREEN); const char* staging = get_staging_path(pack_variant);
gfx_printf(" [OK] manifest.ini erstellt\n"); if (!staging) {
set_color(COLOR_WHITE); return FR_INVALID_PARAMETER;
} else { }
set_color(COLOR_ORANGE);
gfx_printf(" [WARN] manifest.ini konnte nicht erstellt werden\n"); check_and_clear_screen_if_needed();
set_color(COLOR_WHITE);
} if (path_exists(staging)) {
set_color(COLOR_YELLOW);
set_color(COLOR_GREEN); gfx_printf("\nEntferne Installationsordner...\n");
gfx_printf(" Kopie abgeschlossen!\n"); set_color(COLOR_WHITE);
set_color(COLOR_WHITE);
int total = count_directory_items(staging);
return FR_OK; u32 start_x, start_y;
} gfx_con_getpos(&start_x, &start_y);
// Remove staging directory after installation const char *folder_name = strrchr(staging, '/');
int cleanup_staging_directory(omninx_variant_t pack_variant) { if (folder_name) folder_name++;
const char* staging = get_staging_path(pack_variant); else folder_name = staging;
if (!staging) {
return FR_INVALID_PARAMETER; set_color(COLOR_CYAN);
} gfx_printf(" Loesche: %s [ 0%%] (0/%d)", folder_name, total);
set_color(COLOR_WHITE);
check_and_clear_screen_if_needed();
int deleted = 0;
if (path_exists(staging)) { int last_percent = -1;
set_color(COLOR_YELLOW); int res = folder_delete_progress_recursive(staging, &deleted, total, start_x, start_y, folder_name, &last_percent);
gfx_printf("\nEntferne Installationsordner...\n");
set_color(COLOR_WHITE); gfx_con_setpos(start_x, start_y);
if (res == FR_OK) {
int total = count_directory_items(staging); set_color(COLOR_GREEN);
u32 start_x, start_y; gfx_printf(" Loesche: %s [100%%] (%d/%d) - Fertig!\n", folder_name, deleted, total);
gfx_con_getpos(&start_x, &start_y); set_color(COLOR_WHITE);
} else {
const char *folder_name = strrchr(staging, '/'); set_color(COLOR_ORANGE);
if (folder_name) folder_name++; gfx_printf(" Loesche: %s - Fehlgeschlagen!\n", folder_name);
else folder_name = staging; gfx_printf(" [WARN] Ordner konnte nicht entfernt werden (err=%d)\n", res);
set_color(COLOR_WHITE);
set_color(COLOR_CYAN); }
gfx_printf(" Loesche: %s [ 0%%] (0/%d)", folder_name, total); return res;
set_color(COLOR_WHITE); }
int deleted = 0; return FR_OK;
int last_percent = -1; }
int res = folder_delete_progress_recursive(staging, &deleted, total, start_x, start_y, folder_name, &last_percent);
gfx_con_setpos(start_x, start_y);
if (res == FR_OK) {
set_color(COLOR_GREEN);
gfx_printf(" Loesche: %s [100%%] (%d/%d) - Fertig!\n", folder_name, deleted, total);
set_color(COLOR_WHITE);
} else {
set_color(COLOR_ORANGE);
gfx_printf(" Loesche: %s - Fehlgeschlagen!\n", folder_name);
gfx_printf(" [WARN] Ordner konnte nicht entfernt werden (err=%d)\n", res);
set_color(COLOR_WHITE);
}
return res;
}
return FR_OK;
}

View File

@@ -1,9 +1,9 @@
/* /*
* HATS Installer - Simplified disk I/O (SD card only) * OmniNX Installer - Simplified disk I/O (SD card only)
* Based on TegraExplorer diskio.c by shchmue * Based on HATS Installer, TegraExplorer diskio.c by shchmue
* *
* This simplified version removes BIS/eMMC support since the * This simplified version removes BIS/eMMC support since the
* HATS installer only needs SD card access. * OmniNX installer only needs SD card access.
*/ */
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/

File diff suppressed because it is too large Load Diff

View File

@@ -50,11 +50,11 @@ static omninx_variant_t read_manifest_variant(const char *manifest_path) {
LIST_FOREACH_ENTRY(ini_kv_t, kv, &sec->kvs, link) { LIST_FOREACH_ENTRY(ini_kv_t, kv, &sec->kvs, link) {
if (kv->key && !strcmp(kv->key, "current_pack")) { if (kv->key && !strcmp(kv->key, "current_pack")) {
if (kv->val) { if (kv->val) {
if (!strcmp(kv->val, "standard")) { if (!strcmp(kv->val, "Standard")) {
variant = VARIANT_STANDARD; variant = VARIANT_STANDARD;
} else if (!strcmp(kv->val, "light")) { } else if (!strcmp(kv->val, "Light")) {
variant = VARIANT_LIGHT; variant = VARIANT_LIGHT;
} else if (!strcmp(kv->val, "oc")) { } else if (!strcmp(kv->val, "OC")) {
variant = VARIANT_OC; variant = VARIANT_OC;
} }
} }
@@ -156,6 +156,20 @@ omninx_variant_t detect_pack_variant(void) {
return VARIANT_NONE; return VARIANT_NONE;
} }
// Detect all pack variants present on SD card; returns count, fills out_variants[]
int detect_present_variants(omninx_variant_t *out_variants, int max_count) {
int count = 0;
if (max_count <= 0 || !out_variants)
return 0;
if (file_exists(STAGING_STANDARD) && count < max_count)
out_variants[count++] = VARIANT_STANDARD;
if (file_exists(STAGING_LIGHT) && count < max_count)
out_variants[count++] = VARIANT_LIGHT;
if (file_exists(STAGING_OC) && count < max_count)
out_variants[count++] = VARIANT_OC;
return count;
}
// Get human-readable variant name // Get human-readable variant name
const char* get_variant_name(omninx_variant_t variant) { const char* get_variant_name(omninx_variant_t variant) {
switch (variant) { switch (variant) {

View File

@@ -23,9 +23,12 @@ typedef struct {
// Detect current OmniNX installation status // Detect current OmniNX installation status
omninx_status_t detect_omninx_installation(void); omninx_status_t detect_omninx_installation(void);
// Detect which pack variant is present on SD card // Detect which pack variant is present on SD card (first found in fixed order)
omninx_variant_t detect_pack_variant(void); omninx_variant_t detect_pack_variant(void);
// Detect all pack variants present on SD card; returns count, fills out_variants[] (max max_count)
int detect_present_variants(omninx_variant_t *out_variants, int max_count);
// Get human-readable variant name // Get human-readable variant name
const char* get_variant_name(omninx_variant_t variant); const char* get_variant_name(omninx_variant_t variant);