Enabled a write permission system

Plus tons of design and under the hood changes
This commit is contained in:
d0k3 2016-03-01 02:00:48 +01:00
parent 44c351c1a7
commit bf19767a82
5 changed files with 203 additions and 59 deletions

View File

@ -171,30 +171,92 @@ bool ShowPrompt(bool ask, const char *format, ...)
u32 str_width, str_height;
u32 x, y;
char str[384] = {}; // 384 should be more than enough
char str[512] = {}; // 512 should be more than enough
va_list va;
va_start(va, format);
vsnprintf(str, 384, format, va);
vsnprintf(str, 512, format, va);
va_end(va);
str_width = GetDrawStringWidth(str);
str_height = GetDrawStringHeight(str) + (2 * 10);
x = (str_width >= SCREEN_WIDTH_TOP) ? 0 : (SCREEN_WIDTH_TOP - str_width) / 2;
y = (str_height >= SCREEN_HEIGHT) ? 0 : (SCREEN_HEIGHT - str_height) / 2;
y = (str_height >= SCREEN_HEIGHT) ? 0 : (SCREEN_HEIGHT - (str_height+20)) / 2;
ClearScreenF(true, false, COLOR_STD_BG);
DrawStringF(true, x, y, COLOR_STD_FONT, COLOR_STD_BG, (ask) ? "%s\n\n(<A> to continue, <B> to cancel)" : "%s\n\n(<A> to continue)", str);
DrawStringF(true, x, y, COLOR_STD_FONT, COLOR_STD_BG, str);
DrawStringF(true, x, y + str_height, COLOR_STD_FONT, COLOR_STD_BG, (ask) ? "(<A> yes, <B> no)" : "(<A> to continue)");
while (true) {
u32 pad_state = InputWait();
if (pad_state & BUTTON_A) break;
else if (pad_state & BUTTON_B) return false;
else if (ask && (pad_state & BUTTON_B)) return false;
}
ClearScreenF(true, false, COLOR_STD_BG);
return true;
}
bool ShowUnlockSequence(u32 seqlvl, const char *format, ...) {
const u32 seqcolors[4] = { COLOR_STD_FONT, COLOR_GREEN, COLOR_YELLOW, COLOR_RED };
const u32 sequences[4][5] = {
{ BUTTON_RIGHT, BUTTON_DOWN, BUTTON_RIGHT, BUTTON_DOWN, BUTTON_A },
{ BUTTON_LEFT, BUTTON_DOWN, BUTTON_RIGHT, BUTTON_UP, BUTTON_A },
{ BUTTON_LEFT, BUTTON_RIGHT, BUTTON_DOWN, BUTTON_UP, BUTTON_A },
{ BUTTON_LEFT, BUTTON_UP, BUTTON_RIGHT, BUTTON_UP, BUTTON_A }
};
const char seqsymbols[4][5] = {
{ '\x1A', '\x19', '\x1A', '\x19', 'A' },
{ '\x1B', '\x19', '\x1A', '\x18', 'A' },
{ '\x1B', '\x1A', '\x19', '\x18', 'A' },
{ '\x1B', '\x18', '\x1A', '\x18', 'A' },
};
const u32 len = 5;
u32 lvl = 0;
u32 str_width, str_height;
u32 x, y;
char str[512] = {}; // 512 should be more than enough
va_list va;
va_start(va, format);
vsnprintf(str, 512, format, va);
va_end(va);
str_width = GetDrawStringWidth(str);
str_height = GetDrawStringHeight(str) + (2 * 10);
x = (str_width >= SCREEN_WIDTH_TOP) ? 0 : (SCREEN_WIDTH_TOP - str_width) / 2;
y = (str_height >= SCREEN_HEIGHT) ? 0 : (SCREEN_HEIGHT - (str_height + 30)) / 2;
ClearScreenF(true, false, COLOR_STD_BG);
DrawStringF(true, x, y, COLOR_STD_FONT, COLOR_STD_BG, str);
DrawStringF(true, x, y + str_height, COLOR_STD_FONT, COLOR_STD_BG, "To proceed, enter this:");
while (true) {
for (u32 n = 0; n < len; n++) {
DrawStringF(true, x + (n*4*8), y + str_height + 10,
(lvl > n) ? seqcolors[seqlvl] : COLOR_GREY, COLOR_STD_BG, "<%c>", seqsymbols[seqlvl][n]);
}
if (lvl == len)
break;
u32 pad_state = InputWait();
if (!(pad_state & BUTTON_ANY))
continue;
else if (pad_state & sequences[seqlvl][lvl])
lvl++;
else if (pad_state & BUTTON_B)
break;
else if (lvl == 0 || !(pad_state & sequences[seqlvl][lvl-1]))
lvl = 0;
}
ClearScreenF(true, false, COLOR_STD_BG);
return (lvl >= len);
}
void ShowProgress(u64 current, u64 total, const char* opstr, bool clearscreen)
{
const u32 bar_width = 240;
@ -202,14 +264,15 @@ void ShowProgress(u64 current, u64 total, const char* opstr, bool clearscreen)
const u32 bar_pos_x = (SCREEN_WIDTH_TOP - bar_width) / 2;
const u32 bar_pos_y = (SCREEN_HEIGHT / 2) - bar_height - 2;
const u32 text_pos_y = (SCREEN_HEIGHT / 2);
u32 prog_width = ((total > 0) && (current <= total)) ? (current * (bar_width-2)) / total : 0;
u32 prog_width = ((total > 0) && (current <= total)) ? (current * (bar_width-4)) / total : 0;
char tempstr[64];
if (clearscreen) ClearScreenF(true, false, COLOR_STD_BG);
DrawRectangleF(true, bar_pos_x, bar_pos_y, bar_width, bar_height, COLOR_DARKGREY);
DrawRectangleF(true, bar_pos_x + 1, bar_pos_y + 1, bar_width - 2, bar_height - 2, COLOR_STD_BG);
DrawRectangleF(true, bar_pos_x + 1, bar_pos_y + 1, prog_width, bar_height - 2, COLOR_STD_FONT);
DrawRectangleF(true, bar_pos_x + 2, bar_pos_y + 2, prog_width, bar_height - 4, COLOR_STD_FONT);
ResizeString(tempstr, opstr, 28, 8, false);
DrawStringF(true, bar_pos_x, text_pos_y, COLOR_STD_FONT, COLOR_STD_BG, tempstr);
DrawString(TOP_SCREEN0, tempstr, bar_pos_x, text_pos_y, COLOR_STD_FONT, COLOR_STD_BG);
DrawString(TOP_SCREEN1, tempstr, bar_pos_x, text_pos_y, COLOR_STD_FONT, COLOR_STD_BG);
}

