Skip to content

Commit

Permalink
Dump All and Dump to dir
Browse files Browse the repository at this point in the history
  • Loading branch information
3096 committed May 13, 2018
1 parent 261e4e7 commit 5ec3aae
Show file tree
Hide file tree
Showing 3 changed files with 146 additions and 39 deletions.
3 changes: 2 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,11 @@ include $(DEVKITPRO)/libnx/switch_rules
#---------------------------------------------------------------------------------
VERSION_MAJOR := 0
VERSION_MINOR := 1
VERSION_MICRO := 1

APP_TITLE := Y'allAreNUTs
APP_AUTHOR := 3096
APP_VERSION := ${VERSION_MAJOR}.${VERSION_MINOR}
APP_VERSION := ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_MICRO}

TARGET := $(notdir $(CURDIR))
BUILD := build
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ But since I know no one would listen to me and try to use this mess anyway...

Here's an update.

Now you can use up & down to select a save to dump. All dumps will be saved to `save` by pressing A (will overwrite whatever's already in there.) Pressing X will inject all data that's present in `inject` (sometimes doesn't work due to service being broken on 5.0 and without using it, fsdevCommitDevice() can fail... Use at your own risk and always have backups)
Now you can use UP & DOWN, LEFT & RIGHT to select a save to dump. All dumps will be saved to `save` by pressing A or `save/{titleID}/{userID}/` by pressing Y (will overwrite whatever's already in there.) Press ZR to dump all saves. Pressing X will inject all data that's present in `inject` (sometimes doesn't work due to service being broken on 5.0 and without using it, fsdevCommitDevice() can fail... Use at your own risk and always have backups)

Build it with [my fork of libnx](https://github.com/3096/libnx) btw.

Expand Down
180 changes: 143 additions & 37 deletions source/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

const char * EXPORT_DIR = "save/";
const char * INJECT_DIR = "inject/";
const char * SAVE_DEV = "save";

Result getSaveList(std::vector<FsSaveDataInfo> & saveInfoList) {
Result rc=0;
Expand Down Expand Up @@ -40,9 +41,13 @@ Result getSaveList(std::vector<FsSaveDataInfo> & saveInfoList) {
return 0;
}

Result mountSaveByTitleAndUser(u64 titleID, u128 userID) {
Result mountSaveBySaveDataInfo(const FsSaveDataInfo & info, const char * dev) {
Result rc=0;
int ret=0;

u64 titleID = info.titleID;
u128 userID = info.userID;

FsFileSystem tmpfs;

printf("\n\nUsing titleID=0x%016lx userID: 0x%lx 0x%lx\n", titleID, (u64)(userID>>64), (u64)userID);
Expand All @@ -53,7 +58,7 @@ Result mountSaveByTitleAndUser(u64 titleID, u128 userID) {
return rc;
}

ret = fsdevMountDevice("save", tmpfs);
ret = fsdevMountDevice(dev, tmpfs);
if (ret==-1) {
printf("fsdevMountDevice() failed.\n");
rc = ret;
Expand All @@ -72,7 +77,7 @@ int isDirectory(const char *path) {

int cpFile(const char * filenameI, const char * filenameO) {
remove( filenameO );

std::ifstream src(filenameI, std::ios::binary);
std::ofstream dst(filenameO, std::ios::binary);

Expand All @@ -82,7 +87,8 @@ int cpFile(const char * filenameI, const char * filenameO) {
}


int copyAllSave(const char * dev, const char * path, bool isInject) {
int copyAllSave(const char * dev, const char * path, bool isInject,
const char * exportDir) {
DIR* dir;
struct dirent* ent;
char dirPath[0x100];
Expand Down Expand Up @@ -123,19 +129,32 @@ int copyAllSave(const char * dev, const char * path, bool isInject) {
strcpy(filenameI, dev);
strcat(filenameI, filename);

strcpy(filenameO, EXPORT_DIR);
if (exportDir != NULL) {
strcpy(filenameO, exportDir);
} else {
strcpy(filenameO, EXPORT_DIR);
}
strcat(filenameO, filename);
}

printf("Copying %s...\n", filenameI);

if(isDirectory(filenameI)) {
mkdir(filenameO, 0700);
int res = copyAllSave(dev, filename, isInject);
int res = copyAllSave(dev, filename, isInject, exportDir);
if(res != 0)
return res;
} else {
printf("Copying %s... ", filenameI);
cpFile(filenameI, filenameO);
if(isInject) {
if (R_SUCCEEDED(fsdevCommitDevice(SAVE_DEV))) { // Thx yellows8
printf("committed.\n");
} else {
printf("fsdevCommitDevice() failed...\n");
return -2;
}
} else {
printf("\n");
}
}
}
closedir(dir);
Expand All @@ -144,6 +163,28 @@ int copyAllSave(const char * dev, const char * path, bool isInject) {
}
}

int dumpAll() {
return copyAllSave("save:/", ".", false, NULL);
}

int dumpAllTo(char * dir) {
return copyAllSave("save:/", ".", false, dir);
}

void dumpToTitleUserDir(FsSaveDataInfo info) {
char exportDir[0x100];
sprintf(exportDir, "%s%016lx/", EXPORT_DIR, info.titleID);
mkdir(exportDir, 0700);
sprintf(exportDir, "%s%016lx/%lx%lx/",
EXPORT_DIR, info.titleID, (u64)(info.userID>>64), (u64)info.userID);
mkdir(exportDir, 0700);
dumpAllTo(exportDir);
}

int inject() {
return copyAllSave("save:/", ".", true, NULL);
}

Result getTitleName(u64 titleID, char * name) {
Result rc=0;

Expand Down Expand Up @@ -239,31 +280,58 @@ Result getUserNameById(u128 userID, char * username) {
}

int selectSaveFromList(int & selection, int change,
std::vector<FsSaveDataInfo> & saveInfoList, FsSaveDataInfo & info) {
std::vector<FsSaveDataInfo> & saveInfoList, FsSaveDataInfo & info, bool printName) {

selection += change;
change %= saveInfoList.size();
if (selection < 0) {
selection += saveInfoList.size();
selection = abs(selection) % saveInfoList.size();
selection = saveInfoList.size() - selection;
} else if (selection > 0
&& static_cast<unsigned int>(selection) >= saveInfoList.size()) {
selection -= saveInfoList.size();
selection %= saveInfoList.size();
}

info = saveInfoList.at(selection);
char name[0x201];
getTitleName(info.titleID, name);
char username[0x21];
getUserNameById(info.userID, username);
printf("\r ");
gfxFlushBuffers();
gfxSwapBuffers();
gfxWaitForVsync();
printf("\rSelected: %s \t User: %s", name, username);
if (printName){
char name[0x201];
getTitleName(info.titleID, name);
char username[0x21];
getUserNameById(info.userID, username);
printf("\rSelected: %s \t User: %s", name, username);
} else {
printf("\rSelected titleID: 0x%016lx userID: 0x%lx%lx",
info.titleID, (u64)(info.userID>>64), (u64)info.userID);
}

return selection;
}

bool userConfirm(const char * msg) {
printf("\n%s\nPress A to confirm, any other button to cancel\n", msg);

u64 kDownPrevious = hidKeysDown(CONTROLLER_P1_AUTO);
while(appletMainLoop())
{
hidScanInput();
u64 kDown = hidKeysDown(CONTROLLER_P1_AUTO);

if(kDown > kDownPrevious) {
if (kDown & KEY_A)
return true;
else {
printf("Canceled\n");
return false;
}
}

kDownPrevious = kDown;
}
return false;
}

int main(int argc, char **argv)
{
Expand All @@ -275,18 +343,28 @@ int main(int argc, char **argv)

std::vector<FsSaveDataInfo> saveInfoList;

mkdir(EXPORT_DIR, 0700);
mkdir(INJECT_DIR, 0700);

if (R_FAILED(getSaveList(saveInfoList))) {
printf("Failed to get save list 0x%x\n", rc);
}

printf("Y'allAreNUTs v0.1\n");
printf("Press A to dump save to 'save/'; Press X to inject contents from 'inject/'\n");
printf("Press UP and DOWN to select a save; Press PLUS to quit\n\n");
printf("Y'allAreNUTs v0.1.1\n"
"Press UP and DOWN to select a save\n"
"Press LEFT and RIGHT to skip 5 saves\n"
"Press A to dump save to 'save/'\n"
"Press Y to dump save to 'save/{titleID}/{userID}/'\n"
"Press ZR to dump all of your saves\n"
"Press X to inject contents from 'inject/'\n"
"Press R to toggle title ID (for manual look up) if it's garbled text\n"
"Press PLUS to quit\n\n");

// Main loop
int selection = -1;
int selection = 0;
FsSaveDataInfo info;
selectSaveFromList(selection, 1, saveInfoList, info);
bool printName = true;
selectSaveFromList(selection, 0, saveInfoList, info, printName);
while(appletMainLoop())
{
//Scan all the inputs. This should be done once for each frame
Expand All @@ -296,33 +374,61 @@ int main(int argc, char **argv)
u64 kDown = hidKeysDown(CONTROLLER_P1_AUTO);

if (kDown & KEY_UP) {
selectSaveFromList(selection, -1, saveInfoList, info);
selectSaveFromList(selection, -1, saveInfoList, info, printName);
}

if (kDown & KEY_DOWN) {
selectSaveFromList(selection, 1, saveInfoList, info);
selectSaveFromList(selection, 1, saveInfoList, info, printName);
}

if (kDown & KEY_LEFT) {
selectSaveFromList(selection, -5, saveInfoList, info, printName);
}

if (kDown & KEY_RIGHT) {
selectSaveFromList(selection, 5, saveInfoList, info, printName);
}

if (kDown & KEY_R) {
printName = !printName;
selectSaveFromList(selection, 0, saveInfoList, info, printName);
}

if (kDown & KEY_A) {
mountSaveByTitleAndUser(info.titleID, info.userID);
mkdir(EXPORT_DIR, 0700);
copyAllSave("save:/", ".", false);
mountSaveBySaveDataInfo(info, SAVE_DEV);
dumpAll();
fsdevUnmountDevice(SAVE_DEV);
printf("Dump over.\n\n");
}

if (kDown & KEY_Y) {
mountSaveBySaveDataInfo(info, SAVE_DEV);
dumpToTitleUserDir(info);
fsdevUnmountDevice(SAVE_DEV);
printf("Dump over.\n\n");
fsdevUnmountDevice("save");
}

if (kDown & KEY_ZR) {
if (userConfirm("Dump all saves? This may take a while.")) {
for(u32 i = 0; i < saveInfoList.size(); i++) {
info = saveInfoList.at(i);
mountSaveBySaveDataInfo(info, SAVE_DEV);
dumpToTitleUserDir(info);
fsdevUnmountDevice(SAVE_DEV);
}
printf("Dump over.\n\n");
}
}

if (kDown & KEY_X) {
mountSaveByTitleAndUser(info.titleID, info.userID);
if( copyAllSave("save:/", ".", true) == 0 ) {
rc = fsdevCommitDevice("save");
if (R_SUCCEEDED(rc)) {
printf("Changes committed.\n\n");
} else {
printf("fsdevCommitDevice() failed: %x\n", rc);
printf("Try injecting less data maybe?\n\n");
if (userConfirm("Inject data from 'inject/'?")) {
mountSaveBySaveDataInfo(info, SAVE_DEV);
if( inject() == 0 ) {
printf("Inject over.\n\n");

}
fsdevUnmountDevice(SAVE_DEV);
}
fsdevUnmountDevice("save");
}

if (kDown & KEY_PLUS) {
Expand Down

0 comments on commit 5ec3aae

Please sign in to comment.