diff --git a/DiscImageChef.Filesystems/DiscImageChef.Filesystems.csproj b/DiscImageChef.Filesystems/DiscImageChef.Filesystems.csproj index 67b6463e..41f056ed 100644 --- a/DiscImageChef.Filesystems/DiscImageChef.Filesystems.csproj +++ b/DiscImageChef.Filesystems/DiscImageChef.Filesystems.csproj @@ -105,6 +105,7 @@ + diff --git a/DiscImageChef.Filesystems/PFS.cs b/DiscImageChef.Filesystems/PFS.cs new file mode 100644 index 00000000..7c929746 --- /dev/null +++ b/DiscImageChef.Filesystems/PFS.cs @@ -0,0 +1,300 @@ +// /*************************************************************************** +// The Disc Image Chef +// ---------------------------------------------------------------------------- +// +// Filename : AmigaDOS.cs +// Author(s) : Natalia Portillo +// +// Component : Amiga Fast File System plugin. +// +// --[ Description ] ---------------------------------------------------------- +// +// Identifies the Professional File System 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.Text; +using System.Collections.Generic; +using DiscImageChef.Console; +using System.Runtime.InteropServices; + +namespace DiscImageChef.Filesystems +{ + class PFS : Filesystem + { + public PFS() + { + Name = "Professional File System"; + PluginUUID = new Guid("68DE769E-D957-406A-8AE4-3781CA8CDA77"); + } + + public PFS(ImagePlugins.ImagePlugin imagePlugin, ulong partitionStart, ulong partitionEnd) + { + Name = "Professional File System"; + PluginUUID = new Guid("68DE769E-D957-406A-8AE4-3781CA8CDA77"); + } + + /// + /// Boot block, first 2 sectors + /// + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct BootBlock + { + /// + /// "PFS\1" disk type + /// + public uint diskType; + /// + /// Boot code, til completion + /// + public byte[] bootCode; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct RootBlock + { + /// + /// Disk type + /// + public uint diskType; + /// + /// Options + /// + public uint options; + /// + /// Current datestamp + /// + public uint datestamp; + /// + /// Volume creation day + /// + public ushort creationday; + /// + /// Volume creation minute + /// + public ushort creationminute; + /// + /// Volume creation tick + /// + public ushort creationtick; + /// + /// AmigaDOS protection bits + /// + public ushort protection; + /// + /// Volume label (Pascal string) + /// + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] + public byte[] diskname; + /// + /// Last reserved block + /// + public uint lastreserved; + /// + /// First reserved block + /// + public uint firstreserved; + /// + /// Free reserved blocks + /// + public uint reservedfree; + /// + /// Size of reserved blocks in bytes + /// + public ushort reservedblocksize; + /// + /// Blocks in rootblock, including bitmap + /// + public ushort rootblockclusters; + /// + /// Free blocks + /// + public uint blocksfree; + /// + /// Blocks that must be always free + /// + public uint alwaysfree; + /// + /// Current bitmapfield number for allocation + /// + public uint rovingPointer; + /// + /// Pointer to deldir + /// + public uint delDirPtr; + /// + /// Disk size in sectors + /// + public uint diskSize; + /// + /// Rootblock extension + /// + public uint extension; + /// + /// Unused + /// + public uint unused; + } + + /// + /// Identifier for AFS (PFS v1) + /// + const uint AFS_DISK = 0x41465301; + /// + /// Identifier for PFS v2 + /// + const uint PFS2_DISK = 0x50465302; + /// + /// Identifier for PFS v3 + /// + const uint PFS_DISK = 0x50465301; + /// + /// Identifier for multi-user AFS + /// + const uint MUAF_DISK = 0x6D754146; + /// + /// Identifier for multi-user PFS + /// + const uint MUPFS_DISK = 0x6D755046; + + public override bool Identify(ImagePlugins.ImagePlugin imagePlugin, ulong partitionStart, ulong partitionEnd) + { + if(partitionStart >= partitionEnd) + return false; + + BigEndianBitConverter.IsLittleEndian = BitConverter.IsLittleEndian; + + byte[] sector = imagePlugin.ReadSector(2 + partitionStart); + + uint magic = BigEndianBitConverter.ToUInt32(sector, 0x00); + + return magic == AFS_DISK || magic == PFS2_DISK || magic == PFS_DISK || magic == MUAF_DISK || magic == MUPFS_DISK; + } + + public override void GetInformation(ImagePlugins.ImagePlugin imagePlugin, ulong partitionStart, ulong partitionEnd, out string information) + { + byte[] RootBlockSector = imagePlugin.ReadSector(2 + partitionStart); + RootBlock rootBlock = new RootBlock(); + rootBlock = BigEndianMarshal.ByteArrayToStructureBigEndian(RootBlockSector); + + StringBuilder sbInformation = new StringBuilder(); + xmlFSType = new Schemas.FileSystemType(); + + switch(rootBlock.diskType) + { + case AFS_DISK: + case MUAF_DISK: + sbInformation.Append("Professional File System v1"); + xmlFSType.Type = "PFS v1"; + break; + case PFS2_DISK: + sbInformation.Append("Professional File System v2"); + xmlFSType.Type = "PFS v2"; + break; + case PFS_DISK: + case MUPFS_DISK: + sbInformation.Append("Professional File System v3"); + xmlFSType.Type = "PFS v3"; + break; + } + + if(rootBlock.diskType == MUAF_DISK || rootBlock.diskType == MUPFS_DISK) + sbInformation.Append(", with multi-user support"); + + sbInformation.AppendLine(); + + sbInformation.AppendFormat("Volume name: {0}", StringHandlers.PascalToString(rootBlock.diskname)).AppendLine(); + sbInformation.AppendFormat("Volume has {0} free sectors of {1}", rootBlock.blocksfree, rootBlock.diskSize).AppendLine(); + sbInformation.AppendFormat("Volme created on {0}", DateHandlers.AmigaToDateTime(rootBlock.creationday, rootBlock.creationminute, rootBlock.creationtick)).AppendLine(); + if(rootBlock.extension > 0) + sbInformation.AppendFormat("Root block extension resides at block {0}", rootBlock.extension).AppendLine(); + + information = sbInformation.ToString(); + + xmlFSType.CreationDate = DateHandlers.AmigaToDateTime(rootBlock.creationday, rootBlock.creationminute, rootBlock.creationtick); + xmlFSType.CreationDateSpecified = true; + xmlFSType.FreeClusters = rootBlock.blocksfree; + xmlFSType.FreeClustersSpecified = true; + xmlFSType.Clusters = rootBlock.diskSize / imagePlugin.GetSectorSize(); + xmlFSType.ClusterSize = (int)imagePlugin.GetSectorSize(); + } + + 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.Partitions/RDB.cs b/DiscImageChef.Partitions/RDB.cs index bd038d44..f2fd97ce 100644 --- a/DiscImageChef.Partitions/RDB.cs +++ b/DiscImageChef.Partitions/RDB.cs @@ -113,6 +113,10 @@ namespace DiscImageChef.PartPlugins /// const uint TypeIDPFS = 0x50465301; /// + /// Type ID for ProfessionalFileSystem, "PFS\2" + /// + const uint TypeIDPFS2 = 0x50465302; + /// /// Type ID for ProfessionalFileSystem, "muAF" /// const uint TypeIDPFSm = 0x6D754146; @@ -1379,6 +1383,7 @@ namespace DiscImageChef.PartPlugins case TypeIDAMIXReserved: return "Amiga UNIX Reserved partition (swap)"; case TypeIDPFS: + case TypeIDPFS2: case TypeIDPFSm: case TypeIDAFS: return "ProfessionalFileSystem"; diff --git a/README.md b/README.md index 58e350f9..e5309670 100644 --- a/README.md +++ b/README.md @@ -131,6 +131,7 @@ Supported file systems for identification and information only * NILFS2 * Reiser file systems * SGI XFS +* Professional File System Supported checksums =================== diff --git a/TODO b/TODO index 03e011f4..059c5a6b 100644 --- a/TODO +++ b/TODO @@ -10,7 +10,6 @@ Filesystem plugins: --- Add support for SFS filesystem ---- Add support for PFS3 filesystem --- Add support for Apple DOS filesystems --- Add support for CBM filesystem --- Add support for ZFS