Ejemplo n.º 1
0
        Errno Stat(short fileId, out FileEntryInfo stat)
        {
            stat = null;

            if (!_mounted)
            {
                return(Errno.AccessDenied);
            }

            Errno      error;
            ExtentFile file;

            if (fileId <= 4)
            {
                if (!_debug ||
                    fileId == 0)
                {
                    return(Errno.NoSuchFile);
                }
                else
                {
                    stat = new FileEntryInfo();

                    error = GetAttributes(fileId, out FileAttributes attrs);

                    stat.Attributes = attrs;

                    if (error != Errno.NoError)
                    {
                        return(error);
                    }

                    if (fileId < 0 &&
                        fileId != FILEID_BOOT_SIGNED &&
                        fileId != FILEID_LOADER_SIGNED)
                    {
                        error = ReadExtentsFile((short)(fileId * -1), out file);

                        if (error != Errno.NoError)
                        {
                            return(error);
                        }

                        stat.CreationTime  = DateHandlers.LisaToDateTime(file.dtc);
                        stat.AccessTime    = DateHandlers.LisaToDateTime(file.dta);
                        stat.BackupTime    = DateHandlers.LisaToDateTime(file.dtb);
                        stat.LastWriteTime = DateHandlers.LisaToDateTime(file.dtm);

                        stat.Inode     = (ulong)fileId;
                        stat.Links     = 0;
                        stat.Length    = _mddf.datasize;
                        stat.BlockSize = _mddf.datasize;
                        stat.Blocks    = 1;
                    }
                    else
                    {
                        error = ReadSystemFile(fileId, out byte[] buf);

                        if (error != Errno.NoError)
                        {
                            return(error);
                        }

                        stat.CreationTime = fileId != 4 ? _mddf.dtvc : _mddf.dtcc;

                        stat.BackupTime = _mddf.dtvb;

                        stat.Inode     = (ulong)fileId;
                        stat.Links     = 0;
                        stat.Length    = buf.Length;
                        stat.BlockSize = _mddf.datasize;
                        stat.Blocks    = buf.Length / _mddf.datasize;
                    }

                    return(Errno.NoError);
                }
            }

            stat = new FileEntryInfo();

            error           = GetAttributes(fileId, out FileAttributes fileAttributes);
            stat.Attributes = fileAttributes;

            if (error != Errno.NoError)
            {
                return(error);
            }

            error = ReadExtentsFile(fileId, out file);

            if (error != Errno.NoError)
            {
                return(error);
            }

            stat.CreationTime  = DateHandlers.LisaToDateTime(file.dtc);
            stat.AccessTime    = DateHandlers.LisaToDateTime(file.dta);
            stat.BackupTime    = DateHandlers.LisaToDateTime(file.dtb);
            stat.LastWriteTime = DateHandlers.LisaToDateTime(file.dtm);

            stat.Inode = (ulong)fileId;
            stat.Links = 1;

            if (!_fileSizeCache.TryGetValue(fileId, out int len))
            {
                stat.Length = _srecords[fileId].filesize;
            }
            else
            {
                stat.Length = len;
            }

            stat.BlockSize = _mddf.datasize;
            stat.Blocks    = file.length;

            return(Errno.NoError);
        }
Ejemplo n.º 2
0
Archivo: Super.cs Proyecto: paulyc/Aaru
        /// <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
            {
                Blocks         = XmlFsType.Clusters,
                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;

            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
                {
                    XmlFsType.Clusters = fat32Bpb.big_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;
                }

                break;
            }

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

                XmlFsType.Bootable = true;

                break;
            }

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

            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;
                    }
                }

                // This assumes no sane implementation will violate cluster size rules
                // However nothing prevents this to happen
                // If first file on disk uses only one cluster there is absolutely no way to differentiate between FAT12 and FAT16,
                // so let's hope implementations use common sense?
                if (!_fat12 &&
                    !_fat16)
                {
                    ulong clusters;

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

                    if (clusters < 4089)
                    {
                        _fat12 = true;
                    }
                    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
                        };
                    }
                }

                if (bpbKind != BpbKind.Human)
                {
                    if (fakeBpb.sectors == 0)
                    {
                        XmlFsType.Clusters = fakeBpb.spc == 0 ? fakeBpb.big_sectors : fakeBpb.big_sectors / fakeBpb.spc;
                    }
                    else
                    {
                        XmlFsType.Clusters =
                            (ulong)(fakeBpb.spc == 0 ? fakeBpb.sectors : fakeBpb.sectors / fakeBpb.spc);
                    }
                }
                else
                {
                    XmlFsType.Clusters = humanBpb.clusters == 0 ? humanBpb.big_clusters : humanBpb.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.Os2;
                }
            }

            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;
                }

                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;

            if (_fat12)
            {
                byte[] fatBytes =
                    imagePlugin.ReadSectors(_fatFirstSector + (_useFirstFat ? 0 : _sectorsPerFat), _sectorsPerFat);

                _fatEntries = new ushort[_statfs.Blocks];

                int pos = 0;

                for (int i = 0; i + 3 < fatBytes.Length && pos < _fatEntries.Length; i += 3)
                {
                    _fatEntries[pos++] = (ushort)(((fatBytes[i + 1] & 0xF) << 8) + fatBytes[i + 0]);
                    _fatEntries[pos++] = (ushort)(((fatBytes[i + 1] & 0xF0) >> 4) + (fatBytes[i + 2] << 4));
                }
            }
            else if (_fat16)
            {
                AaruConsole.DebugWriteLine("FAT plugin", "Reading FAT16");

                byte[] fatBytes =
                    imagePlugin.ReadSectors(_fatFirstSector + (_useFirstFat ? 0 : _sectorsPerFat), _sectorsPerFat);

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

            // 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))
Ejemplo n.º 3
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();
            uint sectors     = QNX6_SUPER_BLOCK_SIZE / imagePlugin.Info.SectorSize;
            uint bootSectors = QNX6_BOOT_BLOCKS_SIZE / imagePlugin.Info.SectorSize;

            byte[] audiSector = imagePlugin.ReadSectors(partition.Start, sectors);
            byte[] sector     = imagePlugin.ReadSectors(partition.Start + bootSectors, sectors);

            if (sector.Length < QNX6_SUPER_BLOCK_SIZE)
            {
                return;
            }

            QNX6_AudiSuperBlock audiSb = Marshal.ByteArrayToStructureLittleEndian <QNX6_AudiSuperBlock>(audiSector);

            QNX6_SuperBlock qnxSb = Marshal.ByteArrayToStructureLittleEndian <QNX6_SuperBlock>(sector);

            bool audi = audiSb.magic == QNX6_MAGIC;

            if (audi)
            {
                sb.AppendLine("QNX6 (Audi) filesystem");
                sb.AppendFormat("Checksum: 0x{0:X8}", audiSb.checksum).AppendLine();
                sb.AppendFormat("Serial: 0x{0:X16}", audiSb.checksum).AppendLine();
                sb.AppendFormat("{0} bytes per block", audiSb.blockSize).AppendLine();
                sb.AppendFormat("{0} inodes free of {1}", audiSb.freeInodes, audiSb.numInodes).AppendLine();

                sb.AppendFormat("{0} blocks ({1} bytes) free of {2} ({3} bytes)", audiSb.freeBlocks,
                                audiSb.freeBlocks * audiSb.blockSize, audiSb.numBlocks,
                                audiSb.numBlocks * audiSb.blockSize).AppendLine();

                XmlFsType = new FileSystemType
                {
                    Type           = "QNX6 (Audi) filesystem", Clusters = audiSb.numBlocks,
                    ClusterSize    = audiSb.blockSize,
                    Bootable       = true, Files = audiSb.numInodes - audiSb.freeInodes,
                    FilesSpecified = true,
                    FreeClusters   = audiSb.freeBlocks, FreeClustersSpecified = true,
                    VolumeSerial   = $"{audiSb.serial:X16}"
                };

                //xmlFSType.VolumeName = CurrentEncoding.GetString(audiSb.id);

                information = sb.ToString();

                return;
            }

            sb.AppendLine("QNX6 filesystem");
            sb.AppendFormat("Checksum: 0x{0:X8}", qnxSb.checksum).AppendLine();
            sb.AppendFormat("Serial: 0x{0:X16}", qnxSb.checksum).AppendLine();
            sb.AppendFormat("Created on {0}", DateHandlers.UnixUnsignedToDateTime(qnxSb.ctime)).AppendLine();
            sb.AppendFormat("Last mounted on {0}", DateHandlers.UnixUnsignedToDateTime(qnxSb.atime)).AppendLine();
            sb.AppendFormat("Flags: 0x{0:X8}", qnxSb.flags).AppendLine();
            sb.AppendFormat("Version1: 0x{0:X4}", qnxSb.version1).AppendLine();
            sb.AppendFormat("Version2: 0x{0:X4}", qnxSb.version2).AppendLine();

            //sb.AppendFormat("Volume ID: \"{0}\"", CurrentEncoding.GetString(qnxSb.volumeid)).AppendLine();
            sb.AppendFormat("{0} bytes per block", qnxSb.blockSize).AppendLine();
            sb.AppendFormat("{0} inodes free of {1}", qnxSb.freeInodes, qnxSb.numInodes).AppendLine();

            sb.AppendFormat("{0} blocks ({1} bytes) free of {2} ({3} bytes)", qnxSb.freeBlocks,
                            qnxSb.freeBlocks * qnxSb.blockSize, qnxSb.numBlocks, qnxSb.numBlocks * qnxSb.blockSize).
            AppendLine();

            XmlFsType = new FileSystemType
            {
                Type                      = "QNX6 filesystem",
                Clusters                  = qnxSb.numBlocks,
                ClusterSize               = qnxSb.blockSize, Bootable = true,
                Files                     = qnxSb.numInodes - qnxSb.freeInodes,
                FilesSpecified            = true, FreeClusters = qnxSb.freeBlocks,
                FreeClustersSpecified     = true,
                VolumeSerial              = $"{qnxSb.serial:X16}",
                CreationDate              = DateHandlers.UnixUnsignedToDateTime(qnxSb.ctime),
                CreationDateSpecified     = true,
                ModificationDate          = DateHandlers.UnixUnsignedToDateTime(qnxSb.atime),
                ModificationDateSpecified = true
            };

            //xmlFSType.VolumeName = CurrentEncoding.GetString(qnxSb.volumeid);

            information = sb.ToString();
        }
Ejemplo n.º 4
0
        public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information,
                                   Encoding encoding)
        {
            Encoding    = encoding ?? Encoding.GetEncoding("macintosh");
            information = "";

            StringBuilder sb = new StringBuilder();

            byte[] bbSector  = null;
            byte[] mdbSector = null;
            ushort drSigWord;

            bool apmFromHddOnCd = false;

            if (imagePlugin.Info.SectorSize == 2352 || imagePlugin.Info.SectorSize == 2448 ||
                imagePlugin.Info.SectorSize == 2048)
            {
                byte[] tmpSector = imagePlugin.ReadSectors(partition.Start, 2);

                foreach (int offset in new[] { 0, 0x200, 0x400, 0x600, 0x800, 0xA00 })
                {
                    drSigWord = BigEndianBitConverter.ToUInt16(tmpSector, offset);
                    if (drSigWord != HFS_MAGIC)
                    {
                        continue;
                    }

                    bbSector  = new byte[1024];
                    mdbSector = new byte[512];
                    if (offset >= 0x400)
                    {
                        Array.Copy(tmpSector, offset - 0x400, bbSector, 0, 1024);
                    }
                    Array.Copy(tmpSector, offset, mdbSector, 0, 512);
                    apmFromHddOnCd = true;
                    break;
                }

                if (!apmFromHddOnCd)
                {
                    return;
                }
            }
            else
            {
                mdbSector = imagePlugin.ReadSector(2 + partition.Start);
                drSigWord = BigEndianBitConverter.ToUInt16(mdbSector, 0);

                if (drSigWord == HFS_MAGIC)
                {
                    bbSector = imagePlugin.ReadSector(partition.Start);
                }
                else
                {
                    return;
                }
            }

            HfsMasterDirectoryBlock mdb =
                BigEndianMarshal.ByteArrayToStructureBigEndian <HfsMasterDirectoryBlock>(mdbSector);
            HfsBootBlock bb = BigEndianMarshal.ByteArrayToStructureBigEndian <HfsBootBlock>(bbSector);

            sb.AppendLine("Apple Hierarchical File System");
            sb.AppendLine();
            if (apmFromHddOnCd)
            {
                sb.AppendLine("HFS uses 512 bytes/sector while device uses 2048 bytes/sector.").AppendLine();
            }
            sb.AppendLine("Master Directory Block:");
            sb.AppendFormat("Creation date: {0}", DateHandlers.MacToDateTime(mdb.drCrDate)).AppendLine();
            sb.AppendFormat("Last modification date: {0}", DateHandlers.MacToDateTime(mdb.drLsMod)).AppendLine();
            if (mdb.drVolBkUp > 0)
            {
                sb.AppendFormat("Last backup date: {0}", DateHandlers.MacToDateTime(mdb.drVolBkUp)).AppendLine();
                sb.AppendFormat("Backup sequence number: {0}", mdb.drVSeqNum).AppendLine();
            }
            else
            {
                sb.AppendLine("Volume has never been backed up");
            }

            if ((mdb.drAtrb & 0x80) == 0x80)
            {
                sb.AppendLine("Volume is locked by hardware.");
            }
            sb.AppendLine((mdb.drAtrb & 0x100) == 0x100 ? "Volume was unmonted." : "Volume is mounted.");
            if ((mdb.drAtrb & 0x200) == 0x200)
            {
                sb.AppendLine("Volume has spared bad blocks.");
            }
            if ((mdb.drAtrb & 0x400) == 0x400)
            {
                sb.AppendLine("Volume does not need cache.");
            }
            if ((mdb.drAtrb & 0x800) == 0x800)
            {
                sb.AppendLine("Boot volume is inconsistent.");
            }
            if ((mdb.drAtrb & 0x1000) == 0x1000)
            {
                sb.AppendLine("There are reused CNIDs.");
            }
            if ((mdb.drAtrb & 0x2000) == 0x2000)
            {
                sb.AppendLine("Volume is journaled.");
            }
            if ((mdb.drAtrb & 0x4000) == 0x4000)
            {
                sb.AppendLine("Volume is seriously inconsistent.");
            }
            if ((mdb.drAtrb & 0x8000) == 0x8000)
            {
                sb.AppendLine("Volume is locked by software.");
            }

            sb.AppendFormat("{0} files on root directory", mdb.drNmFls).AppendLine();
            sb.AppendFormat("{0} directories on root directory", mdb.drNmRtDirs).AppendLine();
            sb.AppendFormat("{0} files on volume", mdb.drFilCnt).AppendLine();
            sb.AppendFormat("{0} directories on volume", mdb.drDirCnt).AppendLine();
            sb.AppendFormat("Volume write count: {0}", mdb.drWrCnt).AppendLine();

            sb.AppendFormat("Volume bitmap starting sector (in 512-bytes): {0}", mdb.drVBMSt).AppendLine();
            sb.AppendFormat("Next allocation block: {0}.", mdb.drAllocPtr).AppendLine();
            sb.AppendFormat("{0} volume allocation blocks.", mdb.drNmAlBlks).AppendLine();
            sb.AppendFormat("{0} bytes per allocation block.", mdb.drAlBlkSiz).AppendLine();
            sb.AppendFormat("{0} bytes to allocate when extending a file.", mdb.drClpSiz).AppendLine();
            sb.AppendFormat("{0} bytes to allocate when extending a Extents B-Tree.", mdb.drXTClpSiz).AppendLine();
            sb.AppendFormat("{0} bytes to allocate when extending a Catalog B-Tree.", mdb.drCTClpSiz).AppendLine();
            sb.AppendFormat("Sector of first allocation block: {0}", mdb.drAlBlSt).AppendLine();
            sb.AppendFormat("Next unused CNID: {0}", mdb.drNxtCNID).AppendLine();
            sb.AppendFormat("{0} unused allocation blocks.", mdb.drFreeBks).AppendLine();

            sb.AppendFormat("{0} bytes in the Extents B-Tree", mdb.drXTFlSize).AppendLine();
            sb.AppendFormat("{0} bytes in the Catalog B-Tree", mdb.drCTFlSize).AppendLine();

            sb.AppendFormat("Volume name: {0}", StringHandlers.PascalToString(mdb.drVN, Encoding)).AppendLine();

            sb.AppendLine("Finder info:");
            sb.AppendFormat("CNID of bootable system's directory: {0}", mdb.drFndrInfo0).AppendLine();
            sb.AppendFormat("CNID of first-run application's directory: {0}", mdb.drFndrInfo1).AppendLine();
            sb.AppendFormat("CNID of previously opened directory: {0}", mdb.drFndrInfo2).AppendLine();
            sb.AppendFormat("CNID of bootable Mac OS 8 or 9 directory: {0}", mdb.drFndrInfo3).AppendLine();
            sb.AppendFormat("CNID of bootable Mac OS X directory: {0}", mdb.drFndrInfo5).AppendLine();
            if (mdb.drFndrInfo6 != 0 && mdb.drFndrInfo7 != 0)
            {
                sb.AppendFormat("Mac OS X Volume ID: {0:X8}{1:X8}", mdb.drFndrInfo6, mdb.drFndrInfo7).AppendLine();
            }

            if (mdb.drEmbedSigWord == HFSP_MAGIC)
            {
                sb.AppendLine("Volume wraps a HFS+ volume.");
                sb.AppendFormat("Starting block of the HFS+ volume: {0}", mdb.xdrStABNt).AppendLine();
                sb.AppendFormat("Allocations blocks of the HFS+ volume: {0}", mdb.xdrNumABlks).AppendLine();
            }
            else
            {
                sb.AppendFormat("{0} blocks in volume cache", mdb.drVCSize).AppendLine();
                sb.AppendFormat("{0} blocks in volume bitmap cache", mdb.drVBMCSize).AppendLine();
                sb.AppendFormat("{0} blocks in volume common cache", mdb.drCtlCSize).AppendLine();
            }

            if (bb.signature == HFSBB_MAGIC)
            {
                sb.AppendLine("Volume is bootable.");
                sb.AppendLine();
                sb.AppendLine("Boot Block:");
                if ((bb.boot_flags & 0x40) == 0x40)
                {
                    sb.AppendLine("Boot block should be executed.");
                }
                if ((bb.boot_flags & 0x80) == 0x80)
                {
                    sb.AppendLine("Boot block is in new unknown format.");
                }
                else
                {
                    if (bb.boot_flags > 0)
                    {
                        sb.AppendLine("Allocate secondary sound buffer at boot.");
                    }
                    else if (bb.boot_flags < 0)
                    {
                        sb.AppendLine("Allocate secondary sound and video buffers at boot.");
                    }

                    sb.AppendFormat("System filename: {0}", StringHandlers.PascalToString(bb.system_name, Encoding))
                    .AppendLine();
                    sb.AppendFormat("Finder filename: {0}", StringHandlers.PascalToString(bb.finder_name, Encoding))
                    .AppendLine();
                    sb.AppendFormat("Debugger filename: {0}", StringHandlers.PascalToString(bb.debug_name, Encoding))
                    .AppendLine();
                    sb.AppendFormat("Disassembler filename: {0}",
                                    StringHandlers.PascalToString(bb.disasm_name, Encoding)).AppendLine();
                    sb.AppendFormat("Startup screen filename: {0}",
                                    StringHandlers.PascalToString(bb.stupscr_name, Encoding)).AppendLine();
                    sb.AppendFormat("First program to execute at boot: {0}",
                                    StringHandlers.PascalToString(bb.bootup_name, Encoding)).AppendLine();
                    sb.AppendFormat("Clipboard filename: {0}", StringHandlers.PascalToString(bb.clipbrd_name, Encoding))
                    .AppendLine();
                    sb.AppendFormat("Maximum opened files: {0}", bb.max_files * 4).AppendLine();
                    sb.AppendFormat("Event queue size: {0}", bb.queue_size).AppendLine();
                    sb.AppendFormat("Heap size with 128KiB of RAM: {0} bytes", bb.heap_128k).AppendLine();
                    sb.AppendFormat("Heap size with 256KiB of RAM: {0} bytes", bb.heap_256k).AppendLine();
                    sb.AppendFormat("Heap size with 512KiB of RAM or more: {0} bytes", bb.heap_512k).AppendLine();
                }
            }
            else if (mdb.drFndrInfo0 != 0 || mdb.drFndrInfo3 != 0 || mdb.drFndrInfo5 != 0)
            {
                sb.AppendLine("Volume is bootable.");
            }
            else
            {
                sb.AppendLine("Volume is not bootable.");
            }

            information = sb.ToString();

            XmlFsType = new FileSystemType();
            if (mdb.drVolBkUp > 0)
            {
                XmlFsType.BackupDate          = DateHandlers.MacToDateTime(mdb.drVolBkUp);
                XmlFsType.BackupDateSpecified = true;
            }

            XmlFsType.Bootable = bb.signature == HFSBB_MAGIC || mdb.drFndrInfo0 != 0 || mdb.drFndrInfo3 != 0 ||
                                 mdb.drFndrInfo5 != 0;
            XmlFsType.Clusters    = mdb.drNmAlBlks;
            XmlFsType.ClusterSize = (int)mdb.drAlBlkSiz;
            if (mdb.drCrDate > 0)
            {
                XmlFsType.CreationDate          = DateHandlers.MacToDateTime(mdb.drCrDate);
                XmlFsType.CreationDateSpecified = true;
            }

            XmlFsType.Dirty                 = (mdb.drAtrb & 0x100) != 0x100;
            XmlFsType.Files                 = mdb.drFilCnt;
            XmlFsType.FilesSpecified        = true;
            XmlFsType.FreeClusters          = mdb.drFreeBks;
            XmlFsType.FreeClustersSpecified = true;
            if (mdb.drLsMod > 0)
            {
                XmlFsType.ModificationDate          = DateHandlers.MacToDateTime(mdb.drLsMod);
                XmlFsType.ModificationDateSpecified = true;
            }

            XmlFsType.Type       = "HFS";
            XmlFsType.VolumeName = StringHandlers.PascalToString(mdb.drVN, Encoding);
            if (mdb.drFndrInfo6 != 0 && mdb.drFndrInfo7 != 0)
            {
                XmlFsType.VolumeSerial = $"{mdb.drFndrInfo6:X8}{mdb.drFndrInfo7:X8}";
            }
        }
Ejemplo n.º 5
0
        public void Open(string path)
        {
            string filename      = Path.GetFileName(path);
            string filenameNoExt = Path.GetFileNameWithoutExtension(path);
            string parentFolder  = Path.GetDirectoryName(path);

            parentFolder ??= "";

            if (filename is null ||
                filenameNoExt is null)
            {
                throw new ArgumentNullException(nameof(path));
            }

            // Prepend data fork name with "R."
            string proDosAppleDouble = Path.Combine(parentFolder, "R." + filename);

            // Prepend data fork name with '%'
            string unixAppleDouble = Path.Combine(parentFolder, "%" + filename);

            // Change file extension to ADF
            string dosAppleDouble = Path.Combine(parentFolder, filenameNoExt + ".ADF");

            // Change file extension to adf
            string dosAppleDoubleLower = Path.Combine(parentFolder, filenameNoExt + ".adf");

            // Store AppleDouble header file in ".AppleDouble" folder with same name
            string netatalkAppleDouble = Path.Combine(parentFolder, ".AppleDouble", filename);

            // Store AppleDouble header file in "resource.frk" folder with same name
            string daveAppleDouble = Path.Combine(parentFolder, "resource.frk", filename);

            // Prepend data fork name with "._"
            string osxAppleDouble = Path.Combine(parentFolder, "._" + filename);

            // Adds ".rsrc" extension
            string unArAppleDouble = Path.Combine(parentFolder, filename + ".rsrc");

            // Check AppleDouble created by A/UX in ProDOS filesystem
            if (File.Exists(proDosAppleDouble))
            {
                var prodosStream = new FileStream(proDosAppleDouble, FileMode.Open, FileAccess.Read);

                if (prodosStream.Length > 26)
                {
                    byte[] prodosB = new byte[26];
                    prodosStream.Read(prodosB, 0, 26);
                    _header = Marshal.ByteArrayToStructureBigEndian <Header>(prodosB);
                    prodosStream.Close();

                    if (_header.magic == MAGIC &&
                        (_header.version == VERSION || _header.version == VERSION2))
                    {
                        _headerPath = proDosAppleDouble;
                    }
                }
            }

            // Check AppleDouble created by A/UX in UFS filesystem
            if (File.Exists(unixAppleDouble))
            {
                var unixStream = new FileStream(unixAppleDouble, FileMode.Open, FileAccess.Read);

                if (unixStream.Length > 26)
                {
                    byte[] unixB = new byte[26];
                    unixStream.Read(unixB, 0, 26);
                    _header = Marshal.ByteArrayToStructureBigEndian <Header>(unixB);
                    unixStream.Close();

                    if (_header.magic == MAGIC &&
                        (_header.version == VERSION || _header.version == VERSION2))
                    {
                        _headerPath = unixAppleDouble;
                    }
                }
            }

            // Check AppleDouble created by A/UX in FAT filesystem
            if (File.Exists(dosAppleDouble))
            {
                var dosStream = new FileStream(dosAppleDouble, FileMode.Open, FileAccess.Read);

                if (dosStream.Length > 26)
                {
                    byte[] dosB = new byte[26];
                    dosStream.Read(dosB, 0, 26);
                    _header = Marshal.ByteArrayToStructureBigEndian <Header>(dosB);
                    dosStream.Close();

                    if (_header.magic == MAGIC &&
                        (_header.version == VERSION || _header.version == VERSION2))
                    {
                        _headerPath = dosAppleDouble;
                    }
                }
            }

            // Check AppleDouble created by A/UX in case preserving FAT filesystem
            if (File.Exists(dosAppleDoubleLower))
            {
                var doslStream = new FileStream(dosAppleDoubleLower, FileMode.Open, FileAccess.Read);

                if (doslStream.Length > 26)
                {
                    byte[] doslB = new byte[26];
                    doslStream.Read(doslB, 0, 26);
                    _header = Marshal.ByteArrayToStructureBigEndian <Header>(doslB);
                    doslStream.Close();

                    if (_header.magic == MAGIC &&
                        (_header.version == VERSION || _header.version == VERSION2))
                    {
                        _headerPath = dosAppleDoubleLower;
                    }
                }
            }

            // Check AppleDouble created by Netatalk
            if (File.Exists(netatalkAppleDouble))
            {
                var netatalkStream = new FileStream(netatalkAppleDouble, FileMode.Open, FileAccess.Read);

                if (netatalkStream.Length > 26)
                {
                    byte[] netatalkB = new byte[26];
                    netatalkStream.Read(netatalkB, 0, 26);
                    _header = Marshal.ByteArrayToStructureBigEndian <Header>(netatalkB);
                    netatalkStream.Close();

                    if (_header.magic == MAGIC &&
                        (_header.version == VERSION || _header.version == VERSION2))
                    {
                        _headerPath = netatalkAppleDouble;
                    }
                }
            }

            // Check AppleDouble created by DAVE
            if (File.Exists(daveAppleDouble))
            {
                var daveStream = new FileStream(daveAppleDouble, FileMode.Open, FileAccess.Read);

                if (daveStream.Length > 26)
                {
                    byte[] daveB = new byte[26];
                    daveStream.Read(daveB, 0, 26);
                    _header = Marshal.ByteArrayToStructureBigEndian <Header>(daveB);
                    daveStream.Close();

                    if (_header.magic == MAGIC &&
                        (_header.version == VERSION || _header.version == VERSION2))
                    {
                        _headerPath = daveAppleDouble;
                    }
                }
            }

            // Check AppleDouble created by Mac OS X
            if (File.Exists(osxAppleDouble))
            {
                var osxStream = new FileStream(osxAppleDouble, FileMode.Open, FileAccess.Read);

                if (osxStream.Length > 26)
                {
                    byte[] osxB = new byte[26];
                    osxStream.Read(osxB, 0, 26);
                    _header = Marshal.ByteArrayToStructureBigEndian <Header>(osxB);
                    osxStream.Close();

                    if (_header.magic == MAGIC &&
                        (_header.version == VERSION || _header.version == VERSION2))
                    {
                        _headerPath = osxAppleDouble;
                    }
                }
            }

            // Check AppleDouble created by UnAr (from The Unarchiver)
            if (File.Exists(unArAppleDouble))
            {
                var unarStream = new FileStream(unArAppleDouble, FileMode.Open, FileAccess.Read);

                if (unarStream.Length > 26)
                {
                    byte[] unarB = new byte[26];
                    unarStream.Read(unarB, 0, 26);
                    _header = Marshal.ByteArrayToStructureBigEndian <Header>(unarB);
                    unarStream.Close();

                    if (_header.magic == MAGIC &&
                        (_header.version == VERSION || _header.version == VERSION2))
                    {
                        _headerPath = unArAppleDouble;
                    }
                }
            }

            var fs = new FileStream(_headerPath, FileMode.Open, FileAccess.Read);

            fs.Seek(0, SeekOrigin.Begin);

            byte[] hdrB = new byte[26];
            fs.Read(hdrB, 0, 26);
            _header = Marshal.ByteArrayToStructureBigEndian <Header>(hdrB);

            Entry[] entries = new Entry[_header.entries];

            for (int i = 0; i < _header.entries; i++)
            {
                byte[] entry = new byte[12];
                fs.Read(entry, 0, 12);
                entries[i] = Marshal.ByteArrayToStructureBigEndian <Entry>(entry);
            }

            _creationTime  = DateTime.UtcNow;
            _lastWriteTime = _creationTime;

            foreach (Entry entry in entries)
            {
                switch ((EntryId)entry.id)
                {
                case EntryId.DataFork:
                    // AppleDouble have datafork in separated file
                    break;

                case EntryId.FileDates:
                    fs.Seek(entry.offset, SeekOrigin.Begin);
                    byte[] datesB = new byte[16];
                    fs.Read(datesB, 0, 16);

                    FileDates dates = Marshal.ByteArrayToStructureBigEndian <FileDates>(datesB);

                    _creationTime  = DateHandlers.UnixUnsignedToDateTime(dates.creationDate);
                    _lastWriteTime = DateHandlers.UnixUnsignedToDateTime(dates.modificationDate);

                    break;

                case EntryId.FileInfo:
                    fs.Seek(entry.offset, SeekOrigin.Begin);
                    byte[] finfo = new byte[entry.length];
                    fs.Read(finfo, 0, finfo.Length);

                    if (_macintoshHome.SequenceEqual(_header.homeFilesystem))
                    {
                        MacFileInfo macinfo = Marshal.ByteArrayToStructureBigEndian <MacFileInfo>(finfo);

                        _creationTime  = DateHandlers.MacToDateTime(macinfo.creationDate);
                        _lastWriteTime = DateHandlers.MacToDateTime(macinfo.modificationDate);
                    }
                    else if (_proDosHome.SequenceEqual(_header.homeFilesystem))
                    {
                        ProDOSFileInfo prodosinfo = Marshal.ByteArrayToStructureBigEndian <ProDOSFileInfo>(finfo);

                        _creationTime  = DateHandlers.MacToDateTime(prodosinfo.creationDate);
                        _lastWriteTime = DateHandlers.MacToDateTime(prodosinfo.modificationDate);
                    }
                    else if (_unixHome.SequenceEqual(_header.homeFilesystem))
                    {
                        UnixFileInfo unixinfo = Marshal.ByteArrayToStructureBigEndian <UnixFileInfo>(finfo);

                        _creationTime  = DateHandlers.UnixUnsignedToDateTime(unixinfo.creationDate);
                        _lastWriteTime = DateHandlers.UnixUnsignedToDateTime(unixinfo.modificationDate);
                    }
                    else if (_dosHome.SequenceEqual(_header.homeFilesystem))
                    {
                        DOSFileInfo dosinfo = Marshal.ByteArrayToStructureBigEndian <DOSFileInfo>(finfo);

                        _lastWriteTime =
                            DateHandlers.DosToDateTime(dosinfo.modificationDate, dosinfo.modificationTime);
                    }

                    break;

                case EntryId.ResourceFork:
                    _rsrcFork = entry;

                    break;
                }
            }

            _dataFork = new Entry
            {
                id = (uint)EntryId.DataFork
            };

            if (File.Exists(path))
            {
                var dataFs = new FileStream(path, FileMode.Open, FileAccess.Read);
                _dataFork.length = (uint)dataFs.Length;
                dataFs.Close();
            }

            fs.Close();
            _opened   = true;
            _basePath = path;
        }
Ejemplo n.º 6
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 < 256)
            {
                return;
            }

            RBF_IdSector    rbfSb     = new RBF_IdSector();
            RBF_NewIdSector rbf9000Sb = new RBF_NewIdSector();

            foreach (int i in new[] { 0, 4, 15 })
            {
                ulong location = (ulong)i;
                uint  sbSize   = (uint)(Marshal.SizeOf <RBF_IdSector>() / imagePlugin.Info.SectorSize);
                if (Marshal.SizeOf <RBF_IdSector>() % imagePlugin.Info.SectorSize != 0)
                {
                    sbSize++;
                }

                byte[] sector = imagePlugin.ReadSectors(partition.Start + location, sbSize);
                if (sector.Length < Marshal.SizeOf <RBF_IdSector>())
                {
                    return;
                }

                rbfSb     = Marshal.ByteArrayToStructureBigEndian <RBF_IdSector>(sector);
                rbf9000Sb = Marshal.ByteArrayToStructureBigEndian <RBF_NewIdSector>(sector);

                DicConsole.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)
                {
                    break;
                }
            }

            if (rbfSb.dd_sync != RBF_SYNC && rbf9000Sb.rid_sync != RBF_SYNC && rbf9000Sb.rid_sync != RBF_CNYS)
            {
                return;
            }

            if (rbf9000Sb.rid_sync == RBF_CNYS)
            {
                rbf9000Sb = (RBF_NewIdSector)Marshal.SwapStructureMembersEndian(rbf9000Sb);
            }

            StringBuilder sb = new StringBuilder();

            sb.AppendLine("OS-9 Random Block File");

            if (rbf9000Sb.rid_sync == RBF_SYNC)
            {
                sb.AppendFormat("Volume ID: {0:X8}", rbf9000Sb.rid_diskid).AppendLine();
                sb.AppendFormat("{0} blocks in volume", rbf9000Sb.rid_totblocks).AppendLine();
                sb.AppendFormat("{0} cylinders", rbf9000Sb.rid_cylinders).AppendLine();
                sb.AppendFormat("{0} blocks in cylinder 0", rbf9000Sb.rid_cyl0size).AppendLine();
                sb.AppendFormat("{0} blocks per cylinder", rbf9000Sb.rid_cylsize).AppendLine();
                sb.AppendFormat("{0} heads", rbf9000Sb.rid_heads).AppendLine();
                sb.AppendFormat("{0} bytes per block", rbf9000Sb.rid_blocksize).AppendLine();
                // TODO: Convert to flags?
                sb.AppendLine((rbf9000Sb.rid_format & 0x01) == 0x01 ? "Disk is double sided" : "Disk is single sided");
                sb.AppendLine((rbf9000Sb.rid_format & 0x02) == 0x02
                                  ? "Disk is double density"
                                  : "Disk is single density");
                if ((rbf9000Sb.rid_format & 0x10) == 0x10)
                {
                    sb.AppendLine("Disk is 384 TPI");
                }
                else if ((rbf9000Sb.rid_format & 0x08) == 0x08)
                {
                    sb.AppendLine("Disk is 192 TPI");
                }
                else if ((rbf9000Sb.rid_format & 0x04) == 0x04)
                {
                    sb.AppendLine("Disk is 96 TPI or 135 TPI");
                }
                else
                {
                    sb.AppendLine("Disk is 48 TPI");
                }
                sb.AppendFormat("Allocation bitmap descriptor starts at block {0}",
                                rbf9000Sb.rid_bitmap == 0 ? 1 : rbf9000Sb.rid_bitmap).AppendLine();
                if (rbf9000Sb.rid_firstboot > 0)
                {
                    sb.AppendFormat("Debugger descriptor starts at block {0}", rbf9000Sb.rid_firstboot).AppendLine();
                }
                if (rbf9000Sb.rid_bootfile > 0)
                {
                    sb.AppendFormat("Boot file descriptor starts at block {0}", rbf9000Sb.rid_bootfile).AppendLine();
                }
                sb.AppendFormat("Root directory descriptor starts at block {0}", rbf9000Sb.rid_rootdir).AppendLine();
                sb.AppendFormat("Disk is owned by group {0} user {1}", rbf9000Sb.rid_group, rbf9000Sb.rid_owner)
                .AppendLine();
                sb.AppendFormat("Volume was created on {0}", DateHandlers.UnixToDateTime(rbf9000Sb.rid_ctime))
                .AppendLine();
                sb.AppendFormat("Volume's identification block was last written on {0}",
                                DateHandlers.UnixToDateTime(rbf9000Sb.rid_mtime)).AppendLine();
                sb.AppendFormat("Volume name: {0}", StringHandlers.CToString(rbf9000Sb.rid_name, Encoding))
                .AppendLine();

                XmlFsType = new FileSystemType
                {
                    Type                      = "OS-9 Random Block File",
                    Bootable                  = rbf9000Sb.rid_bootfile > 0,
                    ClusterSize               = rbf9000Sb.rid_blocksize,
                    Clusters                  = rbf9000Sb.rid_totblocks,
                    CreationDate              = DateHandlers.UnixToDateTime(rbf9000Sb.rid_ctime),
                    CreationDateSpecified     = true,
                    ModificationDate          = DateHandlers.UnixToDateTime(rbf9000Sb.rid_mtime),
                    ModificationDateSpecified = true,
                    VolumeName                = StringHandlers.CToString(rbf9000Sb.rid_name, Encoding),
                    VolumeSerial              = $"{rbf9000Sb.rid_diskid:X8}"
                };
            }
            else
            {
                sb.AppendFormat("Volume ID: {0:X4}", rbfSb.dd_dsk).AppendLine();
                sb.AppendFormat("{0} blocks in volume", LSNToUInt32(rbfSb.dd_tot)).AppendLine();
                sb.AppendFormat("{0} tracks", rbfSb.dd_tks).AppendLine();
                sb.AppendFormat("{0} sectors per track", rbfSb.dd_spt).AppendLine();
                sb.AppendFormat("{0} bytes per sector", 256 << rbfSb.dd_lsnsize).AppendLine();
                sb.AppendFormat("{0} sectors per cluster ({1} bytes)", rbfSb.dd_bit,
                                rbfSb.dd_bit * (256 << rbfSb.dd_lsnsize)).AppendLine();
                // TODO: Convert to flags?
                sb.AppendLine((rbfSb.dd_fmt & 0x01) == 0x01 ? "Disk is double sided" : "Disk is single sided");
                sb.AppendLine((rbfSb.dd_fmt & 0x02) == 0x02 ? "Disk is double density" : "Disk is single density");
                if ((rbfSb.dd_fmt & 0x10) == 0x10)
                {
                    sb.AppendLine("Disk is 384 TPI");
                }
                else if ((rbfSb.dd_fmt & 0x08) == 0x08)
                {
                    sb.AppendLine("Disk is 192 TPI");
                }
                else if ((rbfSb.dd_fmt & 0x04) == 0x04)
                {
                    sb.AppendLine("Disk is 96 TPI or 135 TPI");
                }
                else
                {
                    sb.AppendLine("Disk is 48 TPI");
                }
                sb.AppendFormat("Allocation bitmap descriptor starts at block {0}",
                                rbfSb.dd_maplsn == 0 ? 1 : rbfSb.dd_maplsn).AppendLine();
                sb.AppendFormat("{0} bytes in allocation bitmap", rbfSb.dd_map).AppendLine();
                if (LSNToUInt32(rbfSb.dd_bt) > 0 && rbfSb.dd_bsz > 0)
                {
                    sb.AppendFormat("Boot file starts at block {0} and has {1} bytes", LSNToUInt32(rbfSb.dd_bt),
                                    rbfSb.dd_bsz).AppendLine();
                }
                sb.AppendFormat("Root directory descriptor starts at block {0}", LSNToUInt32(rbfSb.dd_dir))
                .AppendLine();
                sb.AppendFormat("Disk is owned by user {0}", rbfSb.dd_own).AppendLine();
                sb.AppendFormat("Volume was created on {0}", DateHandlers.Os9ToDateTime(rbfSb.dd_dat)).AppendLine();
                sb.AppendFormat("Volume attributes: {0:X2}", rbfSb.dd_att).AppendLine();
                sb.AppendFormat("Volume name: {0}", StringHandlers.CToString(rbfSb.dd_nam, Encoding)).AppendLine();
                sb.AppendFormat("Path descriptor options: {0}", StringHandlers.CToString(rbfSb.dd_opt, Encoding))
                .AppendLine();

                XmlFsType = new FileSystemType
                {
                    Type                  = "OS-9 Random Block File",
                    Bootable              = LSNToUInt32(rbfSb.dd_bt) > 0 && rbfSb.dd_bsz > 0,
                    ClusterSize           = (uint)(rbfSb.dd_bit * (256 << rbfSb.dd_lsnsize)),
                    Clusters              = LSNToUInt32(rbfSb.dd_tot),
                    CreationDate          = DateHandlers.Os9ToDateTime(rbfSb.dd_dat),
                    CreationDateSpecified = true,
                    VolumeName            = StringHandlers.CToString(rbfSb.dd_nam, Encoding),
                    VolumeSerial          = $"{rbfSb.dd_dsk:X4}"
                };
            }

            information = sb.ToString();
        }
Ejemplo n.º 7
0
        public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information,
                                   Encoding encoding)
        {
            Encoding = encoding ?? Encoding.UTF8;
            byte[] sector = imagePlugin.ReadSector(partition.Start);
            uint   magic  = BitConverter.ToUInt32(sector, 0x00);

            var  sqSb         = new SuperBlock();
            bool littleEndian = true;

            switch (magic)
            {
            case SQUASH_MAGIC:
                sqSb = Marshal.ByteArrayToStructureLittleEndian <SuperBlock>(sector);

                break;

            case SQUASH_CIGAM:
                sqSb         = Marshal.ByteArrayToStructureBigEndian <SuperBlock>(sector);
                littleEndian = false;

                break;
            }

            var sbInformation = new StringBuilder();

            sbInformation.AppendLine("Squash file system");
            sbInformation.AppendLine(littleEndian ? "Little-endian" : "Big-endian");
            sbInformation.AppendFormat("Volume version {0}.{1}", sqSb.s_major, sqSb.s_minor).AppendLine();
            sbInformation.AppendFormat("Volume has {0} bytes", sqSb.bytes_used).AppendLine();
            sbInformation.AppendFormat("Volume has {0} bytes per block", sqSb.block_size).AppendLine();

            sbInformation.AppendFormat("Volume created on {0}", DateHandlers.UnixUnsignedToDateTime(sqSb.mkfs_time)).
            AppendLine();

            sbInformation.AppendFormat("Volume has {0} inodes", sqSb.inodes).AppendLine();

            switch (sqSb.compression)
            {
            case (ushort)SquashCompression.Lz4:
                sbInformation.AppendLine("Volume is compressed using LZ4");

                break;

            case (ushort)SquashCompression.Lzo:
                sbInformation.AppendLine("Volume is compressed using LZO");

                break;

            case (ushort)SquashCompression.Lzma:
                sbInformation.AppendLine("Volume is compressed using LZMA");

                break;

            case (ushort)SquashCompression.Xz:
                sbInformation.AppendLine("Volume is compressed using XZ");

                break;

            case (ushort)SquashCompression.Zlib:
                sbInformation.AppendLine("Volume is compressed using GZIP");

                break;

            case (ushort)SquashCompression.Zstd:
                sbInformation.AppendLine("Volume is compressed using Zstandard");

                break;

            default:
                sbInformation.AppendFormat("Volume is compressed using unknown algorithm {0}", sqSb.compression).
                AppendLine();

                break;
            }

            information = sbInformation.ToString();

            XmlFsType = new FileSystemType
            {
                Type                  = "Squash file system",
                CreationDate          = DateHandlers.UnixUnsignedToDateTime(sqSb.mkfs_time),
                CreationDateSpecified = true,
                Clusters              = (((partition.End - partition.Start) + 1) * imagePlugin.Info.SectorSize) / sqSb.block_size,
                ClusterSize           = sqSb.block_size,
                Files                 = sqSb.inodes,
                FilesSpecified        = true,
                FreeClusters          = 0,
                FreeClustersSpecified = true
            };
        }
Ejemplo n.º 8
0
        public bool Open(IFilter imageFilter)
        {
            Stream stream = imageFilter.GetDataForkStream();

            stream.Seek(0, SeekOrigin.Begin);

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

            byte[] qHdrB = new byte[48];
            stream.Read(qHdrB, 0, 48);
            _qHdr = Marshal.SpanToStructureBigEndian <Header>(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.mtime = {0}", _qHdr.mtime);
            AaruConsole.DebugWriteLine("QCOW plugin", "qHdr.size = {0}", _qHdr.size);
            AaruConsole.DebugWriteLine("QCOW plugin", "qHdr.cluster_bits = {0}", _qHdr.cluster_bits);
            AaruConsole.DebugWriteLine("QCOW plugin", "qHdr.l2_bits = {0}", _qHdr.l2_bits);
            AaruConsole.DebugWriteLine("QCOW plugin", "qHdr.padding = {0}", _qHdr.padding);
            AaruConsole.DebugWriteLine("QCOW plugin", "qHdr.crypt_method = {0}", _qHdr.crypt_method);
            AaruConsole.DebugWriteLine("QCOW plugin", "qHdr.l1_table_offset = {0}", _qHdr.l1_table_offset);

            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.l2_bits < 9 - 3 ||
                _qHdr.l2_bits > 16 - 3)
            {
                throw new ArgumentOutOfRangeException(nameof(_qHdr.l2_bits),
                                                      "L2 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");
            }

            int shift = _qHdr.cluster_bits + _qHdr.l2_bits;

            if (_qHdr.size > ulong.MaxValue - (ulong)(1 << shift))
            {
                throw new ArgumentOutOfRangeException(nameof(_qHdr.size), "Image is too large");
            }

            _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;

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

            byte[] l1TableB = new byte[_l1Size * 8];
            stream.Seek((long)_qHdr.l1_table_offset, SeekOrigin.Begin);
            stream.Read(l1TableB, 0, (int)_l1Size * 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 = _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;
            }

            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 = _qHdr.mtime > 0 ? DateHandlers.UnixUnsignedToDateTime(_qHdr.mtime)
                                                  : 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.Cylinders       = (uint)(_imageInfo.Sectors / 16 / 63);
            _imageInfo.Heads           = 16;
            _imageInfo.SectorsPerTrack = 63;

            return(true);
        }
Ejemplo n.º 9
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 <Reiser_Superblock>() / imagePlugin.Info.SectorSize);

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

            byte[] sector = imagePlugin.ReadSectors(partition.Start + sbAddr, sbSize);
            if (sector.Length < Marshal.SizeOf <Reiser_Superblock>())
            {
                return;
            }

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

            if (!reiser35_magic.SequenceEqual(reiserSb.magic) && !reiser36_magic.SequenceEqual(reiserSb.magic) &&
                !reiserJr_magic.SequenceEqual(reiserSb.magic))
            {
                return;
            }

            StringBuilder sb = new StringBuilder();

            if (reiser35_magic.SequenceEqual(reiserSb.magic))
            {
                sb.AppendLine("Reiser 3.5 filesystem");
            }
            else if (reiser36_magic.SequenceEqual(reiserSb.magic))
            {
                sb.AppendLine("Reiser 3.6 filesystem");
            }
            else if (reiserJr_magic.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 (reiser35_magic.SequenceEqual(reiserSb.magic))
            {
                XmlFsType.Type = "Reiser 3.5 filesystem";
            }
            else if (reiser36_magic.SequenceEqual(reiserSb.magic))
            {
                XmlFsType.Type = "Reiser 3.6 filesystem";
            }
            else if (reiserJr_magic.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();
        }
Ejemplo n.º 10
0
        public Errno Stat(string path, out FileEntryInfo stat)
        {
            stat = null;

            if (!_mounted)
            {
                return(Errno.AccessDenied);
            }

            Errno err = GetFileEntry(path, out DecodedDirectoryEntry entry);

            if (err != Errno.NoError)
            {
                return(err);
            }

            stat = new FileEntryInfo
            {
                Attributes       = new FileAttributes(),
                Blocks           = (long)(entry.Size / 2048), // TODO: XA
                BlockSize        = 2048,
                Length           = (long)entry.Size,
                Links            = 1,
                LastWriteTimeUtc = entry.Timestamp
            };

            if (entry.Extents?.Count > 0)
            {
                stat.Inode = entry.Extents[0].extent;
            }

            if (entry.Size % 2048 > 0)
            {
                stat.Blocks++;
            }

            if (entry.Flags.HasFlag(FileFlags.Directory))
            {
                stat.Attributes |= FileAttributes.Directory;
            }

            if (entry.Flags.HasFlag(FileFlags.Hidden))
            {
                stat.Attributes |= FileAttributes.Hidden;
            }

            //if(entry.FinderInfo?.fdFlags.HasFlag(AppleCommon.FinderFlags.kIsAlias) == true)
            //    stat.Attributes |= FileAttributes.Alias;

            //if(entry.FinderInfo?.fdFlags.HasFlag(AppleCommon.FinderFlags.kIsInvisible) == true)
            //    stat.Attributes |= FileAttributes.Hidden;

            //if(entry.FinderInfo?.fdFlags.HasFlag(AppleCommon.FinderFlags.kHasBeenInited) == true)
            //    stat.Attributes |= FileAttributes.HasBeenInited;

            //if(entry.FinderInfo?.fdFlags.HasFlag(AppleCommon.FinderFlags.kHasCustomIcon) == true)
            //    stat.Attributes |= FileAttributes.HasCustomIcon;

            //if(entry.FinderInfo?.fdFlags.HasFlag(AppleCommon.FinderFlags.kHasNoINITs) == true)
            //    stat.Attributes |= FileAttributes.HasNoINITs;

            //if(entry.FinderInfo?.fdFlags.HasFlag(AppleCommon.FinderFlags.kIsOnDesk) == true)
            //    stat.Attributes |= FileAttributes.IsOnDesk;

            //if(entry.FinderInfo?.fdFlags.HasFlag(AppleCommon.FinderFlags.kIsShared) == true)
            //    stat.Attributes |= FileAttributes.Shared;

            //if(entry.FinderInfo?.fdFlags.HasFlag(AppleCommon.FinderFlags.kIsStationery) == true)
            //    stat.Attributes |= FileAttributes.Stationery;

            //if(entry.FinderInfo?.fdFlags.HasFlag(AppleCommon.FinderFlags.kHasBundle) == true)
            //    stat.Attributes |= FileAttributes.Bundle;

            //if(entry.AppleIcon != null)
            //    stat.Attributes |= FileAttributes.HasCustomIcon;

            if (entry.XA != null)
            {
                if (entry.XA.Value.attributes.HasFlag(XaAttributes.GroupExecute))
                {
                    stat.Mode |= 8;
                }

                if (entry.XA.Value.attributes.HasFlag(XaAttributes.GroupRead))
                {
                    stat.Mode |= 32;
                }

                if (entry.XA.Value.attributes.HasFlag(XaAttributes.OwnerExecute))
                {
                    stat.Mode |= 64;
                }

                if (entry.XA.Value.attributes.HasFlag(XaAttributes.OwnerRead))
                {
                    stat.Mode |= 256;
                }

                if (entry.XA.Value.attributes.HasFlag(XaAttributes.SystemExecute))
                {
                    stat.Mode |= 1;
                }

                if (entry.XA.Value.attributes.HasFlag(XaAttributes.SystemRead))
                {
                    stat.Mode |= 4;
                }

                stat.UID   = entry.XA.Value.user;
                stat.GID   = entry.XA.Value.group;
                stat.Inode = entry.XA.Value.filenumber;
            }

            if (entry.PosixAttributes != null)
            {
                stat.Mode = (uint?)entry.PosixAttributes.Value.st_mode & 0x0FFF;

                if (entry.PosixAttributes.Value.st_mode.HasFlag(PosixMode.Block))
                {
                    stat.Attributes |= FileAttributes.BlockDevice;
                }

                if (entry.PosixAttributes.Value.st_mode.HasFlag(PosixMode.Character))
                {
                    stat.Attributes |= FileAttributes.CharDevice;
                }

                if (entry.PosixAttributes.Value.st_mode.HasFlag(PosixMode.Pipe))
                {
                    stat.Attributes |= FileAttributes.Pipe;
                }

                if (entry.PosixAttributes.Value.st_mode.HasFlag(PosixMode.Socket))
                {
                    stat.Attributes |= FileAttributes.Socket;
                }

                if (entry.PosixAttributes.Value.st_mode.HasFlag(PosixMode.Symlink))
                {
                    stat.Attributes |= FileAttributes.Symlink;
                }

                stat.Links = entry.PosixAttributes.Value.st_nlink;
                stat.UID   = entry.PosixAttributes.Value.st_uid;
                stat.GID   = entry.PosixAttributes.Value.st_gid;
                stat.Inode = entry.PosixAttributes.Value.st_ino;
            }
            else if (entry.PosixAttributesOld != null)
            {
                stat.Mode = (uint?)entry.PosixAttributesOld.Value.st_mode & 0x0FFF;

                if (entry.PosixAttributesOld.Value.st_mode.HasFlag(PosixMode.Block))
                {
                    stat.Attributes |= FileAttributes.BlockDevice;
                }

                if (entry.PosixAttributesOld.Value.st_mode.HasFlag(PosixMode.Character))
                {
                    stat.Attributes |= FileAttributes.CharDevice;
                }

                if (entry.PosixAttributesOld.Value.st_mode.HasFlag(PosixMode.Pipe))
                {
                    stat.Attributes |= FileAttributes.Pipe;
                }

                if (entry.PosixAttributesOld.Value.st_mode.HasFlag(PosixMode.Socket))
                {
                    stat.Attributes |= FileAttributes.Socket;
                }

                if (entry.PosixAttributesOld.Value.st_mode.HasFlag(PosixMode.Symlink))
                {
                    stat.Attributes |= FileAttributes.Symlink;
                }

                stat.Links = entry.PosixAttributesOld.Value.st_nlink;
                stat.UID   = entry.PosixAttributesOld.Value.st_uid;
                stat.GID   = entry.PosixAttributesOld.Value.st_gid;
            }

            //if(entry.AmigaProtection != null)
            //{
            //    if(entry.AmigaProtection.Value.Multiuser.HasFlag(AmigaMultiuser.GroupExec))
            //        stat.Mode |= 8;

            //    if(entry.AmigaProtection.Value.Multiuser.HasFlag(AmigaMultiuser.GroupRead))
            //        stat.Mode |= 32;

            //    if(entry.AmigaProtection.Value.Multiuser.HasFlag(AmigaMultiuser.GroupWrite))
            //        stat.Mode |= 16;

            //    if(entry.AmigaProtection.Value.Multiuser.HasFlag(AmigaMultiuser.OtherExec))
            //        stat.Mode |= 1;

            //    if(entry.AmigaProtection.Value.Multiuser.HasFlag(AmigaMultiuser.OtherRead))
            //        stat.Mode |= 4;

            //    if(entry.AmigaProtection.Value.Multiuser.HasFlag(AmigaMultiuser.OtherWrite))
            //        stat.Mode |= 2;

            //    if(entry.AmigaProtection.Value.Protection.HasFlag(AmigaAttributes.OwnerExec))
            //        stat.Mode |= 64;

            //    if(entry.AmigaProtection.Value.Protection.HasFlag(AmigaAttributes.OwnerRead))
            //        stat.Mode |= 256;

            //    if(entry.AmigaProtection.Value.Protection.HasFlag(AmigaAttributes.OwnerWrite))
            //        stat.Mode |= 128;

            //    if(entry.AmigaProtection.Value.Protection.HasFlag(AmigaAttributes.Archive))
            //        stat.Attributes |= FileAttributes.Archive;
            //}

            if (entry.PosixDeviceNumber != null)
            {
                stat.DeviceNo = ((ulong)entry.PosixDeviceNumber.Value.dev_t_high << 32) +
                                entry.PosixDeviceNumber.Value.dev_t_low;
            }

            if (entry.RripModify != null)
            {
                stat.LastWriteTimeUtc = DecodeIsoDateTime(entry.RripModify);
            }

            if (entry.RripAccess != null)
            {
                stat.AccessTimeUtc = DecodeIsoDateTime(entry.RripAccess);
            }

            if (entry.RripAttributeChange != null)
            {
                stat.StatusChangeTimeUtc = DecodeIsoDateTime(entry.RripAttributeChange);
            }

            if (entry.RripBackup != null)
            {
                stat.BackupTimeUtc = DecodeIsoDateTime(entry.RripBackup);
            }

            if (entry.SymbolicLink != null)
            {
                stat.Attributes |= FileAttributes.Symlink;
            }

            if (entry.XattrLength == 0)
            {
                return(Errno.NoError);
            }

            //if(entry.CdiSystemArea != null)
            //{
            //    stat.UID = entry.CdiSystemArea.Value.owner;
            //    stat.GID = entry.CdiSystemArea.Value.group;

            //    if(entry.CdiSystemArea.Value.attributes.HasFlag(CdiAttributes.GroupExecute))
            //        stat.Mode |= 8;

            //    if(entry.CdiSystemArea.Value.attributes.HasFlag(CdiAttributes.GroupRead))
            //        stat.Mode |= 32;

            //    if(entry.CdiSystemArea.Value.attributes.HasFlag(CdiAttributes.OtherExecute))
            //        stat.Mode |= 1;

            //    if(entry.CdiSystemArea.Value.attributes.HasFlag(CdiAttributes.OtherRead))
            //        stat.Mode |= 4;

            //    if(entry.CdiSystemArea.Value.attributes.HasFlag(CdiAttributes.OwnerExecute))
            //        stat.Mode |= 64;

            //    if(entry.CdiSystemArea.Value.attributes.HasFlag(CdiAttributes.OwnerRead))
            //        stat.Mode |= 256;
            //}

            byte[] ea = ReadSingleExtent(entry.XattrLength * _blockSize, entry.Extents[0].extent);

            ExtendedAttributeRecord ear = Marshal.ByteArrayToStructureLittleEndian <ExtendedAttributeRecord>(ea);

            stat.UID = ear.owner;
            stat.GID = ear.group;

            stat.Mode = 0;

            if (ear.permissions.HasFlag(Permissions.GroupExecute))
            {
                stat.Mode |= 8;
            }

            if (ear.permissions.HasFlag(Permissions.GroupRead))
            {
                stat.Mode |= 32;
            }

            if (ear.permissions.HasFlag(Permissions.OwnerExecute))
            {
                stat.Mode |= 64;
            }

            if (ear.permissions.HasFlag(Permissions.OwnerRead))
            {
                stat.Mode |= 256;
            }

            if (ear.permissions.HasFlag(Permissions.OtherExecute))
            {
                stat.Mode |= 1;
            }

            if (ear.permissions.HasFlag(Permissions.OtherRead))
            {
                stat.Mode |= 4;
            }

            stat.CreationTimeUtc  = DateHandlers.Iso9660ToDateTime(ear.creation_date);
            stat.LastWriteTimeUtc = DateHandlers.Iso9660ToDateTime(ear.modification_date);

            return(Errno.NoError);
        }
Ejemplo n.º 11
0
Archivo: dump.cs Proyecto: 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;
            }

            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();
        }
