Advertisement
rajkosto

rewritten savedata restore from sdcard folder script - rajko

Mar 23rd, 2018
3,294
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. /*
  2. *   0. Make sure your savefiles are in the correct layout under sdcard:/Saves/YOUR_GAME_TID_HERE/
  3. *   1. Boot game
  4. *   2. Wait a  second or so (for the game tid to register but before the code mounts the savedata)
  5. *   3. Home button to pause game
  6. *   4. Run this script
  7. *   5. Look at debug log output to see if it restored everything correctly and then commited
  8. */
  9.  
  10. var tid = '0000000000000000'; //Change Title ID here
  11. 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)
  12.  
  13. if (IFileSystem.prototype.OpenDir === undefined || IFileSystem.prototype.CreateDir === undefined || IFileSystem.prototype.DeleteDir === undefined ||
  14.     IFileSystem.prototype.DeleteDir === undefined || IFileSystem.prototype.Commit === undefined)
  15. {
  16.     throw new Error("Missing IFileSystem functions, please update your PegaSwitch from git!");
  17. }
  18.  
  19. IFile.prototype.SetSize = function (size) {
  20.     return this.sc.ipcMsg(3).datau64(size).sendTo(this.handle).asResult();
  21. };
  22.  
  23. foreachDirEntry = function(dir_obj, callback)
  24. {
  25.     var entryCount = utils.trunc32(dir_obj.GetEntryCount().assertOk());
  26.     if (entryCount > 0 && callback !== undefined)
  27.     {
  28.         var entryBuf = new Uint32Array(0x310 * entryCount);
  29.         dir_obj.GetEntries(entryBuf, entryCount).assertOk();
  30.         for (var entryIdx = 0; entryIdx < entryCount; entryIdx++)
  31.         {
  32.             var fn = utils.u8a2str(new Uint8Array(entryBuf.buffer, 0x310 * entryIdx, 0x300));
  33.             for (var strIdx=0; strIdx<fn.length; strIdx++)
  34.             {
  35.                 if (fn.charCodeAt(strIdx) === 0)
  36.                 {
  37.                     fn = fn.substring(0, strIdx);
  38.                     break;
  39.                 }
  40.             }
  41.             var eType = entryBuf[(0x310 * entryIdx + 0x304) >> 2];         
  42.             callback(fn, eType);
  43.         }
  44.     }
  45.    
  46.     return entryCount;
  47. };
  48.  
  49. copyFiles = function(src_dir, dst_dir)
  50. {
  51.     var thefiles = [];
  52.     foreachDirEntry(src_dir, function(fn, eType)
  53.     {
  54.         if (eType === 1) { thefiles.push(fn); }
  55.     });
  56.     //dont need handle to dst_dir anymore (and it will interfere with Commit ops)
  57.     var dst_dir_fs = dst_dir.fs;
  58.     var dst_dir_path = dst_dir.path;
  59.     dst_dir.Close(); dst_dir = null;
  60.  
  61.     var size = [];
  62.     var buf = null;
  63.     for (var fileIdx=0; fileIdx<thefiles.length; fileIdx++)
  64.     {
  65.         var fn = thefiles[fileIdx];
  66.         utils.log('[Opening existing file] ' + src_dir.path + fn);
  67.         var f_src = src_dir.fs.OpenFile(src_dir.path + fn).assertOk();
  68.         var f_dst = null;
  69.         try
  70.         {
  71.             size = f_src.GetSize().assertOk();
  72.             buf = f_src.Read(new ArrayBuffer(utils.trunc32(size)), 0, size).assertOk();
  73.             f_src.Close(); f_src = null;
  74.  
  75.             utils.log('[Read file complete] ' + src_dir.path + fn + ' = ' + size + ' bytes');
  76.             //try open existing file
  77.             f_dst = dst_dir_fs.OpenFile(dst_dir_path + fn);
  78.             if (f_dst.isOk) //file exists, must be deleted
  79.             {
  80.                 f_dst = f_dst.assertOk();
  81.                 f_dst.Close(); f_dst = null;
  82.  
  83.                 utils.log('[Deleting existing file] ' + dst_dir_path + fn);
  84.                 dst_dir_fs.DeleteFile(dst_dir_path + fn).assertOk();
  85.             }
  86.  
  87.             utils.log('[Creating new file] ' + dst_dir_path + fn + ' with size ' + size + ' bytes');
  88.             dst_dir_fs.CreateFile(dst_dir_path + fn, size).assertOk();
  89.             utils.log('[Opening new file] ' + dst_dir_path + fn);          
  90.             f_dst = dst_dir_fs.OpenFile(dst_dir_path + fn).assertOk();
  91.             utils.log('[Open file OK] ' + dst_dir_path + fn);  
  92.             f_dst.Write(0, buf, size).assertOk();
  93.             utils.log('[Write file OK] ' + dst_dir_path + fn + ' -> ' + size + ' bytes');
  94.             buf = null;
  95.             f_dst.Close(); f_dst = null;
  96.             utils.log('[Close file OK] ' + dst_dir_path + fn);
  97.             if (commitAfterEveryFile)
  98.             {
  99.                 utils.log('[Commiting to fs ' + dst_dir_fs.partition + ' handle ' + dst_dir_fs.handle + '] ' + dst_dir_path + fn);             
  100.                 dst_dir_fs.Commit().assertOk();
  101.                 utils.log('[Commit OK] ' + dst_dir_path + fn);
  102.             }
  103.         }
  104.         finally
  105.         {
  106.             if (f_dst !== null && f_dst instanceof IFile) { f_dst.Close(); f_dst = null; }
  107.             if (f_src !== null) { f_src.Close(); f_src = null; }
  108.         }
  109.     }
  110.  
  111.     return dst_dir;
  112. };
  113.  
  114. evaluateDirs = function(fs_obj, root_dir)
  115. {
  116.     var folders = [];
  117.    
  118.     var dir_obj = fs_obj.OpenDir(root_dir, 1); //directories only
  119.     if (!dir_obj.isOk) { return folders; } //no dirs
  120.     else { dir_obj = dir_obj.assertOk(); }
  121.    
  122.     folders.push(dir_obj.path); //this dir
  123.     for (var evalIdx=0; evalIdx<folders.length; evalIdx++)
  124.     {
  125.         if (evalIdx !== 0)
  126.         {
  127.             dir_obj = fs_obj.OpenDir(folders[evalIdx], 1);
  128.             if (!dir_obj.isOk) { throw new Error('Unable to open dir ' + folders[evalIdx] + ' for listing'); }         
  129.             else { dir_obj = dir_obj.assertOk(); }
  130.         }
  131.  
  132.         foreachDirEntry(dir_obj, function(fn) { folders.push(dir_obj.path + fn + '/'); });
  133.         dir_obj.Close(); dir_obj = null;
  134.     }
  135.  
  136.     return folders;
  137. };
  138.  
  139. utils.log("stage1, hijack fsppr and set perms");
  140. if (SploitCore.prototype.escalateFilesystemPrivileges === undefined)
  141. {
  142.     throw new Error("Missing escalateFilesystemPrivileges function, please update your PegaSwitch from git!");
  143. }
  144. sc.escalateFilesystemPrivileges();
  145.  
  146. utils.log("GetLastUserProfile");
  147. var userID = sc.ipcMsg(4).sendTo('acc:u1').assertOk().data;
  148.  
  149. sc.getService('fsp-srv', (fsp_handle) =>
  150. {
  151.     utils.log('initialized fsp-srv handle: 0x' + fsp_handle.toString(16));
  152.     sc.ipcMsg(1).sendPid().datau64(0).sendTo(fsp_handle).assertOk();
  153.  
  154.     utils.log("stage2, open save data");
  155.     mountSaveData = function (userID, tid) {
  156.         var self = this;
  157.         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()
  158.             .map((r) => new self.sc.IFileSystem(self.sc, r.movedHandles[0]));
  159.     };
  160.    
  161.     mountSDCard = function () {
  162.         var self = this;
  163.         return sc.ipcMsg(18).sendTo(fsp_handle).asResult()
  164.             .map((r) => new self.sc.IFileSystem(self.sc, r.movedHandles[0]));
  165.     };
  166.  
  167.     utils.log('MountSaveData');
  168.     var fs_sd = null;
  169.     var fs_user = mountSaveData(userID, tid).assertOk();
  170.     fs_user.partition = "SAVEDATA";
  171.     utils.log('SAVEDATA handle is ' + fs_user.handle);
  172.    
  173.     try {
  174.         utils.log("Mounting SD card");
  175.         try { fs_sd = mountSDCard().assertOk(); }
  176.         catch(e) { throw new Error("Failed to open SD card. Is it inserted?"); }
  177.         fs_sd.partition = "SDCARD";
  178.         utils.log('SDCARD handle is ' + fs_sd.handle);
  179.    
  180.         var sd_folder_root = '/Saves/'+tid+'/';
  181.         utils.log('[Opening SD dir for listing] ' + sd_folder_root);
  182.         var dirList = evaluateDirs(fs_sd, sd_folder_root);
  183.         if (dirList.length < 1)
  184.         {
  185.             fs_sd.Close(); fs_sd = null;
  186.             fs_user.Close(); fs_user = null;
  187.             throw new Error("Unable to open SD saves dir " + sd_folder_root + ' or its empty');
  188.         }
  189.    
  190.         utils.log('[Opening SAVEDATA dir for listing]');
  191.         var save_root_dir = fs_user.OpenDir('/', 1).assertOk(); //directories only
  192.         var saveEntries = [];
  193.         foreachDirEntry(save_root_dir, function(fn) { saveEntries.push(save_root_dir.path + fn + '/'); });
  194.         save_root_dir.Close(); save_root_dir = null;
  195.         for (var saveDirIdx=0; saveDirIdx<saveEntries.length; saveDirIdx++)
  196.         {
  197.             var currSaveDir = saveEntries[saveDirIdx];
  198.             utils.log('[Deleting SAVEDATA dir] ' + currSaveDir)
  199.             fs_user.DeleteDir(currSaveDir, true).assertOk();
  200.             utils.log('[SAVEDATA dir deleted] ' + currSaveDir)
  201.         }
  202.         save_root_dir = fs_user.OpenDir('/', 2).assertOk(); //files only
  203.         saveEntries = [];
  204.         foreachDirEntry(save_root_dir, function(fn) { saveEntries.push(save_root_dir.path + fn); });
  205.         save_root_dir.Close(); save_root_dir = null;
  206.         for (var saveFnIdx=0; saveFnIdx<saveEntries.length; saveFnIdx++)
  207.         {
  208.             var currSaveFile = saveEntries[saveFnIdx];
  209.             utils.log('[Deleting SAVEDATA file] ' + currSaveFile)
  210.             fs_user.DeleteFile(currSaveFile).assertOk();
  211.             utils.log('[SAVEDATA file deleted] ' + currSaveFile)
  212.         }
  213.         saveEntries = [];
  214.    
  215.         for (var dirIndex = 0; dirIndex < dirList.length; dirIndex++)
  216.         {
  217.             var left_side = dirList[dirIndex];
  218.             var right_side = '/' + dirList[dirIndex].substring(sd_folder_root.length);
  219.    
  220.             utils.log('[Opening folder on SD] '+ left_side);
  221.             var dir_sd = fs_sd.OpenDir(left_side, 2).assertOk();
  222.             utils.log('[Opening folder in savedata] '+ right_side);
  223.             var dir_data = fs_user.OpenDir(right_side, 2);
  224.             if (!dir_data.isOk)
  225.             {
  226.                 utils.log('[Making folder in savedata] '+ right_side);
  227.                 fs_user.CreateDir(right_side).assertOk();
  228.                 utils.log('[Opening newly made folder] ' + right_side);            
  229.                 dir_data = fs_user.OpenDir(right_side, 2).assertOk();
  230.                 utils.log('[New folder opened OK] '+ right_side);
  231.             }
  232.             else
  233.             {
  234.                 dir_data = dir_data.assertOk();
  235.                 utils.log('[Existing folder opened OK] '+ right_side);
  236.             }
  237.    
  238.             try
  239.             {
  240.                 dir_data = copyFiles(dir_sd, dir_data); //because we might change dst_dir inside
  241.             }
  242.             finally
  243.             {
  244.                 if (dir_data !== null) { dir_data.Close(); dir_data = null; }
  245.                 if (dir_sd !== null) { dir_sd.Close(); dir_sd = null; }
  246.             }
  247.         }
  248.    
  249.         utils.log('[Commiting savedata changes]');
  250.         fs_user.Commit().assertOk();
  251.         utils.log('[Closing file systems]');
  252.         fs_user.Close(); fs_user = null;
  253.         fs_sd.Close(); fs_sd = null;
  254.     }
  255.     finally
  256.     {
  257.         if (fs_user !== null) { fs_user.Close(); fs_user = null; }
  258.         if (fs_sd !== null) { fs_sd.Close(); fs_sd = null; }
  259.     }  
  260. });
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement