// /*************************************************************************** // 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-2018 Natalia Portillo // ****************************************************************************/ using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; using System.Text; using DiscImageChef.CommonTypes; using DiscImageChef.DiscImages; using Schemas; using hammer_crc_t = System.UInt32; using hammer_off_t = System.UInt64; using hammer_tid_t = System.UInt64; #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; Encoding currentEncoding; FileSystemType xmlFsType; public virtual FileSystemType XmlFsType => xmlFsType; public virtual Encoding Encoding => currentEncoding; public virtual string Name => "HAMMER Filesystem"; public virtual Guid Id => new Guid("91A188BF-5FD7-4677-BBD3-F59EBA9C864D"); public virtual 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; ulong magic; byte[] sbSector = imagePlugin.ReadSectors(partition.Start, run); magic = BitConverter.ToUInt64(sbSector, 0); return magic == HAMMER_FSBUF_VOLUME || magic == HAMMER_FSBUF_VOLUME_REV; } public virtual void GetInformation(IMediaImage imagePlugin, Partition partition, out string information, Encoding encoding) { currentEncoding = 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++; ulong magic; byte[] sbSector = imagePlugin.ReadSectors(partition.Start, run); magic = BitConverter.ToUInt64(sbSector, 0); if(magic == HAMMER_FSBUF_VOLUME) { GCHandle handle = GCHandle.Alloc(sbSector, GCHandleType.Pinned); hammerSb = (HammerSuperBlock)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(HammerSuperBlock)); handle.Free(); } else hammerSb = BigEndianMarshal.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, currentEncoding)) .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 = (long)(partition.Size / HAMMER_BIGBLOCK_SIZE), ClusterSize = HAMMER_BIGBLOCK_SIZE, Dirty = false, Type = "HAMMER", VolumeName = StringHandlers.CToString(hammerSb.vol_label, currentEncoding), 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 = hammerSb.vol0_stat_bigblocks; xmlFsType.FreeClusters = hammerSb.vol0_stat_freebigblocks; xmlFsType.FreeClustersSpecified = true; xmlFsType.Files = hammerSb.vol0_stat_inodes; xmlFsType.FilesSpecified = true; } // 0 ? //sb.AppendFormat("Volume header CRC: 0x{0:X8}", afs_sb.vol_crc).AppendLine(); information = sb.ToString(); } public virtual Errno Mount(IMediaImage imagePlugin, Partition partition, Encoding encoding, bool debug) { return Errno.NotImplemented; } public virtual Errno Unmount() { return Errno.NotImplemented; } public virtual Errno MapBlock(string path, long fileBlock, ref long deviceBlock) { return Errno.NotImplemented; } public virtual Errno GetAttributes(string path, ref FileAttributes attributes) { return Errno.NotImplemented; } public virtual Errno ListXAttr(string path, ref List xattrs) { return Errno.NotImplemented; } public virtual Errno GetXattr(string path, string xattr, ref byte[] buf) { return Errno.NotImplemented; } public virtual Errno Read(string path, long offset, long size, ref byte[] buf) { return Errno.NotImplemented; } public virtual Errno ReadDir(string path, ref List contents) { return Errno.NotImplemented; } public virtual Errno StatFs(ref FileSystemInfo stat) { return Errno.NotImplemented; } public virtual Errno Stat(string path, ref FileEntryInfo stat) { return Errno.NotImplemented; } public virtual Errno ReadLink(string path, ref string dest) { return Errno.NotImplemented; } /// /// Hammer superblock /// [StructLayout(LayoutKind.Sequential, Pack = 1)] [SuppressMessage("ReSharper", "BuiltInTypeReferenceStyle")] struct HammerSuperBlock { /// for a valid header public ulong vol_signature; /* These are relative to block device offset, not zone offsets. */ /// offset of boot area public long vol_bot_beg; /// offset of memory log public long vol_mem_beg; /// offset of the first buffer in volume public long vol_buf_beg; /// offset of volume EOF (on buffer boundary) public long vol_buf_end; public long vol_reserved01; /// identify filesystem public Guid vol_fsid; /// identify filesystem type public Guid vol_fstype; /// filesystem label [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)] public byte[] vol_label; /// volume number within filesystem public int vol_no; /// number of volumes making up filesystem public int vol_count; /// version control information public uint vol_version; /// header crc public hammer_crc_t vol_crc; /// volume flags public uint vol_flags; /// the root volume number (must be 0) public uint vol_rootvol; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] public 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 long vol0_stat_bigblocks; /// number of free big-blocks public long vol0_stat_freebigblocks; public long vol0_reserved01; /// for statfs only public long vol0_stat_inodes; public long vol0_reserved02; /// B-Tree root offset in zone-8 public hammer_off_t vol0_btree_root; /// highest partially synchronized TID public hammer_tid_t vol0_next_tid; public 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 HammerBlockMap[] vol0_blockmap; /// Array of zone-2 addresses for undo FIFO. [MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)] public 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; } } }