Ejemplo n.º 12
0
        public void Open(string path)
        {
            string filename      = Path.GetFileName(path);
            string filenameNoExt = Path.GetFileNameWithoutExtension(path);
            string parentFolder  = Path.GetDirectoryName(path);

            parentFolder = parentFolder ?? "";
            if (filename is null || filenameNoExt is null)
            {
                throw new ArgumentNullException(nameof(path));
            }

            // Prepend data fork name with "R."
            string ProDosAppleDouble = Path.Combine(parentFolder, "R." + filename);
            // Prepend data fork name with '%'
            string UNIXAppleDouble = Path.Combine(parentFolder, "%" + filename);
            // Change file extension to ADF
            string DOSAppleDouble = Path.Combine(parentFolder, filenameNoExt + ".ADF");
            // Change file extension to adf
            string DOSAppleDoubleLower = Path.Combine(parentFolder, filenameNoExt + ".adf");
            // Store AppleDouble header file in ".AppleDouble" folder with same name
            string NetatalkAppleDouble = Path.Combine(parentFolder, ".AppleDouble", filename);
            // Store AppleDouble header file in "resource.frk" folder with same name
            string DAVEAppleDouble = Path.Combine(parentFolder, "resource.frk", filename);
            // Prepend data fork name with "._"
            string OSXAppleDouble = Path.Combine(parentFolder, "._" + filename);
            // Adds ".rsrc" extension
            string UnArAppleDouble = Path.Combine(parentFolder, filename + ".rsrc");

            // Check AppleDouble created by A/UX in ProDOS filesystem
            if (File.Exists(ProDosAppleDouble))
            {
                FileStream prodosStream = new FileStream(ProDosAppleDouble, FileMode.Open, FileAccess.Read);
                if (prodosStream.Length > 26)
                {
                    byte[] prodos_b = new byte[26];
                    prodosStream.Read(prodos_b, 0, 26);
                    header = Marshal.ByteArrayToStructureBigEndian <AppleDoubleHeader>(prodos_b);
                    prodosStream.Close();
                    if (header.magic == AppleDoubleMagic &&
                        (header.version == AppleDoubleVersion || header.version == AppleDoubleVersion2))
                    {
                        headerPath = ProDosAppleDouble;
                    }
                }
            }

            // Check AppleDouble created by A/UX in UFS filesystem
            if (File.Exists(UNIXAppleDouble))
            {
                FileStream unixStream = new FileStream(UNIXAppleDouble, FileMode.Open, FileAccess.Read);
                if (unixStream.Length > 26)
                {
                    byte[] unix_b = new byte[26];
                    unixStream.Read(unix_b, 0, 26);
                    header = Marshal.ByteArrayToStructureBigEndian <AppleDoubleHeader>(unix_b);
                    unixStream.Close();
                    if (header.magic == AppleDoubleMagic &&
                        (header.version == AppleDoubleVersion || header.version == AppleDoubleVersion2))
                    {
                        headerPath = UNIXAppleDouble;
                    }
                }
            }

            // Check AppleDouble created by A/UX in FAT filesystem
            if (File.Exists(DOSAppleDouble))
            {
                FileStream dosStream = new FileStream(DOSAppleDouble, FileMode.Open, FileAccess.Read);
                if (dosStream.Length > 26)
                {
                    byte[] dos_b = new byte[26];
                    dosStream.Read(dos_b, 0, 26);
                    header = Marshal.ByteArrayToStructureBigEndian <AppleDoubleHeader>(dos_b);
                    dosStream.Close();
                    if (header.magic == AppleDoubleMagic &&
                        (header.version == AppleDoubleVersion || header.version == AppleDoubleVersion2))
                    {
                        headerPath = DOSAppleDouble;
                    }
                }
            }

            // Check AppleDouble created by A/UX in case preserving FAT filesystem
            if (File.Exists(DOSAppleDoubleLower))
            {
                FileStream doslStream = new FileStream(DOSAppleDoubleLower, FileMode.Open, FileAccess.Read);
                if (doslStream.Length > 26)
                {
                    byte[] dosl_b = new byte[26];
                    doslStream.Read(dosl_b, 0, 26);
                    header = Marshal.ByteArrayToStructureBigEndian <AppleDoubleHeader>(dosl_b);
                    doslStream.Close();
                    if (header.magic == AppleDoubleMagic &&
                        (header.version == AppleDoubleVersion || header.version == AppleDoubleVersion2))
                    {
                        headerPath = DOSAppleDoubleLower;
                    }
                }
            }

            // Check AppleDouble created by Netatalk
            if (File.Exists(NetatalkAppleDouble))
            {
                FileStream netatalkStream = new FileStream(NetatalkAppleDouble, FileMode.Open, FileAccess.Read);
                if (netatalkStream.Length > 26)
                {
                    byte[] netatalk_b = new byte[26];
                    netatalkStream.Read(netatalk_b, 0, 26);
                    header = Marshal.ByteArrayToStructureBigEndian <AppleDoubleHeader>(netatalk_b);
                    netatalkStream.Close();
                    if (header.magic == AppleDoubleMagic &&
                        (header.version == AppleDoubleVersion || header.version == AppleDoubleVersion2))
                    {
                        headerPath = NetatalkAppleDouble;
                    }
                }
            }

            // Check AppleDouble created by DAVE
            if (File.Exists(DAVEAppleDouble))
            {
                FileStream daveStream = new FileStream(DAVEAppleDouble, FileMode.Open, FileAccess.Read);
                if (daveStream.Length > 26)
                {
                    byte[] dave_b = new byte[26];
                    daveStream.Read(dave_b, 0, 26);
                    header = Marshal.ByteArrayToStructureBigEndian <AppleDoubleHeader>(dave_b);
                    daveStream.Close();
                    if (header.magic == AppleDoubleMagic &&
                        (header.version == AppleDoubleVersion || header.version == AppleDoubleVersion2))
                    {
                        headerPath = DAVEAppleDouble;
                    }
                }
            }

            // Check AppleDouble created by Mac OS X
            if (File.Exists(OSXAppleDouble))
            {
                FileStream osxStream = new FileStream(OSXAppleDouble, FileMode.Open, FileAccess.Read);
                if (osxStream.Length > 26)
                {
                    byte[] osx_b = new byte[26];
                    osxStream.Read(osx_b, 0, 26);
                    header = Marshal.ByteArrayToStructureBigEndian <AppleDoubleHeader>(osx_b);
                    osxStream.Close();
                    if (header.magic == AppleDoubleMagic &&
                        (header.version == AppleDoubleVersion || header.version == AppleDoubleVersion2))
                    {
                        headerPath = OSXAppleDouble;
                    }
                }
            }

            // Check AppleDouble created by UnAr (from The Unarchiver)
            if (File.Exists(UnArAppleDouble))
            {
                FileStream unarStream = new FileStream(UnArAppleDouble, FileMode.Open, FileAccess.Read);
                if (unarStream.Length > 26)
                {
                    byte[] unar_b = new byte[26];
                    unarStream.Read(unar_b, 0, 26);
                    header = Marshal.ByteArrayToStructureBigEndian <AppleDoubleHeader>(unar_b);
                    unarStream.Close();
                    if (header.magic == AppleDoubleMagic &&
                        (header.version == AppleDoubleVersion || header.version == AppleDoubleVersion2))
                    {
                        headerPath = UnArAppleDouble;
                    }
                }
            }

            FileStream fs = new FileStream(headerPath, FileMode.Open, FileAccess.Read);

            fs.Seek(0, SeekOrigin.Begin);

            byte[] hdr_b = new byte[26];
            fs.Read(hdr_b, 0, 26);
            header = Marshal.ByteArrayToStructureBigEndian <AppleDoubleHeader>(hdr_b);

            AppleDoubleEntry[] entries = new AppleDoubleEntry[header.entries];
            for (int i = 0; i < header.entries; i++)
            {
                byte[] entry = new byte[12];
                fs.Read(entry, 0, 12);
                entries[i] = Marshal.ByteArrayToStructureBigEndian <AppleDoubleEntry>(entry);
            }

            creationTime  = DateTime.UtcNow;
            lastWriteTime = creationTime;
            foreach (AppleDoubleEntry entry in entries)
            {
                switch ((AppleDoubleEntryID)entry.id)
                {
                case AppleDoubleEntryID.DataFork:
                    // AppleDouble have datafork in separated file
                    break;

                case AppleDoubleEntryID.FileDates:
                    fs.Seek(entry.offset, SeekOrigin.Begin);
                    byte[] dates_b = new byte[16];
                    fs.Read(dates_b, 0, 16);
                    AppleDoubleFileDates dates =
                        Marshal.ByteArrayToStructureBigEndian <AppleDoubleFileDates>(dates_b);
                    creationTime  = DateHandlers.UnixUnsignedToDateTime(dates.creationDate);
                    lastWriteTime = DateHandlers.UnixUnsignedToDateTime(dates.modificationDate);
                    break;

                case AppleDoubleEntryID.FileInfo:
                    fs.Seek(entry.offset, SeekOrigin.Begin);
                    byte[] finfo = new byte[entry.length];
                    fs.Read(finfo, 0, finfo.Length);
                    if (MacintoshHome.SequenceEqual(header.homeFilesystem))
                    {
                        AppleDoubleMacFileInfo macinfo =
                            Marshal.ByteArrayToStructureBigEndian <AppleDoubleMacFileInfo>(finfo);
                        creationTime  = DateHandlers.MacToDateTime(macinfo.creationDate);
                        lastWriteTime = DateHandlers.MacToDateTime(macinfo.modificationDate);
                    }
                    else if (ProDOSHome.SequenceEqual(header.homeFilesystem))
                    {
                        AppleDoubleProDOSFileInfo prodosinfo =
                            Marshal.ByteArrayToStructureBigEndian <AppleDoubleProDOSFileInfo>(finfo);
                        creationTime  = DateHandlers.MacToDateTime(prodosinfo.creationDate);
                        lastWriteTime = DateHandlers.MacToDateTime(prodosinfo.modificationDate);
                    }
                    else if (UNIXHome.SequenceEqual(header.homeFilesystem))
                    {
                        AppleDoubleUNIXFileInfo unixinfo =
                            Marshal.ByteArrayToStructureBigEndian <AppleDoubleUNIXFileInfo>(finfo);
                        creationTime  = DateHandlers.UnixUnsignedToDateTime(unixinfo.creationDate);
                        lastWriteTime = DateHandlers.UnixUnsignedToDateTime(unixinfo.modificationDate);
                    }
                    else if (DOSHome.SequenceEqual(header.homeFilesystem))
                    {
                        AppleDoubleDOSFileInfo dosinfo =
                            Marshal.ByteArrayToStructureBigEndian <AppleDoubleDOSFileInfo>(finfo);
                        lastWriteTime =
                            DateHandlers.DosToDateTime(dosinfo.modificationDate, dosinfo.modificationTime);
                    }

                    break;

                case AppleDoubleEntryID.ResourceFork:
                    rsrcFork = entry;
                    break;
                }
            }

            dataFork = new AppleDoubleEntry {
                id = (uint)AppleDoubleEntryID.DataFork
            };
            if (File.Exists(path))
            {
                FileStream dataFs = new FileStream(path, FileMode.Open, FileAccess.Read);
                dataFork.length = (uint)dataFs.Length;
                dataFs.Close();
            }

            fs.Close();
            opened   = true;
            basePath = path;
        }
Ejemplo n.º 13
0
Archivo: Dir.cs Proyecto: paulyc/Aaru
        /// <summary>Reads, interprets and caches the Catalog File</summary>
        Errno ReadCatalog()
        {
            if (!_mounted)
            {
                return(Errno.AccessDenied);
            }

            _catalogCache = new List <CatalogEntry>();

            // Do differently for V1 and V2
            if (_mddf.fsversion == LISA_V2 ||
                _mddf.fsversion == LISA_V1)
            {
                Errno error = ReadFile((short)FILEID_CATALOG, out byte[] buf);

                if (error != Errno.NoError)
                {
                    return(error);
                }

                int offset = 0;
                List <CatalogEntryV2> catalogV2 = new List <CatalogEntryV2>();

                // For each entry on the catalog
                while (offset + 54 < buf.Length)
                {
                    var entV2 = new CatalogEntryV2
                    {
                        filenameLen = buf[offset],
                        filename    = new byte[E_NAME],
                        unknown1    = buf[offset + 0x21],
                        fileType    = buf[offset + 0x22],
                        unknown2    = buf[offset + 0x23],
                        fileID      = BigEndianBitConverter.ToInt16(buf, offset + 0x24),
                        unknown3    = new byte[16]
                    };

                    Array.Copy(buf, offset + 0x01, entV2.filename, 0, E_NAME);
                    Array.Copy(buf, offset + 0x26, entV2.unknown3, 0, 16);

                    offset += 54;

                    // Check that the entry is correct, not empty or garbage
                    if (entV2.filenameLen != 0 &&
                        entV2.filenameLen <= E_NAME &&
                        entV2.fileType != 0 &&
                        entV2.fileID > 0)
                    {
                        catalogV2.Add(entV2);
                    }
                }

                // Convert entries to V3 format
                foreach (CatalogEntryV2 entV2 in catalogV2)
                {
                    error = ReadExtentsFile(entV2.fileID, out ExtentFile ext);

                    if (error != Errno.NoError)
                    {
                        continue;
                    }

                    var entV3 = new CatalogEntry
                    {
                        fileID   = entV2.fileID,
                        filename = new byte[32],
                        fileType = entV2.fileType,
                        length   = (int)_srecords[entV2.fileID].filesize,
                        dtc      = ext.dtc,
                        dtm      = ext.dtm
                    };

                    Array.Copy(entV2.filename, 0, entV3.filename, 0, entV2.filenameLen);

                    _catalogCache.Add(entV3);
                }

                return(Errno.NoError);
            }

            byte[] firstCatalogBlock = null;

            // Search for the first sector describing the catalog
            // While root catalog is not stored in S-Records, probably rest are? (unchecked)
            // If root catalog is not pointed in MDDF (unchecked) maybe it's always following S-Records File?
            for (ulong i = 0; i < _device.Info.Sectors; i++)
            {
                DecodeTag(_device.ReadSectorTag(i, SectorTagType.AppleSectorTag), out LisaTag.PriamTag catTag);

                if (catTag.FileId != FILEID_CATALOG ||
                    catTag.RelPage != 0)
                {
                    continue;
                }

                firstCatalogBlock = _device.ReadSectors(i, 4);

                break;
            }

            // Catalog not found
            if (firstCatalogBlock == null)
            {
                return(Errno.NoSuchFile);
            }

            ulong prevCatalogPointer = BigEndianBitConverter.ToUInt32(firstCatalogBlock, 0x7F6);

            // Traverse double-linked list until first catalog block
            while (prevCatalogPointer != 0xFFFFFFFF)
            {
                DecodeTag(_device.ReadSectorTag(prevCatalogPointer + _mddf.mddf_block + _volumePrefix, SectorTagType.AppleSectorTag),
                          out LisaTag.PriamTag prevTag);

                if (prevTag.FileId != FILEID_CATALOG)
                {
                    return(Errno.InvalidArgument);
                }

                firstCatalogBlock  = _device.ReadSectors(prevCatalogPointer + _mddf.mddf_block + _volumePrefix, 4);
                prevCatalogPointer = BigEndianBitConverter.ToUInt32(firstCatalogBlock, 0x7F6);
            }

            ulong nextCatalogPointer = BigEndianBitConverter.ToUInt32(firstCatalogBlock, 0x7FA);

            List <byte[]> catalogBlocks = new List <byte[]>
            {
                firstCatalogBlock
            };

            // Traverse double-linked list to read full catalog
            while (nextCatalogPointer != 0xFFFFFFFF)
            {
                DecodeTag(_device.ReadSectorTag(nextCatalogPointer + _mddf.mddf_block + _volumePrefix, SectorTagType.AppleSectorTag),
                          out LisaTag.PriamTag nextTag);

                if (nextTag.FileId != FILEID_CATALOG)
                {
                    return(Errno.InvalidArgument);
                }

                byte[] nextCatalogBlock = _device.ReadSectors(nextCatalogPointer + _mddf.mddf_block + _volumePrefix, 4);
                nextCatalogPointer = BigEndianBitConverter.ToUInt32(nextCatalogBlock, 0x7FA);
                catalogBlocks.Add(nextCatalogBlock);
            }

            // Foreach catalog block
            foreach (byte[] buf in catalogBlocks)
            {
                int offset = 0;

                // Traverse all entries
                while (offset + 64 <= buf.Length)
                {
                    // Catalog block header
                    if (buf[offset + 0x24] == 0x08)
                    {
                        offset += 78;
                    }

                    // Maybe just garbage? Found in more than 1 disk
                    else if (buf[offset + 0x24] == 0x7C)
                    {
                        offset += 50;
                    }

                    // Apparently reserved to indicate end of catalog?
                    else if (buf[offset + 0x24] == 0xFF)
                    {
                        break;
                    }

                    // Normal entry
                    else if (buf[offset + 0x24] == 0x03 &&
                             buf[offset] == 0x24)
                    {
                        var entry = new CatalogEntry
                        {
                            marker     = buf[offset],
                            parentID   = BigEndianBitConverter.ToUInt16(buf, offset + 0x01),
                            filename   = new byte[E_NAME],
                            terminator = buf[offset + 0x23],
                            fileType   = buf[offset + 0x24],
                            unknown    = buf[offset + 0x25],
                            fileID     = BigEndianBitConverter.ToInt16(buf, offset + 0x26),
                            dtc        = BigEndianBitConverter.ToUInt32(buf, offset + 0x28),
                            dtm        = BigEndianBitConverter.ToUInt32(buf, offset + 0x2C),
                            length     = BigEndianBitConverter.ToInt32(buf, offset + 0x30),
                            wasted     = BigEndianBitConverter.ToInt32(buf, offset + 0x34),
                            tail       = new byte[8]
                        };

                        Array.Copy(buf, offset + 0x03, entry.filename, 0, E_NAME);
                        Array.Copy(buf, offset + 0x38, entry.tail, 0, 8);

                        if (ReadExtentsFile(entry.fileID, out _) == Errno.NoError)
                        {
                            if (!_fileSizeCache.ContainsKey(entry.fileID))
                            {
                                _catalogCache.Add(entry);
                                _fileSizeCache.Add(entry.fileID, entry.length);
                            }
                        }

                        offset += 64;
                    }

                    // Subdirectory entry
                    else if (buf[offset + 0x24] == 0x01 &&
                             buf[offset] == 0x24)
                    {
                        var entry = new CatalogEntry
                        {
                            marker     = buf[offset],
                            parentID   = BigEndianBitConverter.ToUInt16(buf, offset + 0x01),
                            filename   = new byte[E_NAME],
                            terminator = buf[offset + 0x23],
                            fileType   = buf[offset + 0x24],
                            unknown    = buf[offset + 0x25],
                            fileID     = BigEndianBitConverter.ToInt16(buf, offset + 0x26),
                            dtc        = BigEndianBitConverter.ToUInt32(buf, offset + 0x28),
                            dtm        = BigEndianBitConverter.ToUInt32(buf, offset + 0x2C),
                            length     = 0,
                            wasted     = 0,
                            tail       = null
                        };

                        Array.Copy(buf, offset + 0x03, entry.filename, 0, E_NAME);

                        if (!_directoryDtcCache.ContainsKey(entry.fileID))
                        {
                            _directoryDtcCache.Add(entry.fileID, DateHandlers.LisaToDateTime(entry.dtc));
                        }

                        _catalogCache.Add(entry);

                        offset += 48;
                    }
                    else
                    {
                        break;
                    }
                }
            }

            return(Errno.NoError);
        }
Ejemplo n.º 14
0
        public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information,
                                   Encoding encoding)
        {
            Encoding    = encoding ?? Encoding.GetEncoding("iso-8859-15");
            information = "";
            StringBuilder sb          = new StringBuilder();
            uint          bootSectors = JFS_BOOT_BLOCKS_SIZE / imagePlugin.Info.SectorSize;

            byte[] sector = imagePlugin.ReadSector(partition.Start + bootSectors);
            if (sector.Length < 512)
            {
                return;
            }

            JfsSuperBlock jfsSb = Marshal.ByteArrayToStructureLittleEndian <JfsSuperBlock>(sector);

            sb.AppendLine("JFS filesystem");
            sb.AppendFormat("Version {0}", jfsSb.s_version).AppendLine();
            sb.AppendFormat("{0} blocks of {1} bytes", jfsSb.s_size, jfsSb.s_bsize).AppendLine();
            sb.AppendFormat("{0} blocks per allocation group", jfsSb.s_agsize).AppendLine();

            if (jfsSb.s_flags.HasFlag(JfsFlags.Unicode))
            {
                sb.AppendLine("Volume uses Unicode for directory entries");
            }
            if (jfsSb.s_flags.HasFlag(JfsFlags.RemountRO))
            {
                sb.AppendLine("Volume remounts read-only on error");
            }
            if (jfsSb.s_flags.HasFlag(JfsFlags.Continue))
            {
                sb.AppendLine("Volume continues on error");
            }
            if (jfsSb.s_flags.HasFlag(JfsFlags.Panic))
            {
                sb.AppendLine("Volume panics on error");
            }
            if (jfsSb.s_flags.HasFlag(JfsFlags.UserQuota))
            {
                sb.AppendLine("Volume has user quotas enabled");
            }
            if (jfsSb.s_flags.HasFlag(JfsFlags.GroupQuota))
            {
                sb.AppendLine("Volume has group quotas enabled");
            }
            if (jfsSb.s_flags.HasFlag(JfsFlags.NoJournal))
            {
                sb.AppendLine("Volume is not using any journal");
            }
            if (jfsSb.s_flags.HasFlag(JfsFlags.Discard))
            {
                sb.AppendLine("Volume sends TRIM/UNMAP commands to underlying device");
            }
            if (jfsSb.s_flags.HasFlag(JfsFlags.GroupCommit))
            {
                sb.AppendLine("Volume commits in groups of 1");
            }
            if (jfsSb.s_flags.HasFlag(JfsFlags.LazyCommit))
            {
                sb.AppendLine("Volume commits lazy");
            }
            if (jfsSb.s_flags.HasFlag(JfsFlags.Temporary))
            {
                sb.AppendLine("Volume does not commit to log");
            }
            if (jfsSb.s_flags.HasFlag(JfsFlags.InlineLog))
            {
                sb.AppendLine("Volume has log withing itself");
            }
            if (jfsSb.s_flags.HasFlag(JfsFlags.InlineMoving))
            {
                sb.AppendLine("Volume has log withing itself and is moving it out");
            }
            if (jfsSb.s_flags.HasFlag(JfsFlags.BadSAIT))
            {
                sb.AppendLine("Volume has bad current secondary ait");
            }
            if (jfsSb.s_flags.HasFlag(JfsFlags.Sparse))
            {
                sb.AppendLine("Volume supports sparse files");
            }
            if (jfsSb.s_flags.HasFlag(JfsFlags.DASDEnabled))
            {
                sb.AppendLine("Volume has DASD limits enabled");
            }
            if (jfsSb.s_flags.HasFlag(JfsFlags.DASDPrime))
            {
                sb.AppendLine("Volume primes DASD on boot");
            }
            if (jfsSb.s_flags.HasFlag(JfsFlags.SwapBytes))
            {
                sb.AppendLine("Volume is in a big-endian system");
            }
            if (jfsSb.s_flags.HasFlag(JfsFlags.DirIndex))
            {
                sb.AppendLine("Volume has presistent indexes");
            }
            if (jfsSb.s_flags.HasFlag(JfsFlags.Linux))
            {
                sb.AppendLine("Volume supports Linux");
            }
            if (jfsSb.s_flags.HasFlag(JfsFlags.DFS))
            {
                sb.AppendLine("Volume supports DCE DFS LFS");
            }
            if (jfsSb.s_flags.HasFlag(JfsFlags.OS2))
            {
                sb.AppendLine("Volume supports OS/2, and is case insensitive");
            }
            if (jfsSb.s_flags.HasFlag(JfsFlags.AIX))
            {
                sb.AppendLine("Volume supports AIX");
            }
            if (jfsSb.s_state != 0)
            {
                sb.AppendLine("Volume is dirty");
            }
            sb.AppendFormat("Volume was last updated on {0}",
                            DateHandlers.UnixUnsignedToDateTime(jfsSb.s_time.tv_sec, jfsSb.s_time.tv_nsec))
            .AppendLine();
            if (jfsSb.s_version == 1)
            {
                sb.AppendFormat("Volume name: {0}", StringHandlers.CToString(jfsSb.s_fpack, Encoding)).AppendLine();
            }
            else
            {
                sb.AppendFormat("Volume name: {0}", StringHandlers.CToString(jfsSb.s_label, Encoding)).AppendLine();
            }
            sb.AppendFormat("Volume UUID: {0}", jfsSb.s_uuid).AppendLine();

            XmlFsType = new FileSystemType
            {
                Type        = "JFS filesystem",
                Clusters    = jfsSb.s_size,
                ClusterSize = jfsSb.s_bsize,
                Bootable    = true,
                VolumeName  =
                    StringHandlers.CToString(jfsSb.s_version == 1 ? jfsSb.s_fpack : jfsSb.s_label, Encoding),
                VolumeSerial     = $"{jfsSb.s_uuid}",
                ModificationDate =
                    DateHandlers.UnixUnsignedToDateTime(jfsSb.s_time.tv_sec, jfsSb.s_time.tv_nsec),
                ModificationDateSpecified = true
            };
            if (jfsSb.s_state != 0)
            {
                XmlFsType.Dirty = true;
            }

            information = sb.ToString();
        }
