示例#1
0
文件: AODOS.cs 项目: paulyc/Aaru
        public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information,
                                   Encoding encoding)
        {
            Encoding = Encoding.GetEncoding("koi8-r");
            byte[]    sector = imagePlugin.ReadSector(0);
            BootBlock bb     = Marshal.ByteArrayToStructureLittleEndian <BootBlock>(sector);

            var sbInformation = new StringBuilder();

            sbInformation.AppendLine("Alexander Osipov DOS file system");

            XmlFsType = new FileSystemType
            {
                Type                  = "Alexander Osipov DOS file system",
                Clusters              = imagePlugin.Info.Sectors,
                ClusterSize           = imagePlugin.Info.SectorSize,
                Files                 = bb.files,
                FilesSpecified        = true,
                FreeClusters          = imagePlugin.Info.Sectors - bb.usedSectors,
                FreeClustersSpecified = true,
                VolumeName            = StringHandlers.SpacePaddedToString(bb.volumeLabel, Encoding),
                Bootable              = true
            };

            sbInformation.AppendFormat("{0} files on volume", bb.files).AppendLine();
            sbInformation.AppendFormat("{0} used sectors on volume", bb.usedSectors).AppendLine();

            sbInformation.AppendFormat("Disk name: {0}", StringHandlers.CToString(bb.volumeLabel, Encoding)).
            AppendLine();

            information = sbInformation.ToString();
        }
示例#2
0
文件: AODOS.cs 项目: paulyc/Aaru
        public bool Identify(IMediaImage imagePlugin, Partition partition)
        {
            // Does AO-DOS support hard disks?
            if (partition.Start > 0)
            {
                return(false);
            }

            // How is it really?
            if (imagePlugin.Info.SectorSize != 512)
            {
                return(false);
            }

            // Does AO-DOS support any other kind of disk?
            if (imagePlugin.Info.Sectors != 800 &&
                imagePlugin.Info.Sectors != 1600)
            {
                return(false);
            }

            byte[]    sector = imagePlugin.ReadSector(0);
            BootBlock bb     = Marshal.ByteArrayToStructureLittleEndian <BootBlock>(sector);

            return(bb.identifier.SequenceEqual(_identifier));
        }
示例#3
0
        public bool Identify(IMediaImage imagePlugin, Partition partition)
        {
            if (partition.Start >= partition.End)
            {
                return(false);
            }

            BigEndianBitConverter.IsLittleEndian = BitConverter.IsLittleEndian;

            // Boot block is unless defined otherwise, 2 blocks
            // Funny, you may need boot block to find root block if it's not in standard place just to know size of
            // block size and then read the whole boot block.
            // However while you can set a block size different from the sector size on formatting, the bootblock block
            // size for floppies is the sector size, and for RDB is usually is the hard disk sector size,
            // so this is not entirely wrong...
            byte[]    sector = imagePlugin.ReadSectors(0 + partition.Start, 2);
            BootBlock bblk   = Marshal.ByteArrayToStructureBigEndian <BootBlock>(sector);

            // AROS boot floppies...
            if (sector.Length >= 512 && sector[510] == 0x55 && sector[511] == 0xAA &&
                (bblk.diskType & FFS_MASK) != FFS_MASK && (bblk.diskType & MUFS_MASK) != MUFS_MASK)
            {
                sector = imagePlugin.ReadSectors(1 + partition.Start, 2);
                bblk   = Marshal.ByteArrayToStructureBigEndian <BootBlock>(sector);
            }

            // Not FFS or MuFS?
            if ((bblk.diskType & FFS_MASK) != FFS_MASK && (bblk.diskType & MUFS_MASK) != MUFS_MASK)
            {
                return(false);
            }

            // Clear checksum on sector
            sector[4] = sector[5] = sector[6] = sector[7] = 0;
            uint bsum = AmigaBootChecksum(sector);

            DicConsole.DebugWriteLine("AmigaDOS plugin", "bblk.checksum = 0x{0:X8}", bblk.checksum);
            DicConsole.DebugWriteLine("AmigaDOS plugin", "bsum = 0x{0:X8}", bsum);

            ulong bRootPtr = 0;

            // If bootblock is correct, let's take its rootblock pointer
            if (bsum == bblk.checksum)
            {
                bRootPtr = bblk.root_ptr + partition.Start;
                DicConsole.DebugWriteLine("AmigaDOS plugin", "Bootblock points to {0} as Rootblock", bRootPtr);
            }

            ulong[] rootPtrs =
            {
                bRootPtr + partition.Start,                                      (partition.End - partition.Start + 1) / 2 + partition.Start - 2,
                (partition.End - partition.Start + 1) / 2 + partition.Start - 1,
                (partition.End - partition.Start + 1) / 2 +
                partition.Start,
                (partition.End - partition.Start + 1) / 2 + partition.Start + 4
            };

            RootBlock rblk = new RootBlock();

            // So to handle even number of sectors
            foreach (ulong rootPtr in rootPtrs.Where(rootPtr => rootPtr < partition.End && rootPtr >= partition.Start))
            {
                DicConsole.DebugWriteLine("AmigaDOS plugin", "Searching for Rootblock in sector {0}", rootPtr);

                sector = imagePlugin.ReadSector(rootPtr);

                rblk.type = BigEndianBitConverter.ToUInt32(sector, 0x00);
                DicConsole.DebugWriteLine("AmigaDOS plugin", "rblk.type = {0}", rblk.type);
                if (rblk.type != TYPE_HEADER)
                {
                    continue;
                }

                rblk.hashTableSize = BigEndianBitConverter.ToUInt32(sector, 0x0C);

                DicConsole.DebugWriteLine("AmigaDOS plugin", "rblk.hashTableSize = {0}", rblk.hashTableSize);

                uint blockSize       = (rblk.hashTableSize + 56) * 4;
                uint sectorsPerBlock = (uint)(blockSize / sector.Length);

                DicConsole.DebugWriteLine("AmigaDOS plugin", "blockSize = {0}", blockSize);
                DicConsole.DebugWriteLine("AmigaDOS plugin", "sectorsPerBlock = {0}", sectorsPerBlock);

                if (blockSize % sector.Length > 0)
                {
                    sectorsPerBlock++;
                }

                if (rootPtr + sectorsPerBlock >= partition.End)
                {
                    continue;
                }

                sector = imagePlugin.ReadSectors(rootPtr, sectorsPerBlock);

                // Clear checksum on sector
                rblk.checksum = BigEndianBitConverter.ToUInt32(sector, 20);
                sector[20]    = sector[21] = sector[22] = sector[23] = 0;
                uint rsum = AmigaChecksum(sector);

                DicConsole.DebugWriteLine("AmigaDOS plugin", "rblk.checksum = 0x{0:X8}", rblk.checksum);
                DicConsole.DebugWriteLine("AmigaDOS plugin", "rsum = 0x{0:X8}", rsum);

                rblk.sec_type = BigEndianBitConverter.ToUInt32(sector, sector.Length - 4);
                DicConsole.DebugWriteLine("AmigaDOS plugin", "rblk.sec_type = {0}", rblk.sec_type);

                if (rblk.sec_type == SUBTYPE_ROOT && rblk.checksum == rsum)
                {
                    return(true);
                }
            }

            return(false);
        }
