/// <summary> /// Detects if the stream contains a SquashFs file system. /// </summary> /// <param name="stream">The stream to inspect</param> /// <returns><c>true</c> if stream appears to be a SquashFs file system.</returns> public static bool Detect(Stream stream) { stream.Position = 0; SuperBlock superBlock = new SuperBlock(); if (stream.Length < superBlock.Size) { return(false); } byte[] buffer = Utilities.ReadFully(stream, superBlock.Size); superBlock.ReadFrom(buffer, 0); return(superBlock.Magic == SuperBlock.SquashFsMagic); }
/// <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; }