public byte[] FileRead(BbInode inode) { var data = new byte[inode.Size]; var chain = GetBlockChain(inode.BlockIdx); for (int i = 0; i < chain.Length; i++) { io.Stream.Position = chain[i] * BLOCK_SZ; int numRead = BLOCK_SZ; if (i + 1 == chain.Length) { numRead = (int)(inode.Size % BLOCK_SZ); } if (numRead == 0) { numRead = BLOCK_SZ; } var blockData = io.Reader.ReadBytes(numRead); Array.Copy(blockData, 0, data, i * BLOCK_SZ, numRead); } return(data); }
public void CreateModifiedInodes() { if (ModifiedInodes != null) { return; } ModifiedInodes = new List <BbInode>(); foreach (var node in MainFsInodes) { var newNode = new BbInode(); ModifiedInodes.Add(newNode.Copy(node)); } ModifiedAllocTable = new List <short>(); foreach (var alloc in MainFsAllocTable) { ModifiedAllocTable.Add(alloc); } var newSeqNo = MainFs.SeqNo + 1; MainFs = new BbFat16(); MainFs.Magic = MAGIC_BBFS; MainFs.SeqNo = newSeqNo; MainFs.Link = 0; MainFs.CheckSum = 0; FsHeaders.Add(MainFs); FsInodes.Add(ModifiedInodes); FsAllocationTables.Add(ModifiedAllocTable); MainFsIndex = FsHeaders.Count - 1; }
public bool FileDelete(string fileName) { BbInode foundNode = new BbInode(); bool found = false; foreach (var node in MainFsInodes) { if (node.NameString == fileName) { foundNode = node; found = true; } } if (!found) { return(false); } // make sure we have a modified inodes collection ready... CreateModifiedInodes(); // find node in modified inodes.. found = false; foreach (var node in ModifiedInodes) { if (node.NameString == fileName) { foundNode = node; found = true; } } if (!found) { return(false); } // deallocate all blocks used by the file var chain = GetBlockChain(foundNode.BlockIdx); foreach (var block in chain) { ModifiedAllocTable[block] = FAT_BLOCK_FREE; } // remove file from inode collection ModifiedInodes.Remove(foundNode); return(true); }
public bool FileWrite(string fileName, byte[] fileData, ref BbInode newNode) { newNode = new BbInode(); newNode.NameString = fileName; newNode.Type = 1; newNode.Size = (uint)fileData.Length; // remove any existing file with this name FileDelete(newNode.NameString); // make sure we have a modified inodes collection ready... CreateModifiedInodes(); int numBlocks = (fileData.Length + (BLOCK_SZ - 1)) / BLOCK_SZ; var blockList = TryAllocateBlocks(numBlocks); if (blockList == null) { return(false); // couldn't find enough unused blocks :( } // start writing the file data! for (int i = 0; i < numBlocks; i++) { int dataOffset = i * BLOCK_SZ; int numWrite = BLOCK_SZ; if (dataOffset + numWrite > fileData.Length) { numWrite = fileData.Length % BLOCK_SZ; } SeekToBlock(blockList[i]); io.Stream.Write(fileData, dataOffset, numWrite); } newNode.BlockIdx = blockList[0]; // add new inode to inode list... // make seperate inode to provided one, to make sure nothing can change after adding it to inode list var realNewNode = new BbInode(); realNewNode.Copy(newNode); ModifiedInodes.Add(realNewNode); var chain = GetBlockChain(newNode.BlockIdx); // success! return(true); }
static void ModeNAND() { Console.WriteLine($"Opening NAND image from {filePath}..."); Console.WriteLine(); if (!string.IsNullOrEmpty(outputFile) && !string.IsNullOrEmpty(updateKernelPath)) { // we're updating kernel with output file specified, so copy the input file to specified output file and work with that instead if (File.Exists(outputFile)) { File.Delete(outputFile); } File.Copy(filePath, outputFile); filePath = outputFile; } var nandFile = new iQueNand(filePath) { SkipVerifyFsChecksums = skipVerifyChecksums || fixFsChecksums, InodesOffset = isBadDump ? 0x10 : 0 }; if (!nandFile.Read()) { Console.WriteLine($"[!] Failed to read NAND image!"); return; } if (!string.IsNullOrEmpty(addFiles) || !string.IsNullOrEmpty(addFilesList)) { var filesToAdd = new List <string>(); if (!string.IsNullOrEmpty(addFiles)) { var files = addFiles.Split(','); filesToAdd.AddRange(files); } if (!string.IsNullOrEmpty(addFilesList)) { if (File.Exists(addFilesList)) { var files = File.ReadAllLines(addFilesList); filesToAdd.AddRange(files); } else { Console.WriteLine($"[!] -al (addlist) failed, list {addFilesList} doesn't exist!"); } } if (filesToAdd.Count > 0) { int successful = 0; foreach (var file in filesToAdd) { if (File.Exists(file)) { Console.WriteLine($"Adding file to NAND: {file}"); BbInode node = new BbInode(); if (nandFile.FileWrite(Path.GetFileName(file), File.ReadAllBytes(file), ref node)) { Console.WriteLine($"File added successfully! name: {node.NameString}, block: {node.BlockIdx}"); successful++; } else { Console.WriteLine($"[!] Failed to add file, likely not enough free space in nand!"); } } else { Console.WriteLine($"[!] Failed to add non-existing file:{Environment.NewLine}\t{file}"); } } if (successful > 0) { Console.WriteLine("Writing updated FS to NAND..."); if (nandFile.WriteFilesystem()) { Console.WriteLine($"Added {successful} files successfully!"); } else { Console.WriteLine("[!] Failed to write updated FS, couldn't find FS block to write?"); } } } else { Console.WriteLine("[!] -al (addlist) failed, no files to add!"); } } if (!string.IsNullOrEmpty(deleteFiles)) { var filesToDelete = deleteFiles.Split(','); int successful = 0; foreach (var file in filesToDelete) { // lazy way to get proper 8.3 name for this file.. BbInode inode = new BbInode(); inode.NameString = Path.GetFileName(file); if (nandFile.FileDelete(inode.NameString)) { Console.WriteLine($"File {inode.NameString} removed from NAND!"); successful++; } else { Console.WriteLine($"Failed to remove file {inode.NameString} from NAND..."); } } if (successful > 0) { Console.WriteLine("Writing updated FS to NAND..."); if (nandFile.WriteFilesystem()) { Console.WriteLine($"Removed {successful} files successfully!"); } else { Console.WriteLine("[!] Failed to write updated FS, couldn't find FS block to write?"); } } } if (fixFsChecksums) { nandFile.RepairFsChecksums(); } if (printInfo) { Console.WriteLine(nandFile.ToString(true, true, showAllFsInfo)); } if (writeInfo) { File.WriteAllText(filePath + ".txt", nandFile.ToString(true, false, showAllFsInfo)); Console.WriteLine($"Wrote detailed NAND info to {filePath}.txt"); } if (!string.IsNullOrEmpty(updateKernelPath)) { Console.WriteLine($"Updating NAND SKSA to {updateKernelPath}"); nandFile.SetSKSAData(updateKernelPath); } else { // extract / extractkernel can only be used if we aren't updating kernel in the same session if (extractAll) { if (string.IsNullOrEmpty(outputFile)) { outputFile = filePath + "_ext"; Console.WriteLine("[!] No output path (-o) given, set path to:"); Console.WriteLine($"- {outputFile}"); Console.WriteLine(); } if (!Directory.Exists(outputFile)) { Directory.CreateDirectory(outputFile); } int count = 0; foreach (var file in nandFile.MainFsInodes) { if (!file.IsValid) { continue; } var extPath = Path.Combine(outputFile, file.NameString); Console.WriteLine($"Writing file to {extPath}"); File.WriteAllBytes(extPath, nandFile.FileRead(file)); count++; } Console.WriteLine($"Extracted {count} files to {outputFile}"); } if (extractKernel) { if (string.IsNullOrEmpty(outputFile)) { outputFile = filePath + ".sksa.bin"; Console.WriteLine("[!] No output path (-o) given, set path to:"); Console.WriteLine($"- {outputFile}"); Console.WriteLine(); } if (extractAll) // if we just extracted the fs files we'll extract SKSA into the same folder { outputFile = Path.Combine(outputFile, "sksa.bin"); } File.WriteAllBytes(outputFile, nandFile.GetSKSAData()); Console.WriteLine($"Extracted SKSA to {outputFile}"); } } if (!string.IsNullOrEmpty(generateSparePath)) { File.WriteAllBytes(generateSparePath, nandFile.GenerateSpareData(!generateFullSpare)); Console.WriteLine($"Wrote generated {(generateFullSpare ? "page" : "block")}-spare data to {generateSparePath}"); } }
public bool FileDelete(BbInode node) { var name = node.NameString; return(FileDelete(name)); }