Exemple #1
0
        public void Open(string path)
        {
            // Prepend data fork name with "R."
            string ProDosAppleDouble;
            // Prepend data fork name with '%'
            string UNIXAppleDouble;
            // Change file extension to ADF
            string DOSAppleDouble;
            // Change file extension to adf
            string DOSAppleDoubleLower;
            // Store AppleDouble header file in ".AppleDouble" folder with same name
            string NetatalkAppleDouble;
            // Store AppleDouble header file in "resource.frk" folder with same name
            string DAVEAppleDouble;
            // Prepend data fork name with "._"
            string OSXAppleDouble;
            // Adds ".rsrc" extension
            string UnArAppleDouble;

            string filename      = Path.GetFileName(path);
            string filenameNoExt = Path.GetFileNameWithoutExtension(path);
            string parentFolder  = Path.GetDirectoryName(path);

            ProDosAppleDouble   = Path.Combine(parentFolder ?? throw new InvalidOperationException(), "R." + filename);
            UNIXAppleDouble     = Path.Combine(parentFolder, "%" + filename);
            DOSAppleDouble      = Path.Combine(parentFolder, filenameNoExt + ".ADF");
            DOSAppleDoubleLower = Path.Combine(parentFolder, filenameNoExt + ".adf");
            NetatalkAppleDouble = Path.Combine(parentFolder, ".AppleDouble",
                                               filename ?? throw new InvalidOperationException());
            DAVEAppleDouble = Path.Combine(parentFolder, "resource.frk", filename);
            OSXAppleDouble  = Path.Combine(parentFolder, "._" + filename);
            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 = BigEndianMarshal.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 = BigEndianMarshal.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 = BigEndianMarshal.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 = BigEndianMarshal.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 = BigEndianMarshal.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 = BigEndianMarshal.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 = BigEndianMarshal.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 = BigEndianMarshal.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 = BigEndianMarshal.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] = BigEndianMarshal.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 =
                        BigEndianMarshal.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 =
                            BigEndianMarshal.ByteArrayToStructureBigEndian <AppleDoubleMacFileInfo>(finfo);
                        creationTime  = DateHandlers.MacToDateTime(macinfo.creationDate);
                        lastWriteTime = DateHandlers.MacToDateTime(macinfo.modificationDate);
                    }
                    else if (ProDOSHome.SequenceEqual(header.homeFilesystem))
                    {
                        AppleDoubleProDOSFileInfo prodosinfo =
                            BigEndianMarshal.ByteArrayToStructureBigEndian <AppleDoubleProDOSFileInfo>(finfo);
                        creationTime  = DateHandlers.MacToDateTime(prodosinfo.creationDate);
                        lastWriteTime = DateHandlers.MacToDateTime(prodosinfo.modificationDate);
                    }
                    else if (UNIXHome.SequenceEqual(header.homeFilesystem))
                    {
                        AppleDoubleUNIXFileInfo unixinfo =
                            BigEndianMarshal.ByteArrayToStructureBigEndian <AppleDoubleUNIXFileInfo>(finfo);
                        creationTime  = DateHandlers.UnixUnsignedToDateTime(unixinfo.creationDate);
                        lastWriteTime = DateHandlers.UnixUnsignedToDateTime(unixinfo.modificationDate);
                    }
                    else if (DOSHome.SequenceEqual(header.homeFilesystem))
                    {
                        AppleDoubleDOSFileInfo dosinfo =
                            BigEndianMarshal.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;
        }
        public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information,
                                   Encoding encoding)
        {
            Encoding    = Encoding.BigEndianUnicode;
            information = "";

            HfsPlusVolumeHeader vh = new HfsPlusVolumeHeader();

            ulong hfspOffset;
            bool  wrapped;

            uint sectorsToRead = 0x800 / imagePlugin.Info.SectorSize;

            if (0x800 % imagePlugin.Info.SectorSize > 0)
            {
                sectorsToRead++;
            }

            byte[] vhSector = imagePlugin.ReadSectors(partition.Start, sectorsToRead);

            ushort drSigWord = BigEndianBitConverter.ToUInt16(vhSector, 0x400);

            if (drSigWord == HFS_MAGIC)                                      // "BD"
            {
                drSigWord = BigEndianBitConverter.ToUInt16(vhSector, 0x47C); // Read embedded HFS+ signature

                if (drSigWord == HFSP_MAGIC)                                 // "H+"
                {
                    ushort xdrStABNt = BigEndianBitConverter.ToUInt16(vhSector, 0x47E);

                    uint drAlBlkSiz = BigEndianBitConverter.ToUInt32(vhSector, 0x414);

                    ushort drAlBlSt = BigEndianBitConverter.ToUInt16(vhSector, 0x41C);

                    hfspOffset = (ulong)((drAlBlSt * 512 + xdrStABNt * drAlBlkSiz) / imagePlugin.Info.SectorSize);
                    wrapped    = true;
                }
                else
                {
                    hfspOffset = 0;
                    wrapped    = false;
                }
            }
            else
            {
                hfspOffset = 0;
                wrapped    = false;
            }

            vhSector = imagePlugin.ReadSectors(partition.Start + hfspOffset, sectorsToRead); // Read volume header

            vh.signature = BigEndianBitConverter.ToUInt16(vhSector, 0x400);

            if (vh.signature != HFSP_MAGIC && vh.signature != HFSX_MAGIC)
            {
                return;
            }

            StringBuilder sb = new StringBuilder();

            if (vh.signature == 0x482B)
            {
                sb.AppendLine("HFS+ filesystem.");
            }
            if (vh.signature == 0x4858)
            {
                sb.AppendLine("HFSX filesystem.");
            }
            if (wrapped)
            {
                sb.AppendLine("Volume is wrapped inside an HFS volume.");
            }

            byte[] tmp = new byte[0x400];
            Array.Copy(vhSector, 0x400, tmp, 0, 0x400);
            vhSector = tmp;

            vh = Marshal.ByteArrayToStructureBigEndian <HfsPlusVolumeHeader>(vhSector);

            if (vh.version == 4 || vh.version == 5)
            {
                sb.AppendFormat("Filesystem version is {0}.", vh.version).AppendLine();

                if ((vh.attributes & 0x80) == 0x80)
                {
                    sb.AppendLine("Volume is locked on hardware.");
                }
                if ((vh.attributes & 0x100) == 0x100)
                {
                    sb.AppendLine("Volume is unmounted.");
                }
                if ((vh.attributes & 0x200) == 0x200)
                {
                    sb.AppendLine("There are bad blocks in the extents file.");
                }
                if ((vh.attributes & 0x400) == 0x400)
                {
                    sb.AppendLine("Volume does not require cache.");
                }
                if ((vh.attributes & 0x800) == 0x800)
                {
                    sb.AppendLine("Volume state is inconsistent.");
                }
                if ((vh.attributes & 0x1000) == 0x1000)
                {
                    sb.AppendLine("CNIDs are reused.");
                }
                if ((vh.attributes & 0x2000) == 0x2000)
                {
                    sb.AppendLine("Volume is journaled.");
                }
                if ((vh.attributes & 0x8000) == 0x8000)
                {
                    sb.AppendLine("Volume is locked on software.");
                }

                sb.AppendFormat("Implementation that last mounted the volume: \"{0}\".",
                                Encoding.ASCII.GetString(vh.lastMountedVersion)).AppendLine();
                if ((vh.attributes & 0x2000) == 0x2000)
                {
                    sb.AppendFormat("Journal starts at allocation block {0}.", vh.journalInfoBlock).AppendLine();
                }
                sb.AppendFormat("Creation date: {0}", DateHandlers.MacToDateTime(vh.createDate)).AppendLine();
                sb.AppendFormat("Last modification date: {0}", DateHandlers.MacToDateTime(vh.modifyDate)).AppendLine();
                if (vh.backupDate > 0)
                {
                    sb.AppendFormat("Last backup date: {0}", DateHandlers.MacToDateTime(vh.backupDate)).AppendLine();
                }
                else
                {
                    sb.AppendLine("Volume has never been backed up");
                }
                if (vh.backupDate > 0)
                {
                    sb.AppendFormat("Last check date: {0}", DateHandlers.MacToDateTime(vh.checkedDate)).AppendLine();
                }
                else
                {
                    sb.AppendLine("Volume has never been checked up");
                }
                sb.AppendFormat("{0} files on volume.", vh.fileCount).AppendLine();
                sb.AppendFormat("{0} folders on volume.", vh.folderCount).AppendLine();
                sb.AppendFormat("{0} bytes per allocation block.", vh.blockSize).AppendLine();
                sb.AppendFormat("{0} allocation blocks.", vh.totalBlocks).AppendLine();
                sb.AppendFormat("{0} free blocks.", vh.freeBlocks).AppendLine();
                sb.AppendFormat("Next allocation block: {0}.", vh.nextAllocation).AppendLine();
                sb.AppendFormat("Resource fork clump size: {0} bytes.", vh.rsrcClumpSize).AppendLine();
                sb.AppendFormat("Data fork clump size: {0} bytes.", vh.dataClumpSize).AppendLine();
                sb.AppendFormat("Next unused CNID: {0}.", vh.nextCatalogID).AppendLine();
                sb.AppendFormat("Volume has been mounted writable {0} times.", vh.writeCount).AppendLine();
                sb.AppendFormat("Allocation File is {0} bytes.", vh.allocationFile_logicalSize).AppendLine();
                sb.AppendFormat("Extents File is {0} bytes.", vh.extentsFile_logicalSize).AppendLine();
                sb.AppendFormat("Catalog File is {0} bytes.", vh.catalogFile_logicalSize).AppendLine();
                sb.AppendFormat("Attributes File is {0} bytes.", vh.attributesFile_logicalSize).AppendLine();
                sb.AppendFormat("Startup File is {0} bytes.", vh.startupFile_logicalSize).AppendLine();
                sb.AppendLine("Finder info:");
                sb.AppendFormat("CNID of bootable system's directory: {0}", vh.drFndrInfo0).AppendLine();
                sb.AppendFormat("CNID of first-run application's directory: {0}", vh.drFndrInfo1).AppendLine();
                sb.AppendFormat("CNID of previously opened directory: {0}", vh.drFndrInfo2).AppendLine();
                sb.AppendFormat("CNID of bootable Mac OS 8 or 9 directory: {0}", vh.drFndrInfo3).AppendLine();
                sb.AppendFormat("CNID of bootable Mac OS X directory: {0}", vh.drFndrInfo5).AppendLine();
                if (vh.drFndrInfo6 != 0 && vh.drFndrInfo7 != 0)
                {
                    sb.AppendFormat("Mac OS X Volume ID: {0:X8}{1:X8}", vh.drFndrInfo6, vh.drFndrInfo7).AppendLine();
                }

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

                XmlFsType.Bootable   |= vh.drFndrInfo0 != 0 || vh.drFndrInfo3 != 0 || vh.drFndrInfo5 != 0;
                XmlFsType.Clusters    = vh.totalBlocks;
                XmlFsType.ClusterSize = vh.blockSize;
                if (vh.createDate > 0)
                {
                    XmlFsType.CreationDate          = DateHandlers.MacToDateTime(vh.createDate);
                    XmlFsType.CreationDateSpecified = true;
                }

                XmlFsType.Dirty                 = (vh.attributes & 0x100) != 0x100;
                XmlFsType.Files                 = vh.fileCount;
                XmlFsType.FilesSpecified        = true;
                XmlFsType.FreeClusters          = vh.freeBlocks;
                XmlFsType.FreeClustersSpecified = true;
                if (vh.modifyDate > 0)
                {
                    XmlFsType.ModificationDate          = DateHandlers.MacToDateTime(vh.modifyDate);
                    XmlFsType.ModificationDateSpecified = true;
                }

                if (vh.signature == 0x482B)
                {
                    XmlFsType.Type = "HFS+";
                }
                if (vh.signature == 0x4858)
                {
                    XmlFsType.Type = "HFSX";
                }
                if (vh.drFndrInfo6 != 0 && vh.drFndrInfo7 != 0)
                {
                    XmlFsType.VolumeSerial = $"{vh.drFndrInfo6:X8}{vh.drFndrInfo7:X8}";
                }
                XmlFsType.SystemIdentifier = Encoding.ASCII.GetString(vh.lastMountedVersion);
            }
            else
            {
                sb.AppendFormat("Filesystem version is {0}.", vh.version).AppendLine();
                sb.AppendLine("This version is not supported yet.");
            }

            information = sb.ToString();
        }
