// /*************************************************************************** // The Disc Image Chef // ---------------------------------------------------------------------------- // // Filename : HAMMER.cs // Author(s) : Natalia Portillo // // Component : HAMMER filesystem plugin. // // --[ Description ] ---------------------------------------------------------- // // Identifies the HAMMER filesystem and shows information. // // --[ License ] -------------------------------------------------------------- // // This library is free software; you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as // published by the Free Software Foundation; either version 2.1 of the // License, or (at your option) any later version. // // This library is distributed in the hope that it will be useful, but // WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License along with this library; if not, see . // // ---------------------------------------------------------------------------- // Copyright © 2011-2019 Natalia Portillo // ****************************************************************************/ using System; using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; using System.Text; using DiscImageChef.CommonTypes; using DiscImageChef.CommonTypes.Interfaces; using Schemas; using hammer_crc_t = System.UInt32; using hammer_off_t = System.UInt64; using hammer_tid_t = System.UInt64; using Marshal = DiscImageChef.Helpers.Marshal; #pragma warning disable 169 namespace DiscImageChef.Filesystems { public class HAMMER : IFilesystem { const ulong HAMMER_FSBUF_VOLUME = 0xC8414D4DC5523031; const ulong HAMMER_FSBUF_VOLUME_REV = 0x313052C54D4D41C8; const uint HAMMER_VOLHDR_SIZE = 1928; const int HAMMER_BIGBLOCK_SIZE = 8192 * 1024; public FileSystemType XmlFsType { get; private set; } public Encoding Encoding { get; private set; } public string Name => "HAMMER Filesystem"; public Guid Id => new Guid("91A188BF-5FD7-4677-BBD3-F59EBA9C864D"); public string Author => "Natalia Portillo"; public bool Identify(IMediaImage imagePlugin, Partition partition) { uint run = HAMMER_VOLHDR_SIZE / imagePlugin.Info.SectorSize; if(HAMMER_VOLHDR_SIZE % imagePlugin.Info.SectorSize > 0) run++; if(run + partition.Start >= partition.End) return false; byte[] sbSector = imagePlugin.ReadSectors(partition.Start, run); ulong magic = BitConverter.ToUInt64(sbSector, 0); return magic == HAMMER_FSBUF_VOLUME || magic == HAMMER_FSBUF_VOLUME_REV; } public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information, Encoding encoding) { Encoding = encoding ?? Encoding.GetEncoding("iso-8859-15"); information = ""; StringBuilder sb = new StringBuilder(); HammerSuperBlock hammerSb; uint run = HAMMER_VOLHDR_SIZE / imagePlugin.Info.SectorSize; if(HAMMER_VOLHDR_SIZE % imagePlugin.Info.SectorSize > 0) run++; byte[] sbSector = imagePlugin.ReadSectors(partition.Start, run); ulong magic = BitConverter.ToUInt64(sbSector, 0); if(magic == HAMMER_FSBUF_VOLUME) hammerSb = Marshal.ByteArrayToStructureLittleEndian(sbSector); else hammerSb = Marshal.ByteArrayToStructureBigEndian(sbSector); sb.AppendLine("HAMMER filesystem"); sb.AppendFormat("Volume version: {0}", hammerSb.vol_version).AppendLine(); sb.AppendFormat("Volume {0} of {1} on this filesystem", hammerSb.vol_no + 1, hammerSb.vol_count) .AppendLine(); sb.AppendFormat("Volume name: {0}", StringHandlers.CToString(hammerSb.vol_label, Encoding)).AppendLine(); sb.AppendFormat("Volume serial: {0}", hammerSb.vol_fsid).AppendLine(); sb.AppendFormat("Filesystem type: {0}", hammerSb.vol_fstype).AppendLine(); sb.AppendFormat("Boot area starts at {0}", hammerSb.vol_bot_beg).AppendLine(); sb.AppendFormat("Memory log starts at {0}", hammerSb.vol_mem_beg).AppendLine(); sb.AppendFormat("First volume buffer starts at {0}", hammerSb.vol_buf_beg).AppendLine(); sb.AppendFormat("Volume ends at {0}", hammerSb.vol_buf_end).AppendLine(); XmlFsType = new FileSystemType { Clusters = partition.Size / HAMMER_BIGBLOCK_SIZE, ClusterSize = HAMMER_BIGBLOCK_SIZE, Dirty = false, Type = "HAMMER", VolumeName = StringHandlers.CToString(hammerSb.vol_label, Encoding), VolumeSerial = hammerSb.vol_fsid.ToString() }; if(hammerSb.vol_no == hammerSb.vol_rootvol) { sb.AppendFormat("Filesystem contains {0} \"big-blocks\" ({1} bytes)", hammerSb.vol0_stat_bigblocks, hammerSb.vol0_stat_bigblocks * HAMMER_BIGBLOCK_SIZE).AppendLine(); sb.AppendFormat("Filesystem has {0} \"big-blocks\" free ({1} bytes)", hammerSb.vol0_stat_freebigblocks, hammerSb.vol0_stat_freebigblocks * HAMMER_BIGBLOCK_SIZE).AppendLine(); sb.AppendFormat("Filesystem has {0} inode used", hammerSb.vol0_stat_inodes).AppendLine(); XmlFsType.Clusters = (ulong)hammerSb.vol0_stat_bigblocks; XmlFsType.FreeClusters = (ulong)hammerSb.vol0_stat_freebigblocks; XmlFsType.FreeClustersSpecified = true; XmlFsType.Files = (ulong)hammerSb.vol0_stat_inodes; XmlFsType.FilesSpecified = true; } // 0 ? //sb.AppendFormat("Volume header CRC: 0x{0:X8}", afs_sb.vol_crc).AppendLine(); information = sb.ToString(); } /// /// Hammer superblock /// [StructLayout(LayoutKind.Sequential, Pack = 1)] [SuppressMessage("ReSharper", "BuiltInTypeReferenceStyle")] struct HammerSuperBlock { /// for a valid header public readonly ulong vol_signature; /* These are relative to block device offset, not zone offsets. */ /// offset of boot area public readonly long vol_bot_beg; /// offset of memory log public readonly long vol_mem_beg; /// offset of the first buffer in volume public readonly long vol_buf_beg; /// offset of volume EOF (on buffer boundary) public readonly long vol_buf_end; public readonly long vol_reserved01; /// identify filesystem public readonly Guid vol_fsid; /// identify filesystem type public readonly Guid vol_fstype; /// filesystem label [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)] public readonly byte[] vol_label; /// volume number within filesystem public readonly int vol_no; /// number of volumes making up filesystem public readonly int vol_count; /// version control information public readonly uint vol_version; /// header crc public readonly hammer_crc_t vol_crc; /// volume flags public readonly uint vol_flags; /// the root volume number (must be 0) public readonly uint vol_rootvol; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] public readonly uint[] vol_reserved; /* * These fields are initialized and space is reserved in every * volume making up a HAMMER filesytem, but only the root volume * contains valid data. Note that vol0_stat_bigblocks does not * include big-blocks for freemap and undomap initially allocated * by newfs_hammer(8). */ /// total big-blocks when fs is empty public readonly long vol0_stat_bigblocks; /// number of free big-blocks public readonly long vol0_stat_freebigblocks; public readonly long vol0_reserved01; /// for statfs only public readonly long vol0_stat_inodes; public readonly long vol0_reserved02; /// B-Tree root offset in zone-8 public readonly hammer_off_t vol0_btree_root; /// highest partially synchronized TID public readonly hammer_tid_t vol0_next_tid; public readonly hammer_off_t vol0_reserved03; /// /// Blockmaps for zones. Not all zones use a blockmap. Note that the entire root blockmap is cached in the /// hammer_mount structure. /// [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] public readonly HammerBlockMap[] vol0_blockmap; /// Array of zone-2 addresses for undo FIFO. [MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)] public readonly hammer_off_t[] vol0_undo_array; } [SuppressMessage("ReSharper", "InconsistentNaming")] [SuppressMessage("ReSharper", "BuiltInTypeReferenceStyle")] struct HammerBlockMap { /// zone-2 offset only used by zone-4 public hammer_off_t phys_offset; /// zone-X offset only used by zone-3 public hammer_off_t first_offset; /// zone-X offset for allocation public hammer_off_t next_offset; /// zone-X offset only used by zone-3 public hammer_off_t alloc_offset; public uint reserved01; public hammer_crc_t entry_crc; } } }