// /*************************************************************************** // The Disc Image Chef // ---------------------------------------------------------------------------- // // Filename : RT11.cs // Author(s) : Natalia Portillo // // Component : RT-11 file system plugin. // // --[ Description ] ---------------------------------------------------------- // // Identifies the RT-11 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-2018 Natalia Portillo // ****************************************************************************/ using System; using System.Collections.Generic; using System.Runtime.InteropServices; using System.Text; using DiscImageChef.CommonTypes; using DiscImageChef.DiscImages; using Schemas; namespace DiscImageChef.Filesystems { // Information from http://www.trailing-edge.com/~shoppa/rt11fs/ // TODO: Implement Radix-50 public class RT11 : Filesystem { public RT11() { Name = "RT-11 file system"; PluginUuid = new Guid("DB3E2F98-8F98-463C-8126-E937843DA024"); CurrentEncoding = Encoding.GetEncoding("iso-8859-1"); } public RT11(Encoding encoding) { Name = "RT-11 file system"; PluginUuid = new Guid("DB3E2F98-8F98-463C-8126-E937843DA024"); CurrentEncoding = encoding ?? Encoding.GetEncoding("iso-8859-1"); } public RT11(ImagePlugin imagePlugin, Partition partition, Encoding encoding) { Name = "RT-11 file system"; PluginUuid = new Guid("DB3E2F98-8F98-463C-8126-E937843DA024"); CurrentEncoding = encoding ?? Encoding.GetEncoding("iso-8859-1"); } public override bool Identify(ImagePlugin imagePlugin, Partition partition) { if(1 + partition.Start >= partition.End) return false; if(imagePlugin.GetSectorSize() < 512) return false; byte[] magicB = new byte[12]; byte[] hbSector = imagePlugin.ReadSector(1 + partition.Start); Array.Copy(hbSector, 0x1F0, magicB, 0, 12); string magic = Encoding.ASCII.GetString(magicB); return magic == "DECRT11A "; } public override void GetInformation(ImagePlugin imagePlugin, Partition partition, out string information) { information = ""; StringBuilder sb = new StringBuilder(); byte[] hbSector = imagePlugin.ReadSector(1 + partition.Start); GCHandle handle = GCHandle.Alloc(hbSector, GCHandleType.Pinned); RT11HomeBlock homeblock = (RT11HomeBlock)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(RT11HomeBlock)); handle.Free(); /* TODO: Is this correct? * Assembler: * MOV address, R0 * CLR R1 * MOV #255., R2 * 10$: ADD (R0)+, R1 * SOB R2, 10$ * MOV 1,@R0 */ ushort check = 0; for(int i = 0; i < 512; i += 2) check += BitConverter.ToUInt16(hbSector, i); sb.AppendFormat("Volume format is {0}", StringHandlers.SpacePaddedToString(homeblock.format, CurrentEncoding)).AppendLine(); sb.AppendFormat("{0} sectors per cluster ({1} bytes)", homeblock.cluster, homeblock.cluster * 512) .AppendLine(); sb.AppendFormat("First directory segment starts at block {0}", homeblock.rootBlock).AppendLine(); sb.AppendFormat("Volume owner is \"{0}\"", StringHandlers.SpacePaddedToString(homeblock.ownername, CurrentEncoding)).AppendLine(); sb.AppendFormat("Volume label: \"{0}\"", StringHandlers.SpacePaddedToString(homeblock.volname, CurrentEncoding)).AppendLine(); sb.AppendFormat("Checksum: 0x{0:X4} (calculated 0x{1:X4})", homeblock.checksum, check).AppendLine(); byte[] bootBlock = imagePlugin.ReadSector(0); XmlFsType = new FileSystemType { Type = "RT-11", ClusterSize = homeblock.cluster * 512, Clusters = homeblock.cluster, VolumeName = StringHandlers.SpacePaddedToString(homeblock.volname, CurrentEncoding), Bootable = !ArrayHelpers.ArrayIsNullOrEmpty(bootBlock) }; 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; } [StructLayout(LayoutKind.Sequential, Pack = 1)] struct RT11HomeBlock { /// Bad block replacement table [MarshalAs(UnmanagedType.ByValArray, SizeConst = 130)] public byte[] badBlockTable; /// Unused [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] public byte[] unused; /// INITIALIZE/RESTORE data area [MarshalAs(UnmanagedType.ByValArray, SizeConst = 38)] public byte[] initArea; /// BUP information area [MarshalAs(UnmanagedType.ByValArray, SizeConst = 18)] public byte[] bupInformation; /// Empty [MarshalAs(UnmanagedType.ByValArray, SizeConst = 260)] public byte[] empty; /// Reserved [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] public byte[] reserved1; /// Reserved [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] public byte[] reserved2; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 14)] public byte[] empty2; /// Cluster size public ushort cluster; /// Block of the first directory segment public ushort rootBlock; /// "V3A" in Radix-50 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] public byte[] systemVersion; /// Name of the volume, 12 bytes [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)] public byte[] volname; /// Name of the volume owner, 12 bytes [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)] public byte[] ownername; /// RT11 defines it as "DECRT11A ", 12 bytes [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)] public byte[] format; /// Unused public ushort unused2; /// Checksum of preceding 255 words (16 bit units) public ushort checksum; } } }