public bool Identify(IMediaImage imagePlugin, Partition partition) { if (imagePlugin.Info.SectorSize < 512) { return(false); } uint sbSize = (uint)(Marshal.SizeOf <Superblock>() / imagePlugin.Info.SectorSize); if (Marshal.SizeOf <Superblock>() % imagePlugin.Info.SectorSize != 0) { sbSize++; } byte[] sector = imagePlugin.ReadSectors(partition.Start, sbSize); if (sector.Length < Marshal.SizeOf <Superblock>()) { return(false); } Superblock unicosSb = Marshal.ByteArrayToStructureBigEndian <Superblock>(sector); AaruConsole.DebugWriteLine("UNICOS plugin", "magic = 0x{0:X16} (expected 0x{1:X16})", unicosSb.s_magic, UNICOS_MAGIC); return(unicosSb.s_magic == UNICOS_MAGIC); }
public bool Identify(string path) { if (!File.Exists(path)) { return(false); } var fstream = new FileStream(path, FileMode.Open, FileAccess.Read); if (fstream.Length < 128) { return(false); } byte[] hdrB = new byte[128]; fstream.Read(hdrB, 0, 128); _header = Marshal.ByteArrayToStructureBigEndian <Header>(hdrB); fstream.Close(); return(_header.magic == MAGIC || (_header.version == 0 && _header.filename[0] > 0 && _header.filename[0] < 64 && _header.zero1 == 0 && _header.zero2 == 0 && _header.reserved == 0 && (_header.dataLength > 0 || _header.resourceLength > 0))); }
public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information, Encoding encoding) { Encoding = encoding ?? Encoding.GetEncoding("iso-8859-1"); byte[] rootBlockSector = imagePlugin.ReadSector(partition.Start); RootBlock rootBlock = Marshal.ByteArrayToStructureBigEndian <RootBlock>(rootBlockSector); var sbInformation = new StringBuilder(); sbInformation.AppendLine("SmartFileSystem"); sbInformation.AppendFormat("Volume version {0}", rootBlock.version).AppendLine(); sbInformation.AppendFormat("Volume starts on device byte {0} and ends on byte {1}", rootBlock.firstbyte, rootBlock.lastbyte).AppendLine(); sbInformation. AppendFormat("Volume has {0} blocks of {1} bytes each", rootBlock.totalblocks, rootBlock.blocksize). AppendLine(); sbInformation.AppendFormat("Volume created on {0}", DateHandlers.UnixUnsignedToDateTime(rootBlock.datecreated).AddYears(8)). AppendLine(); sbInformation.AppendFormat("Bitmap starts in block {0}", rootBlock.bitmapbase).AppendLine(); sbInformation.AppendFormat("Admin space container starts in block {0}", rootBlock.adminspacecontainer). AppendLine(); sbInformation.AppendFormat("Root object container starts in block {0}", rootBlock.rootobjectcontainer). AppendLine(); sbInformation. AppendFormat("Root node of the extent B-tree resides in block {0}", rootBlock.extentbnoderoot). AppendLine(); sbInformation.AppendFormat("Root node of the object B-tree resides in block {0}", rootBlock.objectnoderoot). AppendLine(); if (rootBlock.bits.HasFlag(Flags.CaseSensitive)) { sbInformation.AppendLine("Volume is case sensitive"); } if (rootBlock.bits.HasFlag(Flags.RecycledFolder)) { sbInformation.AppendLine("Volume moves deleted files to a recycled folder"); } information = sbInformation.ToString(); XmlFsType = new FileSystemType { CreationDate = DateHandlers.UnixUnsignedToDateTime(rootBlock.datecreated).AddYears(8), CreationDateSpecified = true, Clusters = rootBlock.totalblocks, ClusterSize = rootBlock.blocksize, Type = "SmartFileSystem" }; }
public bool Identify(IMediaImage imagePlugin, Partition partition) { if (imagePlugin.Info.SectorSize < 256) { return(false); } // Documentation says ID should be sector 0 // I've found that OS-9/X68000 has it on sector 4 // I've read OS-9/Apple2 has it on sector 15 foreach (int i in new[] { 0, 4, 15 }) { ulong location = (ulong)i; uint sbSize = (uint)(Marshal.SizeOf <IdSector>() / imagePlugin.Info.SectorSize); if (Marshal.SizeOf <IdSector>() % imagePlugin.Info.SectorSize != 0) { sbSize++; } if (partition.Start + location + sbSize >= imagePlugin.Info.Sectors) { break; } byte[] sector = imagePlugin.ReadSectors(partition.Start + location, sbSize); if (sector.Length < Marshal.SizeOf <IdSector>()) { return(false); } IdSector rbfSb = Marshal.ByteArrayToStructureBigEndian <IdSector>(sector); NewIdSector rbf9000Sb = Marshal.ByteArrayToStructureBigEndian <NewIdSector>(sector); AaruConsole.DebugWriteLine("RBF plugin", "magic at {0} = 0x{1:X8} or 0x{2:X8} (expected 0x{3:X8} or 0x{4:X8})", location, rbfSb.dd_sync, rbf9000Sb.rid_sync, RBF_SYNC, RBF_CNYS); if (rbfSb.dd_sync == RBF_SYNC || rbf9000Sb.rid_sync == RBF_SYNC || rbf9000Sb.rid_sync == RBF_CNYS) { return(true); } } return(false); }
public bool Identify(IMediaImage imagePlugin, Partition partition) { if (imagePlugin.Info.SectorSize < 256) { return(false); } byte[] sector = imagePlugin.ReadSector(partition.Start); SystemBlock lifSb = Marshal.ByteArrayToStructureBigEndian <SystemBlock>(sector); AaruConsole.DebugWriteLine("LIF plugin", "magic 0x{0:X8} (expected 0x{1:X8})", lifSb.magic, LIF_MAGIC); return(lifSb.magic == LIF_MAGIC); }
public bool Identify(byte[] buffer) { if (buffer == null || buffer.Length < 26) { return(false); } byte[] hdrB = new byte[26]; Array.Copy(buffer, 0, hdrB, 0, 26); _header = Marshal.ByteArrayToStructureBigEndian <Header>(hdrB); return(_header.magic == MAGIC && (_header.version == VERSION || _header.version == VERSION2)); }
public bool Identify(Stream stream) { if (stream == null || stream.Length < 26) { return(false); } byte[] hdrB = new byte[26]; stream.Seek(0, SeekOrigin.Begin); stream.Read(hdrB, 0, 26); _header = Marshal.ByteArrayToStructureBigEndian <Header>(hdrB); return(_header.magic == MAGIC && (_header.version == VERSION || _header.version == VERSION2)); }
static RootBlock MarshalRootBlock(byte[] block) { byte[] tmp = new byte[228]; Array.Copy(block, 0, tmp, 0, 24); Array.Copy(block, block.Length - 200, tmp, 28, 200); RootBlock root = Marshal.ByteArrayToStructureBigEndian <RootBlock>(tmp); root.hashTable = new uint[(block.Length - 224) / 4]; for (int i = 0; i < root.hashTable.Length; i++) { root.hashTable[i] = BigEndianBitConverter.ToUInt32(block, 24 + (i * 4)); } return(root); }
public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information, Encoding encoding) { Encoding = encoding ?? Encoding.GetEncoding("iso-8859-15"); byte[] sector = imagePlugin.ReadSector(partition.Start); uint magic = BitConverter.ToUInt32(sector, 0x00); var crSb = new SuperBlock(); bool littleEndian = true; switch (magic) { case CRAM_MAGIC: crSb = Marshal.ByteArrayToStructureLittleEndian <SuperBlock>(sector); break; case CRAM_CIGAM: crSb = Marshal.ByteArrayToStructureBigEndian <SuperBlock>(sector); littleEndian = false; break; } var sbInformation = new StringBuilder(); sbInformation.AppendLine("Cram file system"); sbInformation.AppendLine(littleEndian ? "Little-endian" : "Big-endian"); sbInformation.AppendFormat("Volume edition {0}", crSb.edition).AppendLine(); sbInformation.AppendFormat("Volume name: {0}", StringHandlers.CToString(crSb.name, Encoding)).AppendLine(); sbInformation.AppendFormat("Volume has {0} bytes", crSb.size).AppendLine(); sbInformation.AppendFormat("Volume has {0} blocks", crSb.blocks).AppendLine(); sbInformation.AppendFormat("Volume has {0} files", crSb.files).AppendLine(); information = sbInformation.ToString(); XmlFsType = new FileSystemType { VolumeName = StringHandlers.CToString(crSb.name, Encoding), Type = "Cram file system", Clusters = crSb.blocks, Files = crSb.files, FilesSpecified = true, FreeClusters = 0, FreeClustersSpecified = true }; }
public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information, Encoding encoding) { Encoding = encoding ?? Encoding.GetEncoding("iso-8859-15"); information = ""; if (imagePlugin.Info.SectorSize < 256) { return; } byte[] sector = imagePlugin.ReadSector(partition.Start); SystemBlock lifSb = Marshal.ByteArrayToStructureBigEndian <SystemBlock>(sector); if (lifSb.magic != LIF_MAGIC) { return; } var sb = new StringBuilder(); sb.AppendLine("HP Logical Interchange Format"); sb.AppendFormat("Directory starts at cluster {0}", lifSb.directoryStart).AppendLine(); sb.AppendFormat("LIF identifier: {0}", lifSb.lifId).AppendLine(); sb.AppendFormat("Directory size: {0} clusters", lifSb.directorySize).AppendLine(); sb.AppendFormat("LIF version: {0}", lifSb.lifVersion).AppendLine(); // How is this related to volume size? I have only CDs to test and makes no sense there sb.AppendFormat("{0} tracks", lifSb.tracks).AppendLine(); sb.AppendFormat("{0} heads", lifSb.heads).AppendLine(); sb.AppendFormat("{0} sectors", lifSb.sectors).AppendLine(); sb.AppendFormat("Volume name: {0}", StringHandlers.CToString(lifSb.volumeLabel, Encoding)).AppendLine(); sb.AppendFormat("Volume created on {0}", DateHandlers.LifToDateTime(lifSb.creationDate)).AppendLine(); information = sb.ToString(); XmlFsType = new FileSystemType { Type = "HP Logical Interchange Format", ClusterSize = 256, Clusters = partition.Size / 256, CreationDate = DateHandlers.LifToDateTime(lifSb.creationDate), CreationDateSpecified = true, VolumeName = StringHandlers.CToString(lifSb.volumeLabel, Encoding) }; }
public bool Identify(byte[] buffer) { if (buffer == null || buffer.Length < 128) { return(false); } byte[] hdrB = new byte[128]; Array.Copy(buffer, 0, hdrB, 0, 128); _header = Marshal.ByteArrayToStructureBigEndian <MacBinaryHeader>(hdrB); return(_header.magic == MAGIC || (_header.version == 0 && _header.filename[0] > 0 && _header.filename[0] < 64 && _header.zero1 == 0 && _header.zero2 == 0 && _header.reserved == 0 && (_header.dataLength > 0 || _header.resourceLength > 0))); }
public bool Identify(IMediaImage imagePlugin, Partition partition) { ulong hdrSector = HEADER_POS / imagePlugin.Info.SectorSize; if (partition.Start + hdrSector > imagePlugin.Info.Sectors) { return(false); } byte[] sector = imagePlugin.ReadSector(partition.Start + hdrSector); Header hdr = Marshal.ByteArrayToStructureBigEndian <Header>(sector); AaruConsole.DebugWriteLine("Fossil plugin", "magic at 0x{0:X8} (expected 0x{1:X8})", hdr.magic, FOSSIL_HDR_MAGIC); return(hdr.magic == FOSSIL_HDR_MAGIC); }
public bool Identify(string path) { var fstream = new FileStream(path, FileMode.Open, FileAccess.Read); if (fstream.Length < 26) { return(false); } byte[] hdrB = new byte[26]; fstream.Read(hdrB, 0, 26); _header = Marshal.ByteArrayToStructureBigEndian <AppleSingleHeader>(hdrB); fstream.Close(); return(_header.magic == MAGIC && (_header.version == VERSION || _header.version == VERSION2)); }
public bool Identify(Stream stream) { if (stream == null || stream.Length < 128) { return(false); } byte[] hdrB = new byte[128]; stream.Seek(0, SeekOrigin.Begin); stream.Read(hdrB, 0, 128); _header = Marshal.ByteArrayToStructureBigEndian <MacBinaryHeader>(hdrB); return(_header.magic == MAGIC || (_header.version == 0 && _header.filename[0] > 0 && _header.filename[0] < 64 && _header.zero1 == 0 && _header.zero2 == 0 && _header.reserved == 0 && (_header.dataLength > 0 || _header.resourceLength > 0))); }
public void Open(string path) { var fs = new FileStream(path, FileMode.Open, FileAccess.Read); fs.Seek(0, SeekOrigin.Begin); byte[] hdrB = new byte[128]; fs.Read(hdrB, 0, 128); _header = Marshal.ByteArrayToStructureBigEndian <MacBinaryHeader>(hdrB); uint blocks = 1; blocks += (uint)(_header.secondaryHeaderLength / 128); if (_header.secondaryHeaderLength % 128 > 0) { blocks++; } _dataForkOff = blocks * 128; blocks += _header.dataLength / 128; if (_header.dataLength % 128 > 0) { blocks++; } _rsrcForkOff = blocks * 128; _filename = StringHandlers.PascalToString(_header.filename, Encoding.GetEncoding("macintosh")); _creationTime = DateHandlers.MacToDateTime(_header.creationTime); _lastWriteTime = DateHandlers.MacToDateTime(_header.modificationTime); fs.Close(); _opened = true; _isPath = true; _basePath = path; }
public void Open(byte[] buffer) { var ms = new MemoryStream(buffer); ms.Seek(0, SeekOrigin.Begin); byte[] hdrB = new byte[128]; ms.Read(hdrB, 0, 128); _header = Marshal.ByteArrayToStructureBigEndian <MacBinaryHeader>(hdrB); uint blocks = 1; blocks += (uint)(_header.secondaryHeaderLength / 128); if (_header.secondaryHeaderLength % 128 > 0) { blocks++; } _dataForkOff = blocks * 128; blocks += _header.dataLength / 128; if (_header.dataLength % 128 > 0) { blocks++; } _rsrcForkOff = blocks * 128; _filename = StringHandlers.PascalToString(_header.filename, Encoding.GetEncoding("macintosh")); _creationTime = DateHandlers.MacToDateTime(_header.creationTime); _lastWriteTime = DateHandlers.MacToDateTime(_header.modificationTime); ms.Close(); _opened = true; _isBytes = true; _bytes = buffer; }
public void Open(Stream stream) { stream.Seek(0, SeekOrigin.Begin); byte[] hdrB = new byte[128]; stream.Read(hdrB, 0, 128); _header = Marshal.ByteArrayToStructureBigEndian <Header>(hdrB); uint blocks = 1; blocks += (uint)(_header.secondaryHeaderLength / 128); if (_header.secondaryHeaderLength % 128 > 0) { blocks++; } _dataForkOff = blocks * 128; blocks += _header.dataLength / 128; if (_header.dataLength % 128 > 0) { blocks++; } _rsrcForkOff = blocks * 128; _filename = StringHandlers.PascalToString(_header.filename, Encoding.GetEncoding("macintosh")); _creationTime = DateHandlers.MacToDateTime(_header.creationTime); _lastWriteTime = DateHandlers.MacToDateTime(_header.modificationTime); stream.Seek(0, SeekOrigin.Begin); _opened = true; _isStream = true; _stream = stream; }
public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information, Encoding encoding) { Encoding = encoding ?? Encoding.GetEncoding("iso-8859-15"); information = ""; if (imagePlugin.Info.SectorSize < 512) { return; } var xfsSb = new Superblock(); // Misaligned if (imagePlugin.Info.XmlMediaType == XmlMediaType.OpticalDisc) { uint sbSize = (uint)((Marshal.SizeOf <Superblock>() + 0x400) / imagePlugin.Info.SectorSize); if ((Marshal.SizeOf <Superblock>() + 0x400) % imagePlugin.Info.SectorSize != 0) { sbSize++; } byte[] sector = imagePlugin.ReadSectors(partition.Start, sbSize); if (sector.Length < Marshal.SizeOf <Superblock>()) { return; } byte[] sbpiece = new byte[Marshal.SizeOf <Superblock>()]; foreach (int location in new[] { 0, 0x200, 0x400 }) { Array.Copy(sector, location, sbpiece, 0, Marshal.SizeOf <Superblock>()); xfsSb = Marshal.ByteArrayToStructureBigEndian <Superblock>(sbpiece); AaruConsole.DebugWriteLine("XFS plugin", "magic at 0x{0:X3} = 0x{1:X8} (expected 0x{2:X8})", location, xfsSb.magicnum, XFS_MAGIC); if (xfsSb.magicnum == XFS_MAGIC) { break; } } } else { foreach (int i in new[] { 0, 1, 2 }) { ulong location = (ulong)i; uint sbSize = (uint)(Marshal.SizeOf <Superblock>() / imagePlugin.Info.SectorSize); if (Marshal.SizeOf <Superblock>() % imagePlugin.Info.SectorSize != 0) { sbSize++; } byte[] sector = imagePlugin.ReadSectors(partition.Start + location, sbSize); if (sector.Length < Marshal.SizeOf <Superblock>()) { return; } xfsSb = Marshal.ByteArrayToStructureBigEndian <Superblock>(sector); AaruConsole.DebugWriteLine("XFS plugin", "magic at {0} = 0x{1:X8} (expected 0x{2:X8})", location, xfsSb.magicnum, XFS_MAGIC); if (xfsSb.magicnum == XFS_MAGIC) { break; } } } if (xfsSb.magicnum != XFS_MAGIC) { return; } var sb = new StringBuilder(); sb.AppendLine("XFS filesystem"); sb.AppendFormat("Filesystem version {0}", xfsSb.version & 0xF).AppendLine(); sb.AppendFormat("{0} bytes per sector", xfsSb.sectsize).AppendLine(); sb.AppendFormat("{0} bytes per block", xfsSb.blocksize).AppendLine(); sb.AppendFormat("{0} bytes per inode", xfsSb.inodesize).AppendLine(); sb.AppendFormat("{0} data blocks in volume, {1} free", xfsSb.dblocks, xfsSb.fdblocks).AppendLine(); sb.AppendFormat("{0} blocks per allocation group", xfsSb.agblocks).AppendLine(); sb.AppendFormat("{0} allocation groups in volume", xfsSb.agcount).AppendLine(); sb.AppendFormat("{0} inodes in volume, {1} free", xfsSb.icount, xfsSb.ifree).AppendLine(); if (xfsSb.inprogress > 0) { sb.AppendLine("fsck in progress"); } sb.AppendFormat("Volume name: {0}", StringHandlers.CToString(xfsSb.fname, Encoding)).AppendLine(); sb.AppendFormat("Volume UUID: {0}", xfsSb.uuid).AppendLine(); information = sb.ToString(); XmlFsType = new FileSystemType { Type = "XFS filesystem", ClusterSize = xfsSb.blocksize, Clusters = xfsSb.dblocks, FreeClusters = xfsSb.fdblocks, FreeClustersSpecified = true, Files = xfsSb.icount - xfsSb.ifree, FilesSpecified = true, Dirty = xfsSb.inprogress > 0, VolumeName = StringHandlers.CToString(xfsSb.fname, Encoding), VolumeSerial = xfsSb.uuid.ToString() }; }
public void Open(string path) { var fs = new FileStream(path, 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 ((AppleSingleEntryID)entry.id) { case AppleSingleEntryID.DataFork: _dataFork = entry; break; case AppleSingleEntryID.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.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)) { 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 AppleSingleEntryID.ResourceFork: _rsrcFork = entry; break; } } fs.Close(); _opened = true; _isPath = true; _basePath = path; }
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 <AppleDoubleHeader>(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 <AppleDoubleHeader>(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 <AppleDoubleHeader>(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 <AppleDoubleHeader>(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 <AppleDoubleHeader>(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 <AppleDoubleHeader>(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 <AppleDoubleHeader>(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 <AppleDoubleHeader>(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 <AppleDoubleHeader>(hdrB); AppleDoubleEntry[] entries = new AppleDoubleEntry[_header.entries]; for (int i = 0; i < _header.entries; i++) { byte[] entry = new byte[12]; fs.Read(entry, 0, 12); entries[i] = Marshal.ByteArrayToStructureBigEndian <AppleDoubleEntry>(entry); } _creationTime = DateTime.UtcNow; _lastWriteTime = _creationTime; foreach (AppleDoubleEntry entry in entries) { switch ((AppleDoubleEntryID)entry.id) { case AppleDoubleEntryID.DataFork: // AppleDouble have datafork in separated file break; case AppleDoubleEntryID.FileDates: fs.Seek(entry.offset, SeekOrigin.Begin); byte[] datesB = new byte[16]; fs.Read(datesB, 0, 16); AppleDoubleFileDates dates = Marshal.ByteArrayToStructureBigEndian <AppleDoubleFileDates>(datesB); _creationTime = DateHandlers.UnixUnsignedToDateTime(dates.creationDate); _lastWriteTime = DateHandlers.UnixUnsignedToDateTime(dates.modificationDate); break; case AppleDoubleEntryID.FileInfo: fs.Seek(entry.offset, SeekOrigin.Begin); byte[] finfo = new byte[entry.length]; fs.Read(finfo, 0, finfo.Length); if (_macintoshHome.SequenceEqual(_header.homeFilesystem)) { AppleDoubleMacFileInfo macinfo = Marshal.ByteArrayToStructureBigEndian <AppleDoubleMacFileInfo>(finfo); _creationTime = DateHandlers.MacToDateTime(macinfo.creationDate); _lastWriteTime = DateHandlers.MacToDateTime(macinfo.modificationDate); } else if (_proDosHome.SequenceEqual(_header.homeFilesystem)) { AppleDoubleProDOSFileInfo prodosinfo = Marshal.ByteArrayToStructureBigEndian <AppleDoubleProDOSFileInfo>(finfo); _creationTime = DateHandlers.MacToDateTime(prodosinfo.creationDate); _lastWriteTime = DateHandlers.MacToDateTime(prodosinfo.modificationDate); } else if (_unixHome.SequenceEqual(_header.homeFilesystem)) { AppleDoubleUnixFileInfo unixinfo = Marshal.ByteArrayToStructureBigEndian <AppleDoubleUnixFileInfo>(finfo); _creationTime = DateHandlers.UnixUnsignedToDateTime(unixinfo.creationDate); _lastWriteTime = DateHandlers.UnixUnsignedToDateTime(unixinfo.modificationDate); } else if (_dosHome.SequenceEqual(_header.homeFilesystem)) { AppleDoubleDOSFileInfo dosinfo = Marshal.ByteArrayToStructureBigEndian <AppleDoubleDOSFileInfo>(finfo); _lastWriteTime = DateHandlers.DosToDateTime(dosinfo.modificationDate, dosinfo.modificationTime); } break; case AppleDoubleEntryID.ResourceFork: _rsrcFork = entry; break; } } _dataFork = new AppleDoubleEntry { id = (uint)AppleDoubleEntryID.DataFork }; if (File.Exists(path)) { var dataFs = new FileStream(path, FileMode.Open, FileAccess.Read); _dataFork.length = (uint)dataFs.Length; dataFs.Close(); } fs.Close(); _opened = true; _basePath = path; }
public bool Identify(IMediaImage imagePlugin, Partition partition) { if (imagePlugin.Info.SectorSize < 512) { return(false); } // Misaligned if (imagePlugin.Info.XmlMediaType == XmlMediaType.OpticalDisc) { uint sbSize = (uint)((Marshal.SizeOf <Superblock>() + 0x400) / imagePlugin.Info.SectorSize); if ((Marshal.SizeOf <Superblock>() + 0x400) % imagePlugin.Info.SectorSize != 0) { sbSize++; } byte[] sector = imagePlugin.ReadSectors(partition.Start, sbSize); if (sector.Length < Marshal.SizeOf <Superblock>()) { return(false); } byte[] sbpiece = new byte[Marshal.SizeOf <Superblock>()]; foreach (int location in new[] { 0, 0x200, 0x400 }) { Array.Copy(sector, location, sbpiece, 0, Marshal.SizeOf <Superblock>()); Superblock xfsSb = Marshal.ByteArrayToStructureBigEndian <Superblock>(sbpiece); AaruConsole.DebugWriteLine("XFS plugin", "magic at 0x{0:X3} = 0x{1:X8} (expected 0x{2:X8})", location, xfsSb.magicnum, XFS_MAGIC); if (xfsSb.magicnum == XFS_MAGIC) { return(true); } } } else { foreach (int i in new[] { 0, 1, 2 }) { ulong location = (ulong)i; uint sbSize = (uint)(Marshal.SizeOf <Superblock>() / imagePlugin.Info.SectorSize); if (Marshal.SizeOf <Superblock>() % imagePlugin.Info.SectorSize != 0) { sbSize++; } byte[] sector = imagePlugin.ReadSectors(partition.Start + location, sbSize); if (sector.Length < Marshal.SizeOf <Superblock>()) { return(false); } Superblock xfsSb = Marshal.ByteArrayToStructureBigEndian <Superblock>(sector); AaruConsole.DebugWriteLine("XFS plugin", "magic at {0} = 0x{1:X8} (expected 0x{2:X8})", location, xfsSb.magicnum, XFS_MAGIC); if (xfsSb.magicnum == XFS_MAGIC) { return(true); } } } return(false); }
public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information, Encoding encoding) { Encoding = Encoding.BigEndianUnicode; information = ""; var vh = new VolumeHeader(); 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 == AppleCommon.HFS_MAGIC) // "BD" { drSigWord = BigEndianBitConverter.ToUInt16(vhSector, 0x47C); // Read embedded HFS+ signature if (drSigWord == AppleCommon.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 != AppleCommon.HFSP_MAGIC && vh.signature != AppleCommon.HFSX_MAGIC) { return; } var 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 <VolumeHeader>(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(); }
public bool Identify(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) { return(false); } // 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 <AppleDoubleHeader>(prodosB); prodosStream.Close(); if (_header.magic == MAGIC && (_header.version == VERSION || _header.version == VERSION2)) { return(true); } } } // 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 <AppleDoubleHeader>(unixB); unixStream.Close(); if (_header.magic == MAGIC && (_header.version == VERSION || _header.version == VERSION2)) { return(true); } } } // 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 <AppleDoubleHeader>(dosB); dosStream.Close(); if (_header.magic == MAGIC && (_header.version == VERSION || _header.version == VERSION2)) { return(true); } } } // 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 <AppleDoubleHeader>(doslB); doslStream.Close(); if (_header.magic == MAGIC && (_header.version == VERSION || _header.version == VERSION2)) { return(true); } } } // 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 <AppleDoubleHeader>(netatalkB); netatalkStream.Close(); if (_header.magic == MAGIC && (_header.version == VERSION || _header.version == VERSION2)) { return(true); } } } // 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 <AppleDoubleHeader>(daveB); daveStream.Close(); if (_header.magic == MAGIC && (_header.version == VERSION || _header.version == VERSION2)) { return(true); } } } // 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 <AppleDoubleHeader>(osxB); osxStream.Close(); if (_header.magic == MAGIC && (_header.version == VERSION || _header.version == VERSION2)) { return(true); } } } // Check AppleDouble created by UnAr (from The Unarchiver) if (!File.Exists(unArAppleDouble)) { return(false); } var unarStream = new FileStream(unArAppleDouble, FileMode.Open, FileAccess.Read); if (unarStream.Length <= 26) { return(false); } byte[] unarB = new byte[26]; unarStream.Read(unarB, 0, 26); _header = Marshal.ByteArrayToStructureBigEndian <AppleDoubleHeader>(unarB); unarStream.Close(); return(_header.magic == MAGIC && (_header.version == VERSION || _header.version == VERSION2)); }
public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information, Encoding encoding) { Encoding = encoding ?? Encoding.GetEncoding("iso-8859-15"); information = ""; var sbInformation = new StringBuilder(); uint magic = 0; uint sb_size_in_sectors; byte[] ufs_sb_sectors; ulong sb_offset = partition.Start; bool fs_type_42bsd = false; bool fs_type_43bsd = false; bool fs_type_44bsd = false; bool fs_type_ufs = false; bool fs_type_ufs2 = false; bool fs_type_sun = false; bool fs_type_sun86 = false; if (imagePlugin.Info.SectorSize == 2336 || imagePlugin.Info.SectorSize == 2352 || imagePlugin.Info.SectorSize == 2448) { sb_size_in_sectors = block_size / 2048; } else { sb_size_in_sectors = block_size / imagePlugin.Info.SectorSize; } ulong[] locations = { sb_start_floppy, sb_start_boot, sb_start_long_boot, sb_start_piggy, sb_start_att_dsdd, 8192 / imagePlugin.Info.SectorSize, 65536 / imagePlugin.Info.SectorSize, 262144 / imagePlugin.Info.SectorSize }; foreach (ulong loc in locations.Where(loc => partition.End > partition.Start + loc + sb_size_in_sectors)) { ufs_sb_sectors = imagePlugin.ReadSectors(partition.Start + loc, sb_size_in_sectors); magic = BitConverter.ToUInt32(ufs_sb_sectors, 0x055C); if (magic == UFS_MAGIC || magic == UFS_CIGAM || magic == UFS_MAGIC_BW || magic == UFS_CIGAM_BW || magic == UFS2_MAGIC || magic == UFS2_CIGAM || magic == UFS_BAD_MAGIC || magic == UFS_BAD_CIGAM) { sb_offset = partition.Start + loc; break; } magic = 0; } if (magic == 0) { information = "Not a UFS filesystem, I shouldn't have arrived here!"; return; } XmlFsType = new FileSystemType(); switch (magic) { case UFS_MAGIC: sbInformation.AppendLine("UFS filesystem"); XmlFsType.Type = "UFS"; break; case UFS_CIGAM: sbInformation.AppendLine("Big-endian UFS filesystem"); XmlFsType.Type = "UFS"; break; case UFS_MAGIC_BW: sbInformation.AppendLine("BorderWare UFS filesystem"); XmlFsType.Type = "UFS"; break; case UFS_CIGAM_BW: sbInformation.AppendLine("Big-endian BorderWare UFS filesystem"); XmlFsType.Type = "UFS"; break; case UFS2_MAGIC: sbInformation.AppendLine("UFS2 filesystem"); XmlFsType.Type = "UFS2"; break; case UFS2_CIGAM: sbInformation.AppendLine("Big-endian UFS2 filesystem"); XmlFsType.Type = "UFS2"; break; case UFS_BAD_MAGIC: sbInformation.AppendLine("Incompletely initialized UFS filesystem"); sbInformation.AppendLine("BEWARE!!! Following information may be completely wrong!"); XmlFsType.Type = "UFS"; break; case UFS_BAD_CIGAM: sbInformation.AppendLine("Incompletely initialized big-endian UFS filesystem"); sbInformation.AppendLine("BEWARE!!! Following information may be completely wrong!"); XmlFsType.Type = "UFS"; break; } // Fun with seeking follows on superblock reading! ufs_sb_sectors = imagePlugin.ReadSectors(sb_offset, sb_size_in_sectors); SuperBlock sb = Marshal.ByteArrayToStructureLittleEndian <SuperBlock>(ufs_sb_sectors); SuperBlock bs_sfu = Marshal.ByteArrayToStructureBigEndian <SuperBlock>(ufs_sb_sectors); if ((bs_sfu.fs_magic == UFS_MAGIC && sb.fs_magic == UFS_CIGAM) || (bs_sfu.fs_magic == UFS_MAGIC_BW && sb.fs_magic == UFS_CIGAM_BW) || (bs_sfu.fs_magic == UFS2_MAGIC && sb.fs_magic == UFS2_CIGAM) || (bs_sfu.fs_magic == UFS_BAD_MAGIC && sb.fs_magic == UFS_BAD_CIGAM)) { sb = bs_sfu; sb.fs_old_cstotal.cs_nbfree = Swapping.Swap(sb.fs_old_cstotal.cs_nbfree); sb.fs_old_cstotal.cs_ndir = Swapping.Swap(sb.fs_old_cstotal.cs_ndir); sb.fs_old_cstotal.cs_nffree = Swapping.Swap(sb.fs_old_cstotal.cs_nffree); sb.fs_old_cstotal.cs_nifree = Swapping.Swap(sb.fs_old_cstotal.cs_nifree); sb.fs_cstotal.cs_numclusters = Swapping.Swap(sb.fs_cstotal.cs_numclusters); sb.fs_cstotal.cs_nbfree = Swapping.Swap(sb.fs_cstotal.cs_nbfree); sb.fs_cstotal.cs_ndir = Swapping.Swap(sb.fs_cstotal.cs_ndir); sb.fs_cstotal.cs_nffree = Swapping.Swap(sb.fs_cstotal.cs_nffree); sb.fs_cstotal.cs_nifree = Swapping.Swap(sb.fs_cstotal.cs_nifree); sb.fs_cstotal.cs_spare[0] = Swapping.Swap(sb.fs_cstotal.cs_spare[0]); sb.fs_cstotal.cs_spare[1] = Swapping.Swap(sb.fs_cstotal.cs_spare[1]); sb.fs_cstotal.cs_spare[2] = Swapping.Swap(sb.fs_cstotal.cs_spare[2]); } AaruConsole.DebugWriteLine("FFS plugin", "sb offset: 0x{0:X8}", sb_offset); AaruConsole.DebugWriteLine("FFS plugin", "fs_rlink: 0x{0:X8}", sb.fs_rlink); AaruConsole.DebugWriteLine("FFS plugin", "fs_sblkno: 0x{0:X8}", sb.fs_sblkno); AaruConsole.DebugWriteLine("FFS plugin", "fs_cblkno: 0x{0:X8}", sb.fs_cblkno); AaruConsole.DebugWriteLine("FFS plugin", "fs_iblkno: 0x{0:X8}", sb.fs_iblkno); AaruConsole.DebugWriteLine("FFS plugin", "fs_dblkno: 0x{0:X8}", sb.fs_dblkno); AaruConsole.DebugWriteLine("FFS plugin", "fs_size: 0x{0:X8}", sb.fs_size); AaruConsole.DebugWriteLine("FFS plugin", "fs_dsize: 0x{0:X8}", sb.fs_dsize); AaruConsole.DebugWriteLine("FFS plugin", "fs_ncg: 0x{0:X8}", sb.fs_ncg); AaruConsole.DebugWriteLine("FFS plugin", "fs_bsize: 0x{0:X8}", sb.fs_bsize); AaruConsole.DebugWriteLine("FFS plugin", "fs_fsize: 0x{0:X8}", sb.fs_fsize); AaruConsole.DebugWriteLine("FFS plugin", "fs_frag: 0x{0:X8}", sb.fs_frag); AaruConsole.DebugWriteLine("FFS plugin", "fs_minfree: 0x{0:X8}", sb.fs_minfree); AaruConsole.DebugWriteLine("FFS plugin", "fs_bmask: 0x{0:X8}", sb.fs_bmask); AaruConsole.DebugWriteLine("FFS plugin", "fs_fmask: 0x{0:X8}", sb.fs_fmask); AaruConsole.DebugWriteLine("FFS plugin", "fs_bshift: 0x{0:X8}", sb.fs_bshift); AaruConsole.DebugWriteLine("FFS plugin", "fs_fshift: 0x{0:X8}", sb.fs_fshift); AaruConsole.DebugWriteLine("FFS plugin", "fs_maxcontig: 0x{0:X8}", sb.fs_maxcontig); AaruConsole.DebugWriteLine("FFS plugin", "fs_maxbpg: 0x{0:X8}", sb.fs_maxbpg); AaruConsole.DebugWriteLine("FFS plugin", "fs_fragshift: 0x{0:X8}", sb.fs_fragshift); AaruConsole.DebugWriteLine("FFS plugin", "fs_fsbtodb: 0x{0:X8}", sb.fs_fsbtodb); AaruConsole.DebugWriteLine("FFS plugin", "fs_sbsize: 0x{0:X8}", sb.fs_sbsize); AaruConsole.DebugWriteLine("FFS plugin", "fs_csmask: 0x{0:X8}", sb.fs_csmask); AaruConsole.DebugWriteLine("FFS plugin", "fs_csshift: 0x{0:X8}", sb.fs_csshift); AaruConsole.DebugWriteLine("FFS plugin", "fs_nindir: 0x{0:X8}", sb.fs_nindir); AaruConsole.DebugWriteLine("FFS plugin", "fs_inopb: 0x{0:X8}", sb.fs_inopb); AaruConsole.DebugWriteLine("FFS plugin", "fs_optim: 0x{0:X8}", sb.fs_optim); AaruConsole.DebugWriteLine("FFS plugin", "fs_id_1: 0x{0:X8}", sb.fs_id_1); AaruConsole.DebugWriteLine("FFS plugin", "fs_id_2: 0x{0:X8}", sb.fs_id_2); AaruConsole.DebugWriteLine("FFS plugin", "fs_csaddr: 0x{0:X8}", sb.fs_csaddr); AaruConsole.DebugWriteLine("FFS plugin", "fs_cssize: 0x{0:X8}", sb.fs_cssize); AaruConsole.DebugWriteLine("FFS plugin", "fs_cgsize: 0x{0:X8}", sb.fs_cgsize); AaruConsole.DebugWriteLine("FFS plugin", "fs_ipg: 0x{0:X8}", sb.fs_ipg); AaruConsole.DebugWriteLine("FFS plugin", "fs_fpg: 0x{0:X8}", sb.fs_fpg); AaruConsole.DebugWriteLine("FFS plugin", "fs_fmod: 0x{0:X2}", sb.fs_fmod); AaruConsole.DebugWriteLine("FFS plugin", "fs_clean: 0x{0:X2}", sb.fs_clean); AaruConsole.DebugWriteLine("FFS plugin", "fs_ronly: 0x{0:X2}", sb.fs_ronly); AaruConsole.DebugWriteLine("FFS plugin", "fs_flags: 0x{0:X2}", sb.fs_flags); AaruConsole.DebugWriteLine("FFS plugin", "fs_magic: 0x{0:X8}", sb.fs_magic); if (sb.fs_magic == UFS2_MAGIC) { fs_type_ufs2 = true; } else { const uint SunOSEpoch = 0x1A54C580; // We are supposing there cannot be a Sun's fs created before 1/1/1982 00:00:00 fs_type_43bsd = true; // There is no way of knowing this is the version, but there is of knowing it is not. if (sb.fs_link > 0) { fs_type_42bsd = true; // It was used in 4.2BSD fs_type_43bsd = false; } if ((sb.fs_maxfilesize & 0xFFFFFFFF) > SunOSEpoch && DateHandlers.UnixUnsignedToDateTime(sb.fs_maxfilesize & 0xFFFFFFFF) < DateTime.Now) { fs_type_42bsd = false; fs_type_sun = true; fs_type_43bsd = false; } // This is for sure, as it is shared with a sectors/track with non-x86 SunOS, Epoch is absurdly high for that if (sb.fs_old_npsect > SunOSEpoch && DateHandlers.UnixToDateTime(sb.fs_old_npsect) < DateTime.Now) { fs_type_42bsd = false; fs_type_sun86 = true; fs_type_sun = false; fs_type_43bsd = false; } if (sb.fs_cgrotor > 0x00000000 && (uint)sb.fs_cgrotor < 0xFFFFFFFF) { fs_type_42bsd = false; fs_type_sun = false; fs_type_sun86 = false; fs_type_ufs = true; fs_type_43bsd = false; } // 4.3BSD code does not use these fields, they are always set up to 0 fs_type_43bsd &= sb.fs_id_2 == 0 && sb.fs_id_1 == 0; // This is the only 4.4BSD inode format fs_type_44bsd |= sb.fs_old_inodefmt == 2; } if (!fs_type_ufs2) { sbInformation.AppendLine("There are a lot of variants of UFS using overlapped values on same fields"); sbInformation. AppendLine("I will try to guess which one it is, but unless it's UFS2, I may be surely wrong"); } if (fs_type_42bsd) { sbInformation.AppendLine("Guessed as 42BSD FFS"); } if (fs_type_43bsd) { sbInformation.AppendLine("Guessed as 43BSD FFS"); } if (fs_type_44bsd) { sbInformation.AppendLine("Guessed as 44BSD FFS"); } if (fs_type_sun) { sbInformation.AppendLine("Guessed as SunOS FFS"); } if (fs_type_sun86) { sbInformation.AppendLine("Guessed as SunOS/x86 FFS"); } if (fs_type_ufs) { sbInformation.AppendLine("Guessed as UFS"); } if (fs_type_42bsd) { sbInformation.AppendFormat("Linked list of filesystems: 0x{0:X8}", sb.fs_link).AppendLine(); } sbInformation.AppendFormat("Superblock LBA: {0}", sb.fs_sblkno).AppendLine(); sbInformation.AppendFormat("Cylinder-block LBA: {0}", sb.fs_cblkno).AppendLine(); sbInformation.AppendFormat("inode-block LBA: {0}", sb.fs_iblkno).AppendLine(); sbInformation.AppendFormat("First data block LBA: {0}", sb.fs_dblkno).AppendLine(); sbInformation.AppendFormat("Cylinder group offset in cylinder: {0}", sb.fs_old_cgoffset).AppendLine(); sbInformation.AppendFormat("Volume last written on {0}", DateHandlers.UnixToDateTime(sb.fs_old_time)). AppendLine(); XmlFsType.ModificationDate = DateHandlers.UnixToDateTime(sb.fs_old_time); XmlFsType.ModificationDateSpecified = true; sbInformation.AppendFormat("{0} blocks in volume ({1} bytes)", sb.fs_old_size, (long)sb.fs_old_size * sb.fs_fsize).AppendLine(); XmlFsType.Clusters = (ulong)sb.fs_old_size; XmlFsType.ClusterSize = (uint)sb.fs_fsize; sbInformation.AppendFormat("{0} data blocks in volume ({1} bytes)", sb.fs_old_dsize, (long)sb.fs_old_dsize * sb.fs_fsize).AppendLine(); sbInformation.AppendFormat("{0} cylinder groups in volume", sb.fs_ncg).AppendLine(); sbInformation.AppendFormat("{0} bytes in a basic block", sb.fs_bsize).AppendLine(); sbInformation.AppendFormat("{0} bytes in a frag block", sb.fs_fsize).AppendLine(); sbInformation.AppendFormat("{0} frags in a block", sb.fs_frag).AppendLine(); sbInformation.AppendFormat("{0}% of blocks must be free", sb.fs_minfree).AppendLine(); sbInformation.AppendFormat("{0}ms for optimal next block", sb.fs_old_rotdelay).AppendLine(); sbInformation.AppendFormat("disk rotates {0} times per second ({1}rpm)", sb.fs_old_rps, sb.fs_old_rps * 60). AppendLine(); /* sbInformation.AppendFormat("fs_bmask: 0x{0:X8}", sb.fs_bmask).AppendLine(); * sbInformation.AppendFormat("fs_fmask: 0x{0:X8}", sb.fs_fmask).AppendLine(); * sbInformation.AppendFormat("fs_bshift: 0x{0:X8}", sb.fs_bshift).AppendLine(); * sbInformation.AppendFormat("fs_fshift: 0x{0:X8}", sb.fs_fshift).AppendLine();*/ sbInformation.AppendFormat("{0} contiguous blocks at maximum", sb.fs_maxcontig).AppendLine(); sbInformation.AppendFormat("{0} blocks per cylinder group at maximum", sb.fs_maxbpg).AppendLine(); sbInformation.AppendFormat("Superblock is {0} bytes", sb.fs_sbsize).AppendLine(); sbInformation.AppendFormat("NINDIR: 0x{0:X8}", sb.fs_nindir).AppendLine(); sbInformation.AppendFormat("INOPB: 0x{0:X8}", sb.fs_inopb).AppendLine(); sbInformation.AppendFormat("NSPF: 0x{0:X8}", sb.fs_old_nspf).AppendLine(); switch (sb.fs_optim) { case 0: sbInformation.AppendLine("Filesystem will minimize allocation time"); break; case 1: sbInformation.AppendLine("Filesystem will minimize volume fragmentation"); break; default: sbInformation.AppendFormat("Unknown optimization value: 0x{0:X8}", sb.fs_optim).AppendLine(); break; } if (fs_type_sun) { sbInformation.AppendFormat("{0} sectors/track", sb.fs_old_npsect).AppendLine(); } else if (fs_type_sun86) { sbInformation.AppendFormat("Volume state on {0}", DateHandlers.UnixToDateTime(sb.fs_old_npsect)). AppendLine(); } sbInformation.AppendFormat("Hardware sector interleave: {0}", sb.fs_old_interleave).AppendLine(); sbInformation.AppendFormat("Sector 0 skew: {0}/track", sb.fs_old_trackskew).AppendLine(); if (!fs_type_43bsd && sb.fs_id_1 > 0 && sb.fs_id_2 > 0) { sbInformation.AppendFormat("Volume ID: 0x{0:X8}{1:X8}", sb.fs_id_1, sb.fs_id_2).AppendLine(); } else if (fs_type_43bsd && sb.fs_id_1 > 0 && sb.fs_id_2 > 0) { sbInformation.AppendFormat("{0} µsec for head switch", sb.fs_id_1).AppendLine(); sbInformation.AppendFormat("{0} µsec for track-to-track seek", sb.fs_id_2).AppendLine(); } sbInformation.AppendFormat("Cylinder group summary LBA: {0}", sb.fs_old_csaddr).AppendLine(); sbInformation.AppendFormat("{0} bytes in cylinder group summary", sb.fs_cssize).AppendLine(); sbInformation.AppendFormat("{0} bytes in cylinder group", sb.fs_cgsize).AppendLine(); sbInformation.AppendFormat("{0} tracks/cylinder", sb.fs_old_ntrak).AppendLine(); sbInformation.AppendFormat("{0} sectors/track", sb.fs_old_nsect).AppendLine(); sbInformation.AppendFormat("{0} sectors/cylinder", sb.fs_old_spc).AppendLine(); sbInformation.AppendFormat("{0} cylinder in volume", sb.fs_old_ncyl).AppendLine(); sbInformation.AppendFormat("{0} cylinders/group", sb.fs_old_cpg).AppendLine(); sbInformation.AppendFormat("{0} inodes per cylinder group", sb.fs_ipg).AppendLine(); sbInformation.AppendFormat("{0} blocks per group", sb.fs_fpg / sb.fs_frag).AppendLine(); sbInformation.AppendFormat("{0} directories", sb.fs_old_cstotal.cs_ndir).AppendLine(); sbInformation.AppendFormat("{0} free blocks ({1} bytes)", sb.fs_old_cstotal.cs_nbfree, (long)sb.fs_old_cstotal.cs_nbfree * sb.fs_fsize).AppendLine(); XmlFsType.FreeClusters = (ulong)sb.fs_old_cstotal.cs_nbfree; XmlFsType.FreeClustersSpecified = true; sbInformation.AppendFormat("{0} free inodes", sb.fs_old_cstotal.cs_nifree).AppendLine(); sbInformation.AppendFormat("{0} free frags", sb.fs_old_cstotal.cs_nffree).AppendLine(); if (sb.fs_fmod == 1) { sbInformation.AppendLine("Superblock is under modification"); XmlFsType.Dirty = true; } if (sb.fs_clean == 1) { sbInformation.AppendLine("Volume is clean"); } if (sb.fs_ronly == 1) { sbInformation.AppendLine("Volume is read-only"); } sbInformation.AppendFormat("Volume flags: 0x{0:X2}", sb.fs_flags).AppendLine(); if (fs_type_ufs) { sbInformation.AppendFormat("Volume last mounted on \"{0}\"", StringHandlers.CToString(sb.fs_fsmnt)). AppendLine(); } else if (fs_type_ufs2) { sbInformation.AppendFormat("Volume last mounted on \"{0}\"", StringHandlers.CToString(sb.fs_fsmnt)). AppendLine(); sbInformation.AppendFormat("Volume name: \"{0}\"", StringHandlers.CToString(sb.fs_volname)). AppendLine(); XmlFsType.VolumeName = StringHandlers.CToString(sb.fs_volname); sbInformation.AppendFormat("Volume ID: 0x{0:X16}", sb.fs_swuid).AppendLine(); //xmlFSType.VolumeSerial = string.Format("{0:X16}", sb.fs_swuid); sbInformation.AppendFormat("Last searched cylinder group: {0}", sb.fs_cgrotor).AppendLine(); sbInformation.AppendFormat("{0} contiguously allocated directories", sb.fs_contigdirs).AppendLine(); sbInformation.AppendFormat("Standard superblock LBA: {0}", sb.fs_sblkno).AppendLine(); sbInformation.AppendFormat("{0} directories", sb.fs_cstotal.cs_ndir).AppendLine(); sbInformation.AppendFormat("{0} free blocks ({1} bytes)", sb.fs_cstotal.cs_nbfree, sb.fs_cstotal.cs_nbfree * sb.fs_fsize).AppendLine(); XmlFsType.FreeClusters = (ulong)sb.fs_cstotal.cs_nbfree; XmlFsType.FreeClustersSpecified = true; sbInformation.AppendFormat("{0} free inodes", sb.fs_cstotal.cs_nifree).AppendLine(); sbInformation.AppendFormat("{0} free frags", sb.fs_cstotal.cs_nffree).AppendLine(); sbInformation.AppendFormat("{0} free clusters", sb.fs_cstotal.cs_numclusters).AppendLine(); sbInformation.AppendFormat("Volume last written on {0}", DateHandlers.UnixToDateTime(sb.fs_time)). AppendLine(); XmlFsType.ModificationDate = DateHandlers.UnixToDateTime(sb.fs_time); XmlFsType.ModificationDateSpecified = true; sbInformation.AppendFormat("{0} blocks ({1} bytes)", sb.fs_size, sb.fs_size * sb.fs_fsize).AppendLine(); XmlFsType.Clusters = (ulong)sb.fs_size; sbInformation.AppendFormat("{0} data blocks ({1} bytes)", sb.fs_dsize, sb.fs_dsize * sb.fs_fsize). AppendLine(); sbInformation.AppendFormat("Cylinder group summary area LBA: {0}", sb.fs_csaddr).AppendLine(); sbInformation.AppendFormat("{0} blocks pending of being freed", sb.fs_pendingblocks).AppendLine(); sbInformation.AppendFormat("{0} inodes pending of being freed", sb.fs_pendinginodes).AppendLine(); } if (fs_type_sun) { sbInformation.AppendFormat("Volume state on {0}", DateHandlers.UnixToDateTime(sb.fs_old_npsect)). AppendLine(); } else if (fs_type_sun86) { sbInformation.AppendFormat("{0} sectors/track", sb.fs_state).AppendLine(); } else if (fs_type_44bsd) { sbInformation.AppendFormat("{0} blocks on cluster summary array", sb.fs_contigsumsize).AppendLine(); sbInformation.AppendFormat("Maximum length of a symbolic link: {0}", sb.fs_maxsymlinklen).AppendLine(); sbInformation.AppendFormat("A file can be {0} bytes at max", sb.fs_maxfilesize).AppendLine(); sbInformation.AppendFormat("Volume state on {0}", DateHandlers.UnixToDateTime(sb.fs_state)). AppendLine(); } if (sb.fs_old_nrpos > 0) { sbInformation.AppendFormat("{0} rotational positions", sb.fs_old_nrpos).AppendLine(); } if (sb.fs_old_rotbloff > 0) { sbInformation.AppendFormat("{0} blocks per rotation", sb.fs_old_rotbloff).AppendLine(); } information = sbInformation.ToString(); }
public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information, Encoding encoding) { Encoding = encoding ?? Encoding.GetEncoding("iso-8859-15"); information = ""; var sb = new StringBuilder(); SuperBlock superBlock; uint run = HAMMER_VOLHDR_SIZE / imagePlugin.Info.SectorSize; if (HAMMER_VOLHDR_SIZE % imagePlugin.Info.SectorSize > 0) { run++; } byte[] sbSector = imagePlugin.ReadSectors(partition.Start, run); ulong magic = BitConverter.ToUInt64(sbSector, 0); superBlock = magic == HAMMER_FSBUF_VOLUME?Marshal.ByteArrayToStructureLittleEndian <SuperBlock>(sbSector) : Marshal.ByteArrayToStructureBigEndian <SuperBlock>(sbSector); sb.AppendLine("HAMMER filesystem"); sb.AppendFormat("Volume version: {0}", superBlock.vol_version).AppendLine(); sb.AppendFormat("Volume {0} of {1} on this filesystem", superBlock.vol_no + 1, superBlock.vol_count). AppendLine(); sb.AppendFormat("Volume name: {0}", StringHandlers.CToString(superBlock.vol_label, Encoding)).AppendLine(); sb.AppendFormat("Volume serial: {0}", superBlock.vol_fsid).AppendLine(); sb.AppendFormat("Filesystem type: {0}", superBlock.vol_fstype).AppendLine(); sb.AppendFormat("Boot area starts at {0}", superBlock.vol_bot_beg).AppendLine(); sb.AppendFormat("Memory log starts at {0}", superBlock.vol_mem_beg).AppendLine(); sb.AppendFormat("First volume buffer starts at {0}", superBlock.vol_buf_beg).AppendLine(); sb.AppendFormat("Volume ends at {0}", superBlock.vol_buf_end).AppendLine(); XmlFsType = new FileSystemType { Clusters = partition.Size / HAMMER_BIGBLOCK_SIZE, ClusterSize = HAMMER_BIGBLOCK_SIZE, Dirty = false, Type = "HAMMER", VolumeName = StringHandlers.CToString(superBlock.vol_label, Encoding), VolumeSerial = superBlock.vol_fsid.ToString() }; if (superBlock.vol_no == superBlock.vol_rootvol) { sb.AppendFormat("Filesystem contains {0} \"big-blocks\" ({1} bytes)", superBlock.vol0_stat_bigblocks, superBlock.vol0_stat_bigblocks * HAMMER_BIGBLOCK_SIZE).AppendLine(); sb.AppendFormat("Filesystem has {0} \"big-blocks\" free ({1} bytes)", superBlock.vol0_stat_freebigblocks, superBlock.vol0_stat_freebigblocks * HAMMER_BIGBLOCK_SIZE).AppendLine(); sb.AppendFormat("Filesystem has {0} inode used", superBlock.vol0_stat_inodes).AppendLine(); XmlFsType.Clusters = (ulong)superBlock.vol0_stat_bigblocks; XmlFsType.FreeClusters = (ulong)superBlock.vol0_stat_freebigblocks; XmlFsType.FreeClustersSpecified = true; XmlFsType.Files = (ulong)superBlock.vol0_stat_inodes; XmlFsType.FilesSpecified = true; } // 0 ? //sb.AppendFormat("Volume header CRC: 0x{0:X8}", afs_sb.vol_crc).AppendLine(); information = sb.ToString(); }
public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information, Encoding encoding) { Encoding = encoding ?? Encoding.GetEncoding("iso-8859-15"); information = ""; if (imagePlugin.Info.SectorSize < 512) { return; } var locusSb = new Superblock(); byte[] sector = null; for (ulong location = 0; location <= 8; location++) { uint sbSize = (uint)(Marshal.SizeOf <Superblock>() / imagePlugin.Info.SectorSize); if (Marshal.SizeOf <Superblock>() % imagePlugin.Info.SectorSize != 0) { sbSize++; } sector = imagePlugin.ReadSectors(partition.Start + location, sbSize); if (sector.Length < Marshal.SizeOf <Superblock>()) { return; } locusSb = Marshal.ByteArrayToStructureLittleEndian <Superblock>(sector); if (locusSb.s_magic == LOCUS_MAGIC || locusSb.s_magic == LOCUS_CIGAM || locusSb.s_magic == LOCUS_MAGIC_OLD || locusSb.s_magic == LOCUS_CIGAM_OLD) { break; } } // We don't care about old version for information if (locusSb.s_magic != LOCUS_MAGIC && locusSb.s_magic != LOCUS_CIGAM && locusSb.s_magic != LOCUS_MAGIC_OLD && locusSb.s_magic != LOCUS_CIGAM_OLD) { return; } // Numerical arrays are not important for information so no need to swap them if (locusSb.s_magic == LOCUS_CIGAM || locusSb.s_magic == LOCUS_CIGAM_OLD) { locusSb = Marshal.ByteArrayToStructureBigEndian <Superblock>(sector); locusSb.s_flags = (Flags)Swapping.Swap((ushort)locusSb.s_flags); } var sb = new StringBuilder(); sb.AppendLine(locusSb.s_magic == LOCUS_MAGIC_OLD ? "Locus filesystem (old)" : "Locus filesystem"); int blockSize = locusSb.s_version == Version.SB_SB4096 ? 4096 : 1024; string s_fsmnt = StringHandlers.CToString(locusSb.s_fsmnt, Encoding); string s_fpack = StringHandlers.CToString(locusSb.s_fpack, Encoding); AaruConsole.DebugWriteLine("Locus plugin", "LocusSb.s_magic = 0x{0:X8}", locusSb.s_magic); AaruConsole.DebugWriteLine("Locus plugin", "LocusSb.s_gfs = {0}", locusSb.s_gfs); AaruConsole.DebugWriteLine("Locus plugin", "LocusSb.s_fsize = {0}", locusSb.s_fsize); AaruConsole.DebugWriteLine("Locus plugin", "LocusSb.s_lwm = {0}", locusSb.s_lwm); AaruConsole.DebugWriteLine("Locus plugin", "LocusSb.s_hwm = {0}", locusSb.s_hwm); AaruConsole.DebugWriteLine("Locus plugin", "LocusSb.s_llst = {0}", locusSb.s_llst); AaruConsole.DebugWriteLine("Locus plugin", "LocusSb.s_fstore = {0}", locusSb.s_fstore); AaruConsole.DebugWriteLine("Locus plugin", "LocusSb.s_time = {0}", locusSb.s_time); AaruConsole.DebugWriteLine("Locus plugin", "LocusSb.s_tfree = {0}", locusSb.s_tfree); AaruConsole.DebugWriteLine("Locus plugin", "LocusSb.s_isize = {0}", locusSb.s_isize); AaruConsole.DebugWriteLine("Locus plugin", "LocusSb.s_nfree = {0}", locusSb.s_nfree); AaruConsole.DebugWriteLine("Locus plugin", "LocusSb.s_flags = {0}", locusSb.s_flags); AaruConsole.DebugWriteLine("Locus plugin", "LocusSb.s_tinode = {0}", locusSb.s_tinode); AaruConsole.DebugWriteLine("Locus plugin", "LocusSb.s_lasti = {0}", locusSb.s_lasti); AaruConsole.DebugWriteLine("Locus plugin", "LocusSb.s_nbehind = {0}", locusSb.s_nbehind); AaruConsole.DebugWriteLine("Locus plugin", "LocusSb.s_gfspack = {0}", locusSb.s_gfspack); AaruConsole.DebugWriteLine("Locus plugin", "LocusSb.s_ninode = {0}", locusSb.s_ninode); AaruConsole.DebugWriteLine("Locus plugin", "LocusSb.s_flock = {0}", locusSb.s_flock); AaruConsole.DebugWriteLine("Locus plugin", "LocusSb.s_ilock = {0}", locusSb.s_ilock); AaruConsole.DebugWriteLine("Locus plugin", "LocusSb.s_fmod = {0}", locusSb.s_fmod); AaruConsole.DebugWriteLine("Locus plugin", "LocusSb.s_version = {0}", locusSb.s_version); sb.AppendFormat("Superblock last modified on {0}", DateHandlers.UnixToDateTime(locusSb.s_time)). AppendLine(); sb.AppendFormat("Volume has {0} blocks of {1} bytes each (total {2} bytes)", locusSb.s_fsize, blockSize, locusSb.s_fsize * blockSize).AppendLine(); sb.AppendFormat("{0} blocks free ({1} bytes)", locusSb.s_tfree, locusSb.s_tfree * blockSize).AppendLine(); sb.AppendFormat("I-node list uses {0} blocks", locusSb.s_isize).AppendLine(); sb.AppendFormat("{0} free inodes", locusSb.s_tinode).AppendLine(); sb.AppendFormat("Next free inode search will start at inode {0}", locusSb.s_lasti).AppendLine(); sb.AppendFormat("There are an estimate of {0} free inodes before next search start", locusSb.s_nbehind). AppendLine(); if (locusSb.s_flags.HasFlag(Flags.SB_RDONLY)) { sb.AppendLine("Read-only volume"); } if (locusSb.s_flags.HasFlag(Flags.SB_CLEAN)) { sb.AppendLine("Clean volume"); } if (locusSb.s_flags.HasFlag(Flags.SB_DIRTY)) { sb.AppendLine("Dirty volume"); } if (locusSb.s_flags.HasFlag(Flags.SB_RMV)) { sb.AppendLine("Removable volume"); } if (locusSb.s_flags.HasFlag(Flags.SB_PRIMPACK)) { sb.AppendLine("This is the primary pack"); } if (locusSb.s_flags.HasFlag(Flags.SB_REPLTYPE)) { sb.AppendLine("Replicated volume"); } if (locusSb.s_flags.HasFlag(Flags.SB_USER)) { sb.AppendLine("User replicated volume"); } if (locusSb.s_flags.HasFlag(Flags.SB_BACKBONE)) { sb.AppendLine("Backbone volume"); } if (locusSb.s_flags.HasFlag(Flags.SB_NFS)) { sb.AppendLine("NFS volume"); } if (locusSb.s_flags.HasFlag(Flags.SB_BYHAND)) { sb.AppendLine("Volume inhibits automatic fsck"); } if (locusSb.s_flags.HasFlag(Flags.SB_NOSUID)) { sb.AppendLine("Set-uid/set-gid is disabled"); } if (locusSb.s_flags.HasFlag(Flags.SB_SYNCW)) { sb.AppendLine("Volume uses synchronous writes"); } sb.AppendFormat("Volume label: {0}", s_fsmnt).AppendLine(); sb.AppendFormat("Physical volume name: {0}", s_fpack).AppendLine(); sb.AppendFormat("Global File System number: {0}", locusSb.s_gfs).AppendLine(); sb.AppendFormat("Global File System pack number {0}", locusSb.s_gfspack).AppendLine(); information = sb.ToString(); XmlFsType = new FileSystemType { Type = "Locus filesystem", ClusterSize = (uint)blockSize, Clusters = (ulong)locusSb.s_fsize, // Sometimes it uses one, or the other. Use the bigger VolumeName = string.IsNullOrEmpty(s_fsmnt) ? s_fpack : s_fsmnt, ModificationDate = DateHandlers.UnixToDateTime(locusSb.s_time), ModificationDateSpecified = true, Dirty = !locusSb.s_flags.HasFlag(Flags.SB_CLEAN) || locusSb.s_flags.HasFlag(Flags.SB_DIRTY), FreeClusters = (ulong)locusSb.s_tfree, FreeClustersSpecified = true }; }
public bool Identify(IMediaImage imagePlugin, Partition partition) { if (partition.Start >= partition.End) { return(false); } // Boot block is unless defined otherwise, 2 blocks // Funny, you may need boot block to find root block if it's not in standard place just to know size of // block size and then read the whole boot block. // However while you can set a block size different from the sector size on formatting, the bootblock block // size for floppies is the sector size, and for RDB is usually is the hard disk sector size, // so this is not entirely wrong... byte[] sector = imagePlugin.ReadSectors(0 + partition.Start, 2); BootBlock bblk = Marshal.ByteArrayToStructureBigEndian <BootBlock>(sector); // AROS boot floppies... if (sector.Length >= 512 && sector[510] == 0x55 && sector[511] == 0xAA && (bblk.diskType & FFS_MASK) != FFS_MASK && (bblk.diskType & MUFS_MASK) != MUFS_MASK) { sector = imagePlugin.ReadSectors(1 + partition.Start, 2); bblk = Marshal.ByteArrayToStructureBigEndian <BootBlock>(sector); } // Not FFS or MuFS? if ((bblk.diskType & FFS_MASK) != FFS_MASK && (bblk.diskType & MUFS_MASK) != MUFS_MASK) { return(false); } // Clear checksum on sector sector[4] = sector[5] = sector[6] = sector[7] = 0; uint bsum = AmigaBootChecksum(sector); AaruConsole.DebugWriteLine("AmigaDOS plugin", "bblk.checksum = 0x{0:X8}", bblk.checksum); AaruConsole.DebugWriteLine("AmigaDOS plugin", "bsum = 0x{0:X8}", bsum); ulong bRootPtr = 0; // If bootblock is correct, let's take its rootblock pointer if (bsum == bblk.checksum) { bRootPtr = bblk.root_ptr + partition.Start; AaruConsole.DebugWriteLine("AmigaDOS plugin", "Bootblock points to {0} as Rootblock", bRootPtr); } ulong[] rootPtrs = { bRootPtr + partition.Start, ((((partition.End - partition.Start) + 1) / 2) + partition.Start) - 2, ((((partition.End - partition.Start) + 1) / 2) + partition.Start) - 1, (((partition.End - partition.Start) + 1) / 2) + partition.Start, (((partition.End - partition.Start) + 1) / 2) + partition.Start + 4 }; var rblk = new RootBlock(); // So to handle even number of sectors foreach (ulong rootPtr in rootPtrs.Where(rootPtr => rootPtr < partition.End && rootPtr >= partition.Start)) { AaruConsole.DebugWriteLine("AmigaDOS plugin", "Searching for Rootblock in sector {0}", rootPtr); sector = imagePlugin.ReadSector(rootPtr); rblk.type = BigEndianBitConverter.ToUInt32(sector, 0x00); AaruConsole.DebugWriteLine("AmigaDOS plugin", "rblk.type = {0}", rblk.type); if (rblk.type != TYPE_HEADER) { continue; } rblk.hashTableSize = BigEndianBitConverter.ToUInt32(sector, 0x0C); AaruConsole.DebugWriteLine("AmigaDOS plugin", "rblk.hashTableSize = {0}", rblk.hashTableSize); uint blockSize = (rblk.hashTableSize + 56) * 4; uint sectorsPerBlock = (uint)(blockSize / sector.Length); AaruConsole.DebugWriteLine("AmigaDOS plugin", "blockSize = {0}", blockSize); AaruConsole.DebugWriteLine("AmigaDOS plugin", "sectorsPerBlock = {0}", sectorsPerBlock); if (blockSize % sector.Length > 0) { sectorsPerBlock++; } if (rootPtr + sectorsPerBlock >= partition.End) { continue; } sector = imagePlugin.ReadSectors(rootPtr, sectorsPerBlock); // Clear checksum on sector rblk.checksum = BigEndianBitConverter.ToUInt32(sector, 20); sector[20] = sector[21] = sector[22] = sector[23] = 0; uint rsum = AmigaChecksum(sector); AaruConsole.DebugWriteLine("AmigaDOS plugin", "rblk.checksum = 0x{0:X8}", rblk.checksum); AaruConsole.DebugWriteLine("AmigaDOS plugin", "rsum = 0x{0:X8}", rsum); rblk.sec_type = BigEndianBitConverter.ToUInt32(sector, sector.Length - 4); AaruConsole.DebugWriteLine("AmigaDOS plugin", "rblk.sec_type = {0}", rblk.sec_type); if (rblk.sec_type == SUBTYPE_ROOT && rblk.checksum == rsum) { return(true); } } return(false); }
public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information, Encoding encoding) { Encoding = encoding ?? Encoding.GetEncoding("iso-8859-15"); information = ""; if (imagePlugin.Info.SectorSize < 512) { return; } uint sbSize = (uint)(Marshal.SizeOf <Superblock>() / imagePlugin.Info.SectorSize); if (Marshal.SizeOf <Superblock>() % imagePlugin.Info.SectorSize != 0) { sbSize++; } byte[] sector = imagePlugin.ReadSectors(partition.Start, sbSize); if (sector.Length < Marshal.SizeOf <Superblock>()) { return; } Superblock unicosSb = Marshal.ByteArrayToStructureBigEndian <Superblock>(sector); if (unicosSb.s_magic != UNICOS_MAGIC) { return; } var sb = new StringBuilder(); sb.AppendLine("UNICOS filesystem"); if (unicosSb.s_secure == UNICOS_SECURE) { sb.AppendLine("Volume is secure"); } sb.AppendFormat("Volume contains {0} partitions", unicosSb.s_npart).AppendLine(); sb.AppendFormat("{0} bytes per sector", unicosSb.s_iounit).AppendLine(); sb.AppendLine("4096 bytes per block"); sb.AppendFormat("{0} data blocks in volume", unicosSb.s_fsize).AppendLine(); sb.AppendFormat("Root resides on inode {0}", unicosSb.s_root).AppendLine(); sb.AppendFormat("{0} inodes in volume", unicosSb.s_isize).AppendLine(); sb.AppendFormat("Volume last updated on {0}", DateHandlers.UnixToDateTime(unicosSb.s_time)).AppendLine(); if (unicosSb.s_error > 0) { sb.AppendFormat("Volume is dirty, error code = 0x{0:X16}", unicosSb.s_error).AppendLine(); } sb.AppendFormat("Volume name: {0}", StringHandlers.CToString(unicosSb.s_fname, Encoding)).AppendLine(); information = sb.ToString(); XmlFsType = new FileSystemType { Type = "UNICOS filesystem", ClusterSize = 4096, Clusters = (ulong)unicosSb.s_fsize, VolumeName = StringHandlers.CToString(unicosSb.s_fname, Encoding), ModificationDate = DateHandlers.UnixToDateTime(unicosSb.s_time), ModificationDateSpecified = true }; XmlFsType.Dirty |= unicosSb.s_error > 0; }
public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information, Encoding encoding) { Encoding = encoding ?? Encoding.GetEncoding("iso-8859-15"); information = ""; if (imagePlugin.Info.SectorSize < 512) { return; } if (partition.Start != 0) { return; } uint sbSize = (uint)(Marshal.SizeOf <s_spcl>() / imagePlugin.Info.SectorSize); if (Marshal.SizeOf <s_spcl>() % imagePlugin.Info.SectorSize != 0) { sbSize++; } byte[] sector = imagePlugin.ReadSectors(partition.Start, sbSize); if (sector.Length < Marshal.SizeOf <s_spcl>()) { return; } spcl16 oldHdr = Marshal.ByteArrayToStructureLittleEndian <spcl16>(sector); spcl_aix aixHdr = Marshal.ByteArrayToStructureLittleEndian <spcl_aix>(sector); s_spcl newHdr = Marshal.ByteArrayToStructureLittleEndian <s_spcl>(sector); bool useOld = false; bool useAix = false; if (newHdr.c_magic == OFS_MAGIC || newHdr.c_magic == NFS_MAGIC || newHdr.c_magic == OFS_CIGAM || newHdr.c_magic == NFS_CIGAM || newHdr.c_magic == UFS2_MAGIC || newHdr.c_magic == UFS2_CIGAM) { if (newHdr.c_magic == OFS_CIGAM || newHdr.c_magic == NFS_CIGAM || newHdr.c_magic == UFS2_CIGAM) { newHdr = Marshal.ByteArrayToStructureBigEndian <s_spcl>(sector); } } else if (aixHdr.c_magic == XIX_MAGIC || aixHdr.c_magic == XIX_CIGAM) { useAix = true; if (aixHdr.c_magic == XIX_CIGAM) { aixHdr = Marshal.ByteArrayToStructureBigEndian <spcl_aix>(sector); } } else if (oldHdr.c_magic == OFS_MAGIC) { useOld = true; // Swap PDP-11 endian oldHdr.c_date = (int)Swapping.PDPFromLittleEndian((uint)oldHdr.c_date); oldHdr.c_ddate = (int)Swapping.PDPFromLittleEndian((uint)oldHdr.c_ddate); } else { information = "Could not read dump(8) header block"; return; } var sb = new StringBuilder(); XmlFsType = new FileSystemType { ClusterSize = 1024, Clusters = partition.Size / 1024 }; if (useOld) { XmlFsType.Type = "Old 16-bit dump(8)"; sb.AppendLine(XmlFsType.Type); if (oldHdr.c_date > 0) { XmlFsType.CreationDate = DateHandlers.UnixToDateTime(oldHdr.c_date); XmlFsType.CreationDateSpecified = true; sb.AppendFormat("Dump created on {0}", XmlFsType.CreationDate).AppendLine(); } if (oldHdr.c_ddate > 0) { XmlFsType.BackupDate = DateHandlers.UnixToDateTime(oldHdr.c_ddate); XmlFsType.BackupDateSpecified = true; sb.AppendFormat("Previous dump created on {0}", XmlFsType.BackupDate).AppendLine(); } sb.AppendFormat("Dump volume number: {0}", oldHdr.c_volume).AppendLine(); } else if (useAix) { XmlFsType.Type = "AIX dump(8)"; sb.AppendLine(XmlFsType.Type); if (aixHdr.c_date > 0) { XmlFsType.CreationDate = DateHandlers.UnixToDateTime(aixHdr.c_date); XmlFsType.CreationDateSpecified = true; sb.AppendFormat("Dump created on {0}", XmlFsType.CreationDate).AppendLine(); } if (aixHdr.c_ddate > 0) { XmlFsType.BackupDate = DateHandlers.UnixToDateTime(aixHdr.c_ddate); XmlFsType.BackupDateSpecified = true; sb.AppendFormat("Previous dump created on {0}", XmlFsType.BackupDate).AppendLine(); } sb.AppendFormat("Dump volume number: {0}", aixHdr.c_volume).AppendLine(); } else { XmlFsType.Type = "dump(8)"; sb.AppendLine(XmlFsType.Type); if (newHdr.c_ndate > 0) { XmlFsType.CreationDate = DateHandlers.UnixToDateTime(newHdr.c_ndate); XmlFsType.CreationDateSpecified = true; sb.AppendFormat("Dump created on {0}", XmlFsType.CreationDate).AppendLine(); } else if (newHdr.c_date > 0) { XmlFsType.CreationDate = DateHandlers.UnixToDateTime(newHdr.c_date); XmlFsType.CreationDateSpecified = true; sb.AppendFormat("Dump created on {0}", XmlFsType.CreationDate).AppendLine(); } if (newHdr.c_nddate > 0) { XmlFsType.BackupDate = DateHandlers.UnixToDateTime(newHdr.c_nddate); XmlFsType.BackupDateSpecified = true; sb.AppendFormat("Previous dump created on {0}", XmlFsType.BackupDate).AppendLine(); } else if (newHdr.c_ddate > 0) { XmlFsType.BackupDate = DateHandlers.UnixToDateTime(newHdr.c_ddate); XmlFsType.BackupDateSpecified = true; sb.AppendFormat("Previous dump created on {0}", XmlFsType.BackupDate).AppendLine(); } sb.AppendFormat("Dump volume number: {0}", newHdr.c_volume).AppendLine(); sb.AppendFormat("Dump level: {0}", newHdr.c_level).AppendLine(); string dumpname = StringHandlers.CToString(newHdr.c_label); if (!string.IsNullOrEmpty(dumpname)) { XmlFsType.VolumeName = dumpname; sb.AppendFormat("Dump label: {0}", dumpname).AppendLine(); } string str = StringHandlers.CToString(newHdr.c_filesys); if (!string.IsNullOrEmpty(str)) { sb.AppendFormat("Dumped filesystem name: {0}", str).AppendLine(); } str = StringHandlers.CToString(newHdr.c_dev); if (!string.IsNullOrEmpty(str)) { sb.AppendFormat("Dumped device: {0}", str).AppendLine(); } str = StringHandlers.CToString(newHdr.c_host); if (!string.IsNullOrEmpty(str)) { sb.AppendFormat("Dump hostname: {0}", str).AppendLine(); } } information = sb.ToString(); }
public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information, Encoding encoding) { Encoding = encoding ?? Encoding.GetEncoding("iso-8859-1"); var sbInformation = new StringBuilder(); XmlFsType = new FileSystemType(); information = null; byte[] bootBlockSectors = imagePlugin.ReadSectors(0 + partition.Start, 2); BootBlock bootBlk = Marshal.ByteArrayToStructureBigEndian <BootBlock>(bootBlockSectors); bootBlk.bootCode = new byte[bootBlockSectors.Length - 12]; Array.Copy(bootBlockSectors, 12, bootBlk.bootCode, 0, bootBlk.bootCode.Length); bootBlockSectors[4] = bootBlockSectors[5] = bootBlockSectors[6] = bootBlockSectors[7] = 0; uint bsum = AmigaBootChecksum(bootBlockSectors); ulong bRootPtr = 0; // If bootblock is correct, let's take its rootblock pointer if (bsum == bootBlk.checksum) { bRootPtr = bootBlk.root_ptr + partition.Start; AaruConsole.DebugWriteLine("AmigaDOS plugin", "Bootblock points to {0} as Rootblock", bRootPtr); } ulong[] rootPtrs = { bRootPtr + partition.Start, ((((partition.End - partition.Start) + 1) / 2) + partition.Start) - 2, ((((partition.End - partition.Start) + 1) / 2) + partition.Start) - 1, (((partition.End - partition.Start) + 1) / 2) + partition.Start, (((partition.End - partition.Start) + 1) / 2) + partition.Start + 4 }; var rootBlk = new RootBlock(); byte[] rootBlockSector = null; bool rootFound = false; uint blockSize = 0; // So to handle even number of sectors foreach (ulong rootPtr in rootPtrs.Where(rootPtr => rootPtr < partition.End && rootPtr >= partition.Start)) { AaruConsole.DebugWriteLine("AmigaDOS plugin", "Searching for Rootblock in sector {0}", rootPtr); rootBlockSector = imagePlugin.ReadSector(rootPtr); rootBlk.type = BigEndianBitConverter.ToUInt32(rootBlockSector, 0x00); AaruConsole.DebugWriteLine("AmigaDOS plugin", "rootBlk.type = {0}", rootBlk.type); if (rootBlk.type != TYPE_HEADER) { continue; } rootBlk.hashTableSize = BigEndianBitConverter.ToUInt32(rootBlockSector, 0x0C); AaruConsole.DebugWriteLine("AmigaDOS plugin", "rootBlk.hashTableSize = {0}", rootBlk.hashTableSize); blockSize = (rootBlk.hashTableSize + 56) * 4; uint sectorsPerBlock = (uint)(blockSize / rootBlockSector.Length); AaruConsole.DebugWriteLine("AmigaDOS plugin", "blockSize = {0}", blockSize); AaruConsole.DebugWriteLine("AmigaDOS plugin", "sectorsPerBlock = {0}", sectorsPerBlock); if (blockSize % rootBlockSector.Length > 0) { sectorsPerBlock++; } if (rootPtr + sectorsPerBlock >= partition.End) { continue; } rootBlockSector = imagePlugin.ReadSectors(rootPtr, sectorsPerBlock); // Clear checksum on sector rootBlk.checksum = BigEndianBitConverter.ToUInt32(rootBlockSector, 20); rootBlockSector[20] = rootBlockSector[21] = rootBlockSector[22] = rootBlockSector[23] = 0; uint rsum = AmigaChecksum(rootBlockSector); AaruConsole.DebugWriteLine("AmigaDOS plugin", "rootBlk.checksum = 0x{0:X8}", rootBlk.checksum); AaruConsole.DebugWriteLine("AmigaDOS plugin", "rsum = 0x{0:X8}", rsum); rootBlk.sec_type = BigEndianBitConverter.ToUInt32(rootBlockSector, rootBlockSector.Length - 4); AaruConsole.DebugWriteLine("AmigaDOS plugin", "rootBlk.sec_type = {0}", rootBlk.sec_type); if (rootBlk.sec_type != SUBTYPE_ROOT || rootBlk.checksum != rsum) { continue; } rootBlockSector = imagePlugin.ReadSectors(rootPtr, sectorsPerBlock); rootFound = true; break; } if (!rootFound) { return; } rootBlk = MarshalRootBlock(rootBlockSector); string diskName = StringHandlers.PascalToString(rootBlk.diskName, Encoding); switch (bootBlk.diskType & 0xFF) { case 0: sbInformation.Append("Amiga Original File System"); XmlFsType.Type = "Amiga OFS"; break; case 1: sbInformation.Append("Amiga Fast File System"); XmlFsType.Type = "Amiga FFS"; break; case 2: sbInformation.Append("Amiga Original File System with international characters"); XmlFsType.Type = "Amiga OFS"; break; case 3: sbInformation.Append("Amiga Fast File System with international characters"); XmlFsType.Type = "Amiga FFS"; break; case 4: sbInformation.Append("Amiga Original File System with directory cache"); XmlFsType.Type = "Amiga OFS"; break; case 5: sbInformation.Append("Amiga Fast File System with directory cache"); XmlFsType.Type = "Amiga FFS"; break; case 6: sbInformation.Append("Amiga Original File System with long filenames"); XmlFsType.Type = "Amiga OFS2"; break; case 7: sbInformation.Append("Amiga Fast File System with long filenames"); XmlFsType.Type = "Amiga FFS2"; break; } if ((bootBlk.diskType & 0x6D754600) == 0x6D754600) { sbInformation.Append(", with multi-user patches"); } sbInformation.AppendLine(); sbInformation.AppendFormat("Volume name: {0}", diskName).AppendLine(); if (bootBlk.checksum == bsum) { var sha1Ctx = new Sha1Context(); sha1Ctx.Update(bootBlk.bootCode); sbInformation.AppendLine("Volume is bootable"); sbInformation.AppendFormat("Boot code SHA1 is {0}", sha1Ctx.End()).AppendLine(); } if (rootBlk.bitmapFlag == 0xFFFFFFFF) { sbInformation.AppendLine("Volume bitmap is valid"); } if (rootBlk.bitmapExtensionBlock != 0x00000000 && rootBlk.bitmapExtensionBlock != 0xFFFFFFFF) { sbInformation.AppendFormat("Bitmap extension at block {0}", rootBlk.bitmapExtensionBlock).AppendLine(); } if ((bootBlk.diskType & 0xFF) == 4 || (bootBlk.diskType & 0xFF) == 5) { sbInformation.AppendFormat("Directory cache starts at block {0}", rootBlk.extension).AppendLine(); } ulong blocks = (((partition.End - partition.Start) + 1) * imagePlugin.Info.SectorSize) / blockSize; sbInformation.AppendFormat("Volume block size is {0} bytes", blockSize).AppendLine(); sbInformation.AppendFormat("Volume has {0} blocks", blocks).AppendLine(); sbInformation.AppendFormat("Volume created on {0}", DateHandlers.AmigaToDateTime(rootBlk.cDays, rootBlk.cMins, rootBlk.cTicks)). AppendLine(); sbInformation.AppendFormat("Volume last modified on {0}", DateHandlers.AmigaToDateTime(rootBlk.vDays, rootBlk.vMins, rootBlk.vTicks)). AppendLine(); sbInformation.AppendFormat("Volume root directory last modified on on {0}", DateHandlers.AmigaToDateTime(rootBlk.rDays, rootBlk.rMins, rootBlk.rTicks)). AppendLine(); sbInformation.AppendFormat("Root block checksum is 0x{0:X8}", rootBlk.checksum).AppendLine(); information = sbInformation.ToString(); XmlFsType.CreationDate = DateHandlers.AmigaToDateTime(rootBlk.cDays, rootBlk.cMins, rootBlk.cTicks); XmlFsType.CreationDateSpecified = true; XmlFsType.ModificationDate = DateHandlers.AmigaToDateTime(rootBlk.vDays, rootBlk.vMins, rootBlk.vTicks); XmlFsType.ModificationDateSpecified = true; XmlFsType.Dirty = rootBlk.bitmapFlag != 0xFFFFFFFF; XmlFsType.Clusters = blocks; XmlFsType.ClusterSize = blockSize; XmlFsType.VolumeName = diskName; XmlFsType.Bootable = bsum == bootBlk.checksum; // Useful as a serial XmlFsType.VolumeSerial = $"{rootBlk.checksum:X8}"; }