mirror of
https://github.com/d0k3/GodMode9.git
synced 2025-06-26 05:32:47 +00:00
Improve vff.c / vff.h functionality
This commit is contained in:
parent
d97e754593
commit
94b8588423
@ -49,7 +49,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// GodMode9 version
|
// GodMode9 version
|
||||||
#define VERSION "1.2.1"
|
#define VERSION "1.2.3"
|
||||||
|
|
||||||
// input / output paths
|
// input / output paths
|
||||||
#define INPUT_PATHS "0:", "0:/files9", "1:/rw/files9"
|
#define INPUT_PATHS "0:", "0:/files9", "1:/rw/files9"
|
||||||
|
@ -28,31 +28,3 @@ void SortDirStruct(DirStruct* contents) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// inspired by http://www.geeksforgeeks.org/wildcard-character-matching/
|
|
||||||
bool MatchName(const char *pattern, const char *path) {
|
|
||||||
// handling non asterisk chars
|
|
||||||
for (; *pattern != '*'; pattern++, path++) {
|
|
||||||
if ((*pattern == '\0') && (*path == '\0')) {
|
|
||||||
return true; // end reached simultaneously, match found
|
|
||||||
} else if ((*pattern == '\0') || (*path == '\0')) {
|
|
||||||
return false; // end reached on only one, failure
|
|
||||||
} else if ((*pattern != '?') && (tolower(*pattern) != tolower(*path))) {
|
|
||||||
return false; // chars don't match, failure
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// handling the asterisk (matches one or more chars in path)
|
|
||||||
if ((*(pattern+1) == '?') || (*(pattern+1) == '*')) {
|
|
||||||
return false; // stupid user shenanigans, failure
|
|
||||||
} else if (*path == '\0') {
|
|
||||||
return false; // asterisk, but end reached on path, failure
|
|
||||||
} else if (*(pattern+1) == '\0') {
|
|
||||||
return true; // nothing after the asterisk, match found
|
|
||||||
} else { // we couldn't really go without recursion here
|
|
||||||
for (path++; *path != '\0'; path++) {
|
|
||||||
if (MatchName(pattern + 1, path)) return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
@ -26,4 +26,3 @@ typedef struct {
|
|||||||
|
|
||||||
void DirEntryCpy(DirEntry* dest, const DirEntry* orig);
|
void DirEntryCpy(DirEntry* dest, const DirEntry* orig);
|
||||||
void SortDirStruct(DirStruct* contents);
|
void SortDirStruct(DirStruct* contents);
|
||||||
bool MatchName(const char *pattern, const char *path);
|
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
#include "sddata.h"
|
#include "sddata.h"
|
||||||
#include "image.h"
|
#include "image.h"
|
||||||
#include "ui.h"
|
#include "ui.h"
|
||||||
#include "ff.h"
|
#include "vff.h"
|
||||||
|
|
||||||
// last search pattern, path & mode
|
// last search pattern, path & mode
|
||||||
static char search_pattern[256] = { 0 };
|
static char search_pattern[256] = { 0 };
|
||||||
@ -111,18 +111,18 @@ bool GetDirContentsWorker(DirStruct* contents, char* fpath, int fnsize, const ch
|
|||||||
char* fname = fpath + strnlen(fpath, fnsize - 1);
|
char* fname = fpath + strnlen(fpath, fnsize - 1);
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
|
|
||||||
if (fa_opendir(&pdir, fpath) != FR_OK)
|
if (fvx_opendir(&pdir, fpath) != FR_OK)
|
||||||
return false;
|
return false;
|
||||||
(fname++)[0] = '/';
|
(fname++)[0] = '/';
|
||||||
|
|
||||||
while (f_readdir(&pdir, &fno) == FR_OK) {
|
while (fvx_readdir(&pdir, &fno) == FR_OK) {
|
||||||
if ((strncmp(fno.fname, ".", 2) == 0) || (strncmp(fno.fname, "..", 3) == 0))
|
if ((strncmp(fno.fname, ".", 2) == 0) || (strncmp(fno.fname, "..", 3) == 0))
|
||||||
continue; // filter out virtual entries
|
continue; // filter out virtual entries
|
||||||
strncpy(fname, fno.fname, (fnsize - 1) - (fname - fpath));
|
strncpy(fname, fno.fname, (fnsize - 1) - (fname - fpath));
|
||||||
if (fno.fname[0] == 0) {
|
if (fno.fname[0] == 0) {
|
||||||
ret = true;
|
ret = true;
|
||||||
break;
|
break;
|
||||||
} else if (!pattern || MatchName(pattern, fname)) {
|
} else if (!pattern || (fvx_match_name(fname, pattern) == FR_OK)) {
|
||||||
DirEntry* entry = &(contents->entry[contents->n_entries]);
|
DirEntry* entry = &(contents->entry[contents->n_entries]);
|
||||||
strncpy(entry->path, fpath, 256);
|
strncpy(entry->path, fpath, 256);
|
||||||
entry->name = entry->path + (fname - fpath);
|
entry->name = entry->path + (fname - fpath);
|
||||||
@ -146,7 +146,7 @@ bool GetDirContentsWorker(DirStruct* contents, char* fpath, int fnsize, const ch
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
f_closedir(&pdir);
|
fvx_closedir(&pdir);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -167,13 +167,8 @@ void SearchDirContents(DirStruct* contents, const char* path, const char* patter
|
|||||||
// search the path
|
// search the path
|
||||||
char fpath[256]; // 256 is the maximum length of a full path
|
char fpath[256]; // 256 is the maximum length of a full path
|
||||||
strncpy(fpath, path, 256);
|
strncpy(fpath, path, 256);
|
||||||
if (DriveType(path) & DRV_VIRTUAL) {
|
if (!GetDirContentsWorker(contents, fpath, 256, pattern, recursive))
|
||||||
if (!GetVirtualDirContents(contents, fpath, 256, pattern, recursive))
|
contents->n_entries = 0;
|
||||||
contents->n_entries = 0;
|
|
||||||
} else {
|
|
||||||
if (!GetDirContentsWorker(contents, fpath, 256, pattern, recursive))
|
|
||||||
contents->n_entries = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -128,19 +128,10 @@ size_t FileGetData(const char* path, u8* data, size_t size, size_t foffset) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
size_t FileGetSize(const char* path) {
|
size_t FileGetSize(const char* path) {
|
||||||
int drvtype = DriveType(path);
|
FILINFO fno;
|
||||||
if (drvtype & DRV_FAT) {
|
if (fvx_stat(path, &fno) != FR_OK)
|
||||||
FILINFO fno;
|
return 0;
|
||||||
if (fa_stat(path, &fno) != FR_OK)
|
return fno.fsize;
|
||||||
return 0;
|
|
||||||
return fno.fsize;
|
|
||||||
} else if (drvtype & DRV_VIRTUAL) {
|
|
||||||
VirtualFile vfile;
|
|
||||||
if (!GetVirtualFile(&vfile, path))
|
|
||||||
return 0;
|
|
||||||
return vfile.size;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FileGetSha256(const char* path, u8* sha256) {
|
bool FileGetSha256(const char* path, u8* sha256) {
|
||||||
@ -265,27 +256,6 @@ bool FileInjectFile(const char* dest, const char* orig, u32 offset) {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DirBuilderWorker(char* dest) {
|
|
||||||
DIR tmp_dir;
|
|
||||||
if (fa_opendir(&tmp_dir, dest) != FR_OK) {
|
|
||||||
char* slash = strrchr(dest, '/');
|
|
||||||
if (!slash) return false;
|
|
||||||
*slash = '\0';
|
|
||||||
if (!DirBuilderWorker(dest)) return false;
|
|
||||||
*slash = '/';
|
|
||||||
return (fa_mkdir(dest) == FR_OK);
|
|
||||||
} else {
|
|
||||||
f_closedir(&tmp_dir);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DirBuilder(const char* destdir) {
|
|
||||||
char fdpath[256]; // 256 is the maximum length of a full path
|
|
||||||
strncpy(fdpath, destdir, 255);
|
|
||||||
return DirBuilderWorker(fdpath);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DirCreate(const char* cpath, const char* dirname) {
|
bool DirCreate(const char* cpath, const char* dirname) {
|
||||||
char npath[256]; // 256 is the maximum length of a full path
|
char npath[256]; // 256 is the maximum length of a full path
|
||||||
if (!CheckWritePermissions(cpath)) return false;
|
if (!CheckWritePermissions(cpath)) return false;
|
||||||
@ -474,8 +444,7 @@ bool PathCopyFatToVrt(const char* destdir, const char* orig, u32* flags) {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PathCopyVrtToFat(char* dest, char* orig, u32* flags) {
|
bool PathCopyToFat(char* dest, char* orig, u32* flags, bool move) {
|
||||||
VirtualFile vfile;
|
|
||||||
FILINFO fno;
|
FILINFO fno;
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
|
|
||||||
@ -484,147 +453,8 @@ bool PathCopyVrtToFat(char* dest, char* orig, u32* flags) {
|
|||||||
if (fa_opendir(&tmp_dir, dest) != FR_OK) return false;
|
if (fa_opendir(&tmp_dir, dest) != FR_OK) return false;
|
||||||
f_closedir(&tmp_dir);
|
f_closedir(&tmp_dir);
|
||||||
} else if (!(fno.fattrib & AM_DIR)) return false; // destination is not a directory (must be at this point)
|
} else if (!(fno.fattrib & AM_DIR)) return false; // destination is not a directory (must be at this point)
|
||||||
|
if (fvx_stat(orig, &fno) != FR_OK) return false; // origin does not exist
|
||||||
// build full destination path (on top of destination directory)
|
if (move && (fno.fattrib & AM_VRT)) return false; // trying to move a virtual file
|
||||||
char* oname = strrchr(orig, '/');
|
|
||||||
char* dname = dest + strnlen(dest, 255);
|
|
||||||
if (oname == NULL) return false; // not a proper origin path
|
|
||||||
oname++;
|
|
||||||
*(dname++) = '/';
|
|
||||||
strncpy(dname, oname, 256 - (dname - dest));
|
|
||||||
|
|
||||||
// path string (for output)
|
|
||||||
char deststr[36 + 1];
|
|
||||||
TruncateString(deststr, dest, 36, 8);
|
|
||||||
|
|
||||||
// open / check virtual file
|
|
||||||
if (!GetVirtualFile(&vfile, orig))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// check if destination exists
|
|
||||||
if (flags && !(*flags & (OVERWRITE_CUR|OVERWRITE_ALL)) && (fa_stat(dest, NULL) == FR_OK)) {
|
|
||||||
if (*flags & SKIP_ALL) {
|
|
||||||
*flags |= SKIP_CUR;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
const char* optionstr[5] =
|
|
||||||
{"Choose new name", "Overwrite file(s)", "Skip file(s)", "Overwrite all", "Skip all"};
|
|
||||||
u32 user_select = ShowSelectPrompt((*flags & ASK_ALL) ? 5 : 3, optionstr,
|
|
||||||
"Destination already exists:\n%s", deststr);
|
|
||||||
if (user_select == 1) {
|
|
||||||
do {
|
|
||||||
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;
|
|
||||||
} else if (user_select == 4) {
|
|
||||||
*flags |= OVERWRITE_ALL;
|
|
||||||
} else if (user_select == 5) {
|
|
||||||
*flags |= (SKIP_CUR|SKIP_ALL);
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// check destination write permission (special paths only)
|
|
||||||
if (((*dest == '1') || (strncmp(dest, "0:/Nintendo 3DS", 16) == 0)) &&
|
|
||||||
(!flags || (*flags & (OVERWRITE_CUR|OVERWRITE_ALL))) &&
|
|
||||||
(!flags || !(*flags & OVERRIDE_PERM)) &&
|
|
||||||
!CheckWritePermissions(dest)) return false;
|
|
||||||
|
|
||||||
// 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, "%s\nError: Overwriting file with dir", deststr);
|
|
||||||
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;
|
|
||||||
u64 osize = vfile.size;
|
|
||||||
|
|
||||||
if (GetFreeSpace(dest) < osize) {
|
|
||||||
ShowPrompt(false, "%s\nError: File is too big for destination", deststr);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fx_open(&dfile, dest, FA_WRITE | FA_CREATE_ALWAYS) != FR_OK) {
|
|
||||||
ShowPrompt(false, "%s\nError: Cannot create destination file", deststr);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
f_lseek(&dfile, 0);
|
|
||||||
f_sync(&dfile);
|
|
||||||
|
|
||||||
ret = true;
|
|
||||||
if (flags && (*flags & CALC_SHA)) sha_init(SHA256_MODE);
|
|
||||||
for (u64 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;
|
|
||||||
if (flags && (*flags & CALC_SHA))
|
|
||||||
sha_update(MAIN_BUFFER, read_bytes);
|
|
||||||
}
|
|
||||||
ShowProgress(1, 1, orig);
|
|
||||||
|
|
||||||
fx_close(&dfile);
|
|
||||||
if (!ret) f_unlink(dest);
|
|
||||||
else if (flags && (*flags & CALC_SHA)) {
|
|
||||||
u8 sha256[0x20];
|
|
||||||
char* ext_sha = dest + strnlen(dest, 256);
|
|
||||||
strncpy(ext_sha, ".sha", 256 - (ext_sha - dest));
|
|
||||||
sha_get(sha256);
|
|
||||||
FileSetData(dest, sha256, 0x20, 0, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
*(--dname) = '\0';
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool PathCopyWorker(char* dest, char* orig, u32* flags, bool move) {
|
|
||||||
FILINFO fno;
|
|
||||||
bool ret = false;
|
|
||||||
|
|
||||||
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)
|
|
||||||
if (fa_stat(orig, &fno) != FR_OK) return false; // origin does not exist
|
|
||||||
|
|
||||||
// build full destination path (on top of destination directory)
|
// build full destination path (on top of destination directory)
|
||||||
char* oname = strrchr(orig, '/');
|
char* oname = strrchr(orig, '/');
|
||||||
@ -702,22 +532,22 @@ bool PathCopyWorker(char* dest, char* orig, u32* flags, bool move) {
|
|||||||
}
|
}
|
||||||
} else f_closedir(&pdir);
|
} else f_closedir(&pdir);
|
||||||
|
|
||||||
if (fa_opendir(&pdir, orig) != FR_OK)
|
if (fvx_opendir(&pdir, orig) != FR_OK)
|
||||||
return false;
|
return false;
|
||||||
*(fname++) = '/';
|
*(fname++) = '/';
|
||||||
|
|
||||||
while (f_readdir(&pdir, &fno) == FR_OK) {
|
while (fvx_readdir(&pdir, &fno) == FR_OK) {
|
||||||
if ((strncmp(fno.fname, ".", 2) == 0) || (strncmp(fno.fname, "..", 3) == 0))
|
if ((strncmp(fno.fname, ".", 2) == 0) || (strncmp(fno.fname, "..", 3) == 0))
|
||||||
continue; // filter out virtual entries
|
continue; // filter out virtual entries
|
||||||
strncpy(fname, fno.fname, 256 - (fname - orig));
|
strncpy(fname, fno.fname, 256 - (fname - orig));
|
||||||
if (fno.fname[0] == 0) {
|
if (fno.fname[0] == 0) {
|
||||||
ret = true;
|
ret = true;
|
||||||
break;
|
break;
|
||||||
} else if (!PathCopyWorker(dest, orig, flags, move)) {
|
} else if (!PathCopyToFat(dest, orig, flags, move)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
f_closedir(&pdir);
|
fvx_closedir(&pdir);
|
||||||
} else if (move) { // moving if destination exists
|
} else if (move) { // moving if destination exists
|
||||||
if (fa_stat(dest, &fno) != FR_OK)
|
if (fa_stat(dest, &fno) != FR_OK)
|
||||||
return false;
|
return false;
|
||||||
@ -733,13 +563,13 @@ bool PathCopyWorker(char* dest, char* orig, u32* flags, bool move) {
|
|||||||
FIL dfile;
|
FIL dfile;
|
||||||
u64 fsize;
|
u64 fsize;
|
||||||
|
|
||||||
if (fx_open(&ofile, orig, FA_READ | FA_OPEN_EXISTING) != FR_OK) {
|
if (fvx_open(&ofile, orig, FA_READ | FA_OPEN_EXISTING) != FR_OK) {
|
||||||
if (!FileUnlock(orig) || (fx_open(&ofile, orig, FA_READ | FA_OPEN_EXISTING) != FR_OK))
|
if (!FileUnlock(orig) || (fvx_open(&ofile, orig, FA_READ | FA_OPEN_EXISTING) != FR_OK))
|
||||||
return false;
|
return false;
|
||||||
ShowProgress(0, 0, orig); // reinit progress bar
|
ShowProgress(0, 0, orig); // reinit progress bar
|
||||||
}
|
}
|
||||||
|
|
||||||
fsize = f_size(&ofile);
|
fsize = fvx_size(&ofile);
|
||||||
if (GetFreeSpace(dest) < fsize) {
|
if (GetFreeSpace(dest) < fsize) {
|
||||||
ShowPrompt(false, "%s\nError: File is too big for destination", deststr);
|
ShowPrompt(false, "%s\nError: File is too big for destination", deststr);
|
||||||
fx_close(&ofile);
|
fx_close(&ofile);
|
||||||
@ -754,15 +584,15 @@ bool PathCopyWorker(char* dest, char* orig, u32* flags, bool move) {
|
|||||||
|
|
||||||
f_lseek(&dfile, 0);
|
f_lseek(&dfile, 0);
|
||||||
f_sync(&dfile);
|
f_sync(&dfile);
|
||||||
f_lseek(&ofile, 0);
|
fvx_lseek(&ofile, 0);
|
||||||
f_sync(&ofile);
|
fvx_sync(&ofile);
|
||||||
|
|
||||||
ret = true;
|
ret = true;
|
||||||
if (flags && (*flags & CALC_SHA)) sha_init(SHA256_MODE);
|
if (flags && (*flags & CALC_SHA)) sha_init(SHA256_MODE);
|
||||||
for (u64 pos = 0; (pos < fsize) && ret; pos += MAIN_BUFFER_SIZE) {
|
for (u64 pos = 0; (pos < fsize) && ret; pos += MAIN_BUFFER_SIZE) {
|
||||||
UINT bytes_read = 0;
|
UINT bytes_read = 0;
|
||||||
UINT bytes_written = 0;
|
UINT bytes_written = 0;
|
||||||
if (fx_read(&ofile, MAIN_BUFFER, MAIN_BUFFER_SIZE, &bytes_read) != FR_OK)
|
if (fvx_read(&ofile, MAIN_BUFFER, MAIN_BUFFER_SIZE, &bytes_read) != FR_OK)
|
||||||
ret = false;
|
ret = false;
|
||||||
if (!ShowProgress(pos + (bytes_read / 2), fsize, orig))
|
if (!ShowProgress(pos + (bytes_read / 2), fsize, orig))
|
||||||
ret = false;
|
ret = false;
|
||||||
@ -775,7 +605,7 @@ bool PathCopyWorker(char* dest, char* orig, u32* flags, bool move) {
|
|||||||
}
|
}
|
||||||
ShowProgress(1, 1, orig);
|
ShowProgress(1, 1, orig);
|
||||||
|
|
||||||
fx_close(&ofile);
|
fvx_close(&ofile);
|
||||||
fx_close(&dfile);
|
fx_close(&dfile);
|
||||||
if (!ret) f_unlink(dest);
|
if (!ret) f_unlink(dest);
|
||||||
else if (flags && (*flags & CALC_SHA)) {
|
else if (flags && (*flags & CALC_SHA)) {
|
||||||
@ -802,10 +632,8 @@ bool PathCopy(const char* destdir, const char* orig, u32* flags) {
|
|||||||
char fopath[256];
|
char fopath[256];
|
||||||
strncpy(fdpath, destdir, 255);
|
strncpy(fdpath, destdir, 255);
|
||||||
strncpy(fopath, orig, 255);
|
strncpy(fopath, orig, 255);
|
||||||
if (flags && (*flags & BUILD_PATH)) DirBuilderWorker(fdpath);
|
if (flags && (*flags & BUILD_PATH)) fvx_rmkdir(destdir);
|
||||||
bool res = (odrvtype & DRV_VIRTUAL) ? PathCopyVrtToFat(fdpath, fopath, flags) :
|
return PathCopyToFat(fdpath, fopath, flags, false);
|
||||||
PathCopyWorker(fdpath, fopath, flags, false);
|
|
||||||
return res;
|
|
||||||
} else if (!(odrvtype & DRV_VIRTUAL)) { // FAT to virtual
|
} else if (!(odrvtype & DRV_VIRTUAL)) { // FAT to virtual
|
||||||
if (odrvtype & ddrvtype & (DRV_SYSNAND|DRV_EMUNAND|DRV_IMAGE)) {
|
if (odrvtype & ddrvtype & (DRV_SYSNAND|DRV_EMUNAND|DRV_IMAGE)) {
|
||||||
ShowPrompt(false, "Copy operation is not allowed");
|
ShowPrompt(false, "Copy operation is not allowed");
|
||||||
@ -830,50 +658,17 @@ bool PathMove(const char* destdir, const char* orig, u32* flags) {
|
|||||||
char fopath[256];
|
char fopath[256];
|
||||||
strncpy(fdpath, destdir, 255);
|
strncpy(fdpath, destdir, 255);
|
||||||
strncpy(fopath, orig, 255);
|
strncpy(fopath, orig, 255);
|
||||||
if (flags && (*flags & BUILD_PATH)) DirBuilderWorker(fdpath);
|
if (flags && (*flags & BUILD_PATH)) fvx_rmkdir(destdir);
|
||||||
bool same_drv = (strncmp(orig, destdir, 2) == 0);
|
bool same_drv = (strncmp(orig, destdir, 2) == 0);
|
||||||
bool res = PathCopyWorker(fdpath, fopath, flags, same_drv);
|
bool res = PathCopyToFat(fdpath, fopath, flags, same_drv);
|
||||||
if (res && (!flags || !(*flags&SKIP_CUR))) PathDelete(orig);
|
if (res && (!flags || !(*flags&SKIP_CUR))) PathDelete(orig);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PathDeleteWorker(char* fpath) {
|
|
||||||
FILINFO fno;
|
|
||||||
|
|
||||||
// this code handles directory content deletion
|
|
||||||
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 (fa_opendir(&pdir, fpath) != FR_OK)
|
|
||||||
return false;
|
|
||||||
*(fname++) = '/';
|
|
||||||
|
|
||||||
while (f_readdir(&pdir, &fno) == FR_OK) {
|
|
||||||
if ((strncmp(fno.fname, ".", 2) == 0) || (strncmp(fno.fname, "..", 3) == 0))
|
|
||||||
continue; // filter out virtual entries
|
|
||||||
strncpy(fname, fno.fname, fpath + 255 - fname);
|
|
||||||
if (fno.fname[0] == 0) {
|
|
||||||
break;
|
|
||||||
} else { // return value won't matter
|
|
||||||
PathDeleteWorker(fpath);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
f_closedir(&pdir);
|
|
||||||
*(--fname) = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
return (fa_unlink(fpath) == FR_OK);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool PathDelete(const char* path) {
|
bool PathDelete(const char* path) {
|
||||||
char fpath[256]; // 256 is the maximum length of a full path
|
|
||||||
if (!CheckDirWritePermissions(path)) return false;
|
if (!CheckDirWritePermissions(path)) return false;
|
||||||
strncpy(fpath, path, 256);
|
return (fvx_runlink(path) == FR_OK);
|
||||||
// ShowString("Deleting files, please wait..."); // handled elsewhere
|
|
||||||
return PathDeleteWorker(fpath);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PathRename(const char* path, const char* newname) {
|
bool PathRename(const char* path, const char* newname) {
|
||||||
|
@ -40,9 +40,6 @@ u32 FileFindData(const char* path, u8* data, u32 size_data, u32 offset_file);
|
|||||||
/** Inject file into file @offset **/
|
/** Inject file into file @offset **/
|
||||||
bool FileInjectFile(const char* dest, const char* orig, u32 offset);
|
bool FileInjectFile(const char* dest, const char* orig, u32 offset);
|
||||||
|
|
||||||
/** Recursively build a directory **/
|
|
||||||
bool DirBuilder(const char* destdir);
|
|
||||||
|
|
||||||
/** Create a new directory in cpath **/
|
/** Create a new directory in cpath **/
|
||||||
bool DirCreate(const char* cpath, const char* dirname);
|
bool DirCreate(const char* cpath, const char* dirname);
|
||||||
|
|
||||||
|
@ -996,10 +996,8 @@ u32 CryptGameFile(const char* path, bool inplace, bool encrypt) {
|
|||||||
if (!CheckWritePermissions(destptr))
|
if (!CheckWritePermissions(destptr))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
if (!inplace) {
|
if (!inplace) { // ensure the output dir exists
|
||||||
// ensure the output dir exists
|
if (fvx_rmkdir(OUTPUT_PATH) != FR_OK)
|
||||||
// warning: this will only build output dirs in the root dir (!!!)
|
|
||||||
if ((f_stat(OUTPUT_PATH, NULL) != FR_OK) && (f_mkdir(OUTPUT_PATH) != FR_OK))
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1360,8 +1358,7 @@ u32 BuildCiaFromGameFile(const char* path, bool force_legit) {
|
|||||||
f_unlink(dest); // remove the file if it already exists
|
f_unlink(dest); // remove the file if it already exists
|
||||||
|
|
||||||
// ensure the output dir exists
|
// ensure the output dir exists
|
||||||
// warning: this will only build output dirs in the root dir (!!!)
|
if (fvx_rmkdir(OUTPUT_PATH) != FR_OK)
|
||||||
if ((f_stat(OUTPUT_PATH, NULL) != FR_OK) && (f_mkdir(OUTPUT_PATH) != FR_OK))
|
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
// build CIA from game file
|
// build CIA from game file
|
||||||
@ -1390,8 +1387,7 @@ u32 DumpCxiSrlFromTmdFile(const char* path) {
|
|||||||
char* dname = dest + strnlen(dest, 256);
|
char* dname = dest + strnlen(dest, 256);
|
||||||
|
|
||||||
// ensure the output dir exists
|
// ensure the output dir exists
|
||||||
// warning: this will only build output dirs in the root dir (!!!)
|
if (fvx_rmkdir(OUTPUT_PATH) != FR_OK)
|
||||||
if ((f_stat(OUTPUT_PATH, NULL) != FR_OK) && (f_mkdir(OUTPUT_PATH) != FR_OK))
|
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
// get path to CXI/SRL and decrypt (if encrypted)
|
// get path to CXI/SRL and decrypt (if encrypted)
|
||||||
@ -1717,9 +1713,7 @@ u32 BuildTitleKeyInfo(const char* path, bool dec, bool dump) {
|
|||||||
|
|
||||||
if (dump) {
|
if (dump) {
|
||||||
u32 dump_size = TIKDB_SIZE(tik_info);
|
u32 dump_size = TIKDB_SIZE(tik_info);
|
||||||
// ensure the output dir exists
|
if (fvx_rmkdir(OUTPUT_PATH) != FR_OK) // ensure the output dir exists
|
||||||
// warning: this will only build output dirs in the root dir (!!!)
|
|
||||||
if ((f_stat(OUTPUT_PATH, NULL) != FR_OK) && (f_mkdir(OUTPUT_PATH) != FR_OK))
|
|
||||||
return 1;
|
return 1;
|
||||||
f_unlink(path_out);
|
f_unlink(path_out);
|
||||||
if ((dump_size <= 16) || (fvx_qwrite(path_out, tik_info, 0, dump_size, &br) != FR_OK) || (br != dump_size))
|
if ((dump_size <= 16) || (fvx_qwrite(path_out, tik_info, 0, dump_size, &br) != FR_OK) || (br != dump_size))
|
||||||
@ -1800,9 +1794,7 @@ u32 BuildSeedInfo(const char* path, bool dump) {
|
|||||||
|
|
||||||
if (dump) {
|
if (dump) {
|
||||||
u32 dump_size = SEEDDB_SIZE(seed_info);
|
u32 dump_size = SEEDDB_SIZE(seed_info);
|
||||||
// ensure the output dir exists
|
if (fvx_rmkdir(OUTPUT_PATH) != FR_OK) // ensure the output dir exists
|
||||||
// warning: this will only build output dirs in the root dir (!!!)
|
|
||||||
if ((f_stat(OUTPUT_PATH, NULL) != FR_OK) && (f_mkdir(OUTPUT_PATH) != FR_OK))
|
|
||||||
return 1;
|
return 1;
|
||||||
f_unlink(path_out);
|
f_unlink(path_out);
|
||||||
if ((dump_size <= 16) || (fvx_qwrite(path_out, seed_info, 0, dump_size, &br) != FR_OK) || (br != dump_size))
|
if ((dump_size <= 16) || (fvx_qwrite(path_out, seed_info, 0, dump_size, &br) != FR_OK) || (br != dump_size))
|
||||||
|
@ -19,8 +19,7 @@ u32 CryptAesKeyDb(const char* path, bool inplace, bool encrypt) {
|
|||||||
|
|
||||||
if (!inplace) {
|
if (!inplace) {
|
||||||
// ensure the output dir exists
|
// ensure the output dir exists
|
||||||
// warning: this will only build output dirs in the root dir (!!!)
|
if (fvx_rmkdir(OUTPUT_PATH) != FR_OK)
|
||||||
if ((f_stat(OUTPUT_PATH, NULL) != FR_OK) && (f_mkdir(OUTPUT_PATH) != FR_OK))
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -123,9 +122,7 @@ u32 BuildKeyDb(const char* path, bool dump) {
|
|||||||
dump_size += sizeof(AesKeyInfo);
|
dump_size += sizeof(AesKeyInfo);
|
||||||
if (dump_size >= MAX_KEYDB_SIZE) return 1;
|
if (dump_size >= MAX_KEYDB_SIZE) return 1;
|
||||||
}
|
}
|
||||||
// ensure the output dir exists
|
if (fvx_rmkdir(OUTPUT_PATH) != FR_OK) // ensure the output dir exists
|
||||||
// warning: this will only build output dirs in the root dir (!!!)
|
|
||||||
if ((f_stat(OUTPUT_PATH, NULL) != FR_OK) && (f_mkdir(OUTPUT_PATH) != FR_OK))
|
|
||||||
return 1;
|
return 1;
|
||||||
f_unlink(path_out);
|
f_unlink(path_out);
|
||||||
if (!dump_size || (fvx_qwrite(path_out, key_info, 0, dump_size, &br) != FR_OK) || (br != dump_size))
|
if (!dump_size || (fvx_qwrite(path_out, key_info, 0, dump_size, &br) != FR_OK) || (br != dump_size))
|
||||||
|
@ -1,11 +1,22 @@
|
|||||||
#include "sddata.h"
|
#include "sddata.h"
|
||||||
#include "virtual.h"
|
#include "virtual.h"
|
||||||
#include "ffconf.h"
|
#include "ffconf.h"
|
||||||
|
#include "vff.h"
|
||||||
|
|
||||||
|
#if _USE_LFN != 0
|
||||||
|
#define _MAX_FN_LEN (_MAX_LFN)
|
||||||
|
#else
|
||||||
|
#define _MAX_FN_LEN (8+3)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define _VFIL_ENABLED (!_FS_TINY)
|
||||||
|
#define _VDIR_ENABLED ((sizeof(DIR) - sizeof(_FDID) >= sizeof(VirtualDir)) && (_USE_LFN != 0))
|
||||||
|
|
||||||
#define VFIL(fp) ((VirtualFile*) (void*) fp->buf)
|
#define VFIL(fp) ((VirtualFile*) (void*) fp->buf)
|
||||||
|
#define VDIR(dp) ((VirtualDir*) (void*) &(dp->dptr))
|
||||||
|
|
||||||
FRESULT fvx_open (FIL* fp, const TCHAR* path, BYTE mode) {
|
FRESULT fvx_open (FIL* fp, const TCHAR* path, BYTE mode) {
|
||||||
#if !_FS_TINY
|
#if _VFIL_ENABLED
|
||||||
VirtualFile* vfile = VFIL(fp);
|
VirtualFile* vfile = VFIL(fp);
|
||||||
memset(fp, 0, sizeof(FIL));
|
memset(fp, 0, sizeof(FIL));
|
||||||
if (GetVirtualFile(vfile, path)) {
|
if (GetVirtualFile(vfile, path)) {
|
||||||
@ -19,7 +30,7 @@ FRESULT fvx_open (FIL* fp, const TCHAR* path, BYTE mode) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
FRESULT fvx_read (FIL* fp, void* buff, UINT btr, UINT* br) {
|
FRESULT fvx_read (FIL* fp, void* buff, UINT btr, UINT* br) {
|
||||||
#if !_FS_TINY
|
#if _VFIL_ENABLED
|
||||||
if (fp->obj.fs == NULL) {
|
if (fp->obj.fs == NULL) {
|
||||||
VirtualFile* vfile = VFIL(fp);
|
VirtualFile* vfile = VFIL(fp);
|
||||||
int res = ReadVirtualFile(vfile, buff, fp->fptr, btr, (u32*) br);
|
int res = ReadVirtualFile(vfile, buff, fp->fptr, btr, (u32*) br);
|
||||||
@ -31,7 +42,7 @@ FRESULT fvx_read (FIL* fp, void* buff, UINT btr, UINT* br) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
FRESULT fvx_write (FIL* fp, const void* buff, UINT btw, UINT* bw) {
|
FRESULT fvx_write (FIL* fp, const void* buff, UINT btw, UINT* bw) {
|
||||||
#if !_FS_TINY
|
#if _VFIL_ENABLED
|
||||||
if (fp->obj.fs == NULL) {
|
if (fp->obj.fs == NULL) {
|
||||||
VirtualFile* vfile = VFIL(fp);
|
VirtualFile* vfile = VFIL(fp);
|
||||||
int res = WriteVirtualFile(vfile, buff, fp->fptr, btw, (u32*) bw);
|
int res = WriteVirtualFile(vfile, buff, fp->fptr, btw, (u32*) bw);
|
||||||
@ -43,14 +54,14 @@ FRESULT fvx_write (FIL* fp, const void* buff, UINT btw, UINT* bw) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
FRESULT fvx_close (FIL* fp) {
|
FRESULT fvx_close (FIL* fp) {
|
||||||
#if !_FS_TINY
|
#if _VFIL_ENABLED
|
||||||
if (fp->obj.fs == NULL) return FR_OK;
|
if (fp->obj.fs == NULL) return FR_OK;
|
||||||
#endif
|
#endif
|
||||||
return fx_close( fp );
|
return fx_close( fp );
|
||||||
}
|
}
|
||||||
|
|
||||||
FRESULT fvx_lseek (FIL* fp, FSIZE_t ofs) {
|
FRESULT fvx_lseek (FIL* fp, FSIZE_t ofs) {
|
||||||
#if !_FS_TINY
|
#if _VFIL_ENABLED
|
||||||
if (fp->obj.fs == NULL) {
|
if (fp->obj.fs == NULL) {
|
||||||
fp->fptr = ofs;
|
fp->fptr = ofs;
|
||||||
return FR_OK;
|
return FR_OK;
|
||||||
@ -60,7 +71,7 @@ FRESULT fvx_lseek (FIL* fp, FSIZE_t ofs) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
FRESULT fvx_sync (FIL* fp) {
|
FRESULT fvx_sync (FIL* fp) {
|
||||||
#if !_FS_TINY
|
#if _VFIL_ENABLED
|
||||||
if (fp->obj.fs == NULL) return FR_OK;
|
if (fp->obj.fs == NULL) return FR_OK;
|
||||||
#endif
|
#endif
|
||||||
return f_sync( fp );
|
return f_sync( fp );
|
||||||
@ -72,16 +83,66 @@ FRESULT fvx_stat (const TCHAR* path, FILINFO* fno) {
|
|||||||
if (!GetVirtualFile(&vfile, path)) return FR_NO_PATH;
|
if (!GetVirtualFile(&vfile, path)) return FR_NO_PATH;
|
||||||
fno->fsize = vfile.size;
|
fno->fsize = vfile.size;
|
||||||
fno->fdate = fno->ftime = 0;
|
fno->fdate = fno->ftime = 0;
|
||||||
fno->fattrib = (vfile.flags & VFLAG_DIR) ? AM_DIR : 0;
|
fno->fattrib = (vfile.flags & VFLAG_DIR) ? (AM_DIR|AM_VRT) : AM_VRT;
|
||||||
// could be better...
|
// could be better...
|
||||||
if (_USE_LFN != 0) GetVirtualFilename(fno->fname, &vfile, _MAX_LFN + 1);
|
if (_USE_LFN != 0) GetVirtualFilename(fno->fname, &vfile, _MAX_LFN + 1);
|
||||||
return FR_OK;
|
return FR_OK;
|
||||||
} else return fa_stat(path, fno);
|
} else return fa_stat( path, fno );
|
||||||
|
}
|
||||||
|
|
||||||
|
FRESULT fvx_rename (const TCHAR* path_old, const TCHAR* path_new) {
|
||||||
|
if ((GetVirtualSource(path_old)) || CheckAliasDrive(path_old)) return FR_DENIED;
|
||||||
|
return f_rename( path_old, path_new );
|
||||||
|
}
|
||||||
|
|
||||||
|
FRESULT fvx_unlink (const TCHAR* path) {
|
||||||
|
if (GetVirtualSource(path)) return FR_DENIED;
|
||||||
|
return fa_unlink( path );
|
||||||
|
}
|
||||||
|
|
||||||
|
FRESULT fvx_mkdir (const TCHAR* path) {
|
||||||
|
if (GetVirtualSource(path)) return FR_DENIED;
|
||||||
|
return fa_mkdir( path );
|
||||||
|
}
|
||||||
|
|
||||||
|
FRESULT fvx_opendir (DIR* dp, const TCHAR* path) {
|
||||||
|
if (_VDIR_ENABLED) {
|
||||||
|
VirtualDir* vdir = VDIR(dp);
|
||||||
|
memset(dp, 0, sizeof(DIR));
|
||||||
|
if (GetVirtualDir(vdir, path))
|
||||||
|
return FR_OK;
|
||||||
|
}
|
||||||
|
return fa_opendir( dp, path );
|
||||||
|
}
|
||||||
|
|
||||||
|
FRESULT fvx_closedir (DIR* dp) {
|
||||||
|
if (_VDIR_ENABLED) {
|
||||||
|
if (dp->obj.fs == NULL) return FR_OK;
|
||||||
|
}
|
||||||
|
return f_closedir( dp );
|
||||||
|
}
|
||||||
|
|
||||||
|
FRESULT fvx_readdir (DIR* dp, FILINFO* fno) {
|
||||||
|
if (_VDIR_ENABLED) {
|
||||||
|
if (dp->obj.fs == NULL) {
|
||||||
|
VirtualDir* vdir = VDIR(dp);
|
||||||
|
VirtualFile vfile;
|
||||||
|
if (ReadVirtualDir(&vfile, vdir)) {
|
||||||
|
fno->fsize = vfile.size;
|
||||||
|
fno->fdate = fno->ftime = 0;
|
||||||
|
fno->fattrib = (vfile.flags & VFLAG_DIR) ? (AM_DIR|AM_VRT) : AM_VRT;
|
||||||
|
GetVirtualFilename(fno->fname, &vfile, _MAX_LFN + 1);
|
||||||
|
} else *(fno->fname) = 0;
|
||||||
|
return FR_OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return f_readdir( dp, fno );
|
||||||
}
|
}
|
||||||
|
|
||||||
FRESULT fvx_qread (const TCHAR* path, void* buff, FSIZE_t ofs, UINT btr, UINT* br) {
|
FRESULT fvx_qread (const TCHAR* path, void* buff, FSIZE_t ofs, UINT btr, UINT* br) {
|
||||||
FIL fp;
|
FIL fp;
|
||||||
FRESULT res;
|
FRESULT res;
|
||||||
|
UINT brt = 0;
|
||||||
|
|
||||||
res = fvx_open(&fp, path, FA_READ | FA_OPEN_EXISTING);
|
res = fvx_open(&fp, path, FA_READ | FA_OPEN_EXISTING);
|
||||||
if (res != FR_OK) return res;
|
if (res != FR_OK) return res;
|
||||||
@ -92,15 +153,19 @@ FRESULT fvx_qread (const TCHAR* path, void* buff, FSIZE_t ofs, UINT btr, UINT* b
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
res = fvx_read(&fp, buff, btr, br);
|
res = fvx_read(&fp, buff, btr, &brt);
|
||||||
fvx_close(&fp);
|
fvx_close(&fp);
|
||||||
|
|
||||||
|
if (br) *br = brt;
|
||||||
|
else if ((res == FR_OK) && (brt != btr)) res = FR_DENIED;
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
FRESULT fvx_qwrite (const TCHAR* path, const void* buff, FSIZE_t ofs, UINT btw, UINT* bw) {
|
FRESULT fvx_qwrite (const TCHAR* path, const void* buff, FSIZE_t ofs, UINT btw, UINT* bw) {
|
||||||
FIL fp;
|
FIL fp;
|
||||||
FRESULT res;
|
FRESULT res;
|
||||||
|
UINT bwt = 0;
|
||||||
|
|
||||||
res = fvx_open(&fp, path, FA_WRITE | FA_OPEN_ALWAYS);
|
res = fvx_open(&fp, path, FA_WRITE | FA_OPEN_ALWAYS);
|
||||||
if (res != FR_OK) return res;
|
if (res != FR_OK) return res;
|
||||||
@ -111,8 +176,141 @@ FRESULT fvx_qwrite (const TCHAR* path, const void* buff, FSIZE_t ofs, UINT btw,
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
res = fvx_write(&fp, buff, btw, bw);
|
res = fvx_write(&fp, buff, btw, &bwt);
|
||||||
fvx_close(&fp);
|
fvx_close(&fp);
|
||||||
|
|
||||||
|
if (bw) *bw = bwt;
|
||||||
|
else if ((res == FR_OK) && (bwt != btw)) res = FR_DENIED;
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if !_LFN_UNICODE // this will not work for unicode
|
||||||
|
FRESULT worker_fvx_rmkdir (TCHAR* tpath) {
|
||||||
|
DIR tmp_dir;
|
||||||
|
if (fa_opendir(&tmp_dir, tpath) != FR_OK) {
|
||||||
|
TCHAR* slash = strrchr(tpath, '/');
|
||||||
|
if (!slash) return FR_DENIED;
|
||||||
|
*slash = '\0';
|
||||||
|
FRESULT res;
|
||||||
|
if ((res = worker_fvx_rmkdir(tpath)) != FR_OK) return res;
|
||||||
|
*slash = '/';
|
||||||
|
return fa_mkdir(tpath);
|
||||||
|
} else {
|
||||||
|
f_closedir(&tmp_dir);
|
||||||
|
return FR_OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
FRESULT fvx_rmkdir (const TCHAR* path) {
|
||||||
|
#if !_LFN_UNICODE // this will not work for unicode
|
||||||
|
TCHAR tpath[_MAX_FN_LEN+1];
|
||||||
|
strncpy(tpath, path, _MAX_FN_LEN);
|
||||||
|
return worker_fvx_rmkdir( tpath );
|
||||||
|
#else
|
||||||
|
return FR_DENIED;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#if !_LFN_UNICODE // this will not work for unicode
|
||||||
|
FRESULT worker_fvx_runlink (TCHAR* tpath) {
|
||||||
|
FILINFO fno;
|
||||||
|
FRESULT res;
|
||||||
|
|
||||||
|
// this code handles directory content deletion
|
||||||
|
if ((res = fa_stat(tpath, &fno)) != FR_OK) return res; // tpath does not exist
|
||||||
|
if (fno.fattrib & AM_DIR) { // process folder contents
|
||||||
|
DIR pdir;
|
||||||
|
TCHAR* fname = tpath + strnlen(tpath, 255);
|
||||||
|
|
||||||
|
|
||||||
|
if ((res = fa_opendir(&pdir, tpath)) != FR_OK) return res;
|
||||||
|
*(fname++) = '/';
|
||||||
|
|
||||||
|
while (f_readdir(&pdir, &fno) == FR_OK) {
|
||||||
|
if ((strncmp(fno.fname, ".", 2) == 0) || (strncmp(fno.fname, "..", 3) == 0))
|
||||||
|
continue; // filter out virtual entries
|
||||||
|
strncpy(fname, fno.fname, tpath + 255 - fname);
|
||||||
|
if (fno.fname[0] == 0) {
|
||||||
|
break;
|
||||||
|
} else { // return value won't matter
|
||||||
|
worker_fvx_runlink(tpath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
f_closedir(&pdir);
|
||||||
|
*(--fname) = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
return fa_unlink( tpath );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
FRESULT fvx_runlink (const TCHAR* path) {
|
||||||
|
#if !_LFN_UNICODE // this will not work for unicode
|
||||||
|
TCHAR tpath[_MAX_FN_LEN+1];
|
||||||
|
strncpy(tpath, path, _MAX_FN_LEN);
|
||||||
|
return worker_fvx_runlink( tpath );
|
||||||
|
#else
|
||||||
|
return FR_DENIED;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// inspired by http://www.geeksforgeeks.org/wildcard-character-matching/
|
||||||
|
FRESULT fvx_match_name(const TCHAR* path, const TCHAR* pattern) {
|
||||||
|
// handling non asterisk chars
|
||||||
|
for (; *pattern != '*'; pattern++, path++) {
|
||||||
|
if ((*pattern == '\0') && (*path == '\0')) {
|
||||||
|
return FR_OK; // end reached simultaneously, match found
|
||||||
|
} else if ((*pattern == '\0') || (*path == '\0')) {
|
||||||
|
return FR_NO_FILE; // end reached on only one, failure
|
||||||
|
} else if ((*pattern != '?') && (tolower(*pattern) != tolower(*path))) {
|
||||||
|
return FR_NO_FILE; // chars don't match, failure
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// handling the asterisk (matches one or more chars in path)
|
||||||
|
if ((*(pattern+1) == '?') || (*(pattern+1) == '*')) {
|
||||||
|
return FR_NO_FILE; // stupid user shenanigans, failure
|
||||||
|
} else if (*path == '\0') {
|
||||||
|
return FR_NO_FILE; // asterisk, but end reached on path, failure
|
||||||
|
} else if (*(pattern+1) == '\0') {
|
||||||
|
return FR_OK; // nothing after the asterisk, match found
|
||||||
|
} else { // we couldn't really go without recursion here
|
||||||
|
for (path++; *path != '\0'; path++) {
|
||||||
|
if (fvx_match_name(path, pattern + 1) == FR_OK) return FR_OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return FR_NO_FILE;
|
||||||
|
}
|
||||||
|
|
||||||
|
FRESULT fvx_preaddir (DIR* dp, FILINFO* fno, const TCHAR* pattern) {
|
||||||
|
FRESULT res;
|
||||||
|
while ((res = fvx_readdir(dp, fno)) == FR_OK)
|
||||||
|
if (!pattern || !*(fno->fname) || (fvx_match_name(fno->fname, pattern) == FR_OK)) break;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
FRESULT fvx_findpath (TCHAR* path, const TCHAR* pattern) {
|
||||||
|
strncpy(path, pattern, _MAX_FN_LEN);
|
||||||
|
TCHAR* fname = strrchr(path, '/');
|
||||||
|
if (!fname) return FR_DENIED;
|
||||||
|
*fname = '\0';
|
||||||
|
|
||||||
|
TCHAR* npattern = strrchr(pattern, '/');
|
||||||
|
if (!npattern) return FR_DENIED;
|
||||||
|
npattern++;
|
||||||
|
|
||||||
|
DIR pdir;
|
||||||
|
FILINFO fno;
|
||||||
|
FRESULT res;
|
||||||
|
if ((res = fvx_opendir(&pdir, path)) != FR_OK) return res;
|
||||||
|
if (fvx_preaddir(&pdir, &fno, npattern) != FR_OK) *(fno.fname) = '\0';
|
||||||
|
fvx_closedir( &pdir );
|
||||||
|
|
||||||
|
*(fname++) = '/';
|
||||||
|
strncpy(fname, fno.fname, _MAX_FN_LEN - (fname - path));
|
||||||
|
if (!*(fno.fname)) return FR_NO_FILE;
|
||||||
|
|
||||||
|
return FR_OK;
|
||||||
|
}
|
||||||
|
@ -3,6 +3,8 @@
|
|||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "ff.h"
|
#include "ff.h"
|
||||||
|
|
||||||
|
#define AM_VRT 0x40 // Virtual (FILINFO FAT attribute)
|
||||||
|
|
||||||
#define fvx_tell(fp) ((fp)->fptr)
|
#define fvx_tell(fp) ((fp)->fptr)
|
||||||
#define fvx_size(fp) ((fp)->obj.objsize)
|
#define fvx_size(fp) ((fp)->obj.objsize)
|
||||||
|
|
||||||
@ -15,7 +17,22 @@ FRESULT fvx_close (FIL* fp);
|
|||||||
FRESULT fvx_lseek (FIL* fp, FSIZE_t ofs);
|
FRESULT fvx_lseek (FIL* fp, FSIZE_t ofs);
|
||||||
FRESULT fvx_sync (FIL* fp);
|
FRESULT fvx_sync (FIL* fp);
|
||||||
FRESULT fvx_stat (const TCHAR* path, FILINFO* fno);
|
FRESULT fvx_stat (const TCHAR* path, FILINFO* fno);
|
||||||
|
FRESULT fvx_rename (const TCHAR* path_old, const TCHAR* path_new);
|
||||||
|
FRESULT fvx_unlink (const TCHAR* path);
|
||||||
|
FRESULT fvx_mkdir (const TCHAR* path);
|
||||||
|
FRESULT fvx_opendir (DIR* dp, const TCHAR* path);
|
||||||
|
FRESULT fvx_closedir (DIR* dp);
|
||||||
|
FRESULT fvx_readdir (DIR* dp, FILINFO* fno);
|
||||||
|
|
||||||
// additional quick read / write functions
|
// additional quick read / write functions
|
||||||
FRESULT fvx_qread (const TCHAR* path, void* buff, FSIZE_t ofs, UINT btr, UINT* br);
|
FRESULT fvx_qread (const TCHAR* path, void* buff, FSIZE_t ofs, UINT btr, UINT* br);
|
||||||
FRESULT fvx_qwrite (const TCHAR* path, const void* buff, FSIZE_t ofs, UINT btw, UINT* bw);
|
FRESULT fvx_qwrite (const TCHAR* path, const void* buff, FSIZE_t ofs, UINT btw, UINT* bw);
|
||||||
|
|
||||||
|
// additional recursive functions
|
||||||
|
FRESULT fvx_rmkdir (const TCHAR* path);
|
||||||
|
FRESULT fvx_runlink (const TCHAR* path);
|
||||||
|
|
||||||
|
// additional wildcard based functions
|
||||||
|
FRESULT fvx_match_name(const TCHAR* path, const TCHAR* pattern);
|
||||||
|
FRESULT fvx_preaddir (DIR* dp, FILINFO* fno, const TCHAR* pattern);
|
||||||
|
FRESULT fvx_findfile (const TCHAR* path);
|
||||||
|
@ -131,38 +131,6 @@ bool GetVirtualDir(VirtualDir* vdir, const char* path) {
|
|||||||
return GetVirtualFile(&vfile, path) && OpenVirtualDir(vdir, &vfile);
|
return GetVirtualFile(&vfile, path) && OpenVirtualDir(vdir, &vfile);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GetVirtualDirContents(DirStruct* contents, char* fpath, int fnsize, const char* pattern, bool recursive) {
|
|
||||||
VirtualDir vdir;
|
|
||||||
VirtualFile vfile;
|
|
||||||
char* fname = fpath + strnlen(fpath, fnsize - 1);
|
|
||||||
(fname++)[0] = '/';
|
|
||||||
if (!GetVirtualDir(&vdir, fpath))
|
|
||||||
return false; // get dir reader object
|
|
||||||
while ((contents->n_entries < MAX_DIR_ENTRIES) && (ReadVirtualDir(&vfile, &vdir))) {
|
|
||||||
DirEntry* entry = &(contents->entry[contents->n_entries]);
|
|
||||||
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);
|
|
||||||
entry->size = vfile.size;
|
|
||||||
entry->type = (vfile.flags & VFLAG_DIR) ? T_DIR : T_FILE;
|
|
||||||
entry->marked = 0;
|
|
||||||
if (contents->n_entries >= MAX_DIR_ENTRIES)
|
|
||||||
break; // Too many entries, still okay
|
|
||||||
if (!recursive || (entry->type != T_DIR))
|
|
||||||
contents->n_entries++;
|
|
||||||
}
|
|
||||||
if (recursive && (vfile.flags & VFLAG_DIR)) {
|
|
||||||
if (!GetVirtualDirContents(contents, fpath, fnsize, pattern, recursive))
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true; // not much we can check here
|
|
||||||
}
|
|
||||||
|
|
||||||
bool GetVirtualFilename(char* name, const VirtualFile* vfile, u32 n_chars) {
|
bool GetVirtualFilename(char* name, const VirtualFile* vfile, u32 n_chars) {
|
||||||
if (!(vfile->flags & VFLAG_LV3)) strncpy(name, vfile->name, n_chars);
|
if (!(vfile->flags & VFLAG_LV3)) strncpy(name, vfile->name, n_chars);
|
||||||
else if (!GetVGameLv3Filename(name, vfile, n_chars)) return false;
|
else if (!GetVGameLv3Filename(name, vfile, n_chars)) return false;
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "fsdir.h"
|
|
||||||
#include "nand.h"
|
#include "nand.h"
|
||||||
|
|
||||||
#define VRT_SYSNAND NAND_SYSNAND
|
#define VRT_SYSNAND NAND_SYSNAND
|
||||||
@ -54,8 +53,6 @@ bool OpenVirtualDir(VirtualDir* vdir, VirtualFile* ventry);
|
|||||||
|
|
||||||
bool GetVirtualFile(VirtualFile* vfile, const char* path);
|
bool GetVirtualFile(VirtualFile* vfile, const char* path);
|
||||||
bool GetVirtualDir(VirtualDir* vdir, 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);
|
bool GetVirtualFilename(char* name, const VirtualFile* vfile, u32 n_chars);
|
||||||
|
|
||||||
int ReadVirtualFile(const VirtualFile* vfile, void* buffer, u64 offset, u64 count, u32* bytes_read);
|
int ReadVirtualFile(const VirtualFile* vfile, void* buffer, u64 offset, u64 count, u32* bytes_read);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user