Ejemplo n.º 1
0
        public FragmentWriter(BuilderContext context)
        {
            _context = context;
            _currentBlock = new byte[context.DataBlockSize];
            _currentOffset = 0;

            _fragmentBlocks = new List<FragmentRecord>();
        }
Ejemplo n.º 2
0
 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;
 }
Ejemplo n.º 3
0
        public override void Write(BuilderContext context)
        {
            if (!_written)
            {
                WriteFileData(context);

                WriteInode(context);

                _written = true;
            }
        }
Ejemplo n.º 4
0
        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();
                }
            }
        }
Ejemplo n.º 5
0
        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);
        }
Ejemplo n.º 6
0
 public IdTableWriter(BuilderContext context)
 {
     _context = context;
     _ids = new List<int>();
 }
Ejemplo n.º 7
0
        /// <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);

            superBlock.FragmentTableStart = fragWriter.Persist();
            superBlock.LookupTableStart = -1;
            superBlock.UidGidTableStart = idWriter.Persist();
            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;
        }
Ejemplo n.º 8
0
 public abstract void Write(BuilderContext context);
Ejemplo n.º 9
0
 public abstract void Write(BuilderContext context);
Ejemplo n.º 10
0
        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
        }
Ejemplo n.º 11
0
 public IdTableWriter(BuilderContext context)
 {
     _context = context;
     _ids     = new List <int>();
 }
        /// <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(nameof(output));
            }

            if (!output.CanWrite)
            {
                throw new ArgumentException("Output stream must be writable", nameof(output));
            }

            if (!output.CanSeek)
            {
                throw new ArgumentException("Output stream must support seeking", nameof(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);

            superBlock.FragmentTableStart      = fragWriter.Persist();
            superBlock.LookupTableStart        = -1;
            superBlock.UidGidTableStart        = idWriter.Persist();
            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;
        }