示例#4
0
        public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information,
                                   Encoding encoding)
        {
            Encoding = encoding ?? Encoding.GetEncoding("iso-8859-1");
            StringBuilder sbInformation = new StringBuilder();

            XmlFsType   = new FileSystemType();
            information = null;
            BigEndianBitConverter.IsLittleEndian = BitConverter.IsLittleEndian;

            byte[] bootBlockSectors = imagePlugin.ReadSectors(0 + partition.Start, 2);

            BootBlock bootBlk = Marshal.ByteArrayToStructureBigEndian <BootBlock>(bootBlockSectors);

            bootBlk.bootCode = new byte[bootBlockSectors.Length - 12];
            Array.Copy(bootBlockSectors, 12, bootBlk.bootCode, 0, bootBlk.bootCode.Length);
            bootBlockSectors[4] = bootBlockSectors[5] = bootBlockSectors[6] = bootBlockSectors[7] = 0;
            uint bsum = AmigaBootChecksum(bootBlockSectors);

            ulong bRootPtr = 0;

            // If bootblock is correct, let's take its rootblock pointer
            if (bsum == bootBlk.checksum)
            {
                bRootPtr = bootBlk.root_ptr + partition.Start;
                DicConsole.DebugWriteLine("AmigaDOS plugin", "Bootblock points to {0} as Rootblock", bRootPtr);
            }

            ulong[] rootPtrs =
            {
                bRootPtr + partition.Start,                                      (partition.End - partition.Start + 1) / 2 + partition.Start - 2,
                (partition.End - partition.Start + 1) / 2 + partition.Start - 1,
                (partition.End - partition.Start + 1) / 2 +
                partition.Start,
                (partition.End - partition.Start + 1) / 2 + partition.Start + 4
            };

            RootBlock rootBlk = new RootBlock();

            byte[] rootBlockSector = null;

            bool rootFound = false;
            uint blockSize = 0;

            // So to handle even number of sectors
            foreach (ulong rootPtr in rootPtrs.Where(rootPtr => rootPtr < partition.End && rootPtr >= partition.Start))
            {
                DicConsole.DebugWriteLine("AmigaDOS plugin", "Searching for Rootblock in sector {0}", rootPtr);

                rootBlockSector = imagePlugin.ReadSector(rootPtr);

                rootBlk.type = BigEndianBitConverter.ToUInt32(rootBlockSector, 0x00);
                DicConsole.DebugWriteLine("AmigaDOS plugin", "rootBlk.type = {0}", rootBlk.type);
                if (rootBlk.type != TYPE_HEADER)
                {
                    continue;
                }

                rootBlk.hashTableSize = BigEndianBitConverter.ToUInt32(rootBlockSector, 0x0C);

                DicConsole.DebugWriteLine("AmigaDOS plugin", "rootBlk.hashTableSize = {0}", rootBlk.hashTableSize);

                blockSize = (rootBlk.hashTableSize + 56) * 4;
                uint sectorsPerBlock = (uint)(blockSize / rootBlockSector.Length);

                DicConsole.DebugWriteLine("AmigaDOS plugin", "blockSize = {0}", blockSize);
                DicConsole.DebugWriteLine("AmigaDOS plugin", "sectorsPerBlock = {0}", sectorsPerBlock);

                if (blockSize % rootBlockSector.Length > 0)
                {
                    sectorsPerBlock++;
                }

                if (rootPtr + sectorsPerBlock >= partition.End)
                {
                    continue;
                }

                rootBlockSector = imagePlugin.ReadSectors(rootPtr, sectorsPerBlock);

                // Clear checksum on sector
                rootBlk.checksum    = BigEndianBitConverter.ToUInt32(rootBlockSector, 20);
                rootBlockSector[20] = rootBlockSector[21] = rootBlockSector[22] = rootBlockSector[23] = 0;
                uint rsum = AmigaChecksum(rootBlockSector);

                DicConsole.DebugWriteLine("AmigaDOS plugin", "rootBlk.checksum = 0x{0:X8}", rootBlk.checksum);
                DicConsole.DebugWriteLine("AmigaDOS plugin", "rsum = 0x{0:X8}", rsum);

                rootBlk.sec_type = BigEndianBitConverter.ToUInt32(rootBlockSector, rootBlockSector.Length - 4);
                DicConsole.DebugWriteLine("AmigaDOS plugin", "rootBlk.sec_type = {0}", rootBlk.sec_type);

                if (rootBlk.sec_type != SUBTYPE_ROOT || rootBlk.checksum != rsum)
                {
                    continue;
                }

                rootBlockSector = imagePlugin.ReadSectors(rootPtr, sectorsPerBlock);
                rootFound       = true;
                break;
            }

            if (!rootFound)
            {
                return;
            }

            rootBlk = MarshalRootBlock(rootBlockSector);

            string diskName = StringHandlers.PascalToString(rootBlk.diskName, Encoding);

            switch (bootBlk.diskType & 0xFF)
            {
            case 0:
                sbInformation.Append("Amiga Original File System");
                XmlFsType.Type = "Amiga OFS";
                break;

            case 1:
                sbInformation.Append("Amiga Fast File System");
                XmlFsType.Type = "Amiga FFS";
                break;

            case 2:
                sbInformation.Append("Amiga Original File System with international characters");
                XmlFsType.Type = "Amiga OFS";
                break;

            case 3:
                sbInformation.Append("Amiga Fast File System with international characters");
                XmlFsType.Type = "Amiga FFS";
                break;

            case 4:
                sbInformation.Append("Amiga Original File System with directory cache");
                XmlFsType.Type = "Amiga OFS";
                break;

            case 5:
                sbInformation.Append("Amiga Fast File System with directory cache");
                XmlFsType.Type = "Amiga FFS";
                break;

            case 6:
                sbInformation.Append("Amiga Original File System with long filenames");
                XmlFsType.Type = "Amiga OFS2";
                break;

            case 7:
                sbInformation.Append("Amiga Fast File System with long filenames");
                XmlFsType.Type = "Amiga FFS2";
                break;
            }

            if ((bootBlk.diskType & 0x6D754600) == 0x6D754600)
            {
                sbInformation.Append(", with multi-user patches");
            }

            sbInformation.AppendLine();

            sbInformation.AppendFormat("Volume name: {0}", diskName).AppendLine();

            if (bootBlk.checksum == bsum)
            {
                Sha1Context sha1Ctx = new Sha1Context();
                sha1Ctx.Update(bootBlk.bootCode);
                sbInformation.AppendLine("Volume is bootable");
                sbInformation.AppendFormat("Boot code SHA1 is {0}", sha1Ctx.End()).AppendLine();
            }

            if (rootBlk.bitmapFlag == 0xFFFFFFFF)
            {
                sbInformation.AppendLine("Volume bitmap is valid");
            }

            if (rootBlk.bitmapExtensionBlock != 0x00000000 && rootBlk.bitmapExtensionBlock != 0xFFFFFFFF)
            {
                sbInformation.AppendFormat("Bitmap extension at block {0}", rootBlk.bitmapExtensionBlock).AppendLine();
            }

            if ((bootBlk.diskType & 0xFF) == 4 || (bootBlk.diskType & 0xFF) == 5)
            {
                sbInformation.AppendFormat("Directory cache starts at block {0}", rootBlk.extension).AppendLine();
            }

            ulong blocks = (partition.End - partition.Start + 1) * imagePlugin.Info.SectorSize / blockSize;

            sbInformation.AppendFormat("Volume block size is {0} bytes", blockSize).AppendLine();
            sbInformation.AppendFormat("Volume has {0} blocks", blocks).AppendLine();
            sbInformation.AppendFormat("Volume created on {0}",
                                       DateHandlers.AmigaToDateTime(rootBlk.cDays, rootBlk.cMins, rootBlk.cTicks))
            .AppendLine();
            sbInformation.AppendFormat("Volume last modified on {0}",
                                       DateHandlers.AmigaToDateTime(rootBlk.vDays, rootBlk.vMins, rootBlk.vTicks))
            .AppendLine();
            sbInformation.AppendFormat("Volume root directory last modified on on {0}",
                                       DateHandlers.AmigaToDateTime(rootBlk.rDays, rootBlk.rMins, rootBlk.rTicks))
            .AppendLine();
            sbInformation.AppendFormat("Root block checksum is 0x{0:X8}", rootBlk.checksum).AppendLine();
            information = sbInformation.ToString();

            XmlFsType.CreationDate =
                DateHandlers.AmigaToDateTime(rootBlk.cDays, rootBlk.cMins, rootBlk.cTicks);
            XmlFsType.CreationDateSpecified = true;
            XmlFsType.ModificationDate      =
                DateHandlers.AmigaToDateTime(rootBlk.vDays, rootBlk.vMins, rootBlk.vTicks);
            XmlFsType.ModificationDateSpecified = true;
            XmlFsType.Dirty       = rootBlk.bitmapFlag != 0xFFFFFFFF;
            XmlFsType.Clusters    = blocks;
            XmlFsType.ClusterSize = blockSize;
            XmlFsType.VolumeName  = diskName;
            XmlFsType.Bootable    = bsum == bootBlk.checksum;
            // Useful as a serial
            XmlFsType.VolumeSerial = $"{rootBlk.checksum:X8}";
        }