Exemple #3
0
        public void Open(string path)
        {
            FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read);

            fs.Seek(0, SeekOrigin.Begin);

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

            AppleSingleEntry[] entries = new AppleSingleEntry[header.entries];
            for (int i = 0; i < header.entries; i++)
            {
                byte[] entry = new byte[12];
                fs.Read(entry, 0, 12);
                entries[i] = BigEndianMarshal.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:
                    fs.Seek(entry.offset, SeekOrigin.Begin);
                    byte[] dates_b = new byte[16];
                    fs.Read(dates_b, 0, 16);
                    AppleSingleFileDates dates =
                        BigEndianMarshal.ByteArrayToStructureBigEndian <AppleSingleFileDates>(dates_b);
                    creationTime  = DateHandlers.MacToDateTime(dates.creationDate);
                    lastWriteTime = DateHandlers.MacToDateTime(dates.modificationDate);
                    break;

                case AppleSingleEntryID.FileInfo:
                    fs.Seek(entry.offset, SeekOrigin.Begin);
                    byte[] finfo = new byte[entry.length];
                    fs.Read(finfo, 0, finfo.Length);
                    if (MacintoshHome.SequenceEqual(header.homeFilesystem))
                    {
                        AppleSingleMacFileInfo macinfo =
                            BigEndianMarshal.ByteArrayToStructureBigEndian <AppleSingleMacFileInfo>(finfo);
                        creationTime  = DateHandlers.MacToDateTime(macinfo.creationDate);
                        lastWriteTime = DateHandlers.MacToDateTime(macinfo.modificationDate);
                    }
                    else if (ProDOSHome.SequenceEqual(header.homeFilesystem))
                    {
                        AppleSingleProDOSFileInfo prodosinfo =
                            BigEndianMarshal.ByteArrayToStructureBigEndian <AppleSingleProDOSFileInfo>(finfo);
                        creationTime  = DateHandlers.MacToDateTime(prodosinfo.creationDate);
                        lastWriteTime = DateHandlers.MacToDateTime(prodosinfo.modificationDate);
                    }
                    else if (UNIXHome.SequenceEqual(header.homeFilesystem))
                    {
                        AppleSingleUNIXFileInfo unixinfo =
                            BigEndianMarshal.ByteArrayToStructureBigEndian <AppleSingleUNIXFileInfo>(finfo);
                        creationTime  = DateHandlers.UnixUnsignedToDateTime(unixinfo.creationDate);
                        lastWriteTime = DateHandlers.UnixUnsignedToDateTime(unixinfo.modificationDate);
                    }
                    else if (DOSHome.SequenceEqual(header.homeFilesystem))
                    {
                        AppleSingleDOSFileInfo dosinfo =
                            BigEndianMarshal.ByteArrayToStructureBigEndian <AppleSingleDOSFileInfo>(finfo);
                        lastWriteTime =
                            DateHandlers.DosToDateTime(dosinfo.modificationDate, dosinfo.modificationTime);
                    }
                    break;

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

            fs.Close();
            opened   = true;
            isPath   = true;
            basePath = path;
        }