View File

@ -23,6 +23,10 @@
#define COLOR_YELLOW RGB(0xFF, 0xFF, 0x00)
#define COLOR_CYAN RGB(0xFF, 0x00, 0xFF)
#define COLOR_BRIGHTRED RGB(0xFF, 0x30, 0x30)
#define COLOR_BRIGHTYELLOW RGB(0xFF, 0xFF, 0x30)
#define COLOR_BRIGHTGREEN RGB(0x30, 0xFF, 0x30)
#define COLOR_TINTEDBLUE RGB(0x60, 0x60, 0x80)
#define COLOR_TINTEDYELLOW RGB(0xD0, 0xD0, 0x60)
#define COLOR_TINTEDGREEN RGB(0x70, 0x80, 0x70)
@ -65,4 +69,5 @@ void TruncateString(char* dest, const char* orig, int nsize, int tpos);
void FormatBytes(char* str, u64 bytes);
bool ShowPrompt(bool ask, const char *format, ...);
bool ShowUnlockSequence(u32 seqlvl, const char *format, ...);
void ShowProgress(u64 current, u64 total, const char* opstr, bool clearscreen);

View File

@ -54,13 +54,16 @@ bool CheckWritePermissions(const char* path) {
}
if ((pdrv >= 1) && (pdrv <= 3) && (write_permission_level < 3)) {
ShowPrompt(false, "Writing to the SysNAND is locked!\nUnlock it from the root menu.");
if (ShowPrompt(true, "Writing to the SysNAND is locked!\nUnlock it now?"))
return SetWritePermissions(3);
return false;
} else if ((pdrv >= 4) && (pdrv <= 6) && (write_permission_level < 2)) {
ShowPrompt(false, "Writing to the EmuNAND is locked!\nUnlock it from the root menu.");
if (ShowPrompt(true, "Writing to the EmuNAND is locked!\nUnlock it now?"))
return SetWritePermissions(2);
return false;
} else if ((pdrv == 0) && (write_permission_level < 1)) {
ShowPrompt(false, "Writing to the SD card is locked!\nUnlock it from the root menu.");
if (ShowPrompt(true, "Writing to the SD card is locked!\nUnlock it now?"))
return SetWritePermissions(1);
return false;
}
@ -68,11 +71,38 @@ bool CheckWritePermissions(const char* path) {
}
bool SetWritePermissions(u32 level) {
if (write_permission_level >= level) {
// no need to ask the user here
write_permission_level = level;
return true;
}
switch (level) {
case 1:
if (!ShowUnlockSequence(1, "You want to enable SD card\nwriting permissions."))
return false;
break;
case 2:
if (!ShowUnlockSequence(2, "You want to enable EmuNAND\nwriting permissions.\nThis is potentially dangerous!\nKeep a backup, just in case."))
return false;
break;
case 3:
if (!ShowUnlockSequence(3, "!This is your only warning!\n \nYou want to enable SysNAND\nwriting permissions.\nThis is potentially dangerous\nand can brick your 3DS!\nHaving a SysNAND backup and\nNANDmod is recommended."))
return false;
break;
default:
break;
}
write_permission_level = level;
return true;
}
u32 GetWritePermissions() {
return write_permission_level;
}
bool FileCreate(const char* path, u8* data, u32 size) {
FIL file;
UINT bytes_written = 0;

View File

@ -32,6 +32,9 @@ bool CheckWritePermissions(const char* path);
/** Set new write permissions */
bool SetWritePermissions(u32 level);
/** Get write permissions */
u32 GetWritePermissions();
/** Create / overwrite file and write the provided data to it **/
bool FileCreate(const char* path, u8* data, u32 size);

View File

@ -3,19 +3,32 @@
#include "hid.h"
#include "fs.h"
#define COLOR_TOP_BAR COLOR_WHITE
#define COLOR_TOP_BAR ((GetWritePermissions() == 0) ? COLOR_WHITE : (GetWritePermissions() == 1) ? COLOR_BRIGHTGREEN : (GetWritePermissions() == 2) ? COLOR_BRIGHTYELLOW : COLOR_BRIGHTRED)
#define COLOR_SIDE_BAR COLOR_DARKGREY
#define COLOR_MARKED COLOR_TINTEDYELLOW
#define COLOR_FILE COLOR_TINTEDGREEN
#define COLOR_DIR COLOR_TINTEDBLUE
#define COLOR_ROOT COLOR_GREY
void DrawUserInterface(const char* curr_path, DirEntry* curr_entry, DirStruct* clipboard) {
const u32 info_start = 16;
void DrawUserInterface(const char* curr_path, DirEntry* curr_entry, DirStruct* clipboard, bool switched) {
const u32 info_start = 18;
static u32 state_prev = 0xFFFFFFFF;
u32 state_curr =
((*curr_path) ? (1<<0) : 0) |
((clipboard->n_entries) ? (1<<1) : 0) |
((switched) ? (1<<2) : 0) |
(GetWritePermissions()<<3);
char bytestr0[32];
char bytestr1[32];
char tempstr[64];
if (state_prev != state_curr) {
ClearScreenF(true, false, COLOR_STD_BG);
state_prev = state_curr;
}
// top bar - current path & free/total storage
DrawRectangleF(true, 0, 0, SCREEN_WIDTH_TOP, 12, COLOR_TOP_BAR);
if (strncmp(curr_path, "", 256) != 0) {
@ -52,11 +65,25 @@ void DrawUserInterface(const char* curr_path, DirEntry* curr_entry, DirStruct* c
}
*tempstr = '\0';
if (clipboard->n_entries > 10) snprintf(tempstr, 60, "+ %lu more", clipboard->n_entries - 10);
DrawStringF(true, SCREEN_WIDTH_TOP - (20*8) - 4, info_start + 12 + (10*10), COLOR_GREY, COLOR_STD_BG, "%20s", tempstr);
DrawStringF(true, SCREEN_WIDTH_TOP - (20*8) - 4, info_start + 12 + (10*10), COLOR_DARKGREY, COLOR_STD_BG, "%20s", tempstr);
// bottom: inctruction block
char* instr = "GodMode 9 v0.0.3\n<A>/<B>/<\x18\x19\x1A\x1B> - Navigation\n<L>(+<\x18\x19\x1A\x1B> - Mark entries(s)\n<X> - Make a Screenshot\n<START/+\x1B> - Reboot/Poweroff";
char instr[256];
snprintf(instr, 256, "%s%s%s%s%s%s",
"GodMode 9 v0.0.4\n", // generic start part
(*curr_path && !switched) ? "<R> (hold) - Switch commands\n<L> (+<\x18\x19\x1A\x1B>) - Mark entries\n" :
(*curr_path && switched) ? "<R> (rel.) - Switch commands\n<L> - Make a Screenshot\n" :
"<R+L> - Make a Screenshot\n",
(!(*curr_path)) ? "" :
(!switched) ? "<X> - DELETE file(s)\n<Y> - ADD file(s) to clipboard\n" :
"<X> - RENAME file\n<Y> - CREATE directory\n",
(*curr_path) ? "" :
(GetWritePermissions() <= 1) ? "<X> - Unlock EmuNAND writing\n<Y> - Unlock SysNAND writing\n" :
(GetWritePermissions() == 2) ? "<X> - Relock EmuNAND writing\n<Y> - Unlock SysNAND writing\n" :
"<X> - Relock EmuNAND writing\n<Y> - Relock SysNAND writing\n",
(clipboard->n_entries) ? "<SELECT> - Clear Clipboard\n" : "", // only if clipboard is full
"<START/+\x1B> - Reboot/Poweroff"); // generic end part
DrawStringF(true, (SCREEN_WIDTH_TOP - GetDrawStringWidth(instr)) / 2, SCREEN_HEIGHT - 2 - GetDrawStringHeight(instr), COLOR_STD_FONT, COLOR_STD_BG, instr);
}
@ -115,54 +142,72 @@ u32 GodMode() {
char current_path[256] = { 0x00 };
int mark_setting = -1;
bool switched = false;
u32 cursor = 0;
ClearScreenF(true, true, COLOR_BLACK);
ClearScreenF(true, true, COLOR_STD_BG);
if (!InitFS()) return exit_mode;
GetDirContents(current_dir, "");
clipboard->n_entries = 0;
while (true) { // this is the main loop
DrawUserInterface(current_path, &(current_dir->entry[cursor]), clipboard); // no need to fully do this everytime!
DrawUserInterface(current_path, &(current_dir->entry[cursor]), clipboard, switched);
DrawDirContents(current_dir, cursor);
u32 pad_state = InputWait();
if (pad_state & BUTTON_DOWN) { // cursor up
cursor++;
if (cursor >= current_dir->n_entries)
cursor = current_dir->n_entries - 1;
} else if ((pad_state & BUTTON_UP) && cursor) { // cursor down
cursor--;
} else if ((pad_state & BUTTON_RIGHT) && (mark_setting < 0)) { // cursor down (quick)
cursor += quick_stp;
if (cursor >= current_dir->n_entries)
cursor = current_dir->n_entries - 1;
} else if ((pad_state & BUTTON_LEFT) && (mark_setting < 0)) { // curor up (quick)
cursor = (cursor >= quick_stp) ? cursor - quick_stp : 0;
} else if (pad_state & BUTTON_RIGHT) { // mark all entries
for (u32 c = 0; c < current_dir->n_entries; c++) current_dir->entry[c].marked = 1;
} else if (pad_state & BUTTON_LEFT) { // unmark all entries
for (u32 c = 0; c < current_dir->n_entries; c++) current_dir->entry[c].marked = 0;
} else if ((pad_state & BUTTON_L1) && *current_path) { // switch marking for single entry
if (mark_setting >= 0) {
current_dir->entry[cursor].marked = mark_setting;
} else {
current_dir->entry[cursor].marked ^= 0x1;
mark_setting = current_dir->entry[cursor].marked;
switched = (pad_state & BUTTON_R1);
if (!(*current_path) || switched || !(pad_state & BUTTON_L1)) {
mark_setting = -1;
}
} else if ((pad_state & BUTTON_A) && (current_dir->entry[cursor].type != T_FAT_FILE)) { // one level up
// commands which are valid anywhere
if ((pad_state & BUTTON_A) && (current_dir->entry[cursor].type != T_FAT_FILE)) { // one level up
strncpy(current_path, current_dir->entry[cursor].path, 256);
GetDirContents(current_dir, current_path);
cursor = 0;
ClearScreenF(true, true, COLOR_STD_BG); // not really required
} else if (pad_state & BUTTON_B) { // one level down
char* last_slash = strrchr(current_path, '/');
if (last_slash) *last_slash = '\0';
else *current_path = '\0';
GetDirContents(current_dir, current_path);
cursor = 0;
ClearScreenF(true, true, COLOR_STD_BG); // not really required
} else if (pad_state & BUTTON_X) { // create a screenshot
} else if ((pad_state & BUTTON_DOWN) && (cursor < current_dir->n_entries - 1)) { // cursor up
cursor++;
} else if ((pad_state & BUTTON_UP) && cursor) { // cursor down
cursor--;
} else if ((pad_state & BUTTON_RIGHT) && (mark_setting < 0)) { // cursor down (quick)
cursor += quick_stp;
if (cursor >= current_dir->n_entries)
cursor = current_dir->n_entries - 1;
} else if ((pad_state & BUTTON_LEFT) && (mark_setting < 0)) { // cursor up (quick)
cursor = (cursor >= quick_stp) ? cursor - quick_stp : 0;
} else if (pad_state & BUTTON_RIGHT) { // mark all entries
for (u32 c = 0; c < current_dir->n_entries; c++) current_dir->entry[c].marked = 1;
} else if (pad_state & BUTTON_LEFT) { // unmark all entries
for (u32 c = 0; c < current_dir->n_entries; c++) current_dir->entry[c].marked = 0;
} else if (switched && (pad_state & BUTTON_L1)) { // switched L -> screenshot
CreateScreenshot();
ClearScreenF(true, true, COLOR_STD_BG);
} else if (*current_path && (pad_state & BUTTON_L1)) { // unswitched L - mark/unmark single entry
if (mark_setting >= 0) {
current_dir->entry[cursor].marked = mark_setting;
} else {
current_dir->entry[cursor].marked ^= 0x1;
mark_setting = current_dir->entry[cursor].marked;
}
} else if ((pad_state & BUTTON_SELECT) && (clipboard->n_entries > 0)) { // clear clipboard
clipboard->n_entries = 0;
}
// highly specific commands
if (!(*current_path)) { // in the root folder...
if (pad_state & BUTTON_X) {
SetWritePermissions((GetWritePermissions() >= 2) ? 1 : 2);
} else if (pad_state & BUTTON_Y) {
SetWritePermissions((GetWritePermissions() >= 3) ? 2 : 3);
}
} else if (!switched) { // standard unswitched command set
if (pad_state & BUTTON_X) { // delete a file
// not implemented yet
} else if ((pad_state & BUTTON_Y) && (clipboard->n_entries == 0)) { // fill clipboard
for (u32 c = 0; c < current_dir->n_entries; c++) {
if (current_dir->entry[c].marked) {
@ -175,13 +220,11 @@ u32 GodMode() {
DirEntryCpy(&(clipboard->entry[0]), &(current_dir->entry[cursor]));
clipboard->n_entries = 1;
}
} else if ((pad_state & BUTTON_SELECT) && (clipboard->n_entries > 0)) { // clear clipboard
clipboard->n_entries = 0;
}
} else { // switched command set
// not implemented yet
}
if (!(pad_state & BUTTON_L1)) {
mark_setting = -1;
}
if (pad_state & BUTTON_START) {
exit_mode = (pad_state & BUTTON_LEFT) ? GODMODE_EXIT_POWEROFF : GODMODE_EXIT_REBOOT;
break;