From 790f264a68a76755f750b945490a67cc09918985 Mon Sep 17 00:00:00 2001 From: d0k3 Date: Fri, 2 Dec 2016 12:45:23 +0100 Subject: [PATCH] Enable recursive copy of virtual directories --- source/common.h | 2 +- source/fs.c | 149 +++++++++++++++++++++++++-------------- source/virtual/virtual.c | 18 ++--- source/virtual/virtual.h | 2 + 4 files changed, 110 insertions(+), 61 deletions(-) diff --git a/source/common.h b/source/common.h index fd0ea8e..00abf0f 100644 --- a/source/common.h +++ b/source/common.h @@ -38,7 +38,7 @@ (((v) % (a)) ? ((v) + (a) - ((v) % (a))) : (v)) // GodMode9 version -#define VERSION "0.8.0" +#define VERSION "0.8.1" // buffer area defines (in use by godmode.c) #define DIR_BUFFER (0x21000000) diff --git a/source/fs.c b/source/fs.c index 9cca115..eac751c 100644 --- a/source/fs.c +++ b/source/fs.c @@ -733,39 +733,48 @@ bool PathCopyFatToVrt(const char* destdir, const char* orig) { return ret; } -bool PathCopyVrtToFat(const char* destdir, const char* orig, u32* flags) { - VirtualFile ovfile; - FIL dfile; - bool ret = true; +bool PathCopyVrtToFat(char* dest, char* orig, u32* flags) { + VirtualFile vfile; + FILINFO fno; + bool ret = false; - char dest[256]; // maximum path name length in FAT + if (fa_stat(dest, &fno) != FR_OK) { // is root or destination does not exist + DIR tmp_dir; // check if root + if (fa_opendir(&tmp_dir, dest) != FR_OK) return false; + f_closedir(&tmp_dir); + } else if (!(fno.fattrib & AM_DIR)) return false; // destination is not a directory (must be at this point) + + // build full destination path (on top of destination directory) char* oname = strrchr(orig, '/'); + char* dname = dest + strnlen(dest, 255); if (oname == NULL) return false; // not a proper origin path - snprintf(dest, 255, "%s/%s", destdir, (++oname)); + oname++; + *(dname++) = '/'; + strncpy(dname, oname, 256 - (dname - dest)); - if (!GetVirtualFile(&ovfile, orig)) + // open / check virtual file + if (!GetVirtualFile(&vfile, orig)) return false; // check if destination exists - if (flags && !(*flags & OVERWRITE_ALL) && fa_stat(dest, NULL) == FR_OK) { + if (flags && !(*flags & (OVERWRITE_CUR|OVERWRITE_ALL)) && (fa_stat(dest, NULL) == FR_OK)) { if (*flags & SKIP_ALL) { *flags |= SKIP_CUR; return true; } - char deststr[36 + 1]; - TruncateString(deststr, dest, 36, 8); const char* optionstr[5] = - {"Choose new name", "Overwrite file", "Skip file", "Overwrite all", "Skip all"}; + {"Choose new name", "Overwrite file(s)", "Skip file(s)", "Overwrite all", "Skip all"}; + char namestr[36 + 1]; + TruncateString(namestr, dest, 36, 8); u32 user_select = ShowSelectPrompt((*flags & ASK_ALL) ? 5 : 3, optionstr, - "Destination already exists:\n%s", deststr); + "Destination already exists:\n%s", namestr); if (user_select == 1) { do { - char* dname = strrchr(dest, '/'); - if (dname == NULL) return false; - dname++; if (!ShowStringPrompt(dname, 255 - (dname - dest), "Choose new destination name")) return false; } while (fa_stat(dest, NULL) == FR_OK); + } else if (user_select == 2) { + *flags |= OVERWRITE_CUR; } else if (user_select == 3) { *flags |= SKIP_CUR; return true; @@ -774,39 +783,76 @@ bool PathCopyVrtToFat(const char* destdir, const char* orig, u32* flags) { } else if (user_select == 5) { *flags |= (SKIP_CUR|SKIP_ALL); return true; - } else if (user_select != 2) { + } else { return false; } } - if (fx_open(&dfile, dest, FA_WRITE | FA_CREATE_ALWAYS) != FR_OK) - return false; - f_lseek(&dfile, 0); - f_sync(&dfile); - u32 osize = ovfile.size; - if (GetFreeSpace(dest) < osize) { - ShowPrompt(false, "Error: File is too big for destination"); + // the copy process takes place here + if (!ShowProgress(0, 0, orig)) return false; + if (vfile.flags & VFLAG_DIR) { // processing folders + DIR pdir; + VirtualDir vdir; + char* fname = orig + strnlen(orig, 256); + + // create the destination folder if it does not already exist + if (fa_opendir(&pdir, dest) != FR_OK) { + if (f_mkdir(dest) != FR_OK) { + ShowPrompt(false, "Error: Overwriting file with dir"); + return false; + } + } else f_closedir(&pdir); + + if (!OpenVirtualDir(&vdir, &vfile)) + return false; + *(fname++) = '/'; + while (true) { + if (!ReadVirtualDir(&vfile, &vdir)) { + ret = true; + break; + } + char name[256]; + if (!GetVirtualFilename(name, &vfile, 256)) break; + strncpy(fname, name, 256 - (fname - orig)); + if (!PathCopyVrtToFat(dest, orig, flags)) + break; + } + } else { // copying files + FIL dfile; + u32 osize = vfile.size; + + if (GetFreeSpace(dest) < osize) { + ShowPrompt(false, "Error: File is too big for destination"); + return false; + } + + if (fx_open(&dfile, dest, FA_WRITE | FA_CREATE_ALWAYS) != FR_OK) { + ShowPrompt(false, "Error: Cannot create destination file"); + return false; + } + f_lseek(&dfile, 0); + f_sync(&dfile); + + 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_written = 0; + if (ReadVirtualFile(&vfile, MAIN_BUFFER, pos, read_bytes, NULL) != 0) + ret = false; + if (!ShowProgress(pos + (read_bytes / 2), osize, orig)) + ret = false; + if (fx_write(&dfile, MAIN_BUFFER, read_bytes, &bytes_written) != FR_OK) + ret = false; + if (read_bytes != bytes_written) + ret = false; + } + ShowProgress(1, 1, orig); + fx_close(&dfile); - return false; + if (!ret) f_unlink(dest); } - 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, NULL) != 0) - ret = false; - if (!ShowProgress(pos + (read_bytes / 2), osize, orig)) - ret = false; - if (fx_write(&dfile, MAIN_BUFFER, read_bytes, &bytes_written) != FR_OK) - ret = false; - if (read_bytes != bytes_written) - ret = false; - } - ShowProgress(1, 1, orig); - fx_close(&dfile); - if (!ret) f_unlink(dest); - + *(--dname) = '\0'; return ret; } @@ -882,9 +928,11 @@ bool PathCopyWorker(char* dest, char* orig, u32* flags, bool move) { char* fname = orig + strnlen(orig, 256); // create the destination folder if it does not already exist - if ((fa_opendir(&pdir, dest) != FR_OK) && (f_mkdir(dest) != FR_OK)) { - ShowPrompt(false, "Error: Overwriting file with dir"); - return false; + if (fa_opendir(&pdir, dest) != FR_OK) { + if (f_mkdir(dest) != FR_OK) { + ShowPrompt(false, "Error: Overwriting file with dir"); + return false; + } } else f_closedir(&pdir); if (fa_opendir(&pdir, orig) != FR_OK) @@ -967,24 +1015,21 @@ bool PathCopy(const char* destdir, const char* orig, u32* flags) { if (flags) *flags = *flags & ~(SKIP_CUR|OVERWRITE_CUR); // reset local flags int ddrvtype = DriveType(destdir); int odrvtype = DriveType(orig); - if (!((ddrvtype|odrvtype) & DRV_VIRTUAL)) { // standard FAT to FAT copy + if (!(ddrvtype & DRV_VIRTUAL)) { // FAT / virtual to FAT char fdpath[256]; // 256 is the maximum length of a full path char fopath[256]; strncpy(fdpath, destdir, 255); strncpy(fopath, orig, 255); - bool res = PathCopyWorker(fdpath, fopath, flags, false); + bool res = (odrvtype & DRV_VIRTUAL) ? PathCopyVrtToFat(fdpath, fopath, flags) : + PathCopyWorker(fdpath, fopath, flags, false); return res; - } else if ((ddrvtype&odrvtype) & DRV_VIRTUAL) { // virtual to virtual copy - return PathCopyVrtToVrt(destdir, orig); - } else if (odrvtype & DRV_VIRTUAL) { // virtual to FAT copy - return PathCopyVrtToFat(destdir, orig, flags); - } else { // FAT to virtual copy + } else if (!(odrvtype & DRV_VIRTUAL)) { // FAT to virtual if (!(odrvtype & (DRV_SDCARD|DRV_RAMDRIVE))) { ShowPrompt(false, "Only files from SD card or\nramdrive are accepted"); return false; } return PathCopyFatToVrt(destdir, orig); - } + } else return PathCopyVrtToVrt(destdir, orig); // virtual to virtual } bool PathMove(const char* destdir, const char* orig, u32* flags) { diff --git a/source/virtual/virtual.c b/source/virtual/virtual.c index c1d249f..a6944e4 100644 --- a/source/virtual/virtual.c +++ b/source/virtual/virtual.c @@ -116,13 +116,9 @@ bool GetVirtualDirContents(DirStruct* contents, char* fpath, int fnsize, const c return false; // get dir reader object while ((contents->n_entries < MAX_DIR_ENTRIES) && (ReadVirtualDir(&vfile, &vdir))) { DirEntry* entry = &(contents->entry[contents->n_entries]); - if (!(vfile.flags & VRT_GAME)) { - strncpy(fname, vfile.name, (fnsize - 1) - (fname - fpath)); - } else { - char name[256]; - if (!GetVGameFilename(name, &vfile, 256)) return false; - strncpy(fname, name, (fnsize - 1) - (fname - fpath)); - } + char name[256]; + GetVirtualFilename(name, &vfile, 256); + strncpy(fname, name, (fnsize - 1) - (fname - fpath)); if (!pattern || MatchName(pattern, fname)) { strncpy(entry->path, fpath, 256); entry->name = entry->path + (fname - fpath); @@ -140,7 +136,13 @@ bool GetVirtualDirContents(DirStruct* contents, char* fpath, int fnsize, const c return true; // not much we can check here } -int ReadVirtualFile(const VirtualFile* vfile, u8* buffer, u32 offset, u32 count, u32* bytes_read) +bool GetVirtualFilename(char* name, const VirtualFile* vfile, u32 n_chars) { + if (!(vfile->flags & VRT_GAME)) strncpy(name, vfile->name, n_chars); + else if (!GetVGameFilename(name, vfile, 256)) return false; + return true; +} + +int ReadVirtualFile(const VirtualFile* vfile, u8* buffer, u32 offset, u32 count, u32* bytes_read) /// (u64) !!!! { // basic check of offset / count if (offset >= vfile->size) diff --git a/source/virtual/virtual.h b/source/virtual/virtual.h index bf3608f..eb8861b 100644 --- a/source/virtual/virtual.h +++ b/source/virtual/virtual.h @@ -49,5 +49,7 @@ bool GetVirtualFile(VirtualFile* vfile, const char* path); bool GetVirtualDir(VirtualDir* vdir, const char* path); bool GetVirtualDirContents(DirStruct* contents, char* fpath, int fnsize, const char* pattern, bool recursive); +bool GetVirtualFilename(char* name, const VirtualFile* vfile, u32 n_chars); + int ReadVirtualFile(const VirtualFile* vfile, u8* buffer, u32 offset, u32 count, u32* bytes_read); int WriteVirtualFile(const VirtualFile* vfile, const u8* buffer, u32 offset, u32 count, u32* bytes_written);