diff --git a/DiscImageChef.Filesystems/ChangeLog b/DiscImageChef.Filesystems/ChangeLog index ece4ec3d..c7c3a9fb 100644 --- a/DiscImageChef.Filesystems/ChangeLog +++ b/DiscImageChef.Filesystems/ChangeLog @@ -1,3 +1,12 @@ +2016-09-02 Natalia Portillo + + * Reiser.cs: + * Reiser4.cs: + * DiscImageChef.Filesystems.csproj: Adds support for Reiser + filesystems, closes #19. + + * NILFS2.cs: Corrected plugin GUID not being unique. + 2016-09-02 Natalia Portillo * NILFS2.cs: diff --git a/DiscImageChef.Filesystems/DiscImageChef.Filesystems.csproj b/DiscImageChef.Filesystems/DiscImageChef.Filesystems.csproj index e35d5f90..4519c7d2 100644 --- a/DiscImageChef.Filesystems/DiscImageChef.Filesystems.csproj +++ b/DiscImageChef.Filesystems/DiscImageChef.Filesystems.csproj @@ -102,6 +102,8 @@ + + diff --git a/DiscImageChef.Filesystems/NILFS2.cs b/DiscImageChef.Filesystems/NILFS2.cs index c3b3f41c..40ea4ec5 100644 --- a/DiscImageChef.Filesystems/NILFS2.cs +++ b/DiscImageChef.Filesystems/NILFS2.cs @@ -99,13 +99,13 @@ namespace DiscImageChef.Filesystems public NILFS2() { Name = "NILFS2 Plugin"; - PluginUUID = new Guid("82B0920F-5F0D-4063-9F57-ADE0AE02ECE5"); + PluginUUID = new Guid("35224226-C5CC-48B5-8FFD-3781E91E86B6"); } public NILFS2(ImagePlugins.ImagePlugin imagePlugin, ulong partitionStart, ulong partitionEnd) { Name = "NILFS2 Plugin"; - PluginUUID = new Guid("82B0920F-5F0D-4063-9F57-ADE0AE02ECE5"); + PluginUUID = new Guid("35224226-C5CC-48B5-8FFD-3781E91E86B6"); } public override bool Identify(ImagePlugins.ImagePlugin imagePlugin, ulong partitionStart, ulong partitionEnd) diff --git a/DiscImageChef.Filesystems/Reiser.cs b/DiscImageChef.Filesystems/Reiser.cs new file mode 100644 index 00000000..ca42ecb9 --- /dev/null +++ b/DiscImageChef.Filesystems/Reiser.cs @@ -0,0 +1,265 @@ +// /*************************************************************************** +// The Disc Image Chef +// ---------------------------------------------------------------------------- +// +// Filename : Reiser.cs +// Author(s) : Natalia Portillo +// +// Component : Component +// +// --[ Description ] ---------------------------------------------------------- +// +// Identifies the Reiser 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-2016 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; + +namespace DiscImageChef.Filesystems +{ + class Reiser : Filesystem + { + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct ReiserJournalParams + { + public uint journal_1stblock; + public uint journal_dev; + public uint journal_size; + public uint journal_trans_max; + public uint journal_magic; + public uint journal_max_batch; + public uint journal_max_commit_age; + public uint journal_max_trans_age; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct Reiser_Superblock + { + public uint block_count; + public uint free_blocks; + public uint root_block; + public ReiserJournalParams journal; + public ushort blocksize; + public ushort oid_maxsize; + public ushort oid_cursize; + public ushort umount_state; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)] + public byte[] magic; + public ushort fs_state; + public uint hash_function_code; + public ushort tree_height; + public ushort bmap_nr; + public ushort version; + public ushort reserved_for_journal; + public uint inode_generation; + public uint flags; + public Guid uuid; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + public byte[] label; + public ushort mnt_count; + public ushort max_mnt_count; + public uint last_check; + public uint check_interval; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 76)] + public byte[] unused; + } + + readonly byte[] Reiser35_Magic = { 0x52, 0x65, 0x49, 0x73, 0x45, 0x72, 0x46, 0x73, 0x00, 0x00 }; + readonly byte[] Reiser36_Magic = { 0x52, 0x65, 0x49, 0x73, 0x45, 0x72, 0x32, 0x46, 0x73, 0x00 }; + readonly byte[] ReiserJr_Magic = { 0x52, 0x65, 0x49, 0x73, 0x45, 0x72, 0x33, 0x46, 0x73, 0x00 }; + const uint Reiser_SuperOffset = 0x10000; + + public Reiser() + { + Name = "Reiser Filesystem Plugin"; + PluginUUID = new Guid("1D8CD8B8-27E6-410F-9973-D16409225FBA"); + } + + public Reiser(ImagePlugins.ImagePlugin imagePlugin, ulong partitionStart, ulong partitionEnd) + { + Name = "Reiser Filesystem Plugin"; + PluginUUID = new Guid("1D8CD8B8-27E6-410F-9973-D16409225FBA"); + } + + public override bool Identify(ImagePlugins.ImagePlugin imagePlugin, ulong partitionStart, ulong partitionEnd) + { + if(imagePlugin.GetSectorSize() < 512) + return false; + + uint sbAddr = Reiser_SuperOffset / imagePlugin.GetSectorSize(); + if(sbAddr == 0) + sbAddr = 1; + + Reiser_Superblock reiserSb = new Reiser_Superblock(); + + uint sbSize = (uint)(Marshal.SizeOf(reiserSb) / imagePlugin.GetSectorSize()); + if(Marshal.SizeOf(reiserSb) % imagePlugin.GetSectorSize() != 0) + sbSize++; + + byte[] sector = imagePlugin.ReadSectors(partitionStart + sbAddr, sbSize); + if(sector.Length < Marshal.SizeOf(reiserSb)) + return false; + + IntPtr sbPtr = Marshal.AllocHGlobal(Marshal.SizeOf(reiserSb)); + Marshal.Copy(sector, 0, sbPtr, Marshal.SizeOf(reiserSb)); + reiserSb = (Reiser_Superblock)Marshal.PtrToStructure(sbPtr, typeof(Reiser_Superblock)); + Marshal.FreeHGlobal(sbPtr); + + return Reiser35_Magic.SequenceEqual(reiserSb.magic) || + Reiser36_Magic.SequenceEqual(reiserSb.magic) || + ReiserJr_Magic.SequenceEqual(reiserSb.magic); + } + + public override void GetInformation(ImagePlugins.ImagePlugin imagePlugin, ulong partitionStart, ulong partitionEnd, out string information) + { + information = ""; + if(imagePlugin.GetSectorSize() < 512) + return; + + uint sbAddr = Reiser_SuperOffset / imagePlugin.GetSectorSize(); + if(sbAddr == 0) + sbAddr = 1; + + Reiser_Superblock reiserSb = new Reiser_Superblock(); + + uint sbSize = (uint)(Marshal.SizeOf(reiserSb) / imagePlugin.GetSectorSize()); + if(Marshal.SizeOf(reiserSb) % imagePlugin.GetSectorSize() != 0) + sbSize++; + + byte[] sector = imagePlugin.ReadSectors(partitionStart + sbAddr, sbSize); + if(sector.Length < Marshal.SizeOf(reiserSb)) + return; + + IntPtr sbPtr = Marshal.AllocHGlobal(Marshal.SizeOf(reiserSb)); + Marshal.Copy(sector, 0, sbPtr, Marshal.SizeOf(reiserSb)); + reiserSb = (Reiser_Superblock)Marshal.PtrToStructure(sbPtr, typeof(Reiser_Superblock)); + Marshal.FreeHGlobal(sbPtr); + + if(!Reiser35_Magic.SequenceEqual(reiserSb.magic) && + !Reiser36_Magic.SequenceEqual(reiserSb.magic) && + !ReiserJr_Magic.SequenceEqual(reiserSb.magic)) + return; + + StringBuilder sb = new StringBuilder(); + + if(Reiser35_Magic.SequenceEqual(reiserSb.magic)) + sb.AppendLine("Reiser 3.5 filesystem"); + else if(Reiser36_Magic.SequenceEqual(reiserSb.magic)) + sb.AppendLine("Reiser 3.6 filesystem"); + else if(ReiserJr_Magic.SequenceEqual(reiserSb.magic)) + sb.AppendLine("Reiser Jr. filesystem"); + sb.AppendFormat("Volume has {0} blocks with {1} blocks free", reiserSb.block_count, reiserSb.free_blocks).AppendLine(); + sb.AppendFormat("{0} bytes per block", reiserSb.blocksize).AppendLine(); + sb.AppendFormat("Root directory resides on block {0}", reiserSb.root_block).AppendLine(); + if(reiserSb.umount_state == 2) + sb.AppendLine("Volume has not been cleanly umounted"); + sb.AppendFormat("Volume last checked on {0}", DateHandlers.UNIXUnsignedToDateTime(reiserSb.last_check)).AppendLine(); + if(reiserSb.version >= 2) + { + sb.AppendFormat("Volume UUID: {0}", reiserSb.uuid).AppendLine(); + sb.AppendFormat("Volume name: {0}", Encoding.ASCII.GetString(reiserSb.label)).AppendLine(); + } + + information = sb.ToString(); + + xmlFSType = new Schemas.FileSystemType(); + if(Reiser35_Magic.SequenceEqual(reiserSb.magic)) + xmlFSType.Type = "Reiser 3.5 filesystem"; + else if(Reiser36_Magic.SequenceEqual(reiserSb.magic)) + xmlFSType.Type = "Reiser 3.6 filesystem"; + else if(ReiserJr_Magic.SequenceEqual(reiserSb.magic)) + xmlFSType.Type = "Reiser Jr. filesystem"; + xmlFSType.ClusterSize = reiserSb.blocksize; + xmlFSType.Clusters = reiserSb.block_count; + xmlFSType.FreeClusters = reiserSb.free_blocks; + xmlFSType.FreeClustersSpecified = true; + xmlFSType.Dirty = reiserSb.umount_state == 2; + if(reiserSb.version >= 2) + { + xmlFSType.VolumeName = Encoding.ASCII.GetString(reiserSb.label); + xmlFSType.VolumeSerial = reiserSb.uuid.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/DiscImageChef.Filesystems/Reiser4.cs b/DiscImageChef.Filesystems/Reiser4.cs new file mode 100644 index 00000000..5c5dd0f0 --- /dev/null +++ b/DiscImageChef.Filesystems/Reiser4.cs @@ -0,0 +1,203 @@ +// /*************************************************************************** +// The Disc Image Chef +// ---------------------------------------------------------------------------- +// +// Filename : Reiser4.cs +// Author(s) : Natalia Portillo +// +// Component : Component +// +// --[ Description ] ---------------------------------------------------------- +// +// Identifies the Reiser4 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-2016 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using System.Text; +using System.Linq; + +namespace DiscImageChef.Filesystems +{ + class Reiser4 : Filesystem + { + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct Reiser4_Superblock + { + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + public byte[] magic; + public ushort diskformat; + public ushort blocksize; + public Guid uuid; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + public byte[] label; + } + + readonly byte[] Reiser4_Magic = { 0x52, 0x65, 0x49, 0x73, 0x45, 0x72, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + const uint Reiser4_SuperOffset = 0x10000; + + public Reiser4() + { + Name = "Reiser4 Filesystem Plugin"; + PluginUUID = new Guid("301F2D00-E8D5-4F04-934E-81DFB21D15BA"); + } + + public Reiser4(ImagePlugins.ImagePlugin imagePlugin, ulong partitionStart, ulong partitionEnd) + { + Name = "Reiser4 Filesystem Plugin"; + PluginUUID = new Guid("301F2D00-E8D5-4F04-934E-81DFB21D15BA"); + } + + public override bool Identify(ImagePlugins.ImagePlugin imagePlugin, ulong partitionStart, ulong partitionEnd) + { + if(imagePlugin.GetSectorSize() < 512) + return false; + + uint sbAddr = Reiser4_SuperOffset / imagePlugin.GetSectorSize(); + if(sbAddr == 0) + sbAddr = 1; + + Reiser4_Superblock reiserSb = new Reiser4_Superblock(); + + uint sbSize = (uint)(Marshal.SizeOf(reiserSb) / imagePlugin.GetSectorSize()); + if(Marshal.SizeOf(reiserSb) % imagePlugin.GetSectorSize() != 0) + sbSize++; + + byte[] sector = imagePlugin.ReadSectors(partitionStart + sbAddr, sbSize); + if(sector.Length < Marshal.SizeOf(reiserSb)) + return false; + + IntPtr sbPtr = Marshal.AllocHGlobal(Marshal.SizeOf(reiserSb)); + Marshal.Copy(sector, 0, sbPtr, Marshal.SizeOf(reiserSb)); + reiserSb = (Reiser4_Superblock)Marshal.PtrToStructure(sbPtr, typeof(Reiser4_Superblock)); + Marshal.FreeHGlobal(sbPtr); + + return Reiser4_Magic.SequenceEqual(reiserSb.magic); + } + + public override void GetInformation(ImagePlugins.ImagePlugin imagePlugin, ulong partitionStart, ulong partitionEnd, out string information) + { + information = ""; + if(imagePlugin.GetSectorSize() < 512) + return; + + uint sbAddr = Reiser4_SuperOffset / imagePlugin.GetSectorSize(); + if(sbAddr == 0) + sbAddr = 1; + + Reiser4_Superblock reiserSb = new Reiser4_Superblock(); + + uint sbSize = (uint)(Marshal.SizeOf(reiserSb) / imagePlugin.GetSectorSize()); + if(Marshal.SizeOf(reiserSb) % imagePlugin.GetSectorSize() != 0) + sbSize++; + + byte[] sector = imagePlugin.ReadSectors(partitionStart + sbAddr, sbSize); + if(sector.Length < Marshal.SizeOf(reiserSb)) + return; + + IntPtr sbPtr = Marshal.AllocHGlobal(Marshal.SizeOf(reiserSb)); + Marshal.Copy(sector, 0, sbPtr, Marshal.SizeOf(reiserSb)); + reiserSb = (Reiser4_Superblock)Marshal.PtrToStructure(sbPtr, typeof(Reiser4_Superblock)); + Marshal.FreeHGlobal(sbPtr); + + if(!Reiser4_Magic.SequenceEqual(reiserSb.magic)) + return; + + StringBuilder sb = new StringBuilder(); + + sb.AppendLine("Reiser 4 filesystem"); + sb.AppendFormat("{0} bytes per block", reiserSb.blocksize).AppendLine(); + sb.AppendFormat("Volume disk format: {0}", reiserSb.diskformat).AppendLine(); + sb.AppendFormat("Volume UUID: {0}", reiserSb.uuid).AppendLine(); + sb.AppendFormat("Volume name: {0}", Encoding.ASCII.GetString(reiserSb.label)).AppendLine(); + + information = sb.ToString(); + + xmlFSType = new Schemas.FileSystemType(); + xmlFSType.Type = "Reiser 4 filesystem"; + xmlFSType.ClusterSize = reiserSb.blocksize; + xmlFSType.Clusters = (long)(((partitionEnd - partitionStart) * imagePlugin.GetSectorSize()) / reiserSb.blocksize); + xmlFSType.VolumeName = Encoding.ASCII.GetString(reiserSb.label); + xmlFSType.VolumeSerial = reiserSb.uuid.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 8490980d..532908a2 100644 --- a/README.md +++ b/README.md @@ -127,6 +127,7 @@ Supported file systems for identification and information only * IBM Journaling File System (JFS) * Flash-Friendly File System (F2FS) * NILFS2 +* Reiser file systems Supported checksums =================== diff --git a/TODO b/TODO index 3f472131..c996bc8c 100644 --- a/TODO +++ b/TODO @@ -20,7 +20,6 @@ Filesystem plugins: --- Add support for VxFS --- Add support for VMWare filesystem --- Add support for NwFS ---- Add support for Reiser filesystems --- Add support for Squashfs --- Add support for X-Box filesystems --- Add support for FAT+