mirror of
https://github.com/d0k3/GodMode9.git
synced 2025-06-26 13:42:47 +00:00
Preliminary NAND SD drive support
... no crypto yet. Also some minor bugfixes
This commit is contained in:
parent
7f65846499
commit
1fced99d65
206
source/fatfs/alias.c
Normal file
206
source/fatfs/alias.c
Normal file
@ -0,0 +1,206 @@
|
||||
#include "alias.h"
|
||||
#include "aes.h"
|
||||
#include "sha.h"
|
||||
|
||||
#define SDCRYPT_BUFFER ((u8*)0x21400000)
|
||||
#define SDCRYPT_BUFFER_SIZE (0x100000)
|
||||
|
||||
#define NUM_ALIAS_DRV 2
|
||||
|
||||
char alias_drv[NUM_ALIAS_DRV]; // 1 char ASCII drive number of the alias drive / 0x00 if unused
|
||||
char alias_path[NUM_ALIAS_DRV][128]; // full path to resolve the alias into
|
||||
|
||||
u8 sd_keyy[NUM_ALIAS_DRV][16]; // key Y belonging to alias drive
|
||||
|
||||
int alias_num (const TCHAR* path) {
|
||||
int num = -1;
|
||||
for (u32 i = 0; i < NUM_ALIAS_DRV; i++) {
|
||||
if (!alias_drv[i]) continue;
|
||||
if ((path[0] == alias_drv[i]) && (path[1] == ':')) {
|
||||
num = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return num;
|
||||
}
|
||||
|
||||
void dealias_path (TCHAR* alias, const TCHAR* path) {
|
||||
int num = alias_num(path);
|
||||
if (num >= 0) // set alias (alias is assumed to be 256 byte)
|
||||
snprintf(alias, 256, "%s%s", alias_path[num], path + 2);
|
||||
else strncpy(alias, path, 256);
|
||||
}
|
||||
|
||||
void fx_crypt(XFIL* xfp, void* buff, FSIZE_t off, UINT bt) {
|
||||
u32 mode = AES_CNT_CTRNAND_MODE;
|
||||
u8 ctr[16] __attribute__((aligned(32)));
|
||||
u8 buff16[16];
|
||||
u8* buffer = buff;
|
||||
|
||||
// copy CTR and increment it
|
||||
memcpy(ctr, xfp->iv, 16);
|
||||
add_ctr(ctr, off / 16);
|
||||
|
||||
// setup the key
|
||||
setup_aeskeyY(xfp->keyslot, xfp->keyy);
|
||||
use_aeskey(xfp->keyslot);
|
||||
|
||||
// handle misaligned offset (at beginning)
|
||||
if (off % 16) {
|
||||
memcpy(buff16 + (off % 16), buff, 16 - (off % 16));
|
||||
ctr_decrypt(buff16, buff16, 1, mode, ctr);
|
||||
bt -= 16 - (off % 16);
|
||||
buffer += 16 - (off % 16);
|
||||
}
|
||||
|
||||
// de/encrypt the data
|
||||
ctr_decrypt(buff, buff, bt / 16, mode, ctr);
|
||||
bt -= 16 * (UINT) (bt / 16);
|
||||
buffer += 16 * (UINT) (bt / 16);
|
||||
|
||||
// handle misaligned offset (at end)
|
||||
if (bt) {
|
||||
memcpy(buff16, buff, bt);
|
||||
ctr_decrypt(buff16, buff16, 1, mode, ctr);
|
||||
buffer += bt;
|
||||
bt = 0;
|
||||
}
|
||||
}
|
||||
|
||||
FRESULT fx_open (FIL* fp, XFIL* xfp, const TCHAR* path, BYTE mode) {
|
||||
int num = alias_num(path);
|
||||
xfp->keyslot = 0x40;
|
||||
if (num >= 0) {
|
||||
// get AES counter, see: http://www.3dbrew.org/wiki/Extdata#Encryption
|
||||
// path is the part of the full path after //Nintendo 3DS/<ID0>/<ID1>
|
||||
u8 hashstr[256];
|
||||
u8 sha256sum[32];
|
||||
u32 plen = 0;
|
||||
// poor man's UTF-8 -> UTF-16
|
||||
for (u32 plen = 0; plen < 128; plen++) {
|
||||
hashstr[2*plen] = path[2 + plen];
|
||||
hashstr[2*plen+1] = 0;
|
||||
if (path[plen] == 0) break;
|
||||
}
|
||||
sha_quick(sha256sum, hashstr, (plen + 1) * 2, SHA256_MODE);
|
||||
for (u32 i = 0; i < 16; i++)
|
||||
xfp->iv[i] = sha256sum[i] ^ sha256sum[i+16];
|
||||
// copy over key, set keyslot
|
||||
memcpy(xfp->keyy, sd_keyy[num], 16);
|
||||
xfp->keyslot = 0x34;
|
||||
}
|
||||
|
||||
return fa_open(fp, path, mode);
|
||||
}
|
||||
|
||||
FRESULT fx_read (FIL* fp, XFIL* xfp, void* buff, UINT btr, UINT* br) {
|
||||
FSIZE_t off = f_tell(fp);
|
||||
FRESULT res = f_read(fp, buff, btr, br);
|
||||
if (xfp && (xfp->keyslot < 0x40))
|
||||
fx_crypt(xfp, buff, off, btr);
|
||||
return res;
|
||||
}
|
||||
|
||||
FRESULT fx_write (FIL* fp, XFIL* xfp, const void* buff, UINT btw, UINT* bw) {
|
||||
FSIZE_t off = f_tell(fp);
|
||||
FRESULT res = FR_OK;
|
||||
if (xfp && (xfp->keyslot < 0x40)) {
|
||||
*bw = 0;
|
||||
for (UINT p = 0; (p < btw) && (res == FR_OK); p += SDCRYPT_BUFFER_SIZE) {
|
||||
UINT pcount = min(SDCRYPT_BUFFER_SIZE, (btw - p));
|
||||
UINT bwl = 0;
|
||||
memcpy(SDCRYPT_BUFFER, (u8*) buff + p, pcount);
|
||||
fx_crypt(xfp, SDCRYPT_BUFFER, off + p, pcount);
|
||||
res = f_write(fp, (const void*) SDCRYPT_BUFFER, pcount, &bwl);
|
||||
*bw += bwl;
|
||||
}
|
||||
} else res = f_write(fp, buff, btw, bw);
|
||||
return res;
|
||||
}
|
||||
|
||||
FRESULT fa_open (FIL* fp, const TCHAR* path, BYTE mode) {
|
||||
TCHAR alias[256];
|
||||
dealias_path(alias, path);
|
||||
return f_open(fp, alias, mode);
|
||||
}
|
||||
|
||||
FRESULT fa_opendir (DIR* dp, const TCHAR* path) {
|
||||
TCHAR alias[256];
|
||||
dealias_path(alias, path);
|
||||
return f_opendir(dp, alias);
|
||||
}
|
||||
|
||||
FRESULT fa_stat (const TCHAR* path, FILINFO* fno) {
|
||||
TCHAR alias[256];
|
||||
dealias_path(alias, path);
|
||||
return f_stat(alias, fno);
|
||||
}
|
||||
|
||||
// special functions for access of virtual NAND SD drives
|
||||
bool SetupNandSdDrive(const char* path, const char* sd_path, const char* movable, int num) {
|
||||
char alias[128];
|
||||
|
||||
// initial checks
|
||||
if ((num >= NUM_ALIAS_DRV) || (num < 0)) return false;
|
||||
alias_drv[num] = 0;
|
||||
if (!sd_path || !movable || !path) return true;
|
||||
|
||||
// grab the key Y from movable.sed
|
||||
UINT bytes_read = 0;
|
||||
FIL file;
|
||||
if (f_open(&file, movable, FA_READ | FA_OPEN_EXISTING) != FR_OK)
|
||||
return false;
|
||||
f_lseek(&file, 0x110);
|
||||
if ((f_read(&file, sd_keyy[num], 0x10, &bytes_read) != FR_OK) || (bytes_read != 0x10)) {
|
||||
f_close(&file);
|
||||
return false;
|
||||
}
|
||||
f_close(&file);
|
||||
|
||||
// build the alias path (id0)
|
||||
u32 sha256sum[8];
|
||||
sha_quick(sha256sum, sd_keyy[num], 0x10, SHA256_MODE);
|
||||
snprintf(alias, 127, "%s/Nintendo 3DS/%08lX%08lX%08lX%08lX",
|
||||
sd_path, sha256sum[0], sha256sum[1], sha256sum[2], sha256sum[3]);
|
||||
|
||||
// find the alias path (id1)
|
||||
char* id1 = alias + strnlen(alias, 127);
|
||||
DIR pdir;
|
||||
FILINFO fno;
|
||||
if (f_opendir(&pdir, alias) != FR_OK)
|
||||
return false;
|
||||
(id1++)[0] = '/';
|
||||
*id1 = '\0';
|
||||
while (f_readdir(&pdir, &fno) == FR_OK) {
|
||||
if (fno.fname[0] == 0)
|
||||
break;
|
||||
if ((strnlen(fno.fname, 64) != 32) || !(fno.fattrib & AM_DIR))
|
||||
continue; // check for id1 directory
|
||||
strncpy(id1, fno.fname, 127 - (id1 - alias));
|
||||
break;
|
||||
}
|
||||
f_closedir(&pdir);
|
||||
if (!(*id1)) return false;
|
||||
|
||||
// create the alias drive
|
||||
return SetupAliasDrive(path, alias, num);
|
||||
}
|
||||
|
||||
bool SetupAliasDrive(const char* path, const char* alias, int num) {
|
||||
// initial checks
|
||||
if ((num >= NUM_ALIAS_DRV) || (num < 0)) return false;
|
||||
alias_drv[num] = 0;
|
||||
if (!alias || !path) return true;
|
||||
|
||||
// take over drive path and alias
|
||||
strncpy(alias_path[num], alias, 128);
|
||||
if (path[1] != ':') return false;
|
||||
alias_drv[num] = path[0];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CheckAliasDrive(const char* path) {
|
||||
int num = alias_num(path);
|
||||
return (num >= 0);
|
||||
}
|
24
source/fatfs/alias.h
Normal file
24
source/fatfs/alias.h
Normal file
@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
#include "ff.h"
|
||||
|
||||
typedef struct {
|
||||
u8 iv[16];
|
||||
u8 keyy[16];
|
||||
u32 keyslot;
|
||||
} __attribute__((packed)) XFIL;
|
||||
|
||||
// wrapper functions for ff.h
|
||||
// incomplete(!) extension to FatFS to support on-the-fly crypto & path aliases
|
||||
FRESULT fx_open (FIL* fp, XFIL* xfp, const TCHAR* path, BYTE mode);
|
||||
FRESULT fx_read (FIL* fp, XFIL* xfp, void* buff, UINT btr, UINT* br);
|
||||
FRESULT fx_write (FIL* fp, XFIL* xfp, const void* buff, UINT btw, UINT* bw);
|
||||
FRESULT fa_open (FIL* fp, const TCHAR* path, BYTE mode);
|
||||
FRESULT fa_opendir (DIR* dp, const TCHAR* path);
|
||||
FRESULT fa_stat (const TCHAR* path, FILINFO* fno);
|
||||
|
||||
// special functions for access of virtual NAND SD drives
|
||||
bool SetupNandSdDrive(const char* path, const char* sd_path, const char* movable, int num);
|
||||
bool SetupAliasDrive(const char* path, const char* alias, int num);
|
||||
bool CheckAliasDrive(const char* path);
|
88
source/fs.c
88
source/fs.c
@ -1,6 +1,7 @@
|
||||
#include "ui.h"
|
||||
#include "fs.h"
|
||||
#include "virtual.h"
|
||||
#include "alias.h"
|
||||
#include "image.h"
|
||||
#include "sha.h"
|
||||
#include "sdmmc.h"
|
||||
@ -10,7 +11,7 @@
|
||||
#define MAIN_BUFFER_SIZE (0x100000) // must be multiple of 0x200
|
||||
|
||||
#define NORM_FS 10
|
||||
#define VIRT_FS 5
|
||||
#define VIRT_FS 7
|
||||
|
||||
#define SKIP_CUR (1<<3)
|
||||
#define OVERWRITE_CUR (1<<4)
|
||||
@ -35,11 +36,6 @@ static char search_pattern[256] = { 0 };
|
||||
static char search_path[256] = { 0 };
|
||||
|
||||
bool InitSDCardFS() {
|
||||
#ifndef EXEC_GATEWAY
|
||||
// TODO: Magic?
|
||||
*(u32*)0x10000020 = 0;
|
||||
*(u32*)0x10000020 = 0x340;
|
||||
#endif
|
||||
fs_mounted[0] = (f_mount(fs, "0:", 1) == FR_OK);
|
||||
return fs_mounted[0];
|
||||
}
|
||||
@ -57,10 +53,14 @@ bool InitExtFS() {
|
||||
fs_mounted[7] = (f_mount(fs + 7, "7:", 1) == FR_OK);
|
||||
}
|
||||
}
|
||||
SetupNandSdDrive("A:", "0:", "1:/private/movable.sed", 0);
|
||||
SetupNandSdDrive("B:", "0:", "4:/private/movable.sed", 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
void DeinitExtFS() {
|
||||
SetupNandSdDrive(NULL, NULL, NULL, 0);
|
||||
SetupNandSdDrive(NULL, NULL, NULL, 1);
|
||||
for (u32 i = NORM_FS - 1; i > 0; i--) {
|
||||
if (fs_mounted[i]) {
|
||||
char fsname[8];
|
||||
@ -88,7 +88,10 @@ void SetFSSearch(const char* pattern, const char* path) {
|
||||
int PathToNumFS(const char* path) {
|
||||
int fsnum = *path - (int) '0';
|
||||
if ((fsnum < 0) || (fsnum >= NORM_FS) || (path[1] != ':')) {
|
||||
if (!GetVirtualSource(path) && !IsSearchDrive(path)) ShowPrompt(false, "Invalid path (%s)", path);
|
||||
if (!GetVirtualSource(path) &&
|
||||
!CheckAliasDrive(path) &&
|
||||
!IsSearchDrive(path))
|
||||
ShowPrompt(false, "Invalid path (%s)", path);
|
||||
return -1;
|
||||
}
|
||||
return fsnum;
|
||||
@ -281,7 +284,7 @@ bool GetTempFileName(char* path) {
|
||||
char* cc = tempname;
|
||||
// this does not try all permutations
|
||||
for (; (*cc <= 'Z') && (cc - tempname < 8); (*cc)++) {
|
||||
if (f_stat(path, NULL) != FR_OK) break;
|
||||
if (fa_stat(path, NULL) != FR_OK) break;
|
||||
if (*cc == 'Z') cc++;
|
||||
}
|
||||
return (cc - tempname < 8) ? true : false;
|
||||
@ -289,11 +292,10 @@ bool GetTempFileName(char* path) {
|
||||
|
||||
bool FileSetData(const char* path, const u8* data, size_t size, size_t foffset, bool create) {
|
||||
if (!CheckWritePermissions(path)) return false;
|
||||
if (PathToNumFS(path) >= 0) {
|
||||
if ((PathToNumFS(path) >= 0) || (CheckAliasDrive(path))) {
|
||||
UINT bytes_written = 0;
|
||||
FIL file;
|
||||
if (!CheckWritePermissions(path)) return false;
|
||||
if (f_open(&file, path, FA_WRITE | (create ? FA_CREATE_ALWAYS : FA_OPEN_ALWAYS)) != FR_OK)
|
||||
if (fa_open(&file, path, FA_WRITE | (create ? FA_CREATE_ALWAYS : FA_OPEN_ALWAYS)) != FR_OK)
|
||||
return false;
|
||||
f_lseek(&file, foffset);
|
||||
f_write(&file, data, size, &bytes_written);
|
||||
@ -310,10 +312,10 @@ bool FileSetData(const char* path, const u8* data, size_t size, size_t foffset,
|
||||
|
||||
size_t FileGetData(const char* path, u8* data, size_t size, size_t foffset)
|
||||
{
|
||||
if (PathToNumFS(path) >= 0) {
|
||||
if ((PathToNumFS(path) >= 0) || (CheckAliasDrive(path))) {
|
||||
UINT bytes_read = 0;
|
||||
FIL file;
|
||||
if (f_open(&file, path, FA_READ | FA_OPEN_EXISTING) != FR_OK)
|
||||
if (fa_open(&file, path, FA_READ | FA_OPEN_EXISTING) != FR_OK)
|
||||
return 0;
|
||||
f_lseek(&file, foffset);
|
||||
if (f_read(&file, data, size, &bytes_read) != FR_OK) {
|
||||
@ -333,9 +335,9 @@ size_t FileGetData(const char* path, u8* data, size_t size, size_t foffset)
|
||||
}
|
||||
|
||||
size_t FileGetSize(const char* path) {
|
||||
if (PathToNumFS(path) >= 0) {
|
||||
if ((PathToNumFS(path) >= 0) || (CheckAliasDrive(path))) {
|
||||
FILINFO fno;
|
||||
if (f_stat(path, &fno) != FR_OK)
|
||||
if (fa_stat(path, &fno) != FR_OK)
|
||||
return 0;
|
||||
return fno.fsize;
|
||||
} else if (GetVirtualSource(path)) {
|
||||
@ -372,7 +374,7 @@ bool FileGetSha256(const char* path, u8* sha256) {
|
||||
FIL file;
|
||||
size_t fsize;
|
||||
|
||||
if (f_open(&file, path, FA_READ | FA_OPEN_EXISTING) != FR_OK)
|
||||
if (fa_open(&file, path, FA_READ | FA_OPEN_EXISTING) != FR_OK)
|
||||
return false;
|
||||
fsize = f_size(&file);
|
||||
f_lseek(&file, 0);
|
||||
@ -451,7 +453,7 @@ bool FileInjectFile(const char* dest, const char* orig, u32 offset) {
|
||||
dsize = dvfile.size;
|
||||
} else {
|
||||
vdest = false;
|
||||
if (f_open(&dfile, dest, FA_WRITE | FA_OPEN_EXISTING) != FR_OK)
|
||||
if (fa_open(&dfile, dest, FA_WRITE | FA_OPEN_EXISTING) != FR_OK)
|
||||
return false;
|
||||
dsize = f_size(&dfile);
|
||||
f_lseek(&dfile, offset);
|
||||
@ -468,7 +470,7 @@ bool FileInjectFile(const char* dest, const char* orig, u32 offset) {
|
||||
osize = ovfile.size;
|
||||
} else {
|
||||
vorig = false;
|
||||
if (f_open(&ofile, orig, FA_READ | FA_OPEN_EXISTING) != FR_OK) {
|
||||
if (fa_open(&ofile, orig, FA_READ | FA_OPEN_EXISTING) != FR_OK) {
|
||||
if (!vdest) f_close(&dfile);
|
||||
return false;
|
||||
}
|
||||
@ -563,7 +565,7 @@ bool PathCopyVirtual(const char* destdir, const char* orig, u32* flags) {
|
||||
FIL ofile;
|
||||
u32 osize;
|
||||
|
||||
if (f_open(&ofile, orig, FA_READ | FA_OPEN_EXISTING) != FR_OK)
|
||||
if (fa_open(&ofile, orig, FA_READ | FA_OPEN_EXISTING) != FR_OK)
|
||||
return false;
|
||||
f_lseek(&ofile, 0);
|
||||
f_sync(&ofile);
|
||||
@ -620,7 +622,7 @@ bool PathCopyVirtual(const char* destdir, const char* orig, u32* flags) {
|
||||
return false;
|
||||
|
||||
// check if destination exists
|
||||
if (flags && !(*flags & OVERWRITE_ALL) && f_stat(dest, NULL) == FR_OK) {
|
||||
if (flags && !(*flags & OVERWRITE_ALL) && fa_stat(dest, NULL) == FR_OK) {
|
||||
if (*flags & SKIP_ALL) {
|
||||
*flags |= SKIP_CUR;
|
||||
return true;
|
||||
@ -636,7 +638,7 @@ bool PathCopyVirtual(const char* destdir, const char* orig, u32* flags) {
|
||||
dname++;
|
||||
if (!ShowStringPrompt(dname, 255 - (dname - dest), "Choose new destination name"))
|
||||
return false;
|
||||
} while (f_stat(dest, NULL) == FR_OK);
|
||||
} while (fa_stat(dest, NULL) == FR_OK);
|
||||
} else if (user_select == 3) {
|
||||
*flags |= SKIP_CUR;
|
||||
return true;
|
||||
@ -650,7 +652,7 @@ bool PathCopyVirtual(const char* destdir, const char* orig, u32* flags) {
|
||||
}
|
||||
}
|
||||
|
||||
if (f_open(&dfile, dest, FA_WRITE | FA_CREATE_ALWAYS) != FR_OK)
|
||||
if (fa_open(&dfile, dest, FA_WRITE | FA_CREATE_ALWAYS) != FR_OK)
|
||||
return false;
|
||||
f_lseek(&dfile, 0);
|
||||
f_sync(&dfile);
|
||||
@ -688,12 +690,12 @@ bool PathCopyWorker(char* dest, char* orig, u32* flags, bool move) {
|
||||
FILINFO fno;
|
||||
bool ret = false;
|
||||
|
||||
if (f_stat(dest, &fno) != FR_OK) { // is root or destination does not exist
|
||||
if (fa_stat(dest, &fno) != FR_OK) { // is root or destination does not exist
|
||||
DIR tmp_dir; // check if root
|
||||
if (f_opendir(&tmp_dir, dest) != FR_OK) return false;
|
||||
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)
|
||||
if (f_stat(orig, &fno) != FR_OK) return false; // origin does not exist
|
||||
if (fa_stat(orig, &fno) != FR_OK) return false; // origin does not exist
|
||||
|
||||
// build full destination path (on top of destination directory)
|
||||
char* oname = strrchr(orig, '/');
|
||||
@ -716,7 +718,7 @@ bool PathCopyWorker(char* dest, char* orig, u32* flags, bool move) {
|
||||
}
|
||||
|
||||
// check if destination exists
|
||||
if (flags && !(*flags & (OVERWRITE_CUR|OVERWRITE_ALL)) && (f_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;
|
||||
@ -731,7 +733,7 @@ bool PathCopyWorker(char* dest, char* orig, u32* flags, bool move) {
|
||||
do {
|
||||
if (!ShowStringPrompt(dname, 255 - (dname - dest), "Choose new destination name"))
|
||||
return false;
|
||||
} while (f_stat(dest, NULL) == FR_OK);
|
||||
} while (fa_stat(dest, NULL) == FR_OK);
|
||||
} else if (user_select == 2) {
|
||||
*flags |= OVERWRITE_CUR;
|
||||
} else if (user_select == 3) {
|
||||
@ -749,19 +751,19 @@ bool PathCopyWorker(char* dest, char* orig, u32* flags, bool move) {
|
||||
|
||||
// the copy process takes place here
|
||||
if (!ShowProgress(0, 0, orig)) return false;
|
||||
if (move && f_stat(dest, NULL) != FR_OK) { // moving if dest not existing
|
||||
if (move && fa_stat(dest, NULL) != FR_OK) { // moving if dest not existing
|
||||
ret = (f_rename(orig, dest) == FR_OK);
|
||||
} else if (fno.fattrib & AM_DIR) { // processing folders (same for move & copy)
|
||||
DIR pdir;
|
||||
char* fname = orig + strnlen(orig, 256);
|
||||
|
||||
// create the destination folder if it does not already exist
|
||||
if ((f_opendir(&pdir, dest) != FR_OK) && (f_mkdir(dest) != FR_OK)) {
|
||||
if ((fa_opendir(&pdir, dest) != FR_OK) && (f_mkdir(dest) != FR_OK)) {
|
||||
ShowPrompt(false, "Error: Overwriting file with dir");
|
||||
return false;
|
||||
} else f_closedir(&pdir);
|
||||
|
||||
if (f_opendir(&pdir, orig) != FR_OK)
|
||||
if (fa_opendir(&pdir, orig) != FR_OK)
|
||||
return false;
|
||||
*(fname++) = '/';
|
||||
|
||||
@ -778,7 +780,7 @@ bool PathCopyWorker(char* dest, char* orig, u32* flags, bool move) {
|
||||
}
|
||||
f_closedir(&pdir);
|
||||
} else if (move) { // moving if destination exists
|
||||
if (f_stat(dest, &fno) != FR_OK)
|
||||
if (fa_stat(dest, &fno) != FR_OK)
|
||||
return false;
|
||||
if (fno.fattrib & AM_DIR) {
|
||||
ShowPrompt(false, "Error: Overwriting dir with file");
|
||||
@ -792,7 +794,7 @@ bool PathCopyWorker(char* dest, char* orig, u32* flags, bool move) {
|
||||
FIL dfile;
|
||||
size_t fsize;
|
||||
|
||||
if (f_open(&ofile, orig, FA_READ | FA_OPEN_EXISTING) != FR_OK)
|
||||
if (fa_open(&ofile, orig, FA_READ | FA_OPEN_EXISTING) != FR_OK)
|
||||
return false;
|
||||
fsize = f_size(&ofile);
|
||||
if (GetFreeSpace(dest) < fsize) {
|
||||
@ -801,7 +803,7 @@ bool PathCopyWorker(char* dest, char* orig, u32* flags, bool move) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (f_open(&dfile, dest, FA_WRITE | FA_CREATE_ALWAYS) != FR_OK) {
|
||||
if (fa_open(&dfile, dest, FA_WRITE | FA_CREATE_ALWAYS) != FR_OK) {
|
||||
ShowPrompt(false, "Error: Cannot create destination file");
|
||||
f_close(&ofile);
|
||||
return false;
|
||||
@ -860,8 +862,8 @@ bool PathMove(const char* destdir, const char* orig, u32* flags) {
|
||||
if (!CheckWritePermissions(destdir)) return false;
|
||||
if (!CheckWritePermissions(orig)) return false;
|
||||
if (flags) *flags = *flags & ~(SKIP_CUR|OVERWRITE_CUR); // reset local flags
|
||||
if (GetVirtualSource(destdir) || GetVirtualSource(orig)) {
|
||||
ShowPrompt(false, "Error: Moving virtual files not possible");
|
||||
if ((PathToNumFS(destdir) < 0) || (PathToNumFS(orig) < 0)) {
|
||||
ShowPrompt(false, "Error: Moving is not possible here");
|
||||
return false;
|
||||
} else {
|
||||
char fdpath[256]; // 256 is the maximum length of a full path
|
||||
@ -879,12 +881,12 @@ bool PathDeleteWorker(char* fpath) {
|
||||
FILINFO fno;
|
||||
|
||||
// this code handles directory content deletion
|
||||
if (f_stat(fpath, &fno) != FR_OK) return false; // fpath does not exist
|
||||
if (fa_stat(fpath, &fno) != FR_OK) return false; // fpath does not exist
|
||||
if (fno.fattrib & AM_DIR) { // process folder contents
|
||||
DIR pdir;
|
||||
char* fname = fpath + strnlen(fpath, 255);
|
||||
|
||||
if (f_opendir(&pdir, fpath) != FR_OK)
|
||||
if (fa_opendir(&pdir, fpath) != FR_OK)
|
||||
return false;
|
||||
*(fname++) = '/';
|
||||
|
||||
@ -928,7 +930,7 @@ bool PathRename(const char* path, const char* newname) {
|
||||
strncpy(temp, path, oldname - path);
|
||||
if (!GetTempFileName(temp)) return false;
|
||||
if (f_rename(path, temp) == FR_OK) {
|
||||
if ((f_stat(npath, NULL) == FR_OK) || (f_rename(temp, npath) != FR_OK)) {
|
||||
if ((fa_stat(npath, NULL) == FR_OK) || (f_rename(temp, npath) != FR_OK)) {
|
||||
ShowPrompt(false, "Destination exists in folder");
|
||||
f_rename(temp, path); // something went wrong - try renaming back
|
||||
return false;
|
||||
@ -958,7 +960,7 @@ void CreateScreenshot() {
|
||||
|
||||
for (; n < 1000; n++) {
|
||||
snprintf(filename, 16, "0:/snap%03i.bmp", (int) n);
|
||||
if (f_stat(filename, NULL) != FR_OK) break;
|
||||
if (fa_stat(filename, NULL) != FR_OK) break;
|
||||
}
|
||||
if (n >= 1000) return;
|
||||
|
||||
@ -1036,12 +1038,13 @@ bool GetRootDirContentsWorker(DirStruct* contents) {
|
||||
"SYSNAND CTRNAND", "SYSNAND TWLN", "SYSNAND TWLP",
|
||||
"EMUNAND CTRNAND", "EMUNAND TWLN", "EMUNAND TWLP",
|
||||
"IMGNAND CTRNAND", "IMGNAND TWLN", "IMGNAND TWLP",
|
||||
"SYSNAND SD", "EMUNAND SD",
|
||||
"SYSNAND VIRTUAL", "EMUNAND VIRTUAL", "IMGNAND VIRTUAL",
|
||||
"MEMORY VIRTUAL",
|
||||
"LAST SEARCH"
|
||||
};
|
||||
static const char* drvnum[] = {
|
||||
"0:", "1:", "2:", "3:", "4:", "5:", "6:", "7:", "8:", "9:", "S:", "E:", "I:", "M:", "Z:"
|
||||
"0:", "1:", "2:", "3:", "4:", "5:", "6:", "7:", "8:", "9:", "A:", "B:", "S:", "E:", "I:", "M:", "Z:"
|
||||
};
|
||||
u32 n_entries = 0;
|
||||
|
||||
@ -1049,7 +1052,8 @@ bool GetRootDirContentsWorker(DirStruct* contents) {
|
||||
for (u32 pdrv = 0; (pdrv < NORM_FS+VIRT_FS) && (n_entries < MAX_ENTRIES); pdrv++) {
|
||||
DirEntry* entry = &(contents->entry[n_entries]);
|
||||
if ((pdrv < NORM_FS) && !fs_mounted[pdrv]) continue;
|
||||
else if ((pdrv >= NORM_FS) && (!CheckVirtualDrive(drvnum[pdrv])) && !(IsSearchDrive(drvnum[pdrv]))) continue;
|
||||
else if ((pdrv >= NORM_FS) && (!CheckAliasDrive(drvnum[pdrv])) &&
|
||||
(!CheckVirtualDrive(drvnum[pdrv])) && !(IsSearchDrive(drvnum[pdrv]))) continue;
|
||||
memset(entry->path, 0x00, 64);
|
||||
snprintf(entry->path + 0, 4, drvnum[pdrv]);
|
||||
snprintf(entry->path + 4, 32, "[%s] %s", drvnum[pdrv], drvname[pdrv]);
|
||||
@ -1092,7 +1096,7 @@ bool GetDirContentsWorker(DirStruct* contents, char* fpath, int fnsize, const ch
|
||||
char* fname = fpath + strnlen(fpath, fnsize - 1);
|
||||
bool ret = false;
|
||||
|
||||
if (f_opendir(&pdir, fpath) != FR_OK)
|
||||
if (fa_opendir(&pdir, fpath) != FR_OK)
|
||||
return false;
|
||||
(fname++)[0] = '/';
|
||||
|
||||
|
@ -5,9 +5,10 @@
|
||||
#include "platform.h"
|
||||
#include "nand.h"
|
||||
#include "virtual.h"
|
||||
#include "alias.h"
|
||||
#include "image.h"
|
||||
|
||||
#define VERSION "0.6.8"
|
||||
#define VERSION "0.6.9"
|
||||
|
||||
#define N_PANES 2
|
||||
#define IMG_DRV "789I"
|
||||
@ -797,6 +798,8 @@ u32 GodMode() {
|
||||
} else if (!switched) { // standard unswitched command set
|
||||
if (GetVirtualSource(current_path) && (pad_state & BUTTON_X)) {
|
||||
ShowPrompt(false, "Not allowed in virtual path");
|
||||
} else if (CheckAliasDrive(current_path) && (pad_state & BUTTON_X)) {
|
||||
ShowPrompt(false, "Not allowed in alias path");
|
||||
} else if (pad_state & BUTTON_X) { // delete a file
|
||||
u32 n_marked = 0;
|
||||
for (u32 c = 0; c < current_dir->n_entries; c++)
|
||||
@ -836,6 +839,8 @@ u32 GodMode() {
|
||||
}
|
||||
if (clipboard->n_entries)
|
||||
last_clipboard_size = clipboard->n_entries;
|
||||
} else if (IsSearchDrive(current_path) && (pad_state & BUTTON_Y)) {
|
||||
ShowPrompt(false, "Not allowed in search drive");
|
||||
} else if (pad_state & BUTTON_Y) { // paste files
|
||||
const char* optionstr[2] = { "Copy path(s)", "Move path(s)" };
|
||||
char promptstr[64];
|
||||
@ -846,7 +851,7 @@ u32 GodMode() {
|
||||
TruncateString(namestr, clipboard->entry[0].name, 20, 12);
|
||||
snprintf(promptstr, 64, "Paste \"%s\" here?", namestr);
|
||||
} else snprintf(promptstr, 64, "Paste %lu paths here?", clipboard->n_entries);
|
||||
user_select = (!GetVirtualSource(clipboard->entry[0].path) && !GetVirtualSource(current_path)) ?
|
||||
user_select = ((PathToNumFS(clipboard->entry[0].path) >= 0) && (PathToNumFS(current_path) >= 0)) ?
|
||||
ShowSelectPrompt(2, optionstr, promptstr) : (ShowPrompt(true, promptstr) ? 1 : 0);
|
||||
if (user_select) {
|
||||
for (u32 c = 0; c < clipboard->n_entries; c++) {
|
||||
@ -872,6 +877,8 @@ u32 GodMode() {
|
||||
} else { // switched command set
|
||||
if (GetVirtualSource(current_path) && (pad_state & (BUTTON_X|BUTTON_Y))) {
|
||||
ShowPrompt(false, "Not allowed in virtual path");
|
||||
} else if (CheckAliasDrive(current_path) && (pad_state & (BUTTON_X|BUTTON_Y))) {
|
||||
ShowPrompt(false, "Not allowed in alias path");
|
||||
} else if ((pad_state & BUTTON_X) && (curr_entry->type != T_DOTDOT)) { // rename a file
|
||||
char newname[256];
|
||||
char namestr[20+1];
|
||||
|
Loading…
x
Reference in New Issue
Block a user