Exemple #4
0
        public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information,
                                   Encoding encoding)
        {
            Encoding    = encoding ?? new MacRoman();
            information = "";

            StringBuilder sb = new StringBuilder();

            MFS_MasterDirectoryBlock MDB = new MFS_MasterDirectoryBlock();
            MFS_BootBlock            BB  = new MFS_BootBlock();

            byte[] pString = new byte[16];

            byte[] mdbSector = imagePlugin.ReadSector(2 + partition.Start);
            byte[] bbSector  = imagePlugin.ReadSector(0 + partition.Start);

            BigEndianBitConverter.IsLittleEndian = BitConverter.IsLittleEndian;

            MDB.drSigWord = BigEndianBitConverter.ToUInt16(mdbSector, 0x000);
            if (MDB.drSigWord != MFS_MAGIC)
            {
                return;
            }

            MDB.drCrDate   = BigEndianBitConverter.ToUInt32(mdbSector, 0x002);
            MDB.drLsBkUp   = BigEndianBitConverter.ToUInt32(mdbSector, 0x006);
            MDB.drAtrb     = BigEndianBitConverter.ToUInt16(mdbSector, 0x00A);
            MDB.drNmFls    = BigEndianBitConverter.ToUInt16(mdbSector, 0x00C);
            MDB.drDirSt    = BigEndianBitConverter.ToUInt16(mdbSector, 0x00E);
            MDB.drBlLen    = BigEndianBitConverter.ToUInt16(mdbSector, 0x010);
            MDB.drNmAlBlks = BigEndianBitConverter.ToUInt16(mdbSector, 0x012);
            MDB.drAlBlkSiz = BigEndianBitConverter.ToUInt32(mdbSector, 0x014);
            MDB.drClpSiz   = BigEndianBitConverter.ToUInt32(mdbSector, 0x018);
            MDB.drAlBlSt   = BigEndianBitConverter.ToUInt16(mdbSector, 0x01C);
            MDB.drNxtFNum  = BigEndianBitConverter.ToUInt32(mdbSector, 0x01E);
            MDB.drFreeBks  = BigEndianBitConverter.ToUInt16(mdbSector, 0x022);
            MDB.drVNSiz    = mdbSector[0x024];
            byte[] variableSize = new byte[MDB.drVNSiz + 1];
            Array.Copy(mdbSector, 0x024, variableSize, 0, MDB.drVNSiz + 1);
            MDB.drVN = StringHandlers.PascalToString(variableSize, Encoding);

            BB.signature = BigEndianBitConverter.ToUInt16(bbSector, 0x000);

            if (BB.signature == MFSBB_MAGIC)
            {
                BB.branch       = BigEndianBitConverter.ToUInt32(bbSector, 0x002);
                BB.boot_flags   = bbSector[0x006];
                BB.boot_version = bbSector[0x007];

                BB.sec_sv_pages = BigEndianBitConverter.ToInt16(bbSector, 0x008);

                Array.Copy(mdbSector, 0x00A, pString, 0, 16);
                BB.system_name = StringHandlers.PascalToString(pString, Encoding);
                Array.Copy(mdbSector, 0x01A, pString, 0, 16);
                BB.finder_name = StringHandlers.PascalToString(pString, Encoding);
                Array.Copy(mdbSector, 0x02A, pString, 0, 16);
                BB.debug_name = StringHandlers.PascalToString(pString, Encoding);
                Array.Copy(mdbSector, 0x03A, pString, 0, 16);
                BB.disasm_name = StringHandlers.PascalToString(pString, Encoding);
                Array.Copy(mdbSector, 0x04A, pString, 0, 16);
                BB.stupscr_name = StringHandlers.PascalToString(pString, Encoding);
                Array.Copy(mdbSector, 0x05A, pString, 0, 16);
                BB.bootup_name = StringHandlers.PascalToString(pString, Encoding);
                Array.Copy(mdbSector, 0x06A, pString, 0, 16);
                BB.clipbrd_name = StringHandlers.PascalToString(pString, Encoding);

                BB.max_files  = BigEndianBitConverter.ToUInt16(bbSector, 0x07A);
                BB.queue_size = BigEndianBitConverter.ToUInt16(bbSector, 0x07C);
                BB.heap_128k  = BigEndianBitConverter.ToUInt32(bbSector, 0x07E);
                BB.heap_256k  = BigEndianBitConverter.ToUInt32(bbSector, 0x082);
                BB.heap_512k  = BigEndianBitConverter.ToUInt32(bbSector, 0x086);
            }
            else
            {
                BB.signature = 0x0000;
            }

            sb.AppendLine("Apple Macintosh File System");
            sb.AppendLine();
            sb.AppendLine("Master Directory Block:");
            sb.AppendFormat("Creation date: {0}", DateHandlers.MacToDateTime(MDB.drCrDate)).AppendLine();
            sb.AppendFormat("Last backup date: {0}", DateHandlers.MacToDateTime(MDB.drLsBkUp)).AppendLine();
            if ((MDB.drAtrb & 0x80) == 0x80)
            {
                sb.AppendLine("Volume is locked by hardware.");
            }
            if ((MDB.drAtrb & 0x8000) == 0x8000)
            {
                sb.AppendLine("Volume is locked by software.");
            }
            sb.AppendFormat("{0} files on volume", MDB.drNmFls).AppendLine();
            sb.AppendFormat("First directory sector: {0}", MDB.drDirSt).AppendLine();
            sb.AppendFormat("{0} sectors in directory.", MDB.drBlLen).AppendLine();
            sb.AppendFormat("{0} volume allocation blocks.", MDB.drNmAlBlks + 1).AppendLine();
            sb.AppendFormat("Size of allocation blocks: {0} bytes", MDB.drAlBlkSiz).AppendLine();
            sb.AppendFormat("{0} bytes to allocate.", MDB.drClpSiz).AppendLine();
            sb.AppendFormat("First allocation block (#2) starts in sector {0}.", MDB.drAlBlSt).AppendLine();
            sb.AppendFormat("Next unused file number: {0}", MDB.drNxtFNum).AppendLine();
            sb.AppendFormat("{0} unused allocation blocks.", MDB.drFreeBks).AppendLine();
            sb.AppendFormat("Volume name: {0}", MDB.drVN).AppendLine();

            if (BB.signature == MFSBB_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.sec_sv_pages > 0)
                    {
                        sb.AppendLine("Allocate secondary sound buffer at boot.");
                    }
                    else if (BB.sec_sv_pages < 0)
                    {
                        sb.AppendLine("Allocate secondary sound and video buffers at boot.");
                    }

                    sb.AppendFormat("System filename: {0}", BB.system_name).AppendLine();
                    sb.AppendFormat("Finder filename: {0}", BB.finder_name).AppendLine();
                    sb.AppendFormat("Debugger filename: {0}", BB.debug_name).AppendLine();
                    sb.AppendFormat("Disassembler filename: {0}", BB.disasm_name).AppendLine();
                    sb.AppendFormat("Startup screen filename: {0}", BB.stupscr_name).AppendLine();
                    sb.AppendFormat("First program to execute at boot: {0}", BB.bootup_name).AppendLine();
                    sb.AppendFormat("Clipboard filename: {0}", BB.clipbrd_name).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
            {
                sb.AppendLine("Volume is not bootable.");
            }

            information = sb.ToString();

            XmlFsType = new FileSystemType();
            if (MDB.drLsBkUp > 0)
            {
                XmlFsType.BackupDate          = DateHandlers.MacToDateTime(MDB.drLsBkUp);
                XmlFsType.BackupDateSpecified = true;
            }
            XmlFsType.Bootable    = BB.signature == MFSBB_MAGIC;
            XmlFsType.Clusters    = MDB.drNmAlBlks;
            XmlFsType.ClusterSize = (int)MDB.drAlBlkSiz;
            if (MDB.drCrDate > 0)
            {
                XmlFsType.CreationDate          = DateHandlers.MacToDateTime(MDB.drCrDate);
                XmlFsType.CreationDateSpecified = true;
            }
            XmlFsType.Files                 = MDB.drNmFls;
            XmlFsType.FilesSpecified        = true;
            XmlFsType.FreeClusters          = MDB.drFreeBks;
            XmlFsType.FreeClustersSpecified = true;
            XmlFsType.Type       = "MFS";
            XmlFsType.VolumeName = MDB.drVN;
        }
Exemple #5
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;
                }
            }

            HFS_MasterDirectoryBlock MDB =
                BigEndianMarshal.ByteArrayToStructureBigEndian <HFS_MasterDirectoryBlock>(mdbSector);
            HFS_BootBlock BB = BigEndianMarshal.ByteArrayToStructureBigEndian <HFS_BootBlock>(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}";
            }
        }
Exemple #6
0
        bool FillDirectory()
        {
            idToFilename = new Dictionary <uint, string>();
            idToEntry    = new Dictionary <uint, MFS_FileEntry>();
            filenameToId = new Dictionary <string, uint>();

            int offset = 0;

            while (offset + 51 < directoryBlocks.Length)
            {
                MFS_FileEntry entry = new MFS_FileEntry
                {
                    flUsrWds = new byte[16],
                    flFlags  = (MFS_FileFlags)directoryBlocks[offset + 0]
                };

                if (!entry.flFlags.HasFlag(MFS_FileFlags.Used))
                {
                    break;
                }

                entry.flTyp = directoryBlocks[offset + 1];
                Array.Copy(directoryBlocks, offset + 2, entry.flUsrWds, 0, 16);
                entry.flFlNum  = BigEndianBitConverter.ToUInt32(directoryBlocks, offset + 18);
                entry.flStBlk  = BigEndianBitConverter.ToUInt16(directoryBlocks, offset + 22);
                entry.flLgLen  = BigEndianBitConverter.ToUInt32(directoryBlocks, offset + 24);
                entry.flPyLen  = BigEndianBitConverter.ToUInt32(directoryBlocks, offset + 28);
                entry.flRStBlk = BigEndianBitConverter.ToUInt16(directoryBlocks, offset + 32);
                entry.flRLgLen = BigEndianBitConverter.ToUInt32(directoryBlocks, offset + 34);
                entry.flRPyLen = BigEndianBitConverter.ToUInt32(directoryBlocks, offset + 38);
                entry.flCrDat  = BigEndianBitConverter.ToUInt32(directoryBlocks, offset + 42);
                entry.flMdDat  = BigEndianBitConverter.ToUInt32(directoryBlocks, offset + 46);
                entry.flNam    = new byte[directoryBlocks[offset + 50] + 1];
                Array.Copy(directoryBlocks, offset + 50, entry.flNam, 0, entry.flNam.Length);
                string lowerFilename = StringHandlers
                                       .PascalToString(entry.flNam, Encoding).ToLowerInvariant().Replace('/', ':');

                if (entry.flFlags.HasFlag(MFS_FileFlags.Used) && !idToFilename.ContainsKey(entry.flFlNum) &&
                    !idToEntry.ContainsKey(entry.flFlNum) && !filenameToId.ContainsKey(lowerFilename) &&
                    entry.flFlNum > 0)
                {
                    idToEntry.Add(entry.flFlNum, entry);
                    idToFilename.Add(entry.flFlNum,
                                     StringHandlers.PascalToString(entry.flNam, Encoding).Replace('/', ':'));
                    filenameToId.Add(lowerFilename, entry.flFlNum);

                    DicConsole.DebugWriteLine("DEBUG (AppleMFS plugin)", "entry.flFlags = {0}", entry.flFlags);
                    DicConsole.DebugWriteLine("DEBUG (AppleMFS plugin)", "entry.flTyp = {0}", entry.flTyp);
                    DicConsole.DebugWriteLine("DEBUG (AppleMFS plugin)", "entry.flFlNum = {0}", entry.flFlNum);
                    DicConsole.DebugWriteLine("DEBUG (AppleMFS plugin)", "entry.flStBlk = {0}", entry.flStBlk);
                    DicConsole.DebugWriteLine("DEBUG (AppleMFS plugin)", "entry.flLgLen = {0}", entry.flLgLen);
                    DicConsole.DebugWriteLine("DEBUG (AppleMFS plugin)", "entry.flPyLen = {0}", entry.flPyLen);
                    DicConsole.DebugWriteLine("DEBUG (AppleMFS plugin)", "entry.flRStBlk = {0}", entry.flRStBlk);
                    DicConsole.DebugWriteLine("DEBUG (AppleMFS plugin)", "entry.flRLgLen = {0}", entry.flRLgLen);
                    DicConsole.DebugWriteLine("DEBUG (AppleMFS plugin)", "entry.flRPyLen = {0}", entry.flRPyLen);
                    DicConsole.DebugWriteLine("DEBUG (AppleMFS plugin)", "entry.flCrDat = {0}",
                                              DateHandlers.MacToDateTime(entry.flCrDat));
                    DicConsole.DebugWriteLine("DEBUG (AppleMFS plugin)", "entry.flMdDat = {0}",
                                              DateHandlers.MacToDateTime(entry.flMdDat));
                    DicConsole.DebugWriteLine("DEBUG (AppleMFS plugin)", "entry.flNam0 = {0}",
                                              StringHandlers.PascalToString(entry.flNam, Encoding));
                }

                offset += 50 + entry.flNam.Length;

                // "Entries are always an integral number of words"
                if (offset % 2 != 0)
                {
                    offset++;
                }

                // TODO: "Entries don't cross logical block boundaries"
            }

            return(true);
        }
Exemple #7
0
        public Errno Mount(IMediaImage imagePlugin, Partition partition, Encoding encoding,
                           Dictionary <string, string> options, string @namespace)
        {
            _device         = imagePlugin;
            _partitionStart = partition.Start;
            Encoding        = encoding ?? Encoding.GetEncoding("macintosh");

            options ??= GetDefaultOptions();

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

            _volMdb = new MasterDirectoryBlock();

            _mdbBlocks  = _device.ReadSector(2 + _partitionStart);
            _bootBlocks = _device.ReadSector(0 + _partitionStart);

            _volMdb.drSigWord = BigEndianBitConverter.ToUInt16(_mdbBlocks, 0x000);

            if (_volMdb.drSigWord != MFS_MAGIC)
            {
                return(Errno.InvalidArgument);
            }

            _volMdb.drCrDate   = BigEndianBitConverter.ToUInt32(_mdbBlocks, 0x002);
            _volMdb.drLsBkUp   = BigEndianBitConverter.ToUInt32(_mdbBlocks, 0x006);
            _volMdb.drAtrb     = (AppleCommon.VolumeAttributes)BigEndianBitConverter.ToUInt16(_mdbBlocks, 0x00A);
            _volMdb.drNmFls    = BigEndianBitConverter.ToUInt16(_mdbBlocks, 0x00C);
            _volMdb.drDirSt    = BigEndianBitConverter.ToUInt16(_mdbBlocks, 0x00E);
            _volMdb.drBlLen    = BigEndianBitConverter.ToUInt16(_mdbBlocks, 0x010);
            _volMdb.drNmAlBlks = BigEndianBitConverter.ToUInt16(_mdbBlocks, 0x012);
            _volMdb.drAlBlkSiz = BigEndianBitConverter.ToUInt32(_mdbBlocks, 0x014);
            _volMdb.drClpSiz   = BigEndianBitConverter.ToUInt32(_mdbBlocks, 0x018);
            _volMdb.drAlBlSt   = BigEndianBitConverter.ToUInt16(_mdbBlocks, 0x01C);
            _volMdb.drNxtFNum  = BigEndianBitConverter.ToUInt32(_mdbBlocks, 0x01E);
            _volMdb.drFreeBks  = BigEndianBitConverter.ToUInt16(_mdbBlocks, 0x022);
            _volMdb.drVNSiz    = _mdbBlocks[0x024];
            byte[] variableSize = new byte[_volMdb.drVNSiz + 1];
            Array.Copy(_mdbBlocks, 0x024, variableSize, 0, _volMdb.drVNSiz + 1);
            _volMdb.drVN = StringHandlers.PascalToString(variableSize, Encoding);

            _directoryBlocks = _device.ReadSectors(_volMdb.drDirSt + _partitionStart, _volMdb.drBlLen);
            int bytesInBlockMap = ((_volMdb.drNmAlBlks * 12) / 8) + ((_volMdb.drNmAlBlks * 12) % 8);
            int bytesInWholeMdb = bytesInBlockMap + BYTES_BEFORE_BLOCK_MAP;

            int sectorsInWholeMdb = (bytesInWholeMdb / (int)_device.Info.SectorSize) +
                                    (bytesInWholeMdb % (int)_device.Info.SectorSize);

            byte[] wholeMdb = _device.ReadSectors(_partitionStart + 2, (uint)sectorsInWholeMdb);
            _blockMapBytes = new byte[bytesInBlockMap];
            Array.Copy(wholeMdb, BYTES_BEFORE_BLOCK_MAP, _blockMapBytes, 0, _blockMapBytes.Length);

            int offset = 0;

            _blockMap = new uint[_volMdb.drNmAlBlks + 2 + 1];

            for (int i = 2; i < _volMdb.drNmAlBlks + 2; i += 8)
            {
                uint tmp1 = 0;
                uint tmp2 = 0;
                uint tmp3 = 0;

                if (offset + 4 <= _blockMapBytes.Length)
                {
                    tmp1 = BigEndianBitConverter.ToUInt32(_blockMapBytes, offset);
                }

                if (offset + 4 + 4 <= _blockMapBytes.Length)
                {
                    tmp2 = BigEndianBitConverter.ToUInt32(_blockMapBytes, offset + 4);
                }

                if (offset + 8 + 4 <= _blockMapBytes.Length)
                {
                    tmp3 = BigEndianBitConverter.ToUInt32(_blockMapBytes, offset + 8);
                }

                if (i < _blockMap.Length)
                {
                    _blockMap[i] = (tmp1 & 0xFFF00000) >> 20;
                }

                if (i + 2 < _blockMap.Length)
                {
                    _blockMap[i + 1] = (tmp1 & 0xFFF00) >> 8;
                }

                if (i + 3 < _blockMap.Length)
                {
                    _blockMap[i + 2] = ((tmp1 & 0xFF) << 4) + ((tmp2 & 0xF0000000) >> 28);
                }

                if (i + 4 < _blockMap.Length)
                {
                    _blockMap[i + 3] = (tmp2 & 0xFFF0000) >> 16;
                }

                if (i + 5 < _blockMap.Length)
                {
                    _blockMap[i + 4] = (tmp2 & 0xFFF0) >> 4;
                }

                if (i + 6 < _blockMap.Length)
                {
                    _blockMap[i + 5] = ((tmp2 & 0xF) << 8) + ((tmp3 & 0xFF000000) >> 24);
                }

                if (i + 7 < _blockMap.Length)
                {
                    _blockMap[i + 6] = (tmp3 & 0xFFF000) >> 12;
                }

                if (i + 8 < _blockMap.Length)
                {
                    _blockMap[i + 7] = tmp3 & 0xFFF;
                }

                offset += 12;
            }

            if (_device.Info.ReadableSectorTags.Contains(SectorTagType.AppleSectorTag))
            {
                _mdbTags  = _device.ReadSectorTag(2 + _partitionStart, SectorTagType.AppleSectorTag);
                _bootTags = _device.ReadSectorTag(0 + _partitionStart, SectorTagType.AppleSectorTag);

                _directoryTags = _device.ReadSectorsTag(_volMdb.drDirSt + _partitionStart, _volMdb.drBlLen,
                                                        SectorTagType.AppleSectorTag);

                _bitmapTags = _device.ReadSectorsTag(_partitionStart + 2, (uint)sectorsInWholeMdb,
                                                     SectorTagType.AppleSectorTag);
            }

            _sectorsPerBlock = (int)(_volMdb.drAlBlkSiz / _device.Info.SectorSize);

            if (!FillDirectory())
            {
                return(Errno.InvalidArgument);
            }

            _mounted = true;

            ushort bbSig = BigEndianBitConverter.ToUInt16(_bootBlocks, 0x000);

            if (bbSig != AppleCommon.BB_MAGIC)
            {
                _bootBlocks = null;
            }

            XmlFsType = new FileSystemType();

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

            XmlFsType.Bootable    = bbSig == AppleCommon.BB_MAGIC;
            XmlFsType.Clusters    = _volMdb.drNmAlBlks;
            XmlFsType.ClusterSize = _volMdb.drAlBlkSiz;

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

            XmlFsType.Files                 = _volMdb.drNmFls;
            XmlFsType.FilesSpecified        = true;
            XmlFsType.FreeClusters          = _volMdb.drFreeBks;
            XmlFsType.FreeClustersSpecified = true;
            XmlFsType.Type       = "MFS";
            XmlFsType.VolumeName = _volMdb.drVN;

            return(Errno.NoError);
        }