Ejemplo n.º 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;
            }

            EFS_Superblock efsSb = new EFS_Superblock();

            // Misaligned
            if (imagePlugin.Info.XmlMediaType == XmlMediaType.OpticalDisc)
            {
                uint sbSize = (uint)((Marshal.SizeOf(efsSb) + 0x400) / imagePlugin.Info.SectorSize);
                if ((Marshal.SizeOf(efsSb) + 0x400) % imagePlugin.Info.SectorSize != 0)
                {
                    sbSize++;
                }

                byte[] sector = imagePlugin.ReadSectors(partition.Start, sbSize);
                if (sector.Length < Marshal.SizeOf(efsSb))
                {
                    return;
                }

                byte[] sbpiece = new byte[Marshal.SizeOf(efsSb)];

                Array.Copy(sector, 0x200, sbpiece, 0, Marshal.SizeOf(efsSb));

                efsSb = BigEndianMarshal.ByteArrayToStructureBigEndian <EFS_Superblock>(sbpiece);

                DicConsole.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(efsSb) / imagePlugin.Info.SectorSize);
                if (Marshal.SizeOf(efsSb) % imagePlugin.Info.SectorSize != 0)
                {
                    sbSize++;
                }

                byte[] sector = imagePlugin.ReadSectors(partition.Start + 1, sbSize);
                if (sector.Length < Marshal.SizeOf(efsSb))
                {
                    return;
                }

                efsSb = BigEndianMarshal.ByteArrayToStructureBigEndian <EFS_Superblock>(sector);

                DicConsole.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;
            }

            StringBuilder 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              = efsSb.sb_size,
                FreeClusters          = 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
            };
        }
Ejemplo n.º 16
0
        public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information,
                                   Encoding encoding)
        {
            Encoding    = encoding ?? Encoding.GetEncoding("iso-8859-15");
            information = "";
            var sbInformation = new StringBuilder();

            uint magic = 0;
            uint sb_size_in_sectors;

            byte[] ufs_sb_sectors;
            ulong  sb_offset     = partition.Start;
            bool   fs_type_42bsd = false;
            bool   fs_type_43bsd = false;
            bool   fs_type_44bsd = false;
            bool   fs_type_ufs   = false;
            bool   fs_type_ufs2  = false;
            bool   fs_type_sun   = false;
            bool   fs_type_sun86 = false;

            if (imagePlugin.Info.SectorSize == 2336 ||
                imagePlugin.Info.SectorSize == 2352 ||
                imagePlugin.Info.SectorSize == 2448)
            {
                sb_size_in_sectors = block_size / 2048;
            }
            else
            {
                sb_size_in_sectors = block_size / imagePlugin.Info.SectorSize;
            }

            ulong[] locations =
            {
                sb_start_floppy,                    sb_start_boot,                       sb_start_long_boot, sb_start_piggy, sb_start_att_dsdd,
                8192 / imagePlugin.Info.SectorSize, 65536 / imagePlugin.Info.SectorSize,
                262144 / imagePlugin.Info.SectorSize
            };

            foreach (ulong loc in locations.Where(loc => partition.End > partition.Start + loc + sb_size_in_sectors))
            {
                ufs_sb_sectors = imagePlugin.ReadSectors(partition.Start + loc, sb_size_in_sectors);
                magic          = BitConverter.ToUInt32(ufs_sb_sectors, 0x055C);

                if (magic == UFS_MAGIC ||
                    magic == UFS_CIGAM ||
                    magic == UFS_MAGIC_BW ||
                    magic == UFS_CIGAM_BW ||
                    magic == UFS2_MAGIC ||
                    magic == UFS2_CIGAM ||
                    magic == UFS_BAD_MAGIC ||
                    magic == UFS_BAD_CIGAM)
                {
                    sb_offset = partition.Start + loc;

                    break;
                }

                magic = 0;
            }

            if (magic == 0)
            {
                information = "Not a UFS filesystem, I shouldn't have arrived here!";

                return;
            }

            XmlFsType = new FileSystemType();

            switch (magic)
            {
            case UFS_MAGIC:
                sbInformation.AppendLine("UFS filesystem");
                XmlFsType.Type = "UFS";

                break;

            case UFS_CIGAM:
                sbInformation.AppendLine("Big-endian UFS filesystem");
                XmlFsType.Type = "UFS";

                break;

            case UFS_MAGIC_BW:
                sbInformation.AppendLine("BorderWare UFS filesystem");
                XmlFsType.Type = "UFS";

                break;

            case UFS_CIGAM_BW:
                sbInformation.AppendLine("Big-endian BorderWare UFS filesystem");
                XmlFsType.Type = "UFS";

                break;

            case UFS2_MAGIC:
                sbInformation.AppendLine("UFS2 filesystem");
                XmlFsType.Type = "UFS2";

                break;

            case UFS2_CIGAM:
                sbInformation.AppendLine("Big-endian UFS2 filesystem");
                XmlFsType.Type = "UFS2";

                break;

            case UFS_BAD_MAGIC:
                sbInformation.AppendLine("Incompletely initialized UFS filesystem");
                sbInformation.AppendLine("BEWARE!!! Following information may be completely wrong!");
                XmlFsType.Type = "UFS";

                break;

            case UFS_BAD_CIGAM:
                sbInformation.AppendLine("Incompletely initialized big-endian UFS filesystem");
                sbInformation.AppendLine("BEWARE!!! Following information may be completely wrong!");
                XmlFsType.Type = "UFS";

                break;
            }

            // Fun with seeking follows on superblock reading!
            ufs_sb_sectors = imagePlugin.ReadSectors(sb_offset, sb_size_in_sectors);

            SuperBlock sb = Marshal.ByteArrayToStructureLittleEndian <SuperBlock>(ufs_sb_sectors);

            SuperBlock bs_sfu = Marshal.ByteArrayToStructureBigEndian <SuperBlock>(ufs_sb_sectors);

            if ((bs_sfu.fs_magic == UFS_MAGIC && sb.fs_magic == UFS_CIGAM) ||
                (bs_sfu.fs_magic == UFS_MAGIC_BW && sb.fs_magic == UFS_CIGAM_BW) ||
                (bs_sfu.fs_magic == UFS2_MAGIC && sb.fs_magic == UFS2_CIGAM) ||
                (bs_sfu.fs_magic == UFS_BAD_MAGIC && sb.fs_magic == UFS_BAD_CIGAM))
            {
                sb = bs_sfu;
                sb.fs_old_cstotal.cs_nbfree  = Swapping.Swap(sb.fs_old_cstotal.cs_nbfree);
                sb.fs_old_cstotal.cs_ndir    = Swapping.Swap(sb.fs_old_cstotal.cs_ndir);
                sb.fs_old_cstotal.cs_nffree  = Swapping.Swap(sb.fs_old_cstotal.cs_nffree);
                sb.fs_old_cstotal.cs_nifree  = Swapping.Swap(sb.fs_old_cstotal.cs_nifree);
                sb.fs_cstotal.cs_numclusters = Swapping.Swap(sb.fs_cstotal.cs_numclusters);
                sb.fs_cstotal.cs_nbfree      = Swapping.Swap(sb.fs_cstotal.cs_nbfree);
                sb.fs_cstotal.cs_ndir        = Swapping.Swap(sb.fs_cstotal.cs_ndir);
                sb.fs_cstotal.cs_nffree      = Swapping.Swap(sb.fs_cstotal.cs_nffree);
                sb.fs_cstotal.cs_nifree      = Swapping.Swap(sb.fs_cstotal.cs_nifree);
                sb.fs_cstotal.cs_spare[0]    = Swapping.Swap(sb.fs_cstotal.cs_spare[0]);
                sb.fs_cstotal.cs_spare[1]    = Swapping.Swap(sb.fs_cstotal.cs_spare[1]);
                sb.fs_cstotal.cs_spare[2]    = Swapping.Swap(sb.fs_cstotal.cs_spare[2]);
            }

            AaruConsole.DebugWriteLine("FFS plugin", "sb offset: 0x{0:X8}", sb_offset);
            AaruConsole.DebugWriteLine("FFS plugin", "fs_rlink: 0x{0:X8}", sb.fs_rlink);
            AaruConsole.DebugWriteLine("FFS plugin", "fs_sblkno: 0x{0:X8}", sb.fs_sblkno);
            AaruConsole.DebugWriteLine("FFS plugin", "fs_cblkno: 0x{0:X8}", sb.fs_cblkno);
            AaruConsole.DebugWriteLine("FFS plugin", "fs_iblkno: 0x{0:X8}", sb.fs_iblkno);
            AaruConsole.DebugWriteLine("FFS plugin", "fs_dblkno: 0x{0:X8}", sb.fs_dblkno);
            AaruConsole.DebugWriteLine("FFS plugin", "fs_size: 0x{0:X8}", sb.fs_size);
            AaruConsole.DebugWriteLine("FFS plugin", "fs_dsize: 0x{0:X8}", sb.fs_dsize);
            AaruConsole.DebugWriteLine("FFS plugin", "fs_ncg: 0x{0:X8}", sb.fs_ncg);
            AaruConsole.DebugWriteLine("FFS plugin", "fs_bsize: 0x{0:X8}", sb.fs_bsize);
            AaruConsole.DebugWriteLine("FFS plugin", "fs_fsize: 0x{0:X8}", sb.fs_fsize);
            AaruConsole.DebugWriteLine("FFS plugin", "fs_frag: 0x{0:X8}", sb.fs_frag);
            AaruConsole.DebugWriteLine("FFS plugin", "fs_minfree: 0x{0:X8}", sb.fs_minfree);
            AaruConsole.DebugWriteLine("FFS plugin", "fs_bmask: 0x{0:X8}", sb.fs_bmask);
            AaruConsole.DebugWriteLine("FFS plugin", "fs_fmask: 0x{0:X8}", sb.fs_fmask);
            AaruConsole.DebugWriteLine("FFS plugin", "fs_bshift: 0x{0:X8}", sb.fs_bshift);
            AaruConsole.DebugWriteLine("FFS plugin", "fs_fshift: 0x{0:X8}", sb.fs_fshift);
            AaruConsole.DebugWriteLine("FFS plugin", "fs_maxcontig: 0x{0:X8}", sb.fs_maxcontig);
            AaruConsole.DebugWriteLine("FFS plugin", "fs_maxbpg: 0x{0:X8}", sb.fs_maxbpg);
            AaruConsole.DebugWriteLine("FFS plugin", "fs_fragshift: 0x{0:X8}", sb.fs_fragshift);
            AaruConsole.DebugWriteLine("FFS plugin", "fs_fsbtodb: 0x{0:X8}", sb.fs_fsbtodb);
            AaruConsole.DebugWriteLine("FFS plugin", "fs_sbsize: 0x{0:X8}", sb.fs_sbsize);
            AaruConsole.DebugWriteLine("FFS plugin", "fs_csmask: 0x{0:X8}", sb.fs_csmask);
            AaruConsole.DebugWriteLine("FFS plugin", "fs_csshift: 0x{0:X8}", sb.fs_csshift);
            AaruConsole.DebugWriteLine("FFS plugin", "fs_nindir: 0x{0:X8}", sb.fs_nindir);
            AaruConsole.DebugWriteLine("FFS plugin", "fs_inopb: 0x{0:X8}", sb.fs_inopb);
            AaruConsole.DebugWriteLine("FFS plugin", "fs_optim: 0x{0:X8}", sb.fs_optim);
            AaruConsole.DebugWriteLine("FFS plugin", "fs_id_1: 0x{0:X8}", sb.fs_id_1);
            AaruConsole.DebugWriteLine("FFS plugin", "fs_id_2: 0x{0:X8}", sb.fs_id_2);
            AaruConsole.DebugWriteLine("FFS plugin", "fs_csaddr: 0x{0:X8}", sb.fs_csaddr);
            AaruConsole.DebugWriteLine("FFS plugin", "fs_cssize: 0x{0:X8}", sb.fs_cssize);
            AaruConsole.DebugWriteLine("FFS plugin", "fs_cgsize: 0x{0:X8}", sb.fs_cgsize);
            AaruConsole.DebugWriteLine("FFS plugin", "fs_ipg: 0x{0:X8}", sb.fs_ipg);
            AaruConsole.DebugWriteLine("FFS plugin", "fs_fpg: 0x{0:X8}", sb.fs_fpg);
            AaruConsole.DebugWriteLine("FFS plugin", "fs_fmod: 0x{0:X2}", sb.fs_fmod);
            AaruConsole.DebugWriteLine("FFS plugin", "fs_clean: 0x{0:X2}", sb.fs_clean);
            AaruConsole.DebugWriteLine("FFS plugin", "fs_ronly: 0x{0:X2}", sb.fs_ronly);
            AaruConsole.DebugWriteLine("FFS plugin", "fs_flags: 0x{0:X2}", sb.fs_flags);
            AaruConsole.DebugWriteLine("FFS plugin", "fs_magic: 0x{0:X8}", sb.fs_magic);

            if (sb.fs_magic == UFS2_MAGIC)
            {
                fs_type_ufs2 = true;
            }
            else
            {
                const uint
                    SunOSEpoch =
                    0x1A54C580;     // We are supposing there cannot be a Sun's fs created before 1/1/1982 00:00:00

                fs_type_43bsd =
                    true; // There is no way of knowing this is the version, but there is of knowing it is not.

                if (sb.fs_link > 0)
                {
                    fs_type_42bsd = true; // It was used in 4.2BSD
                    fs_type_43bsd = false;
                }

                if ((sb.fs_maxfilesize & 0xFFFFFFFF) > SunOSEpoch &&
                    DateHandlers.UnixUnsignedToDateTime(sb.fs_maxfilesize & 0xFFFFFFFF) < DateTime.Now)
                {
                    fs_type_42bsd = false;
                    fs_type_sun   = true;
                    fs_type_43bsd = false;
                }

                // This is for sure, as it is shared with a sectors/track with non-x86 SunOS, Epoch is absurdly high for that
                if (sb.fs_old_npsect > SunOSEpoch &&
                    DateHandlers.UnixToDateTime(sb.fs_old_npsect) < DateTime.Now)
                {
                    fs_type_42bsd = false;
                    fs_type_sun86 = true;
                    fs_type_sun   = false;
                    fs_type_43bsd = false;
                }

                if (sb.fs_cgrotor > 0x00000000 &&
                    (uint)sb.fs_cgrotor < 0xFFFFFFFF)
                {
                    fs_type_42bsd = false;
                    fs_type_sun   = false;
                    fs_type_sun86 = false;
                    fs_type_ufs   = true;
                    fs_type_43bsd = false;
                }

                // 4.3BSD code does not use these fields, they are always set up to 0
                fs_type_43bsd &= sb.fs_id_2 == 0 && sb.fs_id_1 == 0;

                // This is the only 4.4BSD inode format
                fs_type_44bsd |= sb.fs_old_inodefmt == 2;
            }

            if (!fs_type_ufs2)
            {
                sbInformation.AppendLine("There are a lot of variants of UFS using overlapped values on same fields");

                sbInformation.
                AppendLine("I will try to guess which one it is, but unless it's UFS2, I may be surely wrong");
            }

            if (fs_type_42bsd)
            {
                sbInformation.AppendLine("Guessed as 42BSD FFS");
            }

            if (fs_type_43bsd)
            {
                sbInformation.AppendLine("Guessed as 43BSD FFS");
            }

            if (fs_type_44bsd)
            {
                sbInformation.AppendLine("Guessed as 44BSD FFS");
            }

            if (fs_type_sun)
            {
                sbInformation.AppendLine("Guessed as SunOS FFS");
            }

            if (fs_type_sun86)
            {
                sbInformation.AppendLine("Guessed as SunOS/x86 FFS");
            }

            if (fs_type_ufs)
            {
                sbInformation.AppendLine("Guessed as UFS");
            }

            if (fs_type_42bsd)
            {
                sbInformation.AppendFormat("Linked list of filesystems: 0x{0:X8}", sb.fs_link).AppendLine();
            }

            sbInformation.AppendFormat("Superblock LBA: {0}", sb.fs_sblkno).AppendLine();
            sbInformation.AppendFormat("Cylinder-block LBA: {0}", sb.fs_cblkno).AppendLine();
            sbInformation.AppendFormat("inode-block LBA: {0}", sb.fs_iblkno).AppendLine();
            sbInformation.AppendFormat("First data block LBA: {0}", sb.fs_dblkno).AppendLine();
            sbInformation.AppendFormat("Cylinder group offset in cylinder: {0}", sb.fs_old_cgoffset).AppendLine();

            sbInformation.AppendFormat("Volume last written on {0}", DateHandlers.UnixToDateTime(sb.fs_old_time)).
            AppendLine();

            XmlFsType.ModificationDate          = DateHandlers.UnixToDateTime(sb.fs_old_time);
            XmlFsType.ModificationDateSpecified = true;

            sbInformation.AppendFormat("{0} blocks in volume ({1} bytes)", sb.fs_old_size,
                                       (long)sb.fs_old_size * sb.fs_fsize).AppendLine();

            XmlFsType.Clusters    = (ulong)sb.fs_old_size;
            XmlFsType.ClusterSize = (uint)sb.fs_fsize;

            sbInformation.AppendFormat("{0} data blocks in volume ({1} bytes)", sb.fs_old_dsize,
                                       (long)sb.fs_old_dsize * sb.fs_fsize).AppendLine();

            sbInformation.AppendFormat("{0} cylinder groups in volume", sb.fs_ncg).AppendLine();
            sbInformation.AppendFormat("{0} bytes in a basic block", sb.fs_bsize).AppendLine();
            sbInformation.AppendFormat("{0} bytes in a frag block", sb.fs_fsize).AppendLine();
            sbInformation.AppendFormat("{0} frags in a block", sb.fs_frag).AppendLine();
            sbInformation.AppendFormat("{0}% of blocks must be free", sb.fs_minfree).AppendLine();
            sbInformation.AppendFormat("{0}ms for optimal next block", sb.fs_old_rotdelay).AppendLine();

            sbInformation.AppendFormat("disk rotates {0} times per second ({1}rpm)", sb.fs_old_rps, sb.fs_old_rps * 60).
            AppendLine();

            /*          sbInformation.AppendFormat("fs_bmask: 0x{0:X8}", sb.fs_bmask).AppendLine();
             *          sbInformation.AppendFormat("fs_fmask: 0x{0:X8}", sb.fs_fmask).AppendLine();
             *          sbInformation.AppendFormat("fs_bshift: 0x{0:X8}", sb.fs_bshift).AppendLine();
             *          sbInformation.AppendFormat("fs_fshift: 0x{0:X8}", sb.fs_fshift).AppendLine();*/
            sbInformation.AppendFormat("{0} contiguous blocks at maximum", sb.fs_maxcontig).AppendLine();
            sbInformation.AppendFormat("{0} blocks per cylinder group at maximum", sb.fs_maxbpg).AppendLine();
            sbInformation.AppendFormat("Superblock is {0} bytes", sb.fs_sbsize).AppendLine();
            sbInformation.AppendFormat("NINDIR: 0x{0:X8}", sb.fs_nindir).AppendLine();
            sbInformation.AppendFormat("INOPB: 0x{0:X8}", sb.fs_inopb).AppendLine();
            sbInformation.AppendFormat("NSPF: 0x{0:X8}", sb.fs_old_nspf).AppendLine();

            switch (sb.fs_optim)
            {
            case 0:
                sbInformation.AppendLine("Filesystem will minimize allocation time");

                break;

            case 1:
                sbInformation.AppendLine("Filesystem will minimize volume fragmentation");

                break;

            default:
                sbInformation.AppendFormat("Unknown optimization value: 0x{0:X8}", sb.fs_optim).AppendLine();

                break;
            }

            if (fs_type_sun)
            {
                sbInformation.AppendFormat("{0} sectors/track", sb.fs_old_npsect).AppendLine();
            }
            else if (fs_type_sun86)
            {
                sbInformation.AppendFormat("Volume state on {0}", DateHandlers.UnixToDateTime(sb.fs_old_npsect)).
                AppendLine();
            }

            sbInformation.AppendFormat("Hardware sector interleave: {0}", sb.fs_old_interleave).AppendLine();
            sbInformation.AppendFormat("Sector 0 skew: {0}/track", sb.fs_old_trackskew).AppendLine();

            if (!fs_type_43bsd &&
                sb.fs_id_1 > 0 &&
                sb.fs_id_2 > 0)
            {
                sbInformation.AppendFormat("Volume ID: 0x{0:X8}{1:X8}", sb.fs_id_1, sb.fs_id_2).AppendLine();
            }
            else if (fs_type_43bsd &&
                     sb.fs_id_1 > 0 &&
                     sb.fs_id_2 > 0)
            {
                sbInformation.AppendFormat("{0} µsec for head switch", sb.fs_id_1).AppendLine();
                sbInformation.AppendFormat("{0} µsec for track-to-track seek", sb.fs_id_2).AppendLine();
            }

            sbInformation.AppendFormat("Cylinder group summary LBA: {0}", sb.fs_old_csaddr).AppendLine();
            sbInformation.AppendFormat("{0} bytes in cylinder group summary", sb.fs_cssize).AppendLine();
            sbInformation.AppendFormat("{0} bytes in cylinder group", sb.fs_cgsize).AppendLine();
            sbInformation.AppendFormat("{0} tracks/cylinder", sb.fs_old_ntrak).AppendLine();
            sbInformation.AppendFormat("{0} sectors/track", sb.fs_old_nsect).AppendLine();
            sbInformation.AppendFormat("{0} sectors/cylinder", sb.fs_old_spc).AppendLine();
            sbInformation.AppendFormat("{0} cylinder in volume", sb.fs_old_ncyl).AppendLine();
            sbInformation.AppendFormat("{0} cylinders/group", sb.fs_old_cpg).AppendLine();
            sbInformation.AppendFormat("{0} inodes per cylinder group", sb.fs_ipg).AppendLine();
            sbInformation.AppendFormat("{0} blocks per group", sb.fs_fpg / sb.fs_frag).AppendLine();
            sbInformation.AppendFormat("{0} directories", sb.fs_old_cstotal.cs_ndir).AppendLine();

            sbInformation.AppendFormat("{0} free blocks ({1} bytes)", sb.fs_old_cstotal.cs_nbfree,
                                       (long)sb.fs_old_cstotal.cs_nbfree * sb.fs_fsize).AppendLine();

            XmlFsType.FreeClusters          = (ulong)sb.fs_old_cstotal.cs_nbfree;
            XmlFsType.FreeClustersSpecified = true;
            sbInformation.AppendFormat("{0} free inodes", sb.fs_old_cstotal.cs_nifree).AppendLine();
            sbInformation.AppendFormat("{0} free frags", sb.fs_old_cstotal.cs_nffree).AppendLine();

            if (sb.fs_fmod == 1)
            {
                sbInformation.AppendLine("Superblock is under modification");
                XmlFsType.Dirty = true;
            }

            if (sb.fs_clean == 1)
            {
                sbInformation.AppendLine("Volume is clean");
            }

            if (sb.fs_ronly == 1)
            {
                sbInformation.AppendLine("Volume is read-only");
            }

            sbInformation.AppendFormat("Volume flags: 0x{0:X2}", sb.fs_flags).AppendLine();

            if (fs_type_ufs)
            {
                sbInformation.AppendFormat("Volume last mounted on \"{0}\"", StringHandlers.CToString(sb.fs_fsmnt)).
                AppendLine();
            }
            else if (fs_type_ufs2)
            {
                sbInformation.AppendFormat("Volume last mounted on \"{0}\"", StringHandlers.CToString(sb.fs_fsmnt)).
                AppendLine();

                sbInformation.AppendFormat("Volume name: \"{0}\"", StringHandlers.CToString(sb.fs_volname)).
                AppendLine();

                XmlFsType.VolumeName = StringHandlers.CToString(sb.fs_volname);
                sbInformation.AppendFormat("Volume ID: 0x{0:X16}", sb.fs_swuid).AppendLine();

                //xmlFSType.VolumeSerial = string.Format("{0:X16}", sb.fs_swuid);
                sbInformation.AppendFormat("Last searched cylinder group: {0}", sb.fs_cgrotor).AppendLine();
                sbInformation.AppendFormat("{0} contiguously allocated directories", sb.fs_contigdirs).AppendLine();
                sbInformation.AppendFormat("Standard superblock LBA: {0}", sb.fs_sblkno).AppendLine();
                sbInformation.AppendFormat("{0} directories", sb.fs_cstotal.cs_ndir).AppendLine();

                sbInformation.AppendFormat("{0} free blocks ({1} bytes)", sb.fs_cstotal.cs_nbfree,
                                           sb.fs_cstotal.cs_nbfree * sb.fs_fsize).AppendLine();

                XmlFsType.FreeClusters          = (ulong)sb.fs_cstotal.cs_nbfree;
                XmlFsType.FreeClustersSpecified = true;
                sbInformation.AppendFormat("{0} free inodes", sb.fs_cstotal.cs_nifree).AppendLine();
                sbInformation.AppendFormat("{0} free frags", sb.fs_cstotal.cs_nffree).AppendLine();
                sbInformation.AppendFormat("{0} free clusters", sb.fs_cstotal.cs_numclusters).AppendLine();

                sbInformation.AppendFormat("Volume last written on {0}", DateHandlers.UnixToDateTime(sb.fs_time)).
                AppendLine();

                XmlFsType.ModificationDate          = DateHandlers.UnixToDateTime(sb.fs_time);
                XmlFsType.ModificationDateSpecified = true;

                sbInformation.AppendFormat("{0} blocks ({1} bytes)", sb.fs_size, sb.fs_size * sb.fs_fsize).AppendLine();

                XmlFsType.Clusters = (ulong)sb.fs_size;

                sbInformation.AppendFormat("{0} data blocks ({1} bytes)", sb.fs_dsize, sb.fs_dsize * sb.fs_fsize).
                AppendLine();

                sbInformation.AppendFormat("Cylinder group summary area LBA: {0}", sb.fs_csaddr).AppendLine();
                sbInformation.AppendFormat("{0} blocks pending of being freed", sb.fs_pendingblocks).AppendLine();
                sbInformation.AppendFormat("{0} inodes pending of being freed", sb.fs_pendinginodes).AppendLine();
            }

            if (fs_type_sun)
            {
                sbInformation.AppendFormat("Volume state on {0}", DateHandlers.UnixToDateTime(sb.fs_old_npsect)).
                AppendLine();
            }
            else if (fs_type_sun86)
            {
                sbInformation.AppendFormat("{0} sectors/track", sb.fs_state).AppendLine();
            }
            else if (fs_type_44bsd)
            {
                sbInformation.AppendFormat("{0} blocks on cluster summary array", sb.fs_contigsumsize).AppendLine();

                sbInformation.AppendFormat("Maximum length of a symbolic link: {0}", sb.fs_maxsymlinklen).AppendLine();

                sbInformation.AppendFormat("A file can be {0} bytes at max", sb.fs_maxfilesize).AppendLine();

                sbInformation.AppendFormat("Volume state on {0}", DateHandlers.UnixToDateTime(sb.fs_state)).
                AppendLine();
            }

            if (sb.fs_old_nrpos > 0)
            {
                sbInformation.AppendFormat("{0} rotational positions", sb.fs_old_nrpos).AppendLine();
            }

            if (sb.fs_old_rotbloff > 0)
            {
                sbInformation.AppendFormat("{0} blocks per rotation", sb.fs_old_rotbloff).AppendLine();
            }

            information = sbInformation.ToString();
        }
Ejemplo n.º 17
0
        static DecodedVolumeDescriptor DecodeJolietDescriptor(PrimaryVolumeDescriptor jolietvd)
        {
            DecodedVolumeDescriptor decodedVD = new DecodedVolumeDescriptor
            {
                SystemIdentifier =
                    Encoding.BigEndianUnicode.GetString(jolietvd.system_id).Replace('\u0000', ' ').TrimEnd(),
                VolumeIdentifier =
                    Encoding.BigEndianUnicode.GetString(jolietvd.volume_id).Replace('\u0000', ' ').TrimEnd(),
                VolumeSetIdentifier =
                    Encoding.BigEndianUnicode.GetString(jolietvd.volume_set_id).Replace('\u0000', ' ').TrimEnd(),
                PublisherIdentifier =
                    Encoding.BigEndianUnicode.GetString(jolietvd.publisher_id).Replace('\u0000', ' ').TrimEnd(),
                DataPreparerIdentifier =
                    Encoding.BigEndianUnicode.GetString(jolietvd.preparer_id).Replace('\u0000', ' ').TrimEnd(),
                ApplicationIdentifier = Encoding.BigEndianUnicode.GetString(jolietvd.application_id)
                                        .Replace('\u0000', ' ').TrimEnd()
            };

            if (jolietvd.creation_date[0] < 0x31 || jolietvd.creation_date[0] > 0x39)
            {
                decodedVD.CreationTime = DateTime.MinValue;
            }
            else
            {
                decodedVD.CreationTime = DateHandlers.Iso9660ToDateTime(jolietvd.creation_date);
            }

            if (jolietvd.modification_date[0] < 0x31 || jolietvd.modification_date[0] > 0x39)
            {
                decodedVD.HasModificationTime = false;
            }
            else
            {
                decodedVD.HasModificationTime = true;
                decodedVD.ModificationTime    = DateHandlers.Iso9660ToDateTime(jolietvd.modification_date);
            }

            if (jolietvd.expiration_date[0] < 0x31 || jolietvd.expiration_date[0] > 0x39)
            {
                decodedVD.HasExpirationTime = false;
            }
            else
            {
                decodedVD.HasExpirationTime = true;
                decodedVD.ExpirationTime    = DateHandlers.Iso9660ToDateTime(jolietvd.expiration_date);
            }

            if (jolietvd.effective_date[0] < 0x31 || jolietvd.effective_date[0] > 0x39)
            {
                decodedVD.HasEffectiveTime = false;
            }
            else
            {
                decodedVD.HasEffectiveTime = true;
                decodedVD.EffectiveTime    = DateHandlers.Iso9660ToDateTime(jolietvd.effective_date);
            }

            decodedVD.Blocks    = jolietvd.volume_space_size;
            decodedVD.BlockSize = jolietvd.logical_block_size;

            return(decodedVD);
        }
Ejemplo n.º 18
0
        public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information,
                                   Encoding encoding)
        {
            Encoding    = encoding ?? Encoding.GetEncoding("macintosh");
            information = "";

            var sb = new StringBuilder();

            byte[] bbSector  = null;
            byte[] mdbSector = null;
            ushort drSigWord;

            bool apmFromHddOnCd = false;

            if (imagePlugin.Info.SectorSize == 2352 ||
                imagePlugin.Info.SectorSize == 2448 ||
                imagePlugin.Info.SectorSize == 2048)
            {
                byte[] tmpSector = imagePlugin.ReadSectors(partition.Start, 2);

                foreach (int offset in new[]
                {
                    0, 0x200, 0x400, 0x600, 0x800, 0xA00
                })
                {
                    drSigWord = BigEndianBitConverter.ToUInt16(tmpSector, offset);

                    if (drSigWord != AppleCommon.HFS_MAGIC)
                    {
                        continue;
                    }

                    bbSector  = new byte[1024];
                    mdbSector = new byte[512];

                    if (offset >= 0x400)
                    {
                        Array.Copy(tmpSector, offset - 0x400, bbSector, 0, 1024);
                    }

                    Array.Copy(tmpSector, offset, mdbSector, 0, 512);
                    apmFromHddOnCd = true;

                    break;
                }

                if (!apmFromHddOnCd)
                {
                    return;
                }
            }
            else
            {
                mdbSector = imagePlugin.ReadSector(2 + partition.Start);
                drSigWord = BigEndianBitConverter.ToUInt16(mdbSector, 0);

                if (drSigWord == AppleCommon.HFS_MAGIC)
                {
                    bbSector = imagePlugin.ReadSector(partition.Start);
                }
                else
                {
                    return;
                }
            }

            MasterDirectoryBlock mdb = Marshal.ByteArrayToStructureBigEndian <MasterDirectoryBlock>(mdbSector);

            sb.AppendLine("Apple Hierarchical File System");
            sb.AppendLine();

            if (apmFromHddOnCd)
            {
                sb.AppendLine("HFS uses 512 bytes/sector while device uses 2048 bytes/sector.").AppendLine();
            }

            sb.AppendLine("Master Directory Block:");
            sb.AppendFormat("Creation date: {0}", DateHandlers.MacToDateTime(mdb.drCrDate)).AppendLine();
            sb.AppendFormat("Last modification date: {0}", DateHandlers.MacToDateTime(mdb.drLsMod)).AppendLine();

            if (mdb.drVolBkUp > 0)
            {
                sb.AppendFormat("Last backup date: {0}", DateHandlers.MacToDateTime(mdb.drVolBkUp)).AppendLine();
                sb.AppendFormat("Backup sequence number: {0}", mdb.drVSeqNum).AppendLine();
            }
            else
            {
                sb.AppendLine("Volume has never been backed up");
            }

            if (mdb.drAtrb.HasFlag(AppleCommon.VolumeAttributes.HardwareLock))
            {
                sb.AppendLine("Volume is locked by hardware.");
            }

            sb.AppendLine(mdb.drAtrb.HasFlag(AppleCommon.VolumeAttributes.Unmounted) ? "Volume was unmonted."
                              : "Volume is mounted.");

            if (mdb.drAtrb.HasFlag(AppleCommon.VolumeAttributes.SparedBadBlocks))
            {
                sb.AppendLine("Volume has spared bad blocks.");
            }

            if (mdb.drAtrb.HasFlag(AppleCommon.VolumeAttributes.DoesNotNeedCache))
            {
                sb.AppendLine("Volume does not need cache.");
            }

            if (mdb.drAtrb.HasFlag(AppleCommon.VolumeAttributes.BootInconsistent))
            {
                sb.AppendLine("Boot volume is inconsistent.");
            }

            if (mdb.drAtrb.HasFlag(AppleCommon.VolumeAttributes.ReusedIds))
            {
                sb.AppendLine("There are reused CNIDs.");
            }

            if (mdb.drAtrb.HasFlag(AppleCommon.VolumeAttributes.Journaled))
            {
                sb.AppendLine("Volume is journaled.");
            }

            if (mdb.drAtrb.HasFlag(AppleCommon.VolumeAttributes.Inconsistent))
            {
                sb.AppendLine("Volume is seriously inconsistent.");
            }

            if (mdb.drAtrb.HasFlag(AppleCommon.VolumeAttributes.SoftwareLock))
            {
                sb.AppendLine("Volume is locked by software.");
            }

            sb.AppendFormat("{0} files on root directory", mdb.drNmFls).AppendLine();
            sb.AppendFormat("{0} directories on root directory", mdb.drNmRtDirs).AppendLine();
            sb.AppendFormat("{0} files on volume", mdb.drFilCnt).AppendLine();
            sb.AppendFormat("{0} directories on volume", mdb.drDirCnt).AppendLine();
            sb.AppendFormat("Volume write count: {0}", mdb.drWrCnt).AppendLine();

            sb.AppendFormat("Volume bitmap starting sector (in 512-bytes): {0}", mdb.drVBMSt).AppendLine();
            sb.AppendFormat("Next allocation block: {0}.", mdb.drAllocPtr).AppendLine();
            sb.AppendFormat("{0} volume allocation blocks.", mdb.drNmAlBlks).AppendLine();
            sb.AppendFormat("{0} bytes per allocation block.", mdb.drAlBlkSiz).AppendLine();
            sb.AppendFormat("{0} bytes to allocate when extending a file.", mdb.drClpSiz).AppendLine();
            sb.AppendFormat("{0} bytes to allocate when extending a Extents B-Tree.", mdb.drXTClpSiz).AppendLine();
            sb.AppendFormat("{0} bytes to allocate when extending a Catalog B-Tree.", mdb.drCTClpSiz).AppendLine();
            sb.AppendFormat("Sector of first allocation block: {0}", mdb.drAlBlSt).AppendLine();
            sb.AppendFormat("Next unused CNID: {0}", mdb.drNxtCNID).AppendLine();
            sb.AppendFormat("{0} unused allocation blocks.", mdb.drFreeBks).AppendLine();

            sb.AppendFormat("{0} bytes in the Extents B-Tree", mdb.drXTFlSize).AppendLine();
            sb.AppendFormat("{0} bytes in the Catalog B-Tree", mdb.drCTFlSize).AppendLine();

            sb.AppendFormat("Volume name: {0}", StringHandlers.PascalToString(mdb.drVN, Encoding)).AppendLine();

            sb.AppendLine("Finder info:");
            sb.AppendFormat("CNID of bootable system's directory: {0}", mdb.drFndrInfo0).AppendLine();
            sb.AppendFormat("CNID of first-run application's directory: {0}", mdb.drFndrInfo1).AppendLine();
            sb.AppendFormat("CNID of previously opened directory: {0}", mdb.drFndrInfo2).AppendLine();
            sb.AppendFormat("CNID of bootable Mac OS 8 or 9 directory: {0}", mdb.drFndrInfo3).AppendLine();
            sb.AppendFormat("CNID of bootable Mac OS X directory: {0}", mdb.drFndrInfo5).AppendLine();

            if (mdb.drFndrInfo6 != 0 &&
                mdb.drFndrInfo7 != 0)
            {
                sb.AppendFormat("Mac OS X Volume ID: {0:X8}{1:X8}", mdb.drFndrInfo6, mdb.drFndrInfo7).AppendLine();
            }

            if (mdb.drEmbedSigWord == AppleCommon.HFSP_MAGIC)
            {
                sb.AppendLine("Volume wraps a HFS+ volume.");
                sb.AppendFormat("Starting block of the HFS+ volume: {0}", mdb.xdrStABNt).AppendLine();
                sb.AppendFormat("Allocations blocks of the HFS+ volume: {0}", mdb.xdrNumABlks).AppendLine();
            }
            else
            {
                sb.AppendFormat("{0} blocks in volume cache", mdb.drVCSize).AppendLine();
                sb.AppendFormat("{0} blocks in volume bitmap cache", mdb.drVBMCSize).AppendLine();
                sb.AppendFormat("{0} blocks in volume common cache", mdb.drCtlCSize).AppendLine();
            }

            string bootBlockInfo = AppleCommon.GetBootBlockInformation(bbSector, Encoding);

            if (bootBlockInfo != null)
            {
                sb.AppendLine("Volume is bootable.");
                sb.AppendLine();
                sb.AppendLine(bootBlockInfo);
            }
            else if (mdb.drFndrInfo0 != 0 ||
                     mdb.drFndrInfo3 != 0 ||
                     mdb.drFndrInfo5 != 0)
            {
                sb.AppendLine("Volume is bootable.");
            }
            else
            {
                sb.AppendLine("Volume is not bootable.");
            }

            information = sb.ToString();

            XmlFsType = new FileSystemType();

            if (mdb.drVolBkUp > 0)
            {
                XmlFsType.BackupDate          = DateHandlers.MacToDateTime(mdb.drVolBkUp);
                XmlFsType.BackupDateSpecified = true;
            }

            XmlFsType.Bootable = bootBlockInfo != null || mdb.drFndrInfo0 != 0 || mdb.drFndrInfo3 != 0 ||
                                 mdb.drFndrInfo5 != 0;

            XmlFsType.Clusters    = mdb.drNmAlBlks;
            XmlFsType.ClusterSize = mdb.drAlBlkSiz;

            if (mdb.drCrDate > 0)
            {
                XmlFsType.CreationDate          = DateHandlers.MacToDateTime(mdb.drCrDate);
                XmlFsType.CreationDateSpecified = true;
            }

            XmlFsType.Dirty                 = !mdb.drAtrb.HasFlag(AppleCommon.VolumeAttributes.Unmounted);
            XmlFsType.Files                 = mdb.drFilCnt;
            XmlFsType.FilesSpecified        = true;
            XmlFsType.FreeClusters          = mdb.drFreeBks;
            XmlFsType.FreeClustersSpecified = true;

            if (mdb.drLsMod > 0)
            {
                XmlFsType.ModificationDate          = DateHandlers.MacToDateTime(mdb.drLsMod);
                XmlFsType.ModificationDateSpecified = true;
            }

            XmlFsType.Type       = "HFS";
            XmlFsType.VolumeName = StringHandlers.PascalToString(mdb.drVN, Encoding);

            if (mdb.drFndrInfo6 != 0 &&
                mdb.drFndrInfo7 != 0)
            {
                XmlFsType.VolumeSerial = $"{mdb.drFndrInfo6:X8}{mdb.drFndrInfo7:X8}";
            }
        }
Ejemplo n.º 19
0
        public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information,
                                   Encoding encoding)
        {
            Encoding    = encoding ?? Encoding.GetEncoding("IBM437");
            information = "";

            StringBuilder sb = new StringBuilder();

            XmlFsType = new FileSystemType();

            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);

            bool   isFat12             = false;
            bool   isFat16             = false;
            bool   isFat32             = false;
            ulong  rootDirectorySector = 0;
            string extraInfo           = null;
            string bootChk             = null;

            XmlFsType.Bootable = bootable;

            // This is needed because for FAT16, GEMDOS increases bytes per sector count instead of using big_sectors field.
            uint sectorsPerRealSector;
            // This is needed because some OSes don't put volume label as first entry in the root directory
            uint sectorsForRootDirectory = 0;

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

            case BpbKind.ShortFat32:
            case BpbKind.LongFat32:
            {
                isFat32 = true;
                Fat32ParameterBlock fat32Bpb =
                    Marshal.ByteArrayToStructureLittleEndian <Fat32ParameterBlock>(bpbSector);
                Fat32ParameterBlockShort shortFat32Bpb =
                    Marshal.ByteArrayToStructureLittleEndian <Fat32ParameterBlockShort>(bpbSector);

                // 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;
                }

                if (fat32Bpb.version != 0)
                {
                    sb.AppendLine("FAT+");
                    XmlFsType.Type = "FAT+";
                }
                else
                {
                    sb.AppendLine("Microsoft FAT32");
                    XmlFsType.Type = "FAT32";
                }

                if (fat32Bpb.oem_name != null)
                {
                    if (fat32Bpb.oem_name[5] == 0x49 && fat32Bpb.oem_name[6] == 0x48 && fat32Bpb.oem_name[7] == 0x43)
                    {
                        sb.AppendLine("Volume has been modified by Windows 9x/Me Volume Tracker.");
                    }
                    else
                    {
                        XmlFsType.SystemIdentifier = StringHandlers.CToString(fat32Bpb.oem_name);
                    }
                }

                if (!string.IsNullOrEmpty(XmlFsType.SystemIdentifier))
                {
                    sb.AppendFormat("OEM Name: {0}", XmlFsType.SystemIdentifier.Trim()).AppendLine();
                }
                sb.AppendFormat("{0} bytes per sector.", fat32Bpb.bps).AppendLine();
                sb.AppendFormat("{0} sectors per cluster.", fat32Bpb.spc).AppendLine();
                XmlFsType.ClusterSize = (uint)(fat32Bpb.bps * fat32Bpb.spc);
                sb.AppendFormat("{0} sectors reserved between BPB and FAT.", fat32Bpb.rsectors).AppendLine();
                if (fat32Bpb.big_sectors == 0 && fat32Bpb.signature == 0x28)
                {
                    sb.AppendFormat("{0} sectors on volume ({1} bytes).", shortFat32Bpb.huge_sectors,
                                    shortFat32Bpb.huge_sectors * shortFat32Bpb.bps).AppendLine();
                    XmlFsType.Clusters = shortFat32Bpb.huge_sectors / shortFat32Bpb.spc;
                }
                else
                {
                    sb.AppendFormat("{0} sectors on volume ({1} bytes).", fat32Bpb.big_sectors,
                                    fat32Bpb.big_sectors * fat32Bpb.bps).AppendLine();
                    XmlFsType.Clusters = fat32Bpb.big_sectors / fat32Bpb.spc;
                }

                sb.AppendFormat("{0} clusters on volume.", XmlFsType.Clusters).AppendLine();
                sb.AppendFormat("Media descriptor: 0x{0:X2}", fat32Bpb.media).AppendLine();
                sb.AppendFormat("{0} sectors per FAT.", fat32Bpb.big_spfat).AppendLine();
                sb.AppendFormat("{0} sectors per track.", fat32Bpb.sptrk).AppendLine();
                sb.AppendFormat("{0} heads.", fat32Bpb.heads).AppendLine();
                sb.AppendFormat("{0} hidden sectors before BPB.", fat32Bpb.hsectors).AppendLine();
                sb.AppendFormat("Cluster of root directory: {0}", fat32Bpb.root_cluster).AppendLine();
                sb.AppendFormat("Sector of FSINFO structure: {0}", fat32Bpb.fsinfo_sector).AppendLine();
                sb.AppendFormat("Sector of backup FAT32 parameter block: {0}", fat32Bpb.backup_sector).AppendLine();
                sb.AppendFormat("Drive number: 0x{0:X2}", fat32Bpb.drive_no).AppendLine();
                sb.AppendFormat("Volume Serial Number: 0x{0:X8}", fat32Bpb.serial_no).AppendLine();
                XmlFsType.VolumeSerial = $"{fat32Bpb.serial_no:X8}";

                if ((fat32Bpb.flags & 0xF8) == 0x00)
                {
                    if ((fat32Bpb.flags & 0x01) == 0x01)
                    {
                        sb.AppendLine("Volume should be checked on next mount.");
                        XmlFsType.Dirty = true;
                    }

                    if ((fat32Bpb.flags & 0x02) == 0x02)
                    {
                        sb.AppendLine("Disk surface should be on next mount.");
                    }
                }

                if ((fat32Bpb.mirror_flags & 0x80) == 0x80)
                {
                    sb.AppendFormat("FATs are out of sync. FAT #{0} is in use.", fat32Bpb.mirror_flags & 0xF)
                    .AppendLine();
                }
                else
                {
                    sb.AppendLine("All copies of FAT are the same.");
                }

                if ((fat32Bpb.mirror_flags & 0x6F20) == 0x6F20)
                {
                    sb.AppendLine("DR-DOS will boot this FAT32 using CHS.");
                }
                else if ((fat32Bpb.mirror_flags & 0x4F20) == 0x4F20)
                {
                    sb.AppendLine("DR-DOS will boot this FAT32 using LBA.");
                }

                if (fat32Bpb.signature == 0x29)
                {
                    XmlFsType.VolumeName = Encoding.ASCII.GetString(fat32Bpb.volume_label);
                    sb.AppendFormat("Filesystem type: {0}", Encoding.ASCII.GetString(fat32Bpb.fs_type))
                    .AppendLine();
                    bootChk = Sha1Context.Data(fat32Bpb.boot_code, out _);
                }
                else
                {
                    bootChk = Sha1Context.Data(shortFat32Bpb.boot_code, out _);
                }

                // 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;
                // First root directory sector
                rootDirectorySector =
                    (ulong)((fat32Bpb.root_cluster - 2) * fat32Bpb.spc + fat32Bpb.big_spfat * fat32Bpb.fats_no +
                            fat32Bpb.rsectors) * sectorsPerRealSector;
                sectorsForRootDirectory = 1;

                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)
                        {
                            sb.AppendFormat("{0} free clusters", fsInfo.free_clusters).AppendLine();
                            XmlFsType.FreeClusters          = fsInfo.free_clusters;
                            XmlFsType.FreeClustersSpecified = true;
                        }

                        if (fsInfo.last_cluster > 2 && fsInfo.last_cluster < 0xFFFFFFFF)
                        {
                            sb.AppendFormat("Last allocated cluster {0}", fsInfo.last_cluster).AppendLine();
                        }
                    }
                }

                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;
                    StringBuilder atariSb = new StringBuilder();
                    atariSb.AppendFormat("cmdload will be loaded with value {0:X4}h",
                                         BigEndianBitConverter.ToUInt16(bpbSector, 0x01E)).AppendLine();
                    atariSb.AppendFormat("Boot program will be loaded at address {0:X4}h", atariBpb.ldaaddr)
                    .AppendLine();
                    atariSb.AppendFormat("FAT and directory will be cached at address {0:X4}h", atariBpb.fatbuf)
                    .AppendLine();
                    if (atariBpb.ldmode == 0)
                    {
                        byte[] tmp = new byte[8];
                        Array.Copy(atariBpb.fname, 0, tmp, 0, 8);
                        string fname = Encoding.ASCII.GetString(tmp).Trim();
                        tmp = new byte[3];
                        Array.Copy(atariBpb.fname, 8, tmp, 0, 3);
                        string extension = Encoding.ASCII.GetString(tmp).Trim();
                        string filename;

                        if (string.IsNullOrEmpty(extension))
                        {
                            filename = fname;
                        }
                        else
                        {
                            filename = fname + "." + extension;
                        }

                        atariSb.AppendFormat("Boot program resides in file \"{0}\"", filename).AppendLine();
                    }
                    else
                    {
                        atariSb
                        .AppendFormat("Boot program starts in sector {0} and is {1} sectors long ({2} bytes)",
                                      atariBpb.ssect, atariBpb.sectcnt, atariBpb.sectcnt * atariBpb.bps)
                        .AppendLine();
                    }

                    extraInfo = atariSb.ToString();
                }

                break;
            }

            case BpbKind.Human:
                XmlFsType.Bootable = true;
                break;
            }

            if (!isFat32)
            {
                // 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;
                    }
                }

                // This assumes no sane implementation will violate cluster size rules
                // However nothing prevents this to happen
                // If first file on disk uses only one cluster there is absolutely no way to differentiate between FAT12 and FAT16,
                // so let's hope implementations use common sense?
                if (!isFat12 && !isFat16)
                {
                    ulong clusters;

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

                    if (clusters < 4089)
                    {
                        isFat12 = true;
                    }
                    else
                    {
                        isFat16 = true;
                    }
                }

                if (isFat12)
                {
                    switch (bpbKind)
                    {
                    case BpbKind.Atari:
                        sb.AppendLine("Atari FAT12");
                        break;

                    case BpbKind.Apricot:
                        sb.AppendLine("Apricot FAT12");
                        break;

                    case BpbKind.Human:
                        sb.AppendLine("Human68k FAT12");
                        break;

                    default:
                        sb.AppendLine("Microsoft FAT12");
                        break;
                    }

                    XmlFsType.Type = "FAT12";
                }
                else if (isFat16)
                {
                    sb.AppendLine(bpbKind == BpbKind.Atari
                                      ? "Atari FAT16"
                                      : bpbKind == BpbKind.Human
                                          ? "Human68k FAT16"
                                          : "Microsoft FAT16");
                    XmlFsType.Type = "FAT16";
                }

                if (bpbKind == BpbKind.Atari)
                {
                    if (atariBpb.serial_no[0] == 0x49 && atariBpb.serial_no[1] == 0x48 && atariBpb.serial_no[2] == 0x43)
                    {
                        sb.AppendLine("Volume has been modified by Windows 9x/Me Volume Tracker.");
                    }
                    else
                    {
                        XmlFsType.VolumeSerial =
                            $"{atariBpb.serial_no[0]:X2}{atariBpb.serial_no[1]:X2}{atariBpb.serial_no[2]:X2}";
                    }

                    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)
                    {
                        sb.AppendLine("Volume has been modified by Windows 9x/Me Volume Tracker.");
                    }
                    else
                    {
                        // 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}";
                    }
                }

                if (XmlFsType.SystemIdentifier != null)
                {
                    sb.AppendFormat("OEM Name: {0}", XmlFsType.SystemIdentifier.Trim()).AppendLine();
                }

                sb.AppendFormat("{0} bytes per sector.", fakeBpb.bps).AppendLine();
                if (bpbKind != BpbKind.Human)
                {
                    if (fakeBpb.sectors == 0)
                    {
                        sb.AppendFormat("{0} sectors on volume ({1} bytes).", fakeBpb.big_sectors,
                                        fakeBpb.big_sectors * fakeBpb.bps).AppendLine();
                        XmlFsType.Clusters = fakeBpb.spc == 0 ? fakeBpb.big_sectors : fakeBpb.big_sectors / fakeBpb.spc;
                    }
                    else
                    {
                        sb.AppendFormat("{0} sectors on volume ({1} bytes).", fakeBpb.sectors,
                                        fakeBpb.sectors * fakeBpb.bps).AppendLine();
                        XmlFsType.Clusters =
                            (ulong)(fakeBpb.spc == 0 ? fakeBpb.sectors : fakeBpb.sectors / fakeBpb.spc);
                    }
                }
                else
                {
                    XmlFsType.Clusters = humanBpb.clusters == 0 ? humanBpb.big_clusters : humanBpb.clusters;
                    sb.AppendFormat("{0} sectors on volume ({1} bytes).",
                                    XmlFsType.Clusters * humanBpb.bpc / imagePlugin.Info.SectorSize,
                                    XmlFsType.Clusters * humanBpb.bpc).AppendLine();
                }

                sb.AppendFormat("{0} sectors per cluster.", fakeBpb.spc).AppendLine();
                sb.AppendFormat("{0} clusters on volume.", XmlFsType.Clusters).AppendLine();
                XmlFsType.ClusterSize = (uint)(fakeBpb.bps * fakeBpb.spc);
                sb.AppendFormat("{0} sectors reserved between BPB and FAT.", fakeBpb.rsectors).AppendLine();
                sb.AppendFormat("{0} FATs.", fakeBpb.fats_no).AppendLine();
                sb.AppendFormat("{0} entries on root directory.", fakeBpb.root_ent).AppendLine();

                if (fakeBpb.media > 0)
                {
                    sb.AppendFormat("Media descriptor: 0x{0:X2}", fakeBpb.media).AppendLine();
                }

                sb.AppendFormat("{0} sectors per FAT.", fakeBpb.spfat).AppendLine();

                if (fakeBpb.sptrk > 0 && fakeBpb.sptrk < 64 && fakeBpb.heads > 0 && fakeBpb.heads < 256)
                {
                    sb.AppendFormat("{0} sectors per track.", fakeBpb.sptrk).AppendLine();
                    sb.AppendFormat("{0} heads.", fakeBpb.heads).AppendLine();
                }

                if (fakeBpb.hsectors <= partition.Start)
                {
                    sb.AppendFormat("{0} hidden sectors before BPB.", fakeBpb.hsectors).AppendLine();
                }

                if (fakeBpb.signature == 0x28 || fakeBpb.signature == 0x29 || andosOemCorrect)
                {
                    sb.AppendFormat("Drive number: 0x{0:X2}", fakeBpb.drive_no).AppendLine();

                    if (XmlFsType.VolumeSerial != null)
                    {
                        sb.AppendFormat("Volume Serial Number: {0}", XmlFsType.VolumeSerial).AppendLine();
                    }

                    if ((fakeBpb.flags & 0xF8) == 0x00)
                    {
                        if ((fakeBpb.flags & 0x01) == 0x01)
                        {
                            sb.AppendLine("Volume should be checked on next mount.");
                            XmlFsType.Dirty = true;
                        }

                        if ((fakeBpb.flags & 0x02) == 0x02)
                        {
                            sb.AppendLine("Disk surface should be on next mount.");
                        }
                    }

                    if (fakeBpb.signature == 0x29 || andosOemCorrect)
                    {
                        XmlFsType.VolumeName = Encoding.ASCII.GetString(fakeBpb.volume_label);
                        sb.AppendFormat("Filesystem type: {0}", Encoding.ASCII.GetString(fakeBpb.fs_type)).AppendLine();
                    }
                }
                else if (bpbKind == BpbKind.Atari && XmlFsType.VolumeSerial != null)
                {
                    sb.AppendFormat("Volume Serial Number: {0}", XmlFsType.VolumeSerial).AppendLine();
                }

                bootChk = Sha1Context.Data(fakeBpb.boot_code, out _);

                // 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;
                }

                sectorsPerRealSector = fakeBpb.bps / imagePlugin.Info.SectorSize;
                // First root directory sector
                rootDirectorySector =
                    (ulong)(fakeBpb.spfat * fakeBpb.fats_no + fakeBpb.rsectors) * sectorsPerRealSector;
                sectorsForRootDirectory = (uint)(fakeBpb.root_ent * 32 / imagePlugin.Info.SectorSize);
            }

            if (extraInfo != null)
            {
                sb.Append(extraInfo);
            }

            if (rootDirectorySector + partition.Start < partition.End &&
                imagePlugin.Info.XmlMediaType != XmlMediaType.OpticalDisc)
            {
                byte[] rootDirectory =
                    imagePlugin.ReadSectors(rootDirectorySector + partition.Start, sectorsForRootDirectory);

                if (bpbKind == BpbKind.DecRainbow)
                {
                    MemoryStream 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();
                }

                for (int i = 0; i < rootDirectory.Length; i += 32)
                {
                    // Not a correct entry
                    if (rootDirectory[i] < DIRENT_MIN && rootDirectory[i] != DIRENT_E5)
                    {
                        continue;
                    }

                    // Deleted or subdirectory entry
                    if (rootDirectory[i] == DIRENT_SUBDIR || rootDirectory[i] == DIRENT_DELETED)
                    {
                        continue;
                    }

                    // Not a volume label
                    if (rootDirectory[i + 0x0B] != 0x08 && rootDirectory[i + 0x0B] != 0x28)
                    {
                        continue;
                    }

                    DirectoryEntry entry =
                        Marshal.ByteArrayToStructureLittleEndian <DirectoryEntry>(rootDirectory, i, 32);

                    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) ? volname.ToLower() : volname;
                    }

                    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;
                        sb.AppendFormat("Volume created on {0}", XmlFsType.CreationDate).AppendLine();
                    }

                    if (entry.mtime > 0 && entry.mdate > 0)
                    {
                        XmlFsType.ModificationDate          = DateHandlers.DosToDateTime(entry.mdate, entry.mtime);
                        XmlFsType.ModificationDateSpecified = true;
                        sb.AppendFormat("Volume last modified on {0}", XmlFsType.ModificationDate).AppendLine();
                    }

                    if (entry.adate > 0)
                    {
                        sb.AppendFormat("Volume last accessed on {0:d}", DateHandlers.DosToDateTime(entry.adate, 0))
                        .AppendLine();
                    }

                    break;
                }
            }

            if (!string.IsNullOrEmpty(XmlFsType.VolumeName))
            {
                sb.AppendFormat("Volume label: {0}", XmlFsType.VolumeName).AppendLine();
            }
            if (XmlFsType.Bootable)
            {
                // Intel short jump
                if (bpbSector[0] == 0xEB && bpbSector[1] < 0x80)
                {
                    int    sigSize  = bpbSector[510] == 0x55 && bpbSector[511] == 0xAA ? 2 : 0;
                    byte[] bootCode = new byte[512 - sigSize - bpbSector[1] - 2];
                    Array.Copy(bpbSector, bpbSector[1] + 2, bootCode, 0, bootCode.Length);
                    Sha1Context.Data(bootCode, out _);
                }
                // Intel big jump
                else if (bpbSector[0] == 0xE9 && BitConverter.ToUInt16(bpbSector, 1) < 0x1FC)
                {
                    int    sigSize  = bpbSector[510] == 0x55 && bpbSector[511] == 0xAA ? 2 : 0;
                    byte[] bootCode = new byte[512 - sigSize - BitConverter.ToUInt16(bpbSector, 1) - 3];
                    Array.Copy(bpbSector, BitConverter.ToUInt16(bpbSector, 1) + 3, bootCode, 0, bootCode.Length);
                    Sha1Context.Data(bootCode, out _);
                }

                sb.AppendLine("Volume is bootable");
                sb.AppendFormat("Boot code's SHA1: {0}", bootChk).AppendLine();
                string bootName = knownBootHashes.FirstOrDefault(t => t.hash == bootChk).name;
                if (string.IsNullOrWhiteSpace(bootName))
                {
                    sb.AppendLine("Unknown boot code.");
                }
                else
                {
                    sb.AppendFormat("Boot code corresponds to {0}", bootName).AppendLine();
                }
            }

            information = sb.ToString();
        }
Ejemplo n.º 20
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;
            }

            UNICOS_Superblock unicosSb = new UNICOS_Superblock();

            uint sbSize = (uint)(Marshal.SizeOf(unicosSb) / imagePlugin.Info.SectorSize);

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

            byte[] sector = imagePlugin.ReadSectors(partition.Start, sbSize);
            if (sector.Length < Marshal.SizeOf(unicosSb))
            {
                return;
            }

            unicosSb = BigEndianMarshal.ByteArrayToStructureBigEndian <UNICOS_Superblock>(sector);

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

            StringBuilder 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                  = unicosSb.s_fsize,
                VolumeName                = StringHandlers.CToString(unicosSb.s_fname, Encoding),
                ModificationDate          = DateHandlers.UnixToDateTime(unicosSb.s_time),
                ModificationDateSpecified = true
            };
            XmlFsType.Dirty |= unicosSb.s_error > 0;
        }
Ejemplo n.º 21
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;
            }

            Locus_Superblock LocusSb = new Locus_Superblock();

            byte[] sector = null;

            for (ulong location = 0; location <= 8; location++)
            {
                uint sbSize = (uint)(Marshal.SizeOf(LocusSb) / imagePlugin.Info.SectorSize);
                if (Marshal.SizeOf(LocusSb) % imagePlugin.Info.SectorSize != 0)
                {
                    sbSize++;
                }

                sector = imagePlugin.ReadSectors(partition.Start + location, sbSize);
                if (sector.Length < Marshal.SizeOf(LocusSb))
                {
                    return;
                }

                IntPtr sbPtr = Marshal.AllocHGlobal(Marshal.SizeOf(LocusSb));
                Marshal.Copy(sector, 0, sbPtr, Marshal.SizeOf(LocusSb));
                LocusSb = (Locus_Superblock)Marshal.PtrToStructure(sbPtr, typeof(Locus_Superblock));
                Marshal.FreeHGlobal(sbPtr);

                if (LocusSb.s_magic == Locus_Magic || LocusSb.s_magic == Locus_Cigam ||
                    LocusSb.s_magic == Locus_OldMagic || LocusSb.s_magic == Locus_OldCigam)
                {
                    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_OldMagic &&
                LocusSb.s_magic != Locus_OldCigam)
            {
                return;
            }

            // Numerical arrays are not important for information so no need to swap them
            if (LocusSb.s_magic == Locus_Cigam || LocusSb.s_magic == Locus_OldCigam)
            {
                LocusSb         = BigEndianMarshal.ByteArrayToStructureBigEndian <Locus_Superblock>(sector);
                LocusSb.s_flags = (LocusFlags)Swapping.Swap((ushort)LocusSb.s_flags);
            }

            StringBuilder sb = new StringBuilder();

            sb.AppendLine(LocusSb.s_magic == Locus_OldMagic ? "Locus filesystem (old)" : "Locus filesystem");

            int blockSize = LocusSb.s_version == LocusVersion.SB_SB4096 ? 4096 : 1024;

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

            DicConsole.DebugWriteLine("Locus plugin", "LocusSb.s_magic = 0x{0:X8}", LocusSb.s_magic);
            DicConsole.DebugWriteLine("Locus plugin", "LocusSb.s_gfs = {0}", LocusSb.s_gfs);
            DicConsole.DebugWriteLine("Locus plugin", "LocusSb.s_fsize = {0}", LocusSb.s_fsize);
            DicConsole.DebugWriteLine("Locus plugin", "LocusSb.s_lwm = {0}", LocusSb.s_lwm);
            DicConsole.DebugWriteLine("Locus plugin", "LocusSb.s_hwm = {0}", LocusSb.s_hwm);
            DicConsole.DebugWriteLine("Locus plugin", "LocusSb.s_llst = {0}", LocusSb.s_llst);
            DicConsole.DebugWriteLine("Locus plugin", "LocusSb.s_fstore = {0}", LocusSb.s_fstore);
            DicConsole.DebugWriteLine("Locus plugin", "LocusSb.s_time = {0}", LocusSb.s_time);
            DicConsole.DebugWriteLine("Locus plugin", "LocusSb.s_tfree = {0}", LocusSb.s_tfree);
            DicConsole.DebugWriteLine("Locus plugin", "LocusSb.s_isize = {0}", LocusSb.s_isize);
            DicConsole.DebugWriteLine("Locus plugin", "LocusSb.s_nfree = {0}", LocusSb.s_nfree);
            DicConsole.DebugWriteLine("Locus plugin", "LocusSb.s_flags = {0}", LocusSb.s_flags);
            DicConsole.DebugWriteLine("Locus plugin", "LocusSb.s_tinode = {0}", LocusSb.s_tinode);
            DicConsole.DebugWriteLine("Locus plugin", "LocusSb.s_lasti = {0}", LocusSb.s_lasti);
            DicConsole.DebugWriteLine("Locus plugin", "LocusSb.s_nbehind = {0}", LocusSb.s_nbehind);
            DicConsole.DebugWriteLine("Locus plugin", "LocusSb.s_gfspack = {0}", LocusSb.s_gfspack);
            DicConsole.DebugWriteLine("Locus plugin", "LocusSb.s_ninode = {0}", LocusSb.s_ninode);
            DicConsole.DebugWriteLine("Locus plugin", "LocusSb.s_flock = {0}", LocusSb.s_flock);
            DicConsole.DebugWriteLine("Locus plugin", "LocusSb.s_ilock = {0}", LocusSb.s_ilock);
            DicConsole.DebugWriteLine("Locus plugin", "LocusSb.s_fmod = {0}", LocusSb.s_fmod);
            DicConsole.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(LocusFlags.SB_RDONLY))
            {
                sb.AppendLine("Read-only volume");
            }
            if (LocusSb.s_flags.HasFlag(LocusFlags.SB_CLEAN))
            {
                sb.AppendLine("Clean volume");
            }
            if (LocusSb.s_flags.HasFlag(LocusFlags.SB_DIRTY))
            {
                sb.AppendLine("Dirty volume");
            }
            if (LocusSb.s_flags.HasFlag(LocusFlags.SB_RMV))
            {
                sb.AppendLine("Removable volume");
            }
            if (LocusSb.s_flags.HasFlag(LocusFlags.SB_PRIMPACK))
            {
                sb.AppendLine("This is the primary pack");
            }
            if (LocusSb.s_flags.HasFlag(LocusFlags.SB_REPLTYPE))
            {
                sb.AppendLine("Replicated volume");
            }
            if (LocusSb.s_flags.HasFlag(LocusFlags.SB_USER))
            {
                sb.AppendLine("User replicated volume");
            }
            if (LocusSb.s_flags.HasFlag(LocusFlags.SB_BACKBONE))
            {
                sb.AppendLine("Backbone volume");
            }
            if (LocusSb.s_flags.HasFlag(LocusFlags.SB_NFS))
            {
                sb.AppendLine("NFS volume");
            }
            if (LocusSb.s_flags.HasFlag(LocusFlags.SB_BYHAND))
            {
                sb.AppendLine("Volume inhibits automatic fsck");
            }
            if (LocusSb.s_flags.HasFlag(LocusFlags.SB_NOSUID))
            {
                sb.AppendLine("Set-uid/set-gid is disabled");
            }
            if (LocusSb.s_flags.HasFlag(LocusFlags.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 = blockSize,
                Clusters    = 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(LocusFlags.SB_CLEAN) || LocusSb.s_flags.HasFlag(LocusFlags.SB_DIRTY),
                FreeClusters          = LocusSb.s_tfree,
                FreeClustersSpecified = true
            };
        }
Ejemplo n.º 22
0
        public Errno Stat(string path, out FileEntryInfo stat)
        {
            stat = null;

            if (!_mounted)
            {
                return(Errno.AccessDenied);
            }

            if (_debug && (string.IsNullOrEmpty(path) || path == "$" || path == "/"))
            {
                stat = new FileEntryInfo
                {
                    Attributes = FileAttributes.Directory | FileAttributes.System | FileAttributes.Hidden,
                    Blocks     = GetClusters(_superblock.rootDirectoryCluster).Length,
                    BlockSize  = _bytesPerCluster,
                    Length     = GetClusters(_superblock.rootDirectoryCluster).Length *_bytesPerCluster,
                    Inode      = _superblock.rootDirectoryCluster,
                    Links      = 1
                };

                return(Errno.NoError);
            }

            Errno err = GetFileEntry(path, out DirectoryEntry entry);

            if (err != Errno.NoError)
            {
                return(err);
            }

            stat = new FileEntryInfo
            {
                Attributes   = new FileAttributes(),
                Blocks       = entry.length / _bytesPerCluster,
                BlockSize    = _bytesPerCluster,
                Length       = entry.length,
                Inode        = entry.firstCluster,
                Links        = 1,
                CreationTime = _littleEndian
                                   ? DateHandlers.DosToDateTime(entry.creationDate, entry.creationTime).AddYears(20)
                                   : DateHandlers.DosToDateTime(entry.creationTime, entry.creationDate),
                AccessTime = _littleEndian
                                 ? DateHandlers.DosToDateTime(entry.lastAccessDate, entry.lastAccessTime).AddYears(20)
                                 : DateHandlers.DosToDateTime(entry.lastAccessTime, entry.lastAccessDate),
                LastWriteTime = _littleEndian
                                    ? DateHandlers.DosToDateTime(entry.lastWrittenDate, entry.lastWrittenTime).
                                AddYears(20)
                                    : DateHandlers.DosToDateTime(entry.lastWrittenTime, entry.lastWrittenDate)
            };

            if (entry.length % _bytesPerCluster > 0)
            {
                stat.Blocks++;
            }

            if (entry.attributes.HasFlag(Attributes.Directory))
            {
                stat.Attributes |= FileAttributes.Directory;
                stat.Blocks      = GetClusters(entry.firstCluster).Length;
                stat.Length      = stat.Blocks * stat.BlockSize;
            }

            if (entry.attributes.HasFlag(Attributes.ReadOnly))
            {
                stat.Attributes |= FileAttributes.ReadOnly;
            }

            if (entry.attributes.HasFlag(Attributes.Hidden))
            {
                stat.Attributes |= FileAttributes.Hidden;
            }

            if (entry.attributes.HasFlag(Attributes.System))
            {
                stat.Attributes |= FileAttributes.System;
            }

            if (entry.attributes.HasFlag(Attributes.Archive))
            {
                stat.Attributes |= FileAttributes.Archive;
            }

            return(Errno.NoError);
        }
Ejemplo n.º 23
0
Archivo: Read.cs Proyecto: paulyc/Aaru
        public bool Open(IFilter imageFilter)
        {
            Header     = new ScpHeader();
            _scpStream = imageFilter.GetDataForkStream();
            _scpStream.Seek(0, SeekOrigin.Begin);

            if (_scpStream.Length < Marshal.SizeOf <ScpHeader>())
            {
                return(false);
            }

            byte[] hdr = new byte[Marshal.SizeOf <ScpHeader>()];
            _scpStream.Read(hdr, 0, Marshal.SizeOf <ScpHeader>());

            Header = Marshal.ByteArrayToStructureLittleEndian <ScpHeader>(hdr);

            AaruConsole.DebugWriteLine("SuperCardPro plugin", "header.signature = \"{0}\"",
                                       StringHandlers.CToString(Header.signature));

            AaruConsole.DebugWriteLine("SuperCardPro plugin", "header.version = {0}.{1}", (Header.version & 0xF0) >> 4,
                                       Header.version & 0xF);

            AaruConsole.DebugWriteLine("SuperCardPro plugin", "header.type = {0}", Header.type);
            AaruConsole.DebugWriteLine("SuperCardPro plugin", "header.revolutions = {0}", Header.revolutions);
            AaruConsole.DebugWriteLine("SuperCardPro plugin", "header.start = {0}", Header.start);
            AaruConsole.DebugWriteLine("SuperCardPro plugin", "header.end = {0}", Header.end);
            AaruConsole.DebugWriteLine("SuperCardPro plugin", "header.flags = {0}", Header.flags);
            AaruConsole.DebugWriteLine("SuperCardPro plugin", "header.bitCellEncoding = {0}", Header.bitCellEncoding);
            AaruConsole.DebugWriteLine("SuperCardPro plugin", "header.heads = {0}", Header.heads);
            AaruConsole.DebugWriteLine("SuperCardPro plugin", "header.reserved = {0}", Header.reserved);
            AaruConsole.DebugWriteLine("SuperCardPro plugin", "header.checksum = 0x{0:X8}", Header.checksum);

            if (!_scpSignature.SequenceEqual(Header.signature))
            {
                return(false);
            }

            ScpTracks = new Dictionary <byte, TrackHeader>();

            for (byte t = Header.start; t <= Header.end; t++)
            {
                if (t >= Header.offsets.Length)
                {
                    break;
                }

                _scpStream.Position = Header.offsets[t];

                var trk = new TrackHeader
                {
                    Signature = new byte[3],
                    Entries   = new TrackEntry[Header.revolutions]
                };

                _scpStream.Read(trk.Signature, 0, trk.Signature.Length);
                trk.TrackNumber = (byte)_scpStream.ReadByte();

                if (!trk.Signature.SequenceEqual(_trkSignature))
                {
                    AaruConsole.DebugWriteLine("SuperCardPro plugin",
                                               "Track header at {0} contains incorrect signature.", Header.offsets[t]);

                    continue;
                }

                if (trk.TrackNumber != t)
                {
                    AaruConsole.DebugWriteLine("SuperCardPro plugin", "Track number at {0} should be {1} but is {2}.",
                                               Header.offsets[t], t, trk.TrackNumber);

                    continue;
                }

                AaruConsole.DebugWriteLine("SuperCardPro plugin", "Found track {0} at {1}.", t, Header.offsets[t]);

                for (byte r = 0; r < Header.revolutions; r++)
                {
                    byte[] rev = new byte[Marshal.SizeOf <TrackEntry>()];
                    _scpStream.Read(rev, 0, Marshal.SizeOf <TrackEntry>());

                    trk.Entries[r] = Marshal.ByteArrayToStructureLittleEndian <TrackEntry>(rev);

                    // De-relative offsets
                    trk.Entries[r].dataOffset += Header.offsets[t];
                }

                ScpTracks.Add(t, trk);
            }

            if (Header.flags.HasFlag(ScpFlags.HasFooter))
            {
                long position = _scpStream.Position;
                _scpStream.Seek(-4, SeekOrigin.End);

                while (_scpStream.Position >= position)
                {
                    byte[] footerSig = new byte[4];
                    _scpStream.Read(footerSig, 0, 4);
                    uint footerMagic = BitConverter.ToUInt32(footerSig, 0);

                    if (footerMagic == FOOTER_SIGNATURE)
                    {
                        _scpStream.Seek(-Marshal.SizeOf <Footer>(), SeekOrigin.Current);

                        AaruConsole.DebugWriteLine("SuperCardPro plugin", "Found footer at {0}", _scpStream.Position);

                        byte[] ftr = new byte[Marshal.SizeOf <Footer>()];
                        _scpStream.Read(ftr, 0, Marshal.SizeOf <Footer>());

                        Footer footer = Marshal.ByteArrayToStructureLittleEndian <Footer>(ftr);

                        AaruConsole.DebugWriteLine("SuperCardPro plugin", "footer.manufacturerOffset = 0x{0:X8}",
                                                   footer.manufacturerOffset);

                        AaruConsole.DebugWriteLine("SuperCardPro plugin", "footer.modelOffset = 0x{0:X8}",
                                                   footer.modelOffset);

                        AaruConsole.DebugWriteLine("SuperCardPro plugin", "footer.serialOffset = 0x{0:X8}",
                                                   footer.serialOffset);

                        AaruConsole.DebugWriteLine("SuperCardPro plugin", "footer.creatorOffset = 0x{0:X8}",
                                                   footer.creatorOffset);

                        AaruConsole.DebugWriteLine("SuperCardPro plugin", "footer.applicationOffset = 0x{0:X8}",
                                                   footer.applicationOffset);

                        AaruConsole.DebugWriteLine("SuperCardPro plugin", "footer.commentsOffset = 0x{0:X8}",
                                                   footer.commentsOffset);

                        AaruConsole.DebugWriteLine("SuperCardPro plugin", "footer.creationTime = {0}",
                                                   footer.creationTime);

                        AaruConsole.DebugWriteLine("SuperCardPro plugin", "footer.modificationTime = {0}",
                                                   footer.modificationTime);

                        AaruConsole.DebugWriteLine("SuperCardPro plugin", "footer.applicationVersion = {0}.{1}",
                                                   (footer.applicationVersion & 0xF0) >> 4,
                                                   footer.applicationVersion & 0xF);

                        AaruConsole.DebugWriteLine("SuperCardPro plugin", "footer.hardwareVersion = {0}.{1}",
                                                   (footer.hardwareVersion & 0xF0) >> 4, footer.hardwareVersion & 0xF);

                        AaruConsole.DebugWriteLine("SuperCardPro plugin", "footer.firmwareVersion = {0}.{1}",
                                                   (footer.firmwareVersion & 0xF0) >> 4, footer.firmwareVersion & 0xF);

                        AaruConsole.DebugWriteLine("SuperCardPro plugin", "footer.imageVersion = {0}.{1}",
                                                   (footer.imageVersion & 0xF0) >> 4, footer.imageVersion & 0xF);

                        AaruConsole.DebugWriteLine("SuperCardPro plugin", "footer.signature = \"{0}\"",
                                                   StringHandlers.CToString(BitConverter.GetBytes(footer.signature)));

                        _imageInfo.DriveManufacturer = ReadPStringUtf8(_scpStream, footer.manufacturerOffset);
                        _imageInfo.DriveModel        = ReadPStringUtf8(_scpStream, footer.modelOffset);
                        _imageInfo.DriveSerialNumber = ReadPStringUtf8(_scpStream, footer.serialOffset);
                        _imageInfo.Creator           = ReadPStringUtf8(_scpStream, footer.creatorOffset);
                        _imageInfo.Application       = ReadPStringUtf8(_scpStream, footer.applicationOffset);
                        _imageInfo.Comments          = ReadPStringUtf8(_scpStream, footer.commentsOffset);

                        AaruConsole.DebugWriteLine("SuperCardPro plugin", "ImageInfo.driveManufacturer = \"{0}\"",
                                                   _imageInfo.DriveManufacturer);

                        AaruConsole.DebugWriteLine("SuperCardPro plugin", "ImageInfo.driveModel = \"{0}\"",
                                                   _imageInfo.DriveModel);

                        AaruConsole.DebugWriteLine("SuperCardPro plugin", "ImageInfo.driveSerialNumber = \"{0}\"",
                                                   _imageInfo.DriveSerialNumber);

                        AaruConsole.DebugWriteLine("SuperCardPro plugin", "ImageInfo.imageCreator = \"{0}\"",
                                                   _imageInfo.Creator);

                        AaruConsole.DebugWriteLine("SuperCardPro plugin", "ImageInfo.imageApplication = \"{0}\"",
                                                   _imageInfo.Application);

                        AaruConsole.DebugWriteLine("SuperCardPro plugin", "ImageInfo.imageComments = \"{0}\"",
                                                   _imageInfo.Comments);

                        _imageInfo.CreationTime = footer.creationTime != 0
                                                      ? DateHandlers.UnixToDateTime(footer.creationTime)
                                                      : imageFilter.GetCreationTime();

                        _imageInfo.LastModificationTime = footer.modificationTime != 0
                                                              ? DateHandlers.UnixToDateTime(footer.modificationTime)
                                                              : imageFilter.GetLastWriteTime();

                        AaruConsole.DebugWriteLine("SuperCardPro plugin", "ImageInfo.imageCreationTime = {0}",
                                                   _imageInfo.CreationTime);

                        AaruConsole.DebugWriteLine("SuperCardPro plugin", "ImageInfo.imageLastModificationTime = {0}",
                                                   _imageInfo.LastModificationTime);

                        _imageInfo.ApplicationVersion =
                            $"{(footer.applicationVersion & 0xF0) >> 4}.{footer.applicationVersion & 0xF}";

                        _imageInfo.DriveFirmwareRevision =
                            $"{(footer.firmwareVersion & 0xF0) >> 4}.{footer.firmwareVersion & 0xF}";

                        _imageInfo.Version = $"{(footer.imageVersion & 0xF0) >> 4}.{footer.imageVersion & 0xF}";

                        break;
                    }

                    _scpStream.Seek(-8, SeekOrigin.Current);
                }
            }
            else
            {
                _imageInfo.Application          = "SuperCardPro";
                _imageInfo.ApplicationVersion   = $"{(Header.version & 0xF0) >> 4}.{Header.version & 0xF}";
                _imageInfo.CreationTime         = imageFilter.GetCreationTime();
                _imageInfo.LastModificationTime = imageFilter.GetLastWriteTime();
                _imageInfo.Version = "1.5";
            }

            throw new NotImplementedException("Flux decoding is not yet implemented.");
        }
Ejemplo n.º 24
0
        public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information,
                                   Encoding encoding)
        {
            Encoding    = encoding ?? Encoding.GetEncoding("ibm850");
            information = "";

            var sb = new StringBuilder();

            byte[] hpofsBpbSector =
                imagePlugin.ReadSector(0 + partition.Start); // Seek to BIOS parameter block, on logical sector 0

            byte[] medInfoSector =
                imagePlugin.ReadSector(13 + partition.Start); // Seek to media information block, on logical sector 13

            byte[] volInfoSector =
                imagePlugin.ReadSector(14 + partition.Start); // Seek to volume information block, on logical sector 14

            BiosParameterBlock     bpb = Marshal.ByteArrayToStructureLittleEndian <BiosParameterBlock>(hpofsBpbSector);
            MediaInformationBlock  mib = Marshal.ByteArrayToStructureBigEndian <MediaInformationBlock>(medInfoSector);
            VolumeInformationBlock vib = Marshal.ByteArrayToStructureBigEndian <VolumeInformationBlock>(volInfoSector);

            AaruConsole.DebugWriteLine("HPOFS Plugin", "bpb.oem_name = \"{0}\"",
                                       StringHandlers.CToString(bpb.oem_name));

            AaruConsole.DebugWriteLine("HPOFS Plugin", "bpb.bps = {0}", bpb.bps);
            AaruConsole.DebugWriteLine("HPOFS Plugin", "bpb.spc = {0}", bpb.spc);
            AaruConsole.DebugWriteLine("HPOFS Plugin", "bpb.rsectors = {0}", bpb.rsectors);
            AaruConsole.DebugWriteLine("HPOFS Plugin", "bpb.fats_no = {0}", bpb.fats_no);
            AaruConsole.DebugWriteLine("HPOFS Plugin", "bpb.root_ent = {0}", bpb.root_ent);
            AaruConsole.DebugWriteLine("HPOFS Plugin", "bpb.sectors = {0}", bpb.sectors);
            AaruConsole.DebugWriteLine("HPOFS Plugin", "bpb.media = 0x{0:X2}", bpb.media);
            AaruConsole.DebugWriteLine("HPOFS Plugin", "bpb.spfat = {0}", bpb.spfat);
            AaruConsole.DebugWriteLine("HPOFS Plugin", "bpb.sptrk = {0}", bpb.sptrk);
            AaruConsole.DebugWriteLine("HPOFS Plugin", "bpb.heads = {0}", bpb.heads);
            AaruConsole.DebugWriteLine("HPOFS Plugin", "bpb.hsectors = {0}", bpb.hsectors);
            AaruConsole.DebugWriteLine("HPOFS Plugin", "bpb.big_sectors = {0}", bpb.big_sectors);
            AaruConsole.DebugWriteLine("HPOFS Plugin", "bpb.drive_no = 0x{0:X2}", bpb.drive_no);
            AaruConsole.DebugWriteLine("HPOFS Plugin", "bpb.nt_flags = {0}", bpb.nt_flags);
            AaruConsole.DebugWriteLine("HPOFS Plugin", "bpb.signature = 0x{0:X2}", bpb.signature);
            AaruConsole.DebugWriteLine("HPOFS Plugin", "bpb.serial_no = 0x{0:X8}", bpb.serial_no);

            AaruConsole.DebugWriteLine("HPOFS Plugin", "bpb.volume_label = \"{0}\"",
                                       StringHandlers.SpacePaddedToString(bpb.volume_label));

            AaruConsole.DebugWriteLine("HPOFS Plugin", "bpb.fs_type = \"{0}\"", StringHandlers.CToString(bpb.fs_type));

            AaruConsole.DebugWriteLine("HPOFS Plugin", "bpb.boot_code is empty? = {0}",
                                       ArrayHelpers.ArrayIsNullOrEmpty(bpb.boot_code));

            AaruConsole.DebugWriteLine("HPOFS Plugin", "bpb.unknown = {0}", bpb.unknown);
            AaruConsole.DebugWriteLine("HPOFS Plugin", "bpb.unknown2 = {0}", bpb.unknown2);
            AaruConsole.DebugWriteLine("HPOFS Plugin", "bpb.signature2 = {0}", bpb.signature2);
            AaruConsole.DebugWriteLine("HPOFS Plugin", "mib.blockId = \"{0}\"", StringHandlers.CToString(mib.blockId));

            AaruConsole.DebugWriteLine("HPOFS Plugin", "mib.volumeLabel = \"{0}\"",
                                       StringHandlers.SpacePaddedToString(mib.volumeLabel));

            AaruConsole.DebugWriteLine("HPOFS Plugin", "mib.comment = \"{0}\"",
                                       StringHandlers.SpacePaddedToString(mib.comment));

            AaruConsole.DebugWriteLine("HPOFS Plugin", "mib.serial = 0x{0:X8}", mib.serial);

            AaruConsole.DebugWriteLine("HPOFS Plugin", "mib.creationTimestamp = {0}",
                                       DateHandlers.DosToDateTime(mib.creationDate, mib.creationTime));

            AaruConsole.DebugWriteLine("HPOFS Plugin", "mib.codepageType = {0}", mib.codepageType);
            AaruConsole.DebugWriteLine("HPOFS Plugin", "mib.codepage = {0}", mib.codepage);
            AaruConsole.DebugWriteLine("HPOFS Plugin", "mib.rps = {0}", mib.rps);
            AaruConsole.DebugWriteLine("HPOFS Plugin", "mib.bps = {0}", mib.bps);
            AaruConsole.DebugWriteLine("HPOFS Plugin", "mib.bpc = {0}", mib.bpc);
            AaruConsole.DebugWriteLine("HPOFS Plugin", "mib.unknown2 = {0}", mib.unknown2);
            AaruConsole.DebugWriteLine("HPOFS Plugin", "mib.sectors = {0}", mib.sectors);
            AaruConsole.DebugWriteLine("HPOFS Plugin", "mib.unknown3 = {0}", mib.unknown3);
            AaruConsole.DebugWriteLine("HPOFS Plugin", "mib.unknown4 = {0}", mib.unknown4);
            AaruConsole.DebugWriteLine("HPOFS Plugin", "mib.major = {0}", mib.major);
            AaruConsole.DebugWriteLine("HPOFS Plugin", "mib.minor = {0}", mib.minor);
            AaruConsole.DebugWriteLine("HPOFS Plugin", "mib.unknown5 = {0}", mib.unknown5);
            AaruConsole.DebugWriteLine("HPOFS Plugin", "mib.unknown6 = {0}", mib.unknown6);

            AaruConsole.DebugWriteLine("HPOFS Plugin", "mib.filler is empty? = {0}",
                                       ArrayHelpers.ArrayIsNullOrEmpty(mib.filler));

            AaruConsole.DebugWriteLine("HPOFS Plugin", "vib.blockId = \"{0}\"", StringHandlers.CToString(vib.blockId));
            AaruConsole.DebugWriteLine("HPOFS Plugin", "vib.unknown = {0}", vib.unknown);
            AaruConsole.DebugWriteLine("HPOFS Plugin", "vib.unknown2 = {0}", vib.unknown2);

            AaruConsole.DebugWriteLine("HPOFS Plugin", "vib.unknown3 is empty? = {0}",
                                       ArrayHelpers.ArrayIsNullOrEmpty(vib.unknown3));

            AaruConsole.DebugWriteLine("HPOFS Plugin", "vib.unknown4 = \"{0}\"",
                                       StringHandlers.SpacePaddedToString(vib.unknown4));

            AaruConsole.DebugWriteLine("HPOFS Plugin", "vib.owner = \"{0}\"",
                                       StringHandlers.SpacePaddedToString(vib.owner));

            AaruConsole.DebugWriteLine("HPOFS Plugin", "vib.unknown5 = \"{0}\"",
                                       StringHandlers.SpacePaddedToString(vib.unknown5));

            AaruConsole.DebugWriteLine("HPOFS Plugin", "vib.unknown6 = {0}", vib.unknown6);
            AaruConsole.DebugWriteLine("HPOFS Plugin", "vib.percentFull = {0}", vib.percentFull);
            AaruConsole.DebugWriteLine("HPOFS Plugin", "vib.unknown7 = {0}", vib.unknown7);

            AaruConsole.DebugWriteLine("HPOFS Plugin", "vib.filler is empty? = {0}",
                                       ArrayHelpers.ArrayIsNullOrEmpty(vib.filler));

            sb.AppendLine("High Performance Optical File System");
            sb.AppendFormat("OEM name: {0}", StringHandlers.SpacePaddedToString(bpb.oem_name)).AppendLine();
            sb.AppendFormat("{0} bytes per sector", bpb.bps).AppendLine();
            sb.AppendFormat("{0} sectors per cluster", bpb.spc).AppendLine();
            sb.AppendFormat("Media descriptor: 0x{0:X2}", bpb.media).AppendLine();
            sb.AppendFormat("{0} sectors per track", bpb.sptrk).AppendLine();
            sb.AppendFormat("{0} heads", bpb.heads).AppendLine();
            sb.AppendFormat("{0} sectors hidden before BPB", bpb.hsectors).AppendLine();
            sb.AppendFormat("{0} sectors on volume ({1} bytes)", mib.sectors, mib.sectors * bpb.bps).AppendLine();
            sb.AppendFormat("BIOS Drive Number: 0x{0:X2}", bpb.drive_no).AppendLine();
            sb.AppendFormat("Serial number: 0x{0:X8}", mib.serial).AppendLine();

            sb.AppendFormat("Volume label: {0}", StringHandlers.SpacePaddedToString(mib.volumeLabel, Encoding)).
            AppendLine();

            sb.AppendFormat("Volume comment: {0}", StringHandlers.SpacePaddedToString(mib.comment, Encoding)).
            AppendLine();

            sb.AppendFormat("Volume owner: {0}", StringHandlers.SpacePaddedToString(vib.owner, Encoding)).AppendLine();

            sb.AppendFormat("Volume created on {0}", DateHandlers.DosToDateTime(mib.creationDate, mib.creationTime)).
            AppendLine();

            sb.AppendFormat("Volume uses {0} codepage {1}", mib.codepageType > 0 && mib.codepageType < 3
                                                                ? mib.codepageType == 2
                                                                      ? "EBCDIC"
                                                                      : "ASCII" : "Unknown", mib.codepage).AppendLine();

            sb.AppendFormat("RPS level: {0}", mib.rps).AppendLine();
            sb.AppendFormat("Filesystem version: {0}.{1}", mib.major, mib.minor).AppendLine();
            sb.AppendFormat("Volume can be filled up to {0}%", vib.percentFull).AppendLine();

            XmlFsType = new FileSystemType
            {
                Clusters               = mib.sectors / bpb.spc, ClusterSize = (uint)(bpb.bps * bpb.spc),
                CreationDate           = DateHandlers.DosToDateTime(mib.creationDate, mib.creationTime),
                CreationDateSpecified  = true,
                DataPreparerIdentifier = StringHandlers.SpacePaddedToString(vib.owner, Encoding), Type = "HPOFS",
                VolumeName             = StringHandlers.SpacePaddedToString(mib.volumeLabel, Encoding),
                VolumeSerial           = $"{mib.serial:X8}",
                SystemIdentifier       = StringHandlers.SpacePaddedToString(bpb.oem_name)
            };

            information = sb.ToString();
        }
Ejemplo n.º 25
0
        public Errno Stat(string path, out FileEntryInfo stat)
        {
            stat = null;

            if (!mounted)
            {
                return(Errno.AccessDenied);
            }

            Errno err = GetFileEntry(path, out CompleteDirectoryEntry completeEntry);

            if (err != Errno.NoError)
            {
                return(err);
            }

            DirectoryEntry entry = completeEntry.Dirent;

            stat = new FileEntryInfo
            {
                Attributes   = new FileAttributes(), Blocks = entry.size / bytesPerCluster, BlockSize = bytesPerCluster,
                Length       = entry.size,
                Inode        = (ulong)(fat32 ? (entry.ea_handle << 16) + entry.start_cluster : entry.start_cluster),
                Links        = 1,
                CreationTime = DateHandlers.DosToDateTime(entry.cdate, entry.ctime)
            };

            if (@namespace != Namespace.Human)
            {
                stat.LastWriteTime = DateHandlers.DosToDateTime(entry.mdate, entry.mtime);
                stat.CreationTime  = stat.CreationTime?.AddMilliseconds(entry.ctime_ms * 10);
            }

            if (entry.size % bytesPerCluster > 0)
            {
                stat.Blocks++;
            }

            if (entry.attributes.HasFlag(FatAttributes.Subdirectory))
            {
                stat.Attributes |= FileAttributes.Directory;

                stat.Blocks = fat32 ? GetClusters((uint)((entry.ea_handle << 16) + entry.start_cluster)).Length
                                  : GetClusters(entry.start_cluster).Length;

                stat.Length = stat.Blocks * stat.BlockSize;
            }

            if (entry.attributes.HasFlag(FatAttributes.ReadOnly))
            {
                stat.Attributes |= FileAttributes.ReadOnly;
            }

            if (entry.attributes.HasFlag(FatAttributes.Hidden))
            {
                stat.Attributes |= FileAttributes.Hidden;
            }

            if (entry.attributes.HasFlag(FatAttributes.System))
            {
                stat.Attributes |= FileAttributes.System;
            }

            if (entry.attributes.HasFlag(FatAttributes.Archive))
            {
                stat.Attributes |= FileAttributes.Archive;
            }

            if (entry.attributes.HasFlag(FatAttributes.Device))
            {
                stat.Attributes |= FileAttributes.Device;
            }

            return(Errno.NoError);
        }
Ejemplo n.º 26
0
        public Errno Mount(IMediaImage imagePlugin, Partition partition, Encoding encoding,
                           Dictionary <string, string> options, string @namespace)
        {
            _device  = imagePlugin;
            Encoding = encoding ?? Encoding.GetEncoding("IBM437");

            options ??= GetDefaultOptions();

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

            // As the identification is so complex, just call Identify() and relay on its findings
            if (!Identify(_device, partition) ||
                !_cpmFound ||
                _workingDefinition == null ||
                _dpb == null)
            {
                return(Errno.InvalidArgument);
            }

            // Build the software interleaving sector mask
            if (_workingDefinition.sides == 1)
            {
                _sectorMask = new int[_workingDefinition.side1.sectorIds.Length];

                for (int m = 0; m < _sectorMask.Length; m++)
                {
                    _sectorMask[m] = _workingDefinition.side1.sectorIds[m] - _workingDefinition.side1.sectorIds[0];
                }
            }
            else
            {
                // Head changes after every track
                if (string.Compare(_workingDefinition.order, "SIDES", StringComparison.InvariantCultureIgnoreCase) == 0)
                {
                    _sectorMask = new int[_workingDefinition.side1.sectorIds.Length +
                                          _workingDefinition.side2.sectorIds.Length];

                    for (int m = 0; m < _workingDefinition.side1.sectorIds.Length; m++)
                    {
                        _sectorMask[m] = _workingDefinition.side1.sectorIds[m] - _workingDefinition.side1.sectorIds[0];
                    }

                    // Skip first track (first side)
                    for (int m = 0; m < _workingDefinition.side2.sectorIds.Length; m++)
                    {
                        _sectorMask[m + _workingDefinition.side1.sectorIds.Length] =
                            (_workingDefinition.side2.sectorIds[m] - _workingDefinition.side2.sectorIds[0]) +
                            _workingDefinition.side1.sectorIds.Length;
                    }
                }

                // Head changes after whole side
                else if (string.Compare(_workingDefinition.order, "CYLINDERS",
                                        StringComparison.InvariantCultureIgnoreCase) == 0)
                {
                    for (int m = 0; m < _workingDefinition.side1.sectorIds.Length; m++)
                    {
                        _sectorMask[m] = _workingDefinition.side1.sectorIds[m] - _workingDefinition.side1.sectorIds[0];
                    }

                    // Skip first track (first side) and first track (second side)
                    for (int m = 0; m < _workingDefinition.side1.sectorIds.Length; m++)
                    {
                        _sectorMask[m + _workingDefinition.side1.sectorIds.Length] =
                            (_workingDefinition.side1.sectorIds[m] - _workingDefinition.side1.sectorIds[0]) +
                            _workingDefinition.side1.sectorIds.Length + _workingDefinition.side2.sectorIds.Length;
                    }

                    // TODO: Implement CYLINDERS ordering
                    AaruConsole.DebugWriteLine("CP/M Plugin", "CYLINDERS ordering not yet implemented.");

                    return(Errno.NotImplemented);
                }

                // TODO: Implement COLUMBIA ordering
                else if (string.Compare(_workingDefinition.order, "COLUMBIA",
                                        StringComparison.InvariantCultureIgnoreCase) == 0)
                {
                    AaruConsole.DebugWriteLine("CP/M Plugin",
                                               "Don't know how to handle COLUMBIA ordering, not proceeding with this definition.");

                    return(Errno.NotImplemented);
                }

                // TODO: Implement EAGLE ordering
                else if (string.Compare(_workingDefinition.order, "EAGLE",
                                        StringComparison.InvariantCultureIgnoreCase) == 0)
                {
                    AaruConsole.DebugWriteLine("CP/M Plugin",
                                               "Don't know how to handle EAGLE ordering, not proceeding with this definition.");

                    return(Errno.NotImplemented);
                }
                else
                {
                    AaruConsole.DebugWriteLine("CP/M Plugin",
                                               "Unknown order type \"{0}\", not proceeding with this definition.",
                                               _workingDefinition.order);

                    return(Errno.NotSupported);
                }
            }

            // Deinterleave whole volume
            Dictionary <ulong, byte[]> deinterleavedSectors = new Dictionary <ulong, byte[]>();

            if (_workingDefinition.sides == 1 ||
                string.Compare(_workingDefinition.order, "SIDES", StringComparison.InvariantCultureIgnoreCase) == 0)
            {
                AaruConsole.DebugWriteLine("CP/M Plugin", "Deinterleaving whole volume.");

                for (int p = 0; p <= (int)(partition.End - partition.Start); p++)
                {
                    byte[] readSector =
                        _device.ReadSector((ulong)((int)partition.Start +
                                                   ((p / _sectorMask.Length) * _sectorMask.Length) +
                                                   _sectorMask[p % _sectorMask.Length]));

                    if (_workingDefinition.complement)
                    {
                        for (int b = 0; b < readSector.Length; b++)
                        {
                            readSector[b] = (byte)(~readSector[b] & 0xFF);
                        }
                    }

                    deinterleavedSectors.Add((ulong)p, readSector);
                }
            }

            int   blockSize       = 128 << _dpb.bsh;
            var   blockMs         = new MemoryStream();
            ulong blockNo         = 0;
            int   sectorsPerBlock = 0;
            Dictionary <ulong, byte[]> allocationBlocks = new Dictionary <ulong, byte[]>();

            AaruConsole.DebugWriteLine("CP/M Plugin", "Creating allocation blocks.");

            // For each volume sector
            for (ulong a = 0; a < (ulong)deinterleavedSectors.Count; a++)
            {
                deinterleavedSectors.TryGetValue(a, out byte[] sector);

                // May it happen? Just in case, CP/M blocks are smaller than physical sectors
                if (sector.Length > blockSize)
                {
                    for (int i = 0; i < sector.Length / blockSize; i++)
                    {
                        byte[] tmp = new byte[blockSize];
                        Array.Copy(sector, blockSize * i, tmp, 0, blockSize);
                        allocationBlocks.Add(blockNo++, tmp);
                    }
                }

                // CP/M blocks are larger than physical sectors
                else if (sector.Length < blockSize)
                {
                    blockMs.Write(sector, 0, sector.Length);
                    sectorsPerBlock++;

                    if (sectorsPerBlock != blockSize / sector.Length)
                    {
                        continue;
                    }

                    allocationBlocks.Add(blockNo++, blockMs.ToArray());
                    sectorsPerBlock = 0;
                    blockMs         = new MemoryStream();
                }

                // CP/M blocks are same size than physical sectors
                else
                {
                    allocationBlocks.Add(blockNo++, sector);
                }
            }

            AaruConsole.DebugWriteLine("CP/M Plugin", "Reading directory.");

            int dirOff;
            int dirSectors = ((_dpb.drm + 1) * 32) / _workingDefinition.bytesPerSector;

            if (_workingDefinition.sofs > 0)
            {
                dirOff = _workingDefinition.sofs;
            }
            else
            {
                dirOff = _workingDefinition.ofs * _workingDefinition.sectorsPerTrack;
            }

            // Read the whole directory blocks
            var dirMs = new MemoryStream();

            for (int d = 0; d < dirSectors; d++)
            {
                deinterleavedSectors.TryGetValue((ulong)(d + dirOff), out byte[] sector);
                dirMs.Write(sector, 0, sector.Length);
            }

            byte[] directory = dirMs.ToArray();

            if (directory == null)
            {
                return(Errno.InvalidArgument);
            }

            int    dirCnt = 0;
            string file1  = null;
            string file2  = null;
            string file3  = null;

            Dictionary <string, Dictionary <int, List <ushort> > > fileExtents =
                new Dictionary <string, Dictionary <int, List <ushort> > >();

            _statCache = new Dictionary <string, FileEntryInfo>();
            _cpmStat   = new FileSystemInfo();
            bool atime = false;

            _dirList           = new List <string>();
            _labelCreationDate = null;
            _labelUpdateDate   = null;
            _passwordCache     = new Dictionary <string, byte[]>();

            AaruConsole.DebugWriteLine("CP/M Plugin", "Traversing directory.");

            // For each directory entry
            for (int dOff = 0; dOff < directory.Length; dOff += 32)
            {
                // Describes a file (does not support PDOS entries with user >= 16, because they're identical to password entries
                if ((directory[dOff] & 0x7F) < 0x10)
                {
                    if (allocationBlocks.Count > 256)
                    {
                        DirectoryEntry16 entry =
                            Marshal.ByteArrayToStructureLittleEndian <DirectoryEntry16>(directory, dOff, 32);

                        bool hidden = (entry.statusUser & 0x80) == 0x80;
                        bool rdOnly = (entry.filename[0] & 0x80) == 0x80 || (entry.extension[0] & 0x80) == 0x80;
                        bool system = (entry.filename[1] & 0x80) == 0x80 || (entry.extension[2] & 0x80) == 0x80;

                        //bool backed = (entry.filename[3] & 0x80) == 0x80 || (entry.extension[3] & 0x80) == 0x80;
                        int user = entry.statusUser & 0x0F;

                        bool validEntry = true;

                        for (int i = 0; i < 8; i++)
                        {
                            entry.filename[i] &= 0x7F;
                            validEntry        &= entry.filename[i] >= 0x20;
                        }

                        for (int i = 0; i < 3; i++)
                        {
                            entry.extension[i] &= 0x7F;
                            validEntry         &= entry.extension[i] >= 0x20;
                        }

                        if (!validEntry)
                        {
                            continue;
                        }

                        string filename  = Encoding.ASCII.GetString(entry.filename).Trim();
                        string extension = Encoding.ASCII.GetString(entry.extension).Trim();

                        // If user is != 0, append user to name to have identical filenames
                        if (user > 0)
                        {
                            filename = $"{user:X1}:{filename}";
                        }

                        if (!string.IsNullOrEmpty(extension))
                        {
                            filename = filename + "." + extension;
                        }

                        int entryNo = ((32 * entry.extentCounter) + entry.extentCounterHigh) / (_dpb.exm + 1);

                        // Do we have a stat for the file already?
                        if (_statCache.TryGetValue(filename, out FileEntryInfo fInfo))
                        {
                            _statCache.Remove(filename);
                        }
                        else
                        {
                            fInfo = new FileEntryInfo
                            {
                                Attributes = new FileAttributes()
                            }
                        };

                        // And any extent?
                        if (fileExtents.TryGetValue(filename, out Dictionary <int, List <ushort> > extentBlocks))
                        {
                            fileExtents.Remove(filename);
                        }
                        else
                        {
                            extentBlocks = new Dictionary <int, List <ushort> >();
                        }

                        // Do we already have this extent? Should never happen
                        if (extentBlocks.TryGetValue(entryNo, out List <ushort> blocks))
                        {
                            extentBlocks.Remove(entryNo);
                        }
                        else
                        {
                            blocks = new List <ushort>();
                        }

                        // Attributes
                        if (hidden)
                        {
                            fInfo.Attributes |= FileAttributes.Hidden;
                        }

                        if (rdOnly)
                        {
                            fInfo.Attributes |= FileAttributes.ReadOnly;
                        }

                        if (system)
                        {
                            fInfo.Attributes |= FileAttributes.System;
                        }

                        // Supposedly there is a value in the directory entry telling how many blocks are designated in
                        // this entry. However some implementations tend to do whatever they wish, but none will ever
                        // allocate block 0 for a file because that's where the directory resides.
                        // There is also a field telling how many bytes are used in the last block, but its meaning is
                        // non-standard so we must ignore it.
                        foreach (ushort blk in entry.allocations.Where(blk => !blocks.Contains(blk) && blk != 0))
                        {
                            blocks.Add(blk);
                        }

                        // Save the file
                        fInfo.UID = (ulong)user;
                        extentBlocks.Add(entryNo, blocks);
                        fileExtents.Add(filename, extentBlocks);
                        _statCache.Add(filename, fInfo);

                        // Add the file to the directory listing
                        if (!_dirList.Contains(filename))
                        {
                            _dirList.Add(filename);
                        }

                        // Count entries 3 by 3 for timestamps
                        switch (dirCnt % 3)
                        {
                        case 0:
                            file1 = filename;

                            break;

                        case 1:
                            file2 = filename;

                            break;

                        case 2:
                            file3 = filename;

                            break;
                        }

                        dirCnt++;
                    }
                    else
                    {
                        DirectoryEntry entry =
                            Marshal.ByteArrayToStructureLittleEndian <DirectoryEntry>(directory, dOff, 32);

                        bool hidden = (entry.statusUser & 0x80) == 0x80;
                        bool rdOnly = (entry.filename[0] & 0x80) == 0x80 || (entry.extension[0] & 0x80) == 0x80;
                        bool system = (entry.filename[1] & 0x80) == 0x80 || (entry.extension[2] & 0x80) == 0x80;

                        //bool backed = (entry.filename[3] & 0x80) == 0x80 || (entry.extension[3] & 0x80) == 0x80;
                        int user = entry.statusUser & 0x0F;

                        bool validEntry = true;

                        for (int i = 0; i < 8; i++)
                        {
                            entry.filename[i] &= 0x7F;
                            validEntry        &= entry.filename[i] >= 0x20;
                        }

                        for (int i = 0; i < 3; i++)
                        {
                            entry.extension[i] &= 0x7F;
                            validEntry         &= entry.extension[i] >= 0x20;
                        }

                        if (!validEntry)
                        {
                            continue;
                        }

                        string filename  = Encoding.ASCII.GetString(entry.filename).Trim();
                        string extension = Encoding.ASCII.GetString(entry.extension).Trim();

                        // If user is != 0, append user to name to have identical filenames
                        if (user > 0)
                        {
                            filename = $"{user:X1}:{filename}";
                        }

                        if (!string.IsNullOrEmpty(extension))
                        {
                            filename = filename + "." + extension;
                        }

                        int entryNo = ((32 * entry.extentCounterHigh) + entry.extentCounter) / (_dpb.exm + 1);

                        // Do we have a stat for the file already?
                        if (_statCache.TryGetValue(filename, out FileEntryInfo fInfo))
                        {
                            _statCache.Remove(filename);
                        }
                        else
                        {
                            fInfo = new FileEntryInfo
                            {
                                Attributes = new FileAttributes()
                            }
                        };

                        // And any extent?
                        if (fileExtents.TryGetValue(filename, out Dictionary <int, List <ushort> > extentBlocks))
                        {
                            fileExtents.Remove(filename);
                        }
                        else
                        {
                            extentBlocks = new Dictionary <int, List <ushort> >();
                        }

                        // Do we already have this extent? Should never happen
                        if (extentBlocks.TryGetValue(entryNo, out List <ushort> blocks))
                        {
                            extentBlocks.Remove(entryNo);
                        }
                        else
                        {
                            blocks = new List <ushort>();
                        }

                        // Attributes
                        if (hidden)
                        {
                            fInfo.Attributes |= FileAttributes.Hidden;
                        }

                        if (rdOnly)
                        {
                            fInfo.Attributes |= FileAttributes.ReadOnly;
                        }

                        if (system)
                        {
                            fInfo.Attributes |= FileAttributes.System;
                        }

                        // Supposedly there is a value in the directory entry telling how many blocks are designated in
                        // this entry. However some implementations tend to do whatever they wish, but none will ever
                        // allocate block 0 for a file because that's where the directory resides.
                        // There is also a field telling how many bytes are used in the last block, but its meaning is
                        // non-standard so we must ignore it.
                        foreach (ushort blk in entry.allocations.Where(blk => !blocks.Contains(blk) && blk != 0))
                        {
                            blocks.Add(blk);
                        }

                        // Save the file
                        fInfo.UID = (ulong)user;
                        extentBlocks.Add(entryNo, blocks);
                        fileExtents.Add(filename, extentBlocks);
                        _statCache.Add(filename, fInfo);

                        // Add the file to the directory listing
                        if (!_dirList.Contains(filename))
                        {
                            _dirList.Add(filename);
                        }

                        // Count entries 3 by 3 for timestamps
                        switch (dirCnt % 3)
                        {
                        case 0:
                            file1 = filename;

                            break;

                        case 1:
                            file2 = filename;

                            break;

                        case 2:
                            file3 = filename;

                            break;
                        }

                        dirCnt++;
                    }
                }

                // A password entry (or a file entry in PDOS, but this does not handle that case)
                else if ((directory[dOff] & 0x7F) >= 0x10 &&
                         (directory[dOff] & 0x7F) < 0x20)
                {
                    PasswordEntry entry = Marshal.ByteArrayToStructureLittleEndian <PasswordEntry>(directory, dOff, 32);

                    int user = entry.userNumber & 0x0F;

                    for (int i = 0; i < 8; i++)
                    {
                        entry.filename[i] &= 0x7F;
                    }

                    for (int i = 0; i < 3; i++)
                    {
                        entry.extension[i] &= 0x7F;
                    }

                    string filename  = Encoding.ASCII.GetString(entry.filename).Trim();
                    string extension = Encoding.ASCII.GetString(entry.extension).Trim();

                    // If user is != 0, append user to name to have identical filenames
                    if (user > 0)
                    {
                        filename = $"{user:X1}:{filename}";
                    }

                    if (!string.IsNullOrEmpty(extension))
                    {
                        filename = filename + "." + extension;
                    }

                    // Do not repeat passwords
                    if (_passwordCache.ContainsKey(filename))
                    {
                        _passwordCache.Remove(filename);
                    }

                    // Copy whole password entry
                    byte[] tmp = new byte[32];
                    Array.Copy(directory, dOff, tmp, 0, 32);
                    _passwordCache.Add(filename, tmp);

                    // Count entries 3 by 3 for timestamps
                    switch (dirCnt % 3)
                    {
                    case 0:
                        file1 = filename;

                        break;

                    case 1:
                        file2 = filename;

                        break;

                    case 2:
                        file3 = filename;

                        break;
                    }

                    dirCnt++;
                }

                // Volume label and password entry. Volume password is ignored.
                else
                {
                    switch (directory[dOff] & 0x7F)
                    {
                    case 0x20:
                        LabelEntry labelEntry =
                            Marshal.ByteArrayToStructureLittleEndian <LabelEntry>(directory, dOff, 32);

                        // The volume label defines if one of the fields in CP/M 3 timestamp is a creation or an
                        // access time
                        atime |= (labelEntry.flags & 0x40) == 0x40;

                        _label             = Encoding.ASCII.GetString(directory, dOff + 1, 11).Trim();
                        _labelCreationDate = new byte[4];
                        _labelUpdateDate   = new byte[4];
                        Array.Copy(directory, dOff + 24, _labelCreationDate, 0, 4);
                        Array.Copy(directory, dOff + 28, _labelUpdateDate, 0, 4);

                        // Count entries 3 by 3 for timestamps
                        switch (dirCnt % 3)
                        {
                        case 0:
                            file1 = null;

                            break;

                        case 1:
                            file2 = null;

                            break;

                        case 2:
                            file3 = null;

                            break;
                        }

                        dirCnt++;

                        break;

                    case 0x21:
                        if (directory[dOff + 10] == 0x00 &&
                            directory[dOff + 20] == 0x00 &&
                            directory[dOff + 30] == 0x00 &&
                            directory[dOff + 31] == 0x00)
                        {
                            DateEntry dateEntry =
                                Marshal.ByteArrayToStructureLittleEndian <DateEntry>(directory, dOff, 32);

                            FileEntryInfo fInfo;

                            // Entry contains timestamps for last 3 entries, whatever the kind they are.
                            if (!string.IsNullOrEmpty(file1))
                            {
                                if (_statCache.TryGetValue(file1, out fInfo))
                                {
                                    _statCache.Remove(file1);
                                }
                                else
                                {
                                    fInfo = new FileEntryInfo();
                                }

                                if (atime)
                                {
                                    fInfo.AccessTime = DateHandlers.CpmToDateTime(dateEntry.date1);
                                }
                                else
                                {
                                    fInfo.CreationTime = DateHandlers.CpmToDateTime(dateEntry.date1);
                                }

                                fInfo.LastWriteTime = DateHandlers.CpmToDateTime(dateEntry.date2);

                                _statCache.Add(file1, fInfo);
                            }

                            if (!string.IsNullOrEmpty(file2))
                            {
                                if (_statCache.TryGetValue(file2, out fInfo))
                                {
                                    _statCache.Remove(file2);
                                }
                                else
                                {
                                    fInfo = new FileEntryInfo();
                                }

                                if (atime)
                                {
                                    fInfo.AccessTime = DateHandlers.CpmToDateTime(dateEntry.date3);
                                }
                                else
                                {
                                    fInfo.CreationTime = DateHandlers.CpmToDateTime(dateEntry.date3);
                                }

                                fInfo.LastWriteTime = DateHandlers.CpmToDateTime(dateEntry.date4);

                                _statCache.Add(file2, fInfo);
                            }

                            if (!string.IsNullOrEmpty(file3))
                            {
                                if (_statCache.TryGetValue(file3, out fInfo))
                                {
                                    _statCache.Remove(file3);
                                }
                                else
                                {
                                    fInfo = new FileEntryInfo();
                                }

                                if (atime)
                                {
                                    fInfo.AccessTime = DateHandlers.CpmToDateTime(dateEntry.date5);
                                }
                                else
                                {
                                    fInfo.CreationTime = DateHandlers.CpmToDateTime(dateEntry.date5);
                                }

                                fInfo.LastWriteTime = DateHandlers.CpmToDateTime(dateEntry.date6);

                                _statCache.Add(file3, fInfo);
                            }

                            file1  = null;
                            file2  = null;
                            file3  = null;
                            dirCnt = 0;
                        }

                        // However, if this byte is 0, timestamp is in Z80DOS or DOS+ format
                        else if (directory[dOff + 1] == 0x00)
                        {
                            TrdPartyDateEntry trdPartyDateEntry =
                                Marshal.ByteArrayToStructureLittleEndian <TrdPartyDateEntry>(directory, dOff, 32);

                            FileEntryInfo fInfo;

                            // Entry contains timestamps for last 3 entries, whatever the kind they are.
                            if (!string.IsNullOrEmpty(file1))
                            {
                                if (_statCache.TryGetValue(file1, out fInfo))
                                {
                                    _statCache.Remove(file1);
                                }
                                else
                                {
                                    fInfo = new FileEntryInfo();
                                }

                                byte[] ctime = new byte[4];
                                ctime[0] = trdPartyDateEntry.create1[0];
                                ctime[1] = trdPartyDateEntry.create1[1];

                                fInfo.AccessTime    = DateHandlers.CpmToDateTime(trdPartyDateEntry.access1);
                                fInfo.CreationTime  = DateHandlers.CpmToDateTime(ctime);
                                fInfo.LastWriteTime = DateHandlers.CpmToDateTime(trdPartyDateEntry.modify1);

                                _statCache.Add(file1, fInfo);
                            }

                            if (!string.IsNullOrEmpty(file2))
                            {
                                if (_statCache.TryGetValue(file2, out fInfo))
                                {
                                    _statCache.Remove(file2);
                                }
                                else
                                {
                                    fInfo = new FileEntryInfo();
                                }

                                byte[] ctime = new byte[4];
                                ctime[0] = trdPartyDateEntry.create2[0];
                                ctime[1] = trdPartyDateEntry.create2[1];

                                fInfo.AccessTime    = DateHandlers.CpmToDateTime(trdPartyDateEntry.access2);
                                fInfo.CreationTime  = DateHandlers.CpmToDateTime(ctime);
                                fInfo.LastWriteTime = DateHandlers.CpmToDateTime(trdPartyDateEntry.modify2);

                                _statCache.Add(file2, fInfo);
                            }

                            if (!string.IsNullOrEmpty(file3))
                            {
                                if (_statCache.TryGetValue(file1, out fInfo))
                                {
                                    _statCache.Remove(file3);
                                }
                                else
                                {
                                    fInfo = new FileEntryInfo();
                                }

                                byte[] ctime = new byte[4];
                                ctime[0] = trdPartyDateEntry.create3[0];
                                ctime[1] = trdPartyDateEntry.create3[1];

                                fInfo.AccessTime    = DateHandlers.CpmToDateTime(trdPartyDateEntry.access3);
                                fInfo.CreationTime  = DateHandlers.CpmToDateTime(ctime);
                                fInfo.LastWriteTime = DateHandlers.CpmToDateTime(trdPartyDateEntry.modify3);

                                _statCache.Add(file3, fInfo);
                            }

                            file1  = null;
                            file2  = null;
                            file3  = null;
                            dirCnt = 0;
                        }

                        break;
                    }
                }
            }

            // Cache all files. As CP/M maximum volume size is 8 Mib
            // this should not be a problem
            AaruConsole.DebugWriteLine("CP/M Plugin", "Reading files.");
            long usedBlocks = 0;

            _fileCache = new Dictionary <string, byte[]>();

            foreach (string filename in _dirList)
            {
                var fileMs = new MemoryStream();

                if (_statCache.TryGetValue(filename, out FileEntryInfo fInfo))
                {
                    _statCache.Remove(filename);
                }

                fInfo.Blocks = 0;

                if (fileExtents.TryGetValue(filename, out Dictionary <int, List <ushort> > extents))
                {
                    for (int ex = 0; ex < extents.Count; ex++)
                    {
                        if (!extents.TryGetValue(ex, out List <ushort> alBlks))
                        {
                            continue;
                        }

                        foreach (ushort alBlk in alBlks)
                        {
                            allocationBlocks.TryGetValue(alBlk, out byte[] blk);
                            fileMs.Write(blk, 0, blk.Length);
                            fInfo.Blocks++;
                        }
                    }
                }

                // If you insist to call CP/M "extent based"
                fInfo.Attributes |= FileAttributes.Extents;
                fInfo.BlockSize   = blockSize;
                fInfo.Length      = fileMs.Length;
                _cpmStat.Files++;
                usedBlocks += fInfo.Blocks;

                _statCache.Add(filename, fInfo);
                _fileCache.Add(filename, fileMs.ToArray());
            }

            _decodedPasswordCache = new Dictionary <string, byte[]>();

            // For each stored password, store a decoded version of it
            if (_passwordCache.Count > 0)
            {
                foreach (KeyValuePair <string, byte[]> kvp in _passwordCache)
                {
                    byte[] tmp = new byte[8];
                    Array.Copy(kvp.Value, 16, tmp, 0, 8);

                    for (int t = 0; t < 8; t++)
                    {
                        tmp[t] ^= kvp.Value[13];
                    }

                    _decodedPasswordCache.Add(kvp.Key, tmp);
                }
            }

            // Generate statfs.
            _cpmStat.Blocks         = (ulong)(_dpb.dsm + 1);
            _cpmStat.FilenameLength = 11;
            _cpmStat.Files          = (ulong)_fileCache.Count;
            _cpmStat.FreeBlocks     = _cpmStat.Blocks - (ulong)usedBlocks;
            _cpmStat.PluginId       = Id;
            _cpmStat.Type           = "CP/M filesystem";

            // Generate XML info
            XmlFsType = new FileSystemType
            {
                Clusters              = _cpmStat.Blocks,
                ClusterSize           = (uint)blockSize,
                Files                 = (ulong)_fileCache.Count,
                FilesSpecified        = true,
                FreeClusters          = _cpmStat.FreeBlocks,
                FreeClustersSpecified = true,
                Type = "CP/M filesystem"
            };

            if (_labelCreationDate != null)
            {
                XmlFsType.CreationDate          = DateHandlers.CpmToDateTime(_labelCreationDate);
                XmlFsType.CreationDateSpecified = true;
            }

            if (_labelUpdateDate != null)
            {
                XmlFsType.ModificationDate          = DateHandlers.CpmToDateTime(_labelUpdateDate);
                XmlFsType.ModificationDateSpecified = true;
            }

            if (!string.IsNullOrEmpty(_label))
            {
                XmlFsType.VolumeName = _label;
            }

            _mounted = true;

            return(Errno.NoError);
        }