示例#5
0
        // TODO: BBC Master hard disks are untested...
        public bool Identify(IMediaImage imagePlugin, Partition partition)
        {
            if (partition.Start >= partition.End)
            {
                return(false);
            }

            ulong sbSector;
            uint  sectorsToRead;

            if (imagePlugin.Info.SectorSize < 256)
            {
                return(false);
            }

            byte[]   sector;
            GCHandle ptr;

            // ADFS-S, ADFS-M, ADFS-L, ADFS-D without partitions
            if (partition.Start == 0)
            {
                sector = imagePlugin.ReadSector(0);
                byte oldChk0 = AcornMapChecksum(sector, 255);
                ptr = GCHandle.Alloc(sector, GCHandleType.Pinned);
                OldMapSector0 oldMap0 =
                    (OldMapSector0)Marshal.PtrToStructure(ptr.AddrOfPinnedObject(), typeof(OldMapSector0));

                sector = imagePlugin.ReadSector(1);
                byte oldChk1 = AcornMapChecksum(sector, 255);
                ptr = GCHandle.Alloc(sector, GCHandleType.Pinned);
                OldMapSector1 oldMap1 =
                    (OldMapSector1)Marshal.PtrToStructure(ptr.AddrOfPinnedObject(), typeof(OldMapSector1));

                DicConsole.DebugWriteLine("ADFS Plugin", "oldMap0.checksum = {0}", oldMap0.checksum);
                DicConsole.DebugWriteLine("ADFS Plugin", "oldChk0 = {0}", oldChk0);

                // According to documentation map1 MUST start on sector 1. On ADFS-D it starts at 0x100, not on sector 1 (0x400)
                if (oldMap0.checksum == oldChk0 && oldMap1.checksum != oldChk1 && sector.Length >= 512)
                {
                    sector = imagePlugin.ReadSector(0);
                    byte[] tmp = new byte[256];
                    Array.Copy(sector, 256, tmp, 0, 256);
                    oldChk1 = AcornMapChecksum(tmp, 255);
                    ptr     = GCHandle.Alloc(tmp, GCHandleType.Pinned);
                    oldMap1 = (OldMapSector1)Marshal.PtrToStructure(ptr.AddrOfPinnedObject(), typeof(OldMapSector1));
                }

                DicConsole.DebugWriteLine("ADFS Plugin", "oldMap1.checksum = {0}", oldMap1.checksum);
                DicConsole.DebugWriteLine("ADFS Plugin", "oldChk1 = {0}", oldChk1);

                if (oldMap0.checksum == oldChk0 && oldMap1.checksum == oldChk1 && oldMap0.checksum != 0 &&
                    oldMap1.checksum != 0)
                {
                    sbSector      = OLD_DIRECTORY_LOCATION / imagePlugin.Info.SectorSize;
                    sectorsToRead = OLD_DIRECTORY_SIZE / imagePlugin.Info.SectorSize;
                    if (OLD_DIRECTORY_SIZE % imagePlugin.Info.SectorSize > 0)
                    {
                        sectorsToRead++;
                    }

                    sector = imagePlugin.ReadSectors(sbSector, sectorsToRead);
                    if (sector.Length > OLD_DIRECTORY_SIZE)
                    {
                        byte[] tmp = new byte[OLD_DIRECTORY_SIZE];
                        Array.Copy(sector, 0, tmp, 0, OLD_DIRECTORY_SIZE - 53);
                        Array.Copy(sector, sector.Length - 54, tmp, OLD_DIRECTORY_SIZE - 54, 53);
                        sector = tmp;
                    }
                    ptr = GCHandle.Alloc(sector, GCHandleType.Pinned);
                    OldDirectory oldRoot =
                        (OldDirectory)Marshal.PtrToStructure(ptr.AddrOfPinnedObject(), typeof(OldDirectory));
                    byte dirChk = AcornDirectoryChecksum(sector, (int)OLD_DIRECTORY_SIZE - 1);

                    DicConsole.DebugWriteLine("ADFS Plugin", "oldRoot.header.magic at 0x200 = {0}",
                                              oldRoot.header.magic);
                    DicConsole.DebugWriteLine("ADFS Plugin", "oldRoot.tail.magic at 0x200 = {0}", oldRoot.tail.magic);
                    DicConsole.DebugWriteLine("ADFS Plugin", "oldRoot.tail.checkByte at 0x200 = {0}",
                                              oldRoot.tail.checkByte);
                    DicConsole.DebugWriteLine("ADFS Plugin", "dirChk at 0x200 = {0}", dirChk);

                    if (oldRoot.header.magic == OLD_DIR_MAGIC && oldRoot.tail.magic == OLD_DIR_MAGIC ||
                        oldRoot.header.magic == NEW_DIR_MAGIC && oldRoot.tail.magic == NEW_DIR_MAGIC)
                    {
                        return(true);
                    }

                    // RISC OS says the old directory can't be in the new location, hard disks created by RISC OS 3.10 do that...
                    sbSector      = NEW_DIRECTORY_LOCATION / imagePlugin.Info.SectorSize;
                    sectorsToRead = NEW_DIRECTORY_SIZE / imagePlugin.Info.SectorSize;
                    if (NEW_DIRECTORY_SIZE % imagePlugin.Info.SectorSize > 0)
                    {
                        sectorsToRead++;
                    }

                    sector = imagePlugin.ReadSectors(sbSector, sectorsToRead);
                    if (sector.Length > OLD_DIRECTORY_SIZE)
                    {
                        byte[] tmp = new byte[OLD_DIRECTORY_SIZE];
                        Array.Copy(sector, 0, tmp, 0, OLD_DIRECTORY_SIZE - 53);
                        Array.Copy(sector, sector.Length - 54, tmp, OLD_DIRECTORY_SIZE - 54, 53);
                        sector = tmp;
                    }
                    ptr     = GCHandle.Alloc(sector, GCHandleType.Pinned);
                    oldRoot = (OldDirectory)Marshal.PtrToStructure(ptr.AddrOfPinnedObject(), typeof(OldDirectory));
                    dirChk  = AcornDirectoryChecksum(sector, (int)OLD_DIRECTORY_SIZE - 1);

                    DicConsole.DebugWriteLine("ADFS Plugin", "oldRoot.header.magic at 0x400 = {0}",
                                              oldRoot.header.magic);
                    DicConsole.DebugWriteLine("ADFS Plugin", "oldRoot.tail.magic at 0x400 = {0}", oldRoot.tail.magic);
                    DicConsole.DebugWriteLine("ADFS Plugin", "oldRoot.tail.checkByte at 0x400 = {0}",
                                              oldRoot.tail.checkByte);
                    DicConsole.DebugWriteLine("ADFS Plugin", "dirChk at 0x400 = {0}", dirChk);

                    if (oldRoot.header.magic == OLD_DIR_MAGIC && oldRoot.tail.magic == OLD_DIR_MAGIC ||
                        oldRoot.header.magic == NEW_DIR_MAGIC && oldRoot.tail.magic == NEW_DIR_MAGIC)
                    {
                        return(true);
                    }
                }
            }

            // Partitioning or not, new formats follow:
            DiscRecord drSb;

            sector = imagePlugin.ReadSector(partition.Start);
            byte newChk = NewMapChecksum(sector);

            DicConsole.DebugWriteLine("ADFS Plugin", "newChk = {0}", newChk);
            DicConsole.DebugWriteLine("ADFS Plugin", "map.zoneChecksum = {0}", sector[0]);

            sbSector      = BOOT_BLOCK_LOCATION / imagePlugin.Info.SectorSize;
            sectorsToRead = BOOT_BLOCK_SIZE / imagePlugin.Info.SectorSize;
            if (BOOT_BLOCK_SIZE % imagePlugin.Info.SectorSize > 0)
            {
                sectorsToRead++;
            }

            if (sbSector + partition.Start + sectorsToRead >= partition.End)
            {
                return(false);
            }

            byte[] bootSector = imagePlugin.ReadSectors(sbSector + partition.Start, sectorsToRead);
            int    bootChk    = 0;

            for (int i = 0; i < 0x1FF; i++)
            {
                bootChk = (bootChk & 0xFF) + (bootChk >> 8) + bootSector[i];
            }

            DicConsole.DebugWriteLine("ADFS Plugin", "bootChk = {0}", bootChk);
            DicConsole.DebugWriteLine("ADFS Plugin", "bBlock.checksum = {0}", bootSector[0x1FF]);

            if (newChk == sector[0] && newChk != 0)
            {
                ptr = GCHandle.Alloc(sector, GCHandleType.Pinned);
                NewMap nmap = (NewMap)Marshal.PtrToStructure(ptr.AddrOfPinnedObject(), typeof(NewMap));
                ptr.Free();
                drSb = nmap.discRecord;
            }
            else if (bootChk == bootSector[0x1FF])
            {
                ptr = GCHandle.Alloc(bootSector, GCHandleType.Pinned);
                BootBlock bBlock = (BootBlock)Marshal.PtrToStructure(ptr.AddrOfPinnedObject(), typeof(BootBlock));
                ptr.Free();
                drSb = bBlock.discRecord;
            }
            else
            {
                return(false);
            }

            DicConsole.DebugWriteLine("ADFS Plugin", "drSb.log2secsize = {0}", drSb.log2secsize);
            DicConsole.DebugWriteLine("ADFS Plugin", "drSb.idlen = {0}", drSb.idlen);
            DicConsole.DebugWriteLine("ADFS Plugin", "drSb.disc_size_high = {0}", drSb.disc_size_high);
            DicConsole.DebugWriteLine("ADFS Plugin", "drSb.disc_size = {0}", drSb.disc_size);
            DicConsole.DebugWriteLine("ADFS Plugin", "IsNullOrEmpty(drSb.reserved) = {0}",
                                      ArrayHelpers.ArrayIsNullOrEmpty(drSb.reserved));

            if (drSb.log2secsize < 8 || drSb.log2secsize > 10)
            {
                return(false);
            }

            if (drSb.idlen < drSb.log2secsize + 3 || drSb.idlen > 19)
            {
                return(false);
            }

            if (drSb.disc_size_high >> drSb.log2secsize != 0)
            {
                return(false);
            }

            if (!ArrayHelpers.ArrayIsNullOrEmpty(drSb.reserved))
            {
                return(false);
            }

            ulong bytes = drSb.disc_size_high;

            bytes *= 0x100000000;
            bytes += drSb.disc_size;

            return(bytes <= imagePlugin.Info.Sectors * imagePlugin.Info.SectorSize);
        }