Exemple #8
0
        public Errno Stat(string path, out FileEntryInfo stat)
        {
            stat = null;

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

            string[] pathElements = path.Split(new[]
            {
                '/'
            }, StringSplitOptions.RemoveEmptyEntries);

            if (pathElements.Length != 1)
            {
                return(Errno.NotSupported);
            }

            path = pathElements[0];

            if (_debug)
            {
                if (string.Compare(path, "$", StringComparison.InvariantCulture) == 0 ||
                    string.Compare(path, "$Boot", StringComparison.InvariantCulture) == 0 ||
                    string.Compare(path, "$Bitmap", StringComparison.InvariantCulture) == 0 ||
                    string.Compare(path, "$MDB", StringComparison.InvariantCulture) == 0)
                {
                    stat = new FileEntryInfo
                    {
                        BlockSize  = _device.Info.SectorSize,
                        Inode      = 0,
                        Links      = 1,
                        Attributes = FileAttributes.System
                    };

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

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

                        stat.Length = _blockMapBytes.Length;
                    }
                    else if (string.Compare(path, "$Boot", StringComparison.InvariantCulture) == 0 &&
                             _bootBlocks != null)
                    {
                        stat.Blocks = (_bootBlocks.Length / stat.BlockSize) + (_bootBlocks.Length % stat.BlockSize);
                        stat.Length = _bootBlocks.Length;
                    }
                    else if (string.Compare(path, "$MDB", StringComparison.InvariantCulture) == 0)
                    {
                        stat.Blocks = (_mdbBlocks.Length / stat.BlockSize) + (_mdbBlocks.Length % stat.BlockSize);
                        stat.Length = _mdbBlocks.Length;
                    }
                    else
                    {
                        return(Errno.InvalidArgument);
                    }

                    return(Errno.NoError);
                }
            }

            if (!_filenameToId.TryGetValue(path.ToLowerInvariant(), out uint fileId))
            {
                return(Errno.NoSuchFile);
            }

            if (!_idToEntry.TryGetValue(fileId, out FileEntry entry))
            {
                return(Errno.NoSuchFile);
            }

            Errno error = GetAttributes(path, out FileAttributes attr);

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

            stat = new FileEntryInfo
            {
                Attributes    = attr,
                Blocks        = entry.flLgLen / _volMdb.drAlBlkSiz,
                BlockSize     = _volMdb.drAlBlkSiz,
                CreationTime  = DateHandlers.MacToDateTime(entry.flCrDat),
                Inode         = entry.flFlNum,
                LastWriteTime = DateHandlers.MacToDateTime(entry.flMdDat),
                Length        = entry.flPyLen,
                Links         = 1
            };

            return(Errno.NoError);
        }
