internal void Persist() { if (_ids.Count * 4 > _context.DataBlockSize) { throw new NotImplementedException("Large numbers of user / group id's"); } for (int i = 0; i < _ids.Count; ++i) { Utilities.WriteBytesLittleEndian(_ids[i], _context.IoBuffer, i * 4); } // Persist the table that references the block containing the id's long blockPos = _context.RawStream.Position + 8; byte[] tableBuffer = new byte[8]; Utilities.WriteBytesLittleEndian(blockPos, tableBuffer, 0); _context.RawStream.Write(tableBuffer, 0, 8); // Persist the actual Id's MetablockWriter writer = new MetablockWriter(); writer.Write(_context.IoBuffer, 0, _ids.Count * 4); writer.Persist(_context.RawStream); }
/// <summary> /// Writes the file system to an existing stream. /// </summary> /// <param name="output">The stream to write to.</param> /// <remarks>The <c>output</c> stream must support seeking and writing.</remarks> public void Build(Stream output) { if (output == null) { throw new ArgumentNullException("output"); } if (!output.CanWrite) { throw new ArgumentException("Output stream must be writable", "output"); } if (!output.CanSeek) { throw new ArgumentException("Output stream must support seeking", "output"); } _context = new BuilderContext() { RawStream = output, DataBlockSize = DefaultBlockSize, IoBuffer = new byte[DefaultBlockSize], }; MetablockWriter inodeWriter = new MetablockWriter(); MetablockWriter dirWriter = new MetablockWriter(); FragmentWriter fragWriter = new FragmentWriter(_context); IdTableWriter idWriter = new IdTableWriter(_context); _context.AllocateInode = AllocateInode; _context.AllocateId = idWriter.AllocateId; _context.WriteDataBlock = WriteDataBlock; _context.WriteFragment = fragWriter.WriteFragment; _context.InodeWriter = inodeWriter; _context.DirectoryWriter = dirWriter; _nextInode = 1; SuperBlock superBlock = new SuperBlock(); superBlock.Magic = SuperBlock.SquashFsMagic; superBlock.CreationTime = DateTime.Now; superBlock.BlockSize = (uint)_context.DataBlockSize; superBlock.Compression = 1; // DEFLATE superBlock.BlockSizeLog2 = (ushort)Utilities.Log2(superBlock.BlockSize); superBlock.MajorVersion = 4; superBlock.MinorVersion = 0; output.Position = superBlock.Size; GetRoot().Reset(); GetRoot().Write(_context); fragWriter.Flush(); superBlock.RootInode = GetRoot().InodeRef; superBlock.InodesCount = _nextInode - 1; superBlock.FragmentsCount = (uint)fragWriter.FragmentCount; superBlock.UidGidCount = (ushort)idWriter.IdCount; superBlock.InodeTableStart = output.Position; inodeWriter.Persist(output); superBlock.DirectoryTableStart = output.Position; dirWriter.Persist(output); if (fragWriter.FragmentCount > 0) { superBlock.FragmentTableStart = output.Position; fragWriter.Persist(); } else { superBlock.FragmentTableStart = -1; } superBlock.LookupTableStart = -1; if (idWriter.IdCount > 0) { superBlock.UidGidTableStart = output.Position; idWriter.Persist(); } else { superBlock.UidGidTableStart = -1; } superBlock.ExtendedAttrsTableStart = -1; superBlock.BytesUsed = output.Position; // Pad to 4KB long end = Utilities.RoundUp(output.Position, 4 * Sizes.OneKiB); if (end != output.Position) { byte[] padding = new byte[(int)(end - output.Position)]; output.Write(padding, 0, padding.Length); } // Go back and write the superblock output.Position = 0; byte[] buffer = new byte[superBlock.Size]; superBlock.WriteTo(buffer, 0); output.Write(buffer, 0, buffer.Length); output.Position = end; }
internal void Persist() { if (_fragmentBlocks.Count > 0) { if (_fragmentBlocks.Count * FragmentRecord.RecordSize > _context.DataBlockSize) { throw new NotImplementedException("Large numbers of fragments"); } // Persist the table that references the block containing the fragment records long blockPos = _context.RawStream.Position + 8; byte[] tableBuffer = new byte[8]; Utilities.WriteBytesLittleEndian(blockPos, tableBuffer, 0); _context.RawStream.Write(tableBuffer, 0, 8); int recordSize = FragmentRecord.RecordSize; byte[] buffer = new byte[_fragmentBlocks.Count * recordSize]; for (int i = 0; i < _fragmentBlocks.Count; ++i) { _fragmentBlocks[i].WriteTo(buffer, i * recordSize); } MetablockWriter writer = new MetablockWriter(); writer.Write(buffer, 0, buffer.Length); writer.Persist(_context.RawStream); } }