diff --git a/DiscImageChef.Filesystems/DiscImageChef.Filesystems.csproj b/DiscImageChef.Filesystems/DiscImageChef.Filesystems.csproj
index c9f4b556d..c3ca696b7 100644
--- a/DiscImageChef.Filesystems/DiscImageChef.Filesystems.csproj
+++ b/DiscImageChef.Filesystems/DiscImageChef.Filesystems.csproj
@@ -127,6 +127,7 @@
+
@@ -187,7 +188,7 @@
-
+
diff --git a/DiscImageChef.Filesystems/Fossil.cs b/DiscImageChef.Filesystems/Fossil.cs
index dde9b8d84..7b718ac67 100644
--- a/DiscImageChef.Filesystems/Fossil.cs
+++ b/DiscImageChef.Filesystems/Fossil.cs
@@ -9,7 +9,7 @@
//
// --[ Description ] ----------------------------------------------------------
//
-// Description
+// Identifies the Fossil filesystem and shows information.
//
// --[ License ] --------------------------------------------------------------
//
@@ -29,13 +29,248 @@
// ----------------------------------------------------------------------------
// 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 Fossil
+ public class Fossil : Filesystem
{
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ struct FossilHeader
+ {
+ ///
+ /// Magic number
+ ///
+ public uint magic;
+ ///
+ /// Header version
+ ///
+ public ushort version;
+ ///
+ /// Block size
+ ///
+ public ushort blockSize;
+ ///
+ /// Block containing superblock
+ ///
+ public uint super;
+ ///
+ /// Block containing labels
+ ///
+ public uint label;
+ ///
+ /// Where do data blocks start
+ ///
+ public uint data;
+ ///
+ /// How many data blocks does it have
+ ///
+ public uint end;
+ }
+
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ struct FossilSuperBlock
+ {
+ ///
+ /// Magic number
+ ///
+ public uint magic;
+ ///
+ /// Header version
+ ///
+ public ushort version;
+ ///
+ /// file system low epoch
+ ///
+ public uint epochLow;
+ ///
+ /// file system high(active) epoch
+ ///
+ public uint epochHigh;
+ ///
+ /// next qid to allocate
+ ///
+ public ulong qid;
+ ///
+ /// data block number: root of active file system
+ ///
+ public int active;
+ ///
+ /// data block number: root of next file system to archive
+ ///
+ public int next;
+ ///
+ /// data block number: root of file system currently being archived
+ ///
+ public int current;
+ ///
+ /// Venti score of last successful archive
+ ///
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
+ public byte[] last;
+ ///
+ /// name of file system(just a comment)
+ ///
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)]
+ public byte[] name;
+ }
+
+ const uint Fossil_HdrMagic = 0x3776AE89;
+ const uint Fossil_SbMagic = 0x2340A3B1;
+ // Fossil header starts at 128KiB
+ const ulong HeaderPos = 128 * 1024;
+
public Fossil()
{
+ Name = "Fossil Filesystem Plugin";
+ PluginUUID = new Guid("932BF104-43F6-494F-973C-45EF58A51DA9");
+ CurrentEncoding = Encoding.UTF8;
+ }
+
+ public Fossil(ImagePlugins.ImagePlugin imagePlugin, Partition partition, Encoding encoding)
+ {
+ Name = "Fossil Filesystem Plugin";
+ PluginUUID = new Guid("932BF104-43F6-494F-973C-45EF58A51DA9");
+ // Technically everything on Plan 9 from Bell Labs is in UTF-8
+ CurrentEncoding = Encoding.UTF8;
+ }
+
+ public override bool Identify(ImagePlugins.ImagePlugin imagePlugin, Partition partition)
+ {
+ ulong hdrSector = HeaderPos / imagePlugin.GetSectorSize();
+
+ FossilHeader hdr = new FossilHeader();
+
+ byte[] sector = imagePlugin.ReadSector(partition.Start + hdrSector);
+ hdr = BigEndianMarshal.ByteArrayToStructureBigEndian(sector);
+
+ DicConsole.DebugWriteLine("Fossil plugin", "magic at 0x{0:X8} (expected 0x{1:X8})", hdr.magic, Fossil_HdrMagic);
+
+ return hdr.magic == Fossil_HdrMagic;
+ }
+
+ public override void GetInformation(ImagePlugins.ImagePlugin imagePlugin, Partition partition, out string information)
+ {
+ information = "";
+ if(imagePlugin.GetSectorSize() < 512)
+ return;
+
+ ulong hdrSector = HeaderPos / imagePlugin.GetSectorSize();
+
+ FossilHeader hdr = new FossilHeader();
+
+ byte[] sector = imagePlugin.ReadSector(partition.Start + hdrSector);
+ hdr = BigEndianMarshal.ByteArrayToStructureBigEndian(sector);
+
+ DicConsole.DebugWriteLine("Fossil plugin", "magic at 0x{0:X8} (expected 0x{1:X8})", hdr.magic, Fossil_HdrMagic);
+
+ StringBuilder sb = new StringBuilder();
+
+ sb.AppendLine("Fossil");
+ sb.AppendFormat("Filesystem version {0}", hdr.version).AppendLine();
+ sb.AppendFormat("{0} bytes per block", hdr.blockSize).AppendLine();
+ sb.AppendFormat("Superblock resides in block {0}", hdr.super).AppendLine();
+ sb.AppendFormat("Labels resides in block {0}", hdr.label).AppendLine();
+ sb.AppendFormat("Data starts at block {0}", hdr.data).AppendLine();
+ sb.AppendFormat("Volume has {0} blocks", hdr.end).AppendLine();
+
+ ulong sbLocation = (hdr.super * (hdr.blockSize / imagePlugin.GetSectorSize())) + partition.Start;
+
+ xmlFSType = new Schemas.FileSystemType
+ {
+ Type = "Fossil filesystem",
+ ClusterSize = hdr.blockSize,
+ Clusters = hdr.end
+ };
+
+ if(sbLocation <= partition.End)
+ {
+ sector = imagePlugin.ReadSector(sbLocation);
+ System.Console.WriteLine("Searching for superblock on sector {0}", sbLocation);
+ FossilSuperBlock fsb = BigEndianMarshal.ByteArrayToStructureBigEndian(sector);
+
+ DicConsole.DebugWriteLine("Fossil plugin", "magic 0x{0:X8} (expected 0x{1:X8})", fsb.magic, Fossil_SbMagic);
+
+ if(fsb.magic == Fossil_SbMagic)
+ {
+ sb.AppendFormat("Epoch low {0}", fsb.epochLow).AppendLine();
+ sb.AppendFormat("Epoch high {0}", fsb.epochHigh).AppendLine();
+ sb.AppendFormat("Next QID {0}", fsb.qid).AppendLine();
+ sb.AppendFormat("Active root block {0}", fsb.active).AppendLine();
+ sb.AppendFormat("Next root block {0}", fsb.next).AppendLine();
+ sb.AppendFormat("Curren root block {0}", fsb.current).AppendLine();
+ sb.AppendFormat("Volume label: \"{0}\"", StringHandlers.CToString(fsb.name, CurrentEncoding)).AppendLine();
+ xmlFSType.VolumeName = StringHandlers.CToString(fsb.name, CurrentEncoding);
+ }
+ }
+
+ information = sb.ToString();
+ }
+
+ 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 b965938bf..bc3a29034 100644
--- a/README.md
+++ b/README.md
@@ -125,6 +125,7 @@ Supported file systems for identification and information only
* DEC Files-11 (only checked with On Disk Structure 2, ODS-2)
* ECMA-67: 130mm Flexible Disk Cartridge Labelling and File Structure for Information Interchange
* Flash-Friendly File System (F2FS)
+* Fossil file system (from Plan9)
* HAMMER file system
* IBM Journaling File System (JFS)
* ISO9660