diff --git a/DiscImageChef.Filesystems/ChangeLog b/DiscImageChef.Filesystems/ChangeLog index d7f136581..89c2e3e9d 100644 --- a/DiscImageChef.Filesystems/ChangeLog +++ b/DiscImageChef.Filesystems/ChangeLog @@ -1,3 +1,10 @@ +2016-09-02 Natalia Portillo + + * QNX6.cs: + * QNX4.cs: + * DiscImageChef.Filesystems.csproj: Adds support for QNX6 + filesystem, closes #18. + 2016-09-02 Natalia Portillo * QNX4.cs: diff --git a/DiscImageChef.Filesystems/DiscImageChef.Filesystems.csproj b/DiscImageChef.Filesystems/DiscImageChef.Filesystems.csproj index 3b174a636..a5fd281d7 100644 --- a/DiscImageChef.Filesystems/DiscImageChef.Filesystems.csproj +++ b/DiscImageChef.Filesystems/DiscImageChef.Filesystems.csproj @@ -98,6 +98,7 @@ + diff --git a/DiscImageChef.Filesystems/QNX4.cs b/DiscImageChef.Filesystems/QNX4.cs index c15411e93..8241cc887 100644 --- a/DiscImageChef.Filesystems/QNX4.cs +++ b/DiscImageChef.Filesystems/QNX4.cs @@ -9,7 +9,7 @@ // // --[ Description ] ---------------------------------------------------------- // -// Description +// Identifies the QNX4 filesystem and shows information. // // --[ License ] -------------------------------------------------------------- // @@ -31,13 +31,9 @@ // ****************************************************************************/ using System; - -using System; -using System.Text; using System.Collections.Generic; -using System.Runtime.InteropServices; -using DiscImageChef.Console; using System.Linq; +using System.Runtime.InteropServices; namespace DiscImageChef.Filesystems { diff --git a/DiscImageChef.Filesystems/QNX6.cs b/DiscImageChef.Filesystems/QNX6.cs new file mode 100644 index 000000000..b5347244b --- /dev/null +++ b/DiscImageChef.Filesystems/QNX6.cs @@ -0,0 +1,288 @@ +// /*************************************************************************** +// The Disc Image Chef +// ---------------------------------------------------------------------------- +// +// Filename : QNX6.cs +// Author(s) : Natalia Portillo +// +// Component : Component +// +// --[ Description ] ---------------------------------------------------------- +// +// Identifies the QNX6 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 QNX6 : Filesystem + { + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct QNX6_RootNode + { + public ulong size; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + public uint[] pointers; + public byte levels; + public byte mode; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)] + public byte[] spare; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct QNX6_SuperBlock + { + public uint magic; + public uint checksum; + public ulong serial; + public uint ctime; + public uint atime; + public uint flags; + public ushort version1; + public ushort version2; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + public byte[] volumeid; + public uint blockSize; + public uint numInodes; + public uint freeInodes; + public uint numBlocks; + public uint freeBlocks; + public uint allocationGroup; + public QNX6_RootNode inode; + public QNX6_RootNode bitmap; + public QNX6_RootNode longfile; + public QNX6_RootNode unknown; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct QNX6_AudiSuperBlock + { + public uint magic; + public uint checksum; + public ulong serial; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)] + public byte[] spare1; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)] + public byte[] id; + public uint blockSize; + public uint numInodes; + public uint freeInodes; + public uint numBlocks; + public uint freeBlocks; + public uint spare2; + public QNX6_RootNode inode; + public QNX6_RootNode bitmap; + public QNX6_RootNode longfile; + public QNX6_RootNode unknown; + } + + const uint QNX6_SuperBlockSize = 0x1000; + const uint QNX6_BootBlocksSize = 0x2000; + const uint QNX6_Magic = 0x68191122; + + public QNX6() + { + Name = "QNX6 Plugin"; + PluginUUID = new Guid("3E610EA2-4D08-4D70-8947-830CD4C74FC0"); + } + + public QNX6(ImagePlugins.ImagePlugin imagePlugin, ulong partitionStart, ulong partitionEnd) + { + Name = "QNX6 Plugin"; + PluginUUID = new Guid("3E610EA2-4D08-4D70-8947-830CD4C74FC0"); + } + + public override bool Identify(ImagePlugins.ImagePlugin imagePlugin, ulong partitionStart, ulong partitionEnd) + { + uint sectors = QNX6_SuperBlockSize / imagePlugin.GetSectorSize(); + uint bootSectors = QNX6_BootBlocksSize / imagePlugin.GetSectorSize(); + + byte[] audiSector = imagePlugin.ReadSectors(partitionStart, sectors); + byte[] sector = imagePlugin.ReadSectors(partitionStart + bootSectors, sectors); + if(sector.Length < QNX6_SuperBlockSize) + return false; + + QNX6_AudiSuperBlock audiSb = new QNX6_AudiSuperBlock(); + IntPtr audiPtr = Marshal.AllocHGlobal(Marshal.SizeOf(audiSb)); + Marshal.Copy(audiSector, 0, audiPtr, Marshal.SizeOf(audiSb)); + audiSb = (QNX6_AudiSuperBlock)Marshal.PtrToStructure(audiPtr, typeof(QNX6_AudiSuperBlock)); + Marshal.FreeHGlobal(audiPtr); + + QNX6_SuperBlock qnxSb = new QNX6_SuperBlock(); + IntPtr sbPtr = Marshal.AllocHGlobal(Marshal.SizeOf(qnxSb)); + Marshal.Copy(sector, 0, sbPtr, Marshal.SizeOf(qnxSb)); + qnxSb = (QNX6_SuperBlock)Marshal.PtrToStructure(sbPtr, typeof(QNX6_SuperBlock)); + Marshal.FreeHGlobal(sbPtr); + + return qnxSb.magic == QNX6_Magic || audiSb.magic == QNX6_Magic; + } + + public override void GetInformation(ImagePlugins.ImagePlugin imagePlugin, ulong partitionStart, ulong partitionEnd, out string information) + { + information = ""; + StringBuilder sb = new StringBuilder(); + uint sectors = QNX6_SuperBlockSize / imagePlugin.GetSectorSize(); + uint bootSectors = QNX6_BootBlocksSize / imagePlugin.GetSectorSize(); + + byte[] audiSector = imagePlugin.ReadSectors(partitionStart, sectors); + byte[] sector = imagePlugin.ReadSectors(partitionStart + bootSectors, sectors); + if(sector.Length < QNX6_SuperBlockSize) + return; + + QNX6_AudiSuperBlock audiSb = new QNX6_AudiSuperBlock(); + IntPtr audiPtr = Marshal.AllocHGlobal(Marshal.SizeOf(audiSb)); + Marshal.Copy(audiSector, 0, audiPtr, Marshal.SizeOf(audiSb)); + audiSb = (QNX6_AudiSuperBlock)Marshal.PtrToStructure(audiPtr, typeof(QNX6_AudiSuperBlock)); + Marshal.FreeHGlobal(audiPtr); + + QNX6_SuperBlock qnxSb = new QNX6_SuperBlock(); + IntPtr sbPtr = Marshal.AllocHGlobal(Marshal.SizeOf(qnxSb)); + Marshal.Copy(sector, 0, sbPtr, Marshal.SizeOf(qnxSb)); + qnxSb = (QNX6_SuperBlock)Marshal.PtrToStructure(sbPtr, typeof(QNX6_SuperBlock)); + Marshal.FreeHGlobal(sbPtr); + + bool audi = false || audiSb.magic == QNX6_Magic; + + if(audi) + { + sb.AppendLine("QNX6 (Audi) filesystem"); + sb.AppendFormat("Checksum: 0x{0:X8}", audiSb.checksum).AppendLine(); + sb.AppendFormat("Serial: 0x{0:X16}", audiSb.checksum).AppendLine(); + sb.AppendFormat("{0} bytes per block", audiSb.blockSize).AppendLine(); + sb.AppendFormat("{0} inodes free of {1}", audiSb.freeInodes, audiSb.numInodes).AppendLine(); + sb.AppendFormat("{0} blocks ({1} bytes) free of {2} ({3} bytes)", audiSb.freeBlocks, audiSb.freeBlocks * audiSb.blockSize, + audiSb.numBlocks, audiSb.numBlocks * audiSb.blockSize).AppendLine(); + + xmlFSType = new Schemas.FileSystemType(); + xmlFSType.Type = "QNX6 (Audi) filesystem"; + xmlFSType.Clusters = audiSb.numBlocks; + xmlFSType.ClusterSize = (int)audiSb.blockSize; + xmlFSType.Bootable = true; + xmlFSType.Files = audiSb.numInodes - audiSb.freeInodes; + xmlFSType.FilesSpecified = true; + xmlFSType.FreeClusters = audiSb.freeBlocks; + xmlFSType.FreeClustersSpecified = true; + //xmlFSType.VolumeName = Encoding.ASCII.GetString(audiSb.id); + xmlFSType.VolumeSerial = string.Format("{0:X16}", audiSb.serial); + + information = sb.ToString(); + return; + } + + sb.AppendLine("QNX6 filesystem"); + sb.AppendFormat("Checksum: 0x{0:X8}", qnxSb.checksum).AppendLine(); + sb.AppendFormat("Serial: 0x{0:X16}", qnxSb.checksum).AppendLine(); + sb.AppendFormat("Created on {0}", DateHandlers.UNIXUnsignedToDateTime(qnxSb.ctime)).AppendLine(); + sb.AppendFormat("Last mounted on {0}", DateHandlers.UNIXUnsignedToDateTime(qnxSb.atime)).AppendLine(); + sb.AppendFormat("Flags: 0x{0:X8}", qnxSb.flags).AppendLine(); + sb.AppendFormat("Version1: 0x{0:X4}", qnxSb.version1).AppendLine(); + sb.AppendFormat("Version2: 0x{0:X4}", qnxSb.version2).AppendLine(); + //sb.AppendFormat("Volume ID: \"{0}\"", Encoding.ASCII.GetString(qnxSb.volumeid)).AppendLine(); + sb.AppendFormat("{0} bytes per block", qnxSb.blockSize).AppendLine(); + sb.AppendFormat("{0} inodes free of {1}", qnxSb.freeInodes, qnxSb.numInodes).AppendLine(); + sb.AppendFormat("{0} blocks ({1} bytes) free of {2} ({3} bytes)", qnxSb.freeBlocks, qnxSb.freeBlocks * qnxSb.blockSize, + qnxSb.numBlocks, qnxSb.numBlocks * qnxSb.blockSize).AppendLine(); + + xmlFSType = new Schemas.FileSystemType(); + xmlFSType.Type = "QNX6 filesystem"; + xmlFSType.Clusters = qnxSb.numBlocks; + xmlFSType.ClusterSize = (int)qnxSb.blockSize; + xmlFSType.Bootable = true; + xmlFSType.Files = qnxSb.numInodes - qnxSb.freeInodes; + xmlFSType.FilesSpecified = true; + xmlFSType.FreeClusters = qnxSb.freeBlocks; + xmlFSType.FreeClustersSpecified = true; + //xmlFSType.VolumeName = Encoding.ASCII.GetString(qnxSb.volumeid); + xmlFSType.VolumeSerial = string.Format("{0:X16}", qnxSb.serial); + xmlFSType.CreationDate = DateHandlers.UNIXUnsignedToDateTime(qnxSb.ctime); + xmlFSType.CreationDateSpecified = true; + xmlFSType.ModificationDate = DateHandlers.UNIXUnsignedToDateTime(qnxSb.atime); + xmlFSType.ModificationDateSpecified = 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/README.md b/README.md index 8db5da2a0..852a3a32c 100644 --- a/README.md +++ b/README.md @@ -123,7 +123,7 @@ Supported file systems for identification and information only * B-tree file system (btrfs) * Apple File System (preliminary detection until on-disk layout is stable) * Microsoft Extended File Allocation Table (exFAT) -* QNX4 filesystem +* QNX4 and QNX6 filesystems Supported checksums =================== diff --git a/TODO b/TODO index 28e554934..bbff70adf 100644 --- a/TODO +++ b/TODO @@ -22,7 +22,6 @@ Filesystem plugins: --- Add support for NwFS --- Add support for JFS --- Add support for Reiser filesystems ---- Add support for QNX filesystems --- Add support for Squashfs --- Add support for X-Box filesystems --- Add support for FAT+