mirror of
https://github.com/d0k3/GodMode9.git
synced 2025-06-26 13:42:47 +00:00
Godmode9 scripting support
This commit is contained in:
parent
9661ffc940
commit
78d9f1747a
@ -49,7 +49,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// GodMode9 version
|
// GodMode9 version
|
||||||
#define VERSION "1.2.3"
|
#define VERSION "1.2.4"
|
||||||
|
|
||||||
// input / output paths
|
// input / output paths
|
||||||
#define INPUT_PATHS "0:", "0:/files9", "1:/rw/files9"
|
#define INPUT_PATHS "0:", "0:/files9", "1:/rw/files9"
|
||||||
@ -82,22 +82,16 @@
|
|||||||
// buffer area defines (in use by sddata.c)
|
// buffer area defines (in use by sddata.c)
|
||||||
#define SDCRYPT_BUFFER ((u8*)0x21400000)
|
#define SDCRYPT_BUFFER ((u8*)0x21400000)
|
||||||
#define SDCRYPT_BUFFER_SIZE (0x100000)
|
#define SDCRYPT_BUFFER_SIZE (0x100000)
|
||||||
|
// buffer area defines (in use by fsscript.c)
|
||||||
|
#define SCRIPT_BUFFER ((u8*)0x21500000)
|
||||||
|
#define SCRIPT_BUFFER_SIZE (0x100000)
|
||||||
// buffer area defines (in use by vgame.c)
|
// buffer area defines (in use by vgame.c)
|
||||||
#define VGAME_BUFFER ((u8*)0x21500000)
|
#define VGAME_BUFFER ((u8*)0x21600000)
|
||||||
#define VGAME_BUFFER_SIZE (0x200000) // 2MB, big RomFS
|
#define VGAME_BUFFER_SIZE (0x200000) // 2MB, big RomFS
|
||||||
// buffer area defines (in use by vcart.c)
|
// buffer area defines (in use by vcart.c)
|
||||||
#define VCART_BUFFER ((u8*)0x21600000)
|
#define VCART_BUFFER ((u8*)0x21800000)
|
||||||
#define VCART_BUFFER_SIZE (0x20000) // 128kB, this is more than enough
|
#define VCART_BUFFER_SIZE (0x20000) // 128kB, this is more than enough
|
||||||
// buffer area defines (in use by image.c, for RAMdrive)
|
// buffer area defines (in use by image.c, for RAMdrive)
|
||||||
#define RAMDRV_BUFFER ((u8*)0x24000000) // top half of FCRAM
|
#define RAMDRV_BUFFER ((u8*)0x24000000) // top half of FCRAM
|
||||||
#define RAMDRV_SIZE_O3DS (0x04000000) // 64MB
|
#define RAMDRV_SIZE_O3DS (0x04000000) // 64MB
|
||||||
#define RAMDRV_SIZE_N3DS (0x0C000000) // 192MB
|
#define RAMDRV_SIZE_N3DS (0x0C000000) // 192MB
|
||||||
|
|
||||||
inline u32 strchrcount(const char* str, char symbol) {
|
|
||||||
u32 count = 0;
|
|
||||||
for (u32 i = 0; str[i] != '\0'; i++) {
|
|
||||||
if (str[i] == symbol)
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
12
source/common/power.h
Normal file
12
source/common/power.h
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
#include "i2c.h"
|
||||||
|
|
||||||
|
inline static void Reboot() {
|
||||||
|
i2cWriteRegister(I2C_DEV_MCU, 0x20, 1 << 2);
|
||||||
|
while(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline static void PowerOff()
|
||||||
|
{
|
||||||
|
i2cWriteRegister(I2C_DEV_MCU, 0x20, 1 << 0);
|
||||||
|
while (true);
|
||||||
|
}
|
@ -6,6 +6,7 @@
|
|||||||
#include "keydb.h"
|
#include "keydb.h"
|
||||||
#include "ctrtransfer.h"
|
#include "ctrtransfer.h"
|
||||||
#include "chainload.h"
|
#include "chainload.h"
|
||||||
|
#include "fsscript.h"
|
||||||
|
|
||||||
u32 IdentifyFileType(const char* path) {
|
u32 IdentifyFileType(const char* path) {
|
||||||
const u8 romfs_magic[] = { ROMFS_MAGIC };
|
const u8 romfs_magic[] = { ROMFS_MAGIC };
|
||||||
@ -105,6 +106,8 @@ u32 IdentifyFileType(const char* path) {
|
|||||||
} else if ((fsize <= PAYLOAD_MAX_SIZE) && ext && (strncasecmp(ext, "bin", 4) == 0)) {
|
} else if ((fsize <= PAYLOAD_MAX_SIZE) && ext && (strncasecmp(ext, "bin", 4) == 0)) {
|
||||||
return BIN_LAUNCH; // assume it's an ARM9 payload
|
return BIN_LAUNCH; // assume it's an ARM9 payload
|
||||||
#endif
|
#endif
|
||||||
|
} else if ((fsize <= SCRIPT_MAX_SIZE) && ext && (strncasecmp(ext, SCRIPT_EXT, strnlen(SCRIPT_EXT, 16) + 1) == 0)) {
|
||||||
|
return TXT_SCRIPT; // should be a script
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
#define BIN_TIKDB (1UL<<17)
|
#define BIN_TIKDB (1UL<<17)
|
||||||
#define BIN_KEYDB (1UL<<18)
|
#define BIN_KEYDB (1UL<<18)
|
||||||
#define BIN_LEGKEY (1UL<<19)
|
#define BIN_LEGKEY (1UL<<19)
|
||||||
|
#define TXT_SCRIPT (1UL<<20)
|
||||||
#define TYPE_BASE 0x00FFFFFF // 24 bit reserved for base types
|
#define TYPE_BASE 0x00FFFFFF // 24 bit reserved for base types
|
||||||
|
|
||||||
#define FLAG_ENC (1UL<<28)
|
#define FLAG_ENC (1UL<<28)
|
||||||
@ -45,6 +46,7 @@
|
|||||||
#define FTYPE_RESTORABLE(tp) (tp&(IMG_NAND))
|
#define FTYPE_RESTORABLE(tp) (tp&(IMG_NAND))
|
||||||
#define FTYPE_EBACKUP(tp) (tp&(IMG_NAND))
|
#define FTYPE_EBACKUP(tp) (tp&(IMG_NAND))
|
||||||
#define FTYPE_XORPAD(tp) (tp&(BIN_NCCHNFO))
|
#define FTYPE_XORPAD(tp) (tp&(BIN_NCCHNFO))
|
||||||
|
#define FTYPE_SCRIPT(tp) (tp&(TXT_SCRIPT))
|
||||||
#define FTYPE_PAYLOAD(tp) (tp&(BIN_LAUNCH))
|
#define FTYPE_PAYLOAD(tp) (tp&(BIN_LAUNCH))
|
||||||
|
|
||||||
u32 IdentifyFileType(const char* path);
|
u32 IdentifyFileType(const char* path);
|
||||||
|
490
source/filesys/fsscript.c
Normal file
490
source/filesys/fsscript.c
Normal file
@ -0,0 +1,490 @@
|
|||||||
|
#include "fsscript.h"
|
||||||
|
#include "fsutil.h"
|
||||||
|
#include "fsinit.h"
|
||||||
|
#include "fsperm.h"
|
||||||
|
#include "nandutil.h"
|
||||||
|
#include "gameutil.h"
|
||||||
|
#include "filetype.h"
|
||||||
|
#include "power.h"
|
||||||
|
#include "vff.h"
|
||||||
|
#include "ui.h"
|
||||||
|
|
||||||
|
#define _MAX_ARGS 2
|
||||||
|
#define _VAR_CNT_LEN 256
|
||||||
|
#define _VAR_NAME_LEN 32
|
||||||
|
#define _ERR_STR_LEN 32
|
||||||
|
|
||||||
|
#define VAR_BUFFER (SCRIPT_BUFFER + SCRIPT_BUFFER_SIZE - VAR_BUFFER_SIZE)
|
||||||
|
|
||||||
|
// some useful macros
|
||||||
|
#define IS_WHITESPACE(c) ((c == ' ') || (c == '\t') || (c == '\r') || (c == '\n'))
|
||||||
|
#define _FLG(c) (1 << (c - 'a'))
|
||||||
|
|
||||||
|
// command ids
|
||||||
|
typedef enum {
|
||||||
|
CMD_ID_NONE = 0,
|
||||||
|
CMD_ID_ECHO,
|
||||||
|
CMD_ID_ASK,
|
||||||
|
CMD_ID_SET,
|
||||||
|
CMD_ID_ALLOW,
|
||||||
|
CMD_ID_CP,
|
||||||
|
CMD_ID_MV,
|
||||||
|
CMD_ID_INJECT,
|
||||||
|
CMD_ID_RM,
|
||||||
|
CMD_ID_MKDIR,
|
||||||
|
CMD_ID_MOUNT,
|
||||||
|
CMD_ID_UMOUNT,
|
||||||
|
CMD_ID_FIND,
|
||||||
|
CMD_ID_FINDNOT,
|
||||||
|
CMD_ID_SHA,
|
||||||
|
CMD_ID_VERIFY,
|
||||||
|
CMD_ID_REBOOT,
|
||||||
|
CMD_ID_POWEROFF
|
||||||
|
} cmd_id;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
cmd_id id;
|
||||||
|
char cmd[16];
|
||||||
|
u32 n_args;
|
||||||
|
u32 allowed_flags;
|
||||||
|
} Gm9ScriptCmd;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char name[_VAR_NAME_LEN]; // variable name
|
||||||
|
char content[_VAR_CNT_LEN];
|
||||||
|
} Gm9ScriptVar;
|
||||||
|
|
||||||
|
Gm9ScriptCmd cmd_list[] = {
|
||||||
|
{ CMD_ID_ECHO , "echo" , 1, 0 },
|
||||||
|
{ CMD_ID_ASK , "ask" , 1, 0 },
|
||||||
|
{ CMD_ID_SET , "set" , 2, 0 },
|
||||||
|
{ CMD_ID_ALLOW , "allow" , 1, _FLG('a') },
|
||||||
|
{ CMD_ID_CP , "cp" , 2, _FLG('h') | _FLG('w') | _FLG('k') | _FLG('s') | _FLG('n')},
|
||||||
|
{ CMD_ID_MV , "mv" , 2, _FLG('w') | _FLG('k') | _FLG('s') | _FLG('n') },
|
||||||
|
{ CMD_ID_INJECT , "inject" , 2, _FLG('n') },
|
||||||
|
{ CMD_ID_RM , "rm" , 1, 0 },
|
||||||
|
{ CMD_ID_MKDIR , "mkdir" , 1, 0 },
|
||||||
|
{ CMD_ID_MOUNT , "mount" , 1, 0 },
|
||||||
|
{ CMD_ID_UMOUNT , "umount" , 0, 0 },
|
||||||
|
{ CMD_ID_FIND , "find" , 2, 0 },
|
||||||
|
{ CMD_ID_FINDNOT , "findnot" , 2, 0 },
|
||||||
|
{ CMD_ID_SHA , "sha" , 2, 0 },
|
||||||
|
{ CMD_ID_VERIFY , "verify" , 1, 0 },
|
||||||
|
{ CMD_ID_REBOOT , "reboot" , 0, 0 },
|
||||||
|
{ CMD_ID_POWEROFF, "poweroff", 0, 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
inline bool strntohex(const char* str, u8* hex, u32 len) {
|
||||||
|
if (!len) {
|
||||||
|
len = strlen(str);
|
||||||
|
if (len%1) return false;
|
||||||
|
else len >>= 1;
|
||||||
|
} else if (len*2 != strnlen(str, (len*2)+1)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (u32 i = 0; i < len; i++) {
|
||||||
|
char bytestr[2+1] = { 0 };
|
||||||
|
u32 bytehex;
|
||||||
|
memcpy(bytestr, str + (i*2), 2);
|
||||||
|
if (sscanf(bytestr, "%02lx", &bytehex) != 1)
|
||||||
|
return false;
|
||||||
|
hex[i] = (u8) bytehex;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* get_var(const char* name, char** endptr) {
|
||||||
|
Gm9ScriptVar* vars = (Gm9ScriptVar*) VAR_BUFFER;
|
||||||
|
u32 max_vars = VAR_BUFFER_SIZE / sizeof(Gm9ScriptVar);
|
||||||
|
|
||||||
|
u32 name_len = 0;
|
||||||
|
char* vname = (char*) name + 1;
|
||||||
|
if (*name != '[') return NULL;
|
||||||
|
for (name_len = 0; vname[name_len] != ']'; name_len++)
|
||||||
|
if ((name_len >= _VAR_NAME_LEN) || !vname[name_len]) return NULL;
|
||||||
|
if (endptr) *endptr = vname + name_len + 1;
|
||||||
|
|
||||||
|
u32 n_var = 0;
|
||||||
|
for (Gm9ScriptVar* var = vars; n_var < max_vars; n_var++, var++) {
|
||||||
|
if (!*(var->name) || (strncmp(var->name, vname, name_len) == 0)) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (n_var >= max_vars || !*(vars[n_var].name)) n_var = 0;
|
||||||
|
|
||||||
|
return vars[n_var].content;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* set_var(const char* name, const char* content) {
|
||||||
|
Gm9ScriptVar* vars = (Gm9ScriptVar*) VAR_BUFFER;
|
||||||
|
u32 max_vars = VAR_BUFFER_SIZE / sizeof(Gm9ScriptVar);
|
||||||
|
|
||||||
|
if ((strnlen(name, _VAR_NAME_LEN) > (_VAR_NAME_LEN-1)) || (strnlen(content, _VAR_CNT_LEN) > (_VAR_CNT_LEN-1)) ||
|
||||||
|
(strchr(name, '[') || strchr(name, ']')))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
u32 n_var = 0;
|
||||||
|
for (Gm9ScriptVar* var = vars; n_var < max_vars; n_var++, var++)
|
||||||
|
if (!*(var->name) || (strncmp(var->name, name, _VAR_NAME_LEN) == 0)) break;
|
||||||
|
if (n_var >= max_vars) return NULL;
|
||||||
|
strncpy(vars[n_var].name, name, _VAR_NAME_LEN);
|
||||||
|
strncpy(vars[n_var].content, content, _VAR_CNT_LEN);
|
||||||
|
if (!n_var) *(vars[n_var].content) = '\0'; // NULL var
|
||||||
|
|
||||||
|
return vars[n_var].content;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool init_vars(void) {
|
||||||
|
// reset var buffer
|
||||||
|
memset(VAR_BUFFER, 0x00, VAR_BUFFER_SIZE);
|
||||||
|
|
||||||
|
// set env vars
|
||||||
|
char env_serial[16] = { 0 };
|
||||||
|
if ((FileGetData("1:/rw/sys/SecureInfo_A", (u8*) env_serial, 0xF, 0x102) != 0xF) &&
|
||||||
|
(FileGetData("1:/rw/sys/SecureInfo_B", (u8*) env_serial, 0xF, 0x102) != 0xF))
|
||||||
|
snprintf(env_serial, 0xF, "UNKNOWN");
|
||||||
|
set_var("NULL", ""); // this one is special and should not be changed later
|
||||||
|
set_var("SERIAL", env_serial);
|
||||||
|
set_var("GM9OUT", OUTPUT_PATH);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool expand_arg(char* argex, const char* arg, u32 len) {
|
||||||
|
char* out = argex;
|
||||||
|
|
||||||
|
for (char* in = (char*) arg; in - arg < (int) len; in++) {
|
||||||
|
u32 out_len = out - argex;
|
||||||
|
if (out_len >= (_VAR_CNT_LEN-1)) return false; // maximum arglen reached
|
||||||
|
|
||||||
|
if (*in == '\\') { // escape line breaks (no other escape is handled)
|
||||||
|
if (*(++in) == 'n') *(out++) = '\n';
|
||||||
|
else {
|
||||||
|
*(out++) = '\\';
|
||||||
|
*(out++) = *in;
|
||||||
|
}
|
||||||
|
} else if (*in == '$') { // replace vars
|
||||||
|
char* content = get_var(in + 1, &in);
|
||||||
|
if (content) {
|
||||||
|
u32 clen = strnlen(content, 256);
|
||||||
|
strncpy(out, content, clen);
|
||||||
|
out += clen;
|
||||||
|
in--; // go back one char
|
||||||
|
} else *(out++) = *in;
|
||||||
|
} else *(out++) = *in;
|
||||||
|
}
|
||||||
|
*out = '\0';
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd_id get_cmd_id(char* cmd, u32 len, u32 flags, u32 argc, char* err_str) {
|
||||||
|
Gm9ScriptCmd* cmd_entry = NULL;
|
||||||
|
|
||||||
|
for (u32 i = 0; i < (sizeof(cmd_list)/sizeof(Gm9ScriptCmd)); i++) {
|
||||||
|
if (strncmp(cmd_list[i].cmd, cmd, len) == 0) {
|
||||||
|
cmd_entry = cmd_list + i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!cmd_entry) {
|
||||||
|
if (err_str) snprintf(err_str, _ERR_STR_LEN, "unknown cmd");
|
||||||
|
} else if (cmd_entry->n_args != argc) {
|
||||||
|
if (err_str) snprintf(err_str, _ERR_STR_LEN, "bad # of args");
|
||||||
|
} else if (~(cmd_entry->allowed_flags|_FLG('o')|_FLG('s')) & flags) {
|
||||||
|
if (err_str) snprintf(err_str, _ERR_STR_LEN, "unrecognized flags");
|
||||||
|
} else return cmd_entry->id;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 get_flag(char* str, u32 len, char* err_str) {
|
||||||
|
char flag_char = '\0';
|
||||||
|
|
||||||
|
if ((len < 2) || (*str != '-')) flag_char = '\0';
|
||||||
|
else if (len == 2) flag_char = str[1];
|
||||||
|
else if (strncmp(str, "--all", len) == 0) flag_char = 'a';
|
||||||
|
else if (strncmp(str, "--hash", len) == 0) flag_char = 'h';
|
||||||
|
else if (strncmp(str, "--skip", len) == 0) flag_char = 'k';
|
||||||
|
else if (strncmp(str, "--no_cancel", len) == 0) flag_char = 'n';
|
||||||
|
else if (strncmp(str, "--optional", len) == 0) flag_char = 'o';
|
||||||
|
else if (strncmp(str, "--silent", len) == 0) flag_char = 's';
|
||||||
|
else if (strncmp(str, "--overwrite", len) == 0) flag_char = 'w';
|
||||||
|
|
||||||
|
if ((flag_char < 'a') && (flag_char > 'z')) {
|
||||||
|
if (err_str) snprintf(err_str, _ERR_STR_LEN, "illegal flag");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _FLG(flag_char);
|
||||||
|
}
|
||||||
|
|
||||||
|
char* get_string(char* ptr, const char* line_end, u32* len, char** next, char* err_str) {
|
||||||
|
char* str = NULL;
|
||||||
|
*len = 0;
|
||||||
|
|
||||||
|
// skip whitespaces
|
||||||
|
for (; IS_WHITESPACE(*ptr) && (ptr < line_end); ptr++);
|
||||||
|
if (ptr >= line_end) return (*next = (char*) line_end); // end reached, all whitespaces
|
||||||
|
|
||||||
|
// handle string
|
||||||
|
if (*ptr == '\"') { // quotes
|
||||||
|
str = ++ptr;
|
||||||
|
for (; (*ptr != '\"') && (ptr < line_end); ptr++, (*len)++);
|
||||||
|
if (ptr >= line_end) { // failed if unresolved quotes
|
||||||
|
if (err_str) snprintf(err_str, _ERR_STR_LEN, "unresolved quotes");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
*next = ptr + 1;
|
||||||
|
} else { // no quotes, no whitespace
|
||||||
|
str = ptr;
|
||||||
|
for (; !IS_WHITESPACE(*ptr) && (ptr < line_end); ptr++, (*len)++);
|
||||||
|
*next = ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool parse_line(const char* line_start, const char* line_end, cmd_id* cmdid, u32* flags, u32* argc, char** argv, char* err_str) {
|
||||||
|
char* ptr = (char*) line_start;
|
||||||
|
char* str;
|
||||||
|
u32 len;
|
||||||
|
|
||||||
|
// set everything to initial values
|
||||||
|
*cmdid = 0;
|
||||||
|
*flags = 0;
|
||||||
|
*argc = 0;
|
||||||
|
|
||||||
|
// search for cmd
|
||||||
|
char* cmd = NULL;
|
||||||
|
u32 cmd_len = 0;
|
||||||
|
if (!(cmd = get_string(ptr, line_end, &cmd_len, &ptr, err_str))) return false; // string error
|
||||||
|
if ((cmd >= line_end) || (*cmd == '#')) return true; // empty line or comment
|
||||||
|
|
||||||
|
// got cmd, now parse flags & args
|
||||||
|
while ((str = get_string(ptr, line_end, &len, &ptr, err_str))) {
|
||||||
|
if ((str >= line_end) || (*str == '#')) // end of line or comment
|
||||||
|
return (*cmdid = get_cmd_id(cmd, cmd_len, *flags, *argc, err_str));
|
||||||
|
if (*str == '-') { // flag
|
||||||
|
u32 flag_add = get_flag(str, len, err_str);
|
||||||
|
if (!flag_add) return false; // not a proper flag
|
||||||
|
*flags |= flag_add;
|
||||||
|
} else if (*argc >= _MAX_ARGS) {
|
||||||
|
if (err_str) snprintf(err_str, _ERR_STR_LEN, "too many arguments");
|
||||||
|
return false; // too many arguments
|
||||||
|
} else if (!expand_arg(argv[(*argc)++], str, len)) {
|
||||||
|
if (err_str) snprintf(err_str, _ERR_STR_LEN, "argument expand failed");
|
||||||
|
return false; // arg expand failed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// end reached with a failed get_string()
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool run_cmd(cmd_id id, u32 flags, char** argv, char* err_str) {
|
||||||
|
bool ret = true; // true unless some cmd messes up
|
||||||
|
|
||||||
|
// perform command
|
||||||
|
if (id == CMD_ID_ECHO) {
|
||||||
|
ShowPrompt(false, argv[0]);
|
||||||
|
} else if (id == CMD_ID_ASK) {
|
||||||
|
ret = ShowPrompt(true, argv[0]);
|
||||||
|
if (err_str) snprintf(err_str, _ERR_STR_LEN, "user abort");
|
||||||
|
} else if (id == CMD_ID_SET) {
|
||||||
|
ret = set_var(argv[0], argv[1]);
|
||||||
|
if (err_str) snprintf(err_str, _ERR_STR_LEN, "set fail");
|
||||||
|
} else if (id == CMD_ID_ALLOW) {
|
||||||
|
if (flags & _FLG('a')) ret = CheckDirWritePermissions(argv[0]);
|
||||||
|
else ret = CheckWritePermissions(argv[0]);
|
||||||
|
if (err_str) snprintf(err_str, _ERR_STR_LEN, "permission fail");
|
||||||
|
} else if (id == CMD_ID_CP) {
|
||||||
|
u32 flags_ext = BUILD_PATH;
|
||||||
|
if (flags && _FLG('h')) flags_ext |= CALC_SHA;
|
||||||
|
if (flags && _FLG('n')) flags_ext |= NO_CANCEL;
|
||||||
|
if (flags && _FLG('s')) flags_ext |= SILENT;
|
||||||
|
if (flags && _FLG('w')) flags_ext |= OVERWRITE_ALL;
|
||||||
|
else if (flags && _FLG('k')) flags_ext |= SKIP_ALL;
|
||||||
|
ret = PathMoveCopy(argv[1], argv[0], &flags_ext, false);
|
||||||
|
if (err_str) snprintf(err_str, _ERR_STR_LEN, "copy fail");
|
||||||
|
} else if (id == CMD_ID_MV) {
|
||||||
|
u32 flags_ext = BUILD_PATH;
|
||||||
|
if (flags && _FLG('n')) flags_ext |= NO_CANCEL;
|
||||||
|
if (flags && _FLG('s')) flags_ext |= SILENT;
|
||||||
|
if (flags && _FLG('w')) flags_ext |= OVERWRITE_ALL;
|
||||||
|
else if (flags && _FLG('k')) flags_ext |= SKIP_ALL;
|
||||||
|
ret = PathMoveCopy(argv[1], argv[0], &flags_ext, true);
|
||||||
|
if (err_str) snprintf(err_str, _ERR_STR_LEN, "move fail");
|
||||||
|
} else if (id == CMD_ID_INJECT) {
|
||||||
|
char* atstr_dst = strrchr(argv[1], '@');
|
||||||
|
char* atstr_org = strrchr(argv[0], '@');
|
||||||
|
u64 at_org = 0;
|
||||||
|
u64 sz_org = 0;
|
||||||
|
if (atstr_org) {
|
||||||
|
*(atstr_org++) = '\0';
|
||||||
|
if (sscanf(atstr_org, "%llX:%llX", &at_org, &sz_org) != 2) {
|
||||||
|
if (sscanf(atstr_org, "%llX", &at_org) != 1) at_org = 0;
|
||||||
|
sz_org = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!atstr_dst) {
|
||||||
|
ret = false;
|
||||||
|
if (err_str) snprintf(err_str, _ERR_STR_LEN, "missing dest offset");
|
||||||
|
} else {
|
||||||
|
u64 at_dst = 0;
|
||||||
|
*(atstr_dst++) = '\0';
|
||||||
|
ret = ((sscanf(atstr_dst, "%llX", &at_dst) == 1) && FileInjectFile(argv[1], argv[0], at_dst, at_org, sz_org, NULL));
|
||||||
|
if (err_str) snprintf(err_str, _ERR_STR_LEN, "inject fail");
|
||||||
|
}
|
||||||
|
} else if (id == CMD_ID_RM) {
|
||||||
|
char pathstr[_ERR_STR_LEN];
|
||||||
|
TruncateString(pathstr, argv[0], 24, 8);
|
||||||
|
ShowString("Deleting %s...", pathstr);
|
||||||
|
ret = PathDelete(argv[0]);
|
||||||
|
if (err_str) snprintf(err_str, _ERR_STR_LEN, "remove fail");
|
||||||
|
} else if (id == CMD_ID_MKDIR) {
|
||||||
|
ret = (fvx_rmkdir(argv[0]) == FR_OK);
|
||||||
|
if (err_str) snprintf(err_str, _ERR_STR_LEN, "makedir fail");
|
||||||
|
} else if (id == CMD_ID_MOUNT) {
|
||||||
|
ret = InitImgFS(argv[0]);
|
||||||
|
if (err_str) snprintf(err_str, _ERR_STR_LEN, "mount fail");
|
||||||
|
} else if (id == CMD_ID_UMOUNT) {
|
||||||
|
InitImgFS(NULL);
|
||||||
|
} else if (id == CMD_ID_FIND) {
|
||||||
|
char* path = set_var(argv[1], ""); // setup the variable, get pointer
|
||||||
|
if (!path) {
|
||||||
|
ret = false;
|
||||||
|
if (err_str) snprintf(err_str, _ERR_STR_LEN, "var fail");
|
||||||
|
} else {
|
||||||
|
ret = (fvx_findpath(path, argv[0]) == FR_OK);
|
||||||
|
if (err_str) snprintf(err_str, _ERR_STR_LEN, "find fail");
|
||||||
|
}
|
||||||
|
} else if (id == CMD_ID_FINDNOT) {
|
||||||
|
char* path = set_var(argv[1], ""); // setup the variable, get pointer
|
||||||
|
if (!path) {
|
||||||
|
ret = false;
|
||||||
|
if (err_str) snprintf(err_str, _ERR_STR_LEN, "var fail");
|
||||||
|
} else {
|
||||||
|
ret = (fvx_findnopath(path, argv[0]) == FR_OK);
|
||||||
|
if (err_str) snprintf(err_str, _ERR_STR_LEN, "findnot fail");
|
||||||
|
}
|
||||||
|
} else if (id == CMD_ID_SHA) {
|
||||||
|
u8 sha256_fil[0x20];
|
||||||
|
u8 sha256_cmp[0x20];
|
||||||
|
if (!FileGetSha256(argv[0], sha256_fil)) {
|
||||||
|
ret = false;
|
||||||
|
if (err_str) snprintf(err_str, _ERR_STR_LEN, "sha arg0 fail");
|
||||||
|
} else if ((FileGetData(argv[1], sha256_cmp, 0x20, 0) != 0x20) && !strntohex(argv[1], sha256_cmp, 0x20)) {
|
||||||
|
ret = false;
|
||||||
|
if (err_str) snprintf(err_str, _ERR_STR_LEN, "sha arg1 fail");
|
||||||
|
} else {
|
||||||
|
ret = (memcmp(sha256_fil, sha256_cmp, 0x20) == 0);
|
||||||
|
if (err_str) snprintf(err_str, _ERR_STR_LEN, "sha does not match");
|
||||||
|
}
|
||||||
|
} else if (id == CMD_ID_VERIFY) {
|
||||||
|
u32 filetype = IdentifyFileType(argv[0]);
|
||||||
|
if (filetype & IMG_NAND) ret = (ValidateNandDump(argv[0]) == 0);
|
||||||
|
else ret = (VerifyGameFile(argv[0]) == 0);
|
||||||
|
if (err_str) snprintf(err_str, _ERR_STR_LEN, "verification failed");
|
||||||
|
} else if (id == CMD_ID_REBOOT) {
|
||||||
|
Reboot();
|
||||||
|
} else if (id == CMD_ID_POWEROFF) {
|
||||||
|
PowerOff();
|
||||||
|
} else { // command not recognized / bad number of arguments
|
||||||
|
ret = false;
|
||||||
|
if (err_str) snprintf(err_str, _ERR_STR_LEN, "unknown error");
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool run_line(const char* line_start, const char* line_end, u32* flags, char* err_str) {
|
||||||
|
char* argv[_MAX_ARGS] = { NULL };
|
||||||
|
u32 argc = 0;
|
||||||
|
cmd_id cmdid;
|
||||||
|
|
||||||
|
// flags handling (if no pointer given)
|
||||||
|
u32 lflags;
|
||||||
|
if (!flags) flags = &lflags;
|
||||||
|
*flags = 0;
|
||||||
|
|
||||||
|
// set up argv vars (if not already done)
|
||||||
|
for (u32 i = 0; i < _MAX_ARGS; i++) {
|
||||||
|
char name[16];
|
||||||
|
snprintf(name, 16, "ARGV%01lu", i);
|
||||||
|
argv[i] = set_var(name, "");
|
||||||
|
if (!argv[i]) return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse current line, grab cmd / flags / args
|
||||||
|
if (!parse_line(line_start, line_end, &cmdid, flags, &argc, argv, err_str)) {
|
||||||
|
*flags &= ~(_FLG('o')|_FLG('s')); // parsing errors are never silent or optional
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// run the command (if available)
|
||||||
|
if (cmdid && !run_cmd(cmdid, *flags, argv, err_str)) {
|
||||||
|
char* msg_fail = get_var("[ERRORMSG]", NULL);
|
||||||
|
if (msg_fail && *msg_fail) *err_str = '\0'; // use custom error message
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// success if we arrive here
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ExecuteGM9Script(const char* path_script) {
|
||||||
|
// revert mount state?
|
||||||
|
char* script = (char*) SCRIPT_BUFFER;
|
||||||
|
char* ptr = script;
|
||||||
|
|
||||||
|
// fetch script
|
||||||
|
u32 script_size;
|
||||||
|
if (!(script_size = FileGetData(path_script, (u8*) script, SCRIPT_MAX_SIZE, 0)))
|
||||||
|
return false;
|
||||||
|
char* end = script + script_size;
|
||||||
|
*end = '\0';
|
||||||
|
|
||||||
|
// initialise variables
|
||||||
|
init_vars();
|
||||||
|
|
||||||
|
for (u32 line = 1; ptr < end; line++) {
|
||||||
|
u32 flags = 0;
|
||||||
|
|
||||||
|
// find line end
|
||||||
|
char* line_end = strchr(ptr, '\n');
|
||||||
|
if (!line_end) line_end = ptr + strlen(ptr);
|
||||||
|
|
||||||
|
// run command
|
||||||
|
char err_str[_ERR_STR_LEN+1] = { 0 };
|
||||||
|
if (!run_line(ptr, line_end, &flags, err_str)) { // error handling
|
||||||
|
if (!(flags & _FLG('s'))) { // not silent
|
||||||
|
if (!*err_str) {
|
||||||
|
char* msg_fail = get_var("[ERRORMSG]", NULL);
|
||||||
|
if (msg_fail && *msg_fail) ShowPrompt(false, msg_fail);
|
||||||
|
else snprintf(err_str, _ERR_STR_LEN, "error message fail");
|
||||||
|
}
|
||||||
|
if (*err_str) {
|
||||||
|
char line_str[32+1];
|
||||||
|
char* lptr0 = ptr;
|
||||||
|
char* lptr1 = line_end;
|
||||||
|
for (; IS_WHITESPACE(*lptr0) && (lptr0 < lptr1); lptr0++); // skip whitespaces
|
||||||
|
if ((lptr1 > lptr0) && (*(lptr1-1) == '\r')) lptr1--; // handle \r
|
||||||
|
if (lptr1 - lptr0 > 32) snprintf(line_str, 32+1, "%.29s...", lptr0);
|
||||||
|
else snprintf(line_str, 32+1, "%.*s", lptr1 - lptr0, lptr0);
|
||||||
|
char path_str[32+1];
|
||||||
|
TruncateString(path_str, path_script, 32, 12);
|
||||||
|
ShowPrompt(false, "%s\nline %lu: %s\n%s", path_str, line, err_str, line_str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!(flags & _FLG('o'))) return false; // failed if not optional
|
||||||
|
}
|
||||||
|
|
||||||
|
// reposition pointer
|
||||||
|
ptr = line_end + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* msg_okay = get_var("[SUCCESSMSG]", NULL);
|
||||||
|
if (msg_okay && *msg_okay) ShowPrompt(false, msg_okay);
|
||||||
|
return true;
|
||||||
|
}
|
10
source/filesys/fsscript.h
Normal file
10
source/filesys/fsscript.h
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
#define VAR_BUFFER_SIZE (72 * 1024) // enough for exactly 256 vars
|
||||||
|
|
||||||
|
#define SCRIPT_EXT "gm9"
|
||||||
|
#define SCRIPT_MAX_SIZE (SCRIPT_BUFFER_SIZE-VAR_BUFFER_SIZE-1)
|
||||||
|
|
||||||
|
bool ExecuteGM9Script(const char* path_script);
|
@ -11,8 +11,8 @@
|
|||||||
#include "ff.h"
|
#include "ff.h"
|
||||||
#include "ui.h"
|
#include "ui.h"
|
||||||
|
|
||||||
#define SKIP_CUR (1UL<<7)
|
#define SKIP_CUR (1UL<<8)
|
||||||
#define OVERWRITE_CUR (1UL<<8)
|
#define OVERWRITE_CUR (1UL<<9)
|
||||||
|
|
||||||
// Volume2Partition resolution table
|
// Volume2Partition resolution table
|
||||||
PARTITION VolToPart[] = {
|
PARTITION VolToPart[] = {
|
||||||
@ -199,13 +199,9 @@ u32 FileFindData(const char* path, u8* data, u32 size_data, u32 offset_file) {
|
|||||||
return found;
|
return found;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FileInjectFile(const char* dest, const char* orig, u32 offset, u32* flags) {
|
bool FileInjectFile(const char* dest, const char* orig, u64 off_dest, u64 off_orig, u64 size, u32* flags) {
|
||||||
FIL ofile;
|
FIL ofile;
|
||||||
FIL dfile;
|
FIL dfile;
|
||||||
u64 osize;
|
|
||||||
u64 dsize;
|
|
||||||
bool no_cancel = (flags && (*flags & NO_CANCEL));
|
|
||||||
bool ret = true;
|
|
||||||
|
|
||||||
if (!CheckWritePermissions(dest)) return false;
|
if (!CheckWritePermissions(dest)) return false;
|
||||||
if (strncmp(dest, orig, 256) == 0) {
|
if (strncmp(dest, orig, 256) == 0) {
|
||||||
@ -221,32 +217,41 @@ bool FileInjectFile(const char* dest, const char* orig, u32 offset, u32* flags)
|
|||||||
fvx_close(&dfile);
|
fvx_close(&dfile);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
fvx_lseek(&dfile, offset);
|
fvx_lseek(&dfile, off_dest);
|
||||||
fvx_lseek(&ofile, 0);
|
fvx_lseek(&ofile, off_orig);
|
||||||
dsize = fvx_size(&dfile);
|
if (!size && (off_orig < fvx_size(&ofile)))
|
||||||
osize = f_size(&ofile);
|
size = fvx_size(&ofile) - off_orig;
|
||||||
|
|
||||||
// check file limits
|
// check file limits
|
||||||
if (offset + osize > dsize) {
|
if (off_dest + size > fvx_size(&dfile)) {
|
||||||
ShowPrompt(false, "Operation would write beyond end of file");
|
ShowPrompt(false, "Operation would write beyond end of file");
|
||||||
fvx_close(&dfile);
|
fvx_close(&dfile);
|
||||||
fvx_close(&ofile);
|
fvx_close(&ofile);
|
||||||
return false;
|
return false;
|
||||||
|
} else if (off_orig + size > fvx_size(&ofile)) {
|
||||||
|
ShowPrompt(false, "Not enough data in file");
|
||||||
|
fvx_close(&dfile);
|
||||||
|
fvx_close(&ofile);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ret = true;
|
||||||
ShowProgress(0, 0, orig);
|
ShowProgress(0, 0, orig);
|
||||||
for (u64 pos = 0; (pos < osize) && ret; pos += MAIN_BUFFER_SIZE) {
|
for (u64 pos = 0; (pos < size) && ret; pos += MAIN_BUFFER_SIZE) {
|
||||||
UINT read_bytes = min(MAIN_BUFFER_SIZE, osize - pos);
|
UINT read_bytes = min(MAIN_BUFFER_SIZE, size - pos);
|
||||||
UINT bytes_read = read_bytes;
|
UINT bytes_read = read_bytes;
|
||||||
UINT bytes_written = read_bytes;
|
UINT bytes_written = read_bytes;
|
||||||
if (fvx_read(&ofile, MAIN_BUFFER, read_bytes, &bytes_read) != FR_OK) {
|
if ((fvx_read(&ofile, MAIN_BUFFER, read_bytes, &bytes_read) != FR_OK) ||
|
||||||
ret = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if ((!ShowProgress(pos + (bytes_read / 2), osize, orig) && !no_cancel) ||
|
|
||||||
(fvx_write(&dfile, MAIN_BUFFER, read_bytes, &bytes_written) != FR_OK) ||
|
(fvx_write(&dfile, MAIN_BUFFER, read_bytes, &bytes_written) != FR_OK) ||
|
||||||
(bytes_read != bytes_written))
|
(bytes_read != bytes_written))
|
||||||
ret = false;
|
ret = false;
|
||||||
|
if (ret && !ShowProgress(pos + bytes_read, size, orig)) {
|
||||||
|
if (flags && (*flags & NO_CANCEL)) {
|
||||||
|
ShowPrompt(false, "Cancel is now allowed here");
|
||||||
|
ShowProgress(0, 0, orig);
|
||||||
|
ShowProgress(pos + bytes_read, size, orig);
|
||||||
|
} else ret = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ShowProgress(1, 1, orig);
|
ShowProgress(1, 1, orig);
|
||||||
|
|
||||||
@ -319,6 +324,7 @@ bool DirInfo(const char* path, u64* tsize, u32* tdirs, u32* tfiles) {
|
|||||||
|
|
||||||
bool PathMoveCopyRec(char* dest, char* orig, u32* flags, bool move) {
|
bool PathMoveCopyRec(char* dest, char* orig, u32* flags, bool move) {
|
||||||
bool to_virtual = GetVirtualSource(dest);
|
bool to_virtual = GetVirtualSource(dest);
|
||||||
|
bool silent = (flags && (*flags & SILENT));
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
|
|
||||||
// check destination write permission (special paths only)
|
// check destination write permission (special paths only)
|
||||||
@ -335,8 +341,7 @@ bool PathMoveCopyRec(char* dest, char* orig, u32* flags, bool move) {
|
|||||||
TruncateString(deststr, dest, 36, 8);
|
TruncateString(deststr, dest, 36, 8);
|
||||||
|
|
||||||
// the copy process takes place here
|
// the copy process takes place here
|
||||||
bool no_cancel = (flags && (*flags & NO_CANCEL));
|
if (!ShowProgress(0, 0, orig) && !(flags && (*flags & NO_CANCEL))) return false;
|
||||||
if (!ShowProgress(0, 0, orig) && !no_cancel) return false;
|
|
||||||
if (move && fvx_stat(dest, NULL) != FR_OK) { // moving if dest not existing
|
if (move && fvx_stat(dest, NULL) != FR_OK) { // moving if dest not existing
|
||||||
ret = (fvx_rename(orig, dest) == FR_OK);
|
ret = (fvx_rename(orig, dest) == FR_OK);
|
||||||
} else if (fno.fattrib & AM_DIR) { // processing folders (same for move & copy)
|
} else if (fno.fattrib & AM_DIR) { // processing folders (same for move & copy)
|
||||||
@ -346,7 +351,7 @@ bool PathMoveCopyRec(char* dest, char* orig, u32* flags, bool move) {
|
|||||||
// create the destination folder if it does not already exist
|
// create the destination folder if it does not already exist
|
||||||
if (fvx_opendir(&pdir, dest) != FR_OK) {
|
if (fvx_opendir(&pdir, dest) != FR_OK) {
|
||||||
if (fvx_mkdir(dest) != FR_OK) {
|
if (fvx_mkdir(dest) != FR_OK) {
|
||||||
ShowPrompt(false, "%s\nError: Overwriting file with dir", deststr);
|
if (!silent) ShowPrompt(false, "%s\nError: Overwriting file with dir", deststr);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else fvx_closedir(&pdir);
|
} else fvx_closedir(&pdir);
|
||||||
@ -378,7 +383,7 @@ bool PathMoveCopyRec(char* dest, char* orig, u32* flags, bool move) {
|
|||||||
} else if (move) { // moving if destination exists
|
} else if (move) { // moving if destination exists
|
||||||
if (fvx_stat(dest, &fno) != FR_OK) return false;
|
if (fvx_stat(dest, &fno) != FR_OK) return false;
|
||||||
if (fno.fattrib & AM_DIR) {
|
if (fno.fattrib & AM_DIR) {
|
||||||
ShowPrompt(false, "%s\nError: Overwriting dir with file", deststr);
|
if (!silent) ShowPrompt(false, "%s\nError: Overwriting dir with file", deststr);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (fvx_unlink(dest) != FR_OK) return false;
|
if (fvx_unlink(dest) != FR_OK) return false;
|
||||||
@ -396,19 +401,19 @@ bool PathMoveCopyRec(char* dest, char* orig, u32* flags, bool move) {
|
|||||||
|
|
||||||
fsize = fvx_size(&ofile);
|
fsize = fvx_size(&ofile);
|
||||||
if (!to_virtual && (GetFreeSpace(dest) < fsize)) {
|
if (!to_virtual && (GetFreeSpace(dest) < fsize)) {
|
||||||
ShowPrompt(false, "%s\nError: Not enough space in drive", deststr);
|
if (!silent) ShowPrompt(false, "%s\nError: Not enough space in drive", deststr);
|
||||||
fvx_close(&ofile);
|
fvx_close(&ofile);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fvx_open(&dfile, dest, FA_WRITE | FA_CREATE_ALWAYS) != FR_OK) {
|
if (fvx_open(&dfile, dest, FA_WRITE | FA_CREATE_ALWAYS) != FR_OK) {
|
||||||
ShowPrompt(false, "%s\nError: Cannot open destination file", deststr);
|
if (!silent) ShowPrompt(false, "%s\nError: Cannot open destination file", deststr);
|
||||||
fvx_close(&ofile);
|
fvx_close(&ofile);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (to_virtual && (fvx_size(&dfile) < fsize)) {
|
if (to_virtual && (fvx_size(&dfile) < fsize)) {
|
||||||
ShowPrompt(false, "%s\nError: Not enough virtual space", deststr);
|
if (!silent) ShowPrompt(false, "%s\nError: Not enough virtual space", deststr);
|
||||||
fvx_close(&ofile);
|
fvx_close(&ofile);
|
||||||
fvx_close(&dfile);
|
fvx_close(&dfile);
|
||||||
return false;
|
return false;
|
||||||
@ -426,9 +431,15 @@ bool PathMoveCopyRec(char* dest, char* orig, u32* flags, bool move) {
|
|||||||
UINT bytes_written = 0;
|
UINT bytes_written = 0;
|
||||||
if ((fvx_read(&ofile, MAIN_BUFFER, MAIN_BUFFER_SIZE, &bytes_read) != FR_OK) ||
|
if ((fvx_read(&ofile, MAIN_BUFFER, MAIN_BUFFER_SIZE, &bytes_read) != FR_OK) ||
|
||||||
(fvx_write(&dfile, MAIN_BUFFER, bytes_read, &bytes_written) != FR_OK) ||
|
(fvx_write(&dfile, MAIN_BUFFER, bytes_read, &bytes_written) != FR_OK) ||
|
||||||
(bytes_read != bytes_written) ||
|
(bytes_read != bytes_written))
|
||||||
(!ShowProgress(pos + bytes_read, fsize, orig) && !no_cancel))
|
|
||||||
ret = false;
|
ret = false;
|
||||||
|
if (ret && !ShowProgress(pos + bytes_read, fsize, orig)) {
|
||||||
|
if (flags && (*flags & NO_CANCEL)) {
|
||||||
|
ShowPrompt(false, "Cancel is now allowed here");
|
||||||
|
ShowProgress(0, 0, orig);
|
||||||
|
ShowProgress(pos + bytes_read, fsize, orig);
|
||||||
|
} else ret = false;
|
||||||
|
}
|
||||||
if (flags && (*flags & CALC_SHA))
|
if (flags && (*flags & CALC_SHA))
|
||||||
sha_update(MAIN_BUFFER, bytes_read);
|
sha_update(MAIN_BUFFER, bytes_read);
|
||||||
}
|
}
|
||||||
@ -529,8 +540,8 @@ bool PathMoveCopy(const char* dest, const char* orig, u32* flags, bool move) {
|
|||||||
|
|
||||||
// actual move / copy operation
|
// actual move / copy operation
|
||||||
bool same_drv = (strncmp(lorig, ldest, 2) == 0);
|
bool same_drv = (strncmp(lorig, ldest, 2) == 0);
|
||||||
bool res = PathMoveCopyRec(ldest, lorig, flags, move & same_drv);
|
bool res = PathMoveCopyRec(ldest, lorig, flags, move && same_drv);
|
||||||
if (move & res && (!flags || !(*flags&SKIP_CUR))) PathDelete(lorig);
|
if (move && res && (!flags || !(*flags&SKIP_CUR))) PathDelete(lorig);
|
||||||
return res;
|
return res;
|
||||||
} else { // virtual destination handling
|
} else { // virtual destination handling
|
||||||
// can't write an SHA file to a virtual destination
|
// can't write an SHA file to a virtual destination
|
||||||
|
@ -5,11 +5,12 @@
|
|||||||
// move / copy flags
|
// move / copy flags
|
||||||
#define OVERRIDE_PERM (1UL<<0)
|
#define OVERRIDE_PERM (1UL<<0)
|
||||||
#define NO_CANCEL (1UL<<1)
|
#define NO_CANCEL (1UL<<1)
|
||||||
#define CALC_SHA (1UL<<2)
|
#define SILENT (1UL<<2)
|
||||||
#define BUILD_PATH (1UL<<3)
|
#define CALC_SHA (1UL<<3)
|
||||||
#define ASK_ALL (1UL<<4)
|
#define BUILD_PATH (1UL<<4)
|
||||||
#define SKIP_ALL (1UL<<5)
|
#define ASK_ALL (1UL<<5)
|
||||||
#define OVERWRITE_ALL (1UL<<6)
|
#define SKIP_ALL (1UL<<6)
|
||||||
|
#define OVERWRITE_ALL (1UL<<7)
|
||||||
|
|
||||||
/** Return total size of SD card **/
|
/** Return total size of SD card **/
|
||||||
uint64_t GetSDCardSize();
|
uint64_t GetSDCardSize();
|
||||||
@ -39,7 +40,7 @@ bool FileGetSha256(const char* path, u8* sha256);
|
|||||||
u32 FileFindData(const char* path, u8* data, u32 size_data, u32 offset_file);
|
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, u32* flags);
|
bool FileInjectFile(const char* dest, const char* orig, u64 off_dest, u64 off_orig, u64 size, u32* flags);
|
||||||
|
|
||||||
/** 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);
|
||||||
|
@ -325,5 +325,37 @@ FRESULT fvx_findpath (TCHAR* path, const TCHAR* pattern) {
|
|||||||
strncpy(fname, fno.fname, _MAX_FN_LEN - (fname - path));
|
strncpy(fname, fno.fname, _MAX_FN_LEN - (fname - path));
|
||||||
if (!*(fno.fname)) return FR_NO_PATH;
|
if (!*(fno.fname)) return FR_NO_PATH;
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
FRESULT fvx_findnopath (TCHAR* path, const TCHAR* pattern) {
|
||||||
|
strncpy(path, pattern, _MAX_FN_LEN);
|
||||||
|
TCHAR* fname = strrchr(path, '/');
|
||||||
|
if (!fname) return FR_DENIED;
|
||||||
|
fname++;
|
||||||
|
|
||||||
|
TCHAR* rep[16];
|
||||||
|
u32 n_rep = 0;
|
||||||
|
for (u32 i = 0; fname[i]; i++) {
|
||||||
|
if (fname[i] == '?') {
|
||||||
|
rep[n_rep] = &(fname[i]);
|
||||||
|
*rep[n_rep++] = '0';
|
||||||
|
}
|
||||||
|
if (n_rep >= 16) return FR_DENIED;
|
||||||
|
}
|
||||||
|
if (!n_rep) return fvx_stat(path, NULL);
|
||||||
|
|
||||||
|
while (fvx_stat(path, NULL) == FR_OK) {
|
||||||
|
for (INT i = n_rep - 1; (i >= 0); i--) {
|
||||||
|
if (*(rep[i]) == '9') {
|
||||||
|
if (!i) return FR_NO_PATH;
|
||||||
|
*(rep[i]) = '0';
|
||||||
|
} else {
|
||||||
|
(*(rep[i]))++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return FR_OK;
|
return FR_OK;
|
||||||
}
|
}
|
||||||
|
@ -36,4 +36,5 @@ FRESULT fvx_runlink (const TCHAR* path);
|
|||||||
// additional wildcard based functions
|
// additional wildcard based functions
|
||||||
FRESULT fvx_match_name(const TCHAR* path, const TCHAR* pattern);
|
FRESULT fvx_match_name(const TCHAR* path, const TCHAR* pattern);
|
||||||
FRESULT fvx_preaddir (DIR* dp, FILINFO* fno, const TCHAR* pattern);
|
FRESULT fvx_preaddir (DIR* dp, FILINFO* fno, const TCHAR* pattern);
|
||||||
FRESULT fvx_findfile (const TCHAR* path);
|
FRESULT fvx_findpath (TCHAR* path, const TCHAR* pattern);
|
||||||
|
FRESULT fvx_findnopath (TCHAR* path, const TCHAR* pattern);
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
#include "fsutil.h"
|
#include "fsutil.h"
|
||||||
#include "fsperm.h"
|
#include "fsperm.h"
|
||||||
#include "fsgame.h"
|
#include "fsgame.h"
|
||||||
|
#include "fsscript.h"
|
||||||
#include "gameutil.h"
|
#include "gameutil.h"
|
||||||
#include "keydbutil.h"
|
#include "keydbutil.h"
|
||||||
#include "nandutil.h"
|
#include "nandutil.h"
|
||||||
@ -686,10 +687,11 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, DirStruct* cur
|
|||||||
bool restorable = (FTYPE_RESTORABLE(filetype) && IS_A9LH && !(drvtype & DRV_SYSNAND));
|
bool restorable = (FTYPE_RESTORABLE(filetype) && IS_A9LH && !(drvtype & DRV_SYSNAND));
|
||||||
bool ebackupable = (FTYPE_EBACKUP(filetype));
|
bool ebackupable = (FTYPE_EBACKUP(filetype));
|
||||||
bool xorpadable = (FTYPE_XORPAD(filetype));
|
bool xorpadable = (FTYPE_XORPAD(filetype));
|
||||||
|
bool scriptable = (FTYPE_SCRIPT(filetype));
|
||||||
bool launchable = ((FTYPE_PAYLOAD(filetype)) && (drvtype & DRV_FAT) && !IS_SIGHAX);
|
bool launchable = ((FTYPE_PAYLOAD(filetype)) && (drvtype & DRV_FAT) && !IS_SIGHAX);
|
||||||
bool special_opt = mountable || verificable || decryptable || encryptable || cia_buildable || cia_buildable_legit || cxi_dumpable ||
|
bool special_opt = mountable || verificable || decryptable || encryptable || cia_buildable || cia_buildable_legit || cxi_dumpable ||
|
||||||
tik_buildable || key_buildable || titleinfo || renamable || transferable || hsinjectable || restorable || xorpadable ||
|
tik_buildable || key_buildable || titleinfo || renamable || transferable || hsinjectable || restorable || xorpadable ||
|
||||||
launchable || ebackupable;
|
ebackupable || launchable || scriptable;
|
||||||
|
|
||||||
char pathstr[32+1];
|
char pathstr[32+1];
|
||||||
TruncateString(pathstr, curr_entry->path, 32, 8);
|
TruncateString(pathstr, curr_entry->path, 32, 8);
|
||||||
@ -733,7 +735,8 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, DirStruct* cur
|
|||||||
(filetype & BIN_KEYDB) ? "AESkeydb options..." :
|
(filetype & BIN_KEYDB) ? "AESkeydb options..." :
|
||||||
(filetype & BIN_LEGKEY) ? "Build " KEYDB_NAME :
|
(filetype & BIN_LEGKEY) ? "Build " KEYDB_NAME :
|
||||||
(filetype & BIN_NCCHNFO)? "NCCHinfo options..." :
|
(filetype & BIN_NCCHNFO)? "NCCHinfo options..." :
|
||||||
(filetype & BIN_LAUNCH) ? "Launch as arm9 payload" : "???";
|
(filetype & BIN_LAUNCH) ? "Launch as arm9 payload" :
|
||||||
|
(filetype & TXT_SCRIPT) ? "Execute GM9 script" : "???";
|
||||||
optionstr[hexviewer-1] = "Show in Hexeditor";
|
optionstr[hexviewer-1] = "Show in Hexeditor";
|
||||||
optionstr[calcsha-1] = "Calculate SHA-256";
|
optionstr[calcsha-1] = "Calculate SHA-256";
|
||||||
if (calccmac > 0) optionstr[calccmac-1] = "Calculate CMAC";
|
if (calccmac > 0) optionstr[calccmac-1] = "Calculate CMAC";
|
||||||
@ -801,7 +804,7 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, DirStruct* cur
|
|||||||
TruncateString(origstr, clipboard->entry[0].name, 18, 10);
|
TruncateString(origstr, clipboard->entry[0].name, 18, 10);
|
||||||
u64 offset = ShowHexPrompt(0, 8, "Inject data from %s?\nSpecifiy offset below.", origstr);
|
u64 offset = ShowHexPrompt(0, 8, "Inject data from %s?\nSpecifiy offset below.", origstr);
|
||||||
if (offset != (u64) -1) {
|
if (offset != (u64) -1) {
|
||||||
if (!FileInjectFile(curr_entry->path, clipboard->entry[0].path, (u32) offset, NULL))
|
if (!FileInjectFile(curr_entry->path, clipboard->entry[0].path, (u32) offset, 0, 0, NULL))
|
||||||
ShowPrompt(false, "Failed injecting %s", origstr);
|
ShowPrompt(false, "Failed injecting %s", origstr);
|
||||||
clipboard->n_entries = 0;
|
clipboard->n_entries = 0;
|
||||||
}
|
}
|
||||||
@ -840,6 +843,7 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, DirStruct* cur
|
|||||||
int xorpad = (xorpadable) ? ++n_opt : -1;
|
int xorpad = (xorpadable) ? ++n_opt : -1;
|
||||||
int xorpad_inplace = (xorpadable) ? ++n_opt : -1;
|
int xorpad_inplace = (xorpadable) ? ++n_opt : -1;
|
||||||
int launch = (launchable) ? ++n_opt : -1;
|
int launch = (launchable) ? ++n_opt : -1;
|
||||||
|
int script = (scriptable) ? ++n_opt : -1;
|
||||||
if (mount > 0) optionstr[mount-1] = "Mount image to drive";
|
if (mount > 0) optionstr[mount-1] = "Mount image to drive";
|
||||||
if (restore > 0) optionstr[restore-1] = "Restore SysNAND (safe)";
|
if (restore > 0) optionstr[restore-1] = "Restore SysNAND (safe)";
|
||||||
if (ebackup > 0) optionstr[ebackup-1] = "Update embedded backup";
|
if (ebackup > 0) optionstr[ebackup-1] = "Update embedded backup";
|
||||||
@ -859,6 +863,7 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, DirStruct* cur
|
|||||||
if (xorpad > 0) optionstr[xorpad-1] = "Build XORpads (SD output)";
|
if (xorpad > 0) optionstr[xorpad-1] = "Build XORpads (SD output)";
|
||||||
if (xorpad_inplace > 0) optionstr[xorpad_inplace-1] = "Build XORpads (inplace)";
|
if (xorpad_inplace > 0) optionstr[xorpad_inplace-1] = "Build XORpads (inplace)";
|
||||||
if (launch > 0) optionstr[launch-1] = "Launch as ARM9 payload";
|
if (launch > 0) optionstr[launch-1] = "Launch as ARM9 payload";
|
||||||
|
if (script > 0) optionstr[script-1] = "Execute GM9 script";
|
||||||
|
|
||||||
// auto select when there is only one option
|
// auto select when there is only one option
|
||||||
user_select = (n_opt <= 1) ? n_opt : (int) ShowSelectPrompt(n_opt, optionstr, (n_marked > 1) ?
|
user_select = (n_opt <= 1) ? n_opt : (int) ShowSelectPrompt(n_opt, optionstr, (n_marked > 1) ?
|
||||||
@ -1200,6 +1205,11 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, DirStruct* cur
|
|||||||
} // failed load is basically impossible here
|
} // failed load is basically impossible here
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
} else if ((user_select == script)) {
|
||||||
|
if (ShowPrompt(true, "%s\nExecute script?", pathstr))
|
||||||
|
ShowPrompt(false, "%s\nScript execute %s", pathstr, ExecuteGM9Script(curr_entry->path) ? "success" : "failure");
|
||||||
|
GetDirContents(current_dir, current_path);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return FileHandlerMenu(current_path, cursor, scroll, current_dir, clipboard);
|
return FileHandlerMenu(current_path, cursor, scroll, current_dir, clipboard);
|
||||||
|
@ -1,20 +1,7 @@
|
|||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "godmode.h"
|
#include "godmode.h"
|
||||||
#include "ui.h"
|
#include "ui.h"
|
||||||
#include "i2c.h"
|
#include "power.h"
|
||||||
|
|
||||||
void Reboot()
|
|
||||||
{
|
|
||||||
i2cWriteRegister(I2C_DEV_MCU, 0x20, 1 << 2);
|
|
||||||
while(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void PowerOff()
|
|
||||||
{
|
|
||||||
i2cWriteRegister(I2C_DEV_MCU, 0x20, 1 << 0);
|
|
||||||
while (true);
|
|
||||||
}
|
|
||||||
|
|
||||||
u8 *top_screen, *bottom_screen;
|
u8 *top_screen, *bottom_screen;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user