From 6e1649859ed321704f1d108789eda13f316f247d Mon Sep 17 00:00:00 2001 From: Natalia Portillo Date: Fri, 2 Sep 2016 06:49:59 +0100 Subject: [PATCH] * TODO: * README.md: * DiscImageChef.Filesystems/JFS.cs: * DiscImageChef.Filesystems/DiscImageChef.Filesystems.csproj: Adds support for IBM JFS, closes #20. * DiscImageChef.Helpers/DateHandlers.cs: Add supports for UNIX timestamps divided in seconds+nanoseconds. --- DiscImageChef.Filesystems/ChangeLog | 6 + .../DiscImageChef.Filesystems.csproj | 1 + DiscImageChef.Filesystems/JFS.cs | 318 ++++++++++++++++++ DiscImageChef.Helpers/ChangeLog | 5 + DiscImageChef.Helpers/DateHandlers.cs | 5 + README.md | 1 + TODO | 1 - 7 files changed, 336 insertions(+), 1 deletion(-) create mode 100644 DiscImageChef.Filesystems/JFS.cs diff --git a/DiscImageChef.Filesystems/ChangeLog b/DiscImageChef.Filesystems/ChangeLog index 2df009cd7..f276d7b1f 100644 --- a/DiscImageChef.Filesystems/ChangeLog +++ b/DiscImageChef.Filesystems/ChangeLog @@ -1,3 +1,9 @@ +2016-09-02 Natalia Portillo + + * JFS.cs: + * DiscImageChef.Filesystems.csproj: Adds support for IBM JFS, + closes #20. + 2016-09-02 Natalia Portillo * BTRFS.cs: Corrected information missing lines. diff --git a/DiscImageChef.Filesystems/DiscImageChef.Filesystems.csproj b/DiscImageChef.Filesystems/DiscImageChef.Filesystems.csproj index a5fd281d7..9bf245208 100644 --- a/DiscImageChef.Filesystems/DiscImageChef.Filesystems.csproj +++ b/DiscImageChef.Filesystems/DiscImageChef.Filesystems.csproj @@ -99,6 +99,7 @@ + diff --git a/DiscImageChef.Filesystems/JFS.cs b/DiscImageChef.Filesystems/JFS.cs new file mode 100644 index 000000000..8d0cca663 --- /dev/null +++ b/DiscImageChef.Filesystems/JFS.cs @@ -0,0 +1,318 @@ +// /*************************************************************************** +// The Disc Image Chef +// ---------------------------------------------------------------------------- +// +// Filename : JFS.cs +// Author(s) : Natalia Portillo +// +// Component : Component +// +// --[ Description ] ---------------------------------------------------------- +// +// Identifies the IBM JFS 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; + +namespace DiscImageChef.Filesystems +{ + class JFS : Filesystem + { + [Flags] + enum JFS_Flags : uint + { + Unicode = 0x00000001, + RemountRO = 0x00000002, + Continue = 0x00000004, + Panic = 0x00000008, + UserQuota = 0x00000010, + GroupQuota = 0x00000020, + NoJournal = 0x00000040, + Discard = 0x00000080, + GroupCommit = 0x00000100, + LazyCommit = 0x00000200, + Temporary = 0x00000400, + InlineLog = 0x00000800, + InlineMoving = 0x00001000, + BadSAIT = 0x00010000, + Sparse = 0x00020000, + DASDEnabled = 0x00040000, + DASDPrime = 0x00080000, + SwapBytes = 0x00100000, + DirIndex = 0x00200000, + Linux = 0x10000000, + DFS = 0x20000000, + OS2 = 0x40000000, + AIX = 0x80000000 + } + + [Flags] + enum JFS_State : uint + { + Clean = 0, + Mounted = 1, + Dirty = 2, + Logredo = 4, + Extendfs = 8 + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct JFS_Extent + { + /// + /// Leftmost 24 bits are extent length, rest 8 bits are most significant for + /// + public uint len_addr; + public uint addr2; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct JFS_TimeStruct + { + public uint tv_sec; + public uint tv_nsec; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct JFS_SuperBlock + { + public uint s_magic; + public uint s_version; + public ulong s_size; + public uint s_bsize; + public ushort s_l2bsize; + public ushort s_l2bfactor; + public uint s_pbsize; + public ushort s_l1pbsize; + public ushort pad; + public uint s_agsize; + public JFS_Flags s_flags; + public JFS_State s_state; + public uint s_compress; + public JFS_Extent s_ait2; + public JFS_Extent s_aim2; + public uint s_logdev; + public uint s_logserial; + public JFS_Extent s_logpxd; + public JFS_Extent s_fsckpxd; + public JFS_TimeStruct s_time; + public uint s_fsckloglen; + public sbyte s_fscklog; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 11)] + public byte[] s_fpack; + public ulong s_xsize; + public JFS_Extent s_xfsckpxd; + public JFS_Extent s_xlogpxd; + public Guid s_uuid; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + public byte[] s_label; + public Guid s_loguuid; + } + + const uint JFS_BootBlocksSize = 0x8000; + const uint JFS_Magic = 0x3153464A; + + public JFS() + { + Name = "JFS Plugin"; + PluginUUID = new Guid("D3BE2A41-8F28-4055-94DC-BB6C72A0E9C4"); + } + + public JFS(ImagePlugins.ImagePlugin imagePlugin, ulong partitionStart, ulong partitionEnd) + { + Name = "JFS Plugin"; + PluginUUID = new Guid("D3BE2A41-8F28-4055-94DC-BB6C72A0E9C4"); + } + + public override bool Identify(ImagePlugins.ImagePlugin imagePlugin, ulong partitionStart, ulong partitionEnd) + { + uint bootSectors = JFS_BootBlocksSize / imagePlugin.GetSectorSize(); + byte[] sector = imagePlugin.ReadSector(partitionStart + bootSectors); + if(sector.Length < 512) + return false; + + JFS_SuperBlock jfsSb = new JFS_SuperBlock(); + IntPtr sbPtr = Marshal.AllocHGlobal(Marshal.SizeOf(jfsSb)); + Marshal.Copy(sector, 0, sbPtr, Marshal.SizeOf(jfsSb)); + jfsSb = (JFS_SuperBlock)Marshal.PtrToStructure(sbPtr, typeof(JFS_SuperBlock)); + Marshal.FreeHGlobal(sbPtr); + + return jfsSb.s_magic == JFS_Magic; + } + + public override void GetInformation(ImagePlugins.ImagePlugin imagePlugin, ulong partitionStart, ulong partitionEnd, out string information) + { + information = ""; + StringBuilder sb = new StringBuilder(); + uint bootSectors = JFS_BootBlocksSize / imagePlugin.GetSectorSize(); + byte[] sector = imagePlugin.ReadSector(partitionStart + bootSectors); + if(sector.Length < 512) + return; + + JFS_SuperBlock jfsSb = new JFS_SuperBlock(); + IntPtr sbPtr = Marshal.AllocHGlobal(Marshal.SizeOf(jfsSb)); + Marshal.Copy(sector, 0, sbPtr, Marshal.SizeOf(jfsSb)); + jfsSb = (JFS_SuperBlock)Marshal.PtrToStructure(sbPtr, typeof(JFS_SuperBlock)); + Marshal.FreeHGlobal(sbPtr); + + sb.AppendLine("JFS filesystem"); + sb.AppendFormat("Version {0}", jfsSb.s_version).AppendLine(); + sb.AppendFormat("{0} blocks of {1} bytes", jfsSb.s_size, jfsSb.s_bsize).AppendLine(); + sb.AppendFormat("{0} blocks per allocation group", jfsSb.s_agsize).AppendLine(); + + if(jfsSb.s_flags.HasFlag(JFS_Flags.Unicode)) + sb.AppendLine("Volume uses Unicode for directory entries"); + if(jfsSb.s_flags.HasFlag(JFS_Flags.RemountRO)) + sb.AppendLine("Volume remounts read-only on error"); + if(jfsSb.s_flags.HasFlag(JFS_Flags.Continue)) + sb.AppendLine("Volume continues on error"); + if(jfsSb.s_flags.HasFlag(JFS_Flags.Panic)) + sb.AppendLine("Volume panics on error"); + if(jfsSb.s_flags.HasFlag(JFS_Flags.UserQuota)) + sb.AppendLine("Volume has user quotas enabled"); + if(jfsSb.s_flags.HasFlag(JFS_Flags.GroupQuota)) + sb.AppendLine("Volume has group quotas enabled"); + if(jfsSb.s_flags.HasFlag(JFS_Flags.NoJournal)) + sb.AppendLine("Volume is not using any journal"); + if(jfsSb.s_flags.HasFlag(JFS_Flags.Discard)) + sb.AppendLine("Volume sends TRIM/UNMAP commands to underlying device"); + if(jfsSb.s_flags.HasFlag(JFS_Flags.GroupCommit)) + sb.AppendLine("Volume commits in groups of 1"); + if(jfsSb.s_flags.HasFlag(JFS_Flags.LazyCommit)) + sb.AppendLine("Volume commits lazy"); + if(jfsSb.s_flags.HasFlag(JFS_Flags.Temporary)) + sb.AppendLine("Volume does not commit to log"); + if(jfsSb.s_flags.HasFlag(JFS_Flags.InlineLog)) + sb.AppendLine("Volume has log withing itself"); + if(jfsSb.s_flags.HasFlag(JFS_Flags.InlineMoving)) + sb.AppendLine("Volume has log withing itself and is moving it out"); + if(jfsSb.s_flags.HasFlag(JFS_Flags.BadSAIT)) + sb.AppendLine("Volume has bad current secondary ait"); + if(jfsSb.s_flags.HasFlag(JFS_Flags.Sparse)) + sb.AppendLine("Volume supports sparse files"); + if(jfsSb.s_flags.HasFlag(JFS_Flags.DASDEnabled)) + sb.AppendLine("Volume has DASD limits enabled"); + if(jfsSb.s_flags.HasFlag(JFS_Flags.DASDPrime)) + sb.AppendLine("Volume primes DASD on boot"); + if(jfsSb.s_flags.HasFlag(JFS_Flags.SwapBytes)) + sb.AppendLine("Volume is in a big-endian system"); + if(jfsSb.s_flags.HasFlag(JFS_Flags.DirIndex)) + sb.AppendLine("Volume has presistent indexes"); + if(jfsSb.s_flags.HasFlag(JFS_Flags.Linux)) + sb.AppendLine("Volume supports Linux"); + if(jfsSb.s_flags.HasFlag(JFS_Flags.DFS)) + sb.AppendLine("Volume supports DCE DFS LFS"); + if(jfsSb.s_flags.HasFlag(JFS_Flags.OS2)) + sb.AppendLine("Volume supports OS/2, and is case insensitive"); + if(jfsSb.s_flags.HasFlag(JFS_Flags.AIX)) + sb.AppendLine("Volume supports AIX"); + if(jfsSb.s_state != 0) + sb.AppendLine("Volume is dirty"); + sb.AppendFormat("Volume was last updated on {0}", DateHandlers.UNIXUnsignedToDateTime(jfsSb.s_time.tv_sec, jfsSb.s_time.tv_nsec)).AppendLine(); + if(jfsSb.s_version == 1) + sb.AppendFormat("Volume name: {0}", Encoding.ASCII.GetString(jfsSb.s_fpack)).AppendLine(); + else + sb.AppendFormat("Volume name: {0}", Encoding.ASCII.GetString(jfsSb.s_label)).AppendLine(); + sb.AppendFormat("Volume UUID: {0}", jfsSb.s_uuid).AppendLine(); + + xmlFSType = new Schemas.FileSystemType(); + xmlFSType.Type = "JFS filesystem"; + xmlFSType.Clusters = (long)jfsSb.s_size; + xmlFSType.ClusterSize = (int)jfsSb.s_bsize; + xmlFSType.Bootable = true; + if(jfsSb.s_version == 1) + xmlFSType.VolumeName = Encoding.ASCII.GetString(jfsSb.s_fpack); + else + xmlFSType.VolumeName = Encoding.ASCII.GetString(jfsSb.s_label); + xmlFSType.VolumeSerial = string.Format("{0}", jfsSb.s_uuid); + xmlFSType.ModificationDate = DateHandlers.UNIXUnsignedToDateTime(jfsSb.s_time.tv_sec, jfsSb.s_time.tv_nsec); + xmlFSType.ModificationDateSpecified = true; + if(jfsSb.s_state != 0) + xmlFSType.Dirty = true; + + information = sb.ToString(); + return; + } + + 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.Helpers/ChangeLog b/DiscImageChef.Helpers/ChangeLog index 1112561b6..4180fa755 100644 --- a/DiscImageChef.Helpers/ChangeLog +++ b/DiscImageChef.Helpers/ChangeLog @@ -1,3 +1,8 @@ +2016-09-02 Natalia Portillo + + * DateHandlers.cs: Add supports for UNIX timestamps divided in + seconds+nanoseconds. + 2016-08-26 Natalia Portillo * DateHandlers.cs: Added CP/M timestamp converter. diff --git a/DiscImageChef.Helpers/DateHandlers.cs b/DiscImageChef.Helpers/DateHandlers.cs index 4cc02b68f..6c1c563b3 100644 --- a/DiscImageChef.Helpers/DateHandlers.cs +++ b/DiscImageChef.Helpers/DateHandlers.cs @@ -64,6 +64,11 @@ namespace DiscImageChef return UNIXEpoch.AddSeconds(UNIXTimeStamp); } + public static DateTime UNIXUnsignedToDateTime(uint seconds, uint nanoseconds) + { + return UNIXEpoch.AddSeconds(seconds).AddTicks((long)nanoseconds / 100); + } + public static DateTime ISO9660ToDateTime(byte[] VDDateTime) { int year, month, day, hour, minute, second, hundredths; diff --git a/README.md b/README.md index 852a3a32c..eb2ade0a3 100644 --- a/README.md +++ b/README.md @@ -124,6 +124,7 @@ Supported file systems for identification and information only * Apple File System (preliminary detection until on-disk layout is stable) * Microsoft Extended File Allocation Table (exFAT) * QNX4 and QNX6 filesystems +* IBM Journaling File System (JFS) Supported checksums =================== diff --git a/TODO b/TODO index bbff70adf..3f472131e 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 JFS --- Add support for Reiser filesystems --- Add support for Squashfs --- Add support for X-Box filesystems