Advertisement
rajkosto

backupUser.js

Mar 25th, 2018
1,284
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. // backups all the files from the USER NAND partition to a folder on the sdcard
  2. // - by rajkosto 25.03.2018.
  3.  
  4. if (IFileSystem.prototype.CreateDir === undefined || IFileSystem.prototype.DeleteDir === undefined)
  5. {
  6.     throw new Error("Missing IFileSystem functions, update your PegaSwitch from git!")
  7. }
  8.  
  9. if (IFile.prototype.SetSize === undefined)
  10. {
  11.     throw new Error("Missing IFile functions, update your PegaSwitch from git!")
  12. }
  13.  
  14. IFile.prototype.ReadPart = function (offset, size, buf) {
  15.     if(size instanceof ArrayBuffer || ArrayBuffer.isView(size)) {
  16.         buf = size;
  17.         size = buf.byteLength;
  18.     }
  19.     var ipcRes = this.sc.ipcMsg(0).datau64(0, offset, size).bDescriptor(buf, size, 1).sendTo(this.handle);
  20.     var bytes_read = [ipcRes.data[0], ipcRes.data[1]];
  21.     return ipcRes.asResult().replaceValue(bytes_read);
  22. };
  23.  
  24. sc.getFSPPR = function () {
  25.     if (sc.closed_pr !== undefined) {
  26.         return;
  27.     }
  28.     sc.enableTurbo();
  29.     var i = 0;
  30.     var srv = null;
  31.     while (true) {
  32.         sc.ipcMsg(2).setType(5).sendTo('pm:shell');
  33.         var srvResult = sc.getService("fsp-pr");
  34.         if(srvResult.isOk) {
  35.             srv = srvResult.getValue();
  36.             break;
  37.         }
  38.         i++;
  39.     }
  40.     utils.log('Got fsp-pr handle after ' + i + ' iterations: ');
  41.     utils.log('fsp-pr handle: 0x' + srv.toString(16));
  42.     sc.svcCloseHandle(srv).assertOk();
  43.     sc.closed_pr = true;
  44. };
  45.  
  46. sc.getFSPPR();
  47. sc.enableTurbo();
  48.  
  49. if(sc.pr_handle) {
  50.     sc.svcCloseHandle(sc.pr_handle);
  51.     sc.pr_handle = undefined;
  52. }
  53.  
  54. sc.getService("fsp-pr", (fsppr) => {
  55.     var pid = sc.getService('fsp-srv', (tmp_hnd) => {
  56.         utils.log("got fspsrv handle: 0x" + tmp_hnd.toString(16));
  57.         sc.ipcMsg(1).sendPid().data(0).sendTo(tmp_hnd).assertOk();
  58.         return sc.read4(sc.ipcBufAddr, 0xC >> 2);
  59.     });
  60.     utils.log('Got process PID: '+pid.toString(16));
  61.    
  62.     var buf1_sz = 0x1C;
  63.     var buf2_sz = 0x2C;
  64.     var buf = sc.malloc(buf1_sz + buf2_sz);
  65.     var buf2 = utils.add2(buf, buf1_sz);
  66.    
  67.     // buffer init
  68.     sc.write4(1, buf, 0x0>>2);
  69.     sc.write8([0xFFFFFFFF, 0xFFFFFFFF], buf, 0x4 >> 2); // This is the permissions value.
  70.     sc.write4(buf1_sz, buf, 0xC >> 2);
  71.     sc.write4(buf1_sz, buf, 0x14 >> 2);
  72.    
  73.     sc.write4(1, buf2, 0x0 >> 2);
  74.     sc.write8([0xFFFFFFFF, 0xFFFFFFFF], buf2, 0x4 >> 2); // This is the permissions value -- actual perms = buf2_val & buf1_val
  75.     sc.write4(0xFFFFFFFF, buf2, 0x14 >> 2);
  76.     sc.write4(0xFFFFFFFF, buf2, 0x18 >> 2);
  77.     sc.write4(0xFFFFFFFF, buf2, 0x24 >> 2);
  78.     sc.write4(0xFFFFFFFF, buf2, 0x28 >> 2);
  79.    
  80.     /* Change to mount a particular title's romfs */
  81.     var tid = '0000000000000000';
  82.    
  83.     sc.ipcMsg(256).data(0).sendTo(fsppr).assertOk().show();
  84.     sc.ipcMsg(1).data(pid).sendTo(fsppr).assertOk().show();
  85.     sc.ipcMsg(0).data(2, [pid,0], utils.parseAddr(tid), buf1_sz, buf2_sz, pid, pid, 0, 0, 0, 0, 0).aDescriptor(buf, buf1_sz).aDescriptor(buf2, buf2_sz).sendTo(fsppr).assertOk().show();
  86.     sc.free(buf);
  87.     sc.free(buf2);
  88. });
  89.  
  90. foreachDirEntry = function(dir_obj, callback)
  91. {
  92.     var entryCount = utils.trunc32(dir_obj.GetEntryCount().assertOk());
  93.     if (entryCount > 0 && callback !== undefined)
  94.     {
  95.         var entryBuf = new Uint32Array(0x310 * entryCount);
  96.         dir_obj.GetEntries(entryBuf, entryCount).assertOk();
  97.         for (var entryIdx = 0; entryIdx < entryCount; entryIdx++)
  98.         {
  99.             var fn = utils.u8a2str(new Uint8Array(entryBuf.buffer, 0x310 * entryIdx, 0x300));
  100.             for (var strIdx=0; strIdx<fn.length; strIdx++)
  101.             {
  102.                 if (fn.charCodeAt(strIdx) === 0)
  103.                 {
  104.                     fn = fn.substring(0, strIdx);
  105.                     break;
  106.                 }
  107.             }
  108.             var eType = entryBuf[(0x310 * entryIdx + 0x304) >> 2];         
  109.             callback(fn, eType);
  110.         }
  111.     }
  112.    
  113.     return entryCount;
  114. };
  115.  
  116. copyFiles = function(src_dir, dst_dir)
  117. {
  118.     var thefiles = [];
  119.     foreachDirEntry(src_dir, function(fn, eType)
  120.     {
  121.         if (eType === 1) { thefiles.push(fn); }
  122.     });
  123.     //dont need handle to dst_dir anymore (and it will interfere with Commit ops)
  124.     var dst_dir_fs = dst_dir.fs;
  125.     var dst_dir_path = dst_dir.path;
  126.     dst_dir.Close(); dst_dir = null;
  127.  
  128.     var CHUNK_SIZE = 1024*1024;
  129.     var buf = new ArrayBuffer(CHUNK_SIZE);
  130.     for (var fileIdx=0; fileIdx<thefiles.length; fileIdx++)
  131.     {
  132.         var fn = thefiles[fileIdx];
  133.         utils.log('[Opening existing file] ' + src_dir.path + fn);
  134.         var f_src = src_dir.fs.OpenFile(src_dir.path + fn).assertOk();
  135.         var size = f_src.GetSize().assertOk();
  136.         utils.log('[Source file size] ' + src_dir.path + fn + ' = ' + size + ' bytes');
  137.  
  138.         var f_dst = null;
  139.         try
  140.         {
  141.             //try open existing destination file
  142.             f_dst = dst_dir_fs.OpenFile(dst_dir_path + fn);
  143.             if (f_dst.isOk) //file exists, so lets just resize it to target size
  144.             {
  145.                 f_dst = f_dst.assertOk();
  146.                 var dst_size = f_dst.GetSize().assertOk();
  147.                 if (!utils.eq(dst_size, size))
  148.                 {
  149.                     utils.log('[Resizing existing file] ' + dst_dir_path + fn + ' ' + dst_size + ' -> ' + size);
  150.                     f_dst.SetSize(dst_size).assertOk();
  151.                     var new_size = f_dst.GetSize().assertOk();
  152.                     utils.log('[Resize complete] ' + dst_dir_path + fn + ' now ' + new_size);
  153.                 }                
  154.             }
  155.             else
  156.             {
  157.                 utils.log('[Creating new file] ' + dst_dir_path + fn + ' with size ' + size + ' bytes');
  158.                 dst_dir_fs.CreateFile(dst_dir_path + fn, size).assertOk();
  159.                 utils.log('[Opening new file] ' + dst_dir_path + fn);          
  160.                 f_dst = dst_dir_fs.OpenFile(dst_dir_path + fn).assertOk();
  161.             }            
  162.             utils.log('[Open dst file OK] ' + dst_dir_path + fn);
  163.             var doneBytes = [0, 0];
  164.             for (var totalSize = size; !utils.eq(doneBytes, totalSize); )
  165.             {
  166.                 var currBlockSize = totalSize;
  167.                 if (!utils.nullptr(doneBytes)) { currBlockSize = utils.sub2(totalSize, doneBytes); }
  168.                 if ((currBlockSize[1] != 0) || (currBlockSize[0] > CHUNK_SIZE)) { currBlockSize = CHUNK_SIZE; }
  169.                 else { currBlockSize = utils.trunc32(currBlockSize); }
  170.                
  171.                 var read_bytes = f_src.ReadPart(doneBytes, currBlockSize, buf).assertOk();
  172.                 utils.log('[Read bytes] ' + '@' + doneBytes + ' (' + currBlockSize + ') returned ' + read_bytes );
  173.                 /*if ((read_bytes[1] != 0) || (read_bytes[0] != currBlockSize))
  174.                 {
  175.                     throw new Error("Read mismatch, wanted " + currBlockSize + " bytes, got " + read_bytes + " bytes");
  176.                 }*/
  177.  
  178.                 var sizeAfterWrite = utils.add2(doneBytes, read_bytes);
  179.                 f_dst.Write(doneBytes, buf, read_bytes).assertOk();
  180.                 utils.log('[Wrote bytes] ' + '@' + doneBytes + ' + ' + read_bytes);
  181.                 doneBytes = sizeAfterWrite;
  182.             }
  183.             utils.log('[Write file Complete] ' + dst_dir_path + fn + ' -> ' + doneBytes + ' bytes');
  184.             f_dst.Close(); f_dst = null;
  185.             utils.log('[Close file OK] ' + dst_dir_path + fn);
  186.         }
  187.         finally
  188.         {
  189.             if (f_dst !== null && f_dst instanceof IFile) { f_dst.Close(); f_dst = null; }
  190.             if (f_src !== null) { f_src.Close(); f_src = null; }
  191.         }
  192.     }
  193.  
  194.     return dst_dir;
  195. };
  196.  
  197. evaluateDirs = function(fs_obj, root_dir)
  198. {
  199.     var folders = [];
  200.    
  201.     var dir_obj = fs_obj.OpenDir(root_dir, 1); //directories only
  202.     if (!dir_obj.isOk) { return folders; } //no dirs
  203.     else { dir_obj = dir_obj.assertOk(); }
  204.    
  205.     folders.push(dir_obj.path); //this dir
  206.     for (var evalIdx=0; evalIdx<folders.length; evalIdx++)
  207.     {
  208.         if (evalIdx !== 0)
  209.         {
  210.             dir_obj = fs_obj.OpenDir(folders[evalIdx], 1);
  211.             if (!dir_obj.isOk) { throw new Error('Unable to open dir ' + folders[evalIdx] + ' for listing'); }         
  212.             else { dir_obj = dir_obj.assertOk(); }
  213.         }
  214.  
  215.         foreachDirEntry(dir_obj, function(fn) { folders.push(dir_obj.path + fn + '/'); });
  216.         dir_obj.Close(); dir_obj = null;
  217.     }
  218.  
  219.     return folders;
  220. };
  221.  
  222. clearOutFolder = function(fs_obj, start_dir_path)
  223. {
  224.     utils.log('[Opening existing dir for listing] ' + start_dir_path + ' on ' + fs_obj.partition);
  225.     var start_dir = fs_obj.OpenDir(start_dir_path, 1).assertOk(); //directories only
  226.     var listEntries = [];
  227.     foreachDirEntry(start_dir, function(fn) { listEntries.push(start_dir.path + fn + '/'); });
  228.     start_dir.Close(); start_dir = null;
  229.     for (var saveDirIdx=0; saveDirIdx<listEntries.length; saveDirIdx++)
  230.     {
  231.         var currDirPath = listEntries[saveDirIdx];
  232.         utils.log('[Deleting existing dir] ' + currDirPath + ' on ' + fs_obj.partition);
  233.         fs_obj.DeleteDir(currDirPath, true).assertOk();
  234.         utils.log('[Existing dir deleted] ' + currDirPath  + ' on ' + fs_obj.partition);
  235.     }
  236.     start_dir = fs_obj.OpenDir(start_dir_path, 2).assertOk(); //files only
  237.     listEntries = [];
  238.     foreachDirEntry(start_dir, function(fn) { listEntries.push(start_dir.path + fn); });
  239.     start_dir.Close(); start_dir = null;
  240.     for (var saveFnIdx=0; saveFnIdx<listEntries.length; saveFnIdx++)
  241.     {
  242.         var currFilePath = listEntries[saveFnIdx];
  243.         utils.log('[Deleting existing file] ' + currFilePath + ' on ' + fs_obj.partition);
  244.         fs_obj.DeleteFile(currFilePath).assertOk();
  245.         utils.log('[Existing file deleted] ' + currFilePath + ' on ' + fs_obj.partition);
  246.     }
  247.     listEntries = [];
  248. };
  249.  
  250. makeOrClearFolder = function(fs_obj, start_dir_path)
  251. {
  252.     var res = fs_obj.CreateDir(start_dir_path);
  253.     if (res.isOk)
  254.     {
  255.         utils.log('[Created new dir] ' + start_dir_path + ' on ' + fs_obj.partition);
  256.     }
  257.     else
  258.     {
  259.         clearOutFolder(fs_obj, start_dir_path);
  260.         utils.log('[Using existing dir] ' + start_dir_path + ' on ' + fs_obj.partition);
  261.     }
  262. };
  263.  
  264. sc.getService('fsp-srv', (fsp_handle) => {
  265.     utils.log('initialized fsp-srv handle: 0x' + fsp_handle.toString(16));
  266.     sc.ipcMsg(1).sendPid().datau64(0).sendTo(fsp_handle).assertOk();
  267.  
  268.     mountSDCard = function () {
  269.         var self = this;
  270.         return sc.ipcMsg(18).sendTo(fsp_handle).asResult()
  271.             .map((r) => new self.sc.IFileSystem(self.sc, r.movedHandles[0]));
  272.     };
  273.    
  274.     mountBisFatPart = function (partId) {
  275.         var pbuf = new ArrayBuffer(1); //just a null terminator
  276.         var self = this;
  277.         return sc.ipcMsg(11).datau32(partId).xDescriptor(pbuf, pbuf.byteLength, 0).sendTo(fsp_handle).asResult()
  278.             .map((r) => new self.sc.IFileSystem(self.sc, r.movedHandles[0]));
  279.     };
  280.  
  281.     var fs_sd = null;
  282.     var fs_user = null;
  283.  
  284.     try {
  285.         utils.log("Mounting SD card");
  286.         try { fs_sd = mountSDCard().assertOk(); }
  287.         catch(e) { throw new Error("Failed to open SD card. Is it inserted?"); }
  288.         fs_sd.partition = "SDCARD";
  289.         utils.log('SDCARD handle = 0x' + fs_sd.handle.toString(16));
  290.        
  291.         utils.log("Mounting USER partition");
  292.         try { fs_user = mountBisFatPart(30).assertOk(); }
  293.         catch(e) { throw new Error("Failed to mount USER partition"); }
  294.         fs_user.partition = "USER";
  295.         utils.log('USER handle = 0x' + fs_user.handle.toString());
  296.  
  297.         utils.log('[Listing folders in USER part]');
  298.         var dirList = evaluateDirs(fs_user, '/');
  299.         if (dirList.length < 1)
  300.         {
  301.             throw new Error("Unable to list USER partition dirs");
  302.         }
  303.         utils.log(dirList.length + ' folders found on USER part');
  304.  
  305.         var date = new Date();
  306.         var sdFolderName = "/user-" + date.getFullYear() + "-" + (date.getMonth()+1) + "-" + date.getDate()
  307.                             + "-" + date.getHours() + "-" + date.getMinutes() +'/';
  308.         makeOrClearFolder(fs_sd, sdFolderName);
  309.         sdFolderName = sdFolderName.substr(0, sdFolderName.length-1);
  310.  
  311.         for (var dirIndex = 0; dirIndex < dirList.length; dirIndex++)
  312.         {
  313.             var left_side = dirList[dirIndex];
  314.             var right_side = sdFolderName + dirList[dirIndex];
  315.            
  316.             utils.log('[Opening folder on USER] '+ left_side);
  317.             var dir_user = fs_user.OpenDir(left_side, 2).assertOk();
  318.             utils.log('[Opening folder on SD] '+ right_side);
  319.             var dir_sd = fs_sd.OpenDir(right_side, 2);
  320.             if (!dir_sd.isOk)
  321.             {
  322.                 utils.log('[Making folder on SD] '+ right_side);
  323.                 fs_sd.CreateDir(right_side).assertOk();
  324.                 utils.log('[Opening newly made folder] ' + right_side);            
  325.                 dir_sd = fs_sd.OpenDir(right_side, 2).assertOk();
  326.                 utils.log('[New folder opened OK] '+ right_side);
  327.             }
  328.             else
  329.             {
  330.                 dir_sd = dir_sd.assertOk();
  331.                 utils.log('[Existing folder opened OK] '+ right_side);
  332.             }
  333.    
  334.             try
  335.             {
  336.                 dir_sd = copyFiles(dir_user, dir_sd); //because we might change dst_dir inside
  337.             }
  338.             finally
  339.             {
  340.                 if (dir_user !== null) { dir_user.Close(); dir_user = null; }
  341.                 if (dir_sd !== null) { dir_sd.Close(); dir_sd = null; }
  342.             }
  343.         }
  344.        
  345.         utils.log('[Closing file systems]');
  346.     }
  347.     finally
  348.     {
  349.         if (fs_user !== null) { fs_user.Close(); fs_user = null; }
  350.         if (fs_sd !== null) { fs_sd.Close(); fs_sd = null; }
  351.     }
  352. });
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement