コード例 #1
0
ファイル: Write.cs プロジェクト: morefun0302/Aaru
        public bool Close()
        {
            if (!IsWriting)
            {
                ErrorMessage = "Image is not opened for writing";

                return(false);
            }

            byte[] hdr = new byte[Marshal.SizeOf <QedHeader>()];
            MemoryMarshal.Write(hdr, ref _qHdr);

            _writingStream.Seek(0, SeekOrigin.Begin);
            _writingStream.Write(hdr, 0, hdr.Length);

            _writingStream.Seek((long)_qHdr.l1_table_offset, SeekOrigin.Begin);
            byte[] l1TableB = MemoryMarshal.Cast <ulong, byte>(_l1Table).ToArray();
            _writingStream.Write(l1TableB, 0, l1TableB.Length);

            _writingStream.Flush();
            _writingStream.Close();

            IsWriting    = false;
            ErrorMessage = "";

            return(true);
        }
コード例 #2
0
ファイル: ext2FS.cs プロジェクト: paulyc/Aaru
        public bool Identify(IMediaImage imagePlugin, Partition partition)
        {
            ulong sbSectorOff = SB_POS / imagePlugin.Info.SectorSize;
            uint  sbOff       = SB_POS % imagePlugin.Info.SectorSize;

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

            int  sbSizeInBytes   = Marshal.SizeOf <SuperBlock>();
            uint sbSizeInSectors = (uint)(sbSizeInBytes / imagePlugin.Info.SectorSize);

            if (sbSizeInBytes % imagePlugin.Info.SectorSize > 0)
            {
                sbSizeInSectors++;
            }

            byte[] sbSector = imagePlugin.ReadSectors(sbSectorOff + partition.Start, sbSizeInSectors);
            byte[] sb       = new byte[sbSizeInBytes];

            if (sbOff + sbSizeInBytes > sbSector.Length)
            {
                return(false);
            }

            Array.Copy(sbSector, sbOff, sb, 0, sbSizeInBytes);

            ushort magic = BitConverter.ToUInt16(sb, 0x038);

            return(magic == EXT2_MAGIC || magic == EXT2_MAGIC_OLD);
        }
コード例 #3
0
        public bool Identify(IMediaImage imagePlugin, Partition partition)
        {
            if (imagePlugin.Info.SectorSize < 512)
            {
                return(false);
            }

            uint sbSize = (uint)(Marshal.SizeOf <Superblock>() / imagePlugin.Info.SectorSize);

            if (Marshal.SizeOf <Superblock>() % imagePlugin.Info.SectorSize != 0)
            {
                sbSize++;
            }

            byte[] sector = imagePlugin.ReadSectors(partition.Start, sbSize);

            if (sector.Length < Marshal.SizeOf <Superblock>())
            {
                return(false);
            }

            Superblock unicosSb = Marshal.ByteArrayToStructureBigEndian <Superblock>(sector);

            AaruConsole.DebugWriteLine("UNICOS plugin", "magic = 0x{0:X16} (expected 0x{1:X16})", unicosSb.s_magic,
                                       UNICOS_MAGIC);

            return(unicosSb.s_magic == UNICOS_MAGIC);
        }
コード例 #4
0
ファイル: ReFS.cs プロジェクト: paulyc/Aaru
        public bool Identify(IMediaImage imagePlugin, Partition partition)
        {
            uint sbSize = (uint)(Marshal.SizeOf <VolumeHeader>() / imagePlugin.Info.SectorSize);

            if (Marshal.SizeOf <VolumeHeader>() % imagePlugin.Info.SectorSize != 0)
            {
                sbSize++;
            }

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

            byte[] sector = imagePlugin.ReadSectors(partition.Start, sbSize);

            if (sector.Length < Marshal.SizeOf <VolumeHeader>())
            {
                return(false);
            }

            VolumeHeader vhdr = Marshal.ByteArrayToStructureLittleEndian <VolumeHeader>(sector);

            return(vhdr.identifier == FSRS && ArrayHelpers.ArrayIsNullOrEmpty(vhdr.mustBeZero) &&
                   vhdr.signature.SequenceEqual(_signature));
        }
コード例 #5
0
        public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information,
                                   Encoding encoding)
        {
            Encoding    = encoding ?? Encoding.GetEncoding("iso-8859-15");
            information = "";

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

            uint sbAddr = REISER4_SUPER_OFFSET / imagePlugin.Info.SectorSize;

            if (sbAddr == 0)
            {
                sbAddr = 1;
            }

            uint sbSize = (uint)(Marshal.SizeOf <Superblock>() / imagePlugin.Info.SectorSize);

            if (Marshal.SizeOf <Superblock>() % imagePlugin.Info.SectorSize != 0)
            {
                sbSize++;
            }

            byte[] sector = imagePlugin.ReadSectors(partition.Start + sbAddr, sbSize);

            if (sector.Length < Marshal.SizeOf <Superblock>())
            {
                return;
            }

            Superblock reiserSb = Marshal.ByteArrayToStructureLittleEndian <Superblock>(sector);

            if (!_magic.SequenceEqual(reiserSb.magic))
            {
                return;
            }

            var sb = new StringBuilder();

            sb.AppendLine("Reiser 4 filesystem");
            sb.AppendFormat("{0} bytes per block", reiserSb.blocksize).AppendLine();
            sb.AppendFormat("Volume disk format: {0}", reiserSb.diskformat).AppendLine();
            sb.AppendFormat("Volume UUID: {0}", reiserSb.uuid).AppendLine();
            sb.AppendFormat("Volume name: {0}", StringHandlers.CToString(reiserSb.label, Encoding)).AppendLine();

            information = sb.ToString();

            XmlFsType = new FileSystemType
            {
                Type         = "Reiser 4 filesystem",
                ClusterSize  = reiserSb.blocksize,
                Clusters     = ((partition.End - partition.Start) * imagePlugin.Info.SectorSize) / reiserSb.blocksize,
                VolumeName   = StringHandlers.CToString(reiserSb.label, Encoding),
                VolumeSerial = reiserSb.uuid.ToString()
            };
        }
コード例 #6
0
        public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information,
                                   Encoding encoding)
        {
            Encoding    = encoding ?? Encoding.GetEncoding("iso-8859-15");
            information = "";

            var sb = new StringBuilder();

            int  sbSizeInBytes   = Marshal.SizeOf <SuperBlock>();
            uint sbSizeInSectors = (uint)(sbSizeInBytes / imagePlugin.Info.SectorSize);

            if (sbSizeInBytes % imagePlugin.Info.SectorSize > 0)
            {
                sbSizeInSectors++;
            }

            byte[]     sbSector = imagePlugin.ReadSectors(partition.Start, sbSizeInSectors);
            SuperBlock supblk   = Marshal.ByteArrayToStructureLittleEndian <SuperBlock>(sbSector);

            sb.AppendFormat("{0} bytes per zone", supblk.s_zone_size).AppendLine();

            sb.AppendFormat("{0} zones in volume ({1} bytes)", supblk.s_nzones, supblk.s_nzones * supblk.s_zone_size).
            AppendLine();

            sb.AppendFormat("{0} inodes", supblk.s_ninodes).AppendLine();

            sb.AppendFormat("{0} data zones ({1} bytes)", supblk.s_ndatazones,
                            supblk.s_ndatazones * supblk.s_zone_size).AppendLine();

            sb.AppendFormat("{0} imap zones ({1} bytes)", supblk.s_imap_zones,
                            supblk.s_imap_zones * supblk.s_zone_size).AppendLine();

            sb.AppendFormat("{0} zmap zones ({1} bytes)", supblk.s_zmap_zones,
                            supblk.s_zmap_zones * supblk.s_zone_size).AppendLine();

            sb.AppendFormat("First data zone: {0}", supblk.s_firstdatazone).AppendLine();

            sb.AppendFormat("Maximum filesize is {0} bytes ({1} MiB)", supblk.s_max_size, supblk.s_max_size / 1048576).
            AppendLine();

            sb.AppendFormat("{0} zones reserved for kernel images ({1} bytes)", supblk.s_kernzones,
                            supblk.s_kernzones * supblk.s_zone_size).AppendLine();

            sb.AppendFormat("First kernel zone: {0}", supblk.s_firstkernzone).AppendLine();

            XmlFsType = new FileSystemType
            {
                Bootable    = !ArrayHelpers.ArrayIsNullOrEmpty(supblk.s_boot_segment),
                Clusters    = supblk.s_nzones,
                ClusterSize = supblk.s_zone_size,
                Type        = "Xia filesystem"
            };

            information = sb.ToString();
        }
コード例 #7
0
        public bool Identify(IMediaImage imagePlugin, Partition partition)
        {
            if (imagePlugin.Info.SectorSize < 256)
            {
                return(false);
            }

            // Documentation says ID should be sector 0
            // I've found that OS-9/X68000 has it on sector 4
            // I've read OS-9/Apple2 has it on sector 15
            foreach (int i in new[]
            {
                0, 4, 15
            })
            {
                ulong location = (ulong)i;

                uint sbSize = (uint)(Marshal.SizeOf <IdSector>() / imagePlugin.Info.SectorSize);

                if (Marshal.SizeOf <IdSector>() % imagePlugin.Info.SectorSize != 0)
                {
                    sbSize++;
                }

                if (partition.Start + location + sbSize >= imagePlugin.Info.Sectors)
                {
                    break;
                }

                byte[] sector = imagePlugin.ReadSectors(partition.Start + location, sbSize);

                if (sector.Length < Marshal.SizeOf <IdSector>())
                {
                    return(false);
                }

                IdSector    rbfSb     = Marshal.ByteArrayToStructureBigEndian <IdSector>(sector);
                NewIdSector rbf9000Sb = Marshal.ByteArrayToStructureBigEndian <NewIdSector>(sector);

                AaruConsole.DebugWriteLine("RBF plugin",
                                           "magic at {0} = 0x{1:X8} or 0x{2:X8} (expected 0x{3:X8} or 0x{4:X8})",
                                           location, rbfSb.dd_sync, rbf9000Sb.rid_sync, RBF_SYNC, RBF_CNYS);

                if (rbfSb.dd_sync == RBF_SYNC ||
                    rbf9000Sb.rid_sync == RBF_SYNC ||
                    rbf9000Sb.rid_sync == RBF_CNYS)
                {
                    return(true);
                }
            }

            return(false);
        }
コード例 #8
0
        public bool Identify(IMediaImage imagePlugin, Partition partition)
        {
            if (imagePlugin.Info.SectorSize < 512)
            {
                return(false);
            }

            for (ulong location = 0; location <= 8; location++)
            {
                uint sbSize = (uint)(Marshal.SizeOf <Superblock>() / imagePlugin.Info.SectorSize);

                if (Marshal.SizeOf <Superblock>() % imagePlugin.Info.SectorSize != 0)
                {
                    sbSize++;
                }

                if (partition.Start + location + sbSize >= imagePlugin.Info.Sectors)
                {
                    break;
                }

                byte[] sector = imagePlugin.ReadSectors(partition.Start + location, sbSize);

                if (sector.Length < Marshal.SizeOf <Superblock>())
                {
                    return(false);
                }

                Superblock locusSb = Marshal.ByteArrayToStructureLittleEndian <Superblock>(sector);

                AaruConsole.DebugWriteLine("Locus plugin", "magic at {1} = 0x{0:X8}", locusSb.s_magic, location);

                if (locusSb.s_magic == LOCUS_MAGIC ||
                    locusSb.s_magic == LOCUS_CIGAM ||
                    locusSb.s_magic == LOCUS_MAGIC_OLD ||
                    locusSb.s_magic == LOCUS_CIGAM_OLD)
                {
                    return(true);
                }
            }

            return(false);
        }
コード例 #9
0
        public bool Identify(IMediaImage imagePlugin, Partition partition)
        {
            int  sbSizeInBytes   = Marshal.SizeOf <SuperBlock>();
            uint sbSizeInSectors = (uint)(sbSizeInBytes / imagePlugin.Info.SectorSize);

            if (sbSizeInBytes % imagePlugin.Info.SectorSize > 0)
            {
                sbSizeInSectors++;
            }

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

            byte[]     sbSector = imagePlugin.ReadSectors(partition.Start, sbSizeInSectors);
            SuperBlock supblk   = Marshal.ByteArrayToStructureLittleEndian <SuperBlock>(sbSector);

            return(supblk.s_magic == XIAFS_SUPER_MAGIC);
        }
コード例 #10
0
ファイル: dump.cs プロジェクト: morefun0302/Aaru
        public bool Identify(IMediaImage imagePlugin, Partition partition)
        {
            if (imagePlugin.Info.SectorSize < 512)
            {
                return(false);
            }

            // It should be start of a tape or floppy or file
            if (partition.Start != 0)
            {
                return(false);
            }

            uint sbSize = (uint)(Marshal.SizeOf <s_spcl>() / imagePlugin.Info.SectorSize);

            if (Marshal.SizeOf <s_spcl>() % imagePlugin.Info.SectorSize != 0)
            {
                sbSize++;
            }

            byte[] sector = imagePlugin.ReadSectors(partition.Start, sbSize);

            if (sector.Length < Marshal.SizeOf <s_spcl>())
            {
                return(false);
            }

            spcl16   oldHdr = Marshal.ByteArrayToStructureLittleEndian <spcl16>(sector);
            spcl_aix aixHdr = Marshal.ByteArrayToStructureLittleEndian <spcl_aix>(sector);
            s_spcl   newHdr = Marshal.ByteArrayToStructureLittleEndian <s_spcl>(sector);

            AaruConsole.DebugWriteLine("dump(8) plugin", "old magic = 0x{0:X8}", oldHdr.c_magic);
            AaruConsole.DebugWriteLine("dump(8) plugin", "aix magic = 0x{0:X8}", aixHdr.c_magic);
            AaruConsole.DebugWriteLine("dump(8) plugin", "new magic = 0x{0:X8}", newHdr.c_magic);

            return(oldHdr.c_magic == OFS_MAGIC || aixHdr.c_magic == XIX_MAGIC || aixHdr.c_magic == XIX_CIGAM ||
                   newHdr.c_magic == OFS_MAGIC || newHdr.c_magic == NFS_MAGIC || newHdr.c_magic == OFS_CIGAM ||
                   newHdr.c_magic == NFS_CIGAM || newHdr.c_magic == UFS2_MAGIC || newHdr.c_magic == UFS2_CIGAM);
        }
コード例 #11
0
        public bool Identify(IMediaImage imagePlugin, Partition partition)
        {
            if (imagePlugin.Info.SectorSize < 512)
            {
                return(false);
            }

            uint sbAddr = REISER_SUPER_OFFSET / imagePlugin.Info.SectorSize;

            if (sbAddr == 0)
            {
                sbAddr = 1;
            }

            uint sbSize = (uint)(Marshal.SizeOf <Superblock>() / imagePlugin.Info.SectorSize);

            if (Marshal.SizeOf <Superblock>() % imagePlugin.Info.SectorSize != 0)
            {
                sbSize++;
            }

            if (partition.Start + sbAddr + sbSize >= partition.End)
            {
                return(false);
            }

            byte[] sector = imagePlugin.ReadSectors(partition.Start + sbAddr, sbSize);

            if (sector.Length < Marshal.SizeOf <Superblock>())
            {
                return(false);
            }

            Superblock reiserSb = Marshal.ByteArrayToStructureLittleEndian <Superblock>(sector);

            return(_magic35.SequenceEqual(reiserSb.magic) || _magic36.SequenceEqual(reiserSb.magic) ||
                   _magicJr.SequenceEqual(reiserSb.magic));
        }
コード例 #12
0
        public bool Identify(IMediaImage imagePlugin, Partition partition)
        {
            if (imagePlugin.Info.SectorSize < F2FS_MIN_SECTOR ||
                imagePlugin.Info.SectorSize > F2FS_MAX_SECTOR)
            {
                return(false);
            }

            uint sbAddr = F2FS_SUPER_OFFSET / imagePlugin.Info.SectorSize;

            if (sbAddr == 0)
            {
                sbAddr = 1;
            }

            uint sbSize = (uint)(Marshal.SizeOf <Superblock>() / imagePlugin.Info.SectorSize);

            if (Marshal.SizeOf <Superblock>() % imagePlugin.Info.SectorSize != 0)
            {
                sbSize++;
            }

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

            byte[] sector = imagePlugin.ReadSectors(partition.Start + sbAddr, sbSize);

            if (sector.Length < Marshal.SizeOf <Superblock>())
            {
                return(false);
            }

            Superblock sb = Marshal.ByteArrayToStructureLittleEndian <Superblock>(sector);

            return(sb.magic == F2FS_MAGIC);
        }
コード例 #13
0
        public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information,
                                   Encoding encoding)
        {
            Encoding    = encoding ?? Encoding.GetEncoding("iso-8859-15");
            information = "";

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

            uint sbAddr = REISER_SUPER_OFFSET / imagePlugin.Info.SectorSize;

            if (sbAddr == 0)
            {
                sbAddr = 1;
            }

            uint sbSize = (uint)(Marshal.SizeOf <Superblock>() / imagePlugin.Info.SectorSize);

            if (Marshal.SizeOf <Superblock>() % imagePlugin.Info.SectorSize != 0)
            {
                sbSize++;
            }

            byte[] sector = imagePlugin.ReadSectors(partition.Start + sbAddr, sbSize);

            if (sector.Length < Marshal.SizeOf <Superblock>())
            {
                return;
            }

            Superblock reiserSb = Marshal.ByteArrayToStructureLittleEndian <Superblock>(sector);

            if (!_magic35.SequenceEqual(reiserSb.magic) &&
                !_magic36.SequenceEqual(reiserSb.magic) &&
                !_magicJr.SequenceEqual(reiserSb.magic))
            {
                return;
            }

            var sb = new StringBuilder();

            if (_magic35.SequenceEqual(reiserSb.magic))
            {
                sb.AppendLine("Reiser 3.5 filesystem");
            }
            else if (_magic36.SequenceEqual(reiserSb.magic))
            {
                sb.AppendLine("Reiser 3.6 filesystem");
            }
            else if (_magicJr.SequenceEqual(reiserSb.magic))
            {
                sb.AppendLine("Reiser Jr. filesystem");
            }

            sb.AppendFormat("Volume has {0} blocks with {1} blocks free", reiserSb.block_count, reiserSb.free_blocks).
            AppendLine();

            sb.AppendFormat("{0} bytes per block", reiserSb.blocksize).AppendLine();
            sb.AppendFormat("Root directory resides on block {0}", reiserSb.root_block).AppendLine();

            if (reiserSb.umount_state == 2)
            {
                sb.AppendLine("Volume has not been cleanly umounted");
            }

            sb.AppendFormat("Volume last checked on {0}", DateHandlers.UnixUnsignedToDateTime(reiserSb.last_check)).
            AppendLine();

            if (reiserSb.version >= 2)
            {
                sb.AppendFormat("Volume UUID: {0}", reiserSb.uuid).AppendLine();
                sb.AppendFormat("Volume name: {0}", Encoding.GetString(reiserSb.label)).AppendLine();
            }

            information = sb.ToString();

            XmlFsType = new FileSystemType();

            if (_magic35.SequenceEqual(reiserSb.magic))
            {
                XmlFsType.Type = "Reiser 3.5 filesystem";
            }
            else if (_magic36.SequenceEqual(reiserSb.magic))
            {
                XmlFsType.Type = "Reiser 3.6 filesystem";
            }
            else if (_magicJr.SequenceEqual(reiserSb.magic))
            {
                XmlFsType.Type = "Reiser Jr. filesystem";
            }

            XmlFsType.ClusterSize           = reiserSb.blocksize;
            XmlFsType.Clusters              = reiserSb.block_count;
            XmlFsType.FreeClusters          = reiserSb.free_blocks;
            XmlFsType.FreeClustersSpecified = true;
            XmlFsType.Dirty = reiserSb.umount_state == 2;

            if (reiserSb.version < 2)
            {
                return;
            }

            XmlFsType.VolumeName   = Encoding.GetString(reiserSb.label);
            XmlFsType.VolumeSerial = reiserSb.uuid.ToString();
        }
コード例 #14
0
ファイル: Read.cs プロジェクト: morefun0302/Aaru
        public bool Open(IFilter imageFilter)
        {
            Stream stream = imageFilter.GetDataForkStream();

            stream.Seek(0, SeekOrigin.Begin);

            if (stream.Length < 512)
            {
                return(false);
            }

            byte[] qHdrB = new byte[Marshal.SizeOf <QCow2Header>()];
            stream.Read(qHdrB, 0, Marshal.SizeOf <QCow2Header>());
            _qHdr = Marshal.SpanToStructureBigEndian <QCow2Header>(qHdrB);

            AaruConsole.DebugWriteLine("QCOW plugin", "qHdr.magic = 0x{0:X8}", _qHdr.magic);
            AaruConsole.DebugWriteLine("QCOW plugin", "qHdr.version = {0}", _qHdr.version);
            AaruConsole.DebugWriteLine("QCOW plugin", "qHdr.backing_file_offset = {0}", _qHdr.backing_file_offset);
            AaruConsole.DebugWriteLine("QCOW plugin", "qHdr.backing_file_size = {0}", _qHdr.backing_file_size);
            AaruConsole.DebugWriteLine("QCOW plugin", "qHdr.cluster_bits = {0}", _qHdr.cluster_bits);
            AaruConsole.DebugWriteLine("QCOW plugin", "qHdr.size = {0}", _qHdr.size);
            AaruConsole.DebugWriteLine("QCOW plugin", "qHdr.crypt_method = {0}", _qHdr.crypt_method);
            AaruConsole.DebugWriteLine("QCOW plugin", "qHdr.l1_size = {0}", _qHdr.l1_size);
            AaruConsole.DebugWriteLine("QCOW plugin", "qHdr.l1_table_offset = {0}", _qHdr.l1_table_offset);
            AaruConsole.DebugWriteLine("QCOW plugin", "qHdr.refcount_table_offset = {0}", _qHdr.refcount_table_offset);

            AaruConsole.DebugWriteLine("QCOW plugin", "qHdr.refcount_table_clusters = {0}",
                                       _qHdr.refcount_table_clusters);

            AaruConsole.DebugWriteLine("QCOW plugin", "qHdr.nb_snapshots = {0}", _qHdr.nb_snapshots);
            AaruConsole.DebugWriteLine("QCOW plugin", "qHdr.snapshots_offset = {0}", _qHdr.snapshots_offset);

            if (_qHdr.version >= QCOW_VERSION3)
            {
                AaruConsole.DebugWriteLine("QCOW plugin", "qHdr.features = {0:X}", _qHdr.features);
                AaruConsole.DebugWriteLine("QCOW plugin", "qHdr.compat_features = {0:X}", _qHdr.compat_features);
                AaruConsole.DebugWriteLine("QCOW plugin", "qHdr.autoclear_features = {0:X}", _qHdr.autoclear_features);
                AaruConsole.DebugWriteLine("QCOW plugin", "qHdr.refcount_order = {0}", _qHdr.refcount_order);
                AaruConsole.DebugWriteLine("QCOW plugin", "qHdr.header_length = {0}", _qHdr.header_length);

                if ((_qHdr.features & QCOW_FEATURE_MASK) != 0)
                {
                    throw new
                          ImageNotSupportedException($"Unknown incompatible features {_qHdr.features & QCOW_FEATURE_MASK:X} enabled, not proceeding.");
                }
            }

            if (_qHdr.size <= 1)
            {
                throw new ArgumentOutOfRangeException(nameof(_qHdr.size), "Image size is too small");
            }

            if (_qHdr.cluster_bits < 9 ||
                _qHdr.cluster_bits > 16)
            {
                throw new ArgumentOutOfRangeException(nameof(_qHdr.cluster_bits),
                                                      "Cluster size must be between 512 bytes and 64 Kbytes");
            }

            if (_qHdr.crypt_method > QCOW_ENCRYPTION_AES)
            {
                throw new ArgumentOutOfRangeException(nameof(_qHdr.crypt_method), "Invalid encryption method");
            }

            if (_qHdr.crypt_method > QCOW_ENCRYPTION_NONE)
            {
                throw new NotImplementedException("AES encrypted images not yet supported");
            }

            if (_qHdr.backing_file_offset != 0)
            {
                throw new NotImplementedException("Differencing images not yet supported");
            }

            _clusterSize    = 1 << (int)_qHdr.cluster_bits;
            _clusterSectors = 1 << ((int)_qHdr.cluster_bits - 9);
            _l2Bits         = (int)(_qHdr.cluster_bits - 3);
            _l2Size         = 1 << _l2Bits;

            AaruConsole.DebugWriteLine("QCOW plugin", "qHdr.clusterSize = {0}", _clusterSize);
            AaruConsole.DebugWriteLine("QCOW plugin", "qHdr.clusterSectors = {0}", _clusterSectors);
            AaruConsole.DebugWriteLine("QCOW plugin", "qHdr.qHdr.l1_size = {0}", _qHdr.l1_size);
            AaruConsole.DebugWriteLine("QCOW plugin", "qHdr.l2Size = {0}", _l2Size);
            AaruConsole.DebugWriteLine("QCOW plugin", "qHdr.sectors = {0}", _imageInfo.Sectors);

            byte[] l1TableB = new byte[_qHdr.l1_size * 8];
            stream.Seek((long)_qHdr.l1_table_offset, SeekOrigin.Begin);
            stream.Read(l1TableB, 0, (int)_qHdr.l1_size * 8);
            _l1Table = MemoryMarshal.Cast <byte, ulong>(l1TableB).ToArray();
            AaruConsole.DebugWriteLine("QCOW plugin", "Reading L1 table");

            for (long i = 0; i < _l1Table.LongLength; i++)
            {
                _l1Table[i] = Swapping.Swap(_l1Table[i]);
            }

            _l1Mask = 0;
            int c = 0;

            _l1Shift = (int)(_l2Bits + _qHdr.cluster_bits);

            for (int i = 0; i < 64; i++)
            {
                _l1Mask <<= 1;

                if (c >= 64 - _l1Shift)
                {
                    continue;
                }

                _l1Mask += 1;
                c++;
            }

            _l2Mask = 0;

            for (int i = 0; i < _l2Bits; i++)
            {
                _l2Mask = (_l2Mask << 1) + 1;
            }

            _l2Mask <<= (int)_qHdr.cluster_bits;

            _sectorMask = 0;

            for (int i = 0; i < _qHdr.cluster_bits; i++)
            {
                _sectorMask = (_sectorMask << 1) + 1;
            }

            AaruConsole.DebugWriteLine("QCOW plugin", "qHdr.l1Mask = {0:X}", _l1Mask);
            AaruConsole.DebugWriteLine("QCOW plugin", "qHdr.l1Shift = {0}", _l1Shift);
            AaruConsole.DebugWriteLine("QCOW plugin", "qHdr.l2Mask = {0:X}", _l2Mask);
            AaruConsole.DebugWriteLine("QCOW plugin", "qHdr.sectorMask = {0:X}", _sectorMask);

            _maxL2TableCache = MAX_CACHE_SIZE / (_l2Size * 8);
            _maxClusterCache = MAX_CACHE_SIZE / _clusterSize;

            _imageStream = stream;

            _sectorCache  = new Dictionary <ulong, byte[]>();
            _l2TableCache = new Dictionary <ulong, ulong[]>();
            _clusterCache = new Dictionary <ulong, byte[]>();

            _imageInfo.CreationTime         = imageFilter.GetCreationTime();
            _imageInfo.LastModificationTime = imageFilter.GetLastWriteTime();
            _imageInfo.MediaTitle           = Path.GetFileNameWithoutExtension(imageFilter.GetFilename());
            _imageInfo.Sectors      = _qHdr.size / 512;
            _imageInfo.SectorSize   = 512;
            _imageInfo.XmlMediaType = XmlMediaType.BlockMedia;
            _imageInfo.MediaType    = MediaType.GENERIC_HDD;
            _imageInfo.ImageSize    = _qHdr.size;
            _imageInfo.Version      = $"{_qHdr.version}";

            _imageInfo.Cylinders       = (uint)(_imageInfo.Sectors / 16 / 63);
            _imageInfo.Heads           = 16;
            _imageInfo.SectorsPerTrack = 63;

            return(true);
        }
コード例 #15
0
        public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information,
                                   Encoding encoding)
        {
            Encoding    = encoding ?? Encoding.GetEncoding("iso-8859-15");
            information = "";

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

            var locusSb = new Superblock();

            byte[] sector = null;

            for (ulong location = 0; location <= 8; location++)
            {
                uint sbSize = (uint)(Marshal.SizeOf <Superblock>() / imagePlugin.Info.SectorSize);

                if (Marshal.SizeOf <Superblock>() % imagePlugin.Info.SectorSize != 0)
                {
                    sbSize++;
                }

                sector = imagePlugin.ReadSectors(partition.Start + location, sbSize);

                if (sector.Length < Marshal.SizeOf <Superblock>())
                {
                    return;
                }

                locusSb = Marshal.ByteArrayToStructureLittleEndian <Superblock>(sector);

                if (locusSb.s_magic == LOCUS_MAGIC ||
                    locusSb.s_magic == LOCUS_CIGAM ||
                    locusSb.s_magic == LOCUS_MAGIC_OLD ||
                    locusSb.s_magic == LOCUS_CIGAM_OLD)
                {
                    break;
                }
            }

            // We don't care about old version for information
            if (locusSb.s_magic != LOCUS_MAGIC &&
                locusSb.s_magic != LOCUS_CIGAM &&
                locusSb.s_magic != LOCUS_MAGIC_OLD &&
                locusSb.s_magic != LOCUS_CIGAM_OLD)
            {
                return;
            }

            // Numerical arrays are not important for information so no need to swap them
            if (locusSb.s_magic == LOCUS_CIGAM ||
                locusSb.s_magic == LOCUS_CIGAM_OLD)
            {
                locusSb         = Marshal.ByteArrayToStructureBigEndian <Superblock>(sector);
                locusSb.s_flags = (Flags)Swapping.Swap((ushort)locusSb.s_flags);
            }

            var sb = new StringBuilder();

            sb.AppendLine(locusSb.s_magic == LOCUS_MAGIC_OLD ? "Locus filesystem (old)" : "Locus filesystem");

            int blockSize = locusSb.s_version == Version.SB_SB4096 ? 4096 : 1024;

            string s_fsmnt = StringHandlers.CToString(locusSb.s_fsmnt, Encoding);
            string s_fpack = StringHandlers.CToString(locusSb.s_fpack, Encoding);

            AaruConsole.DebugWriteLine("Locus plugin", "LocusSb.s_magic = 0x{0:X8}", locusSb.s_magic);
            AaruConsole.DebugWriteLine("Locus plugin", "LocusSb.s_gfs = {0}", locusSb.s_gfs);
            AaruConsole.DebugWriteLine("Locus plugin", "LocusSb.s_fsize = {0}", locusSb.s_fsize);
            AaruConsole.DebugWriteLine("Locus plugin", "LocusSb.s_lwm = {0}", locusSb.s_lwm);
            AaruConsole.DebugWriteLine("Locus plugin", "LocusSb.s_hwm = {0}", locusSb.s_hwm);
            AaruConsole.DebugWriteLine("Locus plugin", "LocusSb.s_llst = {0}", locusSb.s_llst);
            AaruConsole.DebugWriteLine("Locus plugin", "LocusSb.s_fstore = {0}", locusSb.s_fstore);
            AaruConsole.DebugWriteLine("Locus plugin", "LocusSb.s_time = {0}", locusSb.s_time);
            AaruConsole.DebugWriteLine("Locus plugin", "LocusSb.s_tfree = {0}", locusSb.s_tfree);
            AaruConsole.DebugWriteLine("Locus plugin", "LocusSb.s_isize = {0}", locusSb.s_isize);
            AaruConsole.DebugWriteLine("Locus plugin", "LocusSb.s_nfree = {0}", locusSb.s_nfree);
            AaruConsole.DebugWriteLine("Locus plugin", "LocusSb.s_flags = {0}", locusSb.s_flags);
            AaruConsole.DebugWriteLine("Locus plugin", "LocusSb.s_tinode = {0}", locusSb.s_tinode);
            AaruConsole.DebugWriteLine("Locus plugin", "LocusSb.s_lasti = {0}", locusSb.s_lasti);
            AaruConsole.DebugWriteLine("Locus plugin", "LocusSb.s_nbehind = {0}", locusSb.s_nbehind);
            AaruConsole.DebugWriteLine("Locus plugin", "LocusSb.s_gfspack = {0}", locusSb.s_gfspack);
            AaruConsole.DebugWriteLine("Locus plugin", "LocusSb.s_ninode = {0}", locusSb.s_ninode);
            AaruConsole.DebugWriteLine("Locus plugin", "LocusSb.s_flock = {0}", locusSb.s_flock);
            AaruConsole.DebugWriteLine("Locus plugin", "LocusSb.s_ilock = {0}", locusSb.s_ilock);
            AaruConsole.DebugWriteLine("Locus plugin", "LocusSb.s_fmod = {0}", locusSb.s_fmod);
            AaruConsole.DebugWriteLine("Locus plugin", "LocusSb.s_version = {0}", locusSb.s_version);

            sb.AppendFormat("Superblock last modified on {0}", DateHandlers.UnixToDateTime(locusSb.s_time)).
            AppendLine();

            sb.AppendFormat("Volume has {0} blocks of {1} bytes each (total {2} bytes)", locusSb.s_fsize, blockSize,
                            locusSb.s_fsize * blockSize).AppendLine();

            sb.AppendFormat("{0} blocks free ({1} bytes)", locusSb.s_tfree, locusSb.s_tfree * blockSize).AppendLine();
            sb.AppendFormat("I-node list uses {0} blocks", locusSb.s_isize).AppendLine();
            sb.AppendFormat("{0} free inodes", locusSb.s_tinode).AppendLine();
            sb.AppendFormat("Next free inode search will start at inode {0}", locusSb.s_lasti).AppendLine();

            sb.AppendFormat("There are an estimate of {0} free inodes before next search start", locusSb.s_nbehind).
            AppendLine();

            if (locusSb.s_flags.HasFlag(Flags.SB_RDONLY))
            {
                sb.AppendLine("Read-only volume");
            }

            if (locusSb.s_flags.HasFlag(Flags.SB_CLEAN))
            {
                sb.AppendLine("Clean volume");
            }

            if (locusSb.s_flags.HasFlag(Flags.SB_DIRTY))
            {
                sb.AppendLine("Dirty volume");
            }

            if (locusSb.s_flags.HasFlag(Flags.SB_RMV))
            {
                sb.AppendLine("Removable volume");
            }

            if (locusSb.s_flags.HasFlag(Flags.SB_PRIMPACK))
            {
                sb.AppendLine("This is the primary pack");
            }

            if (locusSb.s_flags.HasFlag(Flags.SB_REPLTYPE))
            {
                sb.AppendLine("Replicated volume");
            }

            if (locusSb.s_flags.HasFlag(Flags.SB_USER))
            {
                sb.AppendLine("User replicated volume");
            }

            if (locusSb.s_flags.HasFlag(Flags.SB_BACKBONE))
            {
                sb.AppendLine("Backbone volume");
            }

            if (locusSb.s_flags.HasFlag(Flags.SB_NFS))
            {
                sb.AppendLine("NFS volume");
            }

            if (locusSb.s_flags.HasFlag(Flags.SB_BYHAND))
            {
                sb.AppendLine("Volume inhibits automatic fsck");
            }

            if (locusSb.s_flags.HasFlag(Flags.SB_NOSUID))
            {
                sb.AppendLine("Set-uid/set-gid is disabled");
            }

            if (locusSb.s_flags.HasFlag(Flags.SB_SYNCW))
            {
                sb.AppendLine("Volume uses synchronous writes");
            }

            sb.AppendFormat("Volume label: {0}", s_fsmnt).AppendLine();
            sb.AppendFormat("Physical volume name: {0}", s_fpack).AppendLine();
            sb.AppendFormat("Global File System number: {0}", locusSb.s_gfs).AppendLine();
            sb.AppendFormat("Global File System pack number {0}", locusSb.s_gfspack).AppendLine();

            information = sb.ToString();

            XmlFsType = new FileSystemType
            {
                Type        = "Locus filesystem",
                ClusterSize = (uint)blockSize,
                Clusters    = (ulong)locusSb.s_fsize,

                // Sometimes it uses one, or the other. Use the bigger
                VolumeName                = string.IsNullOrEmpty(s_fsmnt) ? s_fpack : s_fsmnt,
                ModificationDate          = DateHandlers.UnixToDateTime(locusSb.s_time),
                ModificationDateSpecified = true,
                Dirty                 = !locusSb.s_flags.HasFlag(Flags.SB_CLEAN) || locusSb.s_flags.HasFlag(Flags.SB_DIRTY),
                FreeClusters          = (ulong)locusSb.s_tfree,
                FreeClustersSpecified = true
            };
        }
コード例 #16
0
        public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information,
                                   Encoding encoding)
        {
            Encoding    = Encoding.Unicode;
            information = "";

            if (imagePlugin.Info.SectorSize < F2FS_MIN_SECTOR ||
                imagePlugin.Info.SectorSize > F2FS_MAX_SECTOR)
            {
                return;
            }

            uint sbAddr = F2FS_SUPER_OFFSET / imagePlugin.Info.SectorSize;

            if (sbAddr == 0)
            {
                sbAddr = 1;
            }

            uint sbSize = (uint)(Marshal.SizeOf <Superblock>() / imagePlugin.Info.SectorSize);

            if (Marshal.SizeOf <Superblock>() % imagePlugin.Info.SectorSize != 0)
            {
                sbSize++;
            }

            byte[] sector = imagePlugin.ReadSectors(partition.Start + sbAddr, sbSize);

            if (sector.Length < Marshal.SizeOf <Superblock>())
            {
                return;
            }

            Superblock f2fsSb = Marshal.ByteArrayToStructureLittleEndian <Superblock>(sector);

            if (f2fsSb.magic != F2FS_MAGIC)
            {
                return;
            }

            var sb = new StringBuilder();

            sb.AppendLine("F2FS filesystem");
            sb.AppendFormat("Version {0}.{1}", f2fsSb.major_ver, f2fsSb.minor_ver).AppendLine();
            sb.AppendFormat("{0} bytes per sector", 1 << (int)f2fsSb.log_sectorsize).AppendLine();

            sb.AppendFormat("{0} sectors ({1} bytes) per block", 1 << (int)f2fsSb.log_sectors_per_block,
                            1 << (int)f2fsSb.log_blocksize).AppendLine();

            sb.AppendFormat("{0} blocks per segment", f2fsSb.log_blocks_per_seg).AppendLine();
            sb.AppendFormat("{0} blocks in volume", f2fsSb.block_count).AppendLine();
            sb.AppendFormat("{0} segments per section", f2fsSb.segs_per_sec).AppendLine();
            sb.AppendFormat("{0} sections per zone", f2fsSb.secs_per_zone).AppendLine();
            sb.AppendFormat("{0} sections", f2fsSb.section_count).AppendLine();
            sb.AppendFormat("{0} segments", f2fsSb.segment_count).AppendLine();
            sb.AppendFormat("Root directory resides on inode {0}", f2fsSb.root_ino).AppendLine();
            sb.AppendFormat("Volume UUID: {0}", f2fsSb.uuid).AppendLine();

            sb.AppendFormat("Volume name: {0}", StringHandlers.CToString(f2fsSb.volume_name, Encoding.Unicode, true)).
            AppendLine();

            sb.AppendFormat("Volume last mounted on kernel version: {0}", StringHandlers.CToString(f2fsSb.version)).
            AppendLine();

            sb.AppendFormat("Volume created on kernel version: {0}", StringHandlers.CToString(f2fsSb.init_version)).
            AppendLine();

            information = sb.ToString();

            XmlFsType = new FileSystemType
            {
                Type                   = "F2FS filesystem",
                SystemIdentifier       = Encoding.ASCII.GetString(f2fsSb.version),
                Clusters               = f2fsSb.block_count,
                ClusterSize            = (uint)(1 << (int)f2fsSb.log_blocksize),
                DataPreparerIdentifier = Encoding.ASCII.GetString(f2fsSb.init_version),
                VolumeName             = StringHandlers.CToString(f2fsSb.volume_name, Encoding.Unicode, true),
                VolumeSerial           = f2fsSb.uuid.ToString()
            };
        }
コード例 #17
0
ファイル: EFS.cs プロジェクト: paulyc/Aaru
        public bool Identify(IMediaImage imagePlugin, Partition partition)
        {
            if (imagePlugin.Info.SectorSize < 512)
            {
                return(false);
            }

            // Misaligned
            if (imagePlugin.Info.XmlMediaType == XmlMediaType.OpticalDisc)
            {
                uint sbSize = (uint)((Marshal.SizeOf <Superblock>() + 0x200) / imagePlugin.Info.SectorSize);

                if ((Marshal.SizeOf <Superblock>() + 0x200) % imagePlugin.Info.SectorSize != 0)
                {
                    sbSize++;
                }

                byte[] sector = imagePlugin.ReadSectors(partition.Start, sbSize);

                if (sector.Length < Marshal.SizeOf <Superblock>())
                {
                    return(false);
                }

                byte[] sbpiece = new byte[Marshal.SizeOf <Superblock>()];

                Array.Copy(sector, 0x200, sbpiece, 0, Marshal.SizeOf <Superblock>());

                Superblock sb = Marshal.ByteArrayToStructureBigEndian <Superblock>(sbpiece);

                AaruConsole.DebugWriteLine("EFS plugin", "magic at 0x{0:X3} = 0x{1:X8} (expected 0x{2:X8} or 0x{3:X8})",
                                           0x200, sb.sb_magic, EFS_MAGIC, EFS_MAGIC_NEW);

                if (sb.sb_magic == EFS_MAGIC ||
                    sb.sb_magic == EFS_MAGIC_NEW)
                {
                    return(true);
                }
            }
            else
            {
                uint sbSize = (uint)(Marshal.SizeOf <Superblock>() / imagePlugin.Info.SectorSize);

                if (Marshal.SizeOf <Superblock>() % imagePlugin.Info.SectorSize != 0)
                {
                    sbSize++;
                }

                byte[] sector = imagePlugin.ReadSectors(partition.Start + 1, sbSize);

                if (sector.Length < Marshal.SizeOf <Superblock>())
                {
                    return(false);
                }

                Superblock sb = Marshal.ByteArrayToStructureBigEndian <Superblock>(sector);

                AaruConsole.DebugWriteLine("EFS plugin", "magic at {0} = 0x{1:X8} (expected 0x{2:X8} or 0x{3:X8})", 1,
                                           sb.sb_magic, EFS_MAGIC, EFS_MAGIC_NEW);

                if (sb.sb_magic == EFS_MAGIC ||
                    sb.sb_magic == EFS_MAGIC_NEW)
                {
                    return(true);
                }
            }

            return(false);
        }
コード例 #18
0
        public bool Close()
        {
            if (!IsWriting)
            {
                ErrorMessage = "Image is not opened for writing";

                return(false);
            }

            if (!string.IsNullOrEmpty(_imageInfo.Comments))
            {
                _vHdr.comments = _imageInfo.Comments.Length > 255 ? _imageInfo.Comments.Substring(0, 255)
                                     : _imageInfo.Comments;
            }

            if (_vHdr.logicalCylinders == 0)
            {
                _vHdr.logicalCylinders = (uint)(_imageInfo.Sectors / 16 / 63);
                _vHdr.logicalHeads     = 16;
                _vHdr.logicalSpt       = 63;

                while (_vHdr.logicalCylinders == 0)
                {
                    _vHdr.logicalHeads--;

                    if (_vHdr.logicalHeads == 0)
                    {
                        _vHdr.logicalSpt--;
                        _vHdr.logicalHeads = 16;
                    }

                    _vHdr.logicalCylinders = (uint)(_imageInfo.Sectors / _vHdr.logicalHeads / _vHdr.logicalSpt);

                    if (_vHdr.logicalCylinders == 0 &&
                        _vHdr.logicalHeads == 0 &&
                        _vHdr.logicalSpt == 0)
                    {
                        break;
                    }
                }
            }

            byte[] hdr    = new byte[Marshal.SizeOf <Header>()];
            IntPtr hdrPtr = System.Runtime.InteropServices.Marshal.AllocHGlobal(Marshal.SizeOf <Header>());

            System.Runtime.InteropServices.Marshal.StructureToPtr(_vHdr, hdrPtr, true);
            System.Runtime.InteropServices.Marshal.Copy(hdrPtr, hdr, 0, hdr.Length);
            System.Runtime.InteropServices.Marshal.FreeHGlobal(hdrPtr);

            _writingStream.Seek(0, SeekOrigin.Begin);
            _writingStream.Write(hdr, 0, hdr.Length);

            _writingStream.Seek(_vHdr.offsetBlocks, SeekOrigin.Begin);
            _writingStream.Write(MemoryMarshal.Cast <uint, byte>(_ibm).ToArray(), 0, 4 * _ibm.Length);

            _writingStream.Flush();
            _writingStream.Close();

            IsWriting    = false;
            ErrorMessage = "";

            return(true);
        }
コード例 #19
0
        /// <inheritdoc />
        public Errno Mount(IMediaImage imagePlugin, Partition partition, Encoding encoding,
                           Dictionary <string, string> options, string @namespace)
        {
            XmlFsType = new FileSystemType();

            options ??= GetDefaultOptions();

            if (options.TryGetValue("debug", out string debugString))
            {
                bool.TryParse(debugString, out _debug);
            }

            // Default namespace
            @namespace ??= "ecs";

            switch (@namespace.ToLowerInvariant())
            {
            case "dos":
                _namespace = Namespace.Dos;

                break;

            case "nt":
                _namespace = Namespace.Nt;

                break;

            case "os2":
                _namespace = Namespace.Os2;

                break;

            case "ecs":
                _namespace = Namespace.Ecs;

                break;

            case "lfn":
                _namespace = Namespace.Lfn;

                break;

            case "human":
                _namespace = Namespace.Human;

                break;

            default: return(Errno.InvalidArgument);
            }

            AaruConsole.DebugWriteLine("FAT plugin", "Reading BPB");

            uint sectorsPerBpb = imagePlugin.Info.SectorSize < 512 ? 512 / imagePlugin.Info.SectorSize : 1;

            byte[] bpbSector = imagePlugin.ReadSectors(0 + partition.Start, sectorsPerBpb);

            BpbKind bpbKind = DetectBpbKind(bpbSector, imagePlugin, partition, out BiosParameterBlockEbpb fakeBpb,
                                            out HumanParameterBlock humanBpb, out AtariParameterBlock atariBpb,
                                            out byte minBootNearJump, out bool andosOemCorrect, out bool bootable);

            _fat12             = false;
            _fat16             = false;
            _fat32             = false;
            _useFirstFat       = true;
            XmlFsType.Bootable = bootable;

            _statfs = new FileSystemInfo
            {
                FilenameLength = 11,
                Files          = 0, // Requires traversing all directories
                FreeFiles      = 0,
                PluginId       = Id,
                FreeBlocks     = 0 // Requires traversing the FAT
            };

            // This is needed because for FAT16, GEMDOS increases bytes per sector count instead of using big_sectors field.
            uint sectorsPerRealSector = 1;

            // This is needed because some OSes don't put volume label as first entry in the root directory
            uint sectorsForRootDirectory = 0;
            uint rootDirectoryCluster    = 0;

            Encoding = encoding ?? (bpbKind == BpbKind.Human ? Encoding.GetEncoding("shift_jis")
                                        : Encoding.GetEncoding("IBM437"));

            switch (bpbKind)
            {
            case BpbKind.DecRainbow:
            case BpbKind.Hardcoded:
            case BpbKind.Msx:
            case BpbKind.Apricot:
                _fat12 = true;

                break;

            case BpbKind.ShortFat32:
            case BpbKind.LongFat32:
            {
                _fat32 = true;

                Fat32ParameterBlock fat32Bpb =
                    Marshal.ByteArrayToStructureLittleEndian <Fat32ParameterBlock>(bpbSector);

                Fat32ParameterBlockShort shortFat32Bpb =
                    Marshal.ByteArrayToStructureLittleEndian <Fat32ParameterBlockShort>(bpbSector);

                rootDirectoryCluster = fat32Bpb.root_cluster;

                // This is to support FAT partitions on hybrid ISO/USB images
                if (imagePlugin.Info.XmlMediaType == XmlMediaType.OpticalDisc)
                {
                    fat32Bpb.bps       *= 4;
                    fat32Bpb.spc       /= 4;
                    fat32Bpb.big_spfat /= 4;
                    fat32Bpb.hsectors  /= 4;
                    fat32Bpb.sptrk     /= 4;
                }

                XmlFsType.Type = fat32Bpb.version != 0 ? "FAT+" : "FAT32";

                if (fat32Bpb.oem_name != null &&
                    (fat32Bpb.oem_name[5] != 0x49 || fat32Bpb.oem_name[6] != 0x48 || fat32Bpb.oem_name[7] != 0x43))
                {
                    XmlFsType.SystemIdentifier = StringHandlers.CToString(fat32Bpb.oem_name);
                }

                _sectorsPerCluster    = fat32Bpb.spc;
                XmlFsType.ClusterSize = (uint)(fat32Bpb.bps * fat32Bpb.spc);
                _reservedSectors      = fat32Bpb.rsectors;

                if (fat32Bpb.big_sectors == 0 &&
                    fat32Bpb.signature == 0x28)
                {
                    XmlFsType.Clusters = shortFat32Bpb.huge_sectors / shortFat32Bpb.spc;
                }
                else if (fat32Bpb.sectors == 0)
                {
                    XmlFsType.Clusters = fat32Bpb.big_sectors / fat32Bpb.spc;
                }
                else
                {
                    XmlFsType.Clusters = (ulong)(fat32Bpb.sectors / fat32Bpb.spc);
                }

                _sectorsPerFat         = fat32Bpb.big_spfat;
                XmlFsType.VolumeSerial = $"{fat32Bpb.serial_no:X8}";

                _statfs.Id = new FileSystemId
                {
                    IsInt    = true,
                    Serial32 = fat32Bpb.serial_no
                };

                if ((fat32Bpb.flags & 0xF8) == 0x00)
                {
                    if ((fat32Bpb.flags & 0x01) == 0x01)
                    {
                        XmlFsType.Dirty = true;
                    }
                }

                if ((fat32Bpb.mirror_flags & 0x80) == 0x80)
                {
                    _useFirstFat = (fat32Bpb.mirror_flags & 0xF) != 1;
                }

                if (fat32Bpb.signature == 0x29)
                {
                    XmlFsType.VolumeName = StringHandlers.SpacePaddedToString(fat32Bpb.volume_label, Encoding);
                    XmlFsType.VolumeName = XmlFsType.VolumeName?.Replace("\0", "");
                }

                // Check that jumps to a correct boot code position and has boot signature set.
                // This will mean that the volume will boot, even if just to say "this is not bootable change disk"......
                XmlFsType.Bootable =
                    (fat32Bpb.jump[0] == 0xEB && fat32Bpb.jump[1] >= minBootNearJump && fat32Bpb.jump[1] < 0x80) ||
                    (fat32Bpb.jump[0] == 0xE9 && fat32Bpb.jump.Length >= 3 &&
                     BitConverter.ToUInt16(fat32Bpb.jump, 1) >= minBootNearJump &&
                     BitConverter.ToUInt16(fat32Bpb.jump, 1) <= 0x1FC);

                sectorsPerRealSector = fat32Bpb.bps / imagePlugin.Info.SectorSize;
                _sectorsPerCluster  *= sectorsPerRealSector;

                // First root directory sector
                _firstClusterSector =
                    ((ulong)((fat32Bpb.big_spfat * fat32Bpb.fats_no) + fat32Bpb.rsectors) * sectorsPerRealSector) -
                    (2 * _sectorsPerCluster);

                if (fat32Bpb.fsinfo_sector + partition.Start <= partition.End)
                {
                    byte[] fsinfoSector = imagePlugin.ReadSector(fat32Bpb.fsinfo_sector + partition.Start);

                    FsInfoSector fsInfo = Marshal.ByteArrayToStructureLittleEndian <FsInfoSector>(fsinfoSector);

                    if (fsInfo.signature1 == FSINFO_SIGNATURE1 &&
                        fsInfo.signature2 == FSINFO_SIGNATURE2 &&
                        fsInfo.signature3 == FSINFO_SIGNATURE3)
                    {
                        if (fsInfo.free_clusters < 0xFFFFFFFF)
                        {
                            XmlFsType.FreeClusters          = fsInfo.free_clusters;
                            XmlFsType.FreeClustersSpecified = true;
                        }
                    }
                }

                break;
            }

            // Some fields could overflow fake BPB, those will be handled below
            case BpbKind.Atari:
            {
                ushort sum = 0;

                for (int i = 0; i < bpbSector.Length; i += 2)
                {
                    sum += BigEndianBitConverter.ToUInt16(bpbSector, i);
                }

                // TODO: Check this
                if (sum == 0x1234)
                {
                    XmlFsType.Bootable = true;
                }

                // BGM changes the bytes per sector instead of changing the sectors per cluster. Why?! WHY!?
                uint ratio = fakeBpb.bps / imagePlugin.Info.SectorSize;
                fakeBpb.bps         = (ushort)imagePlugin.Info.SectorSize;
                fakeBpb.spc         = (byte)(fakeBpb.spc * ratio);
                fakeBpb.rsectors    = (ushort)(fakeBpb.rsectors * ratio);
                fakeBpb.big_sectors = fakeBpb.sectors * ratio;
                fakeBpb.sectors     = 0;
                fakeBpb.spfat       = (ushort)(fakeBpb.spfat * ratio);
                fakeBpb.sptrk       = (ushort)(fakeBpb.sptrk * ratio);

                break;
            }

            case BpbKind.Human:
                // If not debug set Human68k namespace and ShiftJIS codepage as defaults
                if (!_debug)
                {
                    _namespace = Namespace.Human;
                }

                XmlFsType.Bootable = true;

                break;
            }

            ulong firstRootSector = 0;

            if (!_fat32)
            {
                // This is to support FAT partitions on hybrid ISO/USB images
                if (imagePlugin.Info.XmlMediaType == XmlMediaType.OpticalDisc)
                {
                    fakeBpb.bps      *= 4;
                    fakeBpb.spc      /= 4;
                    fakeBpb.spfat    /= 4;
                    fakeBpb.hsectors /= 4;
                    fakeBpb.sptrk    /= 4;
                    fakeBpb.rsectors /= 4;

                    if (fakeBpb.spc == 0)
                    {
                        fakeBpb.spc = 1;
                    }
                }

                ulong clusters;

                if (bpbKind != BpbKind.Human)
                {
                    int reservedSectors = fakeBpb.rsectors + (fakeBpb.fats_no * fakeBpb.spfat) +
                                          (fakeBpb.root_ent * 32 / fakeBpb.bps);

                    if (fakeBpb.sectors == 0)
                    {
                        clusters = (ulong)(fakeBpb.spc == 0 ? fakeBpb.big_sectors - reservedSectors
                                               : (fakeBpb.big_sectors - reservedSectors) / fakeBpb.spc);
                    }
                    else
                    {
                        clusters = (ulong)(fakeBpb.spc == 0 ? fakeBpb.sectors - reservedSectors
                                               : (fakeBpb.sectors - reservedSectors) / fakeBpb.spc);
                    }
                }
                else
                {
                    clusters = humanBpb.clusters == 0 ? humanBpb.big_clusters : humanBpb.clusters;
                }

                // This will walk all the FAT entries and check if they're valid FAT12 or FAT16 entries.
                // If the whole table is valid in both senses, it considers the type entry in the BPB.
                // BeOS is known to set the type as FAT16 but treat it as FAT12.
                if (!_fat12 &&
                    !_fat16)
                {
                    if (clusters < 4089)
                    {
                        ushort[] fat12 = new ushort[clusters];

                        _reservedSectors     = fakeBpb.rsectors;
                        sectorsPerRealSector = fakeBpb.bps / imagePlugin.Info.SectorSize;
                        _fatFirstSector      = partition.Start + (_reservedSectors * sectorsPerRealSector);

                        byte[] fatBytes = imagePlugin.ReadSectors(_fatFirstSector, fakeBpb.spfat);

                        int pos = 0;

                        for (int i = 0; i + 3 < fatBytes.Length && pos < fat12.Length; i += 3)
                        {
                            fat12[pos++] = (ushort)(((fatBytes[i + 1] & 0xF) << 8) + fatBytes[i + 0]);

                            if (pos >= fat12.Length)
                            {
                                break;
                            }

                            fat12[pos++] = (ushort)(((fatBytes[i + 1] & 0xF0) >> 4) + (fatBytes[i + 2] << 4));
                        }

                        bool fat12Valid = fat12[0] >= FAT12_RESERVED && fat12[1] >= FAT12_RESERVED;

                        foreach (ushort entry in fat12)
                        {
                            if (entry >= FAT12_RESERVED ||
                                entry <= clusters)
                            {
                                continue;
                            }

                            fat12Valid = false;

                            break;
                        }

                        ushort[] fat16 = MemoryMarshal.Cast <byte, ushort>(fatBytes).ToArray();

                        bool fat16Valid = fat16[0] >= FAT16_RESERVED && fat16[1] >= 0x3FF0;

                        foreach (ushort entry in fat16)
                        {
                            if (entry >= FAT16_RESERVED ||
                                entry <= clusters)
                            {
                                continue;
                            }

                            fat16Valid = false;

                            break;
                        }

                        _fat12 = fat12Valid;
                        _fat16 = fat16Valid;

                        // Check BPB type
                        if (_fat12 == _fat16)
                        {
                            _fat12 = Encoding.ASCII.GetString(fakeBpb.fs_type) == "FAT12   ";
                            _fat16 = Encoding.ASCII.GetString(fakeBpb.fs_type) == "FAT16   ";
                        }
                    }
                    else
                    {
                        _fat16 = true;
                    }
                }

                if (_fat12)
                {
                    XmlFsType.Type = "FAT12";
                }
                else if (_fat16)
                {
                    XmlFsType.Type = "FAT16";
                }

                if (bpbKind == BpbKind.Atari)
                {
                    if (atariBpb.serial_no[0] != 0x49 ||
                        atariBpb.serial_no[1] != 0x48 ||
                        atariBpb.serial_no[2] != 0x43)
                    {
                        XmlFsType.VolumeSerial =
                            $"{atariBpb.serial_no[0]:X2}{atariBpb.serial_no[1]:X2}{atariBpb.serial_no[2]:X2}";

                        _statfs.Id = new FileSystemId
                        {
                            IsInt    = true,
                            Serial32 = (uint)((atariBpb.serial_no[0] << 16) + (atariBpb.serial_no[1] << 8) +
                                              atariBpb.serial_no[2])
                        };
                    }

                    XmlFsType.SystemIdentifier = StringHandlers.CToString(atariBpb.oem_name);

                    if (string.IsNullOrEmpty(XmlFsType.SystemIdentifier))
                    {
                        XmlFsType.SystemIdentifier = null;
                    }
                }
                else if (fakeBpb.oem_name != null)
                {
                    if (fakeBpb.oem_name[5] != 0x49 ||
                        fakeBpb.oem_name[6] != 0x48 ||
                        fakeBpb.oem_name[7] != 0x43)
                    {
                        // Later versions of Windows create a DOS 3 BPB without OEM name on 8 sectors/track floppies
                        // OEM ID should be ASCII, otherwise ignore it
                        if (fakeBpb.oem_name[0] >= 0x20 &&
                            fakeBpb.oem_name[0] <= 0x7F &&
                            fakeBpb.oem_name[1] >= 0x20 &&
                            fakeBpb.oem_name[1] <= 0x7F &&
                            fakeBpb.oem_name[2] >= 0x20 &&
                            fakeBpb.oem_name[2] <= 0x7F &&
                            fakeBpb.oem_name[3] >= 0x20 &&
                            fakeBpb.oem_name[3] <= 0x7F &&
                            fakeBpb.oem_name[4] >= 0x20 &&
                            fakeBpb.oem_name[4] <= 0x7F &&
                            fakeBpb.oem_name[5] >= 0x20 &&
                            fakeBpb.oem_name[5] <= 0x7F &&
                            fakeBpb.oem_name[6] >= 0x20 &&
                            fakeBpb.oem_name[6] <= 0x7F &&
                            fakeBpb.oem_name[7] >= 0x20 &&
                            fakeBpb.oem_name[7] <= 0x7F)
                        {
                            XmlFsType.SystemIdentifier = StringHandlers.CToString(fakeBpb.oem_name);
                        }
                        else if (fakeBpb.oem_name[0] < 0x20 &&
                                 fakeBpb.oem_name[1] >= 0x20 &&
                                 fakeBpb.oem_name[1] <= 0x7F &&
                                 fakeBpb.oem_name[2] >= 0x20 &&
                                 fakeBpb.oem_name[2] <= 0x7F &&
                                 fakeBpb.oem_name[3] >= 0x20 &&
                                 fakeBpb.oem_name[3] <= 0x7F &&
                                 fakeBpb.oem_name[4] >= 0x20 &&
                                 fakeBpb.oem_name[4] <= 0x7F &&
                                 fakeBpb.oem_name[5] >= 0x20 &&
                                 fakeBpb.oem_name[5] <= 0x7F &&
                                 fakeBpb.oem_name[6] >= 0x20 &&
                                 fakeBpb.oem_name[6] <= 0x7F &&
                                 fakeBpb.oem_name[7] >= 0x20 &&
                                 fakeBpb.oem_name[7] <= 0x7F)
                        {
                            XmlFsType.SystemIdentifier = StringHandlers.CToString(fakeBpb.oem_name, Encoding, start: 1);
                        }
                    }

                    if (fakeBpb.signature == 0x28 ||
                        fakeBpb.signature == 0x29)
                    {
                        XmlFsType.VolumeSerial = $"{fakeBpb.serial_no:X8}";

                        _statfs.Id = new FileSystemId
                        {
                            IsInt    = true,
                            Serial32 = fakeBpb.serial_no
                        };
                    }
                }

                XmlFsType.Clusters    = clusters;
                _sectorsPerCluster    = fakeBpb.spc;
                XmlFsType.ClusterSize = (uint)(fakeBpb.bps * fakeBpb.spc);
                _reservedSectors      = fakeBpb.rsectors;
                _sectorsPerFat        = fakeBpb.spfat;

                if (fakeBpb.signature == 0x28 ||
                    fakeBpb.signature == 0x29 ||
                    andosOemCorrect)
                {
                    if ((fakeBpb.flags & 0xF8) == 0x00)
                    {
                        if ((fakeBpb.flags & 0x01) == 0x01)
                        {
                            XmlFsType.Dirty = true;
                        }
                    }

                    if (fakeBpb.signature == 0x29 || andosOemCorrect)
                    {
                        XmlFsType.VolumeName = StringHandlers.SpacePaddedToString(fakeBpb.volume_label, Encoding);
                        XmlFsType.VolumeName = XmlFsType.VolumeName?.Replace("\0", "");
                    }
                }

                // Workaround that PCExchange jumps into "FAT16   "...
                if (XmlFsType.SystemIdentifier == "PCX 2.0 ")
                {
                    fakeBpb.jump[1] += 8;
                }

                // Check that jumps to a correct boot code position and has boot signature set.
                // This will mean that the volume will boot, even if just to say "this is not bootable change disk"......
                if (XmlFsType.Bootable == false &&
                    fakeBpb.jump != null)
                {
                    XmlFsType.Bootable |=
                        (fakeBpb.jump[0] == 0xEB && fakeBpb.jump[1] >= minBootNearJump && fakeBpb.jump[1] < 0x80) ||
                        (fakeBpb.jump[0] == 0xE9 && fakeBpb.jump.Length >= 3 &&
                         BitConverter.ToUInt16(fakeBpb.jump, 1) >= minBootNearJump &&
                         BitConverter.ToUInt16(fakeBpb.jump, 1) <= 0x1FC);
                }

                // First root directory sector
                firstRootSector =
                    ((ulong)((fakeBpb.spfat * fakeBpb.fats_no) + fakeBpb.rsectors) * sectorsPerRealSector) +
                    partition.Start;

                sectorsForRootDirectory = (uint)(fakeBpb.root_ent * 32 / imagePlugin.Info.SectorSize);

                sectorsPerRealSector = fakeBpb.bps / imagePlugin.Info.SectorSize;
                _sectorsPerCluster  *= sectorsPerRealSector;
            }

            _firstClusterSector += partition.Start;

            _image = imagePlugin;

            if (_fat32)
            {
                _fatEntriesPerSector = imagePlugin.Info.SectorSize / 4;
            }
            else if (_fat16)
            {
                _fatEntriesPerSector = imagePlugin.Info.SectorSize / 2;
            }
            else
            {
                _fatEntriesPerSector = imagePlugin.Info.SectorSize * 2 / 3;
            }

            _fatFirstSector = partition.Start + (_reservedSectors * sectorsPerRealSector);

            _rootDirectoryCache = new Dictionary <string, CompleteDirectoryEntry>();
            byte[] rootDirectory;

            if (!_fat32)
            {
                _firstClusterSector = firstRootSector + sectorsForRootDirectory - (_sectorsPerCluster * 2);
                rootDirectory       = imagePlugin.ReadSectors(firstRootSector, sectorsForRootDirectory);

                if (bpbKind == BpbKind.DecRainbow)
                {
                    var rootMs = new MemoryStream();

                    foreach (byte[] tmp in from ulong rootSector in new[]
                    {
                        0x17, 0x19, 0x1B, 0x1D, 0x1E, 0x20
                    } select imagePlugin.ReadSector(rootSector))
                    {
                        rootMs.Write(tmp, 0, tmp.Length);
                    }

                    rootDirectory = rootMs.ToArray();
                }
            }
            else
            {
                if (rootDirectoryCluster == 0)
                {
                    return(Errno.InvalidArgument);
                }

                var    rootMs = new MemoryStream();
                uint[] rootDirectoryClusters = GetClusters(rootDirectoryCluster);

                foreach (byte[] buffer in rootDirectoryClusters.Select(cluster =>
                                                                       imagePlugin.
                                                                       ReadSectors(_firstClusterSector + (cluster * _sectorsPerCluster),
                                                                                   _sectorsPerCluster)))
                {
                    rootMs.Write(buffer, 0, buffer.Length);
                }

                rootDirectory = rootMs.ToArray();

                // OS/2 FAT32.IFS uses LFN instead of .LONGNAME
                if (_namespace == Namespace.Os2)
                {
                    _namespace = Namespace.Lfn;
                }
            }

            if (rootDirectory is null)
            {
                return(Errno.InvalidArgument);
            }

            byte[] lastLfnName     = null;
            byte   lastLfnChecksum = 0;

            for (int i = 0; i < rootDirectory.Length; i += Marshal.SizeOf <DirectoryEntry>())
            {
                DirectoryEntry entry =
                    Marshal.ByteArrayToStructureLittleEndian <DirectoryEntry>(rootDirectory, i,
                                                                              Marshal.SizeOf <DirectoryEntry>());

                if (entry.filename[0] == DIRENT_FINISHED)
                {
                    break;
                }

                if (entry.attributes.HasFlag(FatAttributes.LFN))
                {
                    if (_namespace != Namespace.Lfn &&
                        _namespace != Namespace.Ecs)
                    {
                        continue;
                    }

                    LfnEntry lfnEntry =
                        Marshal.ByteArrayToStructureLittleEndian <LfnEntry>(rootDirectory, i,
                                                                            Marshal.SizeOf <LfnEntry>());

                    int lfnSequence = lfnEntry.sequence & LFN_MASK;

                    if ((lfnEntry.sequence & LFN_ERASED) > 0)
                    {
                        continue;
                    }

                    if ((lfnEntry.sequence & LFN_LAST) > 0)
                    {
                        lastLfnName     = new byte[lfnSequence * 26];
                        lastLfnChecksum = lfnEntry.checksum;
                    }

                    if (lastLfnName is null)
                    {
                        continue;
                    }

                    if (lfnEntry.checksum != lastLfnChecksum)
                    {
                        continue;
                    }

                    lfnSequence--;

                    Array.Copy(lfnEntry.name1, 0, lastLfnName, lfnSequence * 26, 10);
                    Array.Copy(lfnEntry.name2, 0, lastLfnName, (lfnSequence * 26) + 10, 12);
                    Array.Copy(lfnEntry.name3, 0, lastLfnName, (lfnSequence * 26) + 22, 4);

                    continue;
                }

                // Not a correct entry
                if (entry.filename[0] < DIRENT_MIN &&
                    entry.filename[0] != DIRENT_E5)
                {
                    continue;
                }

                // Self
                if (Encoding.GetString(entry.filename).TrimEnd() == ".")
                {
                    continue;
                }

                // Parent
                if (Encoding.GetString(entry.filename).TrimEnd() == "..")
                {
                    continue;
                }

                // Deleted
                if (entry.filename[0] == DIRENT_DELETED)
                {
                    continue;
                }

                string filename;

                if (entry.attributes.HasFlag(FatAttributes.VolumeLabel))
                {
                    byte[] fullname = new byte[11];
                    Array.Copy(entry.filename, 0, fullname, 0, 8);
                    Array.Copy(entry.extension, 0, fullname, 8, 3);
                    string volname = Encoding.GetString(fullname).Trim();

                    if (!string.IsNullOrEmpty(volname))
                    {
                        XmlFsType.VolumeName =
                            entry.caseinfo.HasFlag(CaseInfo.AllLowerCase) && _namespace == Namespace.Nt
                                ? volname.ToLower() : volname;
                    }

                    XmlFsType.VolumeName = XmlFsType.VolumeName?.Replace("\0", "");

                    if (entry.ctime > 0 &&
                        entry.cdate > 0)
                    {
                        XmlFsType.CreationDate = DateHandlers.DosToDateTime(entry.cdate, entry.ctime);

                        if (entry.ctime_ms > 0)
                        {
                            XmlFsType.CreationDate = XmlFsType.CreationDate.AddMilliseconds(entry.ctime_ms * 10);
                        }

                        XmlFsType.CreationDateSpecified = true;
                    }

                    if (entry.mtime > 0 &&
                        entry.mdate > 0)
                    {
                        XmlFsType.ModificationDate          = DateHandlers.DosToDateTime(entry.mdate, entry.mtime);
                        XmlFsType.ModificationDateSpecified = true;
                    }

                    continue;
                }

                var completeEntry = new CompleteDirectoryEntry
                {
                    Dirent = entry
                };

                if ((_namespace == Namespace.Lfn || _namespace == Namespace.Ecs) &&
                    lastLfnName != null)
                {
                    byte calculatedLfnChecksum = LfnChecksum(entry.filename, entry.extension);

                    if (calculatedLfnChecksum == lastLfnChecksum)
                    {
                        filename = StringHandlers.CToString(lastLfnName, Encoding.Unicode, true);

                        completeEntry.Lfn = filename;
                        lastLfnName       = null;
                        lastLfnChecksum   = 0;
                    }
                }

                if (entry.filename[0] == DIRENT_E5)
                {
                    entry.filename[0] = DIRENT_DELETED;
                }

                string name      = Encoding.GetString(entry.filename).TrimEnd();
                string extension = Encoding.GetString(entry.extension).TrimEnd();

                if (_namespace == Namespace.Nt)
                {
                    if (entry.caseinfo.HasFlag(CaseInfo.LowerCaseExtension))
                    {
                        extension = extension.ToLower(CultureInfo.CurrentCulture);
                    }

                    if (entry.caseinfo.HasFlag(CaseInfo.LowerCaseBasename))
                    {
                        name = name.ToLower(CultureInfo.CurrentCulture);
                    }
                }

                if (extension != "")
                {
                    filename = name + "." + extension;
                }
                else
                {
                    filename = name;
                }

                if (name == "" &&
                    extension == "")
                {
                    AaruConsole.DebugWriteLine("FAT filesystem", "Found empty filename in root directory");

                    if (!_debug ||
                        (entry.size > 0 && entry.start_cluster == 0))
                    {
                        continue; // Skip invalid name
                    }
                    // If debug, add it
                    name = ":{EMPTYNAME}:";

                    // Try to create a unique filename with an extension from 000 to 999
                    for (int uniq = 0; uniq < 1000; uniq++)
                    {
                        extension = $"{uniq:D03}";

                        if (!_rootDirectoryCache.ContainsKey($"{name}.{extension}"))
                        {
                            break;
                        }
                    }

                    // If we couldn't find it, just skip over
                    if (_rootDirectoryCache.ContainsKey($"{name}.{extension}"))
                    {
                        continue;
                    }
                }

                // Atari ST allows slash AND colon so cannot simply substitute one for the other like in Mac filesystems
                filename = filename.Replace('/', '\u2215');

                completeEntry.Shortname = filename;

                if (_namespace == Namespace.Human)
                {
                    HumanDirectoryEntry humanEntry =
                        Marshal.ByteArrayToStructureLittleEndian <HumanDirectoryEntry>(rootDirectory, i,
                                                                                       Marshal.SizeOf <HumanDirectoryEntry>());

                    completeEntry.HumanDirent = humanEntry;

                    name      = StringHandlers.CToString(humanEntry.name1, Encoding).TrimEnd();
                    extension = StringHandlers.CToString(humanEntry.extension, Encoding).TrimEnd();
                    string name2 = StringHandlers.CToString(humanEntry.name2, Encoding).TrimEnd();

                    if (extension != "")
                    {
                        filename = name + name2 + "." + extension;
                    }
                    else
                    {
                        filename = name + name2;
                    }

                    completeEntry.HumanName = filename;
                }

                if (!_fat32 &&
                    filename == "EA DATA. SF")
                {
                    _eaDirEntry     = entry;
                    lastLfnName     = null;
                    lastLfnChecksum = 0;

                    if (_debug)
                    {
                        _rootDirectoryCache[completeEntry.ToString()] = completeEntry;
                    }

                    continue;
                }

                _rootDirectoryCache[completeEntry.ToString()] = completeEntry;
                lastLfnName     = null;
                lastLfnChecksum = 0;
            }

            XmlFsType.VolumeName = XmlFsType.VolumeName?.Trim();
            _statfs.Blocks       = XmlFsType.Clusters;

            switch (bpbKind)
            {
            case BpbKind.Hardcoded:
                _statfs.Type = $"Microsoft FAT{(_fat16 ? "16" : "12")}";

                break;

            case BpbKind.Atari:
                _statfs.Type = $"Atari FAT{(_fat16 ? "16" : "12")}";

                break;

            case BpbKind.Msx:
                _statfs.Type = $"MSX FAT{(_fat16 ? "16" : "12")}";

                break;

            case BpbKind.Dos2:
            case BpbKind.Dos3:
            case BpbKind.Dos32:
            case BpbKind.Dos33:
            case BpbKind.ShortExtended:
            case BpbKind.Extended:
                _statfs.Type = $"Microsoft FAT{(_fat16 ? "16" : "12")}";

                break;

            case BpbKind.ShortFat32:
            case BpbKind.LongFat32:
                _statfs.Type = XmlFsType.Type == "FAT+" ? "FAT+" : "Microsoft FAT32";

                break;

            case BpbKind.Andos:
                _statfs.Type = $"ANDOS FAT{(_fat16 ? "16" : "12")}";

                break;

            case BpbKind.Apricot:
                _statfs.Type = $"Apricot FAT{(_fat16 ? "16" : "12")}";

                break;

            case BpbKind.DecRainbow:
                _statfs.Type = $"DEC FAT{(_fat16 ? "16" : "12")}";

                break;

            case BpbKind.Human:
                _statfs.Type = $"Human68k FAT{(_fat16 ? "16" : "12")}";

                break;

            default: throw new ArgumentOutOfRangeException();
            }

            _bytesPerCluster = _sectorsPerCluster * imagePlugin.Info.SectorSize;

            ushort[] _firstFatEntries  = new ushort[_statfs.Blocks];
            ushort[] _secondFatEntries = new ushort[_statfs.Blocks];
            bool     _firstFatValid    = true;
            bool     _secondFatValid   = true;

            if (_fat12)
            {
                AaruConsole.DebugWriteLine("FAT plugin", "Reading FAT12");

                byte[] fatBytes = imagePlugin.ReadSectors(_fatFirstSector, _sectorsPerFat);

                int pos = 0;

                for (int i = 0; i + 3 < fatBytes.Length && pos < _firstFatEntries.Length; i += 3)
                {
                    _firstFatEntries[pos++] = (ushort)(((fatBytes[i + 1] & 0xF) << 8) + fatBytes[i + 0]);

                    if (pos >= _firstFatEntries.Length)
                    {
                        break;
                    }

                    _firstFatEntries[pos++] = (ushort)(((fatBytes[i + 1] & 0xF0) >> 4) + (fatBytes[i + 2] << 4));
                }

                fatBytes = imagePlugin.ReadSectors(_fatFirstSector + _sectorsPerFat, _sectorsPerFat);

                _fatEntries = new ushort[_statfs.Blocks];

                pos = 0;

                for (int i = 0; i + 3 < fatBytes.Length && pos < _secondFatEntries.Length; i += 3)
                {
                    _secondFatEntries[pos++] = (ushort)(((fatBytes[i + 1] & 0xF) << 8) + fatBytes[i + 0]);

                    if (pos >= _secondFatEntries.Length)
                    {
                        break;
                    }

                    _secondFatEntries[pos++] = (ushort)(((fatBytes[i + 1] & 0xF0) >> 4) + (fatBytes[i + 2] << 4));
                }

                foreach (ushort entry in _firstFatEntries)
                {
                    if (entry >= FAT12_RESERVED ||
                        entry <= _statfs.Blocks)
                    {
                        continue;
                    }

                    _firstFatValid = false;

                    break;
                }

                foreach (ushort entry in _secondFatEntries)
                {
                    if (entry >= FAT12_RESERVED ||
                        entry <= _statfs.Blocks)
                    {
                        continue;
                    }

                    _secondFatValid = false;

                    break;
                }

                if (_firstFatValid == _secondFatValid)
                {
                    _fatEntries = _useFirstFat ? _firstFatEntries : _secondFatEntries;
                }
                else if (_firstFatValid)
                {
                    _fatEntries = _firstFatEntries;
                }
                else
                {
                    _fatEntries = _secondFatEntries;
                }
            }
            else if (_fat16)
            {
                AaruConsole.DebugWriteLine("FAT plugin", "Reading FAT16");

                byte[] fatBytes = imagePlugin.ReadSectors(_fatFirstSector, _sectorsPerFat);

                AaruConsole.DebugWriteLine("FAT plugin", "Casting FAT");
                _firstFatEntries = MemoryMarshal.Cast <byte, ushort>(fatBytes).ToArray();

                fatBytes = imagePlugin.ReadSectors(_fatFirstSector + _sectorsPerFat, _sectorsPerFat);

                AaruConsole.DebugWriteLine("FAT plugin", "Casting FAT");
                _secondFatEntries = MemoryMarshal.Cast <byte, ushort>(fatBytes).ToArray();

                foreach (ushort entry in _firstFatEntries)
                {
                    if (entry >= FAT16_RESERVED ||
                        entry <= _statfs.Blocks)
                    {
                        continue;
                    }

                    _firstFatValid = false;

                    break;
                }

                foreach (ushort entry in _secondFatEntries)
                {
                    if (entry >= FAT16_RESERVED ||
                        entry <= _statfs.Blocks)
                    {
                        continue;
                    }

                    _secondFatValid = false;

                    break;
                }

                if (_firstFatValid == _secondFatValid)
                {
                    _fatEntries = _useFirstFat ? _firstFatEntries : _secondFatEntries;
                }
                else if (_firstFatValid)
                {
                    _fatEntries = _firstFatEntries;
                }
                else
                {
                    _fatEntries = _secondFatEntries;
                }
            }

            // TODO: Check how this affects international filenames
            _cultureInfo    = new CultureInfo("en-US", false);
            _directoryCache = new Dictionary <string, Dictionary <string, CompleteDirectoryEntry> >();

            // Check it is really an OS/2 EA file
            if (_eaDirEntry.start_cluster != 0)
            {
                CacheEaData();
                ushort eamagic = BitConverter.ToUInt16(_cachedEaData, 0);

                if (eamagic != EADATA_MAGIC)
                {
                    _eaDirEntry   = new DirectoryEntry();
                    _cachedEaData = null;
                }
                else
                {
                    _eaCache = new Dictionary <string, Dictionary <string, byte[]> >();
                }
            }
            else if (_fat32)
            {
                _eaCache = new Dictionary <string, Dictionary <string, byte[]> >();
            }

            // Check OS/2 .LONGNAME
            if (_eaCache != null &&
                (_namespace == Namespace.Os2 || _namespace == Namespace.Ecs) &&
                !_fat32)
            {
                List <KeyValuePair <string, CompleteDirectoryEntry> > rootFilesWithEas =
                    _rootDirectoryCache.Where(t => t.Value.Dirent.ea_handle != 0).ToList();

                foreach (KeyValuePair <string, CompleteDirectoryEntry> fileWithEa in rootFilesWithEas)
                {
                    Dictionary <string, byte[]> eas = GetEas(fileWithEa.Value.Dirent.ea_handle);

                    if (eas is null)
                    {
                        continue;
                    }

                    if (!eas.TryGetValue("com.microsoft.os2.longname", out byte[] longnameEa))
コード例 #20
0
        public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information,
                                   Encoding encoding)
        {
            Encoding    = encoding ?? Encoding.UTF8;
            information = "";

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

            uint sbAddr = NILFS2_SUPER_OFFSET / imagePlugin.Info.SectorSize;

            if (sbAddr == 0)
            {
                sbAddr = 1;
            }

            uint sbSize = (uint)(Marshal.SizeOf <Superblock>() / imagePlugin.Info.SectorSize);

            if (Marshal.SizeOf <Superblock>() % imagePlugin.Info.SectorSize != 0)
            {
                sbSize++;
            }

            byte[] sector = imagePlugin.ReadSectors(partition.Start + sbAddr, sbSize);

            if (sector.Length < Marshal.SizeOf <Superblock>())
            {
                return;
            }

            Superblock nilfsSb = Marshal.ByteArrayToStructureLittleEndian <Superblock>(sector);

            if (nilfsSb.magic != NILFS2_MAGIC)
            {
                return;
            }

            var sb = new StringBuilder();

            sb.AppendLine("NILFS2 filesystem");
            sb.AppendFormat("Version {0}.{1}", nilfsSb.rev_level, nilfsSb.minor_rev_level).AppendLine();
            sb.AppendFormat("{0} bytes per block", 1 << (int)(nilfsSb.log_block_size + 10)).AppendLine();
            sb.AppendFormat("{0} bytes in volume", nilfsSb.dev_size).AppendLine();
            sb.AppendFormat("{0} blocks per segment", nilfsSb.blocks_per_segment).AppendLine();
            sb.AppendFormat("{0} segments", nilfsSb.nsegments).AppendLine();

            if (nilfsSb.creator_os == 0)
            {
                sb.AppendLine("Filesystem created on Linux");
            }
            else
            {
                sb.AppendFormat("Creator OS code: {0}", nilfsSb.creator_os).AppendLine();
            }

            sb.AppendFormat("{0} bytes per inode", nilfsSb.inode_size).AppendLine();
            sb.AppendFormat("Volume UUID: {0}", nilfsSb.uuid).AppendLine();
            sb.AppendFormat("Volume name: {0}", StringHandlers.CToString(nilfsSb.volume_name, Encoding)).AppendLine();
            sb.AppendFormat("Volume created on {0}", DateHandlers.UnixUnsignedToDateTime(nilfsSb.ctime)).AppendLine();

            sb.AppendFormat("Volume last mounted on {0}", DateHandlers.UnixUnsignedToDateTime(nilfsSb.mtime)).
            AppendLine();

            sb.AppendFormat("Volume last written on {0}", DateHandlers.UnixUnsignedToDateTime(nilfsSb.wtime)).
            AppendLine();

            information = sb.ToString();

            XmlFsType = new FileSystemType
            {
                Type                      = "NILFS2 filesystem",
                ClusterSize               = (uint)(1 << (int)(nilfsSb.log_block_size + 10)),
                VolumeName                = StringHandlers.CToString(nilfsSb.volume_name, Encoding),
                VolumeSerial              = nilfsSb.uuid.ToString(),
                CreationDate              = DateHandlers.UnixUnsignedToDateTime(nilfsSb.ctime),
                CreationDateSpecified     = true,
                ModificationDate          = DateHandlers.UnixUnsignedToDateTime(nilfsSb.wtime),
                ModificationDateSpecified = true
            };

            if (nilfsSb.creator_os == 0)
            {
                XmlFsType.SystemIdentifier = "Linux";
            }

            XmlFsType.Clusters = nilfsSb.dev_size / XmlFsType.ClusterSize;
        }
コード例 #21
0
ファイル: EFS.cs プロジェクト: paulyc/Aaru
        public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information,
                                   Encoding encoding)
        {
            Encoding    = encoding ?? Encoding.GetEncoding("iso-8859-15");
            information = "";

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

            var efsSb = new Superblock();

            // Misaligned
            if (imagePlugin.Info.XmlMediaType == XmlMediaType.OpticalDisc)
            {
                uint sbSize = (uint)((Marshal.SizeOf <Superblock>() + 0x400) / imagePlugin.Info.SectorSize);

                if ((Marshal.SizeOf <Superblock>() + 0x400) % imagePlugin.Info.SectorSize != 0)
                {
                    sbSize++;
                }

                byte[] sector = imagePlugin.ReadSectors(partition.Start, sbSize);

                if (sector.Length < Marshal.SizeOf <Superblock>())
                {
                    return;
                }

                byte[] sbpiece = new byte[Marshal.SizeOf <Superblock>()];

                Array.Copy(sector, 0x200, sbpiece, 0, Marshal.SizeOf <Superblock>());

                efsSb = Marshal.ByteArrayToStructureBigEndian <Superblock>(sbpiece);

                AaruConsole.DebugWriteLine("EFS plugin", "magic at 0x{0:X3} = 0x{1:X8} (expected 0x{2:X8} or 0x{3:X8})",
                                           0x200, efsSb.sb_magic, EFS_MAGIC, EFS_MAGIC_NEW);
            }
            else
            {
                uint sbSize = (uint)(Marshal.SizeOf <Superblock>() / imagePlugin.Info.SectorSize);

                if (Marshal.SizeOf <Superblock>() % imagePlugin.Info.SectorSize != 0)
                {
                    sbSize++;
                }

                byte[] sector = imagePlugin.ReadSectors(partition.Start + 1, sbSize);

                if (sector.Length < Marshal.SizeOf <Superblock>())
                {
                    return;
                }

                efsSb = Marshal.ByteArrayToStructureBigEndian <Superblock>(sector);

                AaruConsole.DebugWriteLine("EFS plugin", "magic at {0} = 0x{1:X8} (expected 0x{2:X8} or 0x{3:X8})", 1,
                                           efsSb.sb_magic, EFS_MAGIC, EFS_MAGIC_NEW);
            }

            if (efsSb.sb_magic != EFS_MAGIC &&
                efsSb.sb_magic != EFS_MAGIC_NEW)
            {
                return;
            }

            var sb = new StringBuilder();

            sb.AppendLine("SGI extent filesystem");

            if (efsSb.sb_magic == EFS_MAGIC_NEW)
            {
                sb.AppendLine("New version");
            }

            sb.AppendFormat("Filesystem size: {0} basic blocks", efsSb.sb_size).AppendLine();
            sb.AppendFormat("First cylinder group starts at block {0}", efsSb.sb_firstcg).AppendLine();
            sb.AppendFormat("Cylinder group size: {0} basic blocks", efsSb.sb_cgfsize).AppendLine();
            sb.AppendFormat("{0} inodes per cylinder group", efsSb.sb_cgisize).AppendLine();
            sb.AppendFormat("{0} sectors per track", efsSb.sb_sectors).AppendLine();
            sb.AppendFormat("{0} heads per cylinder", efsSb.sb_heads).AppendLine();
            sb.AppendFormat("{0} cylinder groups", efsSb.sb_ncg).AppendLine();
            sb.AppendFormat("Volume created on {0}", DateHandlers.UnixToDateTime(efsSb.sb_time)).AppendLine();
            sb.AppendFormat("{0} bytes on bitmap", efsSb.sb_bmsize).AppendLine();
            sb.AppendFormat("{0} free blocks", efsSb.sb_tfree).AppendLine();
            sb.AppendFormat("{0} free inodes", efsSb.sb_tinode).AppendLine();

            if (efsSb.sb_bmblock > 0)
            {
                sb.AppendFormat("Bitmap resides at block {0}", efsSb.sb_bmblock).AppendLine();
            }

            if (efsSb.sb_replsb > 0)
            {
                sb.AppendFormat("Replacement superblock resides at block {0}", efsSb.sb_replsb).AppendLine();
            }

            if (efsSb.sb_lastinode > 0)
            {
                sb.AppendFormat("Last inode allocated: {0}", efsSb.sb_lastinode).AppendLine();
            }

            if (efsSb.sb_dirty > 0)
            {
                sb.AppendLine("Volume is dirty");
            }

            sb.AppendFormat("Checksum: 0x{0:X8}", efsSb.sb_checksum).AppendLine();
            sb.AppendFormat("Volume name: {0}", StringHandlers.CToString(efsSb.sb_fname, Encoding)).AppendLine();
            sb.AppendFormat("Volume pack: {0}", StringHandlers.CToString(efsSb.sb_fpack, Encoding)).AppendLine();

            information = sb.ToString();

            XmlFsType = new FileSystemType
            {
                Type                  = "Extent File System",
                ClusterSize           = 512,
                Clusters              = (ulong)efsSb.sb_size,
                FreeClusters          = (ulong)efsSb.sb_tfree,
                FreeClustersSpecified = true,
                Dirty                 = efsSb.sb_dirty > 0,
                VolumeName            = StringHandlers.CToString(efsSb.sb_fname, Encoding),
                VolumeSerial          = $"{efsSb.sb_checksum:X8}",
                CreationDate          = DateHandlers.UnixToDateTime(efsSb.sb_time),
                CreationDateSpecified = true
            };
        }
コード例 #22
0
ファイル: ReFS.cs プロジェクト: paulyc/Aaru
        public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information,
                                   Encoding encoding)
        {
            Encoding    = Encoding.UTF8;
            information = "";

            uint sbSize = (uint)(Marshal.SizeOf <VolumeHeader>() / imagePlugin.Info.SectorSize);

            if (Marshal.SizeOf <VolumeHeader>() % imagePlugin.Info.SectorSize != 0)
            {
                sbSize++;
            }

            if (partition.Start + sbSize >= partition.End)
            {
                return;
            }

            byte[] sector = imagePlugin.ReadSectors(partition.Start, sbSize);

            if (sector.Length < Marshal.SizeOf <VolumeHeader>())
            {
                return;
            }

            VolumeHeader vhdr = Marshal.ByteArrayToStructureLittleEndian <VolumeHeader>(sector);

            AaruConsole.DebugWriteLine("ReFS plugin", "VolumeHeader.jump empty? = {0}",
                                       ArrayHelpers.ArrayIsNullOrEmpty(vhdr.jump));

            AaruConsole.DebugWriteLine("ReFS plugin", "VolumeHeader.signature = {0}",
                                       StringHandlers.CToString(vhdr.signature));

            AaruConsole.DebugWriteLine("ReFS plugin", "VolumeHeader.mustBeZero empty? = {0}",
                                       ArrayHelpers.ArrayIsNullOrEmpty(vhdr.mustBeZero));

            AaruConsole.DebugWriteLine("ReFS plugin", "VolumeHeader.identifier = {0}",
                                       StringHandlers.CToString(BitConverter.GetBytes(vhdr.identifier)));

            AaruConsole.DebugWriteLine("ReFS plugin", "VolumeHeader.length = {0}", vhdr.length);
            AaruConsole.DebugWriteLine("ReFS plugin", "VolumeHeader.checksum = 0x{0:X4}", vhdr.checksum);
            AaruConsole.DebugWriteLine("ReFS plugin", "VolumeHeader.sectors = {0}", vhdr.sectors);
            AaruConsole.DebugWriteLine("ReFS plugin", "VolumeHeader.bytesPerSector = {0}", vhdr.bytesPerSector);

            AaruConsole.DebugWriteLine("ReFS plugin", "VolumeHeader.sectorsPerCluster = {0}", vhdr.sectorsPerCluster);

            AaruConsole.DebugWriteLine("ReFS plugin", "VolumeHeader.unknown1 zero? = {0}", vhdr.unknown1 == 0);
            AaruConsole.DebugWriteLine("ReFS plugin", "VolumeHeader.unknown2 zero? = {0}", vhdr.unknown2 == 0);
            AaruConsole.DebugWriteLine("ReFS plugin", "VolumeHeader.unknown3 zero? = {0}", vhdr.unknown3 == 0);
            AaruConsole.DebugWriteLine("ReFS plugin", "VolumeHeader.unknown4 zero? = {0}", vhdr.unknown4 == 0);

            AaruConsole.DebugWriteLine("ReFS plugin", "VolumeHeader.unknown5 empty? = {0}",
                                       ArrayHelpers.ArrayIsNullOrEmpty(vhdr.unknown5));

            if (vhdr.identifier != FSRS ||
                !ArrayHelpers.ArrayIsNullOrEmpty(vhdr.mustBeZero) ||
                !vhdr.signature.SequenceEqual(_signature))
            {
                return;
            }

            var sb = new StringBuilder();

            sb.AppendLine("Microsoft Resilient File System");
            sb.AppendFormat("Volume uses {0} bytes per sector", vhdr.bytesPerSector).AppendLine();

            sb.AppendFormat("Volume uses {0} sectors per cluster ({1} bytes)", vhdr.sectorsPerCluster,
                            vhdr.sectorsPerCluster * vhdr.bytesPerSector).AppendLine();

            sb.AppendFormat("Volume has {0} sectors ({1} bytes)", vhdr.sectors, vhdr.sectors * vhdr.bytesPerSector).
            AppendLine();

            information = sb.ToString();

            XmlFsType = new FileSystemType
            {
                Type        = "Resilient File System",
                ClusterSize = vhdr.bytesPerSector * vhdr.sectorsPerCluster,
                Clusters    = vhdr.sectors / vhdr.sectorsPerCluster
            };
        }
コード例 #23
0
ファイル: Read.cs プロジェクト: morefun0302/Aaru
        public bool Open(IFilter imageFilter)
        {
            Stream stream = imageFilter.GetDataForkStream();

            _vmEHdr = new VMwareExtentHeader();
            _vmCHdr = new VMwareCowHeader();
            bool embedded = false;

            if (stream.Length > Marshal.SizeOf <VMwareExtentHeader>())
            {
                stream.Seek(0, SeekOrigin.Begin);
                byte[] vmEHdrB = new byte[Marshal.SizeOf <VMwareExtentHeader>()];
                stream.Read(vmEHdrB, 0, Marshal.SizeOf <VMwareExtentHeader>());
                _vmEHdr = Marshal.ByteArrayToStructureLittleEndian <VMwareExtentHeader>(vmEHdrB);
            }

            if (stream.Length > Marshal.SizeOf <VMwareCowHeader>())
            {
                stream.Seek(0, SeekOrigin.Begin);
                byte[] vmCHdrB = new byte[Marshal.SizeOf <VMwareCowHeader>()];
                stream.Read(vmCHdrB, 0, Marshal.SizeOf <VMwareCowHeader>());
                _vmCHdr = Marshal.ByteArrayToStructureLittleEndian <VMwareCowHeader>(vmCHdrB);
            }

            var  ddfStream = new MemoryStream();
            bool vmEHdrSet = false;
            bool cowD      = false;

            if (_vmEHdr.magic == VMWARE_EXTENT_MAGIC)
            {
                vmEHdrSet = true;
                _gdFilter = imageFilter;

                if (_vmEHdr.descriptorOffset == 0 ||
                    _vmEHdr.descriptorSize == 0)
                {
                    throw new Exception("Please open VMDK descriptor.");
                }

                byte[] ddfEmbed = new byte[_vmEHdr.descriptorSize * SECTOR_SIZE];

                stream.Seek((long)(_vmEHdr.descriptorOffset * SECTOR_SIZE), SeekOrigin.Begin);
                stream.Read(ddfEmbed, 0, ddfEmbed.Length);
                ddfStream.Write(ddfEmbed, 0, ddfEmbed.Length);

                embedded = true;
            }
            else if (_vmCHdr.magic == VMWARE_COW_MAGIC)
            {
                _gdFilter = imageFilter;
                cowD      = true;
            }
            else
            {
                byte[] ddfMagic = new byte[0x15];
                stream.Seek(0, SeekOrigin.Begin);
                stream.Read(ddfMagic, 0, 0x15);

                if (!_ddfMagicBytes.SequenceEqual(ddfMagic))
                {
                    throw new Exception("Not a descriptor.");
                }

                stream.Seek(0, SeekOrigin.Begin);
                byte[] ddfExternal = new byte[imageFilter.GetDataForkLength()];
                stream.Read(ddfExternal, 0, ddfExternal.Length);
                ddfStream.Write(ddfExternal, 0, ddfExternal.Length);
            }

            _extents = new Dictionary <ulong, VMwareExtent>();
            ulong currentSector = 0;

            bool matchedCyls = false, matchedHds = false, matchedSpt = false;

            if (cowD)
            {
                int    cowCount = 1;
                string basePath = Path.GetFileNameWithoutExtension(imageFilter.GetBasePath());

                while (true)
                {
                    string curPath;

                    if (cowCount == 1)
                    {
                        curPath = basePath + ".vmdk";
                    }
                    else
                    {
                        curPath = $"{basePath}-{cowCount:D2}.vmdk";
                    }

                    if (!File.Exists(curPath))
                    {
                        break;
                    }

                    IFilter extentFilter = new FiltersList().GetFilter(curPath);
                    Stream  extentStream = extentFilter.GetDataForkStream();

                    if (stream.Length > Marshal.SizeOf <VMwareCowHeader>())
                    {
                        var extHdrCow = new VMwareCowHeader();
                        extentStream.Seek(0, SeekOrigin.Begin);
                        byte[] vmCHdrB = new byte[Marshal.SizeOf <VMwareCowHeader>()];
                        extentStream.Read(vmCHdrB, 0, Marshal.SizeOf <VMwareCowHeader>());
                        extHdrCow = Marshal.ByteArrayToStructureLittleEndian <VMwareCowHeader>(vmCHdrB);

                        if (extHdrCow.magic != VMWARE_COW_MAGIC)
                        {
                            break;
                        }

                        var newExtent = new VMwareExtent
                        {
                            Access   = "RW",
                            Filter   = extentFilter,
                            Filename = extentFilter.GetFilename(),
                            Offset   = 0,
                            Sectors  = extHdrCow.sectors,
                            Type     = "SPARSE"
                        };

                        AaruConsole.DebugWriteLine("VMware plugin", "{0} {1} {2} \"{3}\" {4}", newExtent.Access,
                                                   newExtent.Sectors, newExtent.Type, newExtent.Filename,
                                                   newExtent.Offset);

                        _extents.Add(currentSector, newExtent);
                        currentSector += newExtent.Sectors;
                    }
                    else
                    {
                        break;
                    }

                    cowCount++;
                }

                _imageType = VM_TYPE_SPLIT_SPARSE;
            }
            else
            {
                ddfStream.Seek(0, SeekOrigin.Begin);

                var regexVersion   = new Regex(REGEX_VERSION);
                var regexCid       = new Regex(REGEX_CID);
                var regexParentCid = new Regex(REGEX_CID_PARENT);
                var regexType      = new Regex(REGEX_TYPE);
                var regexExtent    = new Regex(REGEX_EXTENT);
                var regexParent    = new Regex(PARENT_REGEX);
                var regexCylinders = new Regex(REGEX_DDB_CYLINDERS);
                var regexHeads     = new Regex(REGEX_DDB_HEADS);
                var regexSectors   = new Regex(REGEX_DDB_SECTORS);

                var ddfStreamRdr = new StreamReader(ddfStream);

                while (ddfStreamRdr.Peek() >= 0)
                {
                    string line = ddfStreamRdr.ReadLine();

                    Match matchVersion   = regexVersion.Match(line);
                    Match matchCid       = regexCid.Match(line);
                    Match matchParentCid = regexParentCid.Match(line);
                    Match matchType      = regexType.Match(line);
                    Match matchExtent    = regexExtent.Match(line);
                    Match matchParent    = regexParent.Match(line);
                    Match matchCylinders = regexCylinders.Match(line);
                    Match matchHeads     = regexHeads.Match(line);
                    Match matchSectors   = regexSectors.Match(line);

                    if (matchVersion.Success)
                    {
                        uint.TryParse(matchVersion.Groups["version"].Value, out _version);
                        AaruConsole.DebugWriteLine("VMware plugin", "version = {0}", _version);
                    }
                    else if (matchCid.Success)
                    {
                        _cid = Convert.ToUInt32(matchCid.Groups["cid"].Value, 16);
                        AaruConsole.DebugWriteLine("VMware plugin", "cid = {0:x8}", _cid);
                    }
                    else if (matchParentCid.Success)
                    {
                        _parentCid = Convert.ToUInt32(matchParentCid.Groups["cid"].Value, 16);
                        AaruConsole.DebugWriteLine("VMware plugin", "parentCID = {0:x8}", _parentCid);
                    }
                    else if (matchType.Success)
                    {
                        _imageType = matchType.Groups["type"].Value;
                        AaruConsole.DebugWriteLine("VMware plugin", "createType = \"{0}\"", _imageType);
                    }
                    else if (matchExtent.Success)
                    {
                        var newExtent = new VMwareExtent
                        {
                            Access = matchExtent.Groups["access"].Value
                        };

                        if (!embedded)
                        {
                            newExtent.Filter =
                                new FiltersList().
                                GetFilter(Path.Combine(Path.GetDirectoryName(imageFilter.GetBasePath()),
                                                       matchExtent.Groups["filename"].Value));
                        }
                        else
                        {
                            newExtent.Filter = imageFilter;
                        }

                        uint.TryParse(matchExtent.Groups["offset"].Value, out newExtent.Offset);
                        uint.TryParse(matchExtent.Groups["sectors"].Value, out newExtent.Sectors);
                        newExtent.Type = matchExtent.Groups["type"].Value;

                        AaruConsole.DebugWriteLine("VMware plugin", "{0} {1} {2} \"{3}\" {4}", newExtent.Access,
                                                   newExtent.Sectors, newExtent.Type, newExtent.Filename,
                                                   newExtent.Offset);

                        _extents.Add(currentSector, newExtent);
                        currentSector += newExtent.Sectors;
                    }
                    else if (matchParent.Success)
                    {
                        _parentName = matchParent.Groups["filename"].Value;
                        AaruConsole.DebugWriteLine("VMware plugin", "parentFileNameHint = \"{0}\"", _parentName);
                        _hasParent = true;
                    }
                    else if (matchCylinders.Success)
                    {
                        uint.TryParse(matchCylinders.Groups["cylinders"].Value, out _imageInfo.Cylinders);
                        matchedCyls = true;
                    }
                    else if (matchHeads.Success)
                    {
                        uint.TryParse(matchHeads.Groups["heads"].Value, out _imageInfo.Heads);
                        matchedHds = true;
                    }
                    else if (matchSectors.Success)
                    {
                        uint.TryParse(matchSectors.Groups["sectors"].Value, out _imageInfo.SectorsPerTrack);
                        matchedSpt = true;
                    }
                }
            }

            if (_extents.Count == 0)
            {
                throw new Exception("Did not find any extent");
            }

            switch (_imageType)
            {
            case VM_TYPE_MONO_SPARSE:      //"monolithicSparse";
            case VM_TYPE_MONO_FLAT:        //"monolithicFlat";
            case VM_TYPE_SPLIT_SPARSE:     //"twoGbMaxExtentSparse";
            case VM_TYPE_SPLIT_FLAT:       //"twoGbMaxExtentFlat";
            case VMFS_TYPE_FLAT:           //"vmfsPreallocated";
            case VMFS_TYPE_ZERO:           //"vmfsEagerZeroedThick";
            case VMFS_TYPE_THIN:           //"vmfsThin";
            case VMFS_TYPE_SPARSE:         //"vmfsSparse";
            case VMFS_TYPE:                //"vmfs";
            case VM_TYPE_STREAM:           //"streamOptimized";
                break;

            case VM_TYPE_FULL_DEVICE:     //"fullDevice";
            case VM_TYPE_PART_DEVICE:     //"partitionedDevice";
            case VMFS_TYPE_RDM:           //"vmfsRDM";
            case VMFS_TYPE_RDM_OLD:       //"vmfsRawDeviceMap";
            case VMFS_TYPE_RDMP:          //"vmfsRDMP";
            case VMFS_TYPE_RDMP_OLD:      //"vmfsPassthroughRawDeviceMap";
            case VMFS_TYPE_RAW:           //"vmfsRaw";
                throw new
                      ImageNotSupportedException("Raw device image files are not supported, try accessing the device directly.");

            default: throw new ImageNotSupportedException($"Dunno how to handle \"{_imageType}\" extents.");
            }

            bool oneNoFlat = cowD;

            foreach (VMwareExtent extent in _extents.Values)
            {
                if (extent.Filter == null)
                {
                    throw new Exception($"Extent file {extent.Filename} not found.");
                }

                if (extent.Access == "NOACCESS")
                {
                    throw new Exception("Cannot access NOACCESS extents ;).");
                }

                if (extent.Type == "FLAT" ||
                    extent.Type == "ZERO" ||
                    extent.Type == "VMFS" ||
                    cowD)
                {
                    continue;
                }

                Stream extentStream = extent.Filter.GetDataForkStream();
                extentStream.Seek(0, SeekOrigin.Begin);

                if (extentStream.Length < SECTOR_SIZE)
                {
                    throw new Exception($"Extent {extent.Filename} is too small.");
                }

                byte[] extentHdrB = new byte[Marshal.SizeOf <VMwareExtentHeader>()];
                extentStream.Read(extentHdrB, 0, Marshal.SizeOf <VMwareExtentHeader>());
                VMwareExtentHeader extentHdr = Marshal.ByteArrayToStructureLittleEndian <VMwareExtentHeader>(extentHdrB);

                if (extentHdr.magic != VMWARE_EXTENT_MAGIC)
                {
                    throw new Exception($"{extent.Filter} is not an VMware extent.");
                }

                if (extentHdr.capacity < extent.Sectors)
                {
                    throw new
                          Exception($"Extent contains incorrect number of sectors, {extentHdr.capacity}. {extent.Sectors} were expected");
                }

                // TODO: Support compressed extents
                if (extentHdr.compression != COMPRESSION_NONE)
                {
                    throw new ImageNotSupportedException("Compressed extents are not yet supported.");
                }

                if (!vmEHdrSet)
                {
                    _vmEHdr   = extentHdr;
                    _gdFilter = extent.Filter;
                    vmEHdrSet = true;
                }

                oneNoFlat = true;
            }

            if (oneNoFlat &&
                !vmEHdrSet &&
                !cowD)
            {
                throw new
                      Exception("There are sparse extents but there is no header to find the grain tables, cannot proceed.");
            }

            _imageInfo.Sectors = currentSector;

            uint grains    = 0;
            uint gdEntries = 0;
            long gdOffset  = 0;
            uint gtEsPerGt = 0;

            if (oneNoFlat && !cowD)
            {
                AaruConsole.DebugWriteLine("VMware plugin", "vmEHdr.magic = 0x{0:X8}", _vmEHdr.magic);
                AaruConsole.DebugWriteLine("VMware plugin", "vmEHdr.version = {0}", _vmEHdr.version);
                AaruConsole.DebugWriteLine("VMware plugin", "vmEHdr.flags = 0x{0:X8}", _vmEHdr.flags);
                AaruConsole.DebugWriteLine("VMware plugin", "vmEHdr.capacity = {0}", _vmEHdr.capacity);
                AaruConsole.DebugWriteLine("VMware plugin", "vmEHdr.grainSize = {0}", _vmEHdr.grainSize);
                AaruConsole.DebugWriteLine("VMware plugin", "vmEHdr.descriptorOffset = {0}", _vmEHdr.descriptorOffset);
                AaruConsole.DebugWriteLine("VMware plugin", "vmEHdr.descriptorSize = {0}", _vmEHdr.descriptorSize);
                AaruConsole.DebugWriteLine("VMware plugin", "vmEHdr.GTEsPerGT = {0}", _vmEHdr.GTEsPerGT);
                AaruConsole.DebugWriteLine("VMware plugin", "vmEHdr.rgdOffset = {0}", _vmEHdr.rgdOffset);
                AaruConsole.DebugWriteLine("VMware plugin", "vmEHdr.gdOffset = {0}", _vmEHdr.gdOffset);
                AaruConsole.DebugWriteLine("VMware plugin", "vmEHdr.overhead = {0}", _vmEHdr.overhead);
                AaruConsole.DebugWriteLine("VMware plugin", "vmEHdr.uncleanShutdown = {0}", _vmEHdr.uncleanShutdown);

                AaruConsole.DebugWriteLine("VMware plugin", "vmEHdr.singleEndLineChar = 0x{0:X2}",
                                           _vmEHdr.singleEndLineChar);

                AaruConsole.DebugWriteLine("VMware plugin", "vmEHdr.nonEndLineChar = 0x{0:X2}", _vmEHdr.nonEndLineChar);

                AaruConsole.DebugWriteLine("VMware plugin", "vmEHdr.doubleEndLineChar1 = 0x{0:X2}",
                                           _vmEHdr.doubleEndLineChar1);

                AaruConsole.DebugWriteLine("VMware plugin", "vmEHdr.doubleEndLineChar2 = 0x{0:X2}",
                                           _vmEHdr.doubleEndLineChar2);

                AaruConsole.DebugWriteLine("VMware plugin", "vmEHdr.compression = 0x{0:X4}", _vmEHdr.compression);

                _grainSize = _vmEHdr.grainSize;
                grains     = (uint)(_imageInfo.Sectors / _vmEHdr.grainSize) + 1;
                gdEntries  = grains / _vmEHdr.GTEsPerGT;
                gtEsPerGt  = _vmEHdr.GTEsPerGT;

                if ((_vmEHdr.flags & FLAGS_USE_REDUNDANT_TABLE) == FLAGS_USE_REDUNDANT_TABLE)
                {
                    gdOffset = (long)_vmEHdr.rgdOffset;
                }
                else
                {
                    gdOffset = (long)_vmEHdr.gdOffset;
                }
            }
            else if (oneNoFlat && cowD)
            {
                AaruConsole.DebugWriteLine("VMware plugin", "vmCHdr.magic = 0x{0:X8}", _vmCHdr.magic);
                AaruConsole.DebugWriteLine("VMware plugin", "vmCHdr.version = {0}", _vmCHdr.version);
                AaruConsole.DebugWriteLine("VMware plugin", "vmCHdr.flags = 0x{0:X8}", _vmCHdr.flags);
                AaruConsole.DebugWriteLine("VMware plugin", "vmCHdr.sectors = {0}", _vmCHdr.sectors);
                AaruConsole.DebugWriteLine("VMware plugin", "vmCHdr.grainSize = {0}", _vmCHdr.grainSize);
                AaruConsole.DebugWriteLine("VMware plugin", "vmCHdr.gdOffset = {0}", _vmCHdr.gdOffset);
                AaruConsole.DebugWriteLine("VMware plugin", "vmCHdr.numGDEntries = {0}", _vmCHdr.numGDEntries);
                AaruConsole.DebugWriteLine("VMware plugin", "vmCHdr.freeSector = {0}", _vmCHdr.freeSector);
                AaruConsole.DebugWriteLine("VMware plugin", "vmCHdr.cylinders = {0}", _vmCHdr.cylinders);
                AaruConsole.DebugWriteLine("VMware plugin", "vmCHdr.heads = {0}", _vmCHdr.heads);
                AaruConsole.DebugWriteLine("VMware plugin", "vmCHdr.spt = {0}", _vmCHdr.spt);
                AaruConsole.DebugWriteLine("VMware plugin", "vmCHdr.generation = {0}", _vmCHdr.generation);

                AaruConsole.DebugWriteLine("VMware plugin", "vmCHdr.name = {0}",
                                           StringHandlers.CToString(_vmCHdr.name));

                AaruConsole.DebugWriteLine("VMware plugin", "vmCHdr.description = {0}",
                                           StringHandlers.CToString(_vmCHdr.description));

                AaruConsole.DebugWriteLine("VMware plugin", "vmCHdr.savedGeneration = {0}", _vmCHdr.savedGeneration);
                AaruConsole.DebugWriteLine("VMware plugin", "vmCHdr.uncleanShutdown = {0}", _vmCHdr.uncleanShutdown);

                _grainSize            = _vmCHdr.grainSize;
                grains                = (uint)(_imageInfo.Sectors / _vmCHdr.grainSize) + 1;
                gdEntries             = _vmCHdr.numGDEntries;
                gdOffset              = _vmCHdr.gdOffset;
                gtEsPerGt             = grains / gdEntries;
                _imageInfo.MediaTitle = StringHandlers.CToString(_vmCHdr.name);
                _imageInfo.Comments   = StringHandlers.CToString(_vmCHdr.description);
                _version              = _vmCHdr.version;
            }

            if (oneNoFlat)
            {
                if (grains == 0 ||
                    gdEntries == 0)
                {
                    throw new Exception("Some error ocurred setting GD sizes");
                }

                AaruConsole.DebugWriteLine("VMware plugin", "{0} sectors in {1} grains in {2} tables",
                                           _imageInfo.Sectors, grains, gdEntries);

                Stream gdStream = _gdFilter.GetDataForkStream();

                gdStream.Seek(gdOffset * SECTOR_SIZE, SeekOrigin.Begin);

                AaruConsole.DebugWriteLine("VMware plugin", "Reading grain directory");
                byte[] gdBytes = new byte[gdEntries * 4];
                gdStream.Read(gdBytes, 0, gdBytes.Length);
                Span <uint> gd = MemoryMarshal.Cast <byte, uint>(gdBytes);

                AaruConsole.DebugWriteLine("VMware plugin", "Reading grain tables");
                uint currentGrain = 0;
                _gTable = new uint[grains];

                foreach (uint gtOff in gd)
                {
                    byte[] gtBytes = new byte[gtEsPerGt * 4];
                    gdStream.Seek(gtOff * SECTOR_SIZE, SeekOrigin.Begin);
                    gdStream.Read(gtBytes, 0, gtBytes.Length);

                    uint[] currentGt = MemoryMarshal.Cast <byte, uint>(gtBytes).ToArray();
                    Array.Copy(currentGt, 0, _gTable, currentGrain, gtEsPerGt);
                    currentGrain += gtEsPerGt;

                    // TODO: Check speed here

                    /*
                     * for(int i = 0; i < gtEsPerGt; i++)
                     * {
                     *  gTable[currentGrain] = BitConverter.ToUInt32(gtBytes, i * 4);
                     *  currentGrain++;
                     * }
                     */
                }

                _maxCachedGrains = (uint)(MAX_CACHE_SIZE / (_grainSize * SECTOR_SIZE));

                _grainCache = new Dictionary <ulong, byte[]>();
            }

            if (_hasParent)
            {
                IFilter parentFilter =
                    new FiltersList().GetFilter(Path.Combine(imageFilter.GetParentFolder(), _parentName));

                if (parentFilter == null)
                {
                    throw new Exception($"Cannot find parent \"{_parentName}\".");
                }

                _parentImage = new VMware();

                if (!_parentImage.Open(parentFilter))
                {
                    throw new Exception($"Cannot open parent \"{_parentName}\".");
                }
            }

            _sectorCache = new Dictionary <ulong, byte[]>();

            _imageInfo.CreationTime         = imageFilter.GetCreationTime();
            _imageInfo.LastModificationTime = imageFilter.GetLastWriteTime();
            _imageInfo.MediaTitle           = Path.GetFileNameWithoutExtension(imageFilter.GetFilename());
            _imageInfo.SectorSize           = SECTOR_SIZE;
            _imageInfo.XmlMediaType         = XmlMediaType.BlockMedia;
            _imageInfo.MediaType            = MediaType.GENERIC_HDD;
            _imageInfo.ImageSize            = _imageInfo.Sectors * SECTOR_SIZE;

            // VMDK version 1 started on VMware 4, so there is a previous version, "COWD"
            _imageInfo.Version = cowD ? $"{_version}" : $"{_version + 3}";

            if (cowD)
            {
                _imageInfo.Cylinders       = _vmCHdr.cylinders;
                _imageInfo.Heads           = _vmCHdr.heads;
                _imageInfo.SectorsPerTrack = _vmCHdr.spt;
            }
            else if (!matchedCyls ||
                     !matchedHds ||
                     !matchedSpt)
            {
                _imageInfo.Cylinders       = (uint)(_imageInfo.Sectors / 16 / 63);
                _imageInfo.Heads           = 16;
                _imageInfo.SectorsPerTrack = 63;
            }

            return(true);
        }
コード例 #24
0
        public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information,
                                   Encoding encoding)
        {
            Encoding    = encoding ?? Encoding.GetEncoding("iso-8859-15");
            information = "";

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

            uint sbSize = (uint)(Marshal.SizeOf <Superblock>() / imagePlugin.Info.SectorSize);

            if (Marshal.SizeOf <Superblock>() % imagePlugin.Info.SectorSize != 0)
            {
                sbSize++;
            }

            byte[] sector = imagePlugin.ReadSectors(partition.Start, sbSize);

            if (sector.Length < Marshal.SizeOf <Superblock>())
            {
                return;
            }

            Superblock unicosSb = Marshal.ByteArrayToStructureBigEndian <Superblock>(sector);

            if (unicosSb.s_magic != UNICOS_MAGIC)
            {
                return;
            }

            var sb = new StringBuilder();

            sb.AppendLine("UNICOS filesystem");

            if (unicosSb.s_secure == UNICOS_SECURE)
            {
                sb.AppendLine("Volume is secure");
            }

            sb.AppendFormat("Volume contains {0} partitions", unicosSb.s_npart).AppendLine();
            sb.AppendFormat("{0} bytes per sector", unicosSb.s_iounit).AppendLine();
            sb.AppendLine("4096 bytes per block");
            sb.AppendFormat("{0} data blocks in volume", unicosSb.s_fsize).AppendLine();
            sb.AppendFormat("Root resides on inode {0}", unicosSb.s_root).AppendLine();
            sb.AppendFormat("{0} inodes in volume", unicosSb.s_isize).AppendLine();
            sb.AppendFormat("Volume last updated on {0}", DateHandlers.UnixToDateTime(unicosSb.s_time)).AppendLine();

            if (unicosSb.s_error > 0)
            {
                sb.AppendFormat("Volume is dirty, error code = 0x{0:X16}", unicosSb.s_error).AppendLine();
            }

            sb.AppendFormat("Volume name: {0}", StringHandlers.CToString(unicosSb.s_fname, Encoding)).AppendLine();

            information = sb.ToString();

            XmlFsType = new FileSystemType
            {
                Type                      = "UNICOS filesystem",
                ClusterSize               = 4096,
                Clusters                  = (ulong)unicosSb.s_fsize,
                VolumeName                = StringHandlers.CToString(unicosSb.s_fname, Encoding),
                ModificationDate          = DateHandlers.UnixToDateTime(unicosSb.s_time),
                ModificationDateSpecified = true
            };

            XmlFsType.Dirty |= unicosSb.s_error > 0;
        }