Ejemplo n.º 27
0
        public Errno Stat(string path, out FileEntryInfo stat)
        {
            stat = null;

            string[] pathElements = path.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
            if (pathElements.Length != 1)
            {
                return(Errno.NotSupported);
            }

            if (debug)
            {
                if (string.Compare(path, "$", StringComparison.InvariantCulture) == 0 ||
                    string.Compare(path, "$Boot", StringComparison.InvariantCulture) == 0)
                {
                    stat = new FileEntryInfo
                    {
                        Attributes = FileAttributes.System,
                        BlockSize  = device.Info.SectorSize * multiplier,
                        DeviceNo   = 0,
                        GID        = 0,
                        Inode      = 0,
                        Links      = 1,
                        Mode       = 0x124,
                        UID        = 0
                    };

                    if (string.Compare(path, "$", StringComparison.InvariantCulture) == 0)
                    {
                        stat.Blocks = catalogBlocks.Length / stat.BlockSize + catalogBlocks.Length % stat.BlockSize;
                        stat.Length = catalogBlocks.Length;
                    }
                    else
                    {
                        stat.Blocks = bootBlocks.Length / stat.BlockSize + catalogBlocks.Length % stat.BlockSize;
                        stat.Length = bootBlocks.Length;
                    }

                    return(Errno.NoError);
                }
            }

            Errno error = GetFileEntry(path, out PascalFileEntry entry);

            if (error != Errno.NoError)
            {
                return(error);
            }

            stat = new FileEntryInfo
            {
                Attributes       = FileAttributes.File,
                Blocks           = entry.LastBlock - entry.FirstBlock,
                BlockSize        = device.Info.SectorSize * multiplier,
                DeviceNo         = 0,
                GID              = 0,
                Inode            = 0,
                LastWriteTimeUtc = DateHandlers.UcsdPascalToDateTime(entry.ModificationTime),
                Length           = (entry.LastBlock - entry.FirstBlock) * device.Info.SectorSize * multiplier +
                                   entry.LastBytes,
                Links = 1,
                Mode  = 0x124,
                UID   = 0
            };

            return(Errno.NoError);
        }
Ejemplo n.º 28
0
        public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information,
                                   Encoding encoding)
        {
            Encoding = encoding ?? Encoding.GetEncoding("iso-8859-1");
            byte[]    rootBlockSector = imagePlugin.ReadSector(2 + partition.Start);
            RootBlock rootBlock       = Marshal.ByteArrayToStructureBigEndian <RootBlock>(rootBlockSector);

            StringBuilder sbInformation = new StringBuilder();

            XmlFsType = new FileSystemType();

            switch (rootBlock.diskType)
            {
            case AFS_DISK:
            case MUAF_DISK:
                sbInformation.Append("Professional File System v1");
                XmlFsType.Type = "PFS v1";
                break;

            case PFS2_DISK:
                sbInformation.Append("Professional File System v2");
                XmlFsType.Type = "PFS v2";
                break;

            case PFS_DISK:
            case MUPFS_DISK:
                sbInformation.Append("Professional File System v3");
                XmlFsType.Type = "PFS v3";
                break;
            }

            if (rootBlock.diskType == MUAF_DISK || rootBlock.diskType == MUPFS_DISK)
            {
                sbInformation.Append(", with multi-user support");
            }

            sbInformation.AppendLine();

            sbInformation.AppendFormat("Volume name: {0}", StringHandlers.PascalToString(rootBlock.diskname, Encoding))
            .AppendLine();
            sbInformation.AppendFormat("Volume has {0} free sectors of {1}", rootBlock.blocksfree, rootBlock.diskSize)
            .AppendLine();
            sbInformation.AppendFormat("Volume created on {0}",
                                       DateHandlers.AmigaToDateTime(rootBlock.creationday, rootBlock.creationminute,
                                                                    rootBlock.creationtick)).AppendLine();
            if (rootBlock.extension > 0)
            {
                sbInformation.AppendFormat("Root block extension resides at block {0}", rootBlock.extension)
                .AppendLine();
            }

            information = sbInformation.ToString();

            XmlFsType.CreationDate =
                DateHandlers.AmigaToDateTime(rootBlock.creationday, rootBlock.creationminute, rootBlock.creationtick);
            XmlFsType.CreationDateSpecified = true;
            XmlFsType.FreeClusters          = rootBlock.blocksfree;
            XmlFsType.FreeClustersSpecified = true;
            XmlFsType.Clusters    = rootBlock.diskSize;
            XmlFsType.ClusterSize = imagePlugin.Info.SectorSize;
            XmlFsType.VolumeName  = StringHandlers.PascalToString(rootBlock.diskname, Encoding);
        }
Ejemplo n.º 29
0
        public void Open(Stream stream)
        {
            stream.Seek(0, SeekOrigin.Begin);

            byte[] hdrB = new byte[26];
            stream.Read(hdrB, 0, 26);
            _header = Marshal.ByteArrayToStructureBigEndian <AppleSingleHeader>(hdrB);

            AppleSingleEntry[] entries = new AppleSingleEntry[_header.entries];

            for (int i = 0; i < _header.entries; i++)
            {
                byte[] entry = new byte[12];
                stream.Read(entry, 0, 12);
                entries[i] = Marshal.ByteArrayToStructureBigEndian <AppleSingleEntry>(entry);
            }

            _creationTime  = DateTime.UtcNow;
            _lastWriteTime = _creationTime;

            foreach (AppleSingleEntry entry in entries)
            {
                switch ((AppleSingleEntryID)entry.id)
                {
                case AppleSingleEntryID.DataFork:
                    _dataFork = entry;

                    break;

                case AppleSingleEntryID.FileDates:
                    stream.Seek(entry.offset, SeekOrigin.Begin);
                    byte[] datesB = new byte[16];
                    stream.Read(datesB, 0, 16);

                    AppleSingleFileDates dates =
                        Marshal.ByteArrayToStructureBigEndian <AppleSingleFileDates>(datesB);

                    _creationTime  = DateHandlers.MacToDateTime(dates.creationDate);
                    _lastWriteTime = DateHandlers.MacToDateTime(dates.modificationDate);

                    break;

                case AppleSingleEntryID.FileInfo:
                    stream.Seek(entry.offset, SeekOrigin.Begin);
                    byte[] finfo = new byte[entry.length];
                    stream.Read(finfo, 0, finfo.Length);

                    if (_macintoshHome.SequenceEqual(_header.homeFilesystem))
                    {
                        AppleSingleMacFileInfo macinfo =
                            Marshal.ByteArrayToStructureBigEndian <AppleSingleMacFileInfo>(finfo);

                        _creationTime  = DateHandlers.MacToDateTime(macinfo.creationDate);
                        _lastWriteTime = DateHandlers.MacToDateTime(macinfo.modificationDate);
                    }
                    else if (_proDosHome.SequenceEqual(_header.homeFilesystem))
                    {
                        AppleSingleProDOSFileInfo prodosinfo =
                            Marshal.ByteArrayToStructureBigEndian <AppleSingleProDOSFileInfo>(finfo);

                        _creationTime  = DateHandlers.MacToDateTime(prodosinfo.creationDate);
                        _lastWriteTime = DateHandlers.MacToDateTime(prodosinfo.modificationDate);
                    }
                    else if (_unixHome.SequenceEqual(_header.homeFilesystem))
                    {
                        AppleSingleUnixFileInfo unixinfo =
                            Marshal.ByteArrayToStructureBigEndian <AppleSingleUnixFileInfo>(finfo);

                        _creationTime  = DateHandlers.UnixUnsignedToDateTime(unixinfo.creationDate);
                        _lastWriteTime = DateHandlers.UnixUnsignedToDateTime(unixinfo.modificationDate);
                    }
                    else if (_dosHome.SequenceEqual(_header.homeFilesystem))
                    {
                        AppleSingleDOSFileInfo dosinfo =
                            Marshal.ByteArrayToStructureBigEndian <AppleSingleDOSFileInfo>(finfo);

                        _lastWriteTime =
                            DateHandlers.DosToDateTime(dosinfo.modificationDate, dosinfo.modificationTime);
                    }

                    break;

                case AppleSingleEntryID.ResourceFork:
                    _rsrcFork = entry;

                    break;
                }
            }

            stream.Seek(0, SeekOrigin.Begin);
            _opened   = true;
            _isStream = true;
            _stream   = stream;
        }
Ejemplo n.º 30
0
        // TODO: Decode native nvlist
        static bool DecodeNvList(byte[] nvlist, out Dictionary <string, NVS_Item> decodedNvList, bool xdr,
                                 bool littleEndian)
        {
            decodedNvList = new Dictionary <string, NVS_Item>();

            if (nvlist == null ||
                nvlist.Length < 16)
            {
                return(false);
            }

            if (!xdr)
            {
                return(false);
            }

            int offset = 8;

            while (offset < nvlist.Length)
            {
                var item    = new NVS_Item();
                int currOff = offset;

                item.encodedSize = BigEndianBitConverter.ToUInt32(nvlist, offset);

                // Finished
                if (item.encodedSize == 0)
                {
                    break;
                }

                offset          += 4;
                item.decodedSize = BigEndianBitConverter.ToUInt32(nvlist, offset);
                offset          += 4;
                uint nameLength = BigEndianBitConverter.ToUInt32(nvlist, offset);
                offset += 4;

                if (nameLength % 4 > 0)
                {
                    nameLength += 4 - (nameLength % 4);
                }

                byte[] nameBytes = new byte[nameLength];
                Array.Copy(nvlist, offset, nameBytes, 0, nameLength);
                item.name     = StringHandlers.CToString(nameBytes);
                offset       += (int)nameLength;
                item.dataType = (NVS_DataTypes)BigEndianBitConverter.ToUInt32(nvlist, offset);
                offset       += 4;
                item.elements = BigEndianBitConverter.ToUInt32(nvlist, offset);
                offset       += 4;

                if (item.elements == 0)
                {
                    decodedNvList.Add(item.name, item);

                    continue;
                }

                switch (item.dataType)
                {
                case NVS_DataTypes.DATA_TYPE_BOOLEAN:
                case NVS_DataTypes.DATA_TYPE_BOOLEAN_ARRAY:
                case NVS_DataTypes.DATA_TYPE_BOOLEAN_VALUE:
                    if (item.elements > 1)
                    {
                        bool[] boolArray = new bool[item.elements];

                        for (int i = 0; i < item.elements; i++)
                        {
                            uint temp = BigEndianBitConverter.ToUInt32(nvlist, offset);
                            boolArray[i] = temp > 0;
                            offset      += 4;
                        }

                        item.value = boolArray;
                    }
                    else
                    {
                        uint temp = BigEndianBitConverter.ToUInt32(nvlist, offset);
                        item.value = temp > 0;
                        offset    += 4;
                    }

                    break;

                case NVS_DataTypes.DATA_TYPE_BYTE:
                case NVS_DataTypes.DATA_TYPE_BYTE_ARRAY:
                case NVS_DataTypes.DATA_TYPE_UINT8:
                case NVS_DataTypes.DATA_TYPE_UINT8_ARRAY:
                    if (item.elements > 1)
                    {
                        byte[] byteArray = new byte[item.elements];
                        Array.Copy(nvlist, offset, byteArray, 0, item.elements);
                        offset += (int)item.elements;

                        if (item.elements % 4 > 0)
                        {
                            offset += 4 - (int)(item.elements % 4);
                        }

                        item.value = byteArray;
                    }
                    else
                    {
                        item.value = nvlist[offset];
                        offset    += 4;
                    }

                    break;

                case NVS_DataTypes.DATA_TYPE_DOUBLE:
                    if (item.elements > 1)
                    {
                        double[] doubleArray = new double[item.elements];

                        for (int i = 0; i < item.elements; i++)
                        {
                            double temp = BigEndianBitConverter.ToDouble(nvlist, offset);
                            doubleArray[i] = temp;
                            offset        += 8;
                        }

                        item.value = doubleArray;
                    }
                    else
                    {
                        item.value = BigEndianBitConverter.ToDouble(nvlist, offset);
                        offset    += 8;
                    }

                    break;

                case NVS_DataTypes.DATA_TYPE_HRTIME:
                    if (item.elements > 1)
                    {
                        DateTime[] hrtimeArray = new DateTime[item.elements];

                        for (int i = 0; i < item.elements; i++)
                        {
                            DateTime temp =
                                DateHandlers.UnixHrTimeToDateTime(BigEndianBitConverter.ToUInt64(nvlist, offset));

                            hrtimeArray[i] = temp;
                            offset        += 8;
                        }

                        item.value = hrtimeArray;
                    }
                    else
                    {
                        item.value =
                            DateHandlers.UnixHrTimeToDateTime(BigEndianBitConverter.ToUInt64(nvlist, offset));

                        offset += 8;
                    }

                    break;

                case NVS_DataTypes.DATA_TYPE_INT16:
                case NVS_DataTypes.DATA_TYPE_INT16_ARRAY:
                    if (item.elements > 1)
                    {
                        short[] shortArray = new short[item.elements];

                        for (int i = 0; i < item.elements; i++)
                        {
                            short temp = BigEndianBitConverter.ToInt16(nvlist, offset);
                            shortArray[i] = temp;
                            offset       += 4;
                        }

                        item.value = shortArray;
                    }
                    else
                    {
                        item.value = BigEndianBitConverter.ToInt16(nvlist, offset);
                        offset    += 4;
                    }

                    break;

                case NVS_DataTypes.DATA_TYPE_INT32:
                case NVS_DataTypes.DATA_TYPE_INT32_ARRAY:
                    if (item.elements > 1)
                    {
                        int[] intArray = new int[item.elements];

                        for (int i = 0; i < item.elements; i++)
                        {
                            int temp = BigEndianBitConverter.ToInt32(nvlist, offset);
                            intArray[i] = temp;
                            offset     += 4;
                        }

                        item.value = intArray;
                    }
                    else
                    {
                        item.value = BigEndianBitConverter.ToInt32(nvlist, offset);
                        offset    += 4;
                    }

                    break;

                case NVS_DataTypes.DATA_TYPE_INT64:
                case NVS_DataTypes.DATA_TYPE_INT64_ARRAY:
                    if (item.elements > 1)
                    {
                        long[] longArray = new long[item.elements];

                        for (int i = 0; i < item.elements; i++)
                        {
                            long temp = BigEndianBitConverter.ToInt64(nvlist, offset);
                            longArray[i] = temp;
                            offset      += 8;
                        }

                        item.value = longArray;
                    }
                    else
                    {
                        item.value = BigEndianBitConverter.ToInt64(nvlist, offset);
                        offset    += 8;
                    }

                    break;

                case NVS_DataTypes.DATA_TYPE_INT8:
                case NVS_DataTypes.DATA_TYPE_INT8_ARRAY:
                    if (item.elements > 1)
                    {
                        sbyte[] sbyteArray = new sbyte[item.elements];

                        for (int i = 0; i < item.elements; i++)
                        {
                            sbyte temp = (sbyte)nvlist[offset];
                            sbyteArray[i] = temp;
                            offset++;
                        }

                        item.value = sbyteArray;

                        if (sbyteArray.Length % 4 > 0)
                        {
                            offset += 4 - (sbyteArray.Length % 4);
                        }
                    }
                    else
                    {
                        item.value = BigEndianBitConverter.ToInt64(nvlist, offset);
                        offset    += 4;
                    }

                    break;

                case NVS_DataTypes.DATA_TYPE_STRING:
                case NVS_DataTypes.DATA_TYPE_STRING_ARRAY:
                    if (item.elements > 1)
                    {
                        string[] stringArray = new string[item.elements];

                        for (int i = 0; i < item.elements; i++)
                        {
                            uint strLength = BigEndianBitConverter.ToUInt32(nvlist, offset);
                            offset += 4;
                            byte[] strBytes = new byte[strLength];
                            Array.Copy(nvlist, offset, strBytes, 0, strLength);
                            stringArray[i] = StringHandlers.CToString(strBytes);
                            offset        += (int)strLength;

                            if (strLength % 4 > 0)
                            {
                                offset += 4 - (int)(strLength % 4);
                            }
                        }

                        item.value = stringArray;
                    }
                    else
                    {
                        uint strLength = BigEndianBitConverter.ToUInt32(nvlist, offset);
                        offset += 4;
                        byte[] strBytes = new byte[strLength];
                        Array.Copy(nvlist, offset, strBytes, 0, strLength);
                        item.value = StringHandlers.CToString(strBytes);
                        offset    += (int)strLength;

                        if (strLength % 4 > 0)
                        {
                            offset += 4 - (int)(strLength % 4);
                        }
                    }

                    break;

                case NVS_DataTypes.DATA_TYPE_UINT16:
                case NVS_DataTypes.DATA_TYPE_UINT16_ARRAY:
                    if (item.elements > 1)
                    {
                        ushort[] ushortArray = new ushort[item.elements];

                        for (int i = 0; i < item.elements; i++)
                        {
                            ushort temp = BigEndianBitConverter.ToUInt16(nvlist, offset);
                            ushortArray[i] = temp;
                            offset        += 4;
                        }

                        item.value = ushortArray;
                    }
                    else
                    {
                        item.value = BigEndianBitConverter.ToUInt16(nvlist, offset);
                        offset    += 4;
                    }

                    break;

                case NVS_DataTypes.DATA_TYPE_UINT32:
                case NVS_DataTypes.DATA_TYPE_UINT32_ARRAY:
                    if (item.elements > 1)
                    {
                        uint[] uintArray = new uint[item.elements];

                        for (int i = 0; i < item.elements; i++)
                        {
                            uint temp = BigEndianBitConverter.ToUInt32(nvlist, offset);
                            uintArray[i] = temp;
                            offset      += 4;
                        }

                        item.value = uintArray;
                    }
                    else
                    {
                        item.value = BigEndianBitConverter.ToUInt32(nvlist, offset);
                        offset    += 4;
                    }

                    break;

                case NVS_DataTypes.DATA_TYPE_UINT64:
                case NVS_DataTypes.DATA_TYPE_UINT64_ARRAY:
                    if (item.elements > 1)
                    {
                        ulong[] ulongArray = new ulong[item.elements];

                        for (int i = 0; i < item.elements; i++)
                        {
                            ulong temp = BigEndianBitConverter.ToUInt64(nvlist, offset);
                            ulongArray[i] = temp;
                            offset       += 8;
                        }

                        item.value = ulongArray;
                    }
                    else
                    {
                        item.value = BigEndianBitConverter.ToUInt64(nvlist, offset);
                        offset    += 8;
                    }

                    break;

                case NVS_DataTypes.DATA_TYPE_NVLIST:
                    if (item.elements > 1)
                    {
                        goto default;
                    }

                    byte[] subListBytes = new byte[item.encodedSize - (offset - currOff)];
                    Array.Copy(nvlist, offset, subListBytes, 0, subListBytes.Length);

                    if (DecodeNvList(subListBytes, out Dictionary <string, NVS_Item> subList, true, littleEndian))
                    {
                        item.value = subList;
                    }
                    else
                    {
                        goto default;
                    }

                    offset = (int)(currOff + item.encodedSize);

                    break;

                default:
                    byte[] unknown = new byte[item.encodedSize - (offset - currOff)];
                    Array.Copy(nvlist, offset, unknown, 0, unknown.Length);
                    item.value = unknown;
                    offset     = (int)(currOff + item.encodedSize);

                    break;
                }

                decodedNvList.Add(item.name, item);
            }

            return(decodedNvList.Count > 0);
        }