diff --git a/source/err.c b/source/err.c index 3d46632..31eaa92 100644 --- a/source/err.c +++ b/source/err.c @@ -25,7 +25,8 @@ const char *TEErrors[] = { [TE_EXCEPTION_DATA_ABORT - 1] = "E Data abort", [TE_ERR_SAME_LOC - 1] = "Same copy location", [TE_ERR_KEYDUMP_FAIL - 1] = "Keydump failed", - [TE_ERR_PARTITION_NOT_FOUND - 1] = "Failed to find partition" + [TE_ERR_PARTITION_NOT_FOUND - 1] = "Failed to find partition", + [TE_ERR_PATH_IN_PATH - 1] = "Can't move/copy folder into itself" }; const char *GetErrStr(u32 err){ diff --git a/source/err.h b/source/err.h index 98a3edf..88af1ed 100644 --- a/source/err.h +++ b/source/err.h @@ -16,6 +16,7 @@ enum { TE_ERR_SAME_LOC, TE_ERR_KEYDUMP_FAIL, TE_ERR_PARTITION_NOT_FOUND, + TE_ERR_PATH_IN_PATH, }; #define newErrCode(err) (ErrCode_t) {err, __LINE__, __FILE__} diff --git a/source/fs/fscopy.c b/source/fs/fscopy.c index 794dbea..ab8530c 100644 --- a/source/fs/fscopy.c +++ b/source/fs/fscopy.c @@ -6,6 +6,8 @@ #include #include #include "../gfx/gfxutils.h" +#include "fsutils.h" +#include "readers/folderReader.h" ErrCode_t FileCopy(const char *locin, const char *locout, u8 options){ FIL in, out; @@ -78,4 +80,100 @@ ErrCode_t FileCopy(const char *locin, const char *locout, u8 options){ //f_stat(locin, &in_info); //somehow stops fatfs from being weird return err; +} + +void BoxRestOfScreen(){ + u32 tempX, tempY; + gfx_con_getpos(&tempX, &tempY); + gfx_boxGrey(tempX, tempY, YLEFT, tempY + 16, 0x1B); +} + +ErrCode_t FolderCopy(const char *locin, const char *locout){ + char *dstPath = CombinePaths(locout, strrchr(locin, '/') + 1); + int res = 0; + ErrCode_t ret = newErrCode(0); + u32 x, y; + gfx_con_getpos(&x, &y); + + Vector_t fileVec = ReadFolder(locin, &res); + if (res){ + ret = newErrCode(res); + } + else { + vecDefArray(FSEntry_t *, fs, fileVec); + f_mkdir(dstPath); + + for (int i = 0; i < fileVec.count && !ret.err; i++){ + char *temp = CombinePaths(locin, fs[i].name); + if (fs[i].isDir){ + ret = FolderCopy(temp, dstPath); + } + else { + gfx_puts_limit(fs[i].name, (YLEFT - x) / 16 - 10); + BoxRestOfScreen(); + + char *tempDst = CombinePaths(dstPath, fs[i].name); + ret = FileCopy(temp, tempDst, COPY_MODE_PRINT); + free(tempDst); + + gfx_con_setpos(x, y); + } + free(temp); + } + } + + FILINFO fno; + + if (!ret.err){ + res = f_stat(locin, &fno); + if (res) + ret = newErrCode(res); + else + ret = newErrCode(f_chmod(dstPath, fno.fattrib, 0x3A)); + } + + free(dstPath); + clearFileVector(&fileVec); + return ret; +} + +ErrCode_t FolderDelete(const char *path){ + int res = 0; + ErrCode_t ret = newErrCode(0); + u32 x, y; + gfx_con_getpos(&x, &y); + + Vector_t fileVec = ReadFolder(path, &res); + if (res){ + ret = newErrCode(res); + } + else { + vecDefArray(FSEntry_t *, fs, fileVec); + + for (int i = 0; i < fileVec.count && !ret.err; i++){ + char *temp = CombinePaths(path, fs[i].name); + if (fs[i].isDir){ + ret = FolderDelete(temp); + } + else { + gfx_puts_limit(fs[i].name, (YLEFT - x) / 16 - 10); + BoxRestOfScreen(); + res = f_unlink(temp); + if (res){ + ret = newErrCode(res); + } + gfx_con_setpos(x, y); + } + free(temp); + } + } + + if (!ret.err){ + res = f_unlink(path); + if (res) + ret = newErrCode(res); + } + + clearFileVector(&fileVec); + return ret; } \ No newline at end of file diff --git a/source/fs/fscopy.h b/source/fs/fscopy.h index a1d8c40..a7894eb 100644 --- a/source/fs/fscopy.h +++ b/source/fs/fscopy.h @@ -5,4 +5,6 @@ #define COPY_MODE_CANCEL BIT(0) #define COPY_MODE_PRINT BIT(1) -ErrCode_t FileCopy(const char *locin, const char *locout, u8 options); \ No newline at end of file +ErrCode_t FileCopy(const char *locin, const char *locout, u8 options); +ErrCode_t FolderDelete(const char *path); +ErrCode_t FolderCopy(const char *locin, const char *locout); \ No newline at end of file diff --git a/source/fs/fsutils.c b/source/fs/fsutils.c index dc9d8b1..c23bef4 100644 --- a/source/fs/fsutils.c +++ b/source/fs/fsutils.c @@ -32,10 +32,13 @@ char *EscapeFolder(const char *current){ return ret; } -u64 GetFileSize(char *path){ +FSEntry_t GetFileInfo(const char *path){ FILINFO fno; f_stat(path, &fno); - return fno.fsize; + FSEntry_t entry = {.optionUnion = fno.fattrib, .name = strrchr(path, '/') + 1}; + if (!(*entry.name)) + entry.name = "Root"; + return entry; } char *GetFileAttribs(FSEntry_t entry){ diff --git a/source/fs/fsutils.h b/source/fs/fsutils.h index 094a146..4ab88a6 100644 --- a/source/fs/fsutils.h +++ b/source/fs/fsutils.h @@ -2,7 +2,7 @@ #include #include "fstypes.h" -u64 GetFileSize(char *path); +FSEntry_t GetFileInfo(const char *path); char *EscapeFolder(const char *current); char *CombinePaths(const char *current, const char *add); char *GetFileAttribs(FSEntry_t entry); diff --git a/source/fs/menus/explorer.c b/source/fs/menus/explorer.c index e57279c..efe4631 100644 --- a/source/fs/menus/explorer.c +++ b/source/fs/menus/explorer.c @@ -14,12 +14,13 @@ #include "../fscopy.h" #include #include "../../hid/hid.h" +#include "foldermenu.h" MenuEntry_t topEntries[] = { {.optionUnion = COLORTORGB(COLOR_GREEN) | SKIPBIT}, {.optionUnion = COLORTORGB(COLOR_ORANGE)}, {.optionUnion = COLORTORGB(COLOR_GREY) | SKIPBIT, .name = "Clipboard -> Current folder"}, - {.optionUnion = COLORTORGB(COLOR_GREY) | SKIPBIT, .name = "Current folder options"} + {.optionUnion = COLORTORGB(COLOR_ORANGE), .name = "Current folder options"} }; MenuEntry_t MakeMenuOutFSEntry(FSEntry_t entry){ @@ -36,6 +37,9 @@ void FileExplorer(char *path){ char *storedPath = CpyStr(path); int res = 0; + if (TConf.explorerCopyMode == CMODE_Move || TConf.explorerCopyMode == CMODE_MoveFolder) + ResetCopyParams(); + while (1){ topEntries[2].optionUnion = (TConf.explorerCopyMode != CMODE_None) ? (COLORTORGB(COLOR_ORANGE)) : (COLORTORGB(COLOR_GREY) | SKIPBIT); topEntries[1].name = (!strcmp(storedPath, path)) ? "<- Exit explorer" : "<- Folder back"; @@ -74,30 +78,50 @@ void FileExplorer(char *path){ char *oldPath = storedPath; if (res == 2){ - ErrCode_t res; + ErrCode_t err = {0}; char *filename = CpyStr(strrchr(TConf.srcCopy, '/') + 1); char *dst = CombinePaths(storedPath, filename); if (!strcmp(TConf.srcCopy, dst)) - res = newErrCode(TE_ERR_SAME_LOC); - else { - if (TConf.explorerCopyMode == CMODE_Move){ - if ((res.err = f_rename(TConf.srcCopy, dst))) - res = newErrCode(res.err); + err = newErrCode(TE_ERR_SAME_LOC); + + if (!err.err && TConf.explorerCopyMode >= CMODE_CopyFolder){ + if (strstr(dst, TConf.srcCopy) != NULL) + err = newErrCode(TE_ERR_PATH_IN_PATH); + } + + if (!err.err){ + if (TConf.explorerCopyMode == CMODE_Move || TConf.explorerCopyMode == CMODE_MoveFolder){ + if ((err.err = f_rename(TConf.srcCopy, dst))) + err = newErrCode(err.err); + } + else if (TConf.explorerCopyMode == CMODE_Copy) { + gfx_clearscreen(); + RESETCOLOR; + gfx_printf("Hold vol+/- to cancel\nCopying %s... ", filename); + err = FileCopy(TConf.srcCopy, dst, COPY_MODE_CANCEL | COPY_MODE_PRINT); } else { gfx_clearscreen(); RESETCOLOR; - gfx_printf("Hold vol+/- to cancel\nCopying %s... ", filename); - res = FileCopy(TConf.srcCopy, dst, COPY_MODE_CANCEL | COPY_MODE_PRINT); + gfx_printf("\nCopying folder... "); + err = FolderCopy(TConf.srcCopy, storedPath); } } + - DrawError(res); + DrawError(err); free(dst); free(filename); ResetCopyParams(); } + else if (res == 3){ + if (FolderMenu(storedPath)){ + storedPath = EscapeFolder(oldPath); + free(oldPath); + res = 0; + } + } else if (res < ARR_LEN(topEntries)) { if (!strcmp(storedPath, path)){ clearFileVector(&fileVec); diff --git a/source/fs/menus/filemenu.c b/source/fs/menus/filemenu.c index 86b0d20..6938f03 100644 --- a/source/fs/menus/filemenu.c +++ b/source/fs/menus/filemenu.c @@ -17,7 +17,6 @@ #include MenuEntry_t FileMenuEntries[] = { - // Still have to think up the options {.optionUnion = COLORTORGB(COLOR_WHITE) | SKIPBIT, .name = "-- File menu --"}, {.optionUnion = COLORTORGB(COLOR_GREEN) | SKIPBIT}, // For the file name and size {.optionUnion = COLORTORGB(COLOR_VIOLET) | SKIPBIT}, // For the file Attribs @@ -91,7 +90,7 @@ void RunScript(char *path, FSEntry_t entry){ hidWait(); } -menuPaths FileMenuPaths[] = { +fileMenuPath FileMenuPaths[] = { CopyClipboard, MoveClipboard, UnimplementedException, diff --git a/source/fs/menus/foldermenu.c b/source/fs/menus/foldermenu.c new file mode 100644 index 0000000..f30da53 --- /dev/null +++ b/source/fs/menus/foldermenu.c @@ -0,0 +1,101 @@ +#include "foldermenu.h" +#include "../../err.h" +#include "../../gfx/menu.h" +#include "../../gfx/gfxutils.h" +#include "../fsutils.h" +#include +#include +#include +#include "../../tegraexplorer/tconf.h" +#include "../../hid/hid.h" +#include +#include "../../utils/utils.h" +#include "../../keys/nca.h" +#include "../../script/lexer.h" +#include "../../script/parser.h" +#include "../../script/variables.h" +#include +#include "../fscopy.h" + +MenuEntry_t FolderMenuEntries[] = { + {.optionUnion = COLORTORGB(COLOR_WHITE) | SKIPBIT, .name = "-- Folder menu --"}, + {.optionUnion = COLORTORGB(COLOR_GREEN) | SKIPBIT}, // For the file name and size + {.optionUnion = COLORTORGB(COLOR_VIOLET) | SKIPBIT}, // For the file Attribs + {.optionUnion = HIDEBIT}, + {.optionUnion = COLORTORGB(COLOR_WHITE), .name = "<- Back"}, + {.optionUnion = COLORTORGB(COLOR_BLUE), .name = "\nCopy to clipboard"}, + {.optionUnion = COLORTORGB(COLOR_BLUE), .name = "Move to clipboard"}, + {.optionUnion = COLORTORGB(COLOR_BLUE), .name = "Rename current folder\n"}, + {.optionUnion = COLORTORGB(COLOR_RED), .name = "Delete current folder"}, + {.optionUnion = COLORTORGB(COLOR_GREEN), .name = "\nCreate folder"} +}; + +int UnimplementedFolderException(const char *path){ + DrawError(newErrCode(TE_ERR_UNIMPLEMENTED)); + return 0; +} + +int FolderCopyClipboard(const char *path){ + SetCopyParams(path, CMODE_CopyFolder); + return 0; +} + +int FolderMoveClipboard(const char *path){ + SetCopyParams(path, CMODE_MoveFolder); + return 0; +} + +int DeleteFolder(const char *path){ + gfx_con_setpos(384 + 16, 200 + 16 + 10 * 16); + SETCOLOR(COLOR_RED, COLOR_DARKGREY); + gfx_printf("Are you sure? "); + + WaitFor(1000); + if (MakeYesNoHorzMenu(3, COLOR_DARKGREY)){ + gfx_clearscreen(); + SETCOLOR(COLOR_RED, COLOR_DEFAULT); + gfx_printf("\nDeleting... "); + ErrCode_t err = FolderDelete(path); + if (err.err){ + DrawError(err); + } + else return 1; + } + return 0; +} + +folderMenuPath FolderMenuPaths[] = { + FolderCopyClipboard, + FolderMoveClipboard, + UnimplementedFolderException, + DeleteFolder, + UnimplementedFolderException +}; + +int FolderMenu(const char *path){ + FSEntry_t file = GetFileInfo(path); + FolderMenuEntries[1].name = file.name; + + char attribs[16]; + char *attribList = GetFileAttribs(file); + sprintf(attribs, "Attribs:%s\n", attribList); + free(attribList); + FolderMenuEntries[2].name = attribs; + + // If root, disable all options other than create folder! + int isRoot = !strcmp(file.name, "Root"); + FolderMenuEntries[2].hide = isRoot; + for (int i = 5; i <= 8; i++) + FolderMenuEntries[i].hide = isRoot; + + + Vector_t ent = vecFromArray(FolderMenuEntries, ARR_LEN(FolderMenuEntries), sizeof(MenuEntry_t)); + gfx_boxGrey(384, 200, 384 + 512, 200 + 320, 0x33); + gfx_con_setpos(384 + 16, 200 + 16); + int res = newMenu(&ent, 0, 30, 19, ENABLEB | ALWAYSREDRAW | USELIGHTGREY, ent.count); + + if (res <= 4) + return 0; + + return FolderMenuPaths[res - 5](path); +} \ No newline at end of file diff --git a/source/fs/menus/foldermenu.h b/source/fs/menus/foldermenu.h new file mode 100644 index 0000000..137fc1a --- /dev/null +++ b/source/fs/menus/foldermenu.h @@ -0,0 +1,4 @@ +#pragma once + +typedef int (*folderMenuPath)(const char *path); +int FolderMenu(const char *path); \ No newline at end of file diff --git a/source/fs/readers/folderReader.c b/source/fs/readers/folderReader.c index c1e6e79..70b9d26 100644 --- a/source/fs/readers/folderReader.c +++ b/source/fs/readers/folderReader.c @@ -11,7 +11,7 @@ void clearFileVector(Vector_t *v){ free(v->data); } -Vector_t /* of type FSEntry_t */ ReadFolder(char *path, int *res){ +Vector_t /* of type FSEntry_t */ ReadFolder(const char *path, int *res){ Vector_t out = newVec(sizeof(FSEntry_t), 16); // we may want to prealloc with the same size as the folder DIR dir; FILINFO fno; diff --git a/source/fs/readers/folderReader.h b/source/fs/readers/folderReader.h index b875757..be9cff2 100644 --- a/source/fs/readers/folderReader.h +++ b/source/fs/readers/folderReader.h @@ -4,4 +4,4 @@ #include "../fstypes.h" void clearFileVector(Vector_t *v); -Vector_t /* of type FSEntry_t */ ReadFolder(char *path, int *res); \ No newline at end of file +Vector_t /* of type FSEntry_t */ ReadFolder(const char *path, int *res); \ No newline at end of file diff --git a/source/tegraexplorer/mainmenu.c b/source/tegraexplorer/mainmenu.c index a4683ca..2e20d9b 100644 --- a/source/tegraexplorer/mainmenu.c +++ b/source/tegraexplorer/mainmenu.c @@ -72,6 +72,7 @@ void ViewKeys(){ } extern bool sd_mounted; +extern bool is_sd_inited; void MountOrUnmountSD(){ (sd_mounted) ? sd_unmount() : sd_mount(); @@ -100,6 +101,7 @@ void EnterMainMenu(){ mainMenuEntries[1].hide = !sd_mounted; mainMenuEntries[2].hide = !TConf.keysDumped; mainMenuEntries[3].hide = (!TConf.keysDumped || !emu_cfg.enabled || !sd_mounted); + mainMenuEntries[6].hide = (!is_sd_inited || sd_get_card_removed()); mainMenuEntries[7].hide = !TConf.keysDumped; mainMenuEntries[9].name = (sd_mounted) ? "Unmount SD" : "Mount SD"; FunctionMenuHandler(mainMenuEntries, ARR_LEN(mainMenuEntries), mainMenuPaths, ALWAYSREDRAW); diff --git a/source/tegraexplorer/tconf.h b/source/tegraexplorer/tconf.h index 3476dda..33f1237 100644 --- a/source/tegraexplorer/tconf.h +++ b/source/tegraexplorer/tconf.h @@ -12,7 +12,9 @@ enum { enum { CMODE_None = 0, CMODE_Copy, - CMODE_Move + CMODE_Move, + CMODE_CopyFolder, + CMODE_MoveFolder }; typedef struct { @@ -24,7 +26,7 @@ typedef struct { u16 keysDumped:1; u16 curExplorerLoc:2; u16 heldExplorerCopyLoc:2; - u16 explorerCopyMode:2; + u16 explorerCopyMode:4; u16 currentMMCConnected:2; u16 connectedMMCMounted:1; }; diff --git a/source/tegraexplorer/tools.c b/source/tegraexplorer/tools.c index e1e0eda..b9d464c 100644 --- a/source/tegraexplorer/tools.c +++ b/source/tegraexplorer/tools.c @@ -82,7 +82,8 @@ void DumpSysFw(){ return; } RESETCOLOR; - gfx_printf("\nReminder! delete the folder. i can't delete recursively yet"); + gfx_printf("\nDeleting... "); + FolderDelete(baseSdPath); gfx_putc('\n'); }