diff --git a/DiscImageChef.Filesystems/DiscImageChef.Filesystems.csproj b/DiscImageChef.Filesystems/DiscImageChef.Filesystems.csproj index c3ca696b..ceece292 100644 --- a/DiscImageChef.Filesystems/DiscImageChef.Filesystems.csproj +++ b/DiscImageChef.Filesystems/DiscImageChef.Filesystems.csproj @@ -128,6 +128,7 @@ + @@ -188,7 +189,7 @@ - + diff --git a/DiscImageChef.Filesystems/EFS.cs b/DiscImageChef.Filesystems/EFS.cs new file mode 100644 index 00000000..477fec67 --- /dev/null +++ b/DiscImageChef.Filesystems/EFS.cs @@ -0,0 +1,316 @@ +// /*************************************************************************** +// The Disc Image Chef +// ---------------------------------------------------------------------------- +// +// Filename : EFS.cs +// Author(s) : Natalia Portillo +// +// Component : Component +// +// --[ Description ] ---------------------------------------------------------- +// +// Identifies the EFS 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-2017 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using System.Text; +using DiscImageChef.CommonTypes; +using DiscImageChef.Console; + +namespace DiscImageChef.Filesystems +{ + public class EFS : Filesystem + { + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct EFS_Superblock + { + /* 0: fs size incl. bb 0 (in bb) */ + public int sb_size; + /* 4: first cg offset (in bb) */ + public int sb_firstcg; + /* 8: cg size (in bb) */ + public int sb_cgfsize; + /* 12: inodes/cg (in bb) */ + public short sb_cgisize; + /* 14: geom: sectors/track */ + public short sb_sectors; + /* 16: geom: heads/cylinder (unused) */ + public short sb_heads; + /* 18: num of cg's in the filesystem */ + public short sb_ncg; + /* 20: non-0 indicates fsck required */ + public short sb_dirty; + /* 22: */ + public short sb_pad0; + /* 24: superblock ctime */ + public int sb_time; + /* 28: magic [0] */ + public uint sb_magic; + /* 32: name of filesystem */ + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)] + public byte[] sb_fname; + /* 38: name of filesystem pack */ + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)] + public byte[] sb_fpack; + /* 44: bitmap size (in bytes) */ + public int sb_bmsize; + /* 48: total free data blocks */ + public int sb_tfree; + /* 52: total free inodes */ + public int sb_tinode; + /* 56: bitmap offset (grown fs) */ + public int sb_bmblock; + /* 62: repl. superblock offset */ + public int sb_replsb; + /* 64: last allocated inode */ + public int sb_lastinode; + /* 68: unused */ + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)] + public byte[] sb_spare; + /* 88: checksum (all above) */ + public uint sb_checksum; + } + + const uint EFS_Magic = 0x00072959; + const uint EFS_Magic_New = 0x0007295A; + + public EFS() + { + Name = "Extent File System Plugin"; + PluginUUID = new Guid("52A43F90-9AF3-4391-ADFE-65598DEEABAB"); + CurrentEncoding = Encoding.GetEncoding("iso-8859-15"); + } + + public EFS(ImagePlugins.ImagePlugin imagePlugin, Partition partition, Encoding encoding) + { + Name = "Extent File System Plugin"; + PluginUUID = new Guid("52A43F90-9AF3-4391-ADFE-65598DEEABAB"); + if(encoding == null) + CurrentEncoding = Encoding.GetEncoding("iso-8859-15"); + else + CurrentEncoding = encoding; + } + + public override bool Identify(ImagePlugins.ImagePlugin imagePlugin, Partition partition) + { + if(imagePlugin.GetSectorSize() < 512) + return false; + + // Misaligned + if(imagePlugin.ImageInfo.xmlMediaType == ImagePlugins.XmlMediaType.OpticalDisc) + { + EFS_Superblock efs_sb = new EFS_Superblock(); + + uint sbSize = (uint)((Marshal.SizeOf(efs_sb) + 0x200) / imagePlugin.GetSectorSize()); + if((Marshal.SizeOf(efs_sb) + 0x200) % imagePlugin.GetSectorSize() != 0) + sbSize++; + + byte[] sector = imagePlugin.ReadSector(partition.Start, sbSize); + if(sector.Length < Marshal.SizeOf(efs_sb)) + return false; + + byte[] sbpiece = new byte[Marshal.SizeOf(efs_sb)]; + + Array.Copy(sector, 0x200, sbpiece, 0, Marshal.SizeOf(efs_sb)); + + efs_sb = BigEndianMarshal.ByteArrayToStructureBigEndian(sbpiece); + + DicConsole.DebugWriteLine("EFS plugin", "magic at 0x{0:X3} = 0x{1:X8} (expected 0x{2:X8} or 0x{3:X8})", 0x200, efs_sb.sb_magic, EFS_Magic, EFS_Magic_New); + + if(efs_sb.sb_magic == EFS_Magic || efs_sb.sb_magic == EFS_Magic_New) + return true; + } + else + { + EFS_Superblock efsSb = new EFS_Superblock(); + + uint sbSize = (uint)(Marshal.SizeOf(efsSb) / imagePlugin.GetSectorSize()); + if(Marshal.SizeOf(efsSb) % imagePlugin.GetSectorSize() != 0) + sbSize++; + + byte[] sector = imagePlugin.ReadSectors(partition.Start + 1, sbSize); + if(sector.Length < Marshal.SizeOf(efsSb)) + return false; + + efsSb = BigEndianMarshal.ByteArrayToStructureBigEndian(sector); + + DicConsole.DebugWriteLine("EFS plugin", "magic at {0} = 0x{1:X8} (expected 0x{2:X8} or 0x{3:X8})", 1, efsSb.sb_magic, EFS_Magic, EFS_Magic_New); + + if(efsSb.sb_magic == EFS_Magic || efsSb.sb_magic == EFS_Magic_New) + return true; + } + + return false; + } + + public override void GetInformation(ImagePlugins.ImagePlugin imagePlugin, Partition partition, out string information) + { + information = ""; + if(imagePlugin.GetSectorSize() < 512) + return; + + EFS_Superblock efsSb = new EFS_Superblock(); + + // Misaligned + if(imagePlugin.ImageInfo.xmlMediaType == ImagePlugins.XmlMediaType.OpticalDisc) + { + uint sbSize = (uint)((Marshal.SizeOf(efsSb) + 0x400) / imagePlugin.GetSectorSize()); + if((Marshal.SizeOf(efsSb) + 0x400) % imagePlugin.GetSectorSize() != 0) + sbSize++; + + byte[] sector = imagePlugin.ReadSector(partition.Start, sbSize); + if(sector.Length < Marshal.SizeOf(efsSb)) + return; + + byte[] sbpiece = new byte[Marshal.SizeOf(efsSb)]; + + Array.Copy(sector, 0x200, sbpiece, 0, Marshal.SizeOf(efsSb)); + + efsSb = BigEndianMarshal.ByteArrayToStructureBigEndian(sbpiece); + + DicConsole.DebugWriteLine("EFS plugin", "magic at 0x{0:X3} = 0x{1:X8} (expected 0x{2:X8} or 0x{3:X8})", 0x200, efsSb.sb_magic, EFS_Magic, EFS_Magic_New); + } + else + { + uint sbSize = (uint)(Marshal.SizeOf(efsSb) / imagePlugin.GetSectorSize()); + if(Marshal.SizeOf(efsSb) % imagePlugin.GetSectorSize() != 0) + sbSize++; + + byte[] sector = imagePlugin.ReadSectors(partition.Start + 1, sbSize); + if(sector.Length < Marshal.SizeOf(efsSb)) + return; + + efsSb = BigEndianMarshal.ByteArrayToStructureBigEndian(sector); + + DicConsole.DebugWriteLine("EFS plugin", "magic at {0} = 0x{1:X8} (expected 0x{2:X8} or 0x{3:X8})", 1, efsSb.sb_magic, EFS_Magic, EFS_Magic_New); + } + + if(efsSb.sb_magic != EFS_Magic && efsSb.sb_magic != EFS_Magic_New) + return; + + StringBuilder sb = new StringBuilder(); + + sb.AppendLine("SGI extent filesystem"); + if(efsSb.sb_magic == EFS_Magic_New) + sb.AppendLine("New version"); + sb.AppendFormat("Filesystem size: {0} basic blocks", efsSb.sb_size).AppendLine(); + sb.AppendFormat("First cylinder group starts at block {0}", efsSb.sb_firstcg).AppendLine(); + sb.AppendFormat("Cylinder group size: {0} basic blocks", efsSb.sb_cgfsize).AppendLine(); + sb.AppendFormat("{0} inodes per cylinder group", efsSb.sb_cgisize).AppendLine(); + sb.AppendFormat("{0} sectors per track", efsSb.sb_sectors).AppendLine(); + sb.AppendFormat("{0} heads per cylinder", efsSb.sb_heads).AppendLine(); + sb.AppendFormat("{0} cylinder groups", efsSb.sb_ncg).AppendLine(); + sb.AppendFormat("Volume created on {0}", DateHandlers.UNIXToDateTime(efsSb.sb_time)).AppendLine(); + sb.AppendFormat("{0} bytes on bitmap", efsSb.sb_bmsize).AppendLine(); + sb.AppendFormat("{0} free blocks", efsSb.sb_tfree).AppendLine(); + sb.AppendFormat("{0} free inodes", efsSb.sb_tinode).AppendLine(); + if(efsSb.sb_bmblock > 0) + sb.AppendFormat("Bitmap resides at block {0}", efsSb.sb_bmblock).AppendLine(); + if(efsSb.sb_replsb > 0) + sb.AppendFormat("Replacement superblock resides at block {0}", efsSb.sb_replsb).AppendLine(); + if(efsSb.sb_lastinode > 0) + sb.AppendFormat("Last inode allocated: {0}", efsSb.sb_lastinode).AppendLine(); + if(efsSb.sb_dirty > 0) + sb.AppendLine("Volume is dirty"); + sb.AppendFormat("Checksum: 0x{0:X8}", efsSb.sb_checksum).AppendLine(); + sb.AppendFormat("Volume name: {0}", StringHandlers.CToString(efsSb.sb_fname, CurrentEncoding)).AppendLine(); + sb.AppendFormat("Volume pack: {0}", StringHandlers.CToString(efsSb.sb_fpack, CurrentEncoding)).AppendLine(); + + information = sb.ToString(); + + xmlFSType = new Schemas.FileSystemType + { + Type = "Extent File System", + ClusterSize = 512, + Clusters = efsSb.sb_size, + FreeClusters = efsSb.sb_tfree, + FreeClustersSpecified = true, + Dirty = efsSb.sb_dirty > 0, + VolumeName = StringHandlers.CToString(efsSb.sb_fname, CurrentEncoding), + VolumeSerial = string.Format("{0:X8}", efsSb.sb_checksum), + CreationDate = DateHandlers.UNIXToDateTime(efsSb.sb_time), + CreationDateSpecified = true + }; + } + + public override Errno Mount() + { + return Errno.NotImplemented; + } + + public override Errno Mount(bool debug) + { + return Errno.NotImplemented; + } + + public override Errno Unmount() + { + return Errno.NotImplemented; + } + + public override Errno MapBlock(string path, long fileBlock, ref long deviceBlock) + { + return Errno.NotImplemented; + } + + public override Errno GetAttributes(string path, ref FileAttributes attributes) + { + return Errno.NotImplemented; + } + + public override Errno ListXAttr(string path, ref List xattrs) + { + return Errno.NotImplemented; + } + + public override Errno GetXattr(string path, string xattr, ref byte[] buf) + { + return Errno.NotImplemented; + } + + public override Errno Read(string path, long offset, long size, ref byte[] buf) + { + return Errno.NotImplemented; + } + + public override Errno ReadDir(string path, ref List contents) + { + return Errno.NotImplemented; + } + + public override Errno StatFs(ref FileSystemInfo stat) + { + return Errno.NotImplemented; + } + + public override Errno Stat(string path, ref FileEntryInfo stat) + { + return Errno.NotImplemented; + } + + public override Errno ReadLink(string path, ref string dest) + { + return Errno.NotImplemented; + } + } +} \ No newline at end of file diff --git a/README.md b/README.md index bc3a2903..87dcf2c3 100644 --- a/README.md +++ b/README.md @@ -146,6 +146,7 @@ Supported file systems for identification and information only * Professional File System * QNX4 and QNX6 filesystems * Reiser file systems +* SGI Extent File System (EFS) * SGI XFS * SmartFileSystem * SolarOS file system