public FragmentWriter(BuilderContext context) { _context = context; _currentBlock = new byte[context.DataBlockSize]; _currentOffset = 0; _fragmentBlocks = new List<FragmentRecord>(); }
protected void FillCommonInodeData(BuilderContext context) { Inode.Mode = (ushort)Mode; Inode.UidKey = context.AllocateId(UserId); Inode.GidKey = context.AllocateId(GroupId); Inode.ModificationTime = ModificationTime; InodeNumber = (int)context.AllocateInode(); Inode.InodeNumber = (uint)InodeNumber; Inode.NumLinks = NumLinks; }
public override void Write(BuilderContext context) { if (!_written) { WriteFileData(context); WriteInode(context); _written = true; } }
private void WriteFileData(BuilderContext context) { Stream outStream = context.RawStream; bool disposeSource = false; try { if (_source == null) { _source = new FileStream(_sourcePath, FileMode.Open, FileAccess.Read, FileShare.Read); disposeSource = true; } if (_source.Position != 0) { _source.Position = 0; } long startPos = outStream.Position; int bufferedBytes = Utilities.ReadFully(_source, context.IoBuffer, 0, context.DataBlockSize); if (bufferedBytes < context.DataBlockSize) { // Fragment - less than one complete block of data _inode.StartBlock = 0xFFFFFFFF; _inode.FragmentKey = context.WriteFragment(bufferedBytes, out _inode.FragmentOffset); _inode.FileSize = (uint)bufferedBytes; } else { // At least one full block, no fragments used _inode.FragmentKey = 0xFFFFFFFF; _lengths = new List<uint>(); _inode.StartBlock = (uint)startPos; _inode.FileSize = bufferedBytes; while (bufferedBytes > 0) { _lengths.Add(context.WriteDataBlock(context.IoBuffer, 0, bufferedBytes)); bufferedBytes = Utilities.ReadFully(_source, context.IoBuffer, 0, context.DataBlockSize); _inode.FileSize += (uint)bufferedBytes; } } } finally { if (disposeSource) { _source.Dispose(); } } }
/// <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; }
public abstract void Write(BuilderContext context);
public IdTableWriter(BuilderContext context) { _context = context; _ids = new List<int>(); }
private void WriteInode(BuilderContext context) { if (NumLinks != 1) { throw new IOException("Extended file records (with multiple hard links) not supported"); } FillCommonInodeData(context); _inode.Type = InodeType.File; InodeRef = context.InodeWriter.Position; int totalSize = _inode.Size; _inode.WriteTo(context.IoBuffer, 0); if (_lengths != null && _lengths.Count > 0) { for (int i = 0; i < _lengths.Count; ++i) { Utilities.WriteBytesLittleEndian(_lengths[i], context.IoBuffer, _inode.Size + (i * 4)); } totalSize += _lengths.Count * 4; } context.InodeWriter.Write(context.IoBuffer, 0, totalSize); }