示例#6
0
        // TODO: Find root directory on volumes with DiscRecord
        // TODO: Support big directories (ADFS-G?)
        // TODO: Find the real freemap on volumes with DiscRecord, as DiscRecord's discid may be empty but this one isn't
        public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information,
                                   Encoding encoding)
        {
            Encoding = encoding ?? Encoding.GetEncoding("iso-8859-1");
            StringBuilder sbInformation = new StringBuilder();

            XmlFsType   = new FileSystemType();
            information = "";

            ulong sbSector;

            byte[]   sector;
            uint     sectorsToRead;
            GCHandle ptr;
            ulong    bytes;

            // ADFS-S, ADFS-M, ADFS-L, ADFS-D without partitions
            if (partition.Start == 0)
            {
                sector = imagePlugin.ReadSector(0);
                byte oldChk0 = AcornMapChecksum(sector, 255);
                ptr = GCHandle.Alloc(sector, GCHandleType.Pinned);
                OldMapSector0 oldMap0 =
                    (OldMapSector0)Marshal.PtrToStructure(ptr.AddrOfPinnedObject(), typeof(OldMapSector0));

                sector = imagePlugin.ReadSector(1);
                byte oldChk1 = AcornMapChecksum(sector, 255);
                ptr = GCHandle.Alloc(sector, GCHandleType.Pinned);
                OldMapSector1 oldMap1 =
                    (OldMapSector1)Marshal.PtrToStructure(ptr.AddrOfPinnedObject(), typeof(OldMapSector1));

                // According to documentation map1 MUST start on sector 1. On ADFS-D it starts at 0x100, not on sector 1 (0x400)
                if (oldMap0.checksum == oldChk0 && oldMap1.checksum != oldChk1 && sector.Length >= 512)
                {
                    sector = imagePlugin.ReadSector(0);
                    byte[] tmp = new byte[256];
                    Array.Copy(sector, 256, tmp, 0, 256);
                    oldChk1 = AcornMapChecksum(tmp, 255);
                    ptr     = GCHandle.Alloc(tmp, GCHandleType.Pinned);
                    oldMap1 = (OldMapSector1)Marshal.PtrToStructure(ptr.AddrOfPinnedObject(), typeof(OldMapSector1));
                }

                if (oldMap0.checksum == oldChk0 && oldMap1.checksum == oldChk1 && oldMap0.checksum != 0 &&
                    oldMap1.checksum != 0)
                {
                    bytes = (ulong)((oldMap0.size[2] << 16) + (oldMap0.size[1] << 8) + oldMap0.size[0]) * 256;
                    byte[] namebytes = new byte[10];
                    for (int i = 0; i < 5; i++)
                    {
                        namebytes[i * 2]     = oldMap0.name[i];
                        namebytes[i * 2 + 1] = oldMap1.name[i];
                    }

                    XmlFsType = new FileSystemType
                    {
                        Bootable    = oldMap1.boot != 0, // Or not?
                        Clusters    = (long)(bytes / imagePlugin.Info.SectorSize),
                        ClusterSize = (int)imagePlugin.Info.SectorSize,
                        Type        = "Acorn Advanced Disc Filing System"
                    };

                    if (ArrayHelpers.ArrayIsNullOrEmpty(namebytes))
                    {
                        sbSector      = OLD_DIRECTORY_LOCATION / imagePlugin.Info.SectorSize;
                        sectorsToRead = OLD_DIRECTORY_SIZE / imagePlugin.Info.SectorSize;
                        if (OLD_DIRECTORY_SIZE % imagePlugin.Info.SectorSize > 0)
                        {
                            sectorsToRead++;
                        }

                        sector = imagePlugin.ReadSectors(sbSector, sectorsToRead);
                        if (sector.Length > OLD_DIRECTORY_SIZE)
                        {
                            byte[] tmp = new byte[OLD_DIRECTORY_SIZE];
                            Array.Copy(sector, 0, tmp, 0, OLD_DIRECTORY_SIZE - 53);
                            Array.Copy(sector, sector.Length - 54, tmp, OLD_DIRECTORY_SIZE - 54, 53);
                            sector = tmp;
                        }
                        ptr = GCHandle.Alloc(sector, GCHandleType.Pinned);
                        OldDirectory oldRoot =
                            (OldDirectory)Marshal.PtrToStructure(ptr.AddrOfPinnedObject(), typeof(OldDirectory));

                        if (oldRoot.header.magic == OLD_DIR_MAGIC && oldRoot.tail.magic == OLD_DIR_MAGIC)
                        {
                            namebytes = oldRoot.tail.name;
                        }
                        else
                        {
                            // RISC OS says the old directory can't be in the new location, hard disks created by RISC OS 3.10 do that...
                            sbSector      = NEW_DIRECTORY_LOCATION / imagePlugin.Info.SectorSize;
                            sectorsToRead = NEW_DIRECTORY_SIZE / imagePlugin.Info.SectorSize;
                            if (NEW_DIRECTORY_SIZE % imagePlugin.Info.SectorSize > 0)
                            {
                                sectorsToRead++;
                            }

                            sector = imagePlugin.ReadSectors(sbSector, sectorsToRead);
                            if (sector.Length > OLD_DIRECTORY_SIZE)
                            {
                                byte[] tmp = new byte[OLD_DIRECTORY_SIZE];
                                Array.Copy(sector, 0, tmp, 0, OLD_DIRECTORY_SIZE - 53);
                                Array.Copy(sector, sector.Length - 54, tmp, OLD_DIRECTORY_SIZE - 54, 53);
                                sector = tmp;
                            }
                            ptr     = GCHandle.Alloc(sector, GCHandleType.Pinned);
                            oldRoot = (OldDirectory)Marshal.PtrToStructure(ptr.AddrOfPinnedObject(),
                                                                           typeof(OldDirectory));

                            if (oldRoot.header.magic == OLD_DIR_MAGIC && oldRoot.tail.magic == OLD_DIR_MAGIC)
                            {
                                namebytes = oldRoot.tail.name;
                            }
                            else
                            {
                                sector = imagePlugin.ReadSectors(sbSector, sectorsToRead);
                                if (sector.Length > NEW_DIRECTORY_SIZE)
                                {
                                    byte[] tmp = new byte[NEW_DIRECTORY_SIZE];
                                    Array.Copy(sector, 0, tmp, 0, NEW_DIRECTORY_SIZE - 41);
                                    Array.Copy(sector, sector.Length - 42, tmp, NEW_DIRECTORY_SIZE - 42, 41);
                                    sector = tmp;
                                }
                                ptr = GCHandle.Alloc(sector, GCHandleType.Pinned);
                                NewDirectory newRoot =
                                    (NewDirectory)Marshal.PtrToStructure(ptr.AddrOfPinnedObject(),
                                                                         typeof(NewDirectory));
                                if (newRoot.header.magic == NEW_DIR_MAGIC && newRoot.tail.magic == NEW_DIR_MAGIC)
                                {
                                    namebytes = newRoot.tail.title;
                                }
                            }
                        }
                    }

                    sbInformation.AppendLine("Acorn Advanced Disc Filing System");
                    sbInformation.AppendLine();
                    sbInformation.AppendFormat("{0} bytes per sector", imagePlugin.Info.SectorSize).AppendLine();
                    sbInformation.AppendFormat("Volume has {0} bytes", bytes).AppendLine();
                    sbInformation.AppendFormat("Volume name: {0}", StringHandlers.CToString(namebytes, Encoding))
                    .AppendLine();
                    if (oldMap1.discId > 0)
                    {
                        XmlFsType.VolumeSerial = $"{oldMap1.discId:X4}";
                        sbInformation.AppendFormat("Volume ID: {0:X4}", oldMap1.discId).AppendLine();
                    }
                    if (!ArrayHelpers.ArrayIsNullOrEmpty(namebytes))
                    {
                        XmlFsType.VolumeName = StringHandlers.CToString(namebytes, Encoding);
                    }

                    information = sbInformation.ToString();

                    return;
                }
            }

            // Partitioning or not, new formats follow:
            DiscRecord drSb;

            sector = imagePlugin.ReadSector(partition.Start);
            byte newChk = NewMapChecksum(sector);

            DicConsole.DebugWriteLine("ADFS Plugin", "newChk = {0}", newChk);
            DicConsole.DebugWriteLine("ADFS Plugin", "map.zoneChecksum = {0}", sector[0]);

            sbSector      = BOOT_BLOCK_LOCATION / imagePlugin.Info.SectorSize;
            sectorsToRead = BOOT_BLOCK_SIZE / imagePlugin.Info.SectorSize;
            if (BOOT_BLOCK_SIZE % imagePlugin.Info.SectorSize > 0)
            {
                sectorsToRead++;
            }

            byte[] bootSector = imagePlugin.ReadSectors(sbSector + partition.Start, sectorsToRead);
            int    bootChk    = 0;

            for (int i = 0; i < 0x1FF; i++)
            {
                bootChk = (bootChk & 0xFF) + (bootChk >> 8) + bootSector[i];
            }

            DicConsole.DebugWriteLine("ADFS Plugin", "bootChk = {0}", bootChk);
            DicConsole.DebugWriteLine("ADFS Plugin", "bBlock.checksum = {0}", bootSector[0x1FF]);

            if (newChk == sector[0] && newChk != 0)
            {
                ptr = GCHandle.Alloc(sector, GCHandleType.Pinned);
                NewMap nmap = (NewMap)Marshal.PtrToStructure(ptr.AddrOfPinnedObject(), typeof(NewMap));
                ptr.Free();
                drSb = nmap.discRecord;
            }
            else if (bootChk == bootSector[0x1FF])
            {
                ptr = GCHandle.Alloc(bootSector, GCHandleType.Pinned);
                BootBlock bBlock = (BootBlock)Marshal.PtrToStructure(ptr.AddrOfPinnedObject(), typeof(BootBlock));
                ptr.Free();
                drSb = bBlock.discRecord;
            }
            else
            {
                return;
            }

            DicConsole.DebugWriteLine("ADFS Plugin", "drSb.log2secsize = {0}", drSb.log2secsize);
            DicConsole.DebugWriteLine("ADFS Plugin", "drSb.spt = {0}", drSb.spt);
            DicConsole.DebugWriteLine("ADFS Plugin", "drSb.heads = {0}", drSb.heads);
            DicConsole.DebugWriteLine("ADFS Plugin", "drSb.density = {0}", drSb.density);
            DicConsole.DebugWriteLine("ADFS Plugin", "drSb.idlen = {0}", drSb.idlen);
            DicConsole.DebugWriteLine("ADFS Plugin", "drSb.log2bpmb = {0}", drSb.log2bpmb);
            DicConsole.DebugWriteLine("ADFS Plugin", "drSb.skew = {0}", drSb.skew);
            DicConsole.DebugWriteLine("ADFS Plugin", "drSb.bootoption = {0}", drSb.bootoption);
            DicConsole.DebugWriteLine("ADFS Plugin", "drSb.lowsector = {0}", drSb.lowsector);
            DicConsole.DebugWriteLine("ADFS Plugin", "drSb.nzones = {0}", drSb.nzones);
            DicConsole.DebugWriteLine("ADFS Plugin", "drSb.zone_spare = {0}", drSb.zone_spare);
            DicConsole.DebugWriteLine("ADFS Plugin", "drSb.root = {0}", drSb.root);
            DicConsole.DebugWriteLine("ADFS Plugin", "drSb.disc_size = {0}", drSb.disc_size);
            DicConsole.DebugWriteLine("ADFS Plugin", "drSb.disc_id = {0}", drSb.disc_id);
            DicConsole.DebugWriteLine("ADFS Plugin", "drSb.disc_name = {0}",
                                      StringHandlers.CToString(drSb.disc_name, Encoding));
            DicConsole.DebugWriteLine("ADFS Plugin", "drSb.disc_type = {0}", drSb.disc_type);
            DicConsole.DebugWriteLine("ADFS Plugin", "drSb.disc_size_high = {0}", drSb.disc_size_high);
            DicConsole.DebugWriteLine("ADFS Plugin", "drSb.flags = {0}", drSb.flags);
            DicConsole.DebugWriteLine("ADFS Plugin", "drSb.nzones_high = {0}", drSb.nzones_high);
            DicConsole.DebugWriteLine("ADFS Plugin", "drSb.format_version = {0}", drSb.format_version);
            DicConsole.DebugWriteLine("ADFS Plugin", "drSb.root_size = {0}", drSb.root_size);

            if (drSb.log2secsize < 8 || drSb.log2secsize > 10)
            {
                return;
            }

            if (drSb.idlen < drSb.log2secsize + 3 || drSb.idlen > 19)
            {
                return;
            }

            if (drSb.disc_size_high >> drSb.log2secsize != 0)
            {
                return;
            }

            if (!ArrayHelpers.ArrayIsNullOrEmpty(drSb.reserved))
            {
                return;
            }

            bytes  = drSb.disc_size_high;
            bytes *= 0x100000000;
            bytes += drSb.disc_size;

            ulong zones = drSb.nzones_high;

            zones *= 0x100000000;
            zones += drSb.nzones;

            if (bytes > imagePlugin.Info.Sectors * imagePlugin.Info.SectorSize)
            {
                return;
            }

            XmlFsType = new FileSystemType();

            sbInformation.AppendLine("Acorn Advanced Disc Filing System");
            sbInformation.AppendLine();
            sbInformation.AppendFormat("Version {0}", drSb.format_version).AppendLine();
            sbInformation.AppendFormat("{0} bytes per sector", 1 << drSb.log2secsize).AppendLine();
            sbInformation.AppendFormat("{0} sectors per track", drSb.spt).AppendLine();
            sbInformation.AppendFormat("{0} heads", drSb.heads).AppendLine();
            sbInformation.AppendFormat("Density code: {0}", drSb.density).AppendLine();
            sbInformation.AppendFormat("Skew: {0}", drSb.skew).AppendLine();
            sbInformation.AppendFormat("Boot option: {0}", drSb.bootoption).AppendLine();
            // TODO: What the hell is this field refering to?
            sbInformation.AppendFormat("Root starts at frag {0}", drSb.root).AppendLine();
            //sbInformation.AppendFormat("Root is {0} bytes long", drSb.root_size).AppendLine();
            sbInformation.AppendFormat("Volume has {0} bytes in {1} zones", bytes, zones).AppendLine();
            sbInformation.AppendFormat("Volume flags: 0x{0:X4}", drSb.flags).AppendLine();
            if (drSb.disc_id > 0)
            {
                XmlFsType.VolumeSerial = $"{drSb.disc_id:X4}";
                sbInformation.AppendFormat("Volume ID: {0:X4}", drSb.disc_id).AppendLine();
            }
            if (!ArrayHelpers.ArrayIsNullOrEmpty(drSb.disc_name))
            {
                string discname = StringHandlers.CToString(drSb.disc_name, Encoding);
                XmlFsType.VolumeName = discname;
                sbInformation.AppendFormat("Volume name: {0}", discname).AppendLine();
            }

            information = sbInformation.ToString();

            XmlFsType.Bootable   |= drSb.bootoption != 0; // Or not?
            XmlFsType.Clusters    = (long)(bytes / (ulong)(1 << drSb.log2secsize));
            XmlFsType.ClusterSize = 1 << drSb.log2secsize;
            XmlFsType.Type        = "Acorn Advanced Disc Filing System";
        }
