public abstract void Write(BuilderContext context);
public IdTableWriter(BuilderContext context) { _context = context; _ids = new List <int>(); }
private void WriteDirectory(BuilderContext context) { MetadataRef startPos = context.DirectoryWriter.Position; int currentChild = 0; int numDirs = 0; while (currentChild < _children.Count) { long thisBlock = _children[currentChild].Node.InodeRef.Block; int firstInode = _children[currentChild].Node.InodeNumber; int count = 1; while (currentChild + count < _children.Count && _children[currentChild + count].Node.InodeRef.Block == thisBlock && _children[currentChild + count].Node.InodeNumber - firstInode < 0x7FFF) { ++count; } DirectoryHeader hdr = new DirectoryHeader() { Count = count - 1, InodeNumber = firstInode, StartBlock = (int)thisBlock }; hdr.WriteTo(context.IoBuffer, 0); context.DirectoryWriter.Write(context.IoBuffer, 0, hdr.Size); for (int i = 0; i < count; ++i) { Entry child = _children[currentChild + i]; DirectoryRecord record = new DirectoryRecord() { Offset = (ushort)child.Node.InodeRef.Offset, InodeNumber = (short)(child.Node.InodeNumber - firstInode), Type = child.Node.Inode.Type, Name = child.Name }; record.WriteTo(context.IoBuffer, 0); context.DirectoryWriter.Write(context.IoBuffer, 0, record.Size); if (child.Node.Inode.Type == InodeType.Directory || child.Node.Inode.Type == InodeType.ExtendedDirectory) { ++numDirs; } } currentChild += count; } long size = context.DirectoryWriter.DistanceFrom(startPos); if (size > uint.MaxValue) { throw new NotImplementedException("Writing large directories"); } NumLinks = numDirs + 2; // +1 for self, +1 for parent _inode.StartBlock = (uint)startPos.Block; _inode.Offset = (ushort)startPos.Offset; _inode.FileSize = (uint)size + 3; // For some reason, always +3 }
/// <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; }