Exemple #9
0
        public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information,
                                   Encoding encoding)
        {
            Encoding    = encoding ?? new MacRoman();
            information = "";

            var sb = new StringBuilder();

            var mdb = new MasterDirectoryBlock();

            byte[] pString = new byte[16];

            byte[] mdbSector = imagePlugin.ReadSector(2 + partition.Start);
            byte[] bbSector  = imagePlugin.ReadSector(0 + partition.Start);

            mdb.drSigWord = BigEndianBitConverter.ToUInt16(mdbSector, 0x000);

            if (mdb.drSigWord != MFS_MAGIC)
            {
                return;
            }

            mdb.drCrDate   = BigEndianBitConverter.ToUInt32(mdbSector, 0x002);
            mdb.drLsBkUp   = BigEndianBitConverter.ToUInt32(mdbSector, 0x006);
            mdb.drAtrb     = (AppleCommon.VolumeAttributes)BigEndianBitConverter.ToUInt16(mdbSector, 0x00A);
            mdb.drNmFls    = BigEndianBitConverter.ToUInt16(mdbSector, 0x00C);
            mdb.drDirSt    = BigEndianBitConverter.ToUInt16(mdbSector, 0x00E);
            mdb.drBlLen    = BigEndianBitConverter.ToUInt16(mdbSector, 0x010);
            mdb.drNmAlBlks = BigEndianBitConverter.ToUInt16(mdbSector, 0x012);
            mdb.drAlBlkSiz = BigEndianBitConverter.ToUInt32(mdbSector, 0x014);
            mdb.drClpSiz   = BigEndianBitConverter.ToUInt32(mdbSector, 0x018);
            mdb.drAlBlSt   = BigEndianBitConverter.ToUInt16(mdbSector, 0x01C);
            mdb.drNxtFNum  = BigEndianBitConverter.ToUInt32(mdbSector, 0x01E);
            mdb.drFreeBks  = BigEndianBitConverter.ToUInt16(mdbSector, 0x022);
            mdb.drVNSiz    = mdbSector[0x024];
            byte[] variableSize = new byte[mdb.drVNSiz + 1];
            Array.Copy(mdbSector, 0x024, variableSize, 0, mdb.drVNSiz + 1);
            mdb.drVN = StringHandlers.PascalToString(variableSize, Encoding);

            sb.AppendLine("Apple Macintosh File System");
            sb.AppendLine();
            sb.AppendLine("Master Directory Block:");
            sb.AppendFormat("Creation date: {0}", DateHandlers.MacToDateTime(mdb.drCrDate)).AppendLine();
            sb.AppendFormat("Last backup date: {0}", DateHandlers.MacToDateTime(mdb.drLsBkUp)).AppendLine();

            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.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 volume", mdb.drNmFls).AppendLine();
            sb.AppendFormat("First directory sector: {0}", mdb.drDirSt).AppendLine();
            sb.AppendFormat("{0} sectors in directory.", mdb.drBlLen).AppendLine();
            sb.AppendFormat("{0} volume allocation blocks.", mdb.drNmAlBlks + 1).AppendLine();
            sb.AppendFormat("Size of allocation blocks: {0} bytes", mdb.drAlBlkSiz).AppendLine();
            sb.AppendFormat("{0} bytes to allocate.", mdb.drClpSiz).AppendLine();
            sb.AppendFormat("First allocation block (#2) starts in sector {0}.", mdb.drAlBlSt).AppendLine();
            sb.AppendFormat("Next unused file number: {0}", mdb.drNxtFNum).AppendLine();
            sb.AppendFormat("{0} unused allocation blocks.", mdb.drFreeBks).AppendLine();
            sb.AppendFormat("Volume name: {0}", mdb.drVN).AppendLine();

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

            if (bootBlockInfo != null)
            {
                sb.AppendLine("Volume is bootable.");
                sb.AppendLine();
                sb.AppendLine(bootBlockInfo);
            }
            else
            {
                sb.AppendLine("Volume is not bootable.");
            }

            information = sb.ToString();

            XmlFsType = new FileSystemType();

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

            XmlFsType.Bootable    = bootBlockInfo != null;
            XmlFsType.Clusters    = mdb.drNmAlBlks;
            XmlFsType.ClusterSize = mdb.drAlBlkSiz;

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

            XmlFsType.Files                 = mdb.drNmFls;
            XmlFsType.FilesSpecified        = true;
            XmlFsType.FreeClusters          = mdb.drFreeBks;
            XmlFsType.FreeClustersSpecified = true;
            XmlFsType.Type       = "MFS";
            XmlFsType.VolumeName = mdb.drVN;
        }
Exemple #10
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}";
            }
        }