示例#7
0
文件: Info.cs 项目: paulyc/Aaru
        internal static string GetBootBlockInformation(byte[] bbSector, Encoding encoding)
        {
            if (bbSector is null ||
                bbSector.Length < 0x100)
            {
                return(null);
            }

            BootBlock bb = Marshal.ByteArrayToStructureBigEndian <BootBlock>(bbSector);

            if (bb.bbID != BB_MAGIC)
            {
                return(null);
            }

            var sb = new StringBuilder();

            sb.AppendLine("Boot Block:");

            if ((bb.bbVersion & 0x8000) > 0)
            {
                sb.AppendLine("Boot block is in new format.");

                if ((bb.bbVersion & 0x4000) > 0)
                {
                    sb.AppendLine("Boot block should be executed.");

                    if ((bb.bbVersion & 0x2000) > 0)
                    {
                        sb.
                        AppendFormat("System heap will be extended by {0} bytes and a {1} fraction of the available RAM",
                                     bb.bbSysHeapExtra, bb.bbSysHeapFract).AppendLine();
                    }
                }
            }
            else if ((bb.bbVersion & 0xFF) == 0x0D)
            {
                sb.AppendLine("Boot block should be executed.");
            }

            if (bb.bbPageFlags > 0)
            {
                sb.AppendLine("Allocate secondary sound buffer at boot.");
            }
            else if (bb.bbPageFlags < 0)
            {
                sb.AppendLine("Allocate secondary sound and video buffers at boot.");
            }

            sb.AppendFormat("System filename: {0}", StringHandlers.PascalToString(bb.bbSysName, encoding)).AppendLine();

            sb.AppendFormat("Finder filename: {0}", StringHandlers.PascalToString(bb.bbShellName, encoding)).
            AppendLine();

            sb.AppendFormat("Debugger filename: {0}", StringHandlers.PascalToString(bb.bbDbg1Name, encoding)).
            AppendLine();

            sb.AppendFormat("Disassembler filename: {0}", StringHandlers.PascalToString(bb.bbDbg2Name, encoding)).
            AppendLine();

            sb.AppendFormat("Startup screen filename: {0}", StringHandlers.PascalToString(bb.bbScreenName, encoding)).
            AppendLine();

            sb.AppendFormat("First program to execute at boot: {0}",
                            StringHandlers.PascalToString(bb.bbHelloName, encoding)).AppendLine();

            sb.AppendFormat("Clipboard filename: {0}", StringHandlers.PascalToString(bb.bbScrapName, encoding)).
            AppendLine();

            sb.AppendFormat("Maximum opened files: {0}", bb.bbCntFCBs * 4).AppendLine();
            sb.AppendFormat("Event queue size: {0}", bb.bbCntEvts).AppendLine();
            sb.AppendFormat("Heap size with 128KiB of RAM: {0} bytes", bb.bb128KSHeap).AppendLine();
            sb.AppendFormat("Heap size with 256KiB of RAM: {0} bytes", bb.bb256KSHeap).AppendLine();
            sb.AppendFormat("Heap size with 512KiB of RAM or more: {0} bytes", bb.bbSysHeapSize).AppendLine();

            return(sb.ToString());
        }