コード例 #25
0
        public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information,
                                   Encoding encoding)
        {
            Encoding    = encoding ?? Encoding.GetEncoding("iso-8859-15");
            information = "";

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

            var xfsSb = new Superblock();

            // Misaligned
            if (imagePlugin.Info.XmlMediaType == XmlMediaType.OpticalDisc)
            {
                uint sbSize = (uint)((Marshal.SizeOf <Superblock>() + 0x400) / imagePlugin.Info.SectorSize);

                if ((Marshal.SizeOf <Superblock>() + 0x400) % imagePlugin.Info.SectorSize != 0)
                {
                    sbSize++;
                }

                byte[] sector = imagePlugin.ReadSectors(partition.Start, sbSize);

                if (sector.Length < Marshal.SizeOf <Superblock>())
                {
                    return;
                }

                byte[] sbpiece = new byte[Marshal.SizeOf <Superblock>()];

                foreach (int location in new[]
                {
                    0, 0x200, 0x400
                })
                {
                    Array.Copy(sector, location, sbpiece, 0, Marshal.SizeOf <Superblock>());

                    xfsSb = Marshal.ByteArrayToStructureBigEndian <Superblock>(sbpiece);

                    AaruConsole.DebugWriteLine("XFS plugin", "magic at 0x{0:X3} = 0x{1:X8} (expected 0x{2:X8})",
                                               location, xfsSb.magicnum, XFS_MAGIC);

                    if (xfsSb.magicnum == XFS_MAGIC)
                    {
                        break;
                    }
                }
            }
            else
            {
                foreach (int i in new[]
                {
                    0, 1, 2
                })
                {
                    ulong location = (ulong)i;
                    uint  sbSize   = (uint)(Marshal.SizeOf <Superblock>() / imagePlugin.Info.SectorSize);

                    if (Marshal.SizeOf <Superblock>() % imagePlugin.Info.SectorSize != 0)
                    {
                        sbSize++;
                    }

                    byte[] sector = imagePlugin.ReadSectors(partition.Start + location, sbSize);

                    if (sector.Length < Marshal.SizeOf <Superblock>())
                    {
                        return;
                    }

                    xfsSb = Marshal.ByteArrayToStructureBigEndian <Superblock>(sector);

                    AaruConsole.DebugWriteLine("XFS plugin", "magic at {0} = 0x{1:X8} (expected 0x{2:X8})", location,
                                               xfsSb.magicnum, XFS_MAGIC);

                    if (xfsSb.magicnum == XFS_MAGIC)
                    {
                        break;
                    }
                }
            }

            if (xfsSb.magicnum != XFS_MAGIC)
            {
                return;
            }

            var sb = new StringBuilder();

            sb.AppendLine("XFS filesystem");
            sb.AppendFormat("Filesystem version {0}", xfsSb.version & 0xF).AppendLine();
            sb.AppendFormat("{0} bytes per sector", xfsSb.sectsize).AppendLine();
            sb.AppendFormat("{0} bytes per block", xfsSb.blocksize).AppendLine();
            sb.AppendFormat("{0} bytes per inode", xfsSb.inodesize).AppendLine();
            sb.AppendFormat("{0} data blocks in volume, {1} free", xfsSb.dblocks, xfsSb.fdblocks).AppendLine();
            sb.AppendFormat("{0} blocks per allocation group", xfsSb.agblocks).AppendLine();
            sb.AppendFormat("{0} allocation groups in volume", xfsSb.agcount).AppendLine();
            sb.AppendFormat("{0} inodes in volume, {1} free", xfsSb.icount, xfsSb.ifree).AppendLine();

            if (xfsSb.inprogress > 0)
            {
                sb.AppendLine("fsck in progress");
            }

            sb.AppendFormat("Volume name: {0}", StringHandlers.CToString(xfsSb.fname, Encoding)).AppendLine();
            sb.AppendFormat("Volume UUID: {0}", xfsSb.uuid).AppendLine();

            information = sb.ToString();

            XmlFsType = new FileSystemType
            {
                Type                  = "XFS filesystem",
                ClusterSize           = xfsSb.blocksize,
                Clusters              = xfsSb.dblocks,
                FreeClusters          = xfsSb.fdblocks,
                FreeClustersSpecified = true,
                Files                 = xfsSb.icount - xfsSb.ifree,
                FilesSpecified        = true,
                Dirty                 = xfsSb.inprogress > 0,
                VolumeName            = StringHandlers.CToString(xfsSb.fname, Encoding),
                VolumeSerial          = xfsSb.uuid.ToString()
            };
        }
