/// <summary> /// Sets the data blocks. Also updates header for total number of data blocks. /// </summary> void CalculateDataBlockLayout() { // TODO: Consolidate of all this duplicate code if (properties.Sign) { // Include the header block in the total count hdr.Ndblock = 1; var inodesPerBlock = hdr.BlockSize / DinodeS32.SizeOf; hdr.DinodeCount = inodes.Count; hdr.DinodeBlockCount = CeilDiv(inodes.Count, inodesPerBlock); hdr.InodeBlockSig.Blocks = (uint)hdr.DinodeBlockCount; hdr.InodeBlockSig.Size = hdr.DinodeBlockCount * hdr.BlockSize; hdr.InodeBlockSig.SizeCompressed = hdr.DinodeBlockCount * hdr.BlockSize; hdr.InodeBlockSig.SetTime(properties.FileTime); hdr.InodeBlockSig.Flags = 0; for (var i = 0; i < hdr.DinodeBlockCount; i++) { hdr.InodeBlockSig.SetDirectBlock(i, 1 + i); final_sigs.Push(new BlockSigInfo(1 + i, 0xB8 + (36 * i))); } hdr.Ndblock += hdr.DinodeBlockCount; super_root_ino.SetDirectBlock(0, (int)(hdr.DinodeBlockCount + 1)); final_sigs.Push(new BlockSigInfo(super_root_ino.StartBlock, inoNumberToOffset(super_root_ino.Number))); hdr.Ndblock += super_root_ino.Blocks; // flat path table fpt_ino.SetDirectBlock(0, super_root_ino.StartBlock + 1); fpt_ino.Size = fpt.Size; fpt_ino.SizeCompressed = fpt.Size; fpt_ino.Blocks = (uint)CeilDiv(fpt.Size, hdr.BlockSize); final_sigs.Push(new BlockSigInfo(fpt_ino.StartBlock, inoNumberToOffset(fpt_ino.Number))); for (int i = 1; i < fpt_ino.Blocks && i < 12; i++) { fpt_ino.SetDirectBlock(i, (int)hdr.Ndblock++); final_sigs.Push(new BlockSigInfo(fpt_ino.StartBlock, inoNumberToOffset(fpt_ino.Number, i))); } // DATs I've found include an empty block after the FPT hdr.Ndblock++; // HACK: outer PFS has a block of zeroes that is not encrypted??? emptyBlock = (int)hdr.Ndblock; hdr.Ndblock++; var ibStartBlock = hdr.Ndblock; hdr.Ndblock += allNodes.Select(s => calculateIndirectBlocks(s.Size)).Sum(); var sigs_per_block = hdr.BlockSize / 36; // Fill in DB/IB pointers foreach (var n in allNodes) { var blocks = CeilDiv(n.Size, hdr.BlockSize); n.ino.SetDirectBlock(0, (int)hdr.Ndblock); n.ino.Blocks = (uint)blocks; n.ino.Size = n is FSDir?roundUpSizeToBlock(n.Size) : n.Size; if (n.ino.SizeCompressed == 0) { n.ino.SizeCompressed = n.ino.Size; } for (var i = 0; (blocks - i) > 0 && i < 12; i++) { data_sigs.Push(new BlockSigInfo((int)hdr.Ndblock++, inoNumberToOffset(n.ino.Number, i))); } if (blocks > 12) { // More than 12 blocks -> use 1 indirect block // ib[0] final_sigs.Push(new BlockSigInfo(ibStartBlock, inoNumberToOffset(n.ino.Number, 12))); for (int i = 12, pointerOffset = 0; (blocks - i) > 0 && i < (12 + sigs_per_block); i++, pointerOffset += 36) { // ib[0][i] data_sigs.Push(new BlockSigInfo((int)hdr.Ndblock++, ibStartBlock * hdr.BlockSize + pointerOffset)); } ibStartBlock++; } if (blocks > 12 + sigs_per_block) { uint blockSigsDone = 12 + sigs_per_block; // More than 12 + one block of pointers -> use 1 doubly-indirect block + any number of indirect blocks // ib[1] = signature for block of signatures for block of signatures for data blocks final_sigs.Push(new BlockSigInfo(ibStartBlock, inoNumberToOffset(n.ino.Number, 13))); var ib_1_block = ibStartBlock; for (var i = 0; i < sigs_per_block && blockSigsDone < blocks; i++) { // ib[1][i] = signature for block of signatures for data blocks final_sigs.Push(new BlockSigInfo((int)++ibStartBlock, ib_1_block * hdr.BlockSize + i * 36)); for (int j = 0; j < sigs_per_block && blockSigsDone < blocks; j++, blockSigsDone++) { // ib[1][i][j] = signature for data block data_sigs.Push(new BlockSigInfo((int)hdr.Ndblock++, ibStartBlock * hdr.BlockSize + (j * 36))); } } } } } else { // Include the header block in the total count hdr.Ndblock = 1; var inodesPerBlock = hdr.BlockSize / DinodeD32.SizeOf; hdr.DinodeCount = inodes.Count; hdr.DinodeBlockCount = CeilDiv(inodes.Count, inodesPerBlock); hdr.InodeBlockSig.Blocks = (uint)hdr.DinodeBlockCount; hdr.InodeBlockSig.Size = hdr.DinodeBlockCount * hdr.BlockSize; hdr.InodeBlockSig.SizeCompressed = hdr.DinodeBlockCount * hdr.BlockSize; hdr.InodeBlockSig.SetDirectBlock(0, (int)hdr.Ndblock++); hdr.InodeBlockSig.SetTime(properties.FileTime); for (var i = 1; i < hdr.DinodeBlockCount; i++) { if (i < 12) { hdr.InodeBlockSig.SetDirectBlock(i, -1); } hdr.Ndblock++; } super_root_ino.SetDirectBlock(0, (int)hdr.Ndblock); hdr.Ndblock += super_root_ino.Blocks; // flat path table fpt_ino.SetDirectBlock(0, (int)hdr.Ndblock++); fpt_ino.Size = fpt.Size; fpt_ino.SizeCompressed = fpt.Size; fpt_ino.Blocks = (uint)CeilDiv(fpt.Size, hdr.BlockSize); for (int i = 1; i < fpt_ino.Blocks && i < 12; i++) { fpt_ino.SetDirectBlock(i, (int)hdr.Ndblock++); } // DATs I've found include an empty block after the FPT if there's no collision resolver if (cr_ino == null) { hdr.Ndblock++; } else { // collision resolver cr_ino.SetDirectBlock(0, (int)hdr.Ndblock++); cr_ino.Size = colResolver.Size; cr_ino.SizeCompressed = colResolver.Size; cr_ino.Blocks = (uint)CeilDiv(colResolver.Size, hdr.BlockSize); for (int i = 1; i < cr_ino.Blocks && i < 12; i++) { cr_ino.SetDirectBlock(i, (int)hdr.Ndblock++); } } // Calculate length of all dirent blocks foreach (var n in allNodes) { var blocks = CeilDiv(n.Size, hdr.BlockSize); n.ino.SetDirectBlock(0, (int)hdr.Ndblock); n.ino.Blocks = (uint)blocks; n.ino.Size = n is FSDir?roundUpSizeToBlock(n.Size) : n.Size; if (n.ino.SizeCompressed == 0) { n.ino.SizeCompressed = n.ino.Size; } for (int i = 1; i < blocks && i < 12; i++) { n.ino.SetDirectBlock(i, -1); } hdr.Ndblock += blocks; } } }
/// <summary> /// Sets the data blocks. Also updates header for total number of data blocks. /// </summary> void CalculateDataBlockLayout() { long inoNumberToOffset(uint number, int db = 0) => hdr.BlockSize + (DinodeS32.SizeOf * number) + 0x64 + (36 * db); if (properties.Sign) { // Include the header block in the total count hdr.Ndblock = 1; var inodesPerBlock = hdr.BlockSize / DinodeS32.SizeOf; hdr.DinodeCount = inodes.Count; hdr.DinodeBlockCount = CeilDiv(inodes.Count, inodesPerBlock); hdr.InodeBlockSig.Blocks = (uint)hdr.DinodeBlockCount; hdr.InodeBlockSig.Size = hdr.DinodeBlockCount * hdr.BlockSize; hdr.InodeBlockSig.SizeCompressed = hdr.DinodeBlockCount * hdr.BlockSize; hdr.InodeBlockSig.SetTime(properties.FileTime); hdr.InodeBlockSig.Flags = 0; for (var i = 0; i < hdr.DinodeBlockCount; i++) { hdr.InodeBlockSig.SetDirectBlock(i, 1 + i); sig_order.Push(new BlockSigInfo(1 + i, 0xB8 + (36 * i))); } hdr.Ndblock += hdr.DinodeBlockCount; super_root_ino.SetDirectBlock(0, (int)(hdr.DinodeBlockCount + 1)); sig_order.Push(new BlockSigInfo(super_root_ino.StartBlock, inoNumberToOffset(super_root_ino.Number))); hdr.Ndblock += super_root_ino.Blocks; // flat path table fpt_ino.SetDirectBlock(0, super_root_ino.StartBlock + 1); fpt_ino.Size = fpt.Size; fpt_ino.SizeCompressed = fpt.Size; fpt_ino.Blocks = (uint)CeilDiv(fpt.Size, hdr.BlockSize); sig_order.Push(new BlockSigInfo(fpt_ino.StartBlock, inoNumberToOffset(fpt_ino.Number))); for (int i = 1; i < fpt_ino.Blocks && i < 12; i++) { fpt_ino.SetDirectBlock(i, (int)hdr.Ndblock++); sig_order.Push(new BlockSigInfo(fpt_ino.StartBlock, inoNumberToOffset(fpt_ino.Number, i))); } // DATs I've found include an empty block after the FPT hdr.Ndblock++; // HACK: outer PFS has a block of zeroes that is not encrypted??? emptyBlock = (int)hdr.Ndblock; hdr.Ndblock++; var ibStartBlock = hdr.Ndblock; hdr.Ndblock += allNodes.Select(s => calculateIndirectBlocks(s.Size)).Sum(); var sigs_per_block = hdr.BlockSize / 36; // Fill in DB/IB pointers foreach (var n in allNodes) { var blocks = CeilDiv(n.Size, hdr.BlockSize); n.ino.SetDirectBlock(0, (int)hdr.Ndblock); n.ino.Blocks = (uint)blocks; n.ino.Size = n is FSDir?roundUpSizeToBlock(n.Size) : n.Size; if (n.ino.SizeCompressed == 0) { n.ino.SizeCompressed = n.ino.Size; } for (var i = 0; (blocks - i) > 0 && i < 12; i++) { sig_order.Push(new BlockSigInfo((int)hdr.Ndblock++, inoNumberToOffset(n.ino.Number, i))); } if (blocks > 12) { // More than 12 blocks -> use 1 indirect block sig_order.Push(new BlockSigInfo(ibStartBlock, inoNumberToOffset(n.ino.Number, 12))); for (int i = 12, pointerOffset = 0; (blocks - i) > 0 && i < (12 + sigs_per_block); i++, pointerOffset += 36) { sig_order.Push(new BlockSigInfo((int)hdr.Ndblock++, ibStartBlock * hdr.BlockSize + pointerOffset)); } ibStartBlock++; } if (blocks > 12 + sigs_per_block) { // More than 12 + one block of pointers -> use 1 doubly-indirect block + any number of indirect blocks sig_order.Push(new BlockSigInfo(ibStartBlock, inoNumberToOffset(n.ino.Number, 13))); for (var i = 12 + sigs_per_block; (blocks - i) > 0 && i < (12 + sigs_per_block + (sigs_per_block * sigs_per_block)); i += sigs_per_block) { sig_order.Push(new BlockSigInfo(ibStartBlock, inoNumberToOffset(n.ino.Number, 12))); for (int j = 0, pointerOffset = 0; (blocks - i - j) > 0 && j < sigs_per_block; j++, pointerOffset += 36) { sig_order.Push(new BlockSigInfo((int)hdr.Ndblock++, ibStartBlock * hdr.BlockSize + pointerOffset)); } ibStartBlock++; } } } } else { // Include the header block in the total count hdr.Ndblock = 1; var inodesPerBlock = hdr.BlockSize / DinodeD32.SizeOf; hdr.DinodeCount = inodes.Count; hdr.DinodeBlockCount = CeilDiv(inodes.Count, inodesPerBlock); hdr.InodeBlockSig.Blocks = (uint)hdr.DinodeBlockCount; hdr.InodeBlockSig.Size = hdr.DinodeBlockCount * hdr.BlockSize; hdr.InodeBlockSig.SizeCompressed = hdr.DinodeBlockCount * hdr.BlockSize; hdr.InodeBlockSig.SetDirectBlock(0, (int)hdr.Ndblock++); hdr.InodeBlockSig.SetTime(properties.FileTime); for (var i = 1; i < hdr.DinodeBlockCount; i++) { hdr.InodeBlockSig.SetDirectBlock(i, -1); hdr.Ndblock++; } super_root_ino.SetDirectBlock(0, (int)hdr.Ndblock); hdr.Ndblock += super_root_ino.Blocks; // flat path table fpt_ino.SetDirectBlock(0, (int)hdr.Ndblock++); fpt_ino.Size = fpt.Size; fpt_ino.SizeCompressed = fpt.Size; fpt_ino.Blocks = (uint)CeilDiv(fpt.Size, hdr.BlockSize); for (int i = 1; i < fpt_ino.Blocks && i < 12; i++) { fpt_ino.SetDirectBlock(i, (int)hdr.Ndblock++); } // DATs I've found include an empty block after the FPT hdr.Ndblock++; // Calculate length of all dirent blocks foreach (var n in allNodes) { var blocks = CeilDiv(n.Size, hdr.BlockSize); n.ino.SetDirectBlock(0, (int)hdr.Ndblock); n.ino.Blocks = (uint)blocks; n.ino.Size = n is FSDir?roundUpSizeToBlock(n.Size) : n.Size; if (n.ino.SizeCompressed == 0) { n.ino.SizeCompressed = n.ino.Size; } for (int i = 1; i < blocks && i < 12; i++) { n.ino.SetDirectBlock(i, -1); } hdr.Ndblock += blocks; } } }