From 56ac8c1e68882a80017d4bd51f1dd5e0e995c476 Mon Sep 17 00:00:00 2001 From: d0k3 Date: Fri, 17 Jun 2016 19:28:43 +0200 Subject: [PATCH] Allow injecting files into files --- source/fs.c | 80 ++++++++++++++++++++++++++++++++++++++++++++++++ source/fs.h | 3 ++ source/godmode.c | 19 ++++++++---- 3 files changed, 96 insertions(+), 6 deletions(-) diff --git a/source/fs.c b/source/fs.c index 28c68c1..eedcdf8 100644 --- a/source/fs.c +++ b/source/fs.c @@ -301,6 +301,86 @@ bool FileGetSha256(const char* path, u8* sha256) { return ret; } +bool FileInjectFile(const char* dest, const char* orig, u32 offset) { + VirtualFile dvfile; + VirtualFile ovfile; + FIL ofile; + FIL dfile; + size_t osize; + size_t dsize; + + bool vdest; + bool vorig; + bool ret; + + if (!CheckWritePermissions(dest)) return false; + + // open destination + if (GetVirtualSource(dest)) { + vdest = true; + if (!FindVirtualFile(&dvfile, dest, 0)) + return false; + dsize = dvfile.size; + } else { + vdest = false; + if (f_open(&dfile, dest, FA_WRITE | FA_OPEN_EXISTING) != FR_OK) + return false; + dsize = f_size(&dfile); + f_lseek(&dfile, offset); + f_sync(&dfile); + } + + // open origin + if (GetVirtualSource(orig)) { + vorig = true; + if (!FindVirtualFile(&ovfile, orig, 0)) { + if (!vdest) f_close(&dfile); + return false; + } + osize = ovfile.size; + } else { + vorig = false; + if (f_open(&ofile, orig, FA_READ | FA_OPEN_EXISTING) != FR_OK) { + if (!vdest) f_close(&dfile); + return false; + } + osize = f_size(&ofile); + f_lseek(&ofile, 0); + f_sync(&ofile); + } + + // check file limits + if (offset + osize > dsize) { + ShowPrompt(false, "Operation would write beyond end of file"); + if (!vdest) f_close(&dfile); + if (!vorig) f_close(&ofile); + return false; + } + + ret = true; + for (size_t pos = 0; (pos < osize) && ret; pos += MAIN_BUFFER_SIZE) { + UINT read_bytes = min(MAIN_BUFFER_SIZE, osize - pos); + UINT bytes_read = read_bytes; + UINT bytes_written = read_bytes; + if ((!vorig && (f_read(&ofile, MAIN_BUFFER, read_bytes, &bytes_read) != FR_OK)) || + (vorig && ReadVirtualFile(&ovfile, MAIN_BUFFER, pos, read_bytes, NULL) != 0)) + ret = false; + if (!ShowProgress(pos + (bytes_read / 2), osize, orig)) + ret = false; + if ((!vdest && (f_write(&dfile, MAIN_BUFFER, read_bytes, &bytes_written) != FR_OK)) || + (vdest && WriteVirtualFile(&dvfile, MAIN_BUFFER, offset + pos, read_bytes, NULL) != 0)) + ret = false; + if (bytes_read != bytes_written) + ret = false; + } + ShowProgress(1, 1, orig); + + if (!vdest) f_close(&dfile); + if (!vorig) f_close(&ofile); + + return ret; +} + bool PathCopyVirtual(const char* destdir, const char* orig) { char dest[256]; // maximum path name length in FAT char* oname = strrchr(orig, '/'); diff --git a/source/fs.h b/source/fs.h index 5a637dc..3a83935 100644 --- a/source/fs.h +++ b/source/fs.h @@ -59,6 +59,9 @@ size_t FileGetSize(const char* path); /** Get SHA-256 of file **/ bool FileGetSha256(const char* path, u8* sha256); +/** Inject file into file @offset **/ +bool FileInjectFile(const char* dest, const char* orig, u32 offset); + /** Recursively copy a file or directory **/ bool PathCopy(const char* destdir, const char* orig); diff --git a/source/godmode.c b/source/godmode.c index 6881169..3413dfd 100644 --- a/source/godmode.c +++ b/source/godmode.c @@ -7,7 +7,7 @@ #include "virtual.h" #include "image.h" -#define VERSION "0.5.4" +#define VERSION "0.5.5" #define N_PANES 2 #define IMG_DRV "789I" @@ -438,6 +438,7 @@ u32 GodMode() { } else cursor = 0; } else if ((pad_state & BUTTON_A) && (curr_entry->type == T_FILE)) { // process a file u32 file_type = IdentifyImage(curr_entry->path); + bool injectable = (clipboard->n_entries == 1) && (clipboard->entry[0].type == T_FILE); char pathstr[32 + 1]; const char* optionstr[4]; u32 n_opt = 2; @@ -445,10 +446,9 @@ u32 GodMode() { TruncateString(pathstr, curr_entry->path, 32, 8); optionstr[0] = "Show in Hexeditor"; optionstr[1] = "Calculate SHA-256"; - if (file_type && (PathToNumFS(curr_entry->path) == 0)) { - optionstr[2] = (file_type == IMG_NAND) ? "Mount as NAND image" : "Mount as FAT image"; - n_opt = 3; - } + if (injectable) optionstr[n_opt++] = "Inject data @offset"; + if (file_type && (PathToNumFS(curr_entry->path) == 0)) + optionstr[n_opt++] = (file_type == IMG_NAND) ? "Mount as NAND image" : "Mount as FAT image"; u32 user_select = ShowSelectPrompt(n_opt, optionstr, pathstr); if (user_select == 1) { // -> show in hex viewer @@ -485,7 +485,7 @@ u32 GodMode() { strncpy(pathstr_prev, pathstr, 32 + 1); memcpy(sha256_prev, sha256, 32); } - } else if (user_select == 3) { // -> mount as image + } else if ((!injectable && (user_select == 3)) || (user_select == 4)) { // -> mount as image DeinitExtFS(); u32 mount_state = MountImage(curr_entry->path); InitExtFS(); @@ -501,6 +501,13 @@ u32 GodMode() { } if (clipboard->n_entries && (strcspn(clipboard->entry[0].path, IMG_DRV) == 0)) clipboard->n_entries = 0; // remove invalid clipboard stuff + } else if (injectable && (user_select == 3)) { // -> inject data from clipboard + char origstr[24 + 1]; + TruncateString(origstr, clipboard->entry[0].name, 24, 8); + u64 offset = ShowHexPrompt(0, 8, "Inject data from %s?\nSpecifiy offset below.", origstr); + if ((offset != (u64) -1) && !FileInjectFile(curr_entry->path, clipboard->entry[0].path, (u32) offset)) + ShowPrompt(false, "Failed injecting %s", origstr); + clipboard->n_entries = 0; } } else if (*current_path && ((pad_state & BUTTON_B) || // one level down ((pad_state & BUTTON_A) && (curr_entry->type == T_DOTDOT)))) {