diff --git a/source/err.c b/source/err.c index c2183d4..bc9e203 100644 --- a/source/err.c +++ b/source/err.c @@ -28,7 +28,9 @@ const char *TEErrors[] = { [TE_ERR_PARTITION_NOT_FOUND - 1] = "Failed to find partition", [TE_ERR_PATH_IN_PATH - 1] = "Can't move/copy folder into itself", [TE_ERR_EMMC_READ_FAIL - 1] = "Emmc/Emummc read failed", + [TE_ERR_EMMC_WRITE_FAIL - 1] = "Emmc/Emummc write failed", [TE_ERR_NO_SD - 1] = "No sd detected", + [TE_ERR_FILE_TOO_BIG_FOR_DEST - 1] = "File is too big for dest", }; const char *GetErrStr(u32 err){ diff --git a/source/err.h b/source/err.h index b713254..a90eb30 100644 --- a/source/err.h +++ b/source/err.h @@ -20,6 +20,10 @@ enum { TE_ERR_EMMC_READ_FAIL, TE_ERR_EMMC_WRITE_FAIL, TE_ERR_NO_SD, + TE_ERR_FILE_TOO_BIG_FOR_DEST, + TE_ERR_MEM_ALLOC_FAIL, + TE_WARN_FILE_EXISTS, + TE_WARN_FILE_TOO_SMALL_FOR_DEST, }; #define newErrCode(err) (ErrCode_t) {err, __LINE__, __FILE__} diff --git a/source/fs/fsutils.c b/source/fs/fsutils.c index c23bef4..c838097 100644 --- a/source/fs/fsutils.c +++ b/source/fs/fsutils.c @@ -47,7 +47,7 @@ char *GetFileAttribs(FSEntry_t entry){ return ret; } -bool FileExists(char* path){ +bool FileExists(const char* path){ FRESULT fr; FILINFO fno; diff --git a/source/fs/fsutils.h b/source/fs/fsutils.h index 4ab88a6..14eb037 100644 --- a/source/fs/fsutils.h +++ b/source/fs/fsutils.h @@ -6,4 +6,4 @@ FSEntry_t GetFileInfo(const char *path); char *EscapeFolder(const char *current); char *CombinePaths(const char *current, const char *add); char *GetFileAttribs(FSEntry_t entry); -bool FileExists(char* path); \ No newline at end of file +bool FileExists(const char* path); \ No newline at end of file diff --git a/source/storage/emmcfile.c b/source/storage/emmcfile.c index ef5e9e9..86623e1 100644 --- a/source/storage/emmcfile.c +++ b/source/storage/emmcfile.c @@ -11,14 +11,19 @@ #include "../hid/hid.h" #include #include +#include "../fs/fsutils.h" // Uses default storage in nx_emmc.c // Expects the correct mmc & partition to be set -ErrCode_t EmmcDumpToFile(const char *path, u32 lba_start, u32 lba_end){ +ErrCode_t EmmcDumpToFile(const char *path, u32 lba_start, u32 lba_end, u8 force){ FIL fp; u32 curLba = lba_start; u32 totalSectors = lba_end - lba_start + 1; + if (FileExists(path) && !force){ + return newErrCode(TE_WARN_FILE_EXISTS); + } + int res = f_open(&fp, path, FA_CREATE_ALWAYS | FA_WRITE); if (res){ return newErrCode(res); @@ -28,6 +33,9 @@ ErrCode_t EmmcDumpToFile(const char *path, u32 lba_start, u32 lba_end){ u8 *buff = malloc(TConf.FSBuffSize); + if (!buff) + return newErrCode(TE_ERR_MEM_ALLOC_FAIL); + u32 x, y; gfx_con_getpos(&x, &y); @@ -56,21 +64,74 @@ ErrCode_t EmmcDumpToFile(const char *path, u32 lba_start, u32 lba_end){ return err; } -ErrCode_t DumpEmmcPart(const char *path, const char *part){ +ErrCode_t EmmcRestoreFromFile(const char *path, u32 lba_start, u32 lba_end, u8 force){ + FIL fp; + u32 curLba = lba_start; + u32 totalSectorsDest = lba_end - lba_start + 1; + + int res = f_open(&fp, path, FA_OPEN_ALWAYS | FA_READ); + if (res) + return newErrCode(res); + + u64 totalSizeSrc = f_size(&fp); + u32 totalSectorsSrc = totalSizeSrc / NX_EMMC_BLOCKSIZE; + + if (totalSectorsSrc > totalSectorsDest) // We don't close the file here, oh well + return newErrCode(TE_ERR_FILE_TOO_BIG_FOR_DEST); + + if (totalSectorsSrc < totalSectorsDest && !force) + return newErrCode(TE_WARN_FILE_TOO_SMALL_FOR_DEST); + + u8 *buff = malloc(TConf.FSBuffSize); + ErrCode_t err = newErrCode(0); + + if (!buff) + return newErrCode(TE_ERR_MEM_ALLOC_FAIL); + + u32 x, y; + gfx_con_getpos(&x, &y); + + while (totalSectorsSrc > 0){ + u32 num = MIN(totalSectorsSrc, TConf.FSBuffSize / NX_EMMC_BLOCKSIZE); + + if ((res = f_read(&fp, buff, num * NX_EMMC_BLOCKSIZE, NULL))){ + err = newErrCode(res); + break; + } + + if (!emummc_storage_write(&emmc_storage, curLba, num, buff)){ + err = newErrCode(TE_ERR_EMMC_WRITE_FAIL); + break; + } + + curLba += num; + totalSectorsSrc -= num; + + u32 percent = ((curLba - lba_start) * 100) / ((totalSizeSrc / NX_EMMC_BLOCKSIZE)); + gfx_printf("[%3d%%]", percent); + gfx_con_setpos(x, y); + } + + f_close(&fp); + free(buff); + return err; +} + +ErrCode_t DumpOrWriteEmmcPart(const char *path, const char *part, u8 write, u8 force){ const u32 BOOT_PART_SIZE = emmc_storage.ext_csd.boot_mult << 17; + u32 lba_start = 0; + u32 lba_end = 0; if (!sd_mount()) return newErrCode(TE_ERR_NO_SD); - // maybe check for existing file here - if (!memcmp(part, "BOOT0", 5)){ emummc_storage_set_mmc_partition(&emmc_storage, 1); - return EmmcDumpToFile(path, 0, (BOOT_PART_SIZE / NX_EMMC_BLOCKSIZE) - 1); + lba_end = (BOOT_PART_SIZE / NX_EMMC_BLOCKSIZE) - 1; } else if (!memcmp(part, "BOOT1", 5)){ emummc_storage_set_mmc_partition(&emmc_storage, 2); - return EmmcDumpToFile(path, 0, (BOOT_PART_SIZE / NX_EMMC_BLOCKSIZE) - 1); + lba_end = (BOOT_PART_SIZE / NX_EMMC_BLOCKSIZE) - 1; } else { emummc_storage_set_mmc_partition(&emmc_storage, 0); @@ -79,6 +140,9 @@ ErrCode_t DumpEmmcPart(const char *path, const char *part){ if (!system_part) return newErrCode(TE_ERR_PARTITION_NOT_FOUND); - return EmmcDumpToFile(path, system_part->lba_start, system_part->lba_end); + lba_start = system_part->lba_start; + lba_end = system_part->lba_end; } + + return ((write) ? EmmcRestoreFromFile(path, lba_start, lba_end, force) : EmmcDumpToFile(path, lba_start, lba_end, force)); } \ No newline at end of file diff --git a/source/storage/emmcfile.h b/source/storage/emmcfile.h index 0fd5a4f..a1a0b12 100644 --- a/source/storage/emmcfile.h +++ b/source/storage/emmcfile.h @@ -1,4 +1,4 @@ #pragma once #include "../err.h" -ErrCode_t DumpEmmcPart(const char *path, const char *part); \ No newline at end of file +ErrCode_t DumpOrWriteEmmcPart(const char *path, const char *part, u8 write, u8 force); \ No newline at end of file diff --git a/source/storage/gptmenu.c b/source/storage/gptmenu.c index 39438a1..a91db9a 100644 --- a/source/storage/gptmenu.c +++ b/source/storage/gptmenu.c @@ -14,6 +14,7 @@ #include "emmcfile.h" #include #include "../fs/fsutils.h" +#include "../utils/utils.h" MenuEntry_t GptMenuHeader[] = { {.optionUnion = COLORTORGB(COLOR_ORANGE), .name = "<- Back"}, @@ -33,6 +34,8 @@ void GptMenu(u8 MMCType){ if (connectMMC(MMCType)) return; + GptMenuHeader[1].optionUnion = (TConf.explorerCopyMode == CMODE_Copy) ? (COLORTORGB(COLOR_ORANGE)) : (COLORTORGB(COLOR_GREY) | SKIPBIT); + Vector_t GptMenu = newVec(sizeof(MenuEntry_t), 15); GptMenu.count = ARR_LEN(GptMenuHeader); memcpy(GptMenu.data, GptMenuHeader, sizeof(MenuEntry_t) * ARR_LEN(GptMenuHeader)); @@ -74,9 +77,40 @@ void GptMenu(u8 MMCType){ res = newMenu(&GptMenu, res, 40, 20, ALWAYSREDRAW | ENABLEB, GptMenu.count); - if (res < 2){ + if (res < 1){ break; } + else if (res == 1){ + gfx_clearscreen(); + char *fileName = CpyStr(strrchr(TConf.srcCopy, '/') + 1); + + for (int i = 0; i < strlen(fileName); i++){ + if (fileName[i] >= 'a' && fileName[i] <= 'z') + fileName[i] &= ~BIT(5); + } + + gfx_printf("Are you sure you want to flash %s? ", fileName); + if (MakeYesNoHorzMenu(3, COLOR_DEFAULT)){ + RESETCOLOR; + gfx_printf("\nFlashing %s... ", fileName); + ErrCode_t a = DumpOrWriteEmmcPart(TConf.srcCopy, fileName, 1, 0); + if (a.err){ + if (a.err == TE_WARN_FILE_TOO_SMALL_FOR_DEST){ + gfx_printf("\r%s is too small for the destination. Flash anyway? ", fileName); + if (MakeYesNoHorzMenu(3, COLOR_DEFAULT)){ + RESETCOLOR; + gfx_printf("\nFlashing %s... ", fileName); + a = DumpOrWriteEmmcPart(TConf.srcCopy, fileName, 1, 1); + } + else { + a.err = 0; + } + } + DrawError(a); + } + } + free(fileName); + } else if (entries[res].icon == 127){ unmountMMCPart(); ErrCode_t err = mountMMCPart(entries[res].name); @@ -107,9 +141,21 @@ void GptMenu(u8 MMCType){ char *path = CombinePaths("sd:/tegraexplorer/Dumps", entries[res].name); - ErrCode_t a = DumpEmmcPart(path, entries[res].name); - if (a.err) + ErrCode_t a = DumpOrWriteEmmcPart(path, entries[res].name, 0, 0); + if (a.err){ + if (a.err == TE_WARN_FILE_EXISTS){ + gfx_printf("\rDest file for %s exists already. Overwrite? ", entries[res].name); + if (MakeYesNoHorzMenu(3, COLOR_DEFAULT)){ + RESETCOLOR; + gfx_printf("\nDumping %s... ", entries[res].name); + a = DumpOrWriteEmmcPart(path, entries[res].name, 0, 1); + } + else { + a.err = 0; + } + } DrawError(a); + } } } }