コード例 #26
0
        public bool Create(string path, MediaType mediaType, Dictionary <string, string> options, ulong sectors,
                           uint sectorSize)
        {
            if (sectorSize != 512)
            {
                ErrorMessage = "Unsupported sector size";

                return(false);
            }

            if (!SupportedMediaTypes.Contains(mediaType))
            {
                ErrorMessage = $"Unsupported media format {mediaType}";

                return(false);
            }

            // TODO: Correct this calculation
            if ((sectors * sectorSize) / 65536 > uint.MaxValue)
            {
                ErrorMessage = "Too many sectors for selected cluster size";

                return(false);
            }

            _imageInfo = new ImageInfo
            {
                MediaType  = mediaType,
                SectorSize = sectorSize,
                Sectors    = sectors
            };

            try
            {
                _writingStream = new FileStream(path, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None);
            }
            catch (IOException e)
            {
                ErrorMessage = $"Could not create new image file, exception {e.Message}";

                return(false);
            }

            _qHdr = new QCowHeader
            {
                magic           = QCOW_MAGIC,
                version         = QCOW_VERSION,
                size            = sectors * sectorSize,
                cluster_bits    = 12,
                l2_bits         = 9,
                l1_table_offset = (ulong)Marshal.SizeOf <QCowHeader>()
            };

            int shift = _qHdr.cluster_bits + _qHdr.l2_bits;

            _clusterSize    = 1 << _qHdr.cluster_bits;
            _clusterSectors = 1 << (_qHdr.cluster_bits - 9);
            _l1Size         = (uint)(((_qHdr.size + (ulong)(1 << shift)) - 1) >> shift);
            _l2Size         = 1 << _qHdr.l2_bits;

            _l1Table = new ulong[_l1Size];

            _l1Mask = 0;
            int c = 0;

            _l1Shift = _qHdr.l2_bits + _qHdr.cluster_bits;

            for (int i = 0; i < 64; i++)
            {
                _l1Mask <<= 1;

                if (c >= 64 - _l1Shift)
                {
                    continue;
                }

                _l1Mask += 1;
                c++;
            }

            _l2Mask = 0;

            for (int i = 0; i < _qHdr.l2_bits; i++)
            {
                _l2Mask = (_l2Mask << 1) + 1;
            }

            _l2Mask <<= _qHdr.cluster_bits;

            _sectorMask = 0;

            for (int i = 0; i < _qHdr.cluster_bits; i++)
            {
                _sectorMask = (_sectorMask << 1) + 1;
            }

            byte[] empty = new byte[_qHdr.l1_table_offset + (_l1Size * 8)];
            _writingStream.Write(empty, 0, empty.Length);

            IsWriting    = true;
            ErrorMessage = null;

            return(true);
        }
コード例 #27
0
        public bool Create(string path, MediaType mediaType, Dictionary <string, string> options, ulong sectors,
                           uint sectorSize)
        {
            if (sectorSize != 512)
            {
                ErrorMessage = "Unsupported sector size";

                return(false);
            }

            if (!SupportedMediaTypes.Contains(mediaType))
            {
                ErrorMessage = $"Unsupported media format {mediaType}";

                return(false);
            }

            if (sectors * sectorSize / DEFAULT_BLOCK_SIZE > uint.MaxValue)
            {
                ErrorMessage = "Too many sectors for selected cluster size";

                return(false);
            }

            _imageInfo = new ImageInfo
            {
                MediaType  = mediaType,
                SectorSize = sectorSize,
                Sectors    = sectors
            };

            try
            {
                _writingStream = new FileStream(path, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None);
            }
            catch (IOException e)
            {
                ErrorMessage = $"Could not create new image file, exception {e.Message}";

                return(false);
            }

            uint ibmEntries = (uint)(sectors * sectorSize / DEFAULT_BLOCK_SIZE);

            if (sectors * sectorSize % DEFAULT_BLOCK_SIZE > 0)
            {
                ibmEntries++;
            }

            uint headerSectors = 1 + (ibmEntries * 4 / sectorSize);

            if (ibmEntries * 4 % sectorSize != 0)
            {
                headerSectors++;
            }

            _ibm = new uint[ibmEntries];
            _currentWritingPosition = headerSectors * sectorSize;

            _vHdr = new Header
            {
                creator      = DIC_AARU,
                magic        = VDI_MAGIC,
                majorVersion = 1,
                minorVersion = 1,
                headerSize   = Marshal.SizeOf <Header>() - 72,
                imageType    = VdiImageType.Normal,
                offsetBlocks = sectorSize,
                offsetData   = _currentWritingPosition,
                sectorSize   = sectorSize,
                size         = sectors * sectorSize,
                blockSize    = DEFAULT_BLOCK_SIZE,
                blocks       = ibmEntries,
                uuid         = Guid.NewGuid(),
                snapshotUuid = Guid.NewGuid()
            };

            for (uint i = 0; i < ibmEntries; i++)
            {
                _ibm[i] = VDI_EMPTY;
            }

            IsWriting    = true;
            ErrorMessage = null;

            return(true);
        }
コード例 #28
0
        public bool Identify(IMediaImage imagePlugin, Partition partition)
        {
            if (imagePlugin.Info.SectorSize < 512)
            {
                return(false);
            }

            // Misaligned
            if (imagePlugin.Info.XmlMediaType == XmlMediaType.OpticalDisc)
            {
                uint sbSize = (uint)((Marshal.SizeOf <Superblock>() + 0x400) / imagePlugin.Info.SectorSize);

                if ((Marshal.SizeOf <Superblock>() + 0x400) % imagePlugin.Info.SectorSize != 0)
                {
                    sbSize++;
                }

                byte[] sector = imagePlugin.ReadSectors(partition.Start, sbSize);

                if (sector.Length < Marshal.SizeOf <Superblock>())
                {
                    return(false);
                }

                byte[] sbpiece = new byte[Marshal.SizeOf <Superblock>()];

                foreach (int location in new[]
                {
                    0, 0x200, 0x400
                })
                {
                    Array.Copy(sector, location, sbpiece, 0, Marshal.SizeOf <Superblock>());

                    Superblock xfsSb = Marshal.ByteArrayToStructureBigEndian <Superblock>(sbpiece);

                    AaruConsole.DebugWriteLine("XFS plugin", "magic at 0x{0:X3} = 0x{1:X8} (expected 0x{2:X8})",
                                               location, xfsSb.magicnum, XFS_MAGIC);

                    if (xfsSb.magicnum == XFS_MAGIC)
                    {
                        return(true);
                    }
                }
            }
            else
            {
                foreach (int i in new[]
                {
                    0, 1, 2
                })
                {
                    ulong location = (ulong)i;

                    uint sbSize = (uint)(Marshal.SizeOf <Superblock>() / imagePlugin.Info.SectorSize);

                    if (Marshal.SizeOf <Superblock>() % imagePlugin.Info.SectorSize != 0)
                    {
                        sbSize++;
                    }

                    byte[] sector = imagePlugin.ReadSectors(partition.Start + location, sbSize);

                    if (sector.Length < Marshal.SizeOf <Superblock>())
                    {
                        return(false);
                    }

                    Superblock xfsSb = Marshal.ByteArrayToStructureBigEndian <Superblock>(sector);

                    AaruConsole.DebugWriteLine("XFS plugin", "magic at {0} = 0x{1:X8} (expected 0x{2:X8})", location,
                                               xfsSb.magicnum, XFS_MAGIC);

                    if (xfsSb.magicnum == XFS_MAGIC)
                    {
                        return(true);
                    }
                }
            }

            return(false);
        }
コード例 #29
0
ファイル: dump.cs プロジェクト: morefun0302/Aaru
        public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information,
                                   Encoding encoding)
        {
            Encoding    = encoding ?? Encoding.GetEncoding("iso-8859-15");
            information = "";

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

            if (partition.Start != 0)
            {
                return;
            }

            uint sbSize = (uint)(Marshal.SizeOf <s_spcl>() / imagePlugin.Info.SectorSize);

            if (Marshal.SizeOf <s_spcl>() % imagePlugin.Info.SectorSize != 0)
            {
                sbSize++;
            }

            byte[] sector = imagePlugin.ReadSectors(partition.Start, sbSize);

            if (sector.Length < Marshal.SizeOf <s_spcl>())
            {
                return;
            }

            spcl16   oldHdr = Marshal.ByteArrayToStructureLittleEndian <spcl16>(sector);
            spcl_aix aixHdr = Marshal.ByteArrayToStructureLittleEndian <spcl_aix>(sector);
            s_spcl   newHdr = Marshal.ByteArrayToStructureLittleEndian <s_spcl>(sector);

            bool useOld = false;
            bool useAix = false;

            if (newHdr.c_magic == OFS_MAGIC ||
                newHdr.c_magic == NFS_MAGIC ||
                newHdr.c_magic == OFS_CIGAM ||
                newHdr.c_magic == NFS_CIGAM ||
                newHdr.c_magic == UFS2_MAGIC ||
                newHdr.c_magic == UFS2_CIGAM)
            {
                if (newHdr.c_magic == OFS_CIGAM ||
                    newHdr.c_magic == NFS_CIGAM ||
                    newHdr.c_magic == UFS2_CIGAM)
                {
                    newHdr = Marshal.ByteArrayToStructureBigEndian <s_spcl>(sector);
                }
            }
            else if (aixHdr.c_magic == XIX_MAGIC ||
                     aixHdr.c_magic == XIX_CIGAM)
            {
                useAix = true;

                if (aixHdr.c_magic == XIX_CIGAM)
                {
                    aixHdr = Marshal.ByteArrayToStructureBigEndian <spcl_aix>(sector);
                }
            }
            else if (oldHdr.c_magic == OFS_MAGIC)
            {
                useOld = true;

                // Swap PDP-11 endian
                oldHdr.c_date  = (int)Swapping.PDPFromLittleEndian((uint)oldHdr.c_date);
                oldHdr.c_ddate = (int)Swapping.PDPFromLittleEndian((uint)oldHdr.c_ddate);
            }
            else
            {
                information = "Could not read dump(8) header block";

                return;
            }

            var sb = new StringBuilder();

            XmlFsType = new FileSystemType
            {
                ClusterSize = 1024,
                Clusters    = partition.Size / 1024
            };

            if (useOld)
            {
                XmlFsType.Type = "Old 16-bit dump(8)";
                sb.AppendLine(XmlFsType.Type);

                if (oldHdr.c_date > 0)
                {
                    XmlFsType.CreationDate          = DateHandlers.UnixToDateTime(oldHdr.c_date);
                    XmlFsType.CreationDateSpecified = true;
                    sb.AppendFormat("Dump created on {0}", XmlFsType.CreationDate).AppendLine();
                }

                if (oldHdr.c_ddate > 0)
                {
                    XmlFsType.BackupDate          = DateHandlers.UnixToDateTime(oldHdr.c_ddate);
                    XmlFsType.BackupDateSpecified = true;
                    sb.AppendFormat("Previous dump created on {0}", XmlFsType.BackupDate).AppendLine();
                }

                sb.AppendFormat("Dump volume number: {0}", oldHdr.c_volume).AppendLine();
            }
            else if (useAix)
            {
                XmlFsType.Type = "AIX dump(8)";
                sb.AppendLine(XmlFsType.Type);

                if (aixHdr.c_date > 0)
                {
                    XmlFsType.CreationDate          = DateHandlers.UnixToDateTime(aixHdr.c_date);
                    XmlFsType.CreationDateSpecified = true;
                    sb.AppendFormat("Dump created on {0}", XmlFsType.CreationDate).AppendLine();
                }

                if (aixHdr.c_ddate > 0)
                {
                    XmlFsType.BackupDate          = DateHandlers.UnixToDateTime(aixHdr.c_ddate);
                    XmlFsType.BackupDateSpecified = true;
                    sb.AppendFormat("Previous dump created on {0}", XmlFsType.BackupDate).AppendLine();
                }

                sb.AppendFormat("Dump volume number: {0}", aixHdr.c_volume).AppendLine();
            }
            else
            {
                XmlFsType.Type = "dump(8)";
                sb.AppendLine(XmlFsType.Type);

                if (newHdr.c_ndate > 0)
                {
                    XmlFsType.CreationDate          = DateHandlers.UnixToDateTime(newHdr.c_ndate);
                    XmlFsType.CreationDateSpecified = true;
                    sb.AppendFormat("Dump created on {0}", XmlFsType.CreationDate).AppendLine();
                }
                else if (newHdr.c_date > 0)
                {
                    XmlFsType.CreationDate          = DateHandlers.UnixToDateTime(newHdr.c_date);
                    XmlFsType.CreationDateSpecified = true;
                    sb.AppendFormat("Dump created on {0}", XmlFsType.CreationDate).AppendLine();
                }

                if (newHdr.c_nddate > 0)
                {
                    XmlFsType.BackupDate          = DateHandlers.UnixToDateTime(newHdr.c_nddate);
                    XmlFsType.BackupDateSpecified = true;
                    sb.AppendFormat("Previous dump created on {0}", XmlFsType.BackupDate).AppendLine();
                }
                else if (newHdr.c_ddate > 0)
                {
                    XmlFsType.BackupDate          = DateHandlers.UnixToDateTime(newHdr.c_ddate);
                    XmlFsType.BackupDateSpecified = true;
                    sb.AppendFormat("Previous dump created on {0}", XmlFsType.BackupDate).AppendLine();
                }

                sb.AppendFormat("Dump volume number: {0}", newHdr.c_volume).AppendLine();
                sb.AppendFormat("Dump level: {0}", newHdr.c_level).AppendLine();
                string dumpname = StringHandlers.CToString(newHdr.c_label);

                if (!string.IsNullOrEmpty(dumpname))
                {
                    XmlFsType.VolumeName = dumpname;
                    sb.AppendFormat("Dump label: {0}", dumpname).AppendLine();
                }

                string str = StringHandlers.CToString(newHdr.c_filesys);

                if (!string.IsNullOrEmpty(str))
                {
                    sb.AppendFormat("Dumped filesystem name: {0}", str).AppendLine();
                }

                str = StringHandlers.CToString(newHdr.c_dev);

                if (!string.IsNullOrEmpty(str))
                {
                    sb.AppendFormat("Dumped device: {0}", str).AppendLine();
                }

                str = StringHandlers.CToString(newHdr.c_host);

                if (!string.IsNullOrEmpty(str))
                {
                    sb.AppendFormat("Dump hostname: {0}", str).AppendLine();
                }
            }

            information = sb.ToString();
        }
コード例 #30
0
        public bool Create(string path, MediaType mediaType, Dictionary <string, string> options, ulong sectors,
                           uint sectorSize)
        {
            if (sectorSize != 512)
            {
                ErrorMessage = "Unsupported sector size";

                return(false);
            }

            if (!SupportedMediaTypes.Contains(mediaType))
            {
                ErrorMessage = $"Unsupported media format {mediaType}";

                return(false);
            }

            // TODO: Correct this calculation
            if ((sectors * sectorSize) / 65536 > uint.MaxValue)
            {
                ErrorMessage = "Too many sectors for selected cluster size";

                return(false);
            }

            _imageInfo = new ImageInfo
            {
                MediaType  = mediaType,
                SectorSize = sectorSize,
                Sectors    = sectors
            };

            try
            {
                _writingStream = new FileStream(path, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None);
            }
            catch (IOException e)
            {
                ErrorMessage = $"Could not create new image file, exception {e.Message}";

                return(false);
            }

            string extension = Path.GetExtension(path);
            bool   version3  = extension == ".qcow3" || extension == ".qc3";

            _qHdr = new QCow2Header
            {
                magic         = QCOW_MAGIC,
                version       = version3 ? QCOW_VERSION3 : QCOW_VERSION2,
                size          = sectors * sectorSize,
                cluster_bits  = 16,
                header_length = (uint)Marshal.SizeOf <QCow2Header>()
            };

            _clusterSize    = 1 << (int)_qHdr.cluster_bits;
            _clusterSectors = 1 << ((int)_qHdr.cluster_bits - 9);
            _l2Bits         = (int)(_qHdr.cluster_bits - 3);
            _l2Size         = 1 << _l2Bits;

            _l1Mask = 0;
            int c = 0;

            _l1Shift = (int)(_l2Bits + _qHdr.cluster_bits);

            for (int i = 0; i < 64; i++)
            {
                _l1Mask <<= 1;

                if (c >= 64 - _l1Shift)
                {
                    continue;
                }

                _l1Mask += 1;
                c++;
            }

            _l2Mask = 0;

            for (int i = 0; i < _l2Bits; i++)
            {
                _l2Mask = (_l2Mask << 1) + 1;
            }

            _l2Mask <<= (int)_qHdr.cluster_bits;

            _sectorMask = 0;

            for (int i = 0; i < _qHdr.cluster_bits; i++)
            {
                _sectorMask = (_sectorMask << 1) + 1;
            }

            _qHdr.l1_size = (uint)(_qHdr.size >> _l1Shift);

            if (_qHdr.l1_size == 0)
            {
                _qHdr.l1_size = 1;
            }

            _l1Table = new ulong[_qHdr.l1_size];

            ulong clusters       = _qHdr.size / (ulong)_clusterSize;
            ulong refCountBlocks = (clusters * 2) / (ulong)_clusterSize;

            if (refCountBlocks == 0)
            {
                refCountBlocks = 1;
            }

            _qHdr.refcount_table_offset   = (ulong)_clusterSize;
            _qHdr.refcount_table_clusters = (uint)((refCountBlocks * 8) / (ulong)_clusterSize);

            if (_qHdr.refcount_table_clusters == 0)
            {
                _qHdr.refcount_table_clusters = 1;
            }

            _refCountTable        = new ulong[refCountBlocks];
            _qHdr.l1_table_offset = _qHdr.refcount_table_offset + (ulong)(_qHdr.refcount_table_clusters * _clusterSize);
            ulong l1TableClusters = (_qHdr.l1_size * 8) / (ulong)_clusterSize;

            if (l1TableClusters == 0)
            {
                l1TableClusters = 1;
            }

            byte[] empty = new byte[_qHdr.l1_table_offset + (l1TableClusters * (ulong)_clusterSize)];
            _writingStream.Write(empty, 0, empty.Length);

            IsWriting    = true;
            ErrorMessage = null;

            return(true);
        }