Exemple #11
0
        public Errno Mount(IMediaImage imagePlugin, Partition partition, Encoding encoding,
                           Dictionary <string, string> options, string @namespace)
        {
            device         = imagePlugin;
            partitionStart = partition.Start;
            Encoding       = encoding ?? Encoding.GetEncoding("macintosh");
            if (options == null)
            {
                options = GetDefaultOptions();
            }
            if (options.TryGetValue("debug", out string debugString))
            {
                bool.TryParse(debugString, out debug);
            }
            volMDB = new MFS_MasterDirectoryBlock();

            mdbBlocks  = device.ReadSector(2 + partitionStart);
            bootBlocks = device.ReadSector(0 + partitionStart);

            BigEndianBitConverter.IsLittleEndian = BitConverter.IsLittleEndian;

            volMDB.drSigWord = BigEndianBitConverter.ToUInt16(mdbBlocks, 0x000);
            if (volMDB.drSigWord != MFS_MAGIC)
            {
                return(Errno.InvalidArgument);
            }

            volMDB.drCrDate   = BigEndianBitConverter.ToUInt32(mdbBlocks, 0x002);
            volMDB.drLsBkUp   = BigEndianBitConverter.ToUInt32(mdbBlocks, 0x006);
            volMDB.drAtrb     = BigEndianBitConverter.ToUInt16(mdbBlocks, 0x00A);
            volMDB.drNmFls    = BigEndianBitConverter.ToUInt16(mdbBlocks, 0x00C);
            volMDB.drDirSt    = BigEndianBitConverter.ToUInt16(mdbBlocks, 0x00E);
            volMDB.drBlLen    = BigEndianBitConverter.ToUInt16(mdbBlocks, 0x010);
            volMDB.drNmAlBlks = BigEndianBitConverter.ToUInt16(mdbBlocks, 0x012);
            volMDB.drAlBlkSiz = BigEndianBitConverter.ToUInt32(mdbBlocks, 0x014);
            volMDB.drClpSiz   = BigEndianBitConverter.ToUInt32(mdbBlocks, 0x018);
            volMDB.drAlBlSt   = BigEndianBitConverter.ToUInt16(mdbBlocks, 0x01C);
            volMDB.drNxtFNum  = BigEndianBitConverter.ToUInt32(mdbBlocks, 0x01E);
            volMDB.drFreeBks  = BigEndianBitConverter.ToUInt16(mdbBlocks, 0x022);
            volMDB.drVNSiz    = mdbBlocks[0x024];
            byte[] variableSize = new byte[volMDB.drVNSiz + 1];
            Array.Copy(mdbBlocks, 0x024, variableSize, 0, volMDB.drVNSiz + 1);
            volMDB.drVN = StringHandlers.PascalToString(variableSize, Encoding);

            directoryBlocks = device.ReadSectors(volMDB.drDirSt + partitionStart, volMDB.drBlLen);
            int       bytesInBlockMap        = volMDB.drNmAlBlks * 12 / 8 + volMDB.drNmAlBlks * 12 % 8;
            const int BYTES_BEFORE_BLOCK_MAP = 64;
            int       bytesInWholeMdb        = bytesInBlockMap + BYTES_BEFORE_BLOCK_MAP;
            int       sectorsInWholeMdb      = bytesInWholeMdb / (int)device.Info.SectorSize +
                                               bytesInWholeMdb % (int)device.Info.SectorSize;

            byte[] wholeMdb = device.ReadSectors(partitionStart + 2, (uint)sectorsInWholeMdb);
            blockMapBytes = new byte[bytesInBlockMap];
            Array.Copy(wholeMdb, BYTES_BEFORE_BLOCK_MAP, blockMapBytes, 0, blockMapBytes.Length);

            int offset = 0;

            blockMap = new uint[volMDB.drNmAlBlks + 2 + 1];
            for (int i = 2; i < volMDB.drNmAlBlks + 2; i += 8)
            {
                uint tmp1 = 0;
                uint tmp2 = 0;
                uint tmp3 = 0;

                if (offset + 4 <= blockMapBytes.Length)
                {
                    tmp1 = BigEndianBitConverter.ToUInt32(blockMapBytes, offset);
                }
                if (offset + 4 + 4 <= blockMapBytes.Length)
                {
                    tmp2 = BigEndianBitConverter.ToUInt32(blockMapBytes, offset + 4);
                }
                if (offset + 8 + 4 <= blockMapBytes.Length)
                {
                    tmp3 = BigEndianBitConverter.ToUInt32(blockMapBytes, offset + 8);
                }

                if (i < blockMap.Length)
                {
                    blockMap[i] = (tmp1 & 0xFFF00000) >> 20;
                }
                if (i + 2 < blockMap.Length)
                {
                    blockMap[i + 1] = (tmp1 & 0xFFF00) >> 8;
                }
                if (i + 3 < blockMap.Length)
                {
                    blockMap[i + 2] = ((tmp1 & 0xFF) << 4) + ((tmp2 & 0xF0000000) >> 28);
                }
                if (i + 4 < blockMap.Length)
                {
                    blockMap[i + 3] = (tmp2 & 0xFFF0000) >> 16;
                }
                if (i + 5 < blockMap.Length)
                {
                    blockMap[i + 4] = (tmp2 & 0xFFF0) >> 4;
                }
                if (i + 6 < blockMap.Length)
                {
                    blockMap[i + 5] = ((tmp2 & 0xF) << 8) + ((tmp3 & 0xFF000000) >> 24);
                }
                if (i + 7 < blockMap.Length)
                {
                    blockMap[i + 6] = (tmp3 & 0xFFF000) >> 12;
                }
                if (i + 8 < blockMap.Length)
                {
                    blockMap[i + 7] = tmp3 & 0xFFF;
                }

                offset += 12;
            }

            if (device.Info.ReadableSectorTags.Contains(SectorTagType.AppleSectorTag))
            {
                mdbTags       = device.ReadSectorTag(2 + partitionStart, SectorTagType.AppleSectorTag);
                bootTags      = device.ReadSectorTag(0 + partitionStart, SectorTagType.AppleSectorTag);
                directoryTags = device.ReadSectorsTag(volMDB.drDirSt + partitionStart, volMDB.drBlLen,
                                                      SectorTagType.AppleSectorTag);
                bitmapTags = device.ReadSectorsTag(partitionStart + 2, (uint)sectorsInWholeMdb,
                                                   SectorTagType.AppleSectorTag);
            }

            sectorsPerBlock = (int)(volMDB.drAlBlkSiz / device.Info.SectorSize);

            if (!FillDirectory())
            {
                return(Errno.InvalidArgument);
            }

            mounted = true;

            ushort bbSig = BigEndianBitConverter.ToUInt16(bootBlocks, 0x000);

            if (bbSig != MFSBB_MAGIC)
            {
                bootBlocks = null;
            }

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

            XmlFsType.Bootable    = bbSig == MFSBB_MAGIC;
            XmlFsType.Clusters    = volMDB.drNmAlBlks;
            XmlFsType.ClusterSize = volMDB.drAlBlkSiz;
            if (volMDB.drCrDate > 0)
            {
                XmlFsType.CreationDate          = DateHandlers.MacToDateTime(volMDB.drCrDate);
                XmlFsType.CreationDateSpecified = true;
            }

            XmlFsType.Files                 = volMDB.drNmFls;
            XmlFsType.FilesSpecified        = true;
            XmlFsType.FreeClusters          = volMDB.drFreeBks;
            XmlFsType.FreeClustersSpecified = true;
            XmlFsType.Type       = "MFS";
            XmlFsType.VolumeName = volMDB.drVN;

            return(Errno.NoError);
        }
Exemple #12
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;
        }
Exemple #13
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;
        }