From 4d4a0378743cd292eba280ab6598f3f5d9f24995 Mon Sep 17 00:00:00 2001 From: d0k3 Date: Mon, 21 Mar 2016 23:19:23 +0100 Subject: [PATCH] Added ability to copy virtual files --- source/fs.c | 148 ++++++++++++++++++++++++++++++++++++++++-- source/nand/virtual.c | 26 ++++---- source/nand/virtual.h | 2 - 3 files changed, 154 insertions(+), 22 deletions(-) diff --git a/source/fs.c b/source/fs.c index 64afda9..f3bed21 100644 --- a/source/fs.c +++ b/source/fs.c @@ -147,6 +147,131 @@ bool FileGetData(const char* path, u8* data, size_t size, size_t foffset) return (bytes_read == size); } +bool PathCopyVirtual(const char* destdir, const char* orig) { + char dest[256]; // maximum path name length in FAT + char* oname = strrchr(orig, '/'); + char deststr[36 + 1]; + char origstr[36 + 1]; + bool ret = true; + + if (oname == NULL) return false; // not a proper origin path + oname++; + snprintf(dest, 256, "%s/%s", destdir, oname); + + TruncateString(deststr, dest, 36, 8); + TruncateString(origstr, orig, 36, 8); + + if (IsVirtualPath(dest) && IsVirtualPath(orig)) { // virtual to virtual + VirtualFile dvfile; + VirtualFile ovfile; + u32 osize; + + if (!FindVirtualFile(&dvfile, dest)) + return false; + if (!FindVirtualFile(&ovfile, orig)) + return false; + osize = ovfile.size; + if (dvfile.size != osize) { // almost impossible, but so what... + ShowPrompt(false, "Virtual file size mismatch:\n%s\n%s", origstr, deststr); + return false; + } + if ((dvfile.keyslot == ovfile.keyslot) && (dvfile.offset == ovfile.offset)) // this improves copy times + dvfile.keyslot = ovfile.keyslot = 0xFF; + + DeinitNandFS(); + if (!ShowProgress(0, 0, orig)) ret = false; + for (size_t pos = 0; (pos < osize) && ret; pos += MAIN_BUFFER_SIZE) { + UINT read_bytes = min(MAIN_BUFFER_SIZE, osize - pos); + if (ReadVirtualFile(&ovfile, MAIN_BUFFER, pos, read_bytes) != 0) + ret = false; + if (!ShowProgress(pos + (read_bytes / 2), osize, orig)) + ret = false; + if (WriteVirtualFile(&dvfile, MAIN_BUFFER, pos, read_bytes) != 0) + ret = false; + } + ShowProgress(1, 1, orig); + InitNandFS(); + } else if (IsVirtualPath(dest)) { // SD card to virtual (other FAT not allowed!) + VirtualFile dvfile; + FIL ofile; + u32 osize; + + if (!FindVirtualFile(&dvfile, dest)) + return false; + if (f_open(&ofile, orig, FA_READ | FA_OPEN_EXISTING) != FR_OK) + return false; + f_lseek(&ofile, 0); + f_sync(&ofile); + osize = f_size(&ofile); + if (dvfile.size != osize) { + char osizestr[32]; + char dsizestr[32]; + FormatBytes(osizestr, osize); + FormatBytes(dsizestr, dvfile.size); + ShowPrompt(false, "File size mismatch:\n%s (%s)\n%s (%s)", origstr, osizestr, deststr, dsizestr); + f_close(&ofile); + return false; + } + + DeinitNandFS(); + if (!ShowProgress(0, 0, orig)) ret = false; + for (size_t pos = 0; (pos < osize) && ret; pos += MAIN_BUFFER_SIZE) { + UINT bytes_read = 0; + if (f_read(&ofile, MAIN_BUFFER, MAIN_BUFFER_SIZE, &bytes_read) != FR_OK) + ret = false; + if (!ShowProgress(pos + (bytes_read / 2), osize, orig)) + ret = false; + if (WriteVirtualFile(&dvfile, MAIN_BUFFER, pos, bytes_read) != 0) + ret = false; + } + ShowProgress(1, 1, orig); + f_close(&ofile); + InitNandFS(); + } else if (IsVirtualPath(orig)) { // virtual to SD card (other FAT not allowed) + VirtualFile ovfile; + FIL dfile; + u32 osize; + + if (!FindVirtualFile(&ovfile, orig)) + return false; + // check if destination exists + if (f_stat(dest, NULL) == FR_OK) { + if (!ShowPrompt(true, "Destination already exists:\n%s\nOverwrite existing file(s)?", deststr)) + return false; + } + if (f_open(&dfile, dest, FA_WRITE | FA_CREATE_ALWAYS) != FR_OK) + return false; + f_lseek(&dfile, 0); + f_sync(&dfile); + osize = ovfile.size; + if (GetFreeSpace(dest) < osize) { + ShowPrompt(false, "Error: File is too big for destination"); + f_close(&dfile); + return false; + } + + if (!ShowProgress(0, 0, orig)) ret = false; + for (size_t pos = 0; (pos < osize) && ret; pos += MAIN_BUFFER_SIZE) { + UINT read_bytes = min(MAIN_BUFFER_SIZE, osize - pos); + UINT bytes_written = 0; + if (ReadVirtualFile(&ovfile, MAIN_BUFFER, pos, read_bytes) != 0) + ret = false; + if (!ShowProgress(pos + (read_bytes / 2), osize, orig)) + ret = false; + if (f_write(&dfile, MAIN_BUFFER, read_bytes, &bytes_written) != FR_OK) + ret = false; + if (read_bytes != bytes_written) + ret = false; + } + ShowProgress(1, 1, orig); + f_close(&dfile); + } else { + return false; + } + + return ret; +} + bool PathCopyWorker(char* dest, char* orig, bool overwrite) { FILINFO fno = {.lfname = NULL}; bool ret = false; @@ -261,12 +386,21 @@ bool PathCopyWorker(char* dest, char* orig, bool overwrite) { } bool PathCopy(const char* destdir, const char* orig) { - char fdpath[256]; // 256 is the maximum length of a full path - char fopath[256]; if (!CheckWritePermissions(destdir)) return false; - strncpy(fdpath, destdir, 255); - strncpy(fopath, orig, 255); - return PathCopyWorker(fdpath, fopath, false); + if (IsVirtualPath(destdir) || IsVirtualPath(orig)) { + // users are inventive... + if ((PathToNumFS(orig) > 0) && IsVirtualPath(destdir)) { + ShowPrompt(false, "Only files from SD card are accepted"); + return false; + } + return PathCopyVirtual(destdir, orig); + } else { + char fdpath[256]; // 256 is the maximum length of a full path + char fopath[256]; + strncpy(fdpath, destdir, 255); + strncpy(fopath, orig, 255); + return PathCopyWorker(fdpath, fopath, false); + } } bool PathDeleteWorker(char* fpath) { @@ -401,8 +535,8 @@ bool GetRootDirContentsWorker(DirStruct* contents) { for (u32 pdrv = 0; (pdrv < MAX_FS+2) && (n_entries < MAX_ENTRIES); pdrv++) { DirEntry* entry = &(contents->entry[n_entries]); if ((pdrv < MAX_FS) && !fs_mounted[pdrv]) continue; - if ((pdrv == MAX_FS+0) && (!fs_mounted[1] || !fs_mounted[2] || !fs_mounted[3])) continue; - if ((pdrv == MAX_FS+1) && (!fs_mounted[4] || !fs_mounted[5] || !fs_mounted[6])) continue; + if ((pdrv == MAX_FS+0) && (!fs_mounted[1])) continue; + if ((pdrv == MAX_FS+1) && (!fs_mounted[4])) continue; memset(entry->path, 0x00, 64); snprintf(entry->path + 0, 4, "%s:", drvnum[pdrv]); snprintf(entry->path + 4, 32, "[%s:] %s", drvnum[pdrv], drvname[pdrv]); diff --git a/source/nand/virtual.c b/source/nand/virtual.c index afbfc79..0644329 100644 --- a/source/nand/virtual.c +++ b/source/nand/virtual.c @@ -5,24 +5,24 @@ #define VFLAG_ON_N3DS NAND_TYPE_N3DS #define VFLAG_ON_NO3DS NAND_TYPE_NO3DS #define VFLAG_ON_ALL (VFLAG_ON_O3DS | VFLAG_ON_N3DS | VFLAG_ON_NO3DS) -#define VFLAG_NAND_SIZE (1<<29) -#define VFLAG_ON_EMUNAND (1<<30) +#define VFLAG_NAND_SIZE (1<<30) +#define VFLAG_ON_EMUNAND (1<<31) VirtualFile virtualFileTemplates[] = { - { "twln.bin" , 0x00012E00, 0x08FB5200, 0x03, VFLAG_ON_ALL | VFLAG_EXT_NAND_REMOUNT }, - { "twlp.bin" , 0x09011A00, 0x020B6600, 0x03, VFLAG_ON_ALL | VFLAG_EXT_NAND_REMOUNT }, + { "twln.bin" , 0x00012E00, 0x08FB5200, 0x03, VFLAG_ON_ALL }, + { "twlp.bin" , 0x09011A00, 0x020B6600, 0x03, VFLAG_ON_ALL }, { "agbsave.bin" , 0x0B100000, 0x00030000, 0x07, VFLAG_ON_ALL }, { "firm0.bin" , 0x0B130000, 0x00400000, 0x06, VFLAG_ON_ALL }, { "firm1.bin" , 0x0B530000, 0x00400000, 0x06, VFLAG_ON_ALL }, - { "ctrnand_fat.bin" , 0x0B95CA00, 0x2F3E3600, 0x04, VFLAG_ON_O3DS | VFLAG_EXT_NAND_REMOUNT }, - { "ctrnand_fat.bin" , 0x0B95AE00, 0x41D2D200, 0x05, VFLAG_ON_N3DS | VFLAG_EXT_NAND_REMOUNT }, - { "ctrnand_fat.bin" , 0x0B95AE00, 0x41D2D200, 0x04, VFLAG_ON_NO3DS | VFLAG_EXT_NAND_REMOUNT }, - { "ctrnand_full.bin" , 0x0B930000, 0x2F5D0000, 0x04, VFLAG_ON_O3DS | VFLAG_EXT_NAND_REMOUNT }, - { "ctrnand_full.bin" , 0x0B930000, 0x41ED0000, 0x05, VFLAG_ON_N3DS | VFLAG_EXT_NAND_REMOUNT }, - { "ctrnand_full.bin" , 0x0B930000, 0x41ED0000, 0x04, VFLAG_ON_NO3DS | VFLAG_EXT_NAND_REMOUNT }, - { "nand.bin" , 0x00000000, 0x00000000, 0xFF, VFLAG_ON_ALL | VFLAG_NAND_SIZE | VFLAG_EXT_NAND_REMOUNT }, - { "nand_minsize.bin" , 0x00000000, 0x3AF00000, 0xFF, VFLAG_ON_O3DS | VFLAG_EXT_NAND_REMOUNT }, - { "nand_minsize.bin" , 0x00000000, 0x4D800000, 0xFF, VFLAG_ON_N3DS | VFLAG_ON_NO3DS | VFLAG_EXT_NAND_REMOUNT }, + { "ctrnand_fat.bin" , 0x0B95CA00, 0x2F3E3600, 0x04, VFLAG_ON_O3DS }, + { "ctrnand_fat.bin" , 0x0B95AE00, 0x41D2D200, 0x05, VFLAG_ON_N3DS }, + { "ctrnand_fat.bin" , 0x0B95AE00, 0x41D2D200, 0x04, VFLAG_ON_NO3DS }, + { "ctrnand_full.bin" , 0x0B930000, 0x2F5D0000, 0x04, VFLAG_ON_O3DS }, + { "ctrnand_full.bin" , 0x0B930000, 0x41ED0000, 0x05, VFLAG_ON_N3DS }, + { "ctrnand_full.bin" , 0x0B930000, 0x41ED0000, 0x04, VFLAG_ON_NO3DS }, + { "nand.bin" , 0x00000000, 0x00000000, 0xFF, VFLAG_ON_ALL | VFLAG_NAND_SIZE }, + { "nand_minsize.bin" , 0x00000000, 0x3AF00000, 0xFF, VFLAG_ON_O3DS }, + { "nand_minsize.bin" , 0x00000000, 0x4D800000, 0xFF, VFLAG_ON_N3DS | VFLAG_ON_NO3DS }, { "nand_hdr.bin" , 0x00000000, 0x00000200, 0xFF, VFLAG_ON_ALL }, { "sector0x96.bin" , 0x00012C00, 0x00000200, 0xFF, VFLAG_ON_ALL } }; diff --git a/source/nand/virtual.h b/source/nand/virtual.h index 9ecdd4b..846d7b9 100644 --- a/source/nand/virtual.h +++ b/source/nand/virtual.h @@ -3,8 +3,6 @@ #include "common.h" #include "nand.h" -#define VFLAG_EXT_NAND_REMOUNT (1<<31) - static const char* virtualFileList[] = { // must have a match in virtualFileTemplates[] "twln.bin", "twlp.bin", "agbsave.bin", "firm0.bin", "firm1.bin", "ctrnand_fat.bin", "ctrnand_full.bin", "nand.bin", "nand_minsize.bin", "nand_hdr.bin", "sector0x96.bin"