Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- * 0. Make sure your savefiles are in the correct layout under sdcard:/Saves/YOUR_GAME_TID_HERE/
- * 1. Boot game
- * 2. Wait a second or so (for the game tid to register but before the code mounts the savedata)
- * 3. Home button to pause game
- * 4. Run this script
- * 5. Look at debug log output to see if it restored everything correctly and then commited
- */
- var tid = '0000000000000000'; //Change Title ID here
- var commitAfterEveryFile = false; //set this to true if you get strange errors after some amount of files written (needed for BotW and possibly other games which have lots of large save files)
- if (IFileSystem.prototype.OpenDir === undefined || IFileSystem.prototype.CreateDir === undefined || IFileSystem.prototype.DeleteDir === undefined ||
- IFileSystem.prototype.DeleteDir === undefined || IFileSystem.prototype.Commit === undefined)
- {
- throw new Error("Missing IFileSystem functions, please update your PegaSwitch from git!");
- }
- IFile.prototype.SetSize = function (size) {
- return this.sc.ipcMsg(3).datau64(size).sendTo(this.handle).asResult();
- };
- foreachDirEntry = function(dir_obj, callback)
- {
- var entryCount = utils.trunc32(dir_obj.GetEntryCount().assertOk());
- if (entryCount > 0 && callback !== undefined)
- {
- var entryBuf = new Uint32Array(0x310 * entryCount);
- dir_obj.GetEntries(entryBuf, entryCount).assertOk();
- for (var entryIdx = 0; entryIdx < entryCount; entryIdx++)
- {
- var fn = utils.u8a2str(new Uint8Array(entryBuf.buffer, 0x310 * entryIdx, 0x300));
- for (var strIdx=0; strIdx<fn.length; strIdx++)
- {
- if (fn.charCodeAt(strIdx) === 0)
- {
- fn = fn.substring(0, strIdx);
- break;
- }
- }
- var eType = entryBuf[(0x310 * entryIdx + 0x304) >> 2];
- callback(fn, eType);
- }
- }
- return entryCount;
- };
- copyFiles = function(src_dir, dst_dir)
- {
- var thefiles = [];
- foreachDirEntry(src_dir, function(fn, eType)
- {
- if (eType === 1) { thefiles.push(fn); }
- });
- //dont need handle to dst_dir anymore (and it will interfere with Commit ops)
- var dst_dir_fs = dst_dir.fs;
- var dst_dir_path = dst_dir.path;
- dst_dir.Close(); dst_dir = null;
- var size = [];
- var buf = null;
- for (var fileIdx=0; fileIdx<thefiles.length; fileIdx++)
- {
- var fn = thefiles[fileIdx];
- utils.log('[Opening existing file] ' + src_dir.path + fn);
- var f_src = src_dir.fs.OpenFile(src_dir.path + fn).assertOk();
- var f_dst = null;
- try
- {
- size = f_src.GetSize().assertOk();
- buf = f_src.Read(new ArrayBuffer(utils.trunc32(size)), 0, size).assertOk();
- f_src.Close(); f_src = null;
- utils.log('[Read file complete] ' + src_dir.path + fn + ' = ' + size + ' bytes');
- //try open existing file
- f_dst = dst_dir_fs.OpenFile(dst_dir_path + fn);
- if (f_dst.isOk) //file exists, must be deleted
- {
- f_dst = f_dst.assertOk();
- f_dst.Close(); f_dst = null;
- utils.log('[Deleting existing file] ' + dst_dir_path + fn);
- dst_dir_fs.DeleteFile(dst_dir_path + fn).assertOk();
- }
- utils.log('[Creating new file] ' + dst_dir_path + fn + ' with size ' + size + ' bytes');
- dst_dir_fs.CreateFile(dst_dir_path + fn, size).assertOk();
- utils.log('[Opening new file] ' + dst_dir_path + fn);
- f_dst = dst_dir_fs.OpenFile(dst_dir_path + fn).assertOk();
- utils.log('[Open file OK] ' + dst_dir_path + fn);
- f_dst.Write(0, buf, size).assertOk();
- utils.log('[Write file OK] ' + dst_dir_path + fn + ' -> ' + size + ' bytes');
- buf = null;
- f_dst.Close(); f_dst = null;
- utils.log('[Close file OK] ' + dst_dir_path + fn);
- if (commitAfterEveryFile)
- {
- utils.log('[Commiting to fs ' + dst_dir_fs.partition + ' handle ' + dst_dir_fs.handle + '] ' + dst_dir_path + fn);
- dst_dir_fs.Commit().assertOk();
- utils.log('[Commit OK] ' + dst_dir_path + fn);
- }
- }
- finally
- {
- if (f_dst !== null && f_dst instanceof IFile) { f_dst.Close(); f_dst = null; }
- if (f_src !== null) { f_src.Close(); f_src = null; }
- }
- }
- return dst_dir;
- };
- evaluateDirs = function(fs_obj, root_dir)
- {
- var folders = [];
- var dir_obj = fs_obj.OpenDir(root_dir, 1); //directories only
- if (!dir_obj.isOk) { return folders; } //no dirs
- else { dir_obj = dir_obj.assertOk(); }
- folders.push(dir_obj.path); //this dir
- for (var evalIdx=0; evalIdx<folders.length; evalIdx++)
- {
- if (evalIdx !== 0)
- {
- dir_obj = fs_obj.OpenDir(folders[evalIdx], 1);
- if (!dir_obj.isOk) { throw new Error('Unable to open dir ' + folders[evalIdx] + ' for listing'); }
- else { dir_obj = dir_obj.assertOk(); }
- }
- foreachDirEntry(dir_obj, function(fn) { folders.push(dir_obj.path + fn + '/'); });
- dir_obj.Close(); dir_obj = null;
- }
- return folders;
- };
- utils.log("stage1, hijack fsppr and set perms");
- if (SploitCore.prototype.escalateFilesystemPrivileges === undefined)
- {
- throw new Error("Missing escalateFilesystemPrivileges function, please update your PegaSwitch from git!");
- }
- sc.escalateFilesystemPrivileges();
- utils.log("GetLastUserProfile");
- var userID = sc.ipcMsg(4).sendTo('acc:u1').assertOk().data;
- sc.getService('fsp-srv', (fsp_handle) =>
- {
- utils.log('initialized fsp-srv handle: 0x' + fsp_handle.toString(16));
- sc.ipcMsg(1).sendPid().datau64(0).sendTo(fsp_handle).assertOk();
- utils.log("stage2, open save data");
- mountSaveData = function (userID, tid) {
- var self = this;
- return sc.ipcMsg(51).datau64(1, utils.parseAddr(tid), [userID[0], userID[1]], [userID[2], userID[3]], [0,0], 1, 0, 0, 0).sendTo(fsp_handle).asResult()
- .map((r) => new self.sc.IFileSystem(self.sc, r.movedHandles[0]));
- };
- mountSDCard = function () {
- var self = this;
- return sc.ipcMsg(18).sendTo(fsp_handle).asResult()
- .map((r) => new self.sc.IFileSystem(self.sc, r.movedHandles[0]));
- };
- utils.log('MountSaveData');
- var fs_sd = null;
- var fs_user = mountSaveData(userID, tid).assertOk();
- fs_user.partition = "SAVEDATA";
- utils.log('SAVEDATA handle is ' + fs_user.handle);
- try {
- utils.log("Mounting SD card");
- try { fs_sd = mountSDCard().assertOk(); }
- catch(e) { throw new Error("Failed to open SD card. Is it inserted?"); }
- fs_sd.partition = "SDCARD";
- utils.log('SDCARD handle is ' + fs_sd.handle);
- var sd_folder_root = '/Saves/'+tid+'/';
- utils.log('[Opening SD dir for listing] ' + sd_folder_root);
- var dirList = evaluateDirs(fs_sd, sd_folder_root);
- if (dirList.length < 1)
- {
- fs_sd.Close(); fs_sd = null;
- fs_user.Close(); fs_user = null;
- throw new Error("Unable to open SD saves dir " + sd_folder_root + ' or its empty');
- }
- utils.log('[Opening SAVEDATA dir for listing]');
- var save_root_dir = fs_user.OpenDir('/', 1).assertOk(); //directories only
- var saveEntries = [];
- foreachDirEntry(save_root_dir, function(fn) { saveEntries.push(save_root_dir.path + fn + '/'); });
- save_root_dir.Close(); save_root_dir = null;
- for (var saveDirIdx=0; saveDirIdx<saveEntries.length; saveDirIdx++)
- {
- var currSaveDir = saveEntries[saveDirIdx];
- utils.log('[Deleting SAVEDATA dir] ' + currSaveDir)
- fs_user.DeleteDir(currSaveDir, true).assertOk();
- utils.log('[SAVEDATA dir deleted] ' + currSaveDir)
- }
- save_root_dir = fs_user.OpenDir('/', 2).assertOk(); //files only
- saveEntries = [];
- foreachDirEntry(save_root_dir, function(fn) { saveEntries.push(save_root_dir.path + fn); });
- save_root_dir.Close(); save_root_dir = null;
- for (var saveFnIdx=0; saveFnIdx<saveEntries.length; saveFnIdx++)
- {
- var currSaveFile = saveEntries[saveFnIdx];
- utils.log('[Deleting SAVEDATA file] ' + currSaveFile)
- fs_user.DeleteFile(currSaveFile).assertOk();
- utils.log('[SAVEDATA file deleted] ' + currSaveFile)
- }
- saveEntries = [];
- for (var dirIndex = 0; dirIndex < dirList.length; dirIndex++)
- {
- var left_side = dirList[dirIndex];
- var right_side = '/' + dirList[dirIndex].substring(sd_folder_root.length);
- utils.log('[Opening folder on SD] '+ left_side);
- var dir_sd = fs_sd.OpenDir(left_side, 2).assertOk();
- utils.log('[Opening folder in savedata] '+ right_side);
- var dir_data = fs_user.OpenDir(right_side, 2);
- if (!dir_data.isOk)
- {
- utils.log('[Making folder in savedata] '+ right_side);
- fs_user.CreateDir(right_side).assertOk();
- utils.log('[Opening newly made folder] ' + right_side);
- dir_data = fs_user.OpenDir(right_side, 2).assertOk();
- utils.log('[New folder opened OK] '+ right_side);
- }
- else
- {
- dir_data = dir_data.assertOk();
- utils.log('[Existing folder opened OK] '+ right_side);
- }
- try
- {
- dir_data = copyFiles(dir_sd, dir_data); //because we might change dst_dir inside
- }
- finally
- {
- if (dir_data !== null) { dir_data.Close(); dir_data = null; }
- if (dir_sd !== null) { dir_sd.Close(); dir_sd = null; }
- }
- }
- utils.log('[Commiting savedata changes]');
- fs_user.Commit().assertOk();
- utils.log('[Closing file systems]');
- fs_user.Close(); fs_user = null;
- fs_sd.Close(); fs_sd = null;
- }
- finally
- {
- if (fs_user !== null) { fs_user.Close(); fs_user = null; }
- if (fs_sd !== null) { fs_sd.Close(); fs_sd = null; }
- }
- });
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement