diff --git a/include/fsutil.h b/include/fsutil.h index 332ab25..18fe8cf 100644 --- a/include/fsutil.h +++ b/include/fsutil.h @@ -25,3 +25,4 @@ Result fsQuickRead(const char *const path, void *const buf, u32 size); Result fsQuickWrite(const char *const path, const void *const buf, u32 size); +Result fsMakePath(const char *const path); diff --git a/include/util.h b/include/util.h index 248cedd..16809cd 100644 --- a/include/util.h +++ b/include/util.h @@ -26,7 +26,26 @@ -NAKED void wait(u32 cycles); +/** + * @brief Waits at least the specified amount of CPU cycles. + * + * @param[in] cycles The cycles to wait. + */ +NAKED void wait_cycles(u32 cycles); + +/** + * @brief Safer strcpy with checks. + * The dst string always gets terminated except when num is 0. + * If the src string is too long nothing is copied and dst will be terminated. + * This function is not safe against race conditions! + * + * @param dst The destination pointer. + * @param[in] src The source pointer. + * @param[in] num Maximum number of chars to copy including null terminator. + * + * @return The length of the copied string in bytes including null terminator. + */ +size_t safeStrcpy(char *const dst, const char *const src, size_t num); // case insensitive string compare function int strnicmp(const char *str1, const char *str2, u32 len); diff --git a/source/arm11/filebrowser.c b/source/arm11/filebrowser.c index 943c42a..8995c82 100644 --- a/source/arm11/filebrowser.c +++ b/source/arm11/filebrowser.c @@ -3,6 +3,7 @@ #include "types.h" #include "error_codes.h" #include "fs.h" +#include "util.h" #include "arm11/hardware/hid.h" #include "arm11/fmt.h" #include "hardware/gfx.h" @@ -17,7 +18,7 @@ typedef struct { u8 type; // 0 = file, 1 = dir - char str[255]; + char str[256]; } DirListEnt; typedef struct @@ -29,22 +30,6 @@ typedef struct -// num including null terminator. -static size_t safeStrcpy(char *const dst, const char *const src, size_t num) -{ - if(num == 0) return 0; - - const size_t len = strlen(src) + 1; - if(len > num) - { - *dst = '\0'; - return 1; - } - - strcpy(dst, src); - return len; -} - int dlistCompare(const void *a, const void *b) { const DirListEnt *const entA = *(DirListEnt**)a; @@ -90,7 +75,7 @@ static Result scanDir(const char *const path, DirList *const dList, const char * } dList->entries[dListPos].type = isDir; - safeStrcpy(dList->entries[dListPos].str, fi[i].fname, 255); + safeStrcpy(dList->entries[dListPos].str, fi[i].fname, 256); dList->ptrs[dListPos] = &dList->entries[dListPos]; dListPos++; } @@ -196,7 +181,7 @@ Result browseFiles(const char *const basePath, char selected[512]) { // TODO: !!! Insecure !!! if(curDir[pathLen - 1] != '/') curDir[pathLen++] = '/'; - safeStrcpy(curDir + pathLen, dList->ptrs[cursorPos]->str, 255); + safeStrcpy(curDir + pathLen, dList->ptrs[cursorPos]->str, 256); if(dList->ptrs[cursorPos]->type == 0) { diff --git a/source/arm11/hardware/gfx.c b/source/arm11/hardware/gfx.c index 7b03dbd..b5c46a1 100644 --- a/source/arm11/hardware/gfx.c +++ b/source/arm11/hardware/gfx.c @@ -74,7 +74,7 @@ void GFX_init(GfxFbFmt fmtTop, GfxFbFmt fmtBot) // Reset REG_PDN_GPU_CNT = PDN_GPU_CNT_CLK_E; - wait(12); + wait_cycles(12); REG_PDN_GPU_CNT = PDN_GPU_CNT_CLK_E | PDN_GPU_CNT_RST_ALL; REG_GX_GPU_CLK = 0x100; REG_GX_PSC_VRAM = 0; @@ -452,7 +452,7 @@ void GX_textureCopy(const u32 *const in, u32 indim, u32 *out, u32 outdim, u32 si void GX_processCommandList(u32 size, const u32 *const cmdList) { REG_GX_P3D(GPUREG_IRQ_ACK) = 0; // Acknowledge last P3D. - while(REG_GX_PSC_STAT & 1u<<31) wait(0x30); + while(REG_GX_PSC_STAT & 1u<<31) wait_cycles(0x30); REG_GX_P3D(GPUREG_CMDBUF_SIZE0) = size>>3; REG_GX_P3D(GPUREG_CMDBUF_ADDR0) = (u32)cmdList>>3; diff --git a/source/arm11/main.c b/source/arm11/main.c index a29ea08..5380b15 100644 --- a/source/arm11/main.c +++ b/source/arm11/main.c @@ -33,6 +33,7 @@ #include "arm11/power.h" #include "hardware/gfx.h" #include "fs.h" +#include "fsutil.h" #include "arm11/filebrowser.h" #include "arm.h" #include "arm11/hardware/lcd.h" @@ -41,6 +42,9 @@ #include "kevent.h" +#define OAF_WORK_DIR "sdmc:/3ds/open_agb_firm" + + static u32 padRomArea(u32 romFileSize) { @@ -265,7 +269,7 @@ saveTypeFound: return saveType; } -u16 saveDbDebug(const char *const savePath, u32 romSize) +static u16 saveDbDebug(const char *const savePath, u32 romSize) { FILINFO fi; const bool saveExists = fStat(savePath, &fi) == RES_OK; @@ -470,7 +474,7 @@ static void gbaGfxHandler(void *args) } #ifndef NDEBUG -void debugTests(void) +static void debugTests(void) { const u32 kDown = hidKeysDown(); @@ -500,6 +504,52 @@ void debugTests(void) } #endif +static Result handleFsStuff(char romPath[512]) +{ + // Mount SD card. + Result res; + if((res = fMount(FS_DRIVE_SDMC)) == RES_OK) + { + char *lastDir = (char*)calloc(512, 1); + if(lastDir != NULL) + { + do + { + // Create working dir. + if((res = fsMakePath(OAF_WORK_DIR)) != RES_OK && res != RES_FR_EXIST) break; + + // Get last ROM launch path. + if((res = fsQuickRead(OAF_WORK_DIR "/lastdir.bin", lastDir, 511)) != RES_OK) + { + if(res == RES_FR_NO_FILE) strcpy(lastDir, "sdmc:/"); + else break; + } + + // Show file browser. + *romPath = '\0'; + if((res = browseFiles(lastDir, romPath)) != RES_OK) break; + + size_t cmpLen = strrchr(romPath, '/') - romPath; + if((size_t)(strchr(romPath, '/') - romPath) == cmpLen) cmpLen++; // Keep the first '/'. + if(cmpLen < 512) + { + if(cmpLen < strlen(lastDir) || strncmp(lastDir, romPath, cmpLen) != 0) + { + strncpy(lastDir, romPath, cmpLen); + lastDir[cmpLen] = '\0'; + res = fsQuickWrite(OAF_WORK_DIR "/lastdir.bin", lastDir, cmpLen + 1); + } + } + } while(0); + + free(lastDir); + } + else res = RES_OUT_OF_MEM; + } + + return res; +} + int main(void) { GFX_init(GFX_BGR8, GFX_RGB565); @@ -507,12 +557,9 @@ int main(void) consoleInit(SCREEN_BOT, NULL); //CODEC_init(); - // Show file browser. - Result res; char *romPath = (char*)malloc(512); - *romPath = '\0'; - if((res = fMount(FS_DRIVE_SDMC)) != RES_OK || (res = browseFiles("sdmc:/", romPath)) != RES_OK || *romPath == '\0') - goto end; + Result res = handleFsStuff(romPath); + if(res != RES_OK || *romPath == '\0') goto end; ee_puts("Reading ROM and save..."); u32 romSize; diff --git a/source/arm9/hardware/sdmmc.c b/source/arm9/hardware/sdmmc.c index f10c7c5..420e4ad 100644 --- a/source/arm9/hardware/sdmmc.c +++ b/source/arm9/hardware/sdmmc.c @@ -470,7 +470,7 @@ int SD_Init() set_target(&handleSD); // TMIO base clock is half of the CPU clock so 2 CPU cycles = 1 base clock pulse. // cycles = 2 * [TMIO clock divider] * 74 - wait(2 * 128 * 74); + wait_cycles(2 * 128 * 74); sdmmc_send_command(&handleSD,0,0); sdmmc_send_command(&handleSD,0x10408,0x1AA); diff --git a/source/fsutil.c b/source/fsutil.c index 3eeeab0..eb68fec 100644 --- a/source/fsutil.c +++ b/source/fsutil.c @@ -19,6 +19,7 @@ #include #include "fsutil.h" #include "fs.h" +#include "util.h" @@ -54,3 +55,30 @@ Result fsQuickWrite(const char *const path, const void *const buf, u32 size) return res; } + +Result fsMakePath(const char *const path) +{ + char tmpPath[512]; + safeStrcpy(tmpPath, path, 512); + + char *str; + if((str = strchr(tmpPath, ':')) == NULL) str = tmpPath; + else str++; + + // Path without any dir. + if(*str == '\0') return RES_INVALID_ARG; + + Result res = RES_OK; + while((str = strchr(str + 1, '/')) != NULL) + { + *str = '\0'; + if((res = fMkdir(tmpPath)) != RES_OK && res != RES_FR_EXIST) break; + *str = '/'; + } + + // Only create the last dir in the path if the + // previous error code is not an unexpected one. + if(res == RES_OK || res == RES_FR_EXIST) res = fMkdir(tmpPath); + + return res; +} diff --git a/source/util.c b/source/util.c index 0832df4..a2df853 100644 --- a/source/util.c +++ b/source/util.c @@ -23,7 +23,7 @@ -NAKED void wait(u32 cycles) +NAKED void wait_cycles(u32 cycles) { #ifdef ARM9 __asm__("1: subs %0, %0, #4\n\t" @@ -35,6 +35,22 @@ NAKED void wait(u32 cycles) "bx lr\n\t" : : "r" (cycles) : "cc"); } +size_t safeStrcpy(char *const dst, const char *const src, size_t num) +{ + if(num == 0) return 0; + + const size_t len = strlen(src) + 1; + if(len > num) + { + *dst = '\0'; + return 1; + } + + strcpy(dst, src); + + return len; +} + // case insensitive string compare function int strnicmp(const char *str1, const char *str2, u32 len) {