mirror of
https://github.com/aaru-dps/Aaru.Server.git
synced 2025-12-16 19:24:27 +00:00
Move filesystems to a separate library.
This commit is contained in:
@@ -1,3 +1,32 @@
|
||||
2015-10-05 Natalia Portillo <claunia@claunia.com>
|
||||
|
||||
* Plugins.cs:
|
||||
* Plugins/BFS.cs:
|
||||
* Plugins/FFS.cs:
|
||||
* Plugins/ODS.cs:
|
||||
* Plugins/FAT.cs:
|
||||
* Plugins/NTFS.cs:
|
||||
* Plugins/HPFS.cs:
|
||||
* Plugins/SysV.cs:
|
||||
* Plugins/extFS.cs:
|
||||
* Plugins/Opera.cs:
|
||||
* Plugins/Plugin.cs:
|
||||
* Plugins/LisaFS.cs:
|
||||
* Plugins/ext2FS.cs:
|
||||
* Plugins/ProDOS.cs:
|
||||
* Plugins/SolarFS.cs:
|
||||
* Plugins/Symbian.cs:
|
||||
* Plugins/UNIXBFS.cs:
|
||||
* Plugins/ISO9660.cs:
|
||||
* Plugins/MinixFS.cs:
|
||||
* Plugins/AmigaDOS.cs:
|
||||
* Plugins/PCEngine.cs:
|
||||
* Plugins/AppleMFS.cs:
|
||||
* Plugins/AppleHFS.cs:
|
||||
* DiscImageChef.csproj:
|
||||
* Plugins/AppleHFSPlus.cs:
|
||||
Move filesystems to a separate library.
|
||||
|
||||
2015-10-05 Natalia Portillo <claunia@claunia.com>
|
||||
|
||||
* Plugins.cs:
|
||||
|
||||
@@ -39,28 +39,7 @@
|
||||
<ItemGroup>
|
||||
<Compile Include="Main.cs" />
|
||||
<Compile Include="AssemblyInfo.cs" />
|
||||
<Compile Include="Plugins\AppleMFS.cs" />
|
||||
<Compile Include="Plugins\Plugin.cs" />
|
||||
<Compile Include="Plugins.cs" />
|
||||
<Compile Include="Plugins\ISO9660.cs" />
|
||||
<Compile Include="Plugins\PCEngine.cs" />
|
||||
<Compile Include="Plugins\Opera.cs" />
|
||||
<Compile Include="Plugins\AppleHFS.cs" />
|
||||
<Compile Include="Plugins\FAT.cs" />
|
||||
<Compile Include="Plugins\FFS.cs" />
|
||||
<Compile Include="Plugins\AppleHFSPlus.cs" />
|
||||
<Compile Include="Plugins\BFS.cs" />
|
||||
<Compile Include="Plugins\HPFS.cs" />
|
||||
<Compile Include="Plugins\NTFS.cs" />
|
||||
<Compile Include="Plugins\ODS.cs" />
|
||||
<Compile Include="Plugins\Symbian.cs" />
|
||||
<Compile Include="Plugins\extFS.cs" />
|
||||
<Compile Include="Plugins\ext2FS.cs" />
|
||||
<Compile Include="Plugins\MinixFS.cs" />
|
||||
<Compile Include="Plugins\SolarFS.cs" />
|
||||
<Compile Include="Plugins\UNIXBFS.cs" />
|
||||
<Compile Include="Plugins\SysV.cs" />
|
||||
<Compile Include="Plugins\LisaFS.cs" />
|
||||
<Compile Include="Options.cs" />
|
||||
<Compile Include="Commands\Formats.cs" />
|
||||
<Compile Include="Commands\Analyze.cs" />
|
||||
@@ -75,8 +54,6 @@
|
||||
<Compile Include="Decoders\MMC.cs" />
|
||||
<Compile Include="Decoders\BD.cs" />
|
||||
<Compile Include="Decoders\DVD.cs" />
|
||||
<Compile Include="Plugins\ProDOS.cs" />
|
||||
<Compile Include="Plugins\AmigaDOS.cs" />
|
||||
<Compile Include="Commands\Entropy.cs" />
|
||||
<Compile Include="Decoders\Floppy.cs" />
|
||||
<Compile Include="DetectImageFormat.cs" />
|
||||
@@ -197,5 +174,9 @@
|
||||
<Project>{DA7AB65D-B5BA-4003-8893-A51BB071BA2F}</Project>
|
||||
<Name>DiscImageChef.Partitions</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\DiscImageChef.Filesystems\DiscImageChef.Filesystems.csproj">
|
||||
<Project>{D7016DF2-5A5E-4524-B40D-BA2D59576688}</Project>
|
||||
<Name>DiscImageChef.Filesystems</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -98,7 +98,7 @@ namespace DiscImageChef
|
||||
}
|
||||
}
|
||||
|
||||
assembly = Assembly.GetExecutingAssembly();
|
||||
assembly = Assembly.GetAssembly(typeof(Plugin));
|
||||
|
||||
foreach (Type type in assembly.GetTypes())
|
||||
{
|
||||
@@ -106,7 +106,7 @@ namespace DiscImageChef
|
||||
{
|
||||
if (type.IsSubclassOf(typeof(Plugin)))
|
||||
{
|
||||
Plugin plugin = (Plugin)type.GetConstructor(new [] { typeof(PluginBase) }).Invoke(new object[] { this });
|
||||
Plugin plugin = (Plugin)type.GetConstructor(Type.EmptyTypes).Invoke(new object[] { });
|
||||
RegisterPlugin(plugin);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,364 +0,0 @@
|
||||
/***************************************************************************
|
||||
The Disc Image Chef
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
Filename : AmigaDOS.cs
|
||||
Version : 1.0
|
||||
Author(s) : Natalia Portillo
|
||||
|
||||
Component : Filesystem plugins
|
||||
|
||||
Revision : $Revision$
|
||||
Last change by : $Author$
|
||||
Date : $Date$
|
||||
|
||||
--[ Description ] ----------------------------------------------------------
|
||||
|
||||
Identifies PC-Engine CDs.
|
||||
|
||||
--[ License ] --------------------------------------------------------------
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
----------------------------------------------------------------------------
|
||||
Copyright (C) 2011-2014 Claunia.com
|
||||
****************************************************************************/
|
||||
//$Id$
|
||||
|
||||
using System;
|
||||
using System.Text;
|
||||
using DiscImageChef;
|
||||
using DiscImageChef.PartPlugins;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace DiscImageChef.Plugins
|
||||
{
|
||||
class AmigaDOSPlugin : Plugin
|
||||
{
|
||||
public AmigaDOSPlugin(PluginBase Core)
|
||||
{
|
||||
Name = "Amiga DOS filesystem";
|
||||
PluginUUID = new Guid("3c882400-208c-427d-a086-9119852a1bc7");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Boot block, first 2 sectors
|
||||
/// </summary>
|
||||
struct BootBlock
|
||||
{
|
||||
/// <summary>
|
||||
/// Offset 0x00, "DOSx" disk type
|
||||
/// </summary>
|
||||
public UInt32 diskType;
|
||||
/// <summary>
|
||||
/// Offset 0x04, Checksum
|
||||
/// </summary>
|
||||
public UInt32 checksum;
|
||||
/// <summary>
|
||||
/// Offset 0x08, Pointer to root block, mostly invalid
|
||||
/// </summary>
|
||||
public UInt32 root_ptr;
|
||||
/// <summary>
|
||||
/// Offset 0x0C, Boot code, til completion
|
||||
/// </summary>
|
||||
public byte[] bootCode;
|
||||
}
|
||||
|
||||
struct RootBlock
|
||||
{
|
||||
/// <summary>
|
||||
/// Offset 0x00, block type, value = T_HEADER (2)
|
||||
/// </summary>
|
||||
public UInt32 type;
|
||||
/// <summary>
|
||||
/// Offset 0x04, unused
|
||||
/// </summary>
|
||||
public UInt32 headerKey;
|
||||
/// <summary>
|
||||
/// Offset 0x08, unused
|
||||
/// </summary>
|
||||
public UInt32 highSeq;
|
||||
/// <summary>
|
||||
/// Offset 0x0C, longs used by hash table
|
||||
/// </summary>
|
||||
public UInt32 hashTableSize;
|
||||
/// <summary>
|
||||
/// Offset 0x10, unused
|
||||
/// </summary>
|
||||
public UInt32 firstData;
|
||||
/// <summary>
|
||||
/// Offset 0x14, Rootblock checksum
|
||||
/// </summary>
|
||||
public UInt32 checksum;
|
||||
/// <summary>
|
||||
/// Offset 0x18, Hashtable, size = (block size / 4) - 56 or size = hashTableSize
|
||||
/// </summary>
|
||||
public UInt32[] hashTable;
|
||||
/// <summary>
|
||||
/// Offset 0x18+hashTableSize*4+0, bitmap flag, 0xFFFFFFFF if valid
|
||||
/// </summary>
|
||||
public UInt32 bitmapFlag;
|
||||
/// <summary>
|
||||
/// Offset 0x18+hashTableSize*4+4, bitmap pages, 25 entries
|
||||
/// </summary>
|
||||
public UInt32[] bitmapPages;
|
||||
/// <summary>
|
||||
/// Offset 0x18+hashTableSize*4+104, pointer to bitmap extension block
|
||||
/// </summary>
|
||||
public UInt32 bitmapExtensionBlock;
|
||||
/// <summary>
|
||||
/// Offset 0x18+hashTableSize*4+108, last root alteration days since 1978/01/01
|
||||
/// </summary>
|
||||
public UInt32 rDays;
|
||||
/// <summary>
|
||||
/// Offset 0x18+hashTableSize*4+112, last root alteration minutes past midnight
|
||||
/// </summary>
|
||||
public UInt32 rMins;
|
||||
/// <summary>
|
||||
/// Offset 0x18+hashTableSize*4+116, last root alteration ticks (1/50 secs)
|
||||
/// </summary>
|
||||
public UInt32 rTicks;
|
||||
/// <summary>
|
||||
/// Offset 0x18+hashTableSize*4+120, disk name, pascal string, 32 bytes
|
||||
/// </summary>
|
||||
public string diskName;
|
||||
/// <summary>
|
||||
/// Offset 0x18+hashTableSize*4+152, unused
|
||||
/// </summary>
|
||||
public UInt32 reserved1;
|
||||
/// <summary>
|
||||
/// Offset 0x18+hashTableSize*4+156, unused
|
||||
/// </summary>
|
||||
public UInt32 reserved2;
|
||||
/// <summary>
|
||||
/// Offset 0x18+hashTableSize*4+160, last disk alteration days since 1978/01/01
|
||||
/// </summary>
|
||||
public UInt32 vDays;
|
||||
/// <summary>
|
||||
/// Offset 0x18+hashTableSize*4+164, last disk alteration minutes past midnight
|
||||
/// </summary>
|
||||
public UInt32 vMins;
|
||||
/// <summary>
|
||||
/// Offset 0x18+hashTableSize*4+168, last disk alteration ticks (1/50 secs)
|
||||
/// </summary>
|
||||
public UInt32 vTicks;
|
||||
/// <summary>
|
||||
/// Offset 0x18+hashTableSize*4+172, filesystem creation days since 1978/01/01
|
||||
/// </summary>
|
||||
public UInt32 cDays;
|
||||
/// <summary>
|
||||
/// Offset 0x18+hashTableSize*4+176, filesystem creation minutes since 1978/01/01
|
||||
/// </summary>
|
||||
public UInt32 cMins;
|
||||
/// <summary>
|
||||
/// Offset 0x18+hashTableSize*4+180, filesystem creation ticks since 1978/01/01
|
||||
/// </summary>
|
||||
public UInt32 cTicks;
|
||||
/// <summary>
|
||||
/// Offset 0x18+hashTableSize*4+184, unused
|
||||
/// </summary>
|
||||
public UInt32 nextHash;
|
||||
/// <summary>
|
||||
/// Offset 0x18+hashTableSize*4+188, unused
|
||||
/// </summary>
|
||||
public UInt32 parentDir;
|
||||
/// <summary>
|
||||
/// Offset 0x18+hashTableSize*4+192, first directory cache block
|
||||
/// </summary>
|
||||
public UInt32 extension;
|
||||
/// <summary>
|
||||
/// Offset 0x18+hashTableSize*4+196, block secondary type = ST_ROOT (1)
|
||||
/// </summary>
|
||||
public UInt32 sec_type;
|
||||
}
|
||||
|
||||
public override bool Identify(ImagePlugins.ImagePlugin imagePlugin, ulong partitionStart, ulong partitionEnd)
|
||||
{
|
||||
if (partitionStart >= imagePlugin.GetSectors())
|
||||
return false;
|
||||
|
||||
BigEndianBitConverter.IsLittleEndian = BitConverter.IsLittleEndian;
|
||||
|
||||
byte[] sector = imagePlugin.ReadSector(0 + partitionStart);
|
||||
|
||||
UInt32 magic = BigEndianBitConverter.ToUInt32(sector, 0x00);
|
||||
|
||||
if ((magic & 0x6D754600) != 0x6D754600 &&
|
||||
(magic & 0x444F5300) != 0x444F5300)
|
||||
return false;
|
||||
|
||||
ulong root_ptr = BigEndianBitConverter.ToUInt32(sector, 0x08);
|
||||
if (MainClass.isDebug)
|
||||
Console.WriteLine("DEBUG (AmigaDOS plugin): Bootblock points to {0} as Rootblock", root_ptr);
|
||||
|
||||
root_ptr = (partitionEnd - partitionStart) / 2 + partitionStart;
|
||||
|
||||
if (MainClass.isDebug)
|
||||
Console.WriteLine("DEBUG (AmigaDOS plugin): Nonetheless, going to block {0} for Rootblock", root_ptr);
|
||||
|
||||
if (root_ptr >= imagePlugin.GetSectors())
|
||||
return false;
|
||||
|
||||
sector = imagePlugin.ReadSector(root_ptr);
|
||||
|
||||
UInt32 type = BigEndianBitConverter.ToUInt32(sector, 0x00);
|
||||
UInt32 hashTableSize = BigEndianBitConverter.ToUInt32(sector, 0x0C);
|
||||
|
||||
if ((0x18 + hashTableSize * 4 + 196) > sector.Length)
|
||||
return false;
|
||||
|
||||
UInt32 sec_type = BigEndianBitConverter.ToUInt32(sector, (int)(0x18 + hashTableSize * 4 + 196));
|
||||
|
||||
return type == 2 && sec_type == 1;
|
||||
}
|
||||
|
||||
public override void GetInformation(ImagePlugins.ImagePlugin imagePlugin, ulong partitionStart, ulong partitionEnd, out string information)
|
||||
{
|
||||
StringBuilder sbInformation = new StringBuilder();
|
||||
|
||||
byte[] BootBlockSectors = imagePlugin.ReadSectors(0 + partitionStart, 2);
|
||||
byte[] RootBlockSector = imagePlugin.ReadSector((partitionEnd - partitionStart) / 2 + partitionStart);
|
||||
byte[] diskName = new byte[32];
|
||||
|
||||
BootBlock bootBlk = new BootBlock();
|
||||
RootBlock rootBlk = new RootBlock();
|
||||
|
||||
BigEndianBitConverter.IsLittleEndian = BitConverter.IsLittleEndian;
|
||||
|
||||
bootBlk.diskType = BigEndianBitConverter.ToUInt32(BootBlockSectors, 0x00);
|
||||
bootBlk.checksum = BigEndianBitConverter.ToUInt32(BootBlockSectors, 0x04);
|
||||
bootBlk.root_ptr = BigEndianBitConverter.ToUInt32(BootBlockSectors, 0x08);
|
||||
bootBlk.bootCode = new byte[BootBlockSectors.Length - 0x0C];
|
||||
Array.Copy(BootBlockSectors, 0x0C, bootBlk.bootCode, 0, BootBlockSectors.Length - 0x0C);
|
||||
|
||||
if (MainClass.isDebug)
|
||||
{
|
||||
Console.WriteLine("DEBUG (AmigaDOS plugin): Stored boot blocks checksum is 0x{0:X8}", bootBlk.checksum);
|
||||
Console.WriteLine("DEBUG (AmigaDOS plugin): Probably incorrect calculated boot blocks checksum is 0x{0:X8}", AmigaChecksum(RootBlockSector));
|
||||
Checksums.SHA1Context sha1Ctx = new Checksums.SHA1Context();
|
||||
sha1Ctx.Init();
|
||||
sha1Ctx.Update(bootBlk.bootCode);
|
||||
Console.WriteLine("DEBUG (AmigaDOS plugin): Boot code SHA1 is {0}", sha1Ctx.End());
|
||||
}
|
||||
|
||||
rootBlk.type = BigEndianBitConverter.ToUInt32(RootBlockSector, 0x00);
|
||||
rootBlk.headerKey = BigEndianBitConverter.ToUInt32(RootBlockSector, 0x04);
|
||||
rootBlk.highSeq = BigEndianBitConverter.ToUInt32(RootBlockSector, 0x08);
|
||||
rootBlk.hashTableSize = BigEndianBitConverter.ToUInt32(RootBlockSector, 0x0C);
|
||||
rootBlk.firstData = BigEndianBitConverter.ToUInt32(RootBlockSector, 0x10);
|
||||
rootBlk.checksum = BigEndianBitConverter.ToUInt32(RootBlockSector, 0x14);
|
||||
rootBlk.hashTable = new uint[rootBlk.hashTableSize];
|
||||
|
||||
for (int i = 0; i < rootBlk.hashTableSize; i++)
|
||||
rootBlk.hashTable[i] = BigEndianBitConverter.ToUInt32(RootBlockSector, 0x18 + i * 4);
|
||||
|
||||
rootBlk.bitmapFlag = BigEndianBitConverter.ToUInt32(RootBlockSector, (int)(0x18 + rootBlk.hashTableSize * 4 + 0));
|
||||
rootBlk.bitmapPages = new uint[25];
|
||||
|
||||
for (int i = 0; i < 25; i++)
|
||||
rootBlk.bitmapPages[i] = BigEndianBitConverter.ToUInt32(RootBlockSector, (int)(0x18 + rootBlk.hashTableSize * 4 + 4 + i * 4));
|
||||
|
||||
rootBlk.bitmapExtensionBlock = BigEndianBitConverter.ToUInt32(RootBlockSector, (int)(0x18 + rootBlk.hashTableSize * 4 + 104));
|
||||
rootBlk.rDays = BigEndianBitConverter.ToUInt32(RootBlockSector, (int)(0x18 + rootBlk.hashTableSize * 4 + 108));
|
||||
rootBlk.rMins = BigEndianBitConverter.ToUInt32(RootBlockSector, (int)(0x18 + rootBlk.hashTableSize * 4 + 112));
|
||||
rootBlk.rTicks = BigEndianBitConverter.ToUInt32(RootBlockSector, (int)(0x18 + rootBlk.hashTableSize * 4 + 116));
|
||||
|
||||
Array.Copy(RootBlockSector, 0x18 + rootBlk.hashTableSize * 4 + 120, diskName, 0, 32);
|
||||
rootBlk.diskName = StringHandlers.PascalToString(diskName);
|
||||
|
||||
rootBlk.reserved1 = BigEndianBitConverter.ToUInt32(RootBlockSector, (int)(0x18 + rootBlk.hashTableSize * 4 + 152));
|
||||
rootBlk.reserved2 = BigEndianBitConverter.ToUInt32(RootBlockSector, (int)(0x18 + rootBlk.hashTableSize * 4 + 156));
|
||||
rootBlk.vDays = BigEndianBitConverter.ToUInt32(RootBlockSector, (int)(0x18 + rootBlk.hashTableSize * 4 + 160));
|
||||
rootBlk.vMins = BigEndianBitConverter.ToUInt32(RootBlockSector, (int)(0x18 + rootBlk.hashTableSize * 4 + 164));
|
||||
rootBlk.vTicks = BigEndianBitConverter.ToUInt32(RootBlockSector, (int)(0x18 + rootBlk.hashTableSize * 4 + 168));
|
||||
rootBlk.cDays = BigEndianBitConverter.ToUInt32(RootBlockSector, (int)(0x18 + rootBlk.hashTableSize * 4 + 172));
|
||||
rootBlk.cMins = BigEndianBitConverter.ToUInt32(RootBlockSector, (int)(0x18 + rootBlk.hashTableSize * 4 + 176));
|
||||
rootBlk.cTicks = BigEndianBitConverter.ToUInt32(RootBlockSector, (int)(0x18 + rootBlk.hashTableSize * 4 + 180));
|
||||
rootBlk.nextHash = BigEndianBitConverter.ToUInt32(RootBlockSector, (int)(0x18 + rootBlk.hashTableSize * 4 + 184));
|
||||
rootBlk.parentDir = BigEndianBitConverter.ToUInt32(RootBlockSector, (int)(0x18 + rootBlk.hashTableSize * 4 + 188));
|
||||
rootBlk.extension = BigEndianBitConverter.ToUInt32(RootBlockSector, (int)(0x18 + rootBlk.hashTableSize * 4 + 192));
|
||||
rootBlk.sec_type = BigEndianBitConverter.ToUInt32(RootBlockSector, (int)(0x18 + rootBlk.hashTableSize * 4 + 196));
|
||||
|
||||
if (MainClass.isDebug)
|
||||
{
|
||||
Console.WriteLine("DEBUG (AmigaDOS plugin): Stored root block checksum is 0x{0:X8}", rootBlk.checksum);
|
||||
Console.WriteLine("DEBUG (AmigaDOS plugin): Probably incorrect calculated root block checksum is 0x{0:X8}", AmigaChecksum(RootBlockSector));
|
||||
}
|
||||
|
||||
switch (bootBlk.diskType & 0xFF)
|
||||
{
|
||||
case 0:
|
||||
sbInformation.Append("Amiga Original File System");
|
||||
break;
|
||||
case 1:
|
||||
sbInformation.Append("Amiga Fast File System");
|
||||
break;
|
||||
case 2:
|
||||
sbInformation.Append("Amiga Original File System with international characters");
|
||||
break;
|
||||
case 3:
|
||||
sbInformation.Append("Amiga Fast File System with international characters");
|
||||
break;
|
||||
case 4:
|
||||
sbInformation.Append("Amiga Original File System with directory cache");
|
||||
break;
|
||||
case 5:
|
||||
sbInformation.Append("Amiga Fast File System with directory cache");
|
||||
break;
|
||||
case 6:
|
||||
sbInformation.Append("Amiga Original File System with long filenames");
|
||||
break;
|
||||
case 7:
|
||||
sbInformation.Append("Amiga Fast File System with long filenames");
|
||||
break;
|
||||
}
|
||||
|
||||
if ((bootBlk.diskType & 0x6D754600) == 0x6D754600)
|
||||
sbInformation.Append(", with multi-user patches");
|
||||
|
||||
sbInformation.AppendLine();
|
||||
|
||||
if ((bootBlk.diskType & 0xFF) == 6 || (bootBlk.diskType & 0xFF) == 7)
|
||||
sbInformation.AppendLine("AFFS v2, following information may be completely incorrect or garbage.");
|
||||
|
||||
sbInformation.AppendFormat("Volume name: {0}", rootBlk.diskName).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();
|
||||
|
||||
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();
|
||||
|
||||
information = sbInformation.ToString();
|
||||
}
|
||||
|
||||
static UInt32 AmigaChecksum(byte[] data)
|
||||
{
|
||||
BigEndianBitConverter.IsLittleEndian = BitConverter.IsLittleEndian;
|
||||
UInt32 sum = 0;
|
||||
|
||||
for (int i = 0; i < data.Length; i += 4)
|
||||
sum += BigEndianBitConverter.ToUInt32(data, i);
|
||||
|
||||
return sum;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,501 +0,0 @@
|
||||
/***************************************************************************
|
||||
The Disc Image Chef
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
Filename : AppleHFS.cs
|
||||
Version : 1.0
|
||||
Author(s) : Natalia Portillo
|
||||
|
||||
Component : Filesystem plugins
|
||||
|
||||
Revision : $Revision$
|
||||
Last change by : $Author$
|
||||
Date : $Date$
|
||||
|
||||
--[ Description ] ----------------------------------------------------------
|
||||
|
||||
Identifies HFS filesystems and shows information.
|
||||
|
||||
--[ License ] --------------------------------------------------------------
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
----------------------------------------------------------------------------
|
||||
Copyright (C) 2011-2014 Claunia.com
|
||||
****************************************************************************/
|
||||
//$Id$
|
||||
|
||||
using System;
|
||||
using System.Text;
|
||||
using DiscImageChef;
|
||||
|
||||
// Information from Inside Macintosh
|
||||
// https://developer.apple.com/legacy/library/documentation/mac/pdf/Files/File_Manager.pdf
|
||||
namespace DiscImageChef.Plugins
|
||||
{
|
||||
class AppleHFS : Plugin
|
||||
{
|
||||
const UInt16 HFS_MAGIC = 0x4244;
|
||||
// "BD"
|
||||
const UInt16 HFSP_MAGIC = 0x482B;
|
||||
// "H+"
|
||||
const UInt16 HFSBB_MAGIC = 0x4C4B;
|
||||
// "LK"
|
||||
public AppleHFS(PluginBase Core)
|
||||
{
|
||||
Name = "Apple Hierarchical File System";
|
||||
PluginUUID = new Guid("36405F8D-0D26-6ECC-0BBB-1D5225FF404F");
|
||||
}
|
||||
|
||||
public override bool Identify(ImagePlugins.ImagePlugin imagePlugin, ulong partitionStart, ulong partitionEnd)
|
||||
{
|
||||
if ((2 + partitionStart) >= imagePlugin.GetSectors())
|
||||
return false;
|
||||
|
||||
byte[] mdb_sector;
|
||||
UInt16 drSigWord;
|
||||
|
||||
if (imagePlugin.GetSectorSize() == 2352 || imagePlugin.GetSectorSize() == 2448 || imagePlugin.GetSectorSize() == 2048)
|
||||
{
|
||||
mdb_sector = imagePlugin.ReadSector(2 + partitionStart);
|
||||
drSigWord = BigEndianBitConverter.ToUInt16(mdb_sector, 0);
|
||||
|
||||
if (drSigWord == HFS_MAGIC)
|
||||
{
|
||||
drSigWord = BigEndianBitConverter.ToUInt16(mdb_sector, 0x7C); // Seek to embedded HFS+ signature
|
||||
|
||||
return drSigWord != HFSP_MAGIC;
|
||||
}
|
||||
mdb_sector = Read2048SectorAs512(imagePlugin, 2 + partitionStart);
|
||||
drSigWord = BigEndianBitConverter.ToUInt16(mdb_sector, 0);
|
||||
|
||||
if (drSigWord == HFS_MAGIC)
|
||||
{
|
||||
if (MainClass.isDebug)
|
||||
Console.WriteLine("DEBUG (HFS Plugin): HFS sector size is 512 bytes, but device's 2048");
|
||||
|
||||
drSigWord = BigEndianBitConverter.ToUInt16(mdb_sector, 0x7C); // Seek to embedded HFS+ signature
|
||||
|
||||
return drSigWord != HFSP_MAGIC;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mdb_sector = imagePlugin.ReadSector(2 + partitionStart);
|
||||
drSigWord = BigEndianBitConverter.ToUInt16(mdb_sector, 0);
|
||||
|
||||
if (drSigWord == HFS_MAGIC)
|
||||
{
|
||||
drSigWord = BigEndianBitConverter.ToUInt16(mdb_sector, 0x7C); // Seek to embedded HFS+ signature
|
||||
|
||||
return drSigWord != HFSP_MAGIC;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public override void GetInformation(ImagePlugins.ImagePlugin imagePlugin, ulong partitionStart, ulong partitionEnd, out string information)
|
||||
{
|
||||
information = "";
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
HFS_MasterDirectoryBlock MDB = new HFS_MasterDirectoryBlock();
|
||||
HFS_BootBlock BB = new HFS_BootBlock();
|
||||
|
||||
byte[] pString;
|
||||
|
||||
byte[] bb_sector;
|
||||
byte[] mdb_sector;
|
||||
UInt16 drSigWord;
|
||||
|
||||
bool APMFromHDDOnCD = false;
|
||||
|
||||
if (imagePlugin.GetSectorSize() == 2352 || imagePlugin.GetSectorSize() == 2448 || imagePlugin.GetSectorSize() == 2048)
|
||||
{
|
||||
mdb_sector = imagePlugin.ReadSector(2 + partitionStart);
|
||||
drSigWord = BigEndianBitConverter.ToUInt16(mdb_sector, 0);
|
||||
|
||||
if (drSigWord == HFS_MAGIC)
|
||||
{
|
||||
bb_sector = imagePlugin.ReadSector(partitionStart);
|
||||
}
|
||||
else
|
||||
{
|
||||
mdb_sector = Read2048SectorAs512(imagePlugin, 2 + partitionStart);
|
||||
drSigWord = BigEndianBitConverter.ToUInt16(mdb_sector, 0);
|
||||
|
||||
if (drSigWord == HFS_MAGIC)
|
||||
{
|
||||
bb_sector = Read2048SectorAs512(imagePlugin, partitionStart);
|
||||
APMFromHDDOnCD = true;
|
||||
}
|
||||
else
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mdb_sector = imagePlugin.ReadSector(2 + partitionStart);
|
||||
drSigWord = BigEndianBitConverter.ToUInt16(mdb_sector, 0);
|
||||
|
||||
if (drSigWord == HFS_MAGIC)
|
||||
bb_sector = imagePlugin.ReadSector(partitionStart);
|
||||
else
|
||||
return;
|
||||
}
|
||||
|
||||
MDB.drSigWord = BigEndianBitConverter.ToUInt16(mdb_sector, 0x000);
|
||||
if (MDB.drSigWord != HFS_MAGIC)
|
||||
return;
|
||||
|
||||
MDB.drCrDate = BigEndianBitConverter.ToUInt32(mdb_sector, 0x002);
|
||||
MDB.drLsMod = BigEndianBitConverter.ToUInt32(mdb_sector, 0x006);
|
||||
MDB.drAtrb = BigEndianBitConverter.ToUInt16(mdb_sector, 0x00A);
|
||||
MDB.drNmFls = BigEndianBitConverter.ToUInt16(mdb_sector, 0x00C);
|
||||
MDB.drVBMSt = BigEndianBitConverter.ToUInt16(mdb_sector, 0X00E);
|
||||
MDB.drAllocPtr = BigEndianBitConverter.ToUInt16(mdb_sector, 0x010);
|
||||
MDB.drNmAlBlks = BigEndianBitConverter.ToUInt16(mdb_sector, 0x012);
|
||||
MDB.drAlBlkSiz = BigEndianBitConverter.ToUInt32(mdb_sector, 0x014);
|
||||
MDB.drClpSiz = BigEndianBitConverter.ToUInt32(mdb_sector, 0x018);
|
||||
MDB.drAlBlSt = BigEndianBitConverter.ToUInt16(mdb_sector, 0x01C);
|
||||
MDB.drNxtCNID = BigEndianBitConverter.ToUInt32(mdb_sector, 0x01E);
|
||||
MDB.drFreeBks = BigEndianBitConverter.ToUInt16(mdb_sector, 0x022);
|
||||
pString = new byte[28];
|
||||
Array.Copy(mdb_sector, 0x024, pString, 0, 28);
|
||||
MDB.drVN = StringHandlers.PascalToString(pString);
|
||||
|
||||
MDB.drVolBkUp = BigEndianBitConverter.ToUInt32(mdb_sector, 0x040);
|
||||
MDB.drVSeqNum = BigEndianBitConverter.ToUInt16(mdb_sector, 0x044);
|
||||
MDB.drWrCnt = BigEndianBitConverter.ToUInt32(mdb_sector, 0x046);
|
||||
MDB.drXTClpSiz = BigEndianBitConverter.ToUInt32(mdb_sector, 0x04A);
|
||||
MDB.drCTClpSiz = BigEndianBitConverter.ToUInt32(mdb_sector, 0x04E);
|
||||
MDB.drNmRtDirs = BigEndianBitConverter.ToUInt16(mdb_sector, 0x052);
|
||||
MDB.drFilCnt = BigEndianBitConverter.ToUInt32(mdb_sector, 0x054);
|
||||
MDB.drDirCnt = BigEndianBitConverter.ToUInt32(mdb_sector, 0x058);
|
||||
|
||||
MDB.drFndrInfo0 = BigEndianBitConverter.ToUInt32(mdb_sector, 0x05C);
|
||||
MDB.drFndrInfo1 = BigEndianBitConverter.ToUInt32(mdb_sector, 0x060);
|
||||
MDB.drFndrInfo2 = BigEndianBitConverter.ToUInt32(mdb_sector, 0x064);
|
||||
MDB.drFndrInfo3 = BigEndianBitConverter.ToUInt32(mdb_sector, 0x068);
|
||||
MDB.drFndrInfo4 = BigEndianBitConverter.ToUInt32(mdb_sector, 0x06C);
|
||||
MDB.drFndrInfo5 = BigEndianBitConverter.ToUInt32(mdb_sector, 0x070);
|
||||
MDB.drFndrInfo6 = BigEndianBitConverter.ToUInt32(mdb_sector, 0x074);
|
||||
MDB.drFndrInfo7 = BigEndianBitConverter.ToUInt32(mdb_sector, 0x078);
|
||||
|
||||
MDB.drVCSize = BigEndianBitConverter.ToUInt16(mdb_sector, 0x07C);
|
||||
MDB.drVBMCSize = BigEndianBitConverter.ToUInt16(mdb_sector, 0x07E);
|
||||
MDB.drCtlCSize = BigEndianBitConverter.ToUInt16(mdb_sector, 0x080);
|
||||
|
||||
// For HFS+ embedded volume
|
||||
MDB.drEmbedSigWord = BigEndianBitConverter.ToUInt16(mdb_sector, 0x07C);
|
||||
MDB.xdrStABNt = BigEndianBitConverter.ToUInt16(mdb_sector, 0x07E);
|
||||
MDB.xdrNumABlks = BigEndianBitConverter.ToUInt16(mdb_sector, 0x080);
|
||||
|
||||
MDB.drXTFlSize = BigEndianBitConverter.ToUInt32(mdb_sector, 0x082);
|
||||
MDB.drCTFlSize = BigEndianBitConverter.ToUInt32(mdb_sector, 0x092);
|
||||
|
||||
BB.signature = BigEndianBitConverter.ToUInt16(bb_sector, 0x000);
|
||||
|
||||
if (BB.signature == HFSBB_MAGIC)
|
||||
{
|
||||
BB.branch = BigEndianBitConverter.ToUInt32(bb_sector, 0x002);
|
||||
BB.boot_flags = bb_sector[0x006];
|
||||
BB.boot_version = bb_sector[0x007];
|
||||
|
||||
BB.sec_sv_pages = BigEndianBitConverter.ToInt16(bb_sector, 0x008);
|
||||
|
||||
pString = new byte[16];
|
||||
Array.Copy(bb_sector, 0x00A, pString, 0, 16);
|
||||
BB.system_name = StringHandlers.PascalToString(pString);
|
||||
pString = new byte[16];
|
||||
Array.Copy(bb_sector, 0x01A, pString, 0, 16);
|
||||
BB.finder_name = StringHandlers.PascalToString(pString);
|
||||
pString = new byte[16];
|
||||
Array.Copy(bb_sector, 0x02A, pString, 0, 16);
|
||||
BB.debug_name = StringHandlers.PascalToString(pString);
|
||||
pString = new byte[16];
|
||||
Array.Copy(bb_sector, 0x03A, pString, 0, 16);
|
||||
BB.disasm_name = StringHandlers.PascalToString(pString);
|
||||
pString = new byte[16];
|
||||
Array.Copy(bb_sector, 0x04A, pString, 0, 16);
|
||||
BB.stupscr_name = StringHandlers.PascalToString(pString);
|
||||
pString = new byte[16];
|
||||
Array.Copy(bb_sector, 0x05A, pString, 0, 16);
|
||||
BB.bootup_name = StringHandlers.PascalToString(pString);
|
||||
pString = new byte[16];
|
||||
Array.Copy(bb_sector, 0x06A, pString, 0, 16);
|
||||
BB.clipbrd_name = StringHandlers.PascalToString(pString);
|
||||
|
||||
BB.max_files = BigEndianBitConverter.ToUInt16(bb_sector, 0x07A);
|
||||
BB.queue_size = BigEndianBitConverter.ToUInt16(bb_sector, 0x07C);
|
||||
BB.heap_128k = BigEndianBitConverter.ToUInt32(bb_sector, 0x07E);
|
||||
BB.heap_256k = BigEndianBitConverter.ToUInt32(bb_sector, 0x082);
|
||||
BB.heap_512k = BigEndianBitConverter.ToUInt32(bb_sector, 0x086);
|
||||
}
|
||||
else
|
||||
BB.signature = 0x0000;
|
||||
|
||||
sb.AppendLine("Apple Hierarchical File System");
|
||||
sb.AppendLine();
|
||||
if (APMFromHDDOnCD)
|
||||
sb.AppendLine("HFS uses 512 bytes/sector while devices 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();
|
||||
sb.AppendFormat("Last backup date: {0}", DateHandlers.MacToDateTime(MDB.drVolBkUp)).AppendLine();
|
||||
sb.AppendFormat("Backup sequence number: {0}", MDB.drVSeqNum).AppendLine();
|
||||
|
||||
if ((MDB.drAtrb & 0x80) == 0x80)
|
||||
sb.AppendLine("Volume is locked by hardware.");
|
||||
if ((MDB.drAtrb & 0x100) == 0x100)
|
||||
sb.AppendLine("Volume was unmonted.");
|
||||
else
|
||||
sb.AppendLine("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}", MDB.drVN).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();
|
||||
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.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();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static byte[] Read2048SectorAs512(ImagePlugins.ImagePlugin imagePlugin, UInt64 LBA)
|
||||
{
|
||||
UInt64 LBA2k = LBA / 4;
|
||||
int Remainder = (int)(LBA % 4);
|
||||
|
||||
byte[] buffer = imagePlugin.ReadSector(LBA2k);
|
||||
byte[] sector = new byte[512];
|
||||
|
||||
Array.Copy(buffer, Remainder * 512, sector, 0, 512);
|
||||
|
||||
return sector;
|
||||
}
|
||||
|
||||
struct HFS_MasterDirectoryBlock // Should be sector 2 in volume
|
||||
{
|
||||
public UInt16 drSigWord;
|
||||
// 0x000, Signature, 0x4244
|
||||
public UInt32 drCrDate;
|
||||
// 0x002, Volume creation date
|
||||
public UInt32 drLsMod;
|
||||
// 0x006, Volume last modification date
|
||||
public UInt16 drAtrb;
|
||||
// 0x00A, Volume attributes
|
||||
public UInt16 drNmFls;
|
||||
// 0x00C, Files in root directory
|
||||
public UInt16 drVBMSt;
|
||||
// 0x00E, Start 512-byte sector of volume bitmap
|
||||
public UInt16 drAllocPtr;
|
||||
// 0x010, Allocation block to begin next allocation
|
||||
public UInt16 drNmAlBlks;
|
||||
// 0x012, Allocation blocks
|
||||
public UInt32 drAlBlkSiz;
|
||||
// 0x014, Bytes per allocation block
|
||||
public UInt32 drClpSiz;
|
||||
// 0x018, Bytes to allocate when extending a file
|
||||
public UInt16 drAlBlSt;
|
||||
// 0x01C, Start 512-byte sector of first allocation block
|
||||
public UInt32 drNxtCNID;
|
||||
// 0x01E, CNID for next file
|
||||
public UInt16 drFreeBks;
|
||||
// 0x022, Free allocation blocks
|
||||
public string drVN;
|
||||
// 0x024, Volume name (28 bytes)
|
||||
public UInt32 drVolBkUp;
|
||||
// 0x040, Volume last backup time
|
||||
public UInt16 drVSeqNum;
|
||||
// 0x044, Volume backup sequence number
|
||||
public UInt32 drWrCnt;
|
||||
// 0x046, Filesystem write count
|
||||
public UInt32 drXTClpSiz;
|
||||
// 0x04A, Bytes to allocate when extending the extents B-Tree
|
||||
public UInt32 drCTClpSiz;
|
||||
// 0x04E, Bytes to allocate when extending the catalog B-Tree
|
||||
public UInt16 drNmRtDirs;
|
||||
// 0x052, Number of directories in root directory
|
||||
public UInt32 drFilCnt;
|
||||
// 0x054, Number of files in the volume
|
||||
public UInt32 drDirCnt;
|
||||
// 0x058, Number of directories in the volume
|
||||
public UInt32 drFndrInfo0;
|
||||
// 0x05C, finderInfo[0], CNID for bootable system's directory
|
||||
public UInt32 drFndrInfo1;
|
||||
// 0x060, finderInfo[1], CNID of the directory containing the boot application
|
||||
public UInt32 drFndrInfo2;
|
||||
// 0x064, finderInfo[2], CNID of the directory that should be opened on boot
|
||||
public UInt32 drFndrInfo3;
|
||||
// 0x068, finderInfo[3], CNID for Mac OS 8 or 9 directory
|
||||
public UInt32 drFndrInfo4;
|
||||
// 0x06C, finderInfo[4], Reserved
|
||||
public UInt32 drFndrInfo5;
|
||||
// 0x070, finderInfo[5], CNID for Mac OS X directory
|
||||
public UInt32 drFndrInfo6;
|
||||
// 0x074, finderInfo[6], first part of Mac OS X volume ID
|
||||
public UInt32 drFndrInfo7;
|
||||
// 0x078, finderInfo[7], second part of Mac OS X volume ID
|
||||
// If wrapping HFS+
|
||||
public UInt16 drEmbedSigWord;
|
||||
// 0x07C, Embedded volume signature, "H+" if HFS+ is embedded ignore following two fields if not
|
||||
public UInt16 xdrStABNt;
|
||||
// 0x07E, Starting block number of embedded HFS+ volume
|
||||
public UInt16 xdrNumABlks;
|
||||
// 0x080, Allocation blocks used by embedded volume
|
||||
// If not
|
||||
public UInt16 drVCSize;
|
||||
// 0x07C, Size in blocks of volume cache
|
||||
public UInt16 drVBMCSize;
|
||||
// 0x07E, Size in blocks of volume bitmap cache
|
||||
public UInt16 drCtlCSize;
|
||||
// 0x080, Size in blocks of volume common cache
|
||||
// End of variable variables :D
|
||||
public UInt32 drXTFlSize;
|
||||
// 0x082, Bytes in the extents B-Tree
|
||||
// 3 HFS extents following, 32 bits each
|
||||
public UInt32 drCTFlSize;
|
||||
// 0x092, Bytes in the catalog B-Tree
|
||||
// 3 HFS extents following, 32 bits each
|
||||
}
|
||||
|
||||
struct HFS_BootBlock // Should be sectors 0 and 1 in volume
|
||||
{
|
||||
public UInt16 signature;
|
||||
// 0x000, Signature, 0x4C4B if bootable
|
||||
public UInt32 branch;
|
||||
// 0x002, Branch
|
||||
public byte boot_flags;
|
||||
// 0x006, Boot block flags
|
||||
public byte boot_version;
|
||||
// 0x007, Boot block version
|
||||
public Int16 sec_sv_pages;
|
||||
// 0x008, Allocate secondary buffers
|
||||
public string system_name;
|
||||
// 0x00A, System file name (16 bytes)
|
||||
public string finder_name;
|
||||
// 0x01A, Finder file name (16 bytes)
|
||||
public string debug_name;
|
||||
// 0x02A, Debugger file name (16 bytes)
|
||||
public string disasm_name;
|
||||
// 0x03A, Disassembler file name (16 bytes)
|
||||
public string stupscr_name;
|
||||
// 0x04A, Startup screen file name (16 bytes)
|
||||
public string bootup_name;
|
||||
// 0x05A, First program to execute on boot (16 bytes)
|
||||
public string clipbrd_name;
|
||||
// 0x06A, Clipboard file name (16 bytes)
|
||||
public UInt16 max_files;
|
||||
// 0x07A, 1/4 of maximum opened at a time files
|
||||
public UInt16 queue_size;
|
||||
// 0x07C, Event queue size
|
||||
public UInt32 heap_128k;
|
||||
// 0x07E, Heap size on a Mac with 128KiB of RAM
|
||||
public UInt32 heap_256k;
|
||||
// 0x082, Heap size on a Mac with 256KiB of RAM
|
||||
public UInt32 heap_512k;
|
||||
// 0x086, Heap size on a Mac with 512KiB of RAM or more
|
||||
}
|
||||
// Follows boot code
|
||||
}
|
||||
}
|
||||
@@ -1,532 +0,0 @@
|
||||
/***************************************************************************
|
||||
The Disc Image Chef
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
Filename : AppleHFSPlus.cs
|
||||
Version : 1.0
|
||||
Author(s) : Natalia Portillo
|
||||
|
||||
Component : Filesystem plugins
|
||||
|
||||
Revision : $Revision$
|
||||
Last change by : $Author$
|
||||
Date : $Date$
|
||||
|
||||
--[ Description ] ----------------------------------------------------------
|
||||
|
||||
Identifies HFS+/HFSX filesystems and shows information.
|
||||
|
||||
--[ License ] --------------------------------------------------------------
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
----------------------------------------------------------------------------
|
||||
Copyright (C) 2011-2014 Claunia.com
|
||||
****************************************************************************/
|
||||
//$Id$
|
||||
|
||||
using System;
|
||||
using System.Text;
|
||||
using DiscImageChef;
|
||||
|
||||
// Information from Apple TechNote 1150: https://developer.apple.com/legacy/library/technotes/tn/tn1150.html
|
||||
namespace DiscImageChef.Plugins
|
||||
{
|
||||
class AppleHFSPlus : Plugin
|
||||
{
|
||||
const UInt16 HFS_MAGIC = 0x4244;
|
||||
// "BD"
|
||||
const UInt16 HFSP_MAGIC = 0x482B;
|
||||
// "H+"
|
||||
const UInt16 HFSX_MAGIC = 0x4858;
|
||||
// "HX"
|
||||
public AppleHFSPlus(PluginBase Core)
|
||||
{
|
||||
Name = "Apple HFS+ filesystem";
|
||||
PluginUUID = new Guid("36405F8D-0D26-6EBE-436F-62F0586B4F08");
|
||||
}
|
||||
|
||||
public override bool Identify(ImagePlugins.ImagePlugin imagePlugin, ulong partitionStart, ulong partitionEnd)
|
||||
{
|
||||
if ((2 + partitionStart) >= imagePlugin.GetSectors())
|
||||
return false;
|
||||
|
||||
UInt16 drSigWord;
|
||||
UInt16 xdrStABNt;
|
||||
UInt16 drAlBlSt;
|
||||
UInt32 drAlBlkSiz;
|
||||
|
||||
byte[] vh_sector;
|
||||
ulong hfsp_offset;
|
||||
|
||||
vh_sector = imagePlugin.ReadSector(2 + partitionStart); // Read volume header, of HFS Wrapper MDB
|
||||
|
||||
drSigWord = BigEndianBitConverter.ToUInt16(vh_sector, 0); // Check for HFS Wrapper MDB
|
||||
|
||||
if (drSigWord == HFS_MAGIC) // "BD"
|
||||
{
|
||||
drSigWord = BigEndianBitConverter.ToUInt16(vh_sector, 0x07C); // Read embedded HFS+ signature
|
||||
|
||||
if (drSigWord == HFSP_MAGIC) // "H+"
|
||||
{
|
||||
xdrStABNt = BigEndianBitConverter.ToUInt16(vh_sector, 0x07E); // Starting block number of embedded HFS+ volume
|
||||
|
||||
drAlBlkSiz = BigEndianBitConverter.ToUInt32(vh_sector, 0x014); // Block size
|
||||
|
||||
drAlBlSt = BigEndianBitConverter.ToUInt16(vh_sector, 0x01C); // Start of allocated blocks (in 512-byte/block)
|
||||
|
||||
hfsp_offset = (drAlBlSt + xdrStABNt * (drAlBlkSiz / 512)) * (imagePlugin.GetSectorSize() / 512);
|
||||
}
|
||||
else
|
||||
{
|
||||
hfsp_offset = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
hfsp_offset = 0;
|
||||
}
|
||||
|
||||
vh_sector = imagePlugin.ReadSector(2 + partitionStart + hfsp_offset); // Read volume header
|
||||
|
||||
drSigWord = BigEndianBitConverter.ToUInt16(vh_sector, 0);
|
||||
if (drSigWord == HFSP_MAGIC || drSigWord == HFSX_MAGIC)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
public override void GetInformation(ImagePlugins.ImagePlugin imagePlugin, ulong partitionStart, ulong partitionEnd, out string information)
|
||||
{
|
||||
information = "";
|
||||
|
||||
UInt16 drSigWord;
|
||||
UInt16 xdrStABNt;
|
||||
UInt16 drAlBlSt;
|
||||
UInt32 drAlBlkSiz;
|
||||
HFSPlusVolumeHeader HPVH = new HFSPlusVolumeHeader();
|
||||
|
||||
ulong hfsp_offset;
|
||||
bool wrapped;
|
||||
byte[] vh_sector;
|
||||
|
||||
vh_sector = imagePlugin.ReadSector(2 + partitionStart); // Read volume header, of HFS Wrapper MDB
|
||||
|
||||
drSigWord = BigEndianBitConverter.ToUInt16(vh_sector, 0); // Check for HFS Wrapper MDB
|
||||
|
||||
if (drSigWord == HFS_MAGIC) // "BD"
|
||||
{
|
||||
drSigWord = BigEndianBitConverter.ToUInt16(vh_sector, 0x07C); // Read embedded HFS+ signature
|
||||
|
||||
if (drSigWord == HFSP_MAGIC) // "H+"
|
||||
{
|
||||
xdrStABNt = BigEndianBitConverter.ToUInt16(vh_sector, 0x07E); // Starting block number of embedded HFS+ volume
|
||||
|
||||
drAlBlkSiz = BigEndianBitConverter.ToUInt32(vh_sector, 0x014); // Block size
|
||||
|
||||
drAlBlSt = BigEndianBitConverter.ToUInt16(vh_sector, 0x01C); // Start of allocated blocks (in 512-byte/block)
|
||||
|
||||
hfsp_offset = (drAlBlSt + xdrStABNt * (drAlBlkSiz / 512)) * (imagePlugin.GetSectorSize() / 512);
|
||||
wrapped = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
hfsp_offset = 0;
|
||||
wrapped = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
hfsp_offset = 0;
|
||||
wrapped = false;
|
||||
}
|
||||
|
||||
vh_sector = imagePlugin.ReadSector(2 + partitionStart + hfsp_offset); // Read volume header
|
||||
|
||||
HPVH.signature = BigEndianBitConverter.ToUInt16(vh_sector, 0x000);
|
||||
if (HPVH.signature == HFSP_MAGIC || HPVH.signature == HFSX_MAGIC)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
if (HPVH.signature == 0x482B)
|
||||
sb.AppendLine("HFS+ filesystem.");
|
||||
if (HPVH.signature == 0x4858)
|
||||
sb.AppendLine("HFSX filesystem.");
|
||||
if (wrapped)
|
||||
sb.AppendLine("Volume is wrapped inside an HFS volume.");
|
||||
|
||||
HPVH.version = BigEndianBitConverter.ToUInt16(vh_sector, 0x002);
|
||||
|
||||
if (HPVH.version == 4 || HPVH.version == 5)
|
||||
{
|
||||
HPVH.attributes = BigEndianBitConverter.ToUInt32(vh_sector, 0x004);
|
||||
byte[] lastMountedVersion_b = new byte[4];
|
||||
Array.Copy(vh_sector, 0x008, lastMountedVersion_b, 0, 4);
|
||||
HPVH.lastMountedVersion = Encoding.ASCII.GetString(lastMountedVersion_b);
|
||||
HPVH.journalInfoBlock = BigEndianBitConverter.ToUInt32(vh_sector, 0x00C);
|
||||
|
||||
HPVH.createDate = BigEndianBitConverter.ToUInt32(vh_sector, 0x010);
|
||||
HPVH.modifyDate = BigEndianBitConverter.ToUInt32(vh_sector, 0x018);
|
||||
HPVH.backupDate = BigEndianBitConverter.ToUInt32(vh_sector, 0x020);
|
||||
HPVH.checkedDate = BigEndianBitConverter.ToUInt32(vh_sector, 0x028);
|
||||
|
||||
HPVH.fileCount = BigEndianBitConverter.ToUInt32(vh_sector, 0x030);
|
||||
HPVH.folderCount = BigEndianBitConverter.ToUInt32(vh_sector, 0x034);
|
||||
|
||||
HPVH.blockSize = BigEndianBitConverter.ToUInt32(vh_sector, 0x038);
|
||||
HPVH.totalBlocks = BigEndianBitConverter.ToUInt32(vh_sector, 0x03C);
|
||||
HPVH.freeBlocks = BigEndianBitConverter.ToUInt32(vh_sector, 0x040);
|
||||
|
||||
HPVH.nextAllocation = BigEndianBitConverter.ToUInt32(vh_sector, 0x044);
|
||||
HPVH.rsrcClumpSize = BigEndianBitConverter.ToUInt32(vh_sector, 0x048);
|
||||
HPVH.dataClumpSize = BigEndianBitConverter.ToUInt32(vh_sector, 0x04C);
|
||||
HPVH.nextCatalogID = BigEndianBitConverter.ToUInt32(vh_sector, 0x050);
|
||||
|
||||
HPVH.writeCount = BigEndianBitConverter.ToUInt32(vh_sector, 0x054);
|
||||
|
||||
HPVH.drFndrInfo0 = BigEndianBitConverter.ToUInt32(vh_sector, 0x060);
|
||||
HPVH.drFndrInfo1 = BigEndianBitConverter.ToUInt32(vh_sector, 0x064);
|
||||
HPVH.drFndrInfo2 = BigEndianBitConverter.ToUInt32(vh_sector, 0x068);
|
||||
HPVH.drFndrInfo3 = BigEndianBitConverter.ToUInt32(vh_sector, 0x06C);
|
||||
HPVH.drFndrInfo5 = BigEndianBitConverter.ToUInt32(vh_sector, 0x074);
|
||||
HPVH.drFndrInfo6 = BigEndianBitConverter.ToUInt32(vh_sector, 0x078);
|
||||
HPVH.drFndrInfo7 = BigEndianBitConverter.ToUInt32(vh_sector, 0x07C);
|
||||
|
||||
HPVH.allocationFile_logicalSize = BigEndianBitConverter.ToUInt64(vh_sector, 0x080);
|
||||
HPVH.extentsFile_logicalSize = BigEndianBitConverter.ToUInt64(vh_sector, 0x0D0);
|
||||
HPVH.catalogFile_logicalSize = BigEndianBitConverter.ToUInt64(vh_sector, 0x120);
|
||||
HPVH.attributesFile_logicalSize = BigEndianBitConverter.ToUInt64(vh_sector, 0x170);
|
||||
HPVH.startupFile_logicalSize = BigEndianBitConverter.ToUInt64(vh_sector, 0x1C0);
|
||||
|
||||
sb.AppendFormat("Filesystem version is {0}.", HPVH.version).AppendLine();
|
||||
|
||||
if ((HPVH.attributes & 0x80) == 0x80)
|
||||
sb.AppendLine("Volume is locked on hardware.");
|
||||
if ((HPVH.attributes & 0x100) == 0x100)
|
||||
sb.AppendLine("Volume is unmounted.");
|
||||
if ((HPVH.attributes & 0x200) == 0x200)
|
||||
sb.AppendLine("There are bad blocks in the extents file.");
|
||||
if ((HPVH.attributes & 0x400) == 0x400)
|
||||
sb.AppendLine("Volume does not require cache.");
|
||||
if ((HPVH.attributes & 0x800) == 0x800)
|
||||
sb.AppendLine("Volume state is inconsistent.");
|
||||
if ((HPVH.attributes & 0x1000) == 0x1000)
|
||||
sb.AppendLine("CNIDs are reused.");
|
||||
if ((HPVH.attributes & 0x2000) == 0x2000)
|
||||
sb.AppendLine("Volume is journaled.");
|
||||
if ((HPVH.attributes & 0x8000) == 0x8000)
|
||||
sb.AppendLine("Volume is locked on software.");
|
||||
|
||||
sb.AppendFormat("Implementation that last mounted the volume: \"{0}\".", HPVH.lastMountedVersion).AppendLine();
|
||||
if ((HPVH.attributes & 0x2000) == 0x2000)
|
||||
sb.AppendFormat("Journal starts at allocation block {0}.", HPVH.journalInfoBlock).AppendLine();
|
||||
sb.AppendFormat("Creation date: {0}", DateHandlers.MacToDateTime(HPVH.createDate)).AppendLine();
|
||||
sb.AppendFormat("Last modification date: {0}", DateHandlers.MacToDateTime(HPVH.modifyDate)).AppendLine();
|
||||
sb.AppendFormat("Last backup date: {0}", DateHandlers.MacToDateTime(HPVH.backupDate)).AppendLine();
|
||||
sb.AppendFormat("Last check date: {0}", DateHandlers.MacToDateTime(HPVH.checkedDate)).AppendLine();
|
||||
sb.AppendFormat("{0} files on volume.", HPVH.fileCount).AppendLine();
|
||||
sb.AppendFormat("{0} folders on volume.", HPVH.folderCount).AppendLine();
|
||||
sb.AppendFormat("{0} bytes per allocation block.", HPVH.blockSize).AppendLine();
|
||||
sb.AppendFormat("{0} allocation blocks.", HPVH.totalBlocks).AppendLine();
|
||||
sb.AppendFormat("{0} free blocks.", HPVH.freeBlocks).AppendLine();
|
||||
sb.AppendFormat("Next allocation block: {0}.", HPVH.nextAllocation).AppendLine();
|
||||
sb.AppendFormat("Resource fork clump size: {0} bytes.", HPVH.rsrcClumpSize).AppendLine();
|
||||
sb.AppendFormat("Data fork clump size: {0} bytes.", HPVH.dataClumpSize).AppendLine();
|
||||
sb.AppendFormat("Next unused CNID: {0}.", HPVH.nextCatalogID).AppendLine();
|
||||
sb.AppendFormat("Volume has been mounted writable {0} times.", HPVH.writeCount).AppendLine();
|
||||
sb.AppendFormat("Allocation File is {0} bytes.", HPVH.allocationFile_logicalSize).AppendLine();
|
||||
sb.AppendFormat("Extents File is {0} bytes.", HPVH.extentsFile_logicalSize).AppendLine();
|
||||
sb.AppendFormat("Catalog File is {0} bytes.", HPVH.catalogFile_logicalSize).AppendLine();
|
||||
sb.AppendFormat("Attributes File is {0} bytes.", HPVH.attributesFile_logicalSize).AppendLine();
|
||||
sb.AppendFormat("Startup File is {0} bytes.", HPVH.startupFile_logicalSize).AppendLine();
|
||||
sb.AppendLine("Finder info:");
|
||||
sb.AppendFormat("CNID of bootable system's directory: {0}", HPVH.drFndrInfo0).AppendLine();
|
||||
sb.AppendFormat("CNID of first-run application's directory: {0}", HPVH.drFndrInfo1).AppendLine();
|
||||
sb.AppendFormat("CNID of previously opened directory: {0}", HPVH.drFndrInfo2).AppendLine();
|
||||
sb.AppendFormat("CNID of bootable Mac OS 8 or 9 directory: {0}", HPVH.drFndrInfo3).AppendLine();
|
||||
sb.AppendFormat("CNID of bootable Mac OS X directory: {0}", HPVH.drFndrInfo5).AppendLine();
|
||||
sb.AppendFormat("Mac OS X Volume ID: {0:X8}{1:X8}", HPVH.drFndrInfo6, HPVH.drFndrInfo7).AppendLine();
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.AppendFormat("Filesystem version is {0}.", HPVH.version).AppendLine();
|
||||
sb.AppendLine("This version is not supported yet.");
|
||||
}
|
||||
|
||||
information = sb.ToString();
|
||||
}
|
||||
else
|
||||
return;
|
||||
}
|
||||
// Size = 532 bytes
|
||||
struct HFSPlusVolumeHeader // Should be offset 0x0400 bytes in volume
|
||||
{
|
||||
public UInt16 signature;
|
||||
// 0x000, "H+" for HFS+, "HX" for HFSX
|
||||
public UInt16 version;
|
||||
// 0x002, 4 for HFS+, 5 for HFSX
|
||||
public UInt32 attributes;
|
||||
// 0x004, Volume attributes
|
||||
public string lastMountedVersion;
|
||||
// 0x008, Implementation that last mounted the volume.
|
||||
// Reserved by Apple:
|
||||
// "8.10" Mac OS 8.1 to 9.2.2
|
||||
// "10.0" Mac OS X
|
||||
// "HFSJ" Journaled implementation
|
||||
// "fsck" /sbin/fsck
|
||||
public UInt32 journalInfoBlock;
|
||||
// 0x00C, Allocation block number containing the journal
|
||||
public ulong createDate;
|
||||
// 0x010, Date of volume creation
|
||||
public ulong modifyDate;
|
||||
// 0x018, Date of last volume modification
|
||||
public ulong backupDate;
|
||||
// 0x020, Date of last backup
|
||||
public ulong checkedDate;
|
||||
// 0x028, Date of last consistency check
|
||||
public UInt32 fileCount;
|
||||
// 0x030, File on the volume
|
||||
public UInt32 folderCount;
|
||||
// 0x034, Folders on the volume
|
||||
public UInt32 blockSize;
|
||||
// 0x038, Bytes per allocation block
|
||||
public UInt32 totalBlocks;
|
||||
// 0x03C, Allocation blocks on the volume
|
||||
public UInt32 freeBlocks;
|
||||
// 0x040, Free allocation blocks
|
||||
public UInt32 nextAllocation;
|
||||
// 0x044, Hint for next allocation block
|
||||
public UInt32 rsrcClumpSize;
|
||||
// 0x048, Resource fork clump size
|
||||
public UInt32 dataClumpSize;
|
||||
// 0x04C, Data fork clump size
|
||||
public UInt32 nextCatalogID;
|
||||
// 0x050, Next unused CNID
|
||||
public UInt32 writeCount;
|
||||
// 0x054, Times that the volume has been mounted writable
|
||||
public UInt64 encodingsBitmap;
|
||||
// 0x058, Used text encoding hints
|
||||
public UInt32 drFndrInfo0;
|
||||
// 0x060, finderInfo[0], CNID for bootable system's directory
|
||||
public UInt32 drFndrInfo1;
|
||||
// 0x064, finderInfo[1], CNID of the directory containing the boot application
|
||||
public UInt32 drFndrInfo2;
|
||||
// 0x068, finderInfo[2], CNID of the directory that should be opened on boot
|
||||
public UInt32 drFndrInfo3;
|
||||
// 0x06C, finderInfo[3], CNID for Mac OS 8 or 9 directory
|
||||
public UInt32 drFndrInfo4;
|
||||
// 0x070, finderInfo[4], Reserved
|
||||
public UInt32 drFndrInfo5;
|
||||
// 0x074, finderInfo[5], CNID for Mac OS X directory
|
||||
public UInt32 drFndrInfo6;
|
||||
// 0x078, finderInfo[6], first part of Mac OS X volume ID
|
||||
public UInt32 drFndrInfo7;
|
||||
// 0x07C, finderInfo[7], second part of Mac OS X volume ID
|
||||
// HFSPlusForkData allocationFile;
|
||||
public UInt64 allocationFile_logicalSize;
|
||||
// 0x080
|
||||
public UInt32 allocationFile_clumpSize;
|
||||
// 0x088
|
||||
public UInt32 allocationFile_totalBlocks;
|
||||
// 0x08C
|
||||
public UInt32 allocationFile_extents_startBlock0;
|
||||
// 0x090
|
||||
public UInt32 allocationFile_extents_blockCount0;
|
||||
// 0x094
|
||||
public UInt32 allocationFile_extents_startBlock1;
|
||||
// 0x098
|
||||
public UInt32 allocationFile_extents_blockCount1;
|
||||
// 0x09C
|
||||
public UInt32 allocationFile_extents_startBlock2;
|
||||
// 0x0A0
|
||||
public UInt32 allocationFile_extents_blockCount2;
|
||||
// 0x0A4
|
||||
public UInt32 allocationFile_extents_startBlock3;
|
||||
// 0x0A8
|
||||
public UInt32 allocationFile_extents_blockCount3;
|
||||
// 0x0AC
|
||||
public UInt32 allocationFile_extents_startBlock4;
|
||||
// 0x0B0
|
||||
public UInt32 allocationFile_extents_blockCount4;
|
||||
// 0x0B4
|
||||
public UInt32 allocationFile_extents_startBlock5;
|
||||
// 0x0B8
|
||||
public UInt32 allocationFile_extents_blockCount5;
|
||||
// 0x0BC
|
||||
public UInt32 allocationFile_extents_startBlock6;
|
||||
// 0x0C0
|
||||
public UInt32 allocationFile_extents_blockCount6;
|
||||
// 0x0C4
|
||||
public UInt32 allocationFile_extents_startBlock7;
|
||||
// 0x0C8
|
||||
public UInt32 allocationFile_extents_blockCount7;
|
||||
// 0x0CC
|
||||
// HFSPlusForkData extentsFile;
|
||||
public UInt64 extentsFile_logicalSize;
|
||||
// 0x0D0
|
||||
public UInt32 extentsFile_clumpSize;
|
||||
// 0x0D8
|
||||
public UInt32 extentsFile_totalBlocks;
|
||||
// 0x0DC
|
||||
public UInt32 extentsFile_extents_startBlock0;
|
||||
// 0x0E0
|
||||
public UInt32 extentsFile_extents_blockCount0;
|
||||
// 0x0E4
|
||||
public UInt32 extentsFile_extents_startBlock1;
|
||||
// 0x0E8
|
||||
public UInt32 extentsFile_extents_blockCount1;
|
||||
// 0x0EC
|
||||
public UInt32 extentsFile_extents_startBlock2;
|
||||
// 0x0F0
|
||||
public UInt32 extentsFile_extents_blockCount2;
|
||||
// 0x0F4
|
||||
public UInt32 extentsFile_extents_startBlock3;
|
||||
// 0x0F8
|
||||
public UInt32 extentsFile_extents_blockCount3;
|
||||
// 0x0FC
|
||||
public UInt32 extentsFile_extents_startBlock4;
|
||||
// 0x100
|
||||
public UInt32 extentsFile_extents_blockCount4;
|
||||
// 0x104
|
||||
public UInt32 extentsFile_extents_startBlock5;
|
||||
// 0x108
|
||||
public UInt32 extentsFile_extents_blockCount5;
|
||||
// 0x10C
|
||||
public UInt32 extentsFile_extents_startBlock6;
|
||||
// 0x110
|
||||
public UInt32 extentsFile_extents_blockCount6;
|
||||
// 0x114
|
||||
public UInt32 extentsFile_extents_startBlock7;
|
||||
// 0x118
|
||||
public UInt32 extentsFile_extents_blockCount7;
|
||||
// 0x11C
|
||||
// HFSPlusForkData catalogFile;
|
||||
public UInt64 catalogFile_logicalSize;
|
||||
// 0x120
|
||||
public UInt32 catalogFile_clumpSize;
|
||||
// 0x128
|
||||
public UInt32 catalogFile_totalBlocks;
|
||||
// 0x12C
|
||||
public UInt32 catalogFile_extents_startBlock0;
|
||||
// 0x130
|
||||
public UInt32 catalogFile_extents_blockCount0;
|
||||
// 0x134
|
||||
public UInt32 catalogFile_extents_startBlock1;
|
||||
// 0x138
|
||||
public UInt32 catalogFile_extents_blockCount1;
|
||||
// 0x13C
|
||||
public UInt32 catalogFile_extents_startBlock2;
|
||||
// 0x140
|
||||
public UInt32 catalogFile_extents_blockCount2;
|
||||
// 0x144
|
||||
public UInt32 catalogFile_extents_startBlock3;
|
||||
// 0x148
|
||||
public UInt32 catalogFile_extents_blockCount3;
|
||||
// 0x14C
|
||||
public UInt32 catalogFile_extents_startBlock4;
|
||||
// 0x150
|
||||
public UInt32 catalogFile_extents_blockCount4;
|
||||
// 0x154
|
||||
public UInt32 catalogFile_extents_startBlock5;
|
||||
// 0x158
|
||||
public UInt32 catalogFile_extents_blockCount5;
|
||||
// 0x15C
|
||||
public UInt32 catalogFile_extents_startBlock6;
|
||||
// 0x160
|
||||
public UInt32 catalogFile_extents_blockCount6;
|
||||
// 0x164
|
||||
public UInt32 catalogFile_extents_startBlock7;
|
||||
// 0x168
|
||||
public UInt32 catalogFile_extents_blockCount7;
|
||||
// 0x16C
|
||||
// HFSPlusForkData attributesFile;
|
||||
public UInt64 attributesFile_logicalSize;
|
||||
// 0x170
|
||||
public UInt32 attributesFile_clumpSize;
|
||||
// 0x178
|
||||
public UInt32 attributesFile_totalBlocks;
|
||||
// 0x17C
|
||||
public UInt32 attributesFile_extents_startBlock0;
|
||||
// 0x180
|
||||
public UInt32 attributesFile_extents_blockCount0;
|
||||
// 0x184
|
||||
public UInt32 attributesFile_extents_startBlock1;
|
||||
// 0x188
|
||||
public UInt32 attributesFile_extents_blockCount1;
|
||||
// 0x18C
|
||||
public UInt32 attributesFile_extents_startBlock2;
|
||||
// 0x190
|
||||
public UInt32 attributesFile_extents_blockCount2;
|
||||
// 0x194
|
||||
public UInt32 attributesFile_extents_startBlock3;
|
||||
// 0x198
|
||||
public UInt32 attributesFile_extents_blockCount3;
|
||||
// 0x19C
|
||||
public UInt32 attributesFile_extents_startBlock4;
|
||||
// 0x1A0
|
||||
public UInt32 attributesFile_extents_blockCount4;
|
||||
// 0x1A4
|
||||
public UInt32 attributesFile_extents_startBlock5;
|
||||
// 0x1A8
|
||||
public UInt32 attributesFile_extents_blockCount5;
|
||||
// 0x1AC
|
||||
public UInt32 attributesFile_extents_startBlock6;
|
||||
// 0x1B0
|
||||
public UInt32 attributesFile_extents_blockCount6;
|
||||
// 0x1B4
|
||||
public UInt32 attributesFile_extents_startBlock7;
|
||||
// 0x1B8
|
||||
public UInt32 attributesFile_extents_blockCount7;
|
||||
// 0x1BC
|
||||
// HFSPlusForkData startupFile;
|
||||
public UInt64 startupFile_logicalSize;
|
||||
// 0x1C0
|
||||
public UInt32 startupFile_clumpSize;
|
||||
// 0x1C8
|
||||
public UInt32 startupFile_totalBlocks;
|
||||
// 0x1CC
|
||||
public UInt32 startupFile_extents_startBlock0;
|
||||
// 0x1D0
|
||||
public UInt32 startupFile_extents_blockCount0;
|
||||
// 0x1D4
|
||||
public UInt32 startupFile_extents_startBlock1;
|
||||
// 0x1D8
|
||||
public UInt32 startupFile_extents_blockCount1;
|
||||
// 0x1E0
|
||||
public UInt32 startupFile_extents_startBlock2;
|
||||
// 0x1E4
|
||||
public UInt32 startupFile_extents_blockCount2;
|
||||
// 0x1E8
|
||||
public UInt32 startupFile_extents_startBlock3;
|
||||
// 0x1EC
|
||||
public UInt32 startupFile_extents_blockCount3;
|
||||
// 0x1F0
|
||||
public UInt32 startupFile_extents_startBlock4;
|
||||
// 0x1F4
|
||||
public UInt32 startupFile_extents_blockCount4;
|
||||
// 0x1F8
|
||||
public UInt32 startupFile_extents_startBlock5;
|
||||
// 0x1FC
|
||||
public UInt32 startupFile_extents_blockCount5;
|
||||
// 0x200
|
||||
public UInt32 startupFile_extents_startBlock6;
|
||||
// 0x204
|
||||
public UInt32 startupFile_extents_blockCount6;
|
||||
// 0x208
|
||||
public UInt32 startupFile_extents_startBlock7;
|
||||
// 0x20C
|
||||
public UInt32 startupFile_extents_blockCount7;
|
||||
// 0x210
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,275 +0,0 @@
|
||||
/***************************************************************************
|
||||
The Disc Image Chef
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
Filename : AppleMFS.cs
|
||||
Version : 1.0
|
||||
Author(s) : Natalia Portillo
|
||||
|
||||
Component : Filesystem plugins
|
||||
|
||||
Revision : $Revision$
|
||||
Last change by : $Author$
|
||||
Date : $Date$
|
||||
|
||||
--[ Description ] ----------------------------------------------------------
|
||||
|
||||
Identifies the Macintosh FileSystem and shows information.
|
||||
|
||||
--[ License ] --------------------------------------------------------------
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
----------------------------------------------------------------------------
|
||||
Copyright (C) 2011-2014 Claunia.com
|
||||
****************************************************************************/
|
||||
//$Id$
|
||||
|
||||
using System;
|
||||
using System.Text;
|
||||
using DiscImageChef;
|
||||
|
||||
// Information from Inside Macintosh
|
||||
namespace DiscImageChef.Plugins
|
||||
{
|
||||
class AppleMFS : Plugin
|
||||
{
|
||||
const UInt16 MFS_MAGIC = 0xD2D7;
|
||||
// "LK"
|
||||
const UInt16 MFSBB_MAGIC = 0x4C4B;
|
||||
|
||||
public AppleMFS(PluginBase Core)
|
||||
{
|
||||
Name = "Apple Macintosh File System";
|
||||
PluginUUID = new Guid("36405F8D-0D26-4066-6538-5DBF5D065C3A");
|
||||
}
|
||||
|
||||
public override bool Identify(ImagePlugins.ImagePlugin imagePlugin, ulong partitionStart, ulong partitionEnd)
|
||||
{
|
||||
UInt16 drSigWord;
|
||||
|
||||
if ((2 + partitionStart) >= imagePlugin.GetSectors())
|
||||
return false;
|
||||
|
||||
byte[] mdb_sector = imagePlugin.ReadSector(2 + partitionStart);
|
||||
|
||||
drSigWord = BigEndianBitConverter.ToUInt16(mdb_sector, 0x000);
|
||||
|
||||
return drSigWord == MFS_MAGIC;
|
||||
}
|
||||
|
||||
public override void GetInformation(ImagePlugins.ImagePlugin imagePlugin, ulong partitionStart, ulong partitionEnd, out string information)
|
||||
{
|
||||
information = "";
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
MFS_MasterDirectoryBlock MDB = new MFS_MasterDirectoryBlock();
|
||||
MFS_BootBlock BB = new MFS_BootBlock();
|
||||
|
||||
byte[] pString = new byte[16];
|
||||
byte[] variable_size;
|
||||
|
||||
byte[] mdb_sector = imagePlugin.ReadSector(2 + partitionStart);
|
||||
byte[] bb_sector = imagePlugin.ReadSector(0 + partitionStart);
|
||||
|
||||
MDB.drSigWord = BigEndianBitConverter.ToUInt16(mdb_sector, 0x000);
|
||||
if (MDB.drSigWord != MFS_MAGIC)
|
||||
return;
|
||||
|
||||
MDB.drCrDate = BigEndianBitConverter.ToUInt32(mdb_sector, 0x002);
|
||||
MDB.drLsBkUp = BigEndianBitConverter.ToUInt32(mdb_sector, 0x006);
|
||||
MDB.drAtrb = BigEndianBitConverter.ToUInt16(mdb_sector, 0x00A);
|
||||
MDB.drNmFls = BigEndianBitConverter.ToUInt16(mdb_sector, 0x00C);
|
||||
MDB.drDirSt = BigEndianBitConverter.ToUInt16(mdb_sector, 0x00E);
|
||||
MDB.drBlLen = BigEndianBitConverter.ToUInt16(mdb_sector, 0x010);
|
||||
MDB.drNmAlBlks = BigEndianBitConverter.ToUInt16(mdb_sector, 0x012);
|
||||
MDB.drAlBlkSiz = BigEndianBitConverter.ToUInt32(mdb_sector, 0x014);
|
||||
MDB.drClpSiz = BigEndianBitConverter.ToUInt32(mdb_sector, 0x018);
|
||||
MDB.drAlBlSt = BigEndianBitConverter.ToUInt16(mdb_sector, 0x01C);
|
||||
MDB.drNxtFNum = BigEndianBitConverter.ToUInt32(mdb_sector, 0x01E);
|
||||
MDB.drFreeBks = BigEndianBitConverter.ToUInt16(mdb_sector, 0x022);
|
||||
MDB.drVNSiz = mdb_sector[0x024];
|
||||
variable_size = new byte[MDB.drVNSiz];
|
||||
Array.Copy(mdb_sector, 0x025, variable_size, 0, MDB.drVNSiz);
|
||||
MDB.drVN = Encoding.ASCII.GetString(variable_size);
|
||||
|
||||
BB.signature = BigEndianBitConverter.ToUInt16(bb_sector, 0x000);
|
||||
|
||||
if (BB.signature == MFSBB_MAGIC)
|
||||
{
|
||||
BB.branch = BigEndianBitConverter.ToUInt32(bb_sector, 0x002);
|
||||
BB.boot_flags = bb_sector[0x006];
|
||||
BB.boot_version = bb_sector[0x007];
|
||||
|
||||
BB.sec_sv_pages = BigEndianBitConverter.ToInt16(bb_sector, 0x008);
|
||||
|
||||
Array.Copy(mdb_sector, 0x00A, pString, 0, 16);
|
||||
BB.system_name = StringHandlers.PascalToString(pString);
|
||||
Array.Copy(mdb_sector, 0x01A, pString, 0, 16);
|
||||
BB.finder_name = StringHandlers.PascalToString(pString);
|
||||
Array.Copy(mdb_sector, 0x02A, pString, 0, 16);
|
||||
BB.debug_name = StringHandlers.PascalToString(pString);
|
||||
Array.Copy(mdb_sector, 0x03A, pString, 0, 16);
|
||||
BB.disasm_name = StringHandlers.PascalToString(pString);
|
||||
Array.Copy(mdb_sector, 0x04A, pString, 0, 16);
|
||||
BB.stupscr_name = StringHandlers.PascalToString(pString);
|
||||
Array.Copy(mdb_sector, 0x05A, pString, 0, 16);
|
||||
BB.bootup_name = StringHandlers.PascalToString(pString);
|
||||
Array.Copy(mdb_sector, 0x06A, pString, 0, 16);
|
||||
BB.clipbrd_name = StringHandlers.PascalToString(pString);
|
||||
|
||||
BB.max_files = BigEndianBitConverter.ToUInt16(bb_sector, 0x07A);
|
||||
BB.queue_size = BigEndianBitConverter.ToUInt16(bb_sector, 0x07C);
|
||||
BB.heap_128k = BigEndianBitConverter.ToUInt32(bb_sector, 0x07E);
|
||||
BB.heap_256k = BigEndianBitConverter.ToUInt32(bb_sector, 0x082);
|
||||
BB.heap_512k = BigEndianBitConverter.ToUInt32(bb_sector, 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 block: {0}", MDB.drDirSt).AppendLine();
|
||||
sb.AppendFormat("{0} blocks in directory.", MDB.drBlLen).AppendLine();
|
||||
sb.AppendFormat("{0} volume allocation blocks.", MDB.drNmAlBlks).AppendLine();
|
||||
sb.AppendFormat("Size of allocation blocks: {0}", MDB.drAlBlkSiz).AppendLine();
|
||||
sb.AppendFormat("{0} bytes to allocate.", MDB.drClpSiz).AppendLine();
|
||||
sb.AppendFormat("{0} first allocation block.", 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();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
struct MFS_MasterDirectoryBlock // Should be offset 0x0400 bytes in volume
|
||||
{
|
||||
// 0x000, Signature, 0xD2D7
|
||||
public UInt16 drSigWord;
|
||||
// 0x002, Volume creation date
|
||||
public UInt32 drCrDate;
|
||||
// 0x006, Volume last backup date
|
||||
public UInt32 drLsBkUp;
|
||||
// 0x00A, Volume attributes
|
||||
public UInt16 drAtrb;
|
||||
// 0x00C, Volume number of files
|
||||
public UInt16 drNmFls;
|
||||
// 0x00E, First directory block
|
||||
public UInt16 drDirSt;
|
||||
// 0x010, Length of directory in blocks
|
||||
public UInt16 drBlLen;
|
||||
// 0x012, Volume allocation blocks
|
||||
public UInt16 drNmAlBlks;
|
||||
// 0x014, Size of allocation blocks
|
||||
public UInt32 drAlBlkSiz;
|
||||
// 0x018, Number of bytes to allocate
|
||||
public UInt32 drClpSiz;
|
||||
// 0x01C, First allocation block in block map
|
||||
public UInt16 drAlBlSt;
|
||||
// 0x01E. Next unused file number
|
||||
public UInt32 drNxtFNum;
|
||||
// 0x022, Number of unused allocation blocks
|
||||
public UInt16 drFreeBks;
|
||||
// 0x024, Length of volume name
|
||||
public byte drVNSiz;
|
||||
// 0x025, Characters of volume name
|
||||
public string drVN;
|
||||
}
|
||||
|
||||
struct MFS_BootBlock // Should be offset 0x0000 bytes in volume
|
||||
{
|
||||
public UInt16 signature;
|
||||
// 0x000, Signature, 0x4C4B if bootable
|
||||
public UInt32 branch;
|
||||
// 0x002, Branch
|
||||
public byte boot_flags;
|
||||
// 0x006, Boot block flags
|
||||
public byte boot_version;
|
||||
// 0x007, Boot block version
|
||||
public short sec_sv_pages;
|
||||
// 0x008, Allocate secondary buffers
|
||||
public string system_name;
|
||||
// 0x00A, System file name (16 bytes)
|
||||
public string finder_name;
|
||||
// 0x01A, Finder file name (16 bytes)
|
||||
public string debug_name;
|
||||
// 0x02A, Debugger file name (16 bytes)
|
||||
public string disasm_name;
|
||||
// 0x03A, Disassembler file name (16 bytes)
|
||||
public string stupscr_name;
|
||||
// 0x04A, Startup screen file name (16 bytes)
|
||||
public string bootup_name;
|
||||
// 0x05A, First program to execute on boot (16 bytes)
|
||||
public string clipbrd_name;
|
||||
// 0x06A, Clipboard file name (16 bytes)
|
||||
public UInt16 max_files;
|
||||
// 0x07A, 1/4 of maximum opened at a time files
|
||||
public UInt16 queue_size;
|
||||
// 0x07C, Event queue size
|
||||
public UInt32 heap_128k;
|
||||
// 0x07E, Heap size on a Mac with 128KiB of RAM
|
||||
public UInt32 heap_256k;
|
||||
// 0x082, Heap size on a Mac with 256KiB of RAM
|
||||
public UInt32 heap_512k;
|
||||
// 0x086, Heap size on a Mac with 512KiB of RAM or more
|
||||
}
|
||||
// Follows boot code
|
||||
}
|
||||
}
|
||||
@@ -1,254 +0,0 @@
|
||||
/***************************************************************************
|
||||
The Disc Image Chef
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
Filename : BFS.cs
|
||||
Version : 1.0
|
||||
Author(s) : Natalia Portillo
|
||||
|
||||
Component : Filesystem plugins
|
||||
|
||||
Revision : $Revision$
|
||||
Last change by : $Author$
|
||||
Date : $Date$
|
||||
|
||||
--[ Description ] ----------------------------------------------------------
|
||||
|
||||
Identifies BeOS' filesystem and shows information.
|
||||
|
||||
--[ License ] --------------------------------------------------------------
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
----------------------------------------------------------------------------
|
||||
Copyright (C) 2011-2014 Claunia.com
|
||||
****************************************************************************/
|
||||
//$Id$
|
||||
|
||||
using System;
|
||||
using System.Text;
|
||||
using DiscImageChef;
|
||||
|
||||
// Information from Practical Filesystem Design, ISBN 1-55860-497-9
|
||||
namespace DiscImageChef.Plugins
|
||||
{
|
||||
class BeFS : Plugin
|
||||
{
|
||||
// Little endian constants (that is, as read by .NET :p)
|
||||
const UInt32 BEFS_MAGIC1 = 0x42465331;
|
||||
const UInt32 BEFS_MAGIC2 = 0xDD121031;
|
||||
const UInt32 BEFS_MAGIC3 = 0x15B6830E;
|
||||
const UInt32 BEFS_ENDIAN = 0x42494745;
|
||||
// Big endian constants
|
||||
const UInt32 BEFS_CIGAM1 = 0x31534642;
|
||||
const UInt32 BEFS_NAIDNE = 0x45474942;
|
||||
// Common constants
|
||||
const UInt32 BEFS_CLEAN = 0x434C454E;
|
||||
const UInt32 BEFS_DIRTY = 0x44495254;
|
||||
|
||||
public BeFS(PluginBase Core)
|
||||
{
|
||||
Name = "Be Filesystem";
|
||||
PluginUUID = new Guid("dc8572b3-b6ad-46e4-8de9-cbe123ff6672");
|
||||
}
|
||||
|
||||
public override bool Identify(ImagePlugins.ImagePlugin imagePlugin, ulong partitionStart, ulong partitionEnd)
|
||||
{
|
||||
if ((2 + partitionStart) >= imagePlugin.GetSectors())
|
||||
return false;
|
||||
|
||||
UInt32 magic;
|
||||
UInt32 magic_be;
|
||||
|
||||
byte[] sb_sector = imagePlugin.ReadSector(0 + partitionStart);
|
||||
|
||||
magic = BitConverter.ToUInt32(sb_sector, 0x20);
|
||||
magic_be = BigEndianBitConverter.ToUInt32(sb_sector, 0x20);
|
||||
|
||||
if (magic == BEFS_MAGIC1 || magic_be == BEFS_MAGIC1)
|
||||
return true;
|
||||
sb_sector = imagePlugin.ReadSector(1 + partitionStart);
|
||||
|
||||
magic = BitConverter.ToUInt32(sb_sector, 0x20);
|
||||
magic_be = BigEndianBitConverter.ToUInt32(sb_sector, 0x20);
|
||||
|
||||
if (magic == BEFS_MAGIC1 || magic_be == BEFS_MAGIC1)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
public override void GetInformation(ImagePlugins.ImagePlugin imagePlugin, ulong partitionStart, ulong partitionEnd, out string information)
|
||||
{
|
||||
information = "";
|
||||
byte[] name_bytes = new byte[32];
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
BeSuperBlock besb = new BeSuperBlock();
|
||||
|
||||
byte[] sb_sector = imagePlugin.ReadSector(0 + partitionStart);
|
||||
|
||||
BigEndianBitConverter.IsLittleEndian = true; // Default for little-endian
|
||||
|
||||
besb.magic1 = BigEndianBitConverter.ToUInt32(sb_sector, 0x20);
|
||||
if (besb.magic1 == BEFS_MAGIC1 || besb.magic1 == BEFS_CIGAM1) // Magic is at offset
|
||||
{
|
||||
BigEndianBitConverter.IsLittleEndian &= besb.magic1 != BEFS_CIGAM1;
|
||||
}
|
||||
else
|
||||
{
|
||||
sb_sector = imagePlugin.ReadSector(1 + partitionStart);
|
||||
besb.magic1 = BigEndianBitConverter.ToUInt32(sb_sector, 0x20);
|
||||
|
||||
if (besb.magic1 == BEFS_MAGIC1 || besb.magic1 == BEFS_CIGAM1) // There is a boot sector
|
||||
{
|
||||
BigEndianBitConverter.IsLittleEndian &= besb.magic1 != BEFS_CIGAM1;
|
||||
}
|
||||
else
|
||||
return;
|
||||
}
|
||||
|
||||
Array.Copy(sb_sector, 0x000, name_bytes, 0, 0x20);
|
||||
besb.name = StringHandlers.CToString(name_bytes);
|
||||
besb.magic1 = BigEndianBitConverter.ToUInt32(sb_sector, 0x20);
|
||||
besb.fs_byte_order = BigEndianBitConverter.ToUInt32(sb_sector, 0x20);
|
||||
besb.block_size = BigEndianBitConverter.ToUInt32(sb_sector, 0x20);
|
||||
besb.block_shift = BigEndianBitConverter.ToUInt32(sb_sector, 0x20);
|
||||
besb.num_blocks = BigEndianBitConverter.ToInt64(sb_sector, 0x20);
|
||||
besb.used_blocks = BigEndianBitConverter.ToInt64(sb_sector, 0x20);
|
||||
besb.inode_size = BigEndianBitConverter.ToInt32(sb_sector, 0x20);
|
||||
besb.magic2 = BigEndianBitConverter.ToUInt32(sb_sector, 0x20);
|
||||
besb.blocks_per_ag = BigEndianBitConverter.ToInt32(sb_sector, 0x20);
|
||||
besb.ag_shift = BigEndianBitConverter.ToInt32(sb_sector, 0x20);
|
||||
besb.num_ags = BigEndianBitConverter.ToInt32(sb_sector, 0x20);
|
||||
besb.flags = BigEndianBitConverter.ToUInt32(sb_sector, 0x20);
|
||||
besb.log_blocks_ag = BigEndianBitConverter.ToInt32(sb_sector, 0x20);
|
||||
besb.log_blocks_start = BigEndianBitConverter.ToUInt16(sb_sector, 0x20);
|
||||
besb.log_blocks_len = BigEndianBitConverter.ToUInt16(sb_sector, 0x20);
|
||||
besb.log_start = BigEndianBitConverter.ToInt64(sb_sector, 0x20);
|
||||
besb.log_end = BigEndianBitConverter.ToInt64(sb_sector, 0x20);
|
||||
besb.magic3 = BigEndianBitConverter.ToUInt32(sb_sector, 0x20);
|
||||
besb.root_dir_ag = BigEndianBitConverter.ToInt32(sb_sector, 0x20);
|
||||
besb.root_dir_start = BigEndianBitConverter.ToUInt16(sb_sector, 0x20);
|
||||
besb.root_dir_len = BigEndianBitConverter.ToUInt16(sb_sector, 0x20);
|
||||
besb.indices_ag = BigEndianBitConverter.ToInt32(sb_sector, 0x20);
|
||||
besb.indices_start = BigEndianBitConverter.ToUInt16(sb_sector, 0x20);
|
||||
besb.indices_len = BigEndianBitConverter.ToUInt16(sb_sector, 0x20);
|
||||
|
||||
if (!BigEndianBitConverter.IsLittleEndian) // Big-endian filesystem
|
||||
sb.AppendLine("Big-endian BeFS");
|
||||
else
|
||||
sb.AppendLine("Little-endian BeFS");
|
||||
|
||||
if (besb.magic1 != BEFS_MAGIC1 || besb.fs_byte_order != BEFS_ENDIAN ||
|
||||
besb.magic2 != BEFS_MAGIC2 || besb.magic3 != BEFS_MAGIC3 ||
|
||||
besb.root_dir_len != 1 || besb.indices_len != 1 ||
|
||||
(1 << (int)besb.block_shift) != besb.block_size)
|
||||
{
|
||||
sb.AppendLine("Superblock seems corrupt, following information may be incorrect");
|
||||
sb.AppendFormat("Magic 1: 0x{0:X8} (Should be 0x42465331)", besb.magic1).AppendLine();
|
||||
sb.AppendFormat("Magic 2: 0x{0:X8} (Should be 0xDD121031)", besb.magic2).AppendLine();
|
||||
sb.AppendFormat("Magic 3: 0x{0:X8} (Should be 0x15B6830E)", besb.magic3).AppendLine();
|
||||
sb.AppendFormat("Filesystem endianness: 0x{0:X8} (Should be 0x42494745)", besb.fs_byte_order).AppendLine();
|
||||
sb.AppendFormat("Root folder's i-node size: {0} blocks (Should be 1)", besb.root_dir_len).AppendLine();
|
||||
sb.AppendFormat("Indices' i-node size: {0} blocks (Should be 1)", besb.indices_len).AppendLine();
|
||||
sb.AppendFormat("1 << block_shift == block_size => 1 << {0} == {1} (Should be {2})", besb.block_shift,
|
||||
1 << (int)besb.block_shift, besb.block_size).AppendLine();
|
||||
}
|
||||
|
||||
if (besb.flags == BEFS_CLEAN)
|
||||
{
|
||||
if (besb.log_start == besb.log_end)
|
||||
sb.AppendLine("Filesystem is clean");
|
||||
else
|
||||
sb.AppendLine("Filesystem is dirty");
|
||||
}
|
||||
else if (besb.flags == BEFS_DIRTY)
|
||||
sb.AppendLine("Filesystem is dirty");
|
||||
else
|
||||
sb.AppendFormat("Unknown flags: {0:X8}", besb.flags).AppendLine();
|
||||
|
||||
sb.AppendFormat("Volume name: {0}", besb.name).AppendLine();
|
||||
sb.AppendFormat("{0} bytes per block", besb.block_size).AppendLine();
|
||||
sb.AppendFormat("{0} blocks in volume ({1} bytes)", besb.num_blocks, besb.num_blocks * besb.block_size).AppendLine();
|
||||
sb.AppendFormat("{0} used blocks ({1} bytes)", besb.used_blocks, besb.used_blocks * besb.block_size).AppendLine();
|
||||
sb.AppendFormat("{0} bytes per i-node", besb.inode_size).AppendLine();
|
||||
sb.AppendFormat("{0} blocks per allocation group ({1} bytes)", besb.blocks_per_ag, besb.blocks_per_ag * besb.block_size).AppendLine();
|
||||
sb.AppendFormat("{0} allocation groups in volume", besb.num_ags).AppendLine();
|
||||
sb.AppendFormat("Journal resides in block {0} of allocation group {1} and runs for {2} blocks ({3} bytes)", besb.log_blocks_start,
|
||||
besb.log_blocks_ag, besb.log_blocks_len, besb.log_blocks_len * besb.block_size).AppendLine();
|
||||
sb.AppendFormat("Journal starts in byte {0} and ends in byte {1}", besb.log_start, besb.log_end).AppendLine();
|
||||
sb.AppendFormat("Root folder's i-node resides in block {0} of allocation group {1} and runs for {2} blocks ({3} bytes)", besb.root_dir_start,
|
||||
besb.root_dir_ag, besb.root_dir_len, besb.root_dir_len * besb.block_size).AppendLine();
|
||||
sb.AppendFormat("Indices' i-node resides in block {0} of allocation group {1} and runs for {2} blocks ({3} bytes)", besb.indices_start,
|
||||
besb.indices_ag, besb.indices_len, besb.indices_len * besb.block_size).AppendLine();
|
||||
|
||||
information = sb.ToString();
|
||||
}
|
||||
|
||||
struct BeSuperBlock
|
||||
{
|
||||
public string name;
|
||||
// 0x000, Volume name, 32 bytes
|
||||
public UInt32 magic1;
|
||||
// 0x020, "BFS1", 0x42465331
|
||||
public UInt32 fs_byte_order;
|
||||
// 0x024, "BIGE", 0x42494745
|
||||
public UInt32 block_size;
|
||||
// 0x028, Bytes per block
|
||||
public UInt32 block_shift;
|
||||
// 0x02C, 1 << block_shift == block_size
|
||||
public Int64 num_blocks;
|
||||
// 0x030, Blocks in volume
|
||||
public Int64 used_blocks;
|
||||
// 0x038, Used blocks in volume
|
||||
public Int32 inode_size;
|
||||
// 0x040, Bytes per inode
|
||||
public UInt32 magic2;
|
||||
// 0x044, 0xDD121031
|
||||
public Int32 blocks_per_ag;
|
||||
// 0x048, Blocks per allocation group
|
||||
public Int32 ag_shift;
|
||||
// 0x04C, 1 << ag_shift == blocks_per_ag
|
||||
public Int32 num_ags;
|
||||
// 0x050, Allocation groups in volume
|
||||
public UInt32 flags;
|
||||
// 0x054, 0x434c454e if clean, 0x44495254 if dirty
|
||||
public Int32 log_blocks_ag;
|
||||
// 0x058, Allocation group of journal
|
||||
public UInt16 log_blocks_start;
|
||||
// 0x05C, Start block of journal, inside ag
|
||||
public UInt16 log_blocks_len;
|
||||
// 0x05E, Length in blocks of journal, inside ag
|
||||
public Int64 log_start;
|
||||
// 0x060, Start of journal
|
||||
public Int64 log_end;
|
||||
// 0x068, End of journal
|
||||
public UInt32 magic3;
|
||||
// 0x070, 0x15B6830E
|
||||
public Int32 root_dir_ag;
|
||||
// 0x074, Allocation group where root folder's i-node resides
|
||||
public UInt16 root_dir_start;
|
||||
// 0x078, Start in ag of root folder's i-node
|
||||
public UInt16 root_dir_len;
|
||||
// 0x07A, As this is part of inode_addr, this is 1
|
||||
public Int32 indices_ag;
|
||||
// 0x07C, Allocation group where indices' i-node resides
|
||||
public UInt16 indices_start;
|
||||
// 0x080, Start in ag of indices' i-node
|
||||
public UInt16 indices_len;
|
||||
// 0x082, As this is part of inode_addr, this is 1
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,466 +0,0 @@
|
||||
/***************************************************************************
|
||||
The Disc Image Chef
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
Filename : FAT.cs
|
||||
Version : 1.0
|
||||
Author(s) : Natalia Portillo
|
||||
|
||||
Component : Filesystem plugins
|
||||
|
||||
Revision : $Revision$
|
||||
Last change by : $Author$
|
||||
Date : $Date$
|
||||
|
||||
--[ Description ] ----------------------------------------------------------
|
||||
|
||||
Identifies FAT12/16/32 filesystems and shows information.
|
||||
|
||||
--[ License ] --------------------------------------------------------------
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
----------------------------------------------------------------------------
|
||||
Copyright (C) 2011-2014 Claunia.com
|
||||
****************************************************************************/
|
||||
//$Id$
|
||||
|
||||
using System;
|
||||
using System.Text;
|
||||
using DiscImageChef;
|
||||
|
||||
// TODO: Implement detecting DOS bootable disks
|
||||
// TODO: Implement detecting Atari TOS bootable disks and printing corresponding fields
|
||||
namespace DiscImageChef.Plugins
|
||||
{
|
||||
class FAT : Plugin
|
||||
{
|
||||
public FAT(PluginBase Core)
|
||||
{
|
||||
Name = "Microsoft File Allocation Table";
|
||||
PluginUUID = new Guid("33513B2C-0D26-0D2D-32C3-79D8611158E0");
|
||||
}
|
||||
|
||||
public override bool Identify(ImagePlugins.ImagePlugin imagePlugin, ulong partitionStart, ulong partitionEnd)
|
||||
{
|
||||
if ((2 + partitionStart) >= imagePlugin.GetSectors())
|
||||
return false;
|
||||
|
||||
byte media_descriptor; // Not present on DOS <= 3, present on TOS but != of first FAT entry
|
||||
byte fats_no; // Must be 1 or 2. Dunno if it can be 0 in the wild, but it CANNOT BE bigger than 2
|
||||
byte[] fat32_signature = new byte[8]; // "FAT32 "
|
||||
UInt32 first_fat_entry; // No matter FAT size we read 4 bytes for checking
|
||||
UInt16 bps, rsectors;
|
||||
|
||||
byte[] bpb_sector = imagePlugin.ReadSector(0 + partitionStart);
|
||||
byte[] fat_sector = imagePlugin.ReadSector(1 + partitionStart);
|
||||
|
||||
bool bpb_found = true;
|
||||
|
||||
fats_no = bpb_sector[0x010]; // FATs, 1 or 2, maybe 0, never bigger
|
||||
media_descriptor = bpb_sector[0x015]; // Media Descriptor if present is in 0x15
|
||||
Array.Copy(bpb_sector, 0x52, fat32_signature, 0, 8); // FAT32 signature, if present, is in 0x52
|
||||
bps = BitConverter.ToUInt16(bpb_sector, 0x00B); // Bytes per sector
|
||||
if (bps == 0)
|
||||
bps = 0x200;
|
||||
rsectors = BitConverter.ToUInt16(bpb_sector, 0x00E); // Sectors between BPB and FAT, including the BPB sector => [BPB,FAT)
|
||||
if (rsectors == 0)
|
||||
rsectors = 1;
|
||||
if (imagePlugin.GetSectors() > ((ulong)rsectors + partitionStart))
|
||||
fat_sector = imagePlugin.ReadSector(rsectors + partitionStart); // First FAT entry
|
||||
else
|
||||
bpb_found=false;
|
||||
|
||||
if (bpb_found)
|
||||
{
|
||||
first_fat_entry = BitConverter.ToUInt32(fat_sector, 0); // Easier to manage
|
||||
|
||||
if (MainClass.isDebug)
|
||||
{
|
||||
Console.WriteLine("DEBUG (FAT plugin): fats_no = {0}", fats_no);
|
||||
Console.WriteLine("DEBUG (FAT plugin): media_descriptor = 0x{0:X2}", media_descriptor);
|
||||
Console.WriteLine("DEBUG (FAT plugin): fat32_signature = {0}", StringHandlers.CToString(fat32_signature));
|
||||
Console.WriteLine("DEBUG (FAT plugin): bps = {0}", bps);
|
||||
Console.WriteLine("DEBUG (FAT plugin): first_fat_entry = 0x{0:X8}", first_fat_entry);
|
||||
}
|
||||
|
||||
if (fats_no > 2) // Must be 1 or 2, but as TOS makes strange things and I have not checked if it puts this to 0, ignore if 0. MUST NOT BE BIGGER THAN 2!
|
||||
return false;
|
||||
|
||||
// Let's start the fun
|
||||
if (Encoding.ASCII.GetString(fat32_signature) == "FAT32 ")
|
||||
return true; // Seems easy, check reading
|
||||
|
||||
if ((first_fat_entry & 0xFFFFFFF0) == 0xFFFFFFF0) // Seems to be FAT16
|
||||
{
|
||||
if ((first_fat_entry & 0xFF) == media_descriptor)
|
||||
return true; // It MUST be FAT16, or... maybe not :S
|
||||
}
|
||||
else if ((first_fat_entry & 0x00FFFFF0) == 0x00FFFFF0)
|
||||
{
|
||||
//if((first_fat_entry & 0xFF) == media_descriptor) // Pre DOS<4 does not implement this, TOS does and is !=
|
||||
return true; // It MUST be FAT12, or... maybe not :S
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// This may create a lot of false positives, need to do extensive checkins...
|
||||
fat_sector = imagePlugin.ReadSector(1 + partitionStart);
|
||||
first_fat_entry = BitConverter.ToUInt32(fat_sector, 0);
|
||||
byte fat_id = fat_sector[0];
|
||||
|
||||
if ((first_fat_entry & 0x00FFFFF0) == 0x00FFFFF0)
|
||||
{
|
||||
if (fat_id == 0xFF)
|
||||
{
|
||||
if (imagePlugin.GetSectorSize() == 512 && imagePlugin.GetSectors() == 640)
|
||||
return true;
|
||||
if (imagePlugin.GetSectorSize() == 128)
|
||||
{
|
||||
if(imagePlugin.GetSectors() == 2002)
|
||||
return true;
|
||||
if(imagePlugin.GetSectors() == 4004)
|
||||
return true;
|
||||
}
|
||||
if (imagePlugin.GetSectorSize() == 1024)
|
||||
{
|
||||
if(imagePlugin.GetSectors() == 616)
|
||||
return true;
|
||||
if(imagePlugin.GetSectors() == 1232)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
if (fat_id == 0xFE)
|
||||
{
|
||||
if (imagePlugin.GetSectorSize() == 512 && imagePlugin.GetSectors() == 320)
|
||||
return true;
|
||||
if (imagePlugin.GetSectorSize() == 128)
|
||||
{
|
||||
if(imagePlugin.GetSectors() == 2002)
|
||||
return true;
|
||||
if(imagePlugin.GetSectors() == 4004)
|
||||
return true;
|
||||
}
|
||||
if (imagePlugin.GetSectorSize() == 1024)
|
||||
{
|
||||
if(imagePlugin.GetSectors() == 616)
|
||||
return true;
|
||||
if(imagePlugin.GetSectors() == 1232)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
if (fat_id == 0xFD && imagePlugin.GetSectors() == 2002)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public override void GetInformation(ImagePlugins.ImagePlugin imagePlugin, ulong partitionStart, ulong partitionEnd, out string information)
|
||||
{
|
||||
information = "";
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
byte[] dosString; // Space-padded
|
||||
bool isFAT32 = false;
|
||||
UInt32 first_fat_entry;
|
||||
byte media_descriptor, fats_no;
|
||||
string fat32_signature;
|
||||
UInt16 bps, rsectors;
|
||||
|
||||
byte[] bpb_sector = imagePlugin.ReadSector(0 + partitionStart);
|
||||
byte[] fat_sector = imagePlugin.ReadSector(1 + partitionStart);
|
||||
|
||||
bool bpb_found = true;
|
||||
|
||||
fats_no = bpb_sector[0x010]; // FATs, 1 or 2, maybe 0, never bigger
|
||||
media_descriptor = bpb_sector[0x015]; // Media Descriptor if present is in 0x15
|
||||
dosString = new byte[8];
|
||||
Array.Copy(bpb_sector, 0x52, dosString, 0, 8); // FAT32 signature, if present, is in 0x52
|
||||
fat32_signature = Encoding.ASCII.GetString(dosString);
|
||||
bps = BitConverter.ToUInt16(bpb_sector, 0x00B); // Bytes per sector
|
||||
if (bps == 0)
|
||||
bps = 0x200;
|
||||
rsectors = BitConverter.ToUInt16(bpb_sector, 0x00E); // Sectors between BPB and FAT, including the BPB sector => [BPB,FAT)
|
||||
if (rsectors == 0)
|
||||
rsectors = 1;
|
||||
if (imagePlugin.GetSectors() > ((ulong)rsectors + partitionStart))
|
||||
fat_sector = imagePlugin.ReadSector(rsectors + partitionStart); // First FAT entry
|
||||
else
|
||||
bpb_found=false;
|
||||
|
||||
if (bpb_found)
|
||||
{
|
||||
first_fat_entry = BitConverter.ToUInt32(fat_sector, 0); // Easier to manage
|
||||
|
||||
if (fats_no > 2) // Must be 1 or 2, but as TOS makes strange things and I have not checked if it puts this to 0, ignore if 0. MUST NOT BE BIGGER THAN 2!
|
||||
return;
|
||||
|
||||
// Let's start the fun
|
||||
if (fat32_signature == "FAT32 ")
|
||||
{
|
||||
sb.AppendLine("Microsoft FAT32"); // Seems easy, check reading
|
||||
isFAT32 = true;
|
||||
}
|
||||
else if ((first_fat_entry & 0xFFFFFFF0) == 0xFFFFFFF0) // Seems to be FAT16
|
||||
{
|
||||
if ((first_fat_entry & 0xFF) == media_descriptor)
|
||||
sb.AppendLine("Microsoft FAT16"); // It MUST be FAT16, or... maybe not :S
|
||||
}
|
||||
else if ((first_fat_entry & 0x00FFFFF0) == 0x00FFFFF0)
|
||||
{
|
||||
//if((first_fat_entry & 0xFF) == media_descriptor) // Pre DOS<4 does not implement this, TOS does and is !=
|
||||
sb.AppendLine("Microsoft FAT12"); // It MUST be FAT12, or... maybe not :S
|
||||
}
|
||||
else
|
||||
return;
|
||||
|
||||
BIOSParameterBlock BPB = new BIOSParameterBlock();
|
||||
ExtendedParameterBlock EPB = new ExtendedParameterBlock();
|
||||
FAT32ParameterBlock FAT32PB = new FAT32ParameterBlock();
|
||||
|
||||
dosString = new byte[8];
|
||||
Array.Copy(bpb_sector, 0x03, dosString, 0, 8);
|
||||
BPB.OEMName = Encoding.ASCII.GetString(dosString);
|
||||
BPB.bps = BitConverter.ToUInt16(bpb_sector, 0x0B);
|
||||
BPB.spc = bpb_sector[0x0D];
|
||||
BPB.rsectors = BitConverter.ToUInt16(bpb_sector, 0x0E);
|
||||
BPB.fats_no = bpb_sector[0x10];
|
||||
BPB.root_ent = BitConverter.ToUInt16(bpb_sector, 0x11);
|
||||
BPB.sectors = BitConverter.ToUInt16(bpb_sector, 0x13);
|
||||
BPB.media = bpb_sector[0x15];
|
||||
BPB.spfat = BitConverter.ToUInt16(bpb_sector, 0x16);
|
||||
BPB.sptrk = BitConverter.ToUInt16(bpb_sector, 0x18);
|
||||
BPB.heads = BitConverter.ToUInt16(bpb_sector, 0x1A);
|
||||
BPB.hsectors = BitConverter.ToUInt32(bpb_sector, 0x1C);
|
||||
BPB.big_sectors = BitConverter.ToUInt32(bpb_sector, 0x20);
|
||||
|
||||
if (isFAT32)
|
||||
{
|
||||
FAT32PB.spfat = BitConverter.ToUInt32(bpb_sector, 0x24);
|
||||
FAT32PB.fat_flags = BitConverter.ToUInt16(bpb_sector, 0x28);
|
||||
FAT32PB.version = BitConverter.ToUInt16(bpb_sector, 0x2A);
|
||||
FAT32PB.root_cluster = BitConverter.ToUInt32(bpb_sector, 0x2C);
|
||||
FAT32PB.fsinfo_sector = BitConverter.ToUInt16(bpb_sector, 0x30);
|
||||
FAT32PB.backup_sector = BitConverter.ToUInt16(bpb_sector, 0x32);
|
||||
FAT32PB.drive_no = bpb_sector[0x40];
|
||||
FAT32PB.nt_flags = bpb_sector[0x41];
|
||||
FAT32PB.signature = bpb_sector[0x42];
|
||||
FAT32PB.serial_no = BitConverter.ToUInt32(bpb_sector, 0x43);
|
||||
dosString = new byte[11];
|
||||
Array.Copy(bpb_sector, 0x47, dosString, 0, 11);
|
||||
FAT32PB.volume_label = Encoding.ASCII.GetString(dosString);
|
||||
dosString = new byte[8];
|
||||
Array.Copy(bpb_sector, 0x52, dosString, 0, 8);
|
||||
FAT32PB.fs_type = Encoding.ASCII.GetString(dosString);
|
||||
}
|
||||
else
|
||||
{
|
||||
EPB.drive_no = bpb_sector[0x24];
|
||||
EPB.nt_flags = bpb_sector[0x25];
|
||||
EPB.signature = bpb_sector[0x26];
|
||||
EPB.serial_no = BitConverter.ToUInt32(bpb_sector, 0x27);
|
||||
dosString = new byte[11];
|
||||
Array.Copy(bpb_sector, 0x2B, dosString, 0, 11);
|
||||
EPB.volume_label = Encoding.ASCII.GetString(dosString);
|
||||
dosString = new byte[8];
|
||||
Array.Copy(bpb_sector, 0x36, dosString, 0, 8);
|
||||
EPB.fs_type = Encoding.ASCII.GetString(dosString);
|
||||
}
|
||||
|
||||
sb.AppendFormat("OEM Name: {0}", BPB.OEMName).AppendLine();
|
||||
sb.AppendFormat("{0} bytes per sector.", BPB.bps).AppendLine();
|
||||
sb.AppendFormat("{0} sectors per cluster.", BPB.spc).AppendLine();
|
||||
sb.AppendFormat("{0} sectors reserved between BPB and FAT.", BPB.rsectors).AppendLine();
|
||||
sb.AppendFormat("{0} FATs.", BPB.fats_no).AppendLine();
|
||||
sb.AppendFormat("{0} entries on root directory.", BPB.root_ent).AppendLine();
|
||||
if (BPB.sectors == 0)
|
||||
sb.AppendFormat("{0} sectors on volume ({1} bytes).", BPB.big_sectors, BPB.big_sectors * BPB.bps).AppendLine();
|
||||
else
|
||||
sb.AppendFormat("{0} sectors on volume ({1} bytes).", BPB.sectors, BPB.sectors * BPB.bps).AppendLine();
|
||||
if ((BPB.media & 0xF0) == 0xF0)
|
||||
sb.AppendFormat("Media format: 0x{0:X2}", BPB.media).AppendLine();
|
||||
if (fat32_signature == "FAT32 ")
|
||||
sb.AppendFormat("{0} sectors per FAT.", FAT32PB.spfat).AppendLine();
|
||||
else
|
||||
sb.AppendFormat("{0} sectors per FAT.", BPB.spfat).AppendLine();
|
||||
sb.AppendFormat("{0} sectors per track.", BPB.sptrk).AppendLine();
|
||||
sb.AppendFormat("{0} heads.", BPB.heads).AppendLine();
|
||||
sb.AppendFormat("{0} hidden sectors before BPB.", BPB.hsectors).AppendLine();
|
||||
|
||||
if (isFAT32)
|
||||
{
|
||||
sb.AppendFormat("Cluster of root directory: {0}", FAT32PB.root_cluster).AppendLine();
|
||||
sb.AppendFormat("Sector of FSINFO structure: {0}", FAT32PB.fsinfo_sector).AppendLine();
|
||||
sb.AppendFormat("Sector of backup FAT32 parameter block: {0}", FAT32PB.backup_sector).AppendLine();
|
||||
sb.AppendFormat("Drive number: 0x{0:X2}", FAT32PB.drive_no).AppendLine();
|
||||
sb.AppendFormat("Volume Serial Number: 0x{0:X8}", FAT32PB.serial_no).AppendLine();
|
||||
if ((FAT32PB.nt_flags & 0x01) == 0x01)
|
||||
{
|
||||
sb.AppendLine("Volume should be checked on next mount.");
|
||||
if ((EPB.nt_flags & 0x02) == 0x02)
|
||||
sb.AppendLine("Disk surface should be checked also.");
|
||||
}
|
||||
|
||||
sb.AppendFormat("Volume label: {0}", EPB.volume_label).AppendLine();
|
||||
sb.AppendFormat("Filesystem type: {0}", EPB.fs_type).AppendLine();
|
||||
}
|
||||
else if (EPB.signature == 0x28 || EPB.signature == 0x29)
|
||||
{
|
||||
sb.AppendFormat("Drive number: 0x{0:X2}", EPB.drive_no).AppendLine();
|
||||
sb.AppendFormat("Volume Serial Number: 0x{0:X8}", EPB.serial_no).AppendLine();
|
||||
if (EPB.signature == 0x29)
|
||||
{
|
||||
if ((EPB.nt_flags & 0x01) == 0x01)
|
||||
{
|
||||
sb.AppendLine("Volume should be checked on next mount.");
|
||||
if ((EPB.nt_flags & 0x02) == 0x02)
|
||||
sb.AppendLine("Disk surface should be checked also.");
|
||||
}
|
||||
|
||||
sb.AppendFormat("Volume label: {0}", EPB.volume_label).AppendLine();
|
||||
sb.AppendFormat("Filesystem type: {0}", EPB.fs_type).AppendLine();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.AppendLine("Pre-DOS 2.0 Microsoft FAT12.");
|
||||
sb.AppendLine("***WARNING***");
|
||||
sb.AppendLine("This may be a false positive.");
|
||||
sb.AppendFormat("Disk image identifies disk type as {0}.", imagePlugin.GetDiskType()).AppendLine();
|
||||
}
|
||||
|
||||
information = sb.ToString();
|
||||
}
|
||||
|
||||
/// <summary>FAT's BIOS Parameter Block.</summary>
|
||||
public struct BIOSParameterBlock
|
||||
{
|
||||
/// <summary>0x03, OEM Name, 8 bytes, space-padded</summary>
|
||||
public string OEMName;
|
||||
/// <summary>0x0B, Bytes per sector</summary>
|
||||
public UInt16 bps;
|
||||
/// <summary>0x0D, Sectors per cluster</summary>
|
||||
public byte spc;
|
||||
/// <summary>0x0E, Reserved sectors between BPB and FAT</summary>
|
||||
public UInt16 rsectors;
|
||||
/// <summary>0x10, Number of FATs</summary>
|
||||
public byte fats_no;
|
||||
/// <summary>0x11, Number of entries on root directory</summary>
|
||||
public UInt16 root_ent;
|
||||
/// <summary>0x13, Sectors in volume</summary>
|
||||
public UInt16 sectors;
|
||||
/// <summary>0x15, Media descriptor</summary>
|
||||
public byte media;
|
||||
/// <summary>0x16, Sectors per FAT</summary>
|
||||
public UInt16 spfat;
|
||||
/// <summary>0x18, Sectors per track</summary>
|
||||
public UInt16 sptrk;
|
||||
/// <summary>0x1A, Heads</summary>
|
||||
public UInt16 heads;
|
||||
/// <summary>0x1C, Hidden sectors before BPB</summary>
|
||||
public UInt32 hsectors;
|
||||
/// <summary>0x20, Sectors in volume if > 65535</summary>
|
||||
public UInt32 big_sectors;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Atari Boot Block.
|
||||
/// This only applies for bootable disks
|
||||
/// From http://info-coach.fr/atari/software/FD-Soft.php
|
||||
/// </summary>
|
||||
public struct AtariBootBlock
|
||||
{
|
||||
/// <summary>0x01C, Atari ST use 16 bit for hidden sectors, probably so did old DOS</summary>
|
||||
public UInt16 hsectors;
|
||||
/// <summary>0x01E, indicates if COMMAND.PRG must be executed after OS load</summary>
|
||||
public UInt16 xflag;
|
||||
/// <summary>0x020, load mode for, or 0 if fname indicates boot file</summary>
|
||||
public UInt16 ldmode;
|
||||
/// <summary>0x022, sector from which to boot</summary>
|
||||
public UInt16 bsect;
|
||||
/// <summary>0x024, how many sectors to boot</summary>
|
||||
public UInt16 bsects_no;
|
||||
/// <summary>0x026, RAM address where boot should be located</summary>
|
||||
public UInt32 ldaddr;
|
||||
/// <summary>0x02A, RAM address to copy the FAT and root directory</summary>
|
||||
public UInt32 fatbuf;
|
||||
/// <summary>0x02E, 11 bytes, name of boot file</summary>
|
||||
public string fname;
|
||||
/// <summary>0x039, unused</summary>
|
||||
public UInt16 reserved;
|
||||
/// <summary>0x03B, 451 bytes boot code</summary>
|
||||
public byte[] boot_code;
|
||||
/// <summary>0x1FE, the sum of all the BPB+ABB must be 0x1234, so this bigendian value works as adjustment</summary>
|
||||
public UInt16 checksum;
|
||||
}
|
||||
|
||||
/// <summary>DOS Extended Parameter Block</summary>
|
||||
public struct ExtendedParameterBlock
|
||||
{
|
||||
/// <summary>0x24, Drive number<summary>
|
||||
public byte drive_no;
|
||||
/// <summary>0x25, Volume flags if NT (must be 0x29 signature)<summary>
|
||||
public byte nt_flags;
|
||||
/// <summary>0x26, EPB signature, 0x28 or 0x29<summary>
|
||||
public byte signature;
|
||||
/// <summary>0x27, Volume serial number<summary>
|
||||
public UInt32 serial_no;
|
||||
/// <summary>0x2B, Volume label, 11 bytes, space-padded
|
||||
/// Present only if signature == 0x29<summary>
|
||||
public string volume_label;
|
||||
/// <summary>0x36, Filesystem type, 8 bytes, space-padded
|
||||
/// Present only if signature == 0x29<summary>
|
||||
public string fs_type;
|
||||
}
|
||||
|
||||
/// <summary>FAT32 Parameter Block</summary>
|
||||
public struct FAT32ParameterBlock
|
||||
{
|
||||
/// <summary>0x24, Sectors per FAT</summary>
|
||||
public UInt32 spfat;
|
||||
/// <summary>0x28, FAT flags</summary>
|
||||
public UInt16 fat_flags;
|
||||
/// <summary>0x2A, FAT32 version</summary>
|
||||
public UInt16 version;
|
||||
/// <summary>0x2C, Cluster of root directory</summary>
|
||||
public UInt32 root_cluster;
|
||||
/// <summary>0x30, Sector of FSINFO structure</summary>
|
||||
public UInt16 fsinfo_sector;
|
||||
/// <summary>0x32, Sector of FAT32PB backup</summary>
|
||||
public UInt16 backup_sector;
|
||||
/// <summary>0x34, 12 reserved bytes</summary>
|
||||
public byte[] reserved;
|
||||
/// <summary>0x40, Drive number</summary>
|
||||
public byte drive_no;
|
||||
/// <summary>0x41, Volume flags</summary>
|
||||
public byte nt_flags;
|
||||
/// <summary>0x42, FAT32PB signature, should be 0x29</summary>
|
||||
public byte signature;
|
||||
/// <summary>0x43, Volume serial number</summary>
|
||||
public UInt32 serial_no;
|
||||
/// <summary>0x47, Volume label, 11 bytes, space-padded</summary>
|
||||
public string volume_label;
|
||||
/// <summary>0x52, Filesystem type, 8 bytes, space-padded, must be "FAT32 "</summary>
|
||||
public string fs_type;
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,382 +0,0 @@
|
||||
/***************************************************************************
|
||||
The Disc Image Chef
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
Filename : HPFS.cs
|
||||
Version : 1.0
|
||||
Author(s) : Natalia Portillo
|
||||
|
||||
Component : Filesystem plugins
|
||||
|
||||
Revision : $Revision$
|
||||
Last change by : $Author$
|
||||
Date : $Date$
|
||||
|
||||
--[ Description ] ----------------------------------------------------------
|
||||
|
||||
Identifies OS/2 HPFS filesystems and shows information.
|
||||
No pinball playing allowed.
|
||||
|
||||
--[ License ] --------------------------------------------------------------
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
----------------------------------------------------------------------------
|
||||
Copyright (C) 2011-2014 Claunia.com
|
||||
****************************************************************************/
|
||||
//$Id$
|
||||
|
||||
using System;
|
||||
using System.Text;
|
||||
using DiscImageChef;
|
||||
|
||||
// Information from an old unnamed document
|
||||
namespace DiscImageChef.Plugins
|
||||
{
|
||||
class HPFS : Plugin
|
||||
{
|
||||
public HPFS(PluginBase Core)
|
||||
{
|
||||
Name = "OS/2 High Performance File System";
|
||||
PluginUUID = new Guid("33513B2C-f590-4acb-8bf2-0b1d5e19dec5");
|
||||
}
|
||||
|
||||
public override bool Identify(ImagePlugins.ImagePlugin imagePlugin, ulong partitionStart, ulong partitionEnd)
|
||||
{
|
||||
if ((2 + partitionStart) >= imagePlugin.GetSectors())
|
||||
return false;
|
||||
|
||||
UInt32 magic1, magic2;
|
||||
|
||||
byte[] hpfs_sb_sector = imagePlugin.ReadSector(16 + partitionStart); // Seek to superblock, on logical sector 16
|
||||
magic1 = BitConverter.ToUInt32(hpfs_sb_sector, 0x000);
|
||||
magic2 = BitConverter.ToUInt32(hpfs_sb_sector, 0x004);
|
||||
|
||||
if (magic1 == 0xF995E849 && magic2 == 0xFA53E9C5)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
public override void GetInformation(ImagePlugins.ImagePlugin imagePlugin, ulong partitionStart, ulong partitionEnd, out string information)
|
||||
{
|
||||
information = "";
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
HPFS_BIOSParameterBlock hpfs_bpb = new HPFS_BIOSParameterBlock();
|
||||
HPFS_SuperBlock hpfs_sb = new HPFS_SuperBlock();
|
||||
HPFS_SpareBlock hpfs_sp = new HPFS_SpareBlock();
|
||||
|
||||
byte[] oem_name = new byte[8];
|
||||
byte[] volume_name = new byte[11];
|
||||
|
||||
byte[] hpfs_bpb_sector = imagePlugin.ReadSector(0 + partitionStart); // Seek to BIOS parameter block, on logical sector 0
|
||||
byte[] hpfs_sb_sector = imagePlugin.ReadSector(16 + partitionStart); // Seek to superblock, on logical sector 16
|
||||
byte[] hpfs_sp_sector = imagePlugin.ReadSector(17 + partitionStart); // Seek to spareblock, on logical sector 17
|
||||
|
||||
hpfs_bpb.jmp1 = hpfs_bpb_sector[0x000];
|
||||
hpfs_bpb.jmp2 = BitConverter.ToUInt16(hpfs_bpb_sector, 0x001);
|
||||
Array.Copy(hpfs_bpb_sector, 0x003, oem_name, 0, 8);
|
||||
hpfs_bpb.OEMName = StringHandlers.CToString(oem_name);
|
||||
hpfs_bpb.bps = BitConverter.ToUInt16(hpfs_bpb_sector, 0x00B);
|
||||
hpfs_bpb.spc = hpfs_bpb_sector[0x00D];
|
||||
hpfs_bpb.rsectors = BitConverter.ToUInt16(hpfs_bpb_sector, 0x00E);
|
||||
hpfs_bpb.fats_no = hpfs_bpb_sector[0x010];
|
||||
hpfs_bpb.root_ent = BitConverter.ToUInt16(hpfs_bpb_sector, 0x011);
|
||||
hpfs_bpb.sectors = BitConverter.ToUInt16(hpfs_bpb_sector, 0x013);
|
||||
hpfs_bpb.media = hpfs_bpb_sector[0x015];
|
||||
hpfs_bpb.spfat = BitConverter.ToUInt16(hpfs_bpb_sector, 0x016);
|
||||
hpfs_bpb.sptrk = BitConverter.ToUInt16(hpfs_bpb_sector, 0x018);
|
||||
hpfs_bpb.heads = BitConverter.ToUInt16(hpfs_bpb_sector, 0x01A);
|
||||
hpfs_bpb.hsectors = BitConverter.ToUInt32(hpfs_bpb_sector, 0x01C);
|
||||
hpfs_bpb.big_sectors = BitConverter.ToUInt32(hpfs_bpb_sector, 0x024);
|
||||
hpfs_bpb.drive_no = hpfs_bpb_sector[0x028];
|
||||
hpfs_bpb.nt_flags = hpfs_bpb_sector[0x029];
|
||||
hpfs_bpb.signature = hpfs_bpb_sector[0x02A];
|
||||
hpfs_bpb.serial_no = BitConverter.ToUInt32(hpfs_bpb_sector, 0x02B);
|
||||
Array.Copy(hpfs_bpb_sector, 0x02F, volume_name, 0, 11);
|
||||
hpfs_bpb.volume_label = StringHandlers.CToString(volume_name);
|
||||
Array.Copy(hpfs_bpb_sector, 0x03A, oem_name, 0, 8);
|
||||
hpfs_bpb.fs_type = StringHandlers.CToString(oem_name);
|
||||
|
||||
hpfs_sb.magic1 = BitConverter.ToUInt32(hpfs_sb_sector, 0x000);
|
||||
hpfs_sb.magic2 = BitConverter.ToUInt32(hpfs_sb_sector, 0x004);
|
||||
hpfs_sb.version = hpfs_sb_sector[0x008];
|
||||
hpfs_sb.func_version = hpfs_sb_sector[0x009];
|
||||
hpfs_sb.dummy = BitConverter.ToUInt16(hpfs_sb_sector, 0x00A);
|
||||
hpfs_sb.root_fnode = BitConverter.ToUInt32(hpfs_sb_sector, 0x00C);
|
||||
hpfs_sb.sectors = BitConverter.ToUInt32(hpfs_sb_sector, 0x010);
|
||||
hpfs_sb.badblocks = BitConverter.ToUInt32(hpfs_sb_sector, 0x014);
|
||||
hpfs_sb.bitmap_lsn = BitConverter.ToUInt32(hpfs_sb_sector, 0x018);
|
||||
hpfs_sb.zero1 = BitConverter.ToUInt32(hpfs_sb_sector, 0x01C);
|
||||
hpfs_sb.badblock_lsn = BitConverter.ToUInt32(hpfs_sb_sector, 0x020);
|
||||
hpfs_sb.zero2 = BitConverter.ToUInt32(hpfs_sb_sector, 0x024);
|
||||
hpfs_sb.last_chkdsk = BitConverter.ToInt32(hpfs_sb_sector, 0x028);
|
||||
hpfs_sb.last_optim = BitConverter.ToInt32(hpfs_sb_sector, 0x02C);
|
||||
hpfs_sb.dband_sectors = BitConverter.ToUInt32(hpfs_sb_sector, 0x030);
|
||||
hpfs_sb.dband_start = BitConverter.ToUInt32(hpfs_sb_sector, 0x034);
|
||||
hpfs_sb.dband_last = BitConverter.ToUInt32(hpfs_sb_sector, 0x038);
|
||||
hpfs_sb.dband_bitmap = BitConverter.ToUInt32(hpfs_sb_sector, 0x03C);
|
||||
hpfs_sb.zero3 = BitConverter.ToUInt64(hpfs_sb_sector, 0x040);
|
||||
hpfs_sb.zero4 = BitConverter.ToUInt64(hpfs_sb_sector, 0x048);
|
||||
hpfs_sb.zero5 = BitConverter.ToUInt64(hpfs_sb_sector, 0x04C);
|
||||
hpfs_sb.zero6 = BitConverter.ToUInt64(hpfs_sb_sector, 0x050);
|
||||
hpfs_sb.acl_start = BitConverter.ToUInt32(hpfs_sb_sector, 0x058);
|
||||
|
||||
hpfs_sp.magic1 = BitConverter.ToUInt32(hpfs_sp_sector, 0x000);
|
||||
hpfs_sp.magic2 = BitConverter.ToUInt32(hpfs_sp_sector, 0x004);
|
||||
hpfs_sp.flags1 = hpfs_sp_sector[0x008];
|
||||
hpfs_sp.flags2 = hpfs_sp_sector[0x009];
|
||||
hpfs_sp.dummy = BitConverter.ToUInt16(hpfs_sp_sector, 0x00A);
|
||||
hpfs_sp.hotfix_start = BitConverter.ToUInt32(hpfs_sp_sector, 0x00C);
|
||||
hpfs_sp.hotfix_used = BitConverter.ToUInt32(hpfs_sp_sector, 0x010);
|
||||
hpfs_sp.hotfix_entries = BitConverter.ToUInt32(hpfs_sp_sector, 0x014);
|
||||
hpfs_sp.spare_dnodes_free = BitConverter.ToUInt32(hpfs_sp_sector, 0x018);
|
||||
hpfs_sp.spare_dnodes = BitConverter.ToUInt32(hpfs_sp_sector, 0x01C);
|
||||
hpfs_sp.codepage_lsn = BitConverter.ToUInt32(hpfs_sp_sector, 0x020);
|
||||
hpfs_sp.codepages = BitConverter.ToUInt32(hpfs_sp_sector, 0x024);
|
||||
hpfs_sp.sb_crc32 = BitConverter.ToUInt32(hpfs_sp_sector, 0x028);
|
||||
hpfs_sp.sp_crc32 = BitConverter.ToUInt32(hpfs_sp_sector, 0x02C);
|
||||
|
||||
if (hpfs_bpb.fs_type != "HPFS " ||
|
||||
hpfs_sb.magic1 != 0xF995E849 || hpfs_sb.magic2 != 0xFA53E9C5 ||
|
||||
hpfs_sp.magic1 != 0xF9911849 || hpfs_sp.magic2 != 0xFA5229C5)
|
||||
{
|
||||
sb.AppendLine("This may not be HPFS, following information may be not correct.");
|
||||
sb.AppendFormat("File system type: \"{0}\" (Should be \"HPFS \")", hpfs_bpb.fs_type).AppendLine();
|
||||
sb.AppendFormat("Superblock magic1: 0x{0:X8} (Should be 0xF995E849)", hpfs_sb.magic1).AppendLine();
|
||||
sb.AppendFormat("Superblock magic2: 0x{0:X8} (Should be 0xFA53E9C5)", hpfs_sb.magic2).AppendLine();
|
||||
sb.AppendFormat("Spareblock magic1: 0x{0:X8} (Should be 0xF9911849)", hpfs_sp.magic1).AppendLine();
|
||||
sb.AppendFormat("Spareblock magic2: 0x{0:X8} (Should be 0xFA5229C5)", hpfs_sp.magic2).AppendLine();
|
||||
}
|
||||
|
||||
sb.AppendFormat("OEM name: {0}", hpfs_bpb.OEMName).AppendLine();
|
||||
sb.AppendFormat("{0} bytes per sector", hpfs_bpb.bps).AppendLine();
|
||||
sb.AppendFormat("{0} sectors per cluster", hpfs_bpb.spc).AppendLine();
|
||||
// sb.AppendFormat("{0} reserved sectors", hpfs_bpb.rsectors).AppendLine();
|
||||
// sb.AppendFormat("{0} FATs", hpfs_bpb.fats_no).AppendLine();
|
||||
// sb.AppendFormat("{0} entries on root directory", hpfs_bpb.root_ent).AppendLine();
|
||||
// sb.AppendFormat("{0} mini sectors on volume", hpfs_bpb.sectors).AppendLine();
|
||||
sb.AppendFormat("Media descriptor: 0x{0:X2}", hpfs_bpb.media).AppendLine();
|
||||
// sb.AppendFormat("{0} sectors per FAT", hpfs_bpb.spfat).AppendLine();
|
||||
// sb.AppendFormat("{0} sectors per track", hpfs_bpb.sptrk).AppendLine();
|
||||
// sb.AppendFormat("{0} heads", hpfs_bpb.heads).AppendLine();
|
||||
sb.AppendFormat("{0} sectors hidden before BPB", hpfs_bpb.hsectors).AppendLine();
|
||||
sb.AppendFormat("{0} sectors on volume ({1} bytes)", hpfs_bpb.big_sectors, hpfs_bpb.big_sectors * hpfs_bpb.bps).AppendLine();
|
||||
sb.AppendFormat("BIOS Drive Number: 0x{0:X2}", hpfs_bpb.drive_no).AppendLine();
|
||||
// sb.AppendFormat("NT Flags: 0x{0:X2}", hpfs_bpb.nt_flags).AppendLine();
|
||||
sb.AppendFormat("Signature: 0x{0:X2}", hpfs_bpb.signature).AppendLine();
|
||||
sb.AppendFormat("Serial number: 0x{0:X8}", hpfs_bpb.serial_no).AppendLine();
|
||||
sb.AppendFormat("Volume label: {0}", hpfs_bpb.volume_label).AppendLine();
|
||||
// sb.AppendFormat("Filesystem type: \"{0}\"", hpfs_bpb.fs_type).AppendLine();
|
||||
|
||||
DateTime last_chk = DateHandlers.UNIXToDateTime(hpfs_sb.last_chkdsk);
|
||||
DateTime last_optim = DateHandlers.UNIXToDateTime(hpfs_sb.last_optim);
|
||||
|
||||
sb.AppendFormat("HPFS version: {0}", hpfs_sb.version).AppendLine();
|
||||
sb.AppendFormat("Functional version: {0}", hpfs_sb.func_version).AppendLine();
|
||||
sb.AppendFormat("Sector of root directory FNode: {0}", hpfs_sb.root_fnode).AppendLine();
|
||||
// sb.AppendFormat("{0} sectors on volume", hpfs_sb.sectors).AppendLine();
|
||||
sb.AppendFormat("{0} sectors are marked bad", hpfs_sb.badblocks).AppendLine();
|
||||
sb.AppendFormat("Sector of free space bitmaps: {0}", hpfs_sb.bitmap_lsn).AppendLine();
|
||||
sb.AppendFormat("Sector of bad blocks list: {0}", hpfs_sb.badblock_lsn).AppendLine();
|
||||
sb.AppendFormat("Date of last integrity check: {0}", last_chk).AppendLine();
|
||||
if (hpfs_sb.last_optim > 0)
|
||||
sb.AppendFormat("Date of last optimization {0}", last_optim).AppendLine();
|
||||
else
|
||||
sb.AppendLine("Filesystem has never been optimized");
|
||||
sb.AppendFormat("Directory band has {0} sectors", hpfs_sb.dband_sectors).AppendLine();
|
||||
sb.AppendFormat("Directory band starts at sector {0}", hpfs_sb.dband_start).AppendLine();
|
||||
sb.AppendFormat("Directory band ends at sector {0}", hpfs_sb.dband_last).AppendLine();
|
||||
sb.AppendFormat("Sector of directory band bitmap: {0}", hpfs_sb.dband_bitmap).AppendLine();
|
||||
sb.AppendFormat("Sector of ACL directory: {0}", hpfs_sb.acl_start).AppendLine();
|
||||
|
||||
sb.AppendFormat("Sector of Hotfix directory: {0}", hpfs_sp.hotfix_start).AppendLine();
|
||||
sb.AppendFormat("{0} used Hotfix entries", hpfs_sp.hotfix_used).AppendLine();
|
||||
sb.AppendFormat("{0} total Hotfix entries", hpfs_sp.hotfix_entries).AppendLine();
|
||||
sb.AppendFormat("{0} free spare DNodes", hpfs_sp.spare_dnodes_free).AppendLine();
|
||||
sb.AppendFormat("{0} total spare DNodes", hpfs_sp.spare_dnodes).AppendLine();
|
||||
sb.AppendFormat("Sector of codepage directory: {0}", hpfs_sp.codepage_lsn).AppendLine();
|
||||
sb.AppendFormat("{0} codepages used in the volume", hpfs_sp.codepages).AppendLine();
|
||||
sb.AppendFormat("SuperBlock CRC32: {0:X8}", hpfs_sp.sb_crc32).AppendLine();
|
||||
sb.AppendFormat("SpareBlock CRC32: {0:X8}", hpfs_sp.sp_crc32).AppendLine();
|
||||
|
||||
sb.AppendLine("Flags:");
|
||||
if ((hpfs_sp.flags1 & 0x01) == 0x01)
|
||||
sb.AppendLine("Filesystem is dirty.");
|
||||
else
|
||||
sb.AppendLine("Filesystem is clean.");
|
||||
if ((hpfs_sp.flags1 & 0x02) == 0x02)
|
||||
sb.AppendLine("Spare directory blocks are in use");
|
||||
if ((hpfs_sp.flags1 & 0x04) == 0x04)
|
||||
sb.AppendLine("Hotfixes are in use");
|
||||
if ((hpfs_sp.flags1 & 0x08) == 0x08)
|
||||
sb.AppendLine("Disk contains bad sectors");
|
||||
if ((hpfs_sp.flags1 & 0x10) == 0x10)
|
||||
sb.AppendLine("Disk has a bad bitmap");
|
||||
if ((hpfs_sp.flags1 & 0x20) == 0x20)
|
||||
sb.AppendLine("Filesystem was formatted fast");
|
||||
if ((hpfs_sp.flags1 & 0x40) == 0x40)
|
||||
sb.AppendLine("Unknown flag 0x40 on flags1 is active");
|
||||
if ((hpfs_sp.flags1 & 0x80) == 0x80)
|
||||
sb.AppendLine("Filesystem has been mounted by an old IFS");
|
||||
if ((hpfs_sp.flags2 & 0x01) == 0x01)
|
||||
sb.AppendLine("Install DASD limits");
|
||||
if ((hpfs_sp.flags2 & 0x02) == 0x02)
|
||||
sb.AppendLine("Resync DASD limits");
|
||||
if ((hpfs_sp.flags2 & 0x04) == 0x04)
|
||||
sb.AppendLine("DASD limits are operational");
|
||||
if ((hpfs_sp.flags2 & 0x08) == 0x08)
|
||||
sb.AppendLine("Multimedia is active");
|
||||
if ((hpfs_sp.flags2 & 0x10) == 0x10)
|
||||
sb.AppendLine("DCE ACLs are active");
|
||||
if ((hpfs_sp.flags2 & 0x20) == 0x20)
|
||||
sb.AppendLine("DASD limits are dirty");
|
||||
if ((hpfs_sp.flags2 & 0x40) == 0x40)
|
||||
sb.AppendLine("Unknown flag 0x40 on flags2 is active");
|
||||
if ((hpfs_sp.flags2 & 0x80) == 0x80)
|
||||
sb.AppendLine("Unknown flag 0x80 on flags2 is active");
|
||||
|
||||
information = sb.ToString();
|
||||
}
|
||||
|
||||
struct HPFS_BIOSParameterBlock // Sector 0
|
||||
{
|
||||
public byte jmp1;
|
||||
// 0x000, Jump to boot code
|
||||
public UInt16 jmp2;
|
||||
// 0x001, ...;
|
||||
public string OEMName;
|
||||
// 0x003, OEM Name, 8 bytes, space-padded
|
||||
public UInt16 bps;
|
||||
// 0x00B, Bytes per sector
|
||||
public byte spc;
|
||||
// 0x00D, Sectors per cluster
|
||||
public UInt16 rsectors;
|
||||
// 0x00E, Reserved sectors between BPB and... does it have sense in HPFS?
|
||||
public byte fats_no;
|
||||
// 0x010, Number of FATs... seriously?
|
||||
public UInt16 root_ent;
|
||||
// 0x011, Number of entries on root directory... ok
|
||||
public UInt16 sectors;
|
||||
// 0x013, Sectors in volume... doubt it
|
||||
public byte media;
|
||||
// 0x015, Media descriptor
|
||||
public UInt16 spfat;
|
||||
// 0x016, Sectors per FAT... again
|
||||
public UInt16 sptrk;
|
||||
// 0x018, Sectors per track... you're kidding
|
||||
public UInt16 heads;
|
||||
// 0x01A, Heads... stop!
|
||||
public UInt32 hsectors;
|
||||
// 0x01C, Hidden sectors before BPB
|
||||
public UInt32 big_sectors;
|
||||
// 0x024, Sectors in volume if > 65535...
|
||||
public byte drive_no;
|
||||
// 0x028, Drive number
|
||||
public byte nt_flags;
|
||||
// 0x029, Volume flags?
|
||||
public byte signature;
|
||||
// 0x02A, EPB signature, 0x29
|
||||
public UInt32 serial_no;
|
||||
// 0x02B, Volume serial number
|
||||
public string volume_label;
|
||||
// 0x02F, Volume label, 11 bytes, space-padded
|
||||
public string fs_type;
|
||||
// 0x03A, Filesystem type, 8 bytes, space-padded ("HPFS ")
|
||||
}
|
||||
|
||||
struct HPFS_SuperBlock // Sector 16
|
||||
{
|
||||
public UInt32 magic1;
|
||||
// 0x000, 0xF995E849
|
||||
public UInt32 magic2;
|
||||
// 0x004, 0xFA53E9C5
|
||||
public byte version;
|
||||
// 0x008, HPFS version
|
||||
public byte func_version;
|
||||
// 0x009, 2 if <= 4 GiB, 3 if > 4 GiB
|
||||
public UInt16 dummy;
|
||||
// 0x00A, Alignment
|
||||
public UInt32 root_fnode;
|
||||
// 0x00C, LSN pointer to root fnode
|
||||
public UInt32 sectors;
|
||||
// 0x010, Sectors on volume
|
||||
public UInt32 badblocks;
|
||||
// 0x014, Bad blocks on volume
|
||||
public UInt32 bitmap_lsn;
|
||||
// 0x018, LSN pointer to volume bitmap
|
||||
public UInt32 zero1;
|
||||
// 0x01C, 0
|
||||
public UInt32 badblock_lsn;
|
||||
// 0x020, LSN pointer to badblock directory
|
||||
public UInt32 zero2;
|
||||
// 0x024, 0
|
||||
public Int32 last_chkdsk;
|
||||
// 0x028, Time of last CHKDSK
|
||||
public Int32 last_optim;
|
||||
// 0x02C, Time of last optimization
|
||||
public UInt32 dband_sectors;
|
||||
// 0x030, Sectors of dir band
|
||||
public UInt32 dband_start;
|
||||
// 0x034, Start sector of dir band
|
||||
public UInt32 dband_last;
|
||||
// 0x038, Last sector of dir band
|
||||
public UInt32 dband_bitmap;
|
||||
// 0x03C, LSN of free space bitmap
|
||||
public UInt64 zero3;
|
||||
// 0x040, Can be used for volume name (32 bytes)
|
||||
public UInt64 zero4;
|
||||
// 0x048, ...
|
||||
public UInt64 zero5;
|
||||
// 0x04C, ...
|
||||
public UInt64 zero6;
|
||||
// 0x050, ...;
|
||||
public UInt32 acl_start;
|
||||
// 0x058, LSN pointer to ACLs (only HPFS386)
|
||||
}
|
||||
|
||||
struct HPFS_SpareBlock // Sector 17
|
||||
{
|
||||
public UInt32 magic1;
|
||||
// 0x000, 0xF9911849
|
||||
public UInt32 magic2;
|
||||
// 0x004, 0xFA5229C5
|
||||
public byte flags1;
|
||||
// 0x008, HPFS flags
|
||||
public byte flags2;
|
||||
// 0x009, HPFS386 flags
|
||||
public UInt16 dummy;
|
||||
// 0x00A, Alignment
|
||||
public UInt32 hotfix_start;
|
||||
// 0x00C, LSN of hotfix directory
|
||||
public UInt32 hotfix_used;
|
||||
// 0x010, Used hotfixes
|
||||
public UInt32 hotfix_entries;
|
||||
// 0x014, Total hotfixes available
|
||||
public UInt32 spare_dnodes_free;
|
||||
// 0x018, Unused spare dnodes
|
||||
public UInt32 spare_dnodes;
|
||||
// 0x01C, Length of spare dnodes list
|
||||
public UInt32 codepage_lsn;
|
||||
// 0x020, LSN of codepage directory
|
||||
public UInt32 codepages;
|
||||
// 0x024, Number of codepages used
|
||||
public UInt32 sb_crc32;
|
||||
// 0x028, SuperBlock CRC32 (only HPFS386)
|
||||
public UInt32 sp_crc32;
|
||||
// 0x02C, SpareBlock CRC32 (only HPFS386)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,991 +0,0 @@
|
||||
/***************************************************************************
|
||||
The Disc Image Chef
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
Filename : ISO9660.cs
|
||||
Version : 1.0
|
||||
Author(s) : Natalia Portillo
|
||||
|
||||
Component : Filesystem plugins
|
||||
|
||||
Revision : $Revision$
|
||||
Last change by : $Author$
|
||||
Date : $Date$
|
||||
|
||||
--[ Description ] ----------------------------------------------------------
|
||||
|
||||
Identifies ISO9660/ECMA-119 filesystems and shows information.
|
||||
|
||||
--[ License ] --------------------------------------------------------------
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
----------------------------------------------------------------------------
|
||||
Copyright (C) 2011-2014 Claunia.com
|
||||
****************************************************************************/
|
||||
//$Id$
|
||||
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
using DiscImageChef;
|
||||
|
||||
// This is coded following ECMA-119.
|
||||
// TODO: Differentiate ISO Level 1, 2, 3 and ISO 9660:1999
|
||||
// TODO: Apple extensiones, requires XA or advance RR interpretation.
|
||||
// TODO: Needs a major rewrite
|
||||
namespace DiscImageChef.Plugins
|
||||
{
|
||||
class ISO9660Plugin : Plugin
|
||||
{
|
||||
static bool alreadyLaunched;
|
||||
|
||||
public ISO9660Plugin(PluginBase Core)
|
||||
{
|
||||
Name = "ISO9660 Filesystem";
|
||||
PluginUUID = new Guid("d812f4d3-c357-400d-90fd-3b22ef786aa8");
|
||||
alreadyLaunched = false;
|
||||
}
|
||||
|
||||
struct DecodedVolumeDescriptor
|
||||
{
|
||||
public string SystemIdentifier;
|
||||
public string VolumeIdentifier;
|
||||
public string VolumeSetIdentifier;
|
||||
public string PublisherIdentifier;
|
||||
public string DataPreparerIdentifier;
|
||||
public string ApplicationIdentifier;
|
||||
public DateTime CreationTime;
|
||||
public bool HasModificationTime;
|
||||
public DateTime ModificationTime;
|
||||
public bool HasExpirationTime;
|
||||
public DateTime ExpirationTime;
|
||||
public bool HasEffectiveTime;
|
||||
public DateTime EffectiveTime;
|
||||
}
|
||||
|
||||
public override bool Identify(ImagePlugins.ImagePlugin imagePlugin, ulong partitionStart, ulong partitionEnd)
|
||||
{
|
||||
if (alreadyLaunched)
|
||||
return false;
|
||||
alreadyLaunched = true;
|
||||
|
||||
byte VDType;
|
||||
|
||||
// ISO9660 is designed for 2048 bytes/sector devices
|
||||
if (imagePlugin.GetSectorSize() < 2048)
|
||||
return false;
|
||||
|
||||
// ISO9660 Primary Volume Descriptor starts at sector 16, so that's minimal size.
|
||||
if (imagePlugin.GetSectors() <= (16 + partitionStart))
|
||||
return false;
|
||||
|
||||
// Read to Volume Descriptor
|
||||
byte[] vd_sector = imagePlugin.ReadSector(16 + partitionStart);
|
||||
|
||||
VDType = vd_sector[0];
|
||||
byte[] VDMagic = new byte[5];
|
||||
|
||||
// Wrong, VDs can be any order!
|
||||
if (VDType == 255) // Supposedly we are in the PVD.
|
||||
return false;
|
||||
|
||||
Array.Copy(vd_sector, 0x001, VDMagic, 0, 5);
|
||||
|
||||
return Encoding.ASCII.GetString(VDMagic) == "CD001";
|
||||
}
|
||||
|
||||
public override void GetInformation (ImagePlugins.ImagePlugin imagePlugin, ulong partitionStart, ulong partitionEnd, out string information)
|
||||
{
|
||||
information = "";
|
||||
StringBuilder ISOMetadata = new StringBuilder();
|
||||
bool Joliet = false;
|
||||
bool Bootable = false;
|
||||
bool RockRidge = false;
|
||||
byte VDType; // Volume Descriptor Type, should be 1 or 2.
|
||||
byte[] VDMagic = new byte[5]; // Volume Descriptor magic "CD001"
|
||||
byte[] VDSysId = new byte[32]; // System Identifier
|
||||
byte[] VDVolId = new byte[32]; // Volume Identifier
|
||||
byte[] VDVolSetId = new byte[128]; // Volume Set Identifier
|
||||
byte[] VDPubId = new byte[128]; // Publisher Identifier
|
||||
byte[] VDDataPrepId = new byte[128]; // Data Preparer Identifier
|
||||
byte[] VDAppId = new byte[128]; // Application Identifier
|
||||
byte[] VCTime = new byte[17]; // Volume Creation Date and Time
|
||||
byte[] VMTime = new byte[17]; // Volume Modification Date and Time
|
||||
byte[] VXTime = new byte[17]; // Volume Expiration Date and Time
|
||||
byte[] VETime = new byte[17]; // Volume Effective Date and Time
|
||||
|
||||
byte[] JolietMagic = new byte[3];
|
||||
byte[] JolietSysId = new byte[32]; // System Identifier
|
||||
byte[] JolietVolId = new byte[32]; // Volume Identifier
|
||||
byte[] JolietVolSetId = new byte[128]; // Volume Set Identifier
|
||||
byte[] JolietPubId = new byte[128]; // Publisher Identifier
|
||||
byte[] JolietDataPrepId = new byte[128]; // Data Preparer Identifier
|
||||
byte[] JolietAppId = new byte[128]; // Application Identifier
|
||||
byte[] JolietCTime = new byte[17]; // Volume Creation Date and Time
|
||||
byte[] JolietMTime = new byte[17]; // Volume Modification Date and Time
|
||||
byte[] JolietXTime = new byte[17]; // Volume Expiration Date and Time
|
||||
byte[] JolietETime = new byte[17]; // Volume Effective Date and Time
|
||||
|
||||
byte[] BootSysId = new byte[32];
|
||||
string BootSpec = "";
|
||||
|
||||
byte[] VDPathTableStart = new byte[4];
|
||||
byte[] RootDirectoryLocation = new byte[4];
|
||||
|
||||
// ISO9660 is designed for 2048 bytes/sector devices
|
||||
if (imagePlugin.GetSectorSize() < 2048)
|
||||
return;
|
||||
|
||||
// ISO9660 Primary Volume Descriptor starts at sector 16, so that's minimal size.
|
||||
if (imagePlugin.GetSectors() < 16)
|
||||
return;
|
||||
|
||||
ulong counter = 0;
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (MainClass.isDebug)
|
||||
Console.WriteLine("DEBUG (ISO9660 Plugin): Processing VD loop no. {0}", counter);
|
||||
// Seek to Volume Descriptor
|
||||
if (MainClass.isDebug)
|
||||
Console.WriteLine("DEBUG (ISO9660 Plugin): Reading sector {0}", 16 + counter + partitionStart);
|
||||
byte[] vd_sector = imagePlugin.ReadSector(16 + counter + partitionStart);
|
||||
|
||||
VDType = vd_sector[0];
|
||||
if (MainClass.isDebug)
|
||||
Console.WriteLine("DEBUG (ISO9660 Plugin): VDType = {0}", VDType);
|
||||
|
||||
if (VDType == 255) // Supposedly we are in the PVD.
|
||||
{
|
||||
if (counter == 0)
|
||||
return;
|
||||
break;
|
||||
}
|
||||
|
||||
Array.Copy(vd_sector, 0x001, VDMagic, 0, 5);
|
||||
|
||||
if (Encoding.ASCII.GetString(VDMagic) != "CD001") // Recognized, it is an ISO9660, now check for rest of data.
|
||||
{
|
||||
if (counter == 0)
|
||||
return;
|
||||
break;
|
||||
}
|
||||
|
||||
switch(VDType)
|
||||
{
|
||||
case 0: // TODO
|
||||
{
|
||||
Bootable = true;
|
||||
BootSpec = "Unknown";
|
||||
|
||||
// Read to boot system identifier
|
||||
Array.Copy(vd_sector, 0x007, BootSysId, 0, 32);
|
||||
|
||||
if (Encoding.ASCII.GetString(BootSysId).Substring(0, 23) == "EL TORITO SPECIFICATION")
|
||||
BootSpec = "El Torito";
|
||||
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
{
|
||||
// Read first identifiers
|
||||
Array.Copy(vd_sector, 0x008, VDSysId, 0, 32);
|
||||
Array.Copy(vd_sector, 0x028, VDVolId, 0, 32);
|
||||
|
||||
// Get path table start
|
||||
Array.Copy(vd_sector, 0x08C, VDPathTableStart, 0, 4);
|
||||
|
||||
// Read next identifiers
|
||||
Array.Copy(vd_sector, 0x0BE, VDVolSetId, 0, 128);
|
||||
Array.Copy(vd_sector, 0x13E, VDPubId, 0, 128);
|
||||
Array.Copy(vd_sector, 0x1BE, VDDataPrepId, 0, 128);
|
||||
Array.Copy(vd_sector, 0x23E, VDAppId, 0, 128);
|
||||
|
||||
// Read dates
|
||||
Array.Copy(vd_sector, 0x32D, VCTime, 0, 17);
|
||||
Array.Copy(vd_sector, 0x33E, VMTime, 0, 17);
|
||||
Array.Copy(vd_sector, 0x34F, VXTime, 0, 17);
|
||||
Array.Copy(vd_sector, 0x360, VETime, 0, 17);
|
||||
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
// Check if this is Joliet
|
||||
Array.Copy(vd_sector, 0x058, JolietMagic, 0, 3);
|
||||
if (JolietMagic[0] == '%' && JolietMagic[1] == '/')
|
||||
{
|
||||
if (JolietMagic[2] == '@' || JolietMagic[2] == 'C' || JolietMagic[2] == 'E')
|
||||
{
|
||||
Joliet = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
break;
|
||||
|
||||
// Read first identifiers
|
||||
Array.Copy(vd_sector, 0x008, JolietSysId, 0, 32);
|
||||
Array.Copy(vd_sector, 0x028, JolietVolId, 0, 32);
|
||||
|
||||
// Read next identifiers
|
||||
Array.Copy(vd_sector, 0x0BE, JolietVolSetId, 0, 128);
|
||||
Array.Copy(vd_sector, 0x13E, JolietPubId, 0, 128);
|
||||
Array.Copy(vd_sector, 0x13E, JolietDataPrepId, 0, 128);
|
||||
Array.Copy(vd_sector, 0x13E, JolietAppId, 0, 128);
|
||||
|
||||
// Read dates
|
||||
Array.Copy(vd_sector, 0x32D, JolietCTime, 0, 17);
|
||||
Array.Copy(vd_sector, 0x33E, JolietMTime, 0, 17);
|
||||
Array.Copy(vd_sector, 0x34F, JolietXTime, 0, 17);
|
||||
Array.Copy(vd_sector, 0x360, JolietETime, 0, 17);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
counter++;
|
||||
}
|
||||
|
||||
DecodedVolumeDescriptor decodedVD = new DecodedVolumeDescriptor();
|
||||
DecodedVolumeDescriptor decodedJolietVD = new DecodedVolumeDescriptor();
|
||||
|
||||
decodedVD = DecodeVolumeDescriptor(VDSysId, VDVolId, VDVolSetId, VDPubId, VDDataPrepId, VDAppId, VCTime, VMTime, VXTime, VETime);
|
||||
if(Joliet)
|
||||
decodedJolietVD = DecodeJolietDescriptor(JolietSysId, JolietVolId, JolietVolSetId, JolietPubId, JolietDataPrepId, JolietAppId, JolietCTime, JolietMTime, JolietXTime, JolietETime);
|
||||
|
||||
|
||||
ulong i = (ulong)BitConverter.ToInt32(VDPathTableStart, 0);
|
||||
if (MainClass.isDebug)
|
||||
Console.WriteLine("DEBUG (ISO9660 Plugin): VDPathTableStart = {0} + {1} = {2}", i, partitionStart, i + partitionStart);
|
||||
|
||||
// TODO: Check this
|
||||
if ((i + partitionStart) < imagePlugin.GetSectors())
|
||||
{
|
||||
|
||||
byte[] path_table = imagePlugin.ReadSector(i + partitionStart);
|
||||
Array.Copy(path_table, 2, RootDirectoryLocation, 0, 4);
|
||||
// Check for Rock Ridge
|
||||
byte[] root_dir = imagePlugin.ReadSector((ulong)BitConverter.ToInt32(RootDirectoryLocation, 0) + partitionStart);
|
||||
|
||||
byte[] SUSPMagic = new byte[2];
|
||||
byte[] RRMagic = new byte[2];
|
||||
|
||||
Array.Copy(root_dir, 0x22, SUSPMagic, 0, 2);
|
||||
if (Encoding.ASCII.GetString(SUSPMagic) == "SP")
|
||||
{
|
||||
Array.Copy(root_dir, 0x29, RRMagic, 0, 2);
|
||||
RockRidge |= Encoding.ASCII.GetString(RRMagic) == "RR";
|
||||
}
|
||||
}
|
||||
|
||||
#region SEGA IP.BIN Read and decoding
|
||||
|
||||
bool SegaCD = false;
|
||||
bool Saturn = false;
|
||||
bool Dreamcast = false;
|
||||
StringBuilder IPBinInformation = new StringBuilder();
|
||||
|
||||
byte[] SegaHardwareID = new byte[16];
|
||||
byte[] ipbin_sector = imagePlugin.ReadSector(0 + partitionStart);
|
||||
Array.Copy(ipbin_sector, 0x000, SegaHardwareID, 0, 16);
|
||||
|
||||
if (MainClass.isDebug)
|
||||
Console.WriteLine("DEBUG (ISO9660 Plugin): SegaHardwareID = \"{0}\"", Encoding.ASCII.GetString(SegaHardwareID));
|
||||
|
||||
switch (Encoding.ASCII.GetString(SegaHardwareID))
|
||||
{
|
||||
case "SEGADISCSYSTEM ":
|
||||
case "SEGADATADISC ":
|
||||
case "SEGAOS ":
|
||||
{
|
||||
SegaCD = true; // Ok, this contains SegaCD IP.BIN
|
||||
|
||||
if (MainClass.isDebug)
|
||||
Console.WriteLine("DEBUG (ISO9660 Plugin): Found SegaCD IP.BIN");
|
||||
|
||||
IPBinInformation.AppendLine("--------------------------------");
|
||||
IPBinInformation.AppendLine("SEGA IP.BIN INFORMATION:");
|
||||
IPBinInformation.AppendLine("--------------------------------");
|
||||
|
||||
// Definitions following
|
||||
byte[] volume_name = new byte[11]; // 0x010, Varies
|
||||
byte[] spare_space1 = new byte[1]; // 0x01B, 0x00
|
||||
byte[] volume_version = new byte[2]; // 0x01C, Volume version in BCD. <100 = Prerelease.
|
||||
byte[] volume_type = new byte[2]; // 0x01E, Bit 0 = 1 => CD-ROM. Rest should be 0.
|
||||
byte[] system_name = new byte[11]; // 0x020, Unknown, varies!
|
||||
byte[] spare_space2 = new byte[1]; // 0x02B, 0x00
|
||||
byte[] system_version = new byte[2]; // 0x02C, Should be 1
|
||||
byte[] spare_space3 = new byte[2]; // 0x02E, 0x0000
|
||||
byte[] ip_address = new byte[4]; // 0x030, Initial program address
|
||||
byte[] ip_loadsize = new byte[4]; // 0x034, Load size of initial program
|
||||
byte[] ip_entry_address = new byte[4]; // 0x038, Initial program entry address
|
||||
byte[] ip_work_ram_size = new byte[4]; // 0x03C, Initial program work RAM size in bytes
|
||||
byte[] sp_address = new byte[4]; // 0x040, System program address
|
||||
byte[] sp_loadsize = new byte[4]; // 0x044, Load size of system program
|
||||
byte[] sp_entry_address = new byte[4]; // 0x048, System program entry address
|
||||
byte[] sp_work_ram_size = new byte[4]; // 0x04C, System program work RAM size in bytes
|
||||
byte[] release_date = new byte[8]; // 0x050, MMDDYYYY
|
||||
byte[] unknown1 = new byte[7]; // 0x058, Seems to be all 0x20s
|
||||
byte[] spare_space4 = new byte[1]; // 0x05F, 0x00 ?
|
||||
byte[] system_reserved = new byte[160]; // 0x060, System Reserved Area
|
||||
byte[] hardware_id = new byte[16]; // 0x100, Hardware ID
|
||||
byte[] copyright = new byte[3]; // 0x110, "(C)" -- Can be the developer code directly!, if that is the code release date will be displaced
|
||||
byte[] developer_code = new byte[5]; // 0x113 or 0x110, "SEGA" or "T-xx"
|
||||
byte[] release_date2 = new byte[8]; // 0x118, Another release date, this with month in letters?
|
||||
byte[] domestic_title = new byte[48]; // 0x120, Domestic version of the game title
|
||||
byte[] overseas_title = new byte[48]; // 0x150, Overseas version of the game title
|
||||
byte[] product_code = new byte[13]; // 0x180, Official product code
|
||||
byte[] peripherals = new byte[16]; // 0x190, Supported peripherals, see above
|
||||
byte[] spare_space6 = new byte[16]; // 0x1A0, 0x20
|
||||
byte[] spare_space7 = new byte[64]; // 0x1B0, Inside here should be modem information, but I need to get a modem-enabled game
|
||||
byte[] region_codes = new byte[16]; // 0x1F0, Region codes, space-filled
|
||||
//Reading all data
|
||||
Array.Copy(ipbin_sector, 0x010, volume_name, 0, 11); // Varies
|
||||
Array.Copy(ipbin_sector, 0x01B, spare_space1, 0, 1); // 0x00
|
||||
Array.Copy(ipbin_sector, 0x01C, volume_version, 0, 2); // Volume version in BCD. <100 = Prerelease.
|
||||
Array.Copy(ipbin_sector, 0x01E, volume_type, 0, 2); // Bit 0 = 1 => CD-ROM. Rest should be 0.
|
||||
Array.Copy(ipbin_sector, 0x020, system_name, 0, 11); // Unknown, varies!
|
||||
Array.Copy(ipbin_sector, 0x02B, spare_space2, 0, 1); // 0x00
|
||||
Array.Copy(ipbin_sector, 0x02C, system_version, 0, 2); // Should be 1
|
||||
Array.Copy(ipbin_sector, 0x02E, spare_space3, 0, 2); // 0x0000
|
||||
Array.Copy(ipbin_sector, 0x030, ip_address, 0, 4); // Initial program address
|
||||
Array.Copy(ipbin_sector, 0x034, ip_loadsize, 0, 4); // Load size of initial program
|
||||
Array.Copy(ipbin_sector, 0x038, ip_entry_address, 0, 4); // Initial program entry address
|
||||
Array.Copy(ipbin_sector, 0x03C, ip_work_ram_size, 0, 4); // Initial program work RAM size in bytes
|
||||
Array.Copy(ipbin_sector, 0x040, sp_address, 0, 4); // System program address
|
||||
Array.Copy(ipbin_sector, 0x044, sp_loadsize, 0, 4); // Load size of system program
|
||||
Array.Copy(ipbin_sector, 0x048, sp_entry_address, 0, 4); // System program entry address
|
||||
Array.Copy(ipbin_sector, 0x04C, sp_work_ram_size, 0, 4); // System program work RAM size in bytes
|
||||
Array.Copy(ipbin_sector, 0x050, release_date, 0, 8); // MMDDYYYY
|
||||
Array.Copy(ipbin_sector, 0x058, unknown1, 0, 7); // Seems to be all 0x20s
|
||||
Array.Copy(ipbin_sector, 0x05F, spare_space4, 0, 1); // 0x00 ?
|
||||
Array.Copy(ipbin_sector, 0x060, system_reserved, 0, 160); // System Reserved Area
|
||||
Array.Copy(ipbin_sector, 0x100, hardware_id, 0, 16); // Hardware ID
|
||||
Array.Copy(ipbin_sector, 0x110, copyright, 0, 3); // "(C)" -- Can be the developer code directly!, if that is the code release date will be displaced
|
||||
if (Encoding.ASCII.GetString(copyright) == "(C)")
|
||||
Array.Copy(ipbin_sector, 0x113, developer_code, 0, 5); // "SEGA" or "T-xx"
|
||||
else
|
||||
Array.Copy(ipbin_sector, 0x110, developer_code, 0, 5); // "SEGA" or "T-xx"
|
||||
Array.Copy(ipbin_sector, 0x118, release_date2, 0, 8); // Another release date, this with month in letters?
|
||||
Array.Copy(ipbin_sector, 0x120, domestic_title, 0, 48); // Domestic version of the game title
|
||||
Array.Copy(ipbin_sector, 0x150, overseas_title, 0, 48); // Overseas version of the game title
|
||||
//Array.Copy(ipbin_sector, 0x000, application_type, 0, 2); // Application type
|
||||
//Array.Copy(ipbin_sector, 0x000, space_space5, 0, 1); // 0x20
|
||||
Array.Copy(ipbin_sector, 0x180, product_code, 0, 13); // Official product code
|
||||
Array.Copy(ipbin_sector, 0x190, peripherals, 0, 16); // Supported peripherals, see above
|
||||
Array.Copy(ipbin_sector, 0x1A0, spare_space6, 0, 16); // 0x20
|
||||
Array.Copy(ipbin_sector, 0x1B0, spare_space7, 0, 64); // Inside here should be modem information, but I need to get a modem-enabled game
|
||||
Array.Copy(ipbin_sector, 0x1F0, region_codes, 0, 16); // Region codes, space-filled
|
||||
|
||||
if(MainClass.isDebug)
|
||||
{
|
||||
Console.WriteLine("DEBUG (ISO9660 Plugin): segacd_ipbin.volume_name = \"{0}\"", Encoding.ASCII.GetString(volume_name));
|
||||
Console.WriteLine("DEBUG (ISO9660 Plugin): segacd_ipbin.system_name = \"{0}\"", Encoding.ASCII.GetString(system_name));
|
||||
Console.WriteLine("DEBUG (ISO9660 Plugin): segacd_ipbin.volume_version = \"{0}\"", Encoding.ASCII.GetString(volume_version));
|
||||
Console.WriteLine("DEBUG (ISO9660 Plugin): segacd_ipbin.volume_type = 0x{0}", BitConverter.ToInt32(volume_type, 0).ToString("X"));
|
||||
Console.WriteLine("DEBUG (ISO9660 Plugin): segacd_ipbin.system_version = 0x{0}", BitConverter.ToInt32(system_version, 0).ToString("X"));
|
||||
Console.WriteLine("DEBUG (ISO9660 Plugin): segacd_ipbin.ip_address = 0x{0}", BitConverter.ToInt32(ip_address, 0).ToString("X"));
|
||||
Console.WriteLine("DEBUG (ISO9660 Plugin): segacd_ipbin.ip_loadsize = {0}", BitConverter.ToInt32(ip_loadsize, 0));
|
||||
Console.WriteLine("DEBUG (ISO9660 Plugin): segacd_ipbin.ip_entry_address = 0x{0}", BitConverter.ToInt32(ip_entry_address, 0).ToString("X"));
|
||||
Console.WriteLine("DEBUG (ISO9660 Plugin): segacd_ipbin.ip_work_ram_size = {0}", BitConverter.ToInt32(ip_work_ram_size, 0));
|
||||
Console.WriteLine("DEBUG (ISO9660 Plugin): segacd_ipbin.sp_address = 0x{0}", BitConverter.ToInt32(sp_address, 0).ToString("X"));
|
||||
Console.WriteLine("DEBUG (ISO9660 Plugin): segacd_ipbin.sp_loadsize = {0}", BitConverter.ToInt32(sp_loadsize, 0));
|
||||
Console.WriteLine("DEBUG (ISO9660 Plugin): segacd_ipbin.sp_entry_address = 0x{0}", BitConverter.ToInt32(sp_entry_address, 0).ToString("X"));
|
||||
Console.WriteLine("DEBUG (ISO9660 Plugin): segacd_ipbin.sp_work_ram_size = {0}", BitConverter.ToInt32(sp_work_ram_size, 0));
|
||||
Console.WriteLine("DEBUG (ISO9660 Plugin): segacd_ipbin.release_date = \"{0}\"", Encoding.ASCII.GetString(release_date));
|
||||
Console.WriteLine("DEBUG (ISO9660 Plugin): segacd_ipbin.release_date2 = \"{0}\"", Encoding.ASCII.GetString(release_date2));
|
||||
Console.WriteLine("DEBUG (ISO9660 Plugin): segacd_ipbin.developer_code = \"{0}\"", Encoding.ASCII.GetString(developer_code));
|
||||
Console.WriteLine("DEBUG (ISO9660 Plugin): segacd_ipbin.domestic_title = \"{0}\"", Encoding.ASCII.GetString(domestic_title));
|
||||
Console.WriteLine("DEBUG (ISO9660 Plugin): segacd_ipbin.overseas_title = \"{0}\"", Encoding.ASCII.GetString(overseas_title));
|
||||
Console.WriteLine("DEBUG (ISO9660 Plugin): segacd_ipbin.product_code = \"{0}\"", Encoding.ASCII.GetString(product_code));
|
||||
Console.WriteLine("DEBUG (ISO9660 Plugin): segacd_ipbin.peripherals = \"{0}\"", Encoding.ASCII.GetString(peripherals));
|
||||
Console.WriteLine("DEBUG (ISO9660 Plugin): segacd_ipbin.region_codes = \"{0}\"", Encoding.ASCII.GetString(region_codes));
|
||||
}
|
||||
|
||||
// Decoding all data
|
||||
DateTime ipbindate;
|
||||
CultureInfo provider = CultureInfo.InvariantCulture;
|
||||
ipbindate = DateTime.ParseExact(Encoding.ASCII.GetString(release_date), "MMddyyyy", provider);
|
||||
|
||||
/*
|
||||
switch (Encoding.ASCII.GetString(application_type))
|
||||
{
|
||||
case "GM":
|
||||
IPBinInformation.AppendLine("Disc is a game.");
|
||||
break;
|
||||
case "AI":
|
||||
IPBinInformation.AppendLine("Disc is an application.");
|
||||
break;
|
||||
default:
|
||||
IPBinInformation.AppendLine("Disc is from unknown type.");
|
||||
break;
|
||||
}
|
||||
*/
|
||||
|
||||
IPBinInformation.AppendFormat("Volume name: {0}", Encoding.ASCII.GetString(volume_name)).AppendLine();
|
||||
//IPBinInformation.AppendFormat("Volume version: {0}", Encoding.ASCII.GetString(volume_version)).AppendLine();
|
||||
//IPBinInformation.AppendFormat("{0}", Encoding.ASCII.GetString(volume_type)).AppendLine();
|
||||
IPBinInformation.AppendFormat("System name: {0}", Encoding.ASCII.GetString(system_name)).AppendLine();
|
||||
//IPBinInformation.AppendFormat("System version: {0}", Encoding.ASCII.GetString(system_version)).AppendLine();
|
||||
IPBinInformation.AppendFormat("Initial program address: 0x{0}", BitConverter.ToInt32(ip_address, 0).ToString("X")).AppendLine();
|
||||
IPBinInformation.AppendFormat("Initial program load size: {0} bytes", BitConverter.ToInt32(ip_loadsize, 0)).AppendLine();
|
||||
IPBinInformation.AppendFormat("Initial program entry address: 0x{0}", BitConverter.ToInt32(ip_entry_address, 0).ToString("X")).AppendLine();
|
||||
IPBinInformation.AppendFormat("Initial program work RAM: {0} bytes", BitConverter.ToInt32(ip_work_ram_size, 0)).AppendLine();
|
||||
IPBinInformation.AppendFormat("System program address: 0x{0}", BitConverter.ToInt32(sp_address, 0).ToString("X")).AppendLine();
|
||||
IPBinInformation.AppendFormat("System program load size: {0} bytes", BitConverter.ToInt32(sp_loadsize, 0)).AppendLine();
|
||||
IPBinInformation.AppendFormat("System program entry address: 0x{0}", BitConverter.ToInt32(sp_entry_address, 0).ToString("X")).AppendLine();
|
||||
IPBinInformation.AppendFormat("System program work RAM: {0} bytes", BitConverter.ToInt32(sp_work_ram_size, 0)).AppendLine();
|
||||
IPBinInformation.AppendFormat("Release date: {0}", ipbindate).AppendLine();
|
||||
IPBinInformation.AppendFormat("Release date (other format): {0}", Encoding.ASCII.GetString(release_date2)).AppendLine();
|
||||
IPBinInformation.AppendFormat("Hardware ID: {0}", Encoding.ASCII.GetString(hardware_id)).AppendLine();
|
||||
IPBinInformation.AppendFormat("Developer code: {0}", Encoding.ASCII.GetString(developer_code)).AppendLine();
|
||||
IPBinInformation.AppendFormat("Domestic title: {0}", Encoding.ASCII.GetString(domestic_title)).AppendLine();
|
||||
IPBinInformation.AppendFormat("Overseas title: {0}", Encoding.ASCII.GetString(overseas_title)).AppendLine();
|
||||
IPBinInformation.AppendFormat("Product code: {0}", Encoding.ASCII.GetString(product_code)).AppendLine();
|
||||
IPBinInformation.AppendFormat("Peripherals:").AppendLine();
|
||||
foreach(byte peripheral in peripherals)
|
||||
{
|
||||
switch((char)peripheral)
|
||||
{
|
||||
case 'A':
|
||||
IPBinInformation.AppendLine("Game supports analog controller.");
|
||||
break;
|
||||
case 'B':
|
||||
IPBinInformation.AppendLine("Game supports trackball.");
|
||||
break;
|
||||
case 'G':
|
||||
IPBinInformation.AppendLine("Game supports light gun.");
|
||||
break;
|
||||
case 'J':
|
||||
IPBinInformation.AppendLine("Game supports JoyPad.");
|
||||
break;
|
||||
case 'K':
|
||||
IPBinInformation.AppendLine("Game supports keyboard.");
|
||||
break;
|
||||
case 'M':
|
||||
IPBinInformation.AppendLine("Game supports mouse.");
|
||||
break;
|
||||
case 'O':
|
||||
IPBinInformation.AppendLine("Game supports Master System's JoyPad.");
|
||||
break;
|
||||
case 'P':
|
||||
IPBinInformation.AppendLine("Game supports printer interface.");
|
||||
break;
|
||||
case 'R':
|
||||
IPBinInformation.AppendLine("Game supports serial (RS-232C) interface.");
|
||||
break;
|
||||
case 'T':
|
||||
IPBinInformation.AppendLine("Game supports tablet interface.");
|
||||
break;
|
||||
case 'V':
|
||||
IPBinInformation.AppendLine("Game supports paddle controller.");
|
||||
break;
|
||||
case ' ':
|
||||
break;
|
||||
default:
|
||||
IPBinInformation.AppendFormat("Game supports unknown peripheral {0}.", peripheral).AppendLine();
|
||||
break;
|
||||
}
|
||||
}
|
||||
IPBinInformation.AppendLine("Regions supported:");
|
||||
foreach (byte region in region_codes)
|
||||
{
|
||||
switch ((char)region)
|
||||
{
|
||||
case 'J':
|
||||
IPBinInformation.AppendLine("Japanese NTSC.");
|
||||
break;
|
||||
case 'U':
|
||||
IPBinInformation.AppendLine("USA NTSC.");
|
||||
break;
|
||||
case 'E':
|
||||
IPBinInformation.AppendLine("Europe PAL.");
|
||||
break;
|
||||
case ' ':
|
||||
break;
|
||||
default:
|
||||
IPBinInformation.AppendFormat("Game supports unknown region {0}.", region).AppendLine();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case "SEGA SEGASATURN ":
|
||||
{
|
||||
Saturn = true;
|
||||
|
||||
if (MainClass.isDebug)
|
||||
Console.WriteLine("DEBUG (ISO9660 Plugin): Found Sega Saturn IP.BIN");
|
||||
|
||||
IPBinInformation.AppendLine("--------------------------------");
|
||||
IPBinInformation.AppendLine("SEGA IP.BIN INFORMATION:");
|
||||
IPBinInformation.AppendLine("--------------------------------");
|
||||
|
||||
// Definitions following
|
||||
byte[] maker_id = new byte[16]; // 0x010, "SEGA ENTERPRISES"
|
||||
byte[] product_no = new byte[10]; // 0x020, Product number
|
||||
byte[] product_version = new byte[6]; // 0x02A, Product version
|
||||
byte[] release_date = new byte[8]; // 0x030, YYYYMMDD
|
||||
byte[] saturn_media = new byte[3]; // 0x038, "CD-"
|
||||
byte[] disc_no = new byte[1]; // 0x03B, Disc number
|
||||
byte[] disc_no_separator = new byte[1]; // 0x03C, '/'
|
||||
byte[] disc_total_nos = new byte[1]; // 0x03D, Total number of discs
|
||||
byte[] spare_space1 = new byte[2]; // 0x03E, " "
|
||||
byte[] region_codes = new byte[16]; // 0x040, Region codes, space-filled
|
||||
byte[] peripherals = new byte[16]; // 0x050, Supported peripherals, see above
|
||||
byte[] product_name = new byte[112]; // 0x060, Game name, space-filled
|
||||
// Reading all data
|
||||
Array.Copy(ipbin_sector, 0x010, maker_id, 0, 16); // "SEGA ENTERPRISES"
|
||||
Array.Copy(ipbin_sector, 0x020, product_no, 0, 10); // Product number
|
||||
Array.Copy(ipbin_sector, 0x02A, product_version, 0, 6); // Product version
|
||||
Array.Copy(ipbin_sector, 0x030, release_date, 0, 8); // YYYYMMDD
|
||||
Array.Copy(ipbin_sector, 0x038, saturn_media, 0, 3); // "CD-"
|
||||
Array.Copy(ipbin_sector, 0x03B, disc_no, 0, 1); // Disc number
|
||||
Array.Copy(ipbin_sector, 0x03C, disc_no_separator, 0, 1); // '/'
|
||||
Array.Copy(ipbin_sector, 0x03D, disc_total_nos, 0, 1); // Total number of discs
|
||||
Array.Copy(ipbin_sector, 0x03E, spare_space1, 0, 2); // " "
|
||||
Array.Copy(ipbin_sector, 0x040, region_codes, 0, 16); // Region codes, space-filled
|
||||
Array.Copy(ipbin_sector, 0x050, peripherals, 0, 16); // Supported peripherals, see above
|
||||
Array.Copy(ipbin_sector, 0x060, product_name, 0, 112); // Game name, space-filled
|
||||
|
||||
if(MainClass.isDebug)
|
||||
{
|
||||
Console.WriteLine("DEBUG (ISO9660 Plugin): saturn_ipbin.maker_id = \"{0}\"", Encoding.ASCII.GetString(maker_id));
|
||||
Console.WriteLine("DEBUG (ISO9660 Plugin): saturn_ipbin.product_no = \"{0}\"", Encoding.ASCII.GetString(product_no));
|
||||
Console.WriteLine("DEBUG (ISO9660 Plugin): saturn_ipbin.product_version = \"{0}\"", Encoding.ASCII.GetString(product_version));
|
||||
Console.WriteLine("DEBUG (ISO9660 Plugin): saturn_ipbin.release_datedate = \"{0}\"", Encoding.ASCII.GetString(release_date));
|
||||
Console.WriteLine("DEBUG (ISO9660 Plugin): saturn_ipbin.saturn_media = \"{0}\"", Encoding.ASCII.GetString(saturn_media));
|
||||
Console.WriteLine("DEBUG (ISO9660 Plugin): saturn_ipbin.disc_no = {0}", Encoding.ASCII.GetString(disc_no));
|
||||
Console.WriteLine("DEBUG (ISO9660 Plugin): saturn_ipbin.disc_no_separator = \"{0}\"", Encoding.ASCII.GetString(disc_no_separator));
|
||||
Console.WriteLine("DEBUG (ISO9660 Plugin): saturn_ipbin.disc_total_nos = {0}", Encoding.ASCII.GetString(disc_total_nos));
|
||||
Console.WriteLine("DEBUG (ISO9660 Plugin): saturn_ipbin.release_date = \"{0}\"", Encoding.ASCII.GetString(release_date));
|
||||
Console.WriteLine("DEBUG (ISO9660 Plugin): saturn_ipbin.spare_space1 = \"{0}\"", Encoding.ASCII.GetString(spare_space1));
|
||||
Console.WriteLine("DEBUG (ISO9660 Plugin): saturn_ipbin.region_codes = \"{0}\"", Encoding.ASCII.GetString(region_codes));
|
||||
Console.WriteLine("DEBUG (ISO9660 Plugin): saturn_ipbin.peripherals = \"{0}\"", Encoding.ASCII.GetString(peripherals));
|
||||
Console.WriteLine("DEBUG (ISO9660 Plugin): saturn_ipbin.product_name = \"{0}\"", Encoding.ASCII.GetString(product_name));
|
||||
}
|
||||
|
||||
|
||||
// Decoding all data
|
||||
DateTime ipbindate;
|
||||
CultureInfo provider = CultureInfo.InvariantCulture;
|
||||
ipbindate = DateTime.ParseExact(Encoding.ASCII.GetString(release_date), "yyyyMMdd", provider);
|
||||
IPBinInformation.AppendFormat("Product name: {0}", Encoding.ASCII.GetString(product_name)).AppendLine();
|
||||
IPBinInformation.AppendFormat("Product number: {0}", Encoding.ASCII.GetString(product_no)).AppendLine();
|
||||
IPBinInformation.AppendFormat("Product version: {0}", Encoding.ASCII.GetString(product_version)).AppendLine();
|
||||
IPBinInformation.AppendFormat("Release date: {0}", ipbindate).AppendLine();
|
||||
IPBinInformation.AppendFormat("Disc number {0} of {1}", Encoding.ASCII.GetString(disc_no), Encoding.ASCII.GetString(disc_total_nos)).AppendLine();
|
||||
|
||||
IPBinInformation.AppendFormat("Peripherals:").AppendLine();
|
||||
foreach (byte peripheral in peripherals)
|
||||
{
|
||||
switch ((char)peripheral)
|
||||
{
|
||||
case 'A':
|
||||
IPBinInformation.AppendLine("Game supports analog controller.");
|
||||
break;
|
||||
case 'J':
|
||||
IPBinInformation.AppendLine("Game supports JoyPad.");
|
||||
break;
|
||||
case 'K':
|
||||
IPBinInformation.AppendLine("Game supports keyboard.");
|
||||
break;
|
||||
case 'M':
|
||||
IPBinInformation.AppendLine("Game supports mouse.");
|
||||
break;
|
||||
case 'S':
|
||||
IPBinInformation.AppendLine("Game supports analog steering controller.");
|
||||
break;
|
||||
case 'T':
|
||||
IPBinInformation.AppendLine("Game supports multitap.");
|
||||
break;
|
||||
case ' ':
|
||||
break;
|
||||
default:
|
||||
IPBinInformation.AppendFormat("Game supports unknown peripheral {0}.", peripheral).AppendLine();
|
||||
break;
|
||||
}
|
||||
}
|
||||
IPBinInformation.AppendLine("Regions supported:");
|
||||
foreach (byte region in region_codes)
|
||||
{
|
||||
switch ((char)region)
|
||||
{
|
||||
case 'J':
|
||||
IPBinInformation.AppendLine("Japanese NTSC.");
|
||||
break;
|
||||
case 'U':
|
||||
IPBinInformation.AppendLine("North America NTSC.");
|
||||
break;
|
||||
case 'E':
|
||||
IPBinInformation.AppendLine("Europe PAL.");
|
||||
break;
|
||||
case 'T':
|
||||
IPBinInformation.AppendLine("Asia NTSC.");
|
||||
break;
|
||||
case ' ':
|
||||
break;
|
||||
default:
|
||||
IPBinInformation.AppendFormat("Game supports unknown region {0}.", region).AppendLine();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case "SEGA SEGAKATANA ":
|
||||
{
|
||||
Dreamcast = true;
|
||||
|
||||
if (MainClass.isDebug)
|
||||
Console.WriteLine("DEBUG (ISO9660 Plugin): Found Sega Dreamcast IP.BIN");
|
||||
|
||||
IPBinInformation.AppendLine("--------------------------------");
|
||||
IPBinInformation.AppendLine("SEGA IP.BIN INFORMATION:");
|
||||
IPBinInformation.AppendLine("--------------------------------");
|
||||
|
||||
// Declarations following
|
||||
byte[] maker_id = new byte[16]; // 0x010, "SEGA ENTERPRISES"
|
||||
byte[] dreamcast_crc = new byte[4]; // 0x020, CRC of product_no and product_version
|
||||
byte[] spare_space1 = new byte[1]; // 0x024, " "
|
||||
byte[] dreamcast_media = new byte[6]; // 0x025, "GD-ROM"
|
||||
byte[] disc_no = new byte[1]; // 0x02B, Disc number
|
||||
byte[] disc_no_separator = new byte[1]; // 0x02C, '/'
|
||||
byte[] disc_total_nos = new byte[1]; // 0x02D, Total number of discs
|
||||
byte[] spare_space2 = new byte[2]; // 0x02E, " "
|
||||
byte[] region_codes = new byte[8]; // 0x030, Region codes, space-filled
|
||||
byte[] peripherals = new byte[7]; // 0x038, Supported peripherals, bitwise
|
||||
byte[] product_no = new byte[10]; // 0x03C, Product number
|
||||
byte[] product_version = new byte[6]; // 0x046, Product version
|
||||
byte[] release_date = new byte[8]; // 0x04C, YYYYMMDD
|
||||
byte[] spare_space3 = new byte[8]; // 0x054, " "
|
||||
byte[] boot_filename = new byte[12]; // 0x05C, Usually "1ST_READ.BIN" or "0WINCE.BIN "
|
||||
byte[] producer = new byte[16]; // 0x068, Game producer, space-filled
|
||||
byte[] product_name = new byte[128]; // 0x078, Game name, space-filled
|
||||
// Reading all data
|
||||
Array.Copy(ipbin_sector, 0x010, maker_id, 0, 16); // "SEGA ENTERPRISES"
|
||||
Array.Copy(ipbin_sector, 0x020, dreamcast_crc, 0, 4); // CRC of product_no and product_version (hex)
|
||||
Array.Copy(ipbin_sector, 0x024, spare_space1, 0, 1); // " "
|
||||
Array.Copy(ipbin_sector, 0x025, dreamcast_media, 0, 6); // "GD-ROM"
|
||||
Array.Copy(ipbin_sector, 0x02B, disc_no, 0, 1); // Disc number
|
||||
Array.Copy(ipbin_sector, 0x02C, disc_no_separator, 0, 1); // '/'
|
||||
Array.Copy(ipbin_sector, 0x02D, disc_total_nos, 0, 1); // Total number of discs
|
||||
Array.Copy(ipbin_sector, 0x02E, spare_space2, 0, 2); // " "
|
||||
Array.Copy(ipbin_sector, 0x030, region_codes, 0, 8); // Region codes, space-filled
|
||||
Array.Copy(ipbin_sector, 0x038, peripherals, 0, 7); // Supported peripherals, hexadecimal
|
||||
Array.Copy(ipbin_sector, 0x040, product_no, 0, 10); // Product number
|
||||
Array.Copy(ipbin_sector, 0x04A, product_version, 0, 6); // Product version
|
||||
Array.Copy(ipbin_sector, 0x050, release_date, 0, 8); // YYYYMMDD
|
||||
Array.Copy(ipbin_sector, 0x058, spare_space3, 0, 8); // " "
|
||||
Array.Copy(ipbin_sector, 0x060, boot_filename, 0, 12); // Usually "1ST_READ.BIN" or "0WINCE.BIN "
|
||||
Array.Copy(ipbin_sector, 0x070, producer, 0, 16); // Game producer, space-filled
|
||||
Array.Copy(ipbin_sector, 0x080, product_name, 0, 128); // Game name, space-filled
|
||||
|
||||
if(MainClass.isDebug)
|
||||
{
|
||||
Console.WriteLine("DEBUG (ISO9660 Plugin): dreamcast_ipbin.maker_id = \"{0}\"", Encoding.ASCII.GetString(maker_id));
|
||||
Console.WriteLine("DEBUG (ISO9660 Plugin): dreamcast_ipbin.dreamcast_crc = 0x{0}", Encoding.ASCII.GetString(dreamcast_crc));
|
||||
Console.WriteLine("DEBUG (ISO9660 Plugin): dreamcast_ipbin.spare_space1 = \"{0}\"", Encoding.ASCII.GetString(spare_space1));
|
||||
Console.WriteLine("DEBUG (ISO9660 Plugin): dreamcast_ipbin.dreamcast_media = \"{0}\"", Encoding.ASCII.GetString(dreamcast_media));
|
||||
Console.WriteLine("DEBUG (ISO9660 Plugin): dreamcast_ipbin.disc_no = {0}", Encoding.ASCII.GetString(disc_no));
|
||||
Console.WriteLine("DEBUG (ISO9660 Plugin): dreamcast_ipbin.disc_no_separator = \"{0}\"", Encoding.ASCII.GetString(disc_no_separator));
|
||||
Console.WriteLine("DEBUG (ISO9660 Plugin): dreamcast_ipbin.disc_total_nos = \"{0}\"", Encoding.ASCII.GetString(disc_total_nos));
|
||||
Console.WriteLine("DEBUG (ISO9660 Plugin): dreamcast_ipbin.spare_space2 = \"{0}\"", Encoding.ASCII.GetString(spare_space2));
|
||||
Console.WriteLine("DEBUG (ISO9660 Plugin): dreamcast_ipbin.region_codes = \"{0}\"", Encoding.ASCII.GetString(region_codes));
|
||||
Console.WriteLine("DEBUG (ISO9660 Plugin): dreamcast_ipbin.peripherals = \"{0}\"", Encoding.ASCII.GetString(peripherals));
|
||||
Console.WriteLine("DEBUG (ISO9660 Plugin): dreamcast_ipbin.product_no = \"{0}\"", Encoding.ASCII.GetString(product_no));
|
||||
Console.WriteLine("DEBUG (ISO9660 Plugin): dreamcast_ipbin.product_version = \"{0}\"", Encoding.ASCII.GetString(product_version));
|
||||
Console.WriteLine("DEBUG (ISO9660 Plugin): dreamcast_ipbin.release_date = \"{0}\"", Encoding.ASCII.GetString(release_date));
|
||||
Console.WriteLine("DEBUG (ISO9660 Plugin): dreamcast_ipbin.spare_space3 = \"{0}\"", Encoding.ASCII.GetString(spare_space3));
|
||||
Console.WriteLine("DEBUG (ISO9660 Plugin): dreamcast_ipbin.boot_filename = \"{0}\"", Encoding.ASCII.GetString(boot_filename));
|
||||
Console.WriteLine("DEBUG (ISO9660 Plugin): dreamcast_ipbin.producer = \"{0}\"", Encoding.ASCII.GetString(producer));
|
||||
Console.WriteLine("DEBUG (ISO9660 Plugin): dreamcast_ipbin.product_name = \"{0}\"", Encoding.ASCII.GetString(product_name));
|
||||
}
|
||||
|
||||
// Decoding all data
|
||||
DateTime ipbindate;
|
||||
CultureInfo provider = CultureInfo.InvariantCulture;
|
||||
ipbindate = DateTime.ParseExact(Encoding.ASCII.GetString(release_date), "yyyyMMdd", provider);
|
||||
IPBinInformation.AppendFormat("Product name: {0}", Encoding.ASCII.GetString(product_name)).AppendLine();
|
||||
IPBinInformation.AppendFormat("Product version: {0}", Encoding.ASCII.GetString(product_version)).AppendLine();
|
||||
IPBinInformation.AppendFormat("Producer: {0}", Encoding.ASCII.GetString(producer)).AppendLine();
|
||||
IPBinInformation.AppendFormat("Disc media: {0}", Encoding.ASCII.GetString(dreamcast_media)).AppendLine();
|
||||
IPBinInformation.AppendFormat("Disc number {0} of {1}", Encoding.ASCII.GetString(disc_no), Encoding.ASCII.GetString(disc_total_nos)).AppendLine();
|
||||
IPBinInformation.AppendFormat("Release date: {0}", ipbindate).AppendLine();
|
||||
switch (Encoding.ASCII.GetString(boot_filename))
|
||||
{
|
||||
case "1ST_READ.BIN":
|
||||
IPBinInformation.AppendLine("Disc boots natively.");
|
||||
break;
|
||||
case "0WINCE.BIN ":
|
||||
IPBinInformation.AppendLine("Disc boots using Windows CE.");
|
||||
break;
|
||||
default:
|
||||
IPBinInformation.AppendFormat("Disc boots using unknown loader: {0}.", Encoding.ASCII.GetString(boot_filename)).AppendLine();
|
||||
break;
|
||||
}
|
||||
IPBinInformation.AppendLine("Regions supported:");
|
||||
foreach (byte region in region_codes)
|
||||
{
|
||||
switch ((char)region)
|
||||
{
|
||||
case 'J':
|
||||
IPBinInformation.AppendLine("Japanese NTSC.");
|
||||
break;
|
||||
case 'U':
|
||||
IPBinInformation.AppendLine("North America NTSC.");
|
||||
break;
|
||||
case 'E':
|
||||
IPBinInformation.AppendLine("Europe PAL.");
|
||||
break;
|
||||
case ' ':
|
||||
break;
|
||||
default:
|
||||
IPBinInformation.AppendFormat("Game supports unknown region {0}.", region).AppendLine();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int iPeripherals = int.Parse(Encoding.ASCII.GetString(peripherals), NumberStyles.HexNumber);
|
||||
|
||||
if((iPeripherals & 0x00000010) == 0x00000010)
|
||||
IPBinInformation.AppendLine("Game uses Windows CE.");
|
||||
|
||||
IPBinInformation.AppendFormat("Peripherals:").AppendLine();
|
||||
|
||||
if ((iPeripherals & 0x00000100) == 0x00000100)
|
||||
IPBinInformation.AppendLine("Game supports the VGA Box.");
|
||||
if ((iPeripherals & 0x00001000) == 0x00001000)
|
||||
IPBinInformation.AppendLine("Game supports other expansion.");
|
||||
if ((iPeripherals & 0x00002000) == 0x00002000)
|
||||
IPBinInformation.AppendLine("Game supports Puru Puru pack.");
|
||||
if ((iPeripherals & 0x00004000) == 0x00004000)
|
||||
IPBinInformation.AppendLine("Game supports Mike Device.");
|
||||
if ((iPeripherals & 0x00008000) == 0x00008000)
|
||||
IPBinInformation.AppendLine("Game supports Memory Card.");
|
||||
if ((iPeripherals & 0x00010000) == 0x00010000)
|
||||
IPBinInformation.AppendLine("Game requires A + B + Start buttons and D-Pad.");
|
||||
if ((iPeripherals & 0x00020000) == 0x00020000)
|
||||
IPBinInformation.AppendLine("Game requires C button.");
|
||||
if ((iPeripherals & 0x00040000) == 0x00040000)
|
||||
IPBinInformation.AppendLine("Game requires D button.");
|
||||
if ((iPeripherals & 0x00080000) == 0x00080000)
|
||||
IPBinInformation.AppendLine("Game requires X button.");
|
||||
if ((iPeripherals & 0x00100000) == 0x00100000)
|
||||
IPBinInformation.AppendLine("Game requires Y button.");
|
||||
if ((iPeripherals & 0x00200000) == 0x00200000)
|
||||
IPBinInformation.AppendLine("Game requires Z button.");
|
||||
if ((iPeripherals & 0x00400000) == 0x00400000)
|
||||
IPBinInformation.AppendLine("Game requires expanded direction buttons.");
|
||||
if ((iPeripherals & 0x00800000) == 0x00800000)
|
||||
IPBinInformation.AppendLine("Game requires analog R trigger.");
|
||||
if ((iPeripherals & 0x01000000) == 0x01000000)
|
||||
IPBinInformation.AppendLine("Game requires analog L trigger.");
|
||||
if ((iPeripherals & 0x02000000) == 0x02000000)
|
||||
IPBinInformation.AppendLine("Game requires analog horizontal controller.");
|
||||
if ((iPeripherals & 0x04000000) == 0x04000000)
|
||||
IPBinInformation.AppendLine("Game requires analog vertical controller.");
|
||||
if ((iPeripherals & 0x08000000) == 0x08000000)
|
||||
IPBinInformation.AppendLine("Game requires expanded analog horizontal controller.");
|
||||
if ((iPeripherals & 0x10000000) == 0x10000000)
|
||||
IPBinInformation.AppendLine("Game requires expanded analog vertical controller.");
|
||||
if ((iPeripherals & 0x20000000) == 0x20000000)
|
||||
IPBinInformation.AppendLine("Game supports Gun.");
|
||||
if ((iPeripherals & 0x40000000) == 0x40000000)
|
||||
IPBinInformation.AppendLine("Game supports Keyboard.");
|
||||
if ((iPeripherals & 0x80000000) == 0x80000000)
|
||||
IPBinInformation.AppendLine("Game supports Mouse.");
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
ISOMetadata.AppendFormat("ISO9660 file system").AppendLine();
|
||||
if(Joliet)
|
||||
ISOMetadata.AppendFormat("Joliet extensions present.").AppendLine();
|
||||
if (RockRidge)
|
||||
ISOMetadata.AppendFormat("Rock Ridge Interchange Protocol present.").AppendLine();
|
||||
if (Bootable)
|
||||
ISOMetadata.AppendFormat("Disc bootable following {0} specifications.", BootSpec).AppendLine();
|
||||
if (SegaCD)
|
||||
{
|
||||
ISOMetadata.AppendLine("This is a SegaCD / MegaCD disc.");
|
||||
ISOMetadata.AppendLine(IPBinInformation.ToString());
|
||||
}
|
||||
if (Saturn)
|
||||
{
|
||||
ISOMetadata.AppendLine("This is a Sega Saturn disc.");
|
||||
ISOMetadata.AppendLine(IPBinInformation.ToString());
|
||||
}
|
||||
if (Dreamcast)
|
||||
{
|
||||
ISOMetadata.AppendLine("This is a Sega Dreamcast disc.");
|
||||
ISOMetadata.AppendLine(IPBinInformation.ToString());
|
||||
}
|
||||
ISOMetadata.AppendLine("--------------------------------");
|
||||
ISOMetadata.AppendLine("VOLUME DESCRIPTOR INFORMATION:");
|
||||
ISOMetadata.AppendLine("--------------------------------");
|
||||
ISOMetadata.AppendFormat("System identifier: {0}", decodedVD.SystemIdentifier).AppendLine();
|
||||
ISOMetadata.AppendFormat("Volume identifier: {0}", decodedVD.VolumeIdentifier).AppendLine();
|
||||
ISOMetadata.AppendFormat("Volume set identifier: {0}", decodedVD.VolumeSetIdentifier).AppendLine();
|
||||
ISOMetadata.AppendFormat("Publisher identifier: {0}", decodedVD.PublisherIdentifier).AppendLine();
|
||||
ISOMetadata.AppendFormat("Data preparer identifier: {0}", decodedVD.DataPreparerIdentifier).AppendLine();
|
||||
ISOMetadata.AppendFormat("Application identifier: {0}", decodedVD.ApplicationIdentifier).AppendLine();
|
||||
ISOMetadata.AppendFormat("Volume creation date: {0}", decodedVD.CreationTime).AppendLine();
|
||||
if (decodedVD.HasModificationTime)
|
||||
ISOMetadata.AppendFormat("Volume modification date: {0}", decodedVD.ModificationTime).AppendLine();
|
||||
else
|
||||
ISOMetadata.AppendFormat("Volume has not been modified.").AppendLine();
|
||||
if (decodedVD.HasExpirationTime)
|
||||
ISOMetadata.AppendFormat("Volume expiration date: {0}", decodedVD.ExpirationTime).AppendLine();
|
||||
else
|
||||
ISOMetadata.AppendFormat("Volume does not expire.").AppendLine();
|
||||
if (decodedVD.HasEffectiveTime)
|
||||
ISOMetadata.AppendFormat("Volume effective date: {0}", decodedVD.EffectiveTime).AppendLine();
|
||||
else
|
||||
ISOMetadata.AppendFormat("Volume has always been effective.").AppendLine();
|
||||
|
||||
if(Joliet)
|
||||
{
|
||||
ISOMetadata.AppendLine("---------------------------------------");
|
||||
ISOMetadata.AppendLine("JOLIET VOLUME DESCRIPTOR INFORMATION:");
|
||||
ISOMetadata.AppendLine("---------------------------------------");
|
||||
ISOMetadata.AppendFormat("System identifier: {0}", decodedJolietVD.SystemIdentifier).AppendLine();
|
||||
ISOMetadata.AppendFormat("Volume identifier: {0}", decodedJolietVD.VolumeIdentifier).AppendLine();
|
||||
ISOMetadata.AppendFormat("Volume set identifier: {0}", decodedJolietVD.VolumeSetIdentifier).AppendLine();
|
||||
ISOMetadata.AppendFormat("Publisher identifier: {0}", decodedJolietVD.PublisherIdentifier).AppendLine();
|
||||
ISOMetadata.AppendFormat("Data preparer identifier: {0}", decodedJolietVD.DataPreparerIdentifier).AppendLine();
|
||||
ISOMetadata.AppendFormat("Application identifier: {0}", decodedJolietVD.ApplicationIdentifier).AppendLine();
|
||||
ISOMetadata.AppendFormat("Volume creation date: {0}", decodedJolietVD.CreationTime).AppendLine();
|
||||
if (decodedJolietVD.HasModificationTime)
|
||||
ISOMetadata.AppendFormat("Volume modification date: {0}", decodedJolietVD.ModificationTime).AppendLine();
|
||||
else
|
||||
ISOMetadata.AppendFormat("Volume has not been modified.").AppendLine();
|
||||
if (decodedJolietVD.HasExpirationTime)
|
||||
ISOMetadata.AppendFormat("Volume expiration date: {0}", decodedJolietVD.ExpirationTime).AppendLine();
|
||||
else
|
||||
ISOMetadata.AppendFormat("Volume does not expire.").AppendLine();
|
||||
if (decodedJolietVD.HasEffectiveTime)
|
||||
ISOMetadata.AppendFormat("Volume effective date: {0}", decodedJolietVD.EffectiveTime).AppendLine();
|
||||
else
|
||||
ISOMetadata.AppendFormat("Volume has always been effective.").AppendLine();
|
||||
}
|
||||
|
||||
information = ISOMetadata.ToString();
|
||||
}
|
||||
|
||||
static DecodedVolumeDescriptor DecodeJolietDescriptor(byte[] VDSysId, byte[] VDVolId, byte[] VDVolSetId, byte[] VDPubId, byte[] VDDataPrepId, byte[] VDAppId, byte[] VCTime, byte[] VMTime, byte[] VXTime, byte[] VETime)
|
||||
{
|
||||
DecodedVolumeDescriptor decodedVD = new DecodedVolumeDescriptor();
|
||||
|
||||
decodedVD.SystemIdentifier = Encoding.BigEndianUnicode.GetString(VDSysId);
|
||||
decodedVD.VolumeIdentifier = Encoding.BigEndianUnicode.GetString(VDVolId);
|
||||
decodedVD.VolumeSetIdentifier = Encoding.BigEndianUnicode.GetString(VDVolSetId);
|
||||
decodedVD.PublisherIdentifier = Encoding.BigEndianUnicode.GetString(VDPubId);
|
||||
decodedVD.DataPreparerIdentifier = Encoding.BigEndianUnicode.GetString(VDDataPrepId);
|
||||
decodedVD.ApplicationIdentifier = Encoding.BigEndianUnicode.GetString(VDAppId);
|
||||
if (VCTime[0] == '0' || VCTime[0] == 0x00)
|
||||
decodedVD.CreationTime = DateTime.MinValue;
|
||||
else
|
||||
decodedVD.CreationTime = DateHandlers.ISO9660ToDateTime(VCTime);
|
||||
|
||||
if (VMTime[0] == '0' || VMTime[0] == 0x00)
|
||||
{
|
||||
decodedVD.HasModificationTime = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
decodedVD.HasModificationTime = true;
|
||||
decodedVD.ModificationTime = DateHandlers.ISO9660ToDateTime(VMTime);
|
||||
}
|
||||
|
||||
if (VXTime[0] == '0' || VXTime[0] == 0x00)
|
||||
{
|
||||
decodedVD.HasExpirationTime = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
decodedVD.HasExpirationTime = true;
|
||||
decodedVD.ExpirationTime = DateHandlers.ISO9660ToDateTime(VXTime);
|
||||
}
|
||||
|
||||
if (VETime[0] == '0' || VETime[0] == 0x00)
|
||||
{
|
||||
decodedVD.HasEffectiveTime = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
decodedVD.HasEffectiveTime = true;
|
||||
decodedVD.EffectiveTime = DateHandlers.ISO9660ToDateTime(VETime);
|
||||
}
|
||||
|
||||
return decodedVD;
|
||||
}
|
||||
|
||||
static DecodedVolumeDescriptor DecodeVolumeDescriptor(byte[] VDSysId, byte[] VDVolId, byte[] VDVolSetId, byte[] VDPubId, byte[] VDDataPrepId, byte[] VDAppId, byte[] VCTime, byte[] VMTime, byte[] VXTime, byte[] VETime)
|
||||
{
|
||||
DecodedVolumeDescriptor decodedVD = new DecodedVolumeDescriptor();
|
||||
|
||||
decodedVD.SystemIdentifier = Encoding.ASCII.GetString(VDSysId);
|
||||
decodedVD.VolumeIdentifier = Encoding.ASCII.GetString(VDVolId);
|
||||
decodedVD.VolumeSetIdentifier = Encoding.ASCII.GetString(VDVolSetId);
|
||||
decodedVD.PublisherIdentifier = Encoding.ASCII.GetString(VDPubId);
|
||||
decodedVD.DataPreparerIdentifier = Encoding.ASCII.GetString(VDDataPrepId);
|
||||
decodedVD.ApplicationIdentifier = Encoding.ASCII.GetString(VDAppId);
|
||||
if (VCTime[0] == '0' || VCTime[0] == 0x00)
|
||||
decodedVD.CreationTime = DateTime.MinValue;
|
||||
else
|
||||
decodedVD.CreationTime = DateHandlers.ISO9660ToDateTime(VCTime);
|
||||
|
||||
if (VMTime[0] == '0' || VMTime[0] == 0x00)
|
||||
{
|
||||
decodedVD.HasModificationTime = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
decodedVD.HasModificationTime = true;
|
||||
decodedVD.ModificationTime = DateHandlers.ISO9660ToDateTime(VMTime);
|
||||
}
|
||||
|
||||
if (VXTime[0] == '0' || VXTime[0] == 0x00)
|
||||
{
|
||||
decodedVD.HasExpirationTime = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
decodedVD.HasExpirationTime = true;
|
||||
decodedVD.ExpirationTime = DateHandlers.ISO9660ToDateTime(VXTime);
|
||||
}
|
||||
|
||||
if (VETime[0] == '0' || VETime[0] == 0x00)
|
||||
{
|
||||
decodedVD.HasEffectiveTime = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
decodedVD.HasEffectiveTime = true;
|
||||
decodedVD.EffectiveTime = DateHandlers.ISO9660ToDateTime(VETime);
|
||||
}
|
||||
|
||||
return decodedVD;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,584 +0,0 @@
|
||||
/***************************************************************************
|
||||
The Disc Image Chef
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
Filename : LisaFS.cs
|
||||
Version : 1.0
|
||||
Author(s) : Natalia Portillo
|
||||
|
||||
Component : Filesystem plugins
|
||||
|
||||
Revision : $Revision$
|
||||
Last change by : $Author$
|
||||
Date : $Date$
|
||||
|
||||
--[ Description ] ----------------------------------------------------------
|
||||
|
||||
Identifies Apple Lisa filesystems and shows information.
|
||||
|
||||
--[ License ] --------------------------------------------------------------
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
----------------------------------------------------------------------------
|
||||
Copyright (C) 2011-2014 Claunia.com
|
||||
****************************************************************************/
|
||||
//$Id$
|
||||
|
||||
using System;
|
||||
using System.Text;
|
||||
using DiscImageChef;
|
||||
using DiscImageChef.ImagePlugins;
|
||||
|
||||
// All information by Natalia Portillo
|
||||
// Variable names from Lisa API
|
||||
namespace DiscImageChef.Plugins
|
||||
{
|
||||
class LisaFS : Plugin
|
||||
{
|
||||
const byte LisaFSv1 = 0x0E;
|
||||
const byte LisaFSv2 = 0x0F;
|
||||
const byte LisaFSv3 = 0x11;
|
||||
const uint E_NAME = 32;
|
||||
// Maximum string size in LisaFS
|
||||
const UInt16 FILEID_FREE = 0x0000;
|
||||
const UInt16 FILEID_BOOT = 0xAAAA;
|
||||
const UInt16 FILEID_LOADER = 0xBBBB;
|
||||
const UInt16 FILEID_MDDF = 0x0001;
|
||||
const UInt16 FILEID_BITMAP = 0x0002;
|
||||
const UInt16 FILEID_SRECORD = 0x0003;
|
||||
const UInt16 FILEID_DIRECTORY = 0x0004;
|
||||
// "Catalog file"
|
||||
const UInt16 FILEID_ERASED = 0x7FFF;
|
||||
const UInt16 FILEID_MAX = FILEID_ERASED;
|
||||
|
||||
public LisaFS(PluginBase Core)
|
||||
{
|
||||
Name = "Apple Lisa File System";
|
||||
PluginUUID = new Guid("7E6034D1-D823-4248-A54D-239742B28391");
|
||||
}
|
||||
|
||||
public override bool Identify(ImagePlugin imagePlugin, ulong partitionStart, ulong partitionEnd)
|
||||
{
|
||||
try
|
||||
{
|
||||
if(imagePlugin.ImageInfo.readableSectorTags==null)
|
||||
return false;
|
||||
|
||||
if(!imagePlugin.ImageInfo.readableSectorTags.Contains(SectorTagType.AppleSectorTag))
|
||||
return false;
|
||||
|
||||
// LisaOS is big-endian
|
||||
BigEndianBitConverter.IsLittleEndian = BitConverter.IsLittleEndian;
|
||||
|
||||
// Minimal LisaOS disk is 3.5" single sided double density, 800 sectors
|
||||
if (imagePlugin.GetSectors() < 800)
|
||||
return false;
|
||||
|
||||
// LisaOS searches sectors until tag tells MDDF resides there, so we'll search 100 sectors
|
||||
for (int i = 0; i < 100; i++)
|
||||
{
|
||||
byte[] tag = imagePlugin.ReadSectorTag((ulong)i, SectorTagType.AppleSectorTag);
|
||||
UInt16 fileid = BigEndianBitConverter.ToUInt16(tag, 0x04);
|
||||
|
||||
if (MainClass.isDebug)
|
||||
Console.WriteLine("DEBUG (LisaFS plugin): Sector {0}, file ID 0x{1:X4}", i, fileid);
|
||||
|
||||
if (fileid == FILEID_MDDF)
|
||||
{
|
||||
byte[] sector = imagePlugin.ReadSector((ulong)i);
|
||||
Lisa_MDDF mddf = new Lisa_MDDF();
|
||||
|
||||
mddf.mddf_block = BigEndianBitConverter.ToUInt32(sector, 0x6C);
|
||||
mddf.volsize_minus_one = BigEndianBitConverter.ToUInt32(sector, 0x70);
|
||||
mddf.volsize_minus_mddf_minus_one = BigEndianBitConverter.ToUInt32(sector, 0x74);
|
||||
mddf.vol_size = BigEndianBitConverter.ToUInt32(sector, 0x78);
|
||||
mddf.blocksize = BigEndianBitConverter.ToUInt16(sector, 0x7C);
|
||||
mddf.datasize = BigEndianBitConverter.ToUInt16(sector, 0x7E);
|
||||
|
||||
if (MainClass.isDebug)
|
||||
{
|
||||
Console.WriteLine("DEBUG (LisaFS plugin): Current sector = {0}", i);
|
||||
Console.WriteLine("DEBUG (LisaFS plugin): mddf.mddf_block = {0}", mddf.mddf_block);
|
||||
Console.WriteLine("DEBUG (LisaFS plugin): Disk size = {0} sectors", imagePlugin.GetSectors());
|
||||
Console.WriteLine("DEBUG (LisaFS plugin): mddf.vol_size = {0} sectors", mddf.vol_size);
|
||||
Console.WriteLine("DEBUG (LisaFS plugin): mddf.vol_size - 1 = {0}", mddf.volsize_minus_one);
|
||||
Console.WriteLine("DEBUG (LisaFS plugin): mddf.vol_size - mddf.mddf_block -1 = {0}", mddf.volsize_minus_mddf_minus_one);
|
||||
Console.WriteLine("DEBUG (LisaFS plugin): Disk sector = {0} bytes", imagePlugin.GetSectorSize());
|
||||
Console.WriteLine("DEBUG (LisaFS plugin): mddf.blocksize = {0} bytes", mddf.blocksize);
|
||||
Console.WriteLine("DEBUG (LisaFS plugin): mddf.datasize = {0} bytes", mddf.datasize);
|
||||
}
|
||||
|
||||
if (mddf.mddf_block != i)
|
||||
return false;
|
||||
|
||||
if (mddf.vol_size > imagePlugin.GetSectors())
|
||||
return false;
|
||||
|
||||
if (mddf.vol_size - 1 != mddf.volsize_minus_one)
|
||||
return false;
|
||||
|
||||
if (mddf.vol_size - i - 1 != mddf.volsize_minus_mddf_minus_one)
|
||||
return false;
|
||||
|
||||
if (mddf.datasize > mddf.blocksize)
|
||||
return false;
|
||||
|
||||
if (mddf.blocksize < imagePlugin.GetSectorSize())
|
||||
return false;
|
||||
|
||||
if (mddf.datasize != imagePlugin.GetSectorSize())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (MainClass.isDebug)
|
||||
Console.WriteLine("DEBUG (LisaFS plugin): Exception {0}, {1}, {2}", ex.Message, ex.InnerException, ex.StackTrace);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public override void GetInformation(ImagePlugin imagePlugin, ulong partitionStart, ulong partitionEnd, out string information)
|
||||
{
|
||||
information = "";
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
try
|
||||
{
|
||||
if(imagePlugin.ImageInfo.readableSectorTags==null)
|
||||
return;
|
||||
|
||||
if(!imagePlugin.ImageInfo.readableSectorTags.Contains(SectorTagType.AppleSectorTag))
|
||||
return;
|
||||
|
||||
// LisaOS is big-endian
|
||||
BigEndianBitConverter.IsLittleEndian = BitConverter.IsLittleEndian;
|
||||
|
||||
// Minimal LisaOS disk is 3.5" single sided double density, 800 sectors
|
||||
if (imagePlugin.GetSectors() < 800)
|
||||
return;
|
||||
|
||||
// LisaOS searches sectors until tag tells MDDF resides there, so we'll search 100 sectors
|
||||
for (int i = 0; i < 100; i++)
|
||||
{
|
||||
byte[] tag = imagePlugin.ReadSectorTag((ulong)i, SectorTagType.AppleSectorTag);
|
||||
UInt16 fileid = BigEndianBitConverter.ToUInt16(tag, 0x04);
|
||||
|
||||
if (MainClass.isDebug)
|
||||
Console.WriteLine("DEBUG (LisaFS plugin): Sector {0}, file ID 0x{1:X4}", i, fileid);
|
||||
|
||||
if (fileid == FILEID_MDDF)
|
||||
{
|
||||
byte[] sector = imagePlugin.ReadSector((ulong)i);
|
||||
Lisa_MDDF mddf = new Lisa_MDDF();
|
||||
byte[] pString = new byte[33];
|
||||
UInt32 lisa_time;
|
||||
|
||||
mddf.fsversion = BigEndianBitConverter.ToUInt16(sector, 0x00);
|
||||
mddf.volid = BigEndianBitConverter.ToUInt64(sector, 0x02);
|
||||
mddf.volnum = BigEndianBitConverter.ToUInt16(sector, 0x0A);
|
||||
Array.Copy(sector, 0x0C, pString, 0, 33);
|
||||
mddf.volname = StringHandlers.PascalToString(pString);
|
||||
mddf.unknown1 = sector[0x2D];
|
||||
Array.Copy(sector, 0x2E, pString, 0, 33);
|
||||
// Prevent garbage
|
||||
if (pString[0] <= 32)
|
||||
mddf.password = StringHandlers.PascalToString(pString);
|
||||
else
|
||||
mddf.password = "";
|
||||
mddf.unknown2 = sector[0x4F];
|
||||
mddf.machine_id = BigEndianBitConverter.ToUInt32(sector, 0x50);
|
||||
mddf.master_copy_id = BigEndianBitConverter.ToUInt32(sector, 0x54);
|
||||
lisa_time = BigEndianBitConverter.ToUInt32(sector, 0x58);
|
||||
mddf.dtvc = DateHandlers.LisaToDateTime(lisa_time);
|
||||
lisa_time = BigEndianBitConverter.ToUInt32(sector, 0x5C);
|
||||
mddf.dtcc = DateHandlers.LisaToDateTime(lisa_time);
|
||||
lisa_time = BigEndianBitConverter.ToUInt32(sector, 0x60);
|
||||
mddf.dtvb = DateHandlers.LisaToDateTime(lisa_time);
|
||||
lisa_time = BigEndianBitConverter.ToUInt32(sector, 0x64);
|
||||
mddf.dtvs = DateHandlers.LisaToDateTime(lisa_time);
|
||||
mddf.unknown3 = BigEndianBitConverter.ToUInt32(sector, 0x68);
|
||||
mddf.mddf_block = BigEndianBitConverter.ToUInt32(sector, 0x6C);
|
||||
mddf.volsize_minus_one = BigEndianBitConverter.ToUInt32(sector, 0x70);
|
||||
mddf.volsize_minus_mddf_minus_one = BigEndianBitConverter.ToUInt32(sector, 0x74);
|
||||
mddf.vol_size = BigEndianBitConverter.ToUInt32(sector, 0x78);
|
||||
mddf.blocksize = BigEndianBitConverter.ToUInt16(sector, 0x7C);
|
||||
mddf.datasize = BigEndianBitConverter.ToUInt16(sector, 0x7E);
|
||||
mddf.unknown4 = BigEndianBitConverter.ToUInt16(sector, 0x80);
|
||||
mddf.unknown5 = BigEndianBitConverter.ToUInt32(sector, 0x82);
|
||||
mddf.unknown6 = BigEndianBitConverter.ToUInt32(sector, 0x86);
|
||||
mddf.clustersize = BigEndianBitConverter.ToUInt16(sector, 0x8A);
|
||||
mddf.fs_size = BigEndianBitConverter.ToUInt32(sector, 0x8C);
|
||||
mddf.unknown7 = BigEndianBitConverter.ToUInt32(sector, 0x90);
|
||||
mddf.unknown8 = BigEndianBitConverter.ToUInt32(sector, 0x94);
|
||||
mddf.unknown9 = BigEndianBitConverter.ToUInt32(sector, 0x98);
|
||||
mddf.unknown10 = BigEndianBitConverter.ToUInt32(sector, 0x9C);
|
||||
mddf.unknown11 = BigEndianBitConverter.ToUInt32(sector, 0xA0);
|
||||
mddf.unknown12 = BigEndianBitConverter.ToUInt32(sector, 0xA4);
|
||||
mddf.unknown13 = BigEndianBitConverter.ToUInt32(sector, 0xA8);
|
||||
mddf.unknown14 = BigEndianBitConverter.ToUInt32(sector, 0xAC);
|
||||
mddf.filecount = BigEndianBitConverter.ToUInt16(sector, 0xB0);
|
||||
mddf.unknown15 = BigEndianBitConverter.ToUInt32(sector, 0xB2);
|
||||
mddf.unknown16 = BigEndianBitConverter.ToUInt32(sector, 0xB6);
|
||||
mddf.freecount = BigEndianBitConverter.ToUInt32(sector, 0xBA);
|
||||
mddf.unknown17 = BigEndianBitConverter.ToUInt16(sector, 0xBE);
|
||||
mddf.unknown18 = BigEndianBitConverter.ToUInt32(sector, 0xC0);
|
||||
mddf.overmount_stamp = BigEndianBitConverter.ToUInt64(sector, 0xC4);
|
||||
mddf.serialization = BigEndianBitConverter.ToUInt32(sector, 0xCC);
|
||||
mddf.unknown19 = BigEndianBitConverter.ToUInt32(sector, 0xD0);
|
||||
mddf.unknown_timestamp = BigEndianBitConverter.ToUInt32(sector, 0xD4);
|
||||
mddf.unknown20 = BigEndianBitConverter.ToUInt32(sector, 0xD8);
|
||||
mddf.unknown21 = BigEndianBitConverter.ToUInt32(sector, 0xDC);
|
||||
mddf.unknown22 = BigEndianBitConverter.ToUInt32(sector, 0xE0);
|
||||
mddf.unknown23 = BigEndianBitConverter.ToUInt32(sector, 0xE4);
|
||||
mddf.unknown24 = BigEndianBitConverter.ToUInt32(sector, 0xE8);
|
||||
mddf.unknown25 = BigEndianBitConverter.ToUInt32(sector, 0xEC);
|
||||
mddf.unknown26 = BigEndianBitConverter.ToUInt32(sector, 0xF0);
|
||||
mddf.unknown27 = BigEndianBitConverter.ToUInt32(sector, 0xF4);
|
||||
mddf.unknown28 = BigEndianBitConverter.ToUInt32(sector, 0xF8);
|
||||
mddf.unknown29 = BigEndianBitConverter.ToUInt32(sector, 0xFC);
|
||||
mddf.unknown30 = BigEndianBitConverter.ToUInt32(sector, 0x100);
|
||||
mddf.unknown31 = BigEndianBitConverter.ToUInt32(sector, 0x104);
|
||||
mddf.unknown32 = BigEndianBitConverter.ToUInt32(sector, 0x108);
|
||||
mddf.unknown33 = BigEndianBitConverter.ToUInt32(sector, 0x10C);
|
||||
mddf.unknown34 = BigEndianBitConverter.ToUInt32(sector, 0x110);
|
||||
mddf.unknown35 = BigEndianBitConverter.ToUInt32(sector, 0x114);
|
||||
mddf.backup_volid = BigEndianBitConverter.ToUInt64(sector, 0x118);
|
||||
mddf.label_size = BigEndianBitConverter.ToUInt16(sector, 0x120);
|
||||
mddf.fs_overhead = BigEndianBitConverter.ToUInt16(sector, 0x122);
|
||||
mddf.result_scavenge = BigEndianBitConverter.ToUInt16(sector, 0x124);
|
||||
mddf.boot_code = BigEndianBitConverter.ToUInt16(sector, 0x126);
|
||||
mddf.boot_environ = BigEndianBitConverter.ToUInt16(sector, 0x6C);
|
||||
mddf.unknown36 = BigEndianBitConverter.ToUInt32(sector, 0x12A);
|
||||
mddf.unknown37 = BigEndianBitConverter.ToUInt32(sector, 0x12E);
|
||||
mddf.unknown38 = BigEndianBitConverter.ToUInt32(sector, 0x132);
|
||||
mddf.vol_sequence = BigEndianBitConverter.ToUInt16(sector, 0x136);
|
||||
mddf.vol_left_mounted = sector[0x138];
|
||||
|
||||
if (MainClass.isDebug)
|
||||
{
|
||||
Console.WriteLine("mddf.unknown1 = 0x{0:X2} ({0})", mddf.unknown1);
|
||||
Console.WriteLine("mddf.unknown2 = 0x{0:X2} ({0})", mddf.unknown2);
|
||||
Console.WriteLine("mddf.unknown3 = 0x{0:X8} ({0})", mddf.unknown3);
|
||||
Console.WriteLine("mddf.unknown4 = 0x{0:X4} ({0})", mddf.unknown4);
|
||||
Console.WriteLine("mddf.unknown5 = 0x{0:X8} ({0})", mddf.unknown5);
|
||||
Console.WriteLine("mddf.unknown6 = 0x{0:X8} ({0})", mddf.unknown6);
|
||||
Console.WriteLine("mddf.unknown7 = 0x{0:X8} ({0})", mddf.unknown7);
|
||||
Console.WriteLine("mddf.unknown8 = 0x{0:X8} ({0})", mddf.unknown8);
|
||||
Console.WriteLine("mddf.unknown9 = 0x{0:X8} ({0})", mddf.unknown9);
|
||||
Console.WriteLine("mddf.unknown10 = 0x{0:X8} ({0})", mddf.unknown10);
|
||||
Console.WriteLine("mddf.unknown11 = 0x{0:X8} ({0})", mddf.unknown11);
|
||||
Console.WriteLine("mddf.unknown12 = 0x{0:X8} ({0})", mddf.unknown12);
|
||||
Console.WriteLine("mddf.unknown13 = 0x{0:X8} ({0})", mddf.unknown13);
|
||||
Console.WriteLine("mddf.unknown14 = 0x{0:X8} ({0})", mddf.unknown14);
|
||||
Console.WriteLine("mddf.unknown15 = 0x{0:X8} ({0})", mddf.unknown15);
|
||||
Console.WriteLine("mddf.unknown16 = 0x{0:X8} ({0})", mddf.unknown16);
|
||||
Console.WriteLine("mddf.unknown17 = 0x{0:X4} ({0})", mddf.unknown17);
|
||||
Console.WriteLine("mddf.unknown18 = 0x{0:X8} ({0})", mddf.unknown18);
|
||||
Console.WriteLine("mddf.unknown19 = 0x{0:X8} ({0})", mddf.unknown19);
|
||||
Console.WriteLine("mddf.unknown20 = 0x{0:X8} ({0})", mddf.unknown20);
|
||||
Console.WriteLine("mddf.unknown21 = 0x{0:X8} ({0})", mddf.unknown21);
|
||||
Console.WriteLine("mddf.unknown22 = 0x{0:X8} ({0})", mddf.unknown22);
|
||||
Console.WriteLine("mddf.unknown23 = 0x{0:X8} ({0})", mddf.unknown23);
|
||||
Console.WriteLine("mddf.unknown24 = 0x{0:X8} ({0})", mddf.unknown24);
|
||||
Console.WriteLine("mddf.unknown25 = 0x{0:X8} ({0})", mddf.unknown25);
|
||||
Console.WriteLine("mddf.unknown26 = 0x{0:X8} ({0})", mddf.unknown26);
|
||||
Console.WriteLine("mddf.unknown27 = 0x{0:X8} ({0})", mddf.unknown27);
|
||||
Console.WriteLine("mddf.unknown28 = 0x{0:X8} ({0})", mddf.unknown28);
|
||||
Console.WriteLine("mddf.unknown29 = 0x{0:X8} ({0})", mddf.unknown29);
|
||||
Console.WriteLine("mddf.unknown30 = 0x{0:X8} ({0})", mddf.unknown30);
|
||||
Console.WriteLine("mddf.unknown31 = 0x{0:X8} ({0})", mddf.unknown31);
|
||||
Console.WriteLine("mddf.unknown32 = 0x{0:X8} ({0})", mddf.unknown32);
|
||||
Console.WriteLine("mddf.unknown33 = 0x{0:X8} ({0})", mddf.unknown33);
|
||||
Console.WriteLine("mddf.unknown34 = 0x{0:X8} ({0})", mddf.unknown34);
|
||||
Console.WriteLine("mddf.unknown35 = 0x{0:X8} ({0})", mddf.unknown35);
|
||||
Console.WriteLine("mddf.unknown36 = 0x{0:X8} ({0})", mddf.unknown36);
|
||||
Console.WriteLine("mddf.unknown37 = 0x{0:X8} ({0})", mddf.unknown37);
|
||||
Console.WriteLine("mddf.unknown38 = 0x{0:X8} ({0})", mddf.unknown38);
|
||||
Console.WriteLine("mddf.unknown_timestamp = 0x{0:X8} ({0}, {1})", mddf.unknown_timestamp, DateHandlers.LisaToDateTime(mddf.unknown_timestamp));
|
||||
}
|
||||
|
||||
if (mddf.mddf_block != i)
|
||||
return;
|
||||
|
||||
if (mddf.vol_size > imagePlugin.GetSectors())
|
||||
return;
|
||||
|
||||
if (mddf.vol_size - 1 != mddf.volsize_minus_one)
|
||||
return;
|
||||
|
||||
if (mddf.vol_size - i - 1 != mddf.volsize_minus_mddf_minus_one)
|
||||
return;
|
||||
|
||||
if (mddf.datasize > mddf.blocksize)
|
||||
return;
|
||||
|
||||
if (mddf.blocksize < imagePlugin.GetSectorSize())
|
||||
return;
|
||||
|
||||
if (mddf.datasize != imagePlugin.GetSectorSize())
|
||||
return;
|
||||
|
||||
switch (mddf.fsversion)
|
||||
{
|
||||
case LisaFSv1:
|
||||
sb.AppendLine("LisaFS v1");
|
||||
break;
|
||||
case LisaFSv2:
|
||||
sb.AppendLine("LisaFS v2");
|
||||
break;
|
||||
case LisaFSv3:
|
||||
sb.AppendLine("LisaFS v3");
|
||||
break;
|
||||
default:
|
||||
sb.AppendFormat("Uknown LisaFS version {0}", mddf.fsversion).AppendLine();
|
||||
break;
|
||||
}
|
||||
|
||||
sb.AppendFormat("Volume name: \"{0}\"", mddf.volname).AppendLine();
|
||||
sb.AppendFormat("Volume password: \"{0}\"", mddf.password).AppendLine();
|
||||
sb.AppendFormat("Volume ID: 0x{0:X16}", mddf.volid).AppendLine();
|
||||
sb.AppendFormat("Backup volume ID: 0x{0:X16}", mddf.backup_volid).AppendLine();
|
||||
|
||||
sb.AppendFormat("Master copy ID: 0x{0:X8}", mddf.master_copy_id).AppendLine();
|
||||
|
||||
sb.AppendFormat("Volume is number {0} of {1}", mddf.volnum, mddf.vol_sequence).AppendLine();
|
||||
|
||||
sb.AppendFormat("Serial number of Lisa computer that created this volume: {0}", mddf.machine_id).AppendLine();
|
||||
sb.AppendFormat("Serial number of Lisa computer that can use this volume's software {0}", mddf.serialization).AppendLine();
|
||||
|
||||
sb.AppendFormat("Volume created on {0}", mddf.dtvc).AppendLine();
|
||||
sb.AppendFormat("Some timestamp, says {0}", mddf.dtcc).AppendLine();
|
||||
sb.AppendFormat("Volume backed up on {0}", mddf.dtvb).AppendLine();
|
||||
sb.AppendFormat("Volume scavenged on {0}", mddf.dtvs).AppendLine();
|
||||
sb.AppendFormat("MDDF is in block {0}", mddf.mddf_block).AppendLine();
|
||||
sb.AppendFormat("{0} blocks minus one", mddf.volsize_minus_one).AppendLine();
|
||||
sb.AppendFormat("{0} blocks minus one minus MDDF offset", mddf.volsize_minus_mddf_minus_one).AppendLine();
|
||||
sb.AppendFormat("{0} blocks in volume", mddf.vol_size).AppendLine();
|
||||
sb.AppendFormat("{0} bytes per sector (uncooked)", mddf.blocksize).AppendLine();
|
||||
sb.AppendFormat("{0} bytes per sector", mddf.datasize).AppendLine();
|
||||
sb.AppendFormat("{0} blocks per cluster", mddf.clustersize).AppendLine();
|
||||
sb.AppendFormat("{0} blocks in filesystem", mddf.fs_size).AppendLine();
|
||||
sb.AppendFormat("{0} files in volume", mddf.filecount).AppendLine();
|
||||
sb.AppendFormat("{0} blocks free", mddf.freecount).AppendLine();
|
||||
sb.AppendFormat("{0} bytes in LisaInfo", mddf.label_size).AppendLine();
|
||||
sb.AppendFormat("Filesystem overhead: {0}", mddf.fs_overhead).AppendLine();
|
||||
sb.AppendFormat("Scanvenger result code: 0x{0:X8}", mddf.result_scavenge).AppendLine();
|
||||
sb.AppendFormat("Boot code: 0x{0:X8}", mddf.boot_code).AppendLine();
|
||||
sb.AppendFormat("Boot environment: 0x{0:X8}", mddf.boot_environ).AppendLine();
|
||||
sb.AppendFormat("Overmount stamp: 0x{0:X16}", mddf.overmount_stamp).AppendLine();
|
||||
|
||||
if (mddf.vol_left_mounted == 0)
|
||||
sb.AppendLine("Volume is clean");
|
||||
else
|
||||
sb.AppendLine("Volume is dirty");
|
||||
|
||||
information = sb.ToString();
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (MainClass.isDebug)
|
||||
Console.WriteLine("DEBUG (LisaFS plugin): Exception {0}, {1}, {2}", ex.Message, ex.InnerException, ex.StackTrace);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
struct Lisa_MDDF
|
||||
{
|
||||
// 0x00, Filesystem version
|
||||
public UInt16 fsversion;
|
||||
// 0x02, Volume ID
|
||||
public UInt64 volid;
|
||||
// 0x0A, Volume sequence number
|
||||
public UInt16 volnum;
|
||||
// 0x0C, Pascal string, 32+1 bytes, volume name
|
||||
public string volname;
|
||||
// 0x2D, unknown, possible padding
|
||||
public byte unknown1;
|
||||
// 0x2E, Pascal string, 32+1 bytes, password
|
||||
public string password;
|
||||
// 0x4F, unknown, possible padding
|
||||
public byte unknown2;
|
||||
// 0x50, Lisa serial number that init'ed this disk
|
||||
public UInt32 machine_id;
|
||||
// 0x54, ID of the master copy ? no idea really
|
||||
public UInt32 master_copy_id;
|
||||
// 0x58, Date of volume creation
|
||||
public DateTime dtvc;
|
||||
// 0x5C, Date...
|
||||
public DateTime dtcc;
|
||||
// 0x60, Date of volume backup
|
||||
public DateTime dtvb;
|
||||
// 0x64, Date of volume scavenging
|
||||
public DateTime dtvs;
|
||||
// 0x68, unknown
|
||||
public UInt32 unknown3;
|
||||
// 0x6C, block the MDDF is residing on
|
||||
public UInt32 mddf_block;
|
||||
// 0x70, volsize-1
|
||||
public UInt32 volsize_minus_one;
|
||||
// 0x74, volsize-1-mddf_block
|
||||
public UInt32 volsize_minus_mddf_minus_one;
|
||||
// 0x78, Volume size in blocks
|
||||
public UInt32 vol_size;
|
||||
// 0x7C, Blocks size of underlying drive (data+tags)
|
||||
public UInt16 blocksize;
|
||||
// 0x7E, Data only block size
|
||||
public UInt16 datasize;
|
||||
// 0x80, unknown
|
||||
public UInt16 unknown4;
|
||||
// 0x82, unknown
|
||||
public UInt32 unknown5;
|
||||
// 0x86, unknown
|
||||
public UInt32 unknown6;
|
||||
// 0x8A, Size in sectors of filesystem clusters
|
||||
public UInt16 clustersize;
|
||||
// 0x8C, Filesystem size in blocks
|
||||
public UInt32 fs_size;
|
||||
// 0x90, unknown
|
||||
public UInt32 unknown7;
|
||||
// 0x94, unknown
|
||||
public UInt32 unknown8;
|
||||
// 0x98, unknown
|
||||
public UInt32 unknown9;
|
||||
// 0x9C, unknown
|
||||
public UInt32 unknown10;
|
||||
// 0xA0, unknown
|
||||
public UInt32 unknown11;
|
||||
// 0xA4, unknown
|
||||
public UInt32 unknown12;
|
||||
// 0xA8, unknown
|
||||
public UInt32 unknown13;
|
||||
// 0xAC, unknown
|
||||
public UInt32 unknown14;
|
||||
// 0xB0, Files in volume
|
||||
public UInt16 filecount;
|
||||
// 0xB2, unknown
|
||||
public UInt32 unknown15;
|
||||
// 0xB6, unknown
|
||||
public UInt32 unknown16;
|
||||
// 0xBA, Free blocks
|
||||
public UInt32 freecount;
|
||||
// 0xBE, unknown
|
||||
public UInt16 unknown17;
|
||||
// 0xC0, unknown
|
||||
public UInt32 unknown18;
|
||||
// 0xC4, no idea
|
||||
public UInt64 overmount_stamp;
|
||||
// 0xCC, serialization, lisa serial number authorized to use blocked software on this volume
|
||||
public UInt32 serialization;
|
||||
// 0xD0, unknown
|
||||
public UInt32 unknown19;
|
||||
// 0xD4, unknown, possible timestamp
|
||||
public UInt32 unknown_timestamp;
|
||||
// 0xD8, unknown
|
||||
public UInt32 unknown20;
|
||||
// 0xDC, unknown
|
||||
public UInt32 unknown21;
|
||||
// 0xE0, unknown
|
||||
public UInt32 unknown22;
|
||||
// 0xE4, unknown
|
||||
public UInt32 unknown23;
|
||||
// 0xE8, unknown
|
||||
public UInt32 unknown24;
|
||||
// 0xEC, unknown
|
||||
public UInt32 unknown25;
|
||||
// 0xF0, unknown
|
||||
public UInt32 unknown26;
|
||||
// 0xF4, unknown
|
||||
public UInt32 unknown27;
|
||||
// 0xF8, unknown
|
||||
public UInt32 unknown28;
|
||||
// 0xFC, unknown
|
||||
public UInt32 unknown29;
|
||||
// 0x100, unknown
|
||||
public UInt32 unknown30;
|
||||
// 0x104, unknown
|
||||
public UInt32 unknown31;
|
||||
// 0x108, unknown
|
||||
public UInt32 unknown32;
|
||||
// 0x10C, unknown
|
||||
public UInt32 unknown33;
|
||||
// 0x110, unknown
|
||||
public UInt32 unknown34;
|
||||
// 0x114, unknown
|
||||
public UInt32 unknown35;
|
||||
// 0x118, ID of volume where this volume was backed up
|
||||
public UInt64 backup_volid;
|
||||
// 0x120, Size of LisaInfo label
|
||||
public UInt16 label_size;
|
||||
// 0x122, not clear
|
||||
public UInt16 fs_overhead;
|
||||
// 0x124, Return code of Scavenger
|
||||
public UInt16 result_scavenge;
|
||||
// 0x126, No idea
|
||||
public UInt16 boot_code;
|
||||
// 0x128, No idea
|
||||
public UInt16 boot_environ;
|
||||
// 0x12A, unknown
|
||||
public UInt32 unknown36;
|
||||
// 0x12E, unknown
|
||||
public UInt32 unknown37;
|
||||
// 0x132, unknown
|
||||
public UInt32 unknown38;
|
||||
// 0x136, Total volumes in sequence
|
||||
public UInt16 vol_sequence;
|
||||
// 0x138, Volume is dirty?
|
||||
public byte vol_left_mounted;
|
||||
// Is password present? (On-disk position unknown)
|
||||
public byte passwd_present;
|
||||
// Opened files (memory-only?) (On-disk position unknown)
|
||||
public UInt32 opencount;
|
||||
// No idea (On-disk position unknown)
|
||||
public UInt32 copy_thread;
|
||||
// Flags are boolean, but Pascal seems to use them as full unsigned 8 bit values
|
||||
// No idea (On-disk position unknown)
|
||||
public byte privileged;
|
||||
// Read-only volume (On-disk position unknown)
|
||||
public byte write_protected;
|
||||
// Master disk (On-disk position unknown)
|
||||
public byte master;
|
||||
// Copy disk (On-disk position unknown)
|
||||
public byte copy;
|
||||
// No idea (On-disk position unknown)
|
||||
public byte copy_flag;
|
||||
// No idea (On-disk position unknown)
|
||||
public byte scavenge_flag;
|
||||
}
|
||||
|
||||
struct Lisa_Tag
|
||||
{
|
||||
// 0x00 Unknown
|
||||
public UInt32 unknown1;
|
||||
// 0x04 File ID
|
||||
public UInt16 fileID;
|
||||
// 0x06 Unknown
|
||||
public UInt16 unknown2;
|
||||
// 0x08 Unknown
|
||||
public UInt32 unknown3;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,286 +0,0 @@
|
||||
/***************************************************************************
|
||||
The Disc Image Chef
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
Filename : MinixFS.cs
|
||||
Version : 1.0
|
||||
Author(s) : Natalia Portillo
|
||||
|
||||
Component : Filesystem plugins
|
||||
|
||||
Revision : $Revision$
|
||||
Last change by : $Author$
|
||||
Date : $Date$
|
||||
|
||||
--[ Description ] ----------------------------------------------------------
|
||||
|
||||
Identifies Minix v1, v2 and v3 filesystems and shows information.
|
||||
|
||||
--[ License ] --------------------------------------------------------------
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
----------------------------------------------------------------------------
|
||||
Copyright (C) 2011-2014 Claunia.com
|
||||
****************************************************************************/
|
||||
//$Id$
|
||||
|
||||
using System;
|
||||
using System.Text;
|
||||
using DiscImageChef;
|
||||
|
||||
// Information from the Linux kernel
|
||||
namespace DiscImageChef.Plugins
|
||||
{
|
||||
class MinixFS : Plugin
|
||||
{
|
||||
const UInt16 MINIX_MAGIC = 0x137F;
|
||||
// Minix v1, 14 char filenames
|
||||
const UInt16 MINIX_MAGIC2 = 0x138F;
|
||||
// Minix v1, 30 char filenames
|
||||
const UInt16 MINIX2_MAGIC = 0x2468;
|
||||
// Minix v2, 14 char filenames
|
||||
const UInt16 MINIX2_MAGIC2 = 0x2478;
|
||||
// Minix v2, 30 char filenames
|
||||
const UInt16 MINIX3_MAGIC = 0x4D5A;
|
||||
// Minix v3, 60 char filenames
|
||||
// Byteswapped
|
||||
const UInt16 MINIX_CIGAM = 0x7F13;
|
||||
// Minix v1, 14 char filenames
|
||||
const UInt16 MINIX_CIGAM2 = 0x8F13;
|
||||
// Minix v1, 30 char filenames
|
||||
const UInt16 MINIX2_CIGAM = 0x6824;
|
||||
// Minix v2, 14 char filenames
|
||||
const UInt16 MINIX2_CIGAM2 = 0x7824;
|
||||
// Minix v2, 30 char filenames
|
||||
const UInt16 MINIX3_CIGAM = 0x5A4D;
|
||||
// Minix v3, 60 char filenames
|
||||
|
||||
public MinixFS(PluginBase Core)
|
||||
{
|
||||
Name = "Minix Filesystem";
|
||||
PluginUUID = new Guid("FE248C3B-B727-4AE5-A39F-79EA9A07D4B3");
|
||||
}
|
||||
|
||||
public override bool Identify(ImagePlugins.ImagePlugin imagePlugin, ulong partitionStart, ulong partitionEnd)
|
||||
{
|
||||
if ((2 + partitionStart) >= imagePlugin.GetSectors())
|
||||
return false;
|
||||
|
||||
UInt16 magic;
|
||||
byte[] minix_sb_sector = imagePlugin.ReadSector(2 + partitionStart);
|
||||
|
||||
magic = BitConverter.ToUInt16(minix_sb_sector, 0x010); // Here should reside magic number on Minix V1 & V2
|
||||
|
||||
if (magic == MINIX_MAGIC || magic == MINIX_MAGIC2 || magic == MINIX2_MAGIC || magic == MINIX2_MAGIC2 ||
|
||||
magic == MINIX_CIGAM || magic == MINIX_CIGAM2 || magic == MINIX2_CIGAM || magic == MINIX2_CIGAM2)
|
||||
return true;
|
||||
magic = BitConverter.ToUInt16(minix_sb_sector, 0x018); // Here should reside magic number on Minix V3
|
||||
|
||||
if (magic == MINIX3_MAGIC || magic == MINIX3_CIGAM)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
public override void GetInformation(ImagePlugins.ImagePlugin imagePlugin, ulong partitionStart, ulong partitionEnd, out string information)
|
||||
{
|
||||
information = "";
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
bool minix3 = false;
|
||||
int filenamesize;
|
||||
string minixVersion;
|
||||
UInt16 magic;
|
||||
byte[] minix_sb_sector = imagePlugin.ReadSector(2 + partitionStart);
|
||||
|
||||
magic = BigEndianBitConverter.ToUInt16(minix_sb_sector, 0x018);
|
||||
|
||||
if (magic == MINIX3_MAGIC || magic == MINIX3_CIGAM)
|
||||
{
|
||||
filenamesize = 60;
|
||||
minixVersion = "Minix V3 filesystem";
|
||||
BigEndianBitConverter.IsLittleEndian = magic != MINIX3_CIGAM;
|
||||
|
||||
minix3 = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
magic = BigEndianBitConverter.ToUInt16(minix_sb_sector, 0x010);
|
||||
|
||||
switch (magic)
|
||||
{
|
||||
case MINIX_MAGIC:
|
||||
filenamesize = 14;
|
||||
minixVersion = "Minix V1 filesystem";
|
||||
BigEndianBitConverter.IsLittleEndian = true;
|
||||
break;
|
||||
case MINIX_MAGIC2:
|
||||
filenamesize = 30;
|
||||
minixVersion = "Minix V1 filesystem";
|
||||
BigEndianBitConverter.IsLittleEndian = true;
|
||||
break;
|
||||
case MINIX2_MAGIC:
|
||||
filenamesize = 14;
|
||||
minixVersion = "Minix V2 filesystem";
|
||||
BigEndianBitConverter.IsLittleEndian = true;
|
||||
break;
|
||||
case MINIX2_MAGIC2:
|
||||
filenamesize = 30;
|
||||
minixVersion = "Minix V2 filesystem";
|
||||
BigEndianBitConverter.IsLittleEndian = true;
|
||||
break;
|
||||
case MINIX_CIGAM:
|
||||
filenamesize = 14;
|
||||
minixVersion = "Minix V1 filesystem";
|
||||
BigEndianBitConverter.IsLittleEndian = false;
|
||||
break;
|
||||
case MINIX_CIGAM2:
|
||||
filenamesize = 30;
|
||||
minixVersion = "Minix V1 filesystem";
|
||||
BigEndianBitConverter.IsLittleEndian = false;
|
||||
break;
|
||||
case MINIX2_CIGAM:
|
||||
filenamesize = 14;
|
||||
minixVersion = "Minix V2 filesystem";
|
||||
BigEndianBitConverter.IsLittleEndian = false;
|
||||
break;
|
||||
case MINIX2_CIGAM2:
|
||||
filenamesize = 30;
|
||||
minixVersion = "Minix V2 filesystem";
|
||||
BigEndianBitConverter.IsLittleEndian = false;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (minix3)
|
||||
{
|
||||
Minix3SuperBlock mnx_sb = new Minix3SuperBlock();
|
||||
|
||||
mnx_sb.s_ninodes = BigEndianBitConverter.ToUInt32(minix_sb_sector, 0x00);
|
||||
mnx_sb.s_pad0 = BigEndianBitConverter.ToUInt16(minix_sb_sector, 0x04);
|
||||
mnx_sb.s_imap_blocks = BigEndianBitConverter.ToUInt16(minix_sb_sector, 0x06);
|
||||
mnx_sb.s_zmap_blocks = BigEndianBitConverter.ToUInt16(minix_sb_sector, 0x08);
|
||||
mnx_sb.s_firstdatazone = BigEndianBitConverter.ToUInt16(minix_sb_sector, 0x0A);
|
||||
mnx_sb.s_log_zone_size = BigEndianBitConverter.ToUInt16(minix_sb_sector, 0x0C);
|
||||
mnx_sb.s_pad1 = BigEndianBitConverter.ToUInt16(minix_sb_sector, 0x0E);
|
||||
mnx_sb.s_max_size = BigEndianBitConverter.ToUInt32(minix_sb_sector, 0x10);
|
||||
mnx_sb.s_zones = BigEndianBitConverter.ToUInt32(minix_sb_sector, 0x14);
|
||||
mnx_sb.s_magic = BigEndianBitConverter.ToUInt16(minix_sb_sector, 0x18);
|
||||
mnx_sb.s_pad2 = BigEndianBitConverter.ToUInt16(minix_sb_sector, 0x1A);
|
||||
mnx_sb.s_blocksize = BigEndianBitConverter.ToUInt16(minix_sb_sector, 0x1C);
|
||||
mnx_sb.s_disk_version = minix_sb_sector[0x1E];
|
||||
|
||||
sb.AppendLine(minixVersion);
|
||||
sb.AppendFormat("{0} chars in filename", filenamesize).AppendLine();
|
||||
sb.AppendFormat("{0} zones on volume ({1} bytes)", mnx_sb.s_zones, mnx_sb.s_zones * mnx_sb.s_blocksize).AppendLine();
|
||||
sb.AppendFormat("{0} bytes/block", mnx_sb.s_blocksize).AppendLine();
|
||||
sb.AppendFormat("{0} inodes on volume", mnx_sb.s_ninodes).AppendLine();
|
||||
sb.AppendFormat("{0} blocks on inode map ({1} bytes)", mnx_sb.s_imap_blocks, mnx_sb.s_imap_blocks * mnx_sb.s_blocksize).AppendLine();
|
||||
sb.AppendFormat("{0} blocks on zone map ({1} bytes)", mnx_sb.s_zmap_blocks, mnx_sb.s_zmap_blocks * mnx_sb.s_blocksize).AppendLine();
|
||||
sb.AppendFormat("First data zone: {0}", mnx_sb.s_firstdatazone).AppendLine();
|
||||
//sb.AppendFormat("log2 of blocks/zone: {0}", mnx_sb.s_log_zone_size).AppendLine(); // Apparently 0
|
||||
sb.AppendFormat("{0} bytes maximum per file", mnx_sb.s_max_size).AppendLine();
|
||||
sb.AppendFormat("On-disk filesystem version: {0}", mnx_sb.s_disk_version).AppendLine();
|
||||
}
|
||||
else
|
||||
{
|
||||
MinixSuperBlock mnx_sb = new MinixSuperBlock();
|
||||
|
||||
mnx_sb.s_ninodes = BigEndianBitConverter.ToUInt16(minix_sb_sector, 0x00);
|
||||
mnx_sb.s_nzones = BigEndianBitConverter.ToUInt16(minix_sb_sector, 0x02);
|
||||
mnx_sb.s_imap_blocks = BigEndianBitConverter.ToUInt16(minix_sb_sector, 0x04);
|
||||
mnx_sb.s_zmap_blocks = BigEndianBitConverter.ToUInt16(minix_sb_sector, 0x06);
|
||||
mnx_sb.s_firstdatazone = BigEndianBitConverter.ToUInt16(minix_sb_sector, 0x08);
|
||||
mnx_sb.s_log_zone_size = BigEndianBitConverter.ToUInt16(minix_sb_sector, 0x0A);
|
||||
mnx_sb.s_max_size = BigEndianBitConverter.ToUInt32(minix_sb_sector, 0x0C);
|
||||
mnx_sb.s_magic = BigEndianBitConverter.ToUInt16(minix_sb_sector, 0x10);
|
||||
mnx_sb.s_state = BigEndianBitConverter.ToUInt16(minix_sb_sector, 0x12);
|
||||
mnx_sb.s_zones = BigEndianBitConverter.ToUInt32(minix_sb_sector, 0x14);
|
||||
|
||||
sb.AppendLine(minixVersion);
|
||||
sb.AppendFormat("{0} chars in filename", filenamesize).AppendLine();
|
||||
if (mnx_sb.s_zones > 0) // On V2
|
||||
sb.AppendFormat("{0} zones on volume ({1} bytes)", mnx_sb.s_zones, mnx_sb.s_zones * 1024).AppendLine();
|
||||
else
|
||||
sb.AppendFormat("{0} zones on volume ({1} bytes)", mnx_sb.s_nzones, mnx_sb.s_nzones * 1024).AppendLine();
|
||||
sb.AppendFormat("{0} inodes on volume", mnx_sb.s_ninodes).AppendLine();
|
||||
sb.AppendFormat("{0} blocks on inode map ({1} bytes)", mnx_sb.s_imap_blocks, mnx_sb.s_imap_blocks * 1024).AppendLine();
|
||||
sb.AppendFormat("{0} blocks on zone map ({1} bytes)", mnx_sb.s_zmap_blocks, mnx_sb.s_zmap_blocks * 1024).AppendLine();
|
||||
sb.AppendFormat("First data zone: {0}", mnx_sb.s_firstdatazone).AppendLine();
|
||||
//sb.AppendFormat("log2 of blocks/zone: {0}", mnx_sb.s_log_zone_size).AppendLine(); // Apparently 0
|
||||
sb.AppendFormat("{0} bytes maximum per file", mnx_sb.s_max_size).AppendLine();
|
||||
sb.AppendFormat("Filesystem state: {0:X4}", mnx_sb.s_state).AppendLine();
|
||||
}
|
||||
information = sb.ToString();
|
||||
}
|
||||
|
||||
public struct MinixSuperBlock
|
||||
{
|
||||
public UInt16 s_ninodes;
|
||||
// 0x00, inodes on volume
|
||||
public UInt16 s_nzones;
|
||||
// 0x02, zones on volume
|
||||
public UInt16 s_imap_blocks;
|
||||
// 0x04, blocks on inode map
|
||||
public UInt16 s_zmap_blocks;
|
||||
// 0x06, blocks on zone map
|
||||
public UInt16 s_firstdatazone;
|
||||
// 0x08, first data zone
|
||||
public UInt16 s_log_zone_size;
|
||||
// 0x0A, log2 of blocks/zone
|
||||
public UInt32 s_max_size;
|
||||
// 0x0C, max file size
|
||||
public UInt16 s_magic;
|
||||
// 0x10, magic
|
||||
public UInt16 s_state;
|
||||
// 0x12, filesystem state
|
||||
public UInt32 s_zones;
|
||||
// 0x14, number of zones
|
||||
}
|
||||
|
||||
public struct Minix3SuperBlock
|
||||
{
|
||||
public UInt32 s_ninodes;
|
||||
// 0x00, inodes on volume
|
||||
public UInt16 s_pad0;
|
||||
// 0x04, padding
|
||||
public UInt16 s_imap_blocks;
|
||||
// 0x06, blocks on inode map
|
||||
public UInt16 s_zmap_blocks;
|
||||
// 0x08, blocks on zone map
|
||||
public UInt16 s_firstdatazone;
|
||||
// 0x0A, first data zone
|
||||
public UInt16 s_log_zone_size;
|
||||
// 0x0C, log2 of blocks/zone
|
||||
public UInt16 s_pad1;
|
||||
// 0x0E, padding
|
||||
public UInt32 s_max_size;
|
||||
// 0x10, max file size
|
||||
public UInt32 s_zones;
|
||||
// 0x14, number of zones
|
||||
public UInt16 s_magic;
|
||||
// 0x18, magic
|
||||
public UInt16 s_pad2;
|
||||
// 0x1A, padding
|
||||
public UInt16 s_blocksize;
|
||||
// 0x1C, bytes in a block
|
||||
public byte s_disk_version;
|
||||
// 0x1E, on-disk structures version
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,241 +0,0 @@
|
||||
/***************************************************************************
|
||||
The Disc Image Chef
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
Filename : NTFS.cs
|
||||
Version : 1.0
|
||||
Author(s) : Natalia Portillo
|
||||
|
||||
Component : Filesystem plugins
|
||||
|
||||
Revision : $Revision$
|
||||
Last change by : $Author$
|
||||
Date : $Date$
|
||||
|
||||
--[ Description ] ----------------------------------------------------------
|
||||
|
||||
Identifies Windows NT FileSystem (aka NTFS) and shows information.
|
||||
|
||||
--[ License ] --------------------------------------------------------------
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
----------------------------------------------------------------------------
|
||||
Copyright (C) 2011-2014 Claunia.com
|
||||
****************************************************************************/
|
||||
//$Id$
|
||||
|
||||
using System;
|
||||
using System.Text;
|
||||
using DiscImageChef;
|
||||
|
||||
// Information from Inside Windows NT
|
||||
namespace DiscImageChef.Plugins
|
||||
{
|
||||
class NTFS : Plugin
|
||||
{
|
||||
public NTFS(PluginBase Core)
|
||||
{
|
||||
Name = "New Technology File System (NTFS)";
|
||||
PluginUUID = new Guid("33513B2C-1e6d-4d21-a660-0bbc789c3871");
|
||||
}
|
||||
|
||||
public override bool Identify(ImagePlugins.ImagePlugin imagePlugin, ulong partitionStart, ulong partitionEnd)
|
||||
{
|
||||
if ((2 + partitionStart) >= imagePlugin.GetSectors())
|
||||
return false;
|
||||
|
||||
byte[] eigth_bytes = new byte[8];
|
||||
byte signature1, fats_no;
|
||||
UInt16 spfat, signature2;
|
||||
string oem_name;
|
||||
|
||||
byte[] ntfs_bpb = imagePlugin.ReadSector(0 + partitionStart);
|
||||
|
||||
Array.Copy(ntfs_bpb, 0x003, eigth_bytes, 0, 8);
|
||||
oem_name = StringHandlers.CToString(eigth_bytes);
|
||||
|
||||
if (oem_name != "NTFS ")
|
||||
return false;
|
||||
|
||||
fats_no = ntfs_bpb[0x010];
|
||||
|
||||
if (fats_no != 0)
|
||||
return false;
|
||||
|
||||
spfat = BitConverter.ToUInt16(ntfs_bpb, 0x016);
|
||||
|
||||
if (spfat != 0)
|
||||
return false;
|
||||
|
||||
signature1 = ntfs_bpb[0x026];
|
||||
|
||||
if (signature1 != 0x80)
|
||||
return false;
|
||||
|
||||
signature2 = BitConverter.ToUInt16(ntfs_bpb, 0x1FE);
|
||||
|
||||
return signature2 == 0xAA55;
|
||||
|
||||
}
|
||||
|
||||
public override void GetInformation(ImagePlugins.ImagePlugin imagePlugin, ulong partitionStart, ulong partitionEnd, out string information)
|
||||
{
|
||||
information = "";
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
byte[] ntfs_bpb = imagePlugin.ReadSector(0 + partitionStart);
|
||||
|
||||
NTFS_BootBlock ntfs_bb = new NTFS_BootBlock();
|
||||
|
||||
byte[] oem_name = new byte[8];
|
||||
|
||||
ntfs_bb.jmp1 = ntfs_bpb[0x000];
|
||||
ntfs_bb.jmp2 = BitConverter.ToUInt16(ntfs_bpb, 0x001);
|
||||
Array.Copy(ntfs_bpb, 0x003, oem_name, 0, 8);
|
||||
ntfs_bb.OEMName = StringHandlers.CToString(oem_name);
|
||||
ntfs_bb.bps = BitConverter.ToUInt16(ntfs_bpb, 0x00B);
|
||||
ntfs_bb.spc = ntfs_bpb[0x00D];
|
||||
ntfs_bb.rsectors = BitConverter.ToUInt16(ntfs_bpb, 0x00E);
|
||||
ntfs_bb.fats_no = ntfs_bpb[0x010];
|
||||
ntfs_bb.root_ent = BitConverter.ToUInt16(ntfs_bpb, 0x011);
|
||||
ntfs_bb.sml_sectors = BitConverter.ToUInt16(ntfs_bpb, 0x013);
|
||||
ntfs_bb.media = ntfs_bpb[0x015];
|
||||
ntfs_bb.spfat = BitConverter.ToUInt16(ntfs_bpb, 0x016);
|
||||
ntfs_bb.sptrk = BitConverter.ToUInt16(ntfs_bpb, 0x018);
|
||||
ntfs_bb.heads = BitConverter.ToUInt16(ntfs_bpb, 0x01A);
|
||||
ntfs_bb.hsectors = BitConverter.ToUInt32(ntfs_bpb, 0x01C);
|
||||
ntfs_bb.big_sectors = BitConverter.ToUInt32(ntfs_bpb, 0x020);
|
||||
ntfs_bb.drive_no = ntfs_bpb[0x024];
|
||||
ntfs_bb.nt_flags = ntfs_bpb[0x025];
|
||||
ntfs_bb.signature1 = ntfs_bpb[0x026];
|
||||
ntfs_bb.dummy = ntfs_bpb[0x027];
|
||||
ntfs_bb.sectors = BitConverter.ToInt64(ntfs_bpb, 0x028);
|
||||
ntfs_bb.mft_lsn = BitConverter.ToInt64(ntfs_bpb, 0x030);
|
||||
ntfs_bb.mftmirror_lsn = BitConverter.ToInt64(ntfs_bpb, 0x038);
|
||||
ntfs_bb.mft_rc_clusters = (sbyte)ntfs_bpb[0x040];
|
||||
ntfs_bb.dummy2 = ntfs_bpb[0x041];
|
||||
ntfs_bb.dummy3 = BitConverter.ToUInt16(ntfs_bpb, 0x042);
|
||||
ntfs_bb.index_blk_cts = (sbyte)ntfs_bpb[0x044];
|
||||
ntfs_bb.dummy4 = ntfs_bpb[0x045];
|
||||
ntfs_bb.dummy5 = BitConverter.ToUInt16(ntfs_bpb, 0x046);
|
||||
ntfs_bb.serial_no = BitConverter.ToUInt64(ntfs_bpb, 0x048);
|
||||
ntfs_bb.signature2 = BitConverter.ToUInt16(ntfs_bpb, 0x1FE);
|
||||
|
||||
sb.AppendFormat("{0} bytes per sector", ntfs_bb.bps).AppendLine();
|
||||
sb.AppendFormat("{0} sectors per cluster ({1} bytes)", ntfs_bb.spc, ntfs_bb.spc * ntfs_bb.bps).AppendLine();
|
||||
// sb.AppendFormat("{0} reserved sectors", ntfs_bb.rsectors).AppendLine();
|
||||
// sb.AppendFormat("{0} FATs", ntfs_bb.fats_no).AppendLine();
|
||||
// sb.AppendFormat("{0} entries in the root folder", ntfs_bb.root_ent).AppendLine();
|
||||
// sb.AppendFormat("{0} sectors on volume (small)", ntfs_bb.sml_sectors).AppendLine();
|
||||
sb.AppendFormat("Media descriptor: 0x{0:X2}", ntfs_bb.media).AppendLine();
|
||||
// sb.AppendFormat("{0} sectors per FAT", ntfs_bb.spfat).AppendLine();
|
||||
sb.AppendFormat("{0} sectors per track", ntfs_bb.sptrk).AppendLine();
|
||||
sb.AppendFormat("{0} heads", ntfs_bb.heads).AppendLine();
|
||||
sb.AppendFormat("{0} hidden sectors before filesystem", ntfs_bb.hsectors).AppendLine();
|
||||
// sb.AppendFormat("{0} sectors on volume (big)", ntfs_bb.big_sectors).AppendLine();
|
||||
sb.AppendFormat("BIOS drive number: 0x{0:X2}", ntfs_bb.drive_no).AppendLine();
|
||||
// sb.AppendFormat("NT flags: 0x{0:X2}", ntfs_bb.nt_flags).AppendLine();
|
||||
// sb.AppendFormat("Signature 1: 0x{0:X2}", ntfs_bb.signature1).AppendLine();
|
||||
sb.AppendFormat("{0} sectors on volume ({1} bytes)", ntfs_bb.sectors, ntfs_bb.sectors * ntfs_bb.bps).AppendLine();
|
||||
sb.AppendFormat("Sectors where $MFT starts: {0}", ntfs_bb.mft_lsn).AppendLine();
|
||||
sb.AppendFormat("Sectors where $MFTMirr starts: {0}", ntfs_bb.mftmirror_lsn).AppendLine();
|
||||
|
||||
if (ntfs_bb.mft_rc_clusters > 0)
|
||||
sb.AppendFormat("{0} clusters per MFT record ({1} bytes)", ntfs_bb.mft_rc_clusters,
|
||||
ntfs_bb.mft_rc_clusters * ntfs_bb.bps * ntfs_bb.spc).AppendLine();
|
||||
else
|
||||
sb.AppendFormat("{0} bytes per MFT record", 1 << -ntfs_bb.mft_rc_clusters).AppendLine();
|
||||
if (ntfs_bb.index_blk_cts > 0)
|
||||
sb.AppendFormat("{0} clusters per Index block ({1} bytes)", ntfs_bb.index_blk_cts,
|
||||
ntfs_bb.index_blk_cts * ntfs_bb.bps * ntfs_bb.spc).AppendLine();
|
||||
else
|
||||
sb.AppendFormat("{0} bytes per Index block", 1 << -ntfs_bb.index_blk_cts).AppendLine();
|
||||
|
||||
sb.AppendFormat("Volume serial number: {0:X16}", ntfs_bb.serial_no).AppendLine();
|
||||
// sb.AppendFormat("Signature 2: 0x{0:X4}", ntfs_bb.signature2).AppendLine();
|
||||
|
||||
information = sb.ToString();
|
||||
}
|
||||
|
||||
struct NTFS_BootBlock // Sector 0
|
||||
{
|
||||
// BIOS Parameter Block
|
||||
public byte jmp1;
|
||||
// 0x000, Jump to boot code
|
||||
public UInt16 jmp2;
|
||||
// 0x001, ...;
|
||||
public string OEMName;
|
||||
// 0x003, OEM Name, 8 bytes, space-padded, must be "NTFS "
|
||||
public UInt16 bps;
|
||||
// 0x00B, Bytes per sector
|
||||
public byte spc;
|
||||
// 0x00D, Sectors per cluster
|
||||
public UInt16 rsectors;
|
||||
// 0x00E, Reserved sectors, seems 0
|
||||
public byte fats_no;
|
||||
// 0x010, Number of FATs... obviously, 0
|
||||
public UInt16 root_ent;
|
||||
// 0x011, Number of entries on root directory... 0
|
||||
public UInt16 sml_sectors;
|
||||
// 0x013, Sectors in volume... 0
|
||||
public byte media;
|
||||
// 0x015, Media descriptor
|
||||
public UInt16 spfat;
|
||||
// 0x016, Sectors per FAT... 0
|
||||
public UInt16 sptrk;
|
||||
// 0x018, Sectors per track, required to boot
|
||||
public UInt16 heads;
|
||||
// 0x01A, Heads... required to boot
|
||||
public UInt32 hsectors;
|
||||
// 0x01C, Hidden sectors before BPB
|
||||
public UInt32 big_sectors;
|
||||
// 0x020, Sectors in volume if > 65535... 0
|
||||
public byte drive_no;
|
||||
// 0x024, Drive number
|
||||
public byte nt_flags;
|
||||
// 0x025, 0
|
||||
public byte signature1;
|
||||
// 0x026, EPB signature, 0x80
|
||||
public byte dummy;
|
||||
// 0x027, Alignment
|
||||
// End of BIOS Parameter Block
|
||||
// NTFS real superblock
|
||||
public Int64 sectors;
|
||||
// 0x028, Sectors on volume
|
||||
public Int64 mft_lsn;
|
||||
// 0x030, LSN of $MFT
|
||||
public Int64 mftmirror_lsn;
|
||||
// 0x038, LSN of $MFTMirror
|
||||
public sbyte mft_rc_clusters;
|
||||
// 0x040, Clusters per MFT record
|
||||
public byte dummy2;
|
||||
// 0x041, Alignment
|
||||
public UInt16 dummy3;
|
||||
// 0x042, Alignment
|
||||
public sbyte index_blk_cts;
|
||||
// 0x044, Clusters per index block
|
||||
public byte dummy4;
|
||||
// 0x045, Alignment
|
||||
public UInt16 dummy5;
|
||||
// 0x046, Alignment
|
||||
public UInt64 serial_no;
|
||||
// 0x048, Volume serial number
|
||||
// End of NTFS superblock, followed by 430 bytes of boot code
|
||||
public UInt16 signature2;
|
||||
// 0x1FE, 0xAA55
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,359 +0,0 @@
|
||||
/***************************************************************************
|
||||
The Disc Image Chef
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
Filename : ODS.cs
|
||||
Version : 1.0
|
||||
Author(s) : Natalia Portillo
|
||||
|
||||
Component : Filesystem plugins
|
||||
|
||||
Revision : $Revision$
|
||||
Last change by : $Author$
|
||||
Date : $Date$
|
||||
|
||||
--[ Description ] ----------------------------------------------------------
|
||||
|
||||
Identifies VMS filesystems and shows information.
|
||||
|
||||
--[ License ] --------------------------------------------------------------
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
----------------------------------------------------------------------------
|
||||
Copyright (C) 2011-2014 Claunia.com
|
||||
****************************************************************************/
|
||||
//$Id$
|
||||
using System;
|
||||
using System.Text;
|
||||
using DiscImageChef;
|
||||
|
||||
// Information from VMS File System Internals by Kirby McCoy
|
||||
// ISBN: 1-55558-056-4
|
||||
// With some hints from http://www.decuslib.com/DECUS/vmslt97b/gnusoftware/gccaxp/7_1/vms/hm2def.h
|
||||
// Expects the home block to be always in sector #1 (does not check deltas)
|
||||
// Assumes a sector size of 512 bytes (VMS does on HDDs and optical drives, dunno about M.O.)
|
||||
// Book only describes ODS-2. Need to test ODS-1 and ODS-5
|
||||
// There is an ODS with signature "DECFILES11A", yet to be seen
|
||||
// Time is a 64 bit unsigned integer, tenths of microseconds since 1858/11/17 00:00:00.
|
||||
// TODO: Implement checksum
|
||||
namespace DiscImageChef.Plugins
|
||||
{
|
||||
class ODS : Plugin
|
||||
{
|
||||
public ODS(PluginBase Core)
|
||||
{
|
||||
Name = "Files-11 On-Disk Structure";
|
||||
PluginUUID = new Guid("de20633c-8021-4384-aeb0-83b0df14491f");
|
||||
}
|
||||
|
||||
public override bool Identify(ImagePlugins.ImagePlugin imagePlugin, ulong partitionStart, ulong partitionEnd)
|
||||
{
|
||||
if ((2 + partitionStart) >= imagePlugin.GetSectors())
|
||||
return false;
|
||||
|
||||
if (imagePlugin.GetSectorSize() < 512)
|
||||
return false;
|
||||
|
||||
byte[] magic_b = new byte[12];
|
||||
string magic;
|
||||
byte[] hb_sector = imagePlugin.ReadSector(1 + partitionStart);
|
||||
|
||||
Array.Copy(hb_sector, 0x1F0, magic_b, 0, 12);
|
||||
magic = Encoding.ASCII.GetString(magic_b);
|
||||
|
||||
return magic == "DECFILE11A " || magic == "DECFILE11B ";
|
||||
}
|
||||
|
||||
public override void GetInformation(ImagePlugins.ImagePlugin imagePlugin, ulong partitionStart, ulong partitionEnd, out string information)
|
||||
{
|
||||
information = "";
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
ODSHomeBlock homeblock = new ODSHomeBlock();
|
||||
byte[] temp_string = new byte[12];
|
||||
homeblock.min_class = new byte[20];
|
||||
homeblock.max_class = new byte[20];
|
||||
|
||||
byte[] hb_sector = imagePlugin.ReadSector(1 + partitionStart);
|
||||
|
||||
homeblock.homelbn = BitConverter.ToUInt32(hb_sector, 0x000);
|
||||
homeblock.alhomelbn = BitConverter.ToUInt32(hb_sector, 0x004);
|
||||
homeblock.altidxlbn = BitConverter.ToUInt32(hb_sector, 0x008);
|
||||
homeblock.struclev = BitConverter.ToUInt16(hb_sector, 0x00C);
|
||||
homeblock.cluster = BitConverter.ToUInt16(hb_sector, 0x00E);
|
||||
homeblock.homevbn = BitConverter.ToUInt16(hb_sector, 0x010);
|
||||
homeblock.alhomevbn = BitConverter.ToUInt16(hb_sector, 0x012);
|
||||
homeblock.altidxvbn = BitConverter.ToUInt16(hb_sector, 0x014);
|
||||
homeblock.ibmapvbn = BitConverter.ToUInt16(hb_sector, 0x016);
|
||||
homeblock.ibmaplbn = BitConverter.ToUInt32(hb_sector, 0x018);
|
||||
homeblock.maxfiles = BitConverter.ToUInt32(hb_sector, 0x01C);
|
||||
homeblock.ibmapsize = BitConverter.ToUInt16(hb_sector, 0x020);
|
||||
homeblock.resfiles = BitConverter.ToUInt16(hb_sector, 0x022);
|
||||
homeblock.devtype = BitConverter.ToUInt16(hb_sector, 0x024);
|
||||
homeblock.rvn = BitConverter.ToUInt16(hb_sector, 0x026);
|
||||
homeblock.setcount = BitConverter.ToUInt16(hb_sector, 0x028);
|
||||
homeblock.volchar = BitConverter.ToUInt16(hb_sector, 0x02A);
|
||||
homeblock.volowner = BitConverter.ToUInt32(hb_sector, 0x02C);
|
||||
homeblock.sec_mask = BitConverter.ToUInt32(hb_sector, 0x030);
|
||||
homeblock.protect = BitConverter.ToUInt16(hb_sector, 0x034);
|
||||
homeblock.fileprot = BitConverter.ToUInt16(hb_sector, 0x036);
|
||||
homeblock.recprot = BitConverter.ToUInt16(hb_sector, 0x038);
|
||||
homeblock.checksum1 = BitConverter.ToUInt16(hb_sector, 0x03A);
|
||||
homeblock.credate = BitConverter.ToUInt64(hb_sector, 0x03C);
|
||||
homeblock.window = hb_sector[0x044];
|
||||
homeblock.lru_lim = hb_sector[0x045];
|
||||
homeblock.extend = BitConverter.ToUInt16(hb_sector, 0x046);
|
||||
homeblock.retainmin = BitConverter.ToUInt64(hb_sector, 0x048);
|
||||
homeblock.retainmax = BitConverter.ToUInt64(hb_sector, 0x050);
|
||||
homeblock.revdate = BitConverter.ToUInt64(hb_sector, 0x058);
|
||||
Array.Copy(hb_sector, 0x060, homeblock.min_class, 0, 20);
|
||||
Array.Copy(hb_sector, 0x074, homeblock.max_class, 0, 20);
|
||||
homeblock.filetab_fid1 = BitConverter.ToUInt16(hb_sector, 0x088);
|
||||
homeblock.filetab_fid2 = BitConverter.ToUInt16(hb_sector, 0x08A);
|
||||
homeblock.filetab_fid3 = BitConverter.ToUInt16(hb_sector, 0x08C);
|
||||
homeblock.lowstruclev = BitConverter.ToUInt16(hb_sector, 0x08E);
|
||||
homeblock.highstruclev = BitConverter.ToUInt16(hb_sector, 0x090);
|
||||
homeblock.copydate = BitConverter.ToUInt64(hb_sector, 0x092);
|
||||
homeblock.serialnum = BitConverter.ToUInt32(hb_sector, 0x1C8);
|
||||
Array.Copy(hb_sector, 0x1CC, temp_string, 0, 12);
|
||||
homeblock.strucname = StringHandlers.CToString(temp_string);
|
||||
Array.Copy(hb_sector, 0x1D8, temp_string, 0, 12);
|
||||
homeblock.volname = StringHandlers.CToString(temp_string);
|
||||
Array.Copy(hb_sector, 0x1E4, temp_string, 0, 12);
|
||||
homeblock.ownername = StringHandlers.CToString(temp_string);
|
||||
Array.Copy(hb_sector, 0x1F0, temp_string, 0, 12);
|
||||
homeblock.format = StringHandlers.CToString(temp_string);
|
||||
homeblock.checksum2 = BitConverter.ToUInt16(hb_sector, 0x1FE);
|
||||
|
||||
if ((homeblock.struclev & 0xFF00) != 0x0200 || (homeblock.struclev & 0xFF) != 1 || homeblock.format != "DECFILE11B ")
|
||||
sb.AppendLine("The following information may be incorrect for this volume.");
|
||||
if (homeblock.resfiles < 5 || homeblock.devtype != 0)
|
||||
sb.AppendLine("This volume may be corrupted.");
|
||||
|
||||
sb.AppendFormat("Volume format is {0}", homeblock.format).AppendLine();
|
||||
sb.AppendFormat("Volume is Level {0} revision {1}", (homeblock.struclev & 0xFF00) >> 8, homeblock.struclev & 0xFF).AppendLine();
|
||||
sb.AppendFormat("Lowest structure in the volume is Level {0}, revision {1}", (homeblock.lowstruclev & 0xFF00) >> 8, homeblock.lowstruclev & 0xFF).AppendLine();
|
||||
sb.AppendFormat("Highest structure in the volume is Level {0}, revision {1}", (homeblock.highstruclev & 0xFF00) >> 8, homeblock.highstruclev & 0xFF).AppendLine();
|
||||
sb.AppendFormat("{0} sectors per cluster ({1} bytes)", homeblock.cluster, homeblock.cluster * 512).AppendLine();
|
||||
sb.AppendFormat("This home block is on sector {0} (cluster {1})", homeblock.homelbn, homeblock.homevbn).AppendLine();
|
||||
sb.AppendFormat("Secondary home block is on sector {0} (cluster {1})", homeblock.alhomelbn, homeblock.alhomevbn).AppendLine();
|
||||
sb.AppendFormat("Volume bitmap starts in sector {0} (cluster {1})", homeblock.ibmaplbn, homeblock.ibmapvbn).AppendLine();
|
||||
sb.AppendFormat("Volume bitmap runs for {0} sectors ({1} bytes)", homeblock.ibmapsize, homeblock.ibmapsize * 512).AppendLine();
|
||||
sb.AppendFormat("Backup INDEXF.SYS;1 is in sector {0} (cluster {1})", homeblock.altidxlbn, homeblock.altidxvbn).AppendLine();
|
||||
sb.AppendFormat("{0} maximum files on the volume", homeblock.maxfiles).AppendLine();
|
||||
sb.AppendFormat("{0} reserved files", homeblock.resfiles).AppendLine();
|
||||
if (homeblock.rvn > 0 && homeblock.setcount > 0 && homeblock.strucname != " ")
|
||||
sb.AppendFormat("Volume is {0} of {1} in set \"{2}\".", homeblock.rvn, homeblock.setcount, homeblock.strucname).AppendLine();
|
||||
sb.AppendFormat("Volume owner is \"{0}\" (ID 0x{1:X8})", homeblock.ownername, homeblock.volowner).AppendLine();
|
||||
sb.AppendFormat("Volume label: \"{0}\"", homeblock.volname).AppendLine();
|
||||
sb.AppendFormat("Drive serial number: 0x{0:X8}", homeblock.serialnum).AppendLine();
|
||||
sb.AppendFormat("Volume was created on {0}", DateHandlers.VMSToDateTime(homeblock.credate)).AppendLine();
|
||||
if (homeblock.revdate > 0)
|
||||
sb.AppendFormat("Volume was last modified on {0}", DateHandlers.VMSToDateTime(homeblock.revdate)).AppendLine();
|
||||
if (homeblock.copydate > 0)
|
||||
sb.AppendFormat("Volume copied on {0}", DateHandlers.VMSToDateTime(homeblock.copydate)).AppendLine();
|
||||
sb.AppendFormat("Checksums: 0x{0:X4} and 0x{1:X4}", homeblock.checksum1, homeblock.checksum2).AppendLine();
|
||||
sb.AppendLine("Flags:");
|
||||
sb.AppendFormat("Window: {0}", homeblock.window).AppendLine();
|
||||
sb.AppendFormat("Cached directores: {0}", homeblock.lru_lim).AppendLine();
|
||||
sb.AppendFormat("Default allocation: {0} blocks", homeblock.extend).AppendLine();
|
||||
if ((homeblock.volchar & 0x01) == 0x01)
|
||||
sb.AppendLine("Readings should be verified");
|
||||
if ((homeblock.volchar & 0x02) == 0x02)
|
||||
sb.AppendLine("Writings should be verified");
|
||||
if ((homeblock.volchar & 0x04) == 0x04)
|
||||
sb.AppendLine("Files should be erased or overwritten when deleted");
|
||||
if ((homeblock.volchar & 0x08) == 0x08)
|
||||
sb.AppendLine("Highwater mark is to be disabled");
|
||||
if ((homeblock.volchar & 0x10) == 0x10)
|
||||
sb.AppendLine("Classification checks are enabled");
|
||||
sb.AppendLine("Volume permissions (r = read, w = write, c = create, d = delete)");
|
||||
sb.AppendLine("System, owner, group, world");
|
||||
// System
|
||||
if ((homeblock.protect & 0x1000) == 0x1000)
|
||||
sb.Append("-");
|
||||
else
|
||||
sb.Append("r");
|
||||
if ((homeblock.protect & 0x2000) == 0x2000)
|
||||
sb.Append("-");
|
||||
else
|
||||
sb.Append("w");
|
||||
if ((homeblock.protect & 0x4000) == 0x4000)
|
||||
sb.Append("-");
|
||||
else
|
||||
sb.Append("c");
|
||||
if ((homeblock.protect & 0x8000) == 0x8000)
|
||||
sb.Append("-");
|
||||
else
|
||||
sb.Append("d");
|
||||
// Owner
|
||||
if ((homeblock.protect & 0x100) == 0x100)
|
||||
sb.Append("-");
|
||||
else
|
||||
sb.Append("r");
|
||||
if ((homeblock.protect & 0x200) == 0x200)
|
||||
sb.Append("-");
|
||||
else
|
||||
sb.Append("w");
|
||||
if ((homeblock.protect & 0x400) == 0x400)
|
||||
sb.Append("-");
|
||||
else
|
||||
sb.Append("c");
|
||||
if ((homeblock.protect & 0x800) == 0x800)
|
||||
sb.Append("-");
|
||||
else
|
||||
sb.Append("d");
|
||||
// Group
|
||||
if ((homeblock.protect & 0x10) == 0x10)
|
||||
sb.Append("-");
|
||||
else
|
||||
sb.Append("r");
|
||||
if ((homeblock.protect & 0x20) == 0x20)
|
||||
sb.Append("-");
|
||||
else
|
||||
sb.Append("w");
|
||||
if ((homeblock.protect & 0x40) == 0x40)
|
||||
sb.Append("-");
|
||||
else
|
||||
sb.Append("c");
|
||||
if ((homeblock.protect & 0x80) == 0x80)
|
||||
sb.Append("-");
|
||||
else
|
||||
sb.Append("d");
|
||||
// World (other)
|
||||
if ((homeblock.protect & 0x1) == 0x1)
|
||||
sb.Append("-");
|
||||
else
|
||||
sb.Append("r");
|
||||
if ((homeblock.protect & 0x2) == 0x2)
|
||||
sb.Append("-");
|
||||
else
|
||||
sb.Append("w");
|
||||
if ((homeblock.protect & 0x4) == 0x4)
|
||||
sb.Append("-");
|
||||
else
|
||||
sb.Append("c");
|
||||
if ((homeblock.protect & 0x8) == 0x8)
|
||||
sb.Append("-");
|
||||
else
|
||||
sb.Append("d");
|
||||
|
||||
sb.AppendLine();
|
||||
|
||||
sb.AppendLine("Unknown structures:");
|
||||
sb.AppendFormat("Security mask: 0x{0:X8}", homeblock.sec_mask).AppendLine();
|
||||
sb.AppendFormat("File protection: 0x{0:X4}", homeblock.fileprot).AppendLine();
|
||||
sb.AppendFormat("Record protection: 0x{0:X4}", homeblock.recprot).AppendLine();
|
||||
|
||||
information = sb.ToString();
|
||||
}
|
||||
|
||||
struct ODSHomeBlock
|
||||
{
|
||||
public UInt32 homelbn;
|
||||
// 0x000, LBN of THIS home block
|
||||
public UInt32 alhomelbn;
|
||||
// 0x004, LBN of the secondary home block
|
||||
public UInt32 altidxlbn;
|
||||
// 0x008, LBN of backup INDEXF.SYS;1
|
||||
public UInt16 struclev;
|
||||
// 0x00C, High byte contains filesystem version (1, 2 or 5), low byte contains revision (1)
|
||||
public UInt16 cluster;
|
||||
// 0x00E, Number of blocks each bit of the volume bitmap represents
|
||||
public UInt16 homevbn;
|
||||
// 0x010, VBN of THIS home block
|
||||
public UInt16 alhomevbn;
|
||||
// 0x012, VBN of the secondary home block
|
||||
public UInt16 altidxvbn;
|
||||
// 0x014, VBN of backup INDEXF.SYS;1
|
||||
public UInt16 ibmapvbn;
|
||||
// 0x016, VBN of the bitmap
|
||||
public UInt32 ibmaplbn;
|
||||
// 0x018, LBN of the bitmap
|
||||
public UInt32 maxfiles;
|
||||
// 0x01C, Max files on volume
|
||||
public UInt16 ibmapsize;
|
||||
// 0x020, Bitmap size in sectors
|
||||
public UInt16 resfiles;
|
||||
// 0x022, Reserved files, 5 at minimum
|
||||
public UInt16 devtype;
|
||||
// 0x024, Device type, ODS-2 defines it as always 0
|
||||
public UInt16 rvn;
|
||||
// 0x026, Relative volume number (number of the volume in a set)
|
||||
public UInt16 setcount;
|
||||
// 0x028, Total number of volumes in the set this volume is
|
||||
public UInt16 volchar;
|
||||
// 0x02A, Flags
|
||||
public UInt32 volowner;
|
||||
// 0x02C, User ID of the volume owner
|
||||
public UInt32 sec_mask;
|
||||
// 0x030, Security mask (??)
|
||||
public UInt16 protect;
|
||||
// 0x034, Volume permissions (system, owner, group and other)
|
||||
public UInt16 fileprot;
|
||||
// 0x036, Default file protection, unsupported in ODS-2
|
||||
public UInt16 recprot;
|
||||
// 0x038, Default file record protection
|
||||
public UInt16 checksum1;
|
||||
// 0x03A, Checksum of all preceding entries
|
||||
public UInt64 credate;
|
||||
// 0x03C, Creation date
|
||||
public byte window;
|
||||
// 0x044, Window size (pointers for the window)
|
||||
public byte lru_lim;
|
||||
// 0x045, Directories to be stored in cache
|
||||
public UInt16 extend;
|
||||
// 0x046, Default allocation size in blocks
|
||||
public UInt64 retainmin;
|
||||
// 0x048, Minimum file retention period
|
||||
public UInt64 retainmax;
|
||||
// 0x050, Maximum file retention period
|
||||
public UInt64 revdate;
|
||||
// 0x058, Last modification date
|
||||
public byte[] min_class;
|
||||
// 0x060, Minimum security class, 20 bytes
|
||||
public byte[] max_class;
|
||||
// 0x074, Maximum security class, 20 bytes
|
||||
public UInt16 filetab_fid1;
|
||||
// 0x088, File lookup table FID
|
||||
public UInt16 filetab_fid2;
|
||||
// 0x08A, File lookup table FID
|
||||
public UInt16 filetab_fid3;
|
||||
// 0x08C, File lookup table FID
|
||||
public UInt16 lowstruclev;
|
||||
// 0x08E, Lowest structure level on the volume
|
||||
public UInt16 highstruclev;
|
||||
// 0x090, Highest structure level on the volume
|
||||
public UInt64 copydate;
|
||||
// 0x092, Volume copy date (??)
|
||||
public byte[] reserved1;
|
||||
// 0x09A, 302 bytes
|
||||
public UInt32 serialnum;
|
||||
// 0x1C8, Physical drive serial number
|
||||
public string strucname;
|
||||
// 0x1CC, Name of the volume set, 12 bytes
|
||||
public string volname;
|
||||
// 0x1D8, Volume label, 12 bytes
|
||||
public string ownername;
|
||||
// 0x1E4, Name of the volume owner, 12 bytes
|
||||
public string format;
|
||||
// 0x1F0, ODS-2 defines it as "DECFILE11B", 12 bytes
|
||||
public UInt16 reserved2;
|
||||
// 0x1FC, Reserved
|
||||
public UInt16 checksum2;
|
||||
// 0x1FE, Checksum of preceding 255 words (16 bit units)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,166 +0,0 @@
|
||||
/***************************************************************************
|
||||
The Disc Image Chef
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
Filename : Opera.cs
|
||||
Version : 1.0
|
||||
Author(s) : Natalia Portillo
|
||||
|
||||
Component : Filesystem plugins
|
||||
|
||||
Revision : $Revision$
|
||||
Last change by : $Author$
|
||||
Date : $Date$
|
||||
|
||||
--[ Description ] ----------------------------------------------------------
|
||||
|
||||
Identifies 3DO filesystems (aka Opera) and shows information.
|
||||
|
||||
--[ License ] --------------------------------------------------------------
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
----------------------------------------------------------------------------
|
||||
Copyright (C) 2011-2014 Claunia.com
|
||||
****************************************************************************/
|
||||
//$Id$
|
||||
|
||||
using System;
|
||||
using System.Text;
|
||||
using DiscImageChef;
|
||||
|
||||
|
||||
namespace DiscImageChef.Plugins
|
||||
{
|
||||
class OperaFS : Plugin
|
||||
{
|
||||
public OperaFS(PluginBase Core)
|
||||
{
|
||||
Name = "Opera Filesystem Plugin";
|
||||
PluginUUID = new Guid("0ec84ec7-eae6-4196-83fe-943b3fe46dbd");
|
||||
}
|
||||
|
||||
public override bool Identify(ImagePlugins.ImagePlugin imagePlugin, ulong partitionStart, ulong partitionEnd)
|
||||
{
|
||||
if ((2 + partitionStart) >= imagePlugin.GetSectors())
|
||||
return false;
|
||||
|
||||
byte[] sb_sector = imagePlugin.ReadSector(0 + partitionStart);
|
||||
|
||||
byte record_type;
|
||||
byte[] sync_bytes = new byte[5];
|
||||
byte record_version;
|
||||
|
||||
record_type = sb_sector[0x000];
|
||||
Array.Copy(sb_sector, 0x001, sync_bytes, 0, 5);
|
||||
record_version = sb_sector[0x006];
|
||||
|
||||
if (record_type != 1 || record_version != 1)
|
||||
return false;
|
||||
return Encoding.ASCII.GetString(sync_bytes) == "ZZZZZ";
|
||||
|
||||
}
|
||||
|
||||
public override void GetInformation(ImagePlugins.ImagePlugin imagePlugin, ulong partitionStart, ulong partitionEnd, out string information)
|
||||
{
|
||||
information = "";
|
||||
StringBuilder SuperBlockMetadata = new StringBuilder();
|
||||
|
||||
byte[] sb_sector = imagePlugin.ReadSector(0 + partitionStart);
|
||||
|
||||
OperaSuperBlock sb = new OperaSuperBlock();
|
||||
byte[] cString = new byte[32];
|
||||
sb.sync_bytes = new byte[5];
|
||||
|
||||
sb.record_type = sb_sector[0x000];
|
||||
Array.Copy(sb_sector, 0x001, sb.sync_bytes, 0, 5);
|
||||
sb.record_version = sb_sector[0x006];
|
||||
sb.volume_flags = sb_sector[0x007];
|
||||
Array.Copy(sb_sector, 0x008, cString, 0, 32);
|
||||
sb.volume_comment = StringHandlers.CToString(cString);
|
||||
Array.Copy(sb_sector, 0x028, cString, 0, 32);
|
||||
sb.volume_label = StringHandlers.CToString(cString);
|
||||
sb.volume_id = BigEndianBitConverter.ToInt32(sb_sector, 0x048);
|
||||
sb.block_size = BigEndianBitConverter.ToInt32(sb_sector, 0x04C);
|
||||
sb.block_count = BigEndianBitConverter.ToInt32(sb_sector, 0x050);
|
||||
sb.root_dirid = BigEndianBitConverter.ToInt32(sb_sector, 0x054);
|
||||
sb.rootdir_blocks = BigEndianBitConverter.ToInt32(sb_sector, 0x058);
|
||||
sb.rootdir_bsize = BigEndianBitConverter.ToInt32(sb_sector, 0x05C);
|
||||
sb.last_root_copy = BigEndianBitConverter.ToInt32(sb_sector, 0x060);
|
||||
|
||||
if (sb.record_type != 1 || sb.record_version != 1)
|
||||
return;
|
||||
if (Encoding.ASCII.GetString(sb.sync_bytes) != "ZZZZZ")
|
||||
return;
|
||||
|
||||
if (sb.volume_comment.Length == 0)
|
||||
sb.volume_comment = "Not set.";
|
||||
|
||||
if (sb.volume_label.Length == 0)
|
||||
sb.volume_label = "Not set.";
|
||||
|
||||
SuperBlockMetadata.AppendFormat("Opera filesystem disc.").AppendLine();
|
||||
SuperBlockMetadata.AppendFormat("Volume label: {0}", sb.volume_label).AppendLine();
|
||||
SuperBlockMetadata.AppendFormat("Volume comment: {0}", sb.volume_comment).AppendLine();
|
||||
SuperBlockMetadata.AppendFormat("Volume identifier: 0x{0:X8}", sb.volume_id).AppendLine();
|
||||
SuperBlockMetadata.AppendFormat("Block size: {0} bytes", sb.block_size).AppendLine();
|
||||
if (imagePlugin.GetSectorSize() == 2336 || imagePlugin.GetSectorSize() == 2352 || imagePlugin.GetSectorSize() == 2448)
|
||||
{
|
||||
if (sb.block_size != 2048)
|
||||
SuperBlockMetadata.AppendFormat("WARNING: Filesystem indicates {0} bytes/block while device indicates {1} bytes/block", sb.block_size, 2048);
|
||||
}
|
||||
else if (imagePlugin.GetSectorSize() != sb.block_size)
|
||||
SuperBlockMetadata.AppendFormat("WARNING: Filesystem indicates {0} bytes/block while device indicates {1} bytes/block", sb.block_size, imagePlugin.GetSectorSize());
|
||||
SuperBlockMetadata.AppendFormat("Volume size: {0} blocks, {1} bytes", sb.block_count, sb.block_size * sb.block_count).AppendLine();
|
||||
if ((ulong)sb.block_count > imagePlugin.GetSectors())
|
||||
SuperBlockMetadata.AppendFormat("WARNING: Filesystem indicates {0} blocks while device indicates {1} blocks", sb.block_count, imagePlugin.GetSectors());
|
||||
SuperBlockMetadata.AppendFormat("Root directory identifier: 0x{0:X8}", sb.root_dirid).AppendLine();
|
||||
SuperBlockMetadata.AppendFormat("Root directory block size: {0} bytes", sb.rootdir_bsize).AppendLine();
|
||||
SuperBlockMetadata.AppendFormat("Root directory size: {0} blocks, {1} bytes", sb.rootdir_blocks, sb.rootdir_bsize * sb.rootdir_blocks).AppendLine();
|
||||
SuperBlockMetadata.AppendFormat("Last root directory copy: {0}", sb.last_root_copy).AppendLine();
|
||||
|
||||
information = SuperBlockMetadata.ToString();
|
||||
}
|
||||
|
||||
struct OperaSuperBlock
|
||||
{
|
||||
public byte record_type;
|
||||
// 0x000, Record type, must be 1
|
||||
public byte[] sync_bytes;
|
||||
// 0x001, 5 bytes, "ZZZZZ" = new byte[5];
|
||||
public byte record_version;
|
||||
// 0x006, Record version, must be 1
|
||||
public byte volume_flags;
|
||||
// 0x007, Volume flags
|
||||
public string volume_comment;
|
||||
// 0x008, 32 bytes, volume comment
|
||||
public string volume_label;
|
||||
// 0x028, 32 bytes, volume label
|
||||
public Int32 volume_id;
|
||||
// 0x048, Volume ID
|
||||
public Int32 block_size;
|
||||
// 0x04C, Block size in bytes
|
||||
public Int32 block_count;
|
||||
// 0x050, Blocks in volume
|
||||
public Int32 root_dirid;
|
||||
// 0x054, Root directory ID
|
||||
public Int32 rootdir_blocks;
|
||||
// 0x058, Root directory blocks
|
||||
public Int32 rootdir_bsize;
|
||||
// 0x05C, Root directory block size
|
||||
public Int32 last_root_copy;
|
||||
// 0x060, Last root directory copy
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
/***************************************************************************
|
||||
The Disc Image Chef
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
Filename : PCEngine.cs
|
||||
Version : 1.0
|
||||
Author(s) : Natalia Portillo
|
||||
|
||||
Component : Filesystem plugins
|
||||
|
||||
Revision : $Revision$
|
||||
Last change by : $Author$
|
||||
Date : $Date$
|
||||
|
||||
--[ Description ] ----------------------------------------------------------
|
||||
|
||||
Identifies PC-Engine CDs.
|
||||
|
||||
--[ License ] --------------------------------------------------------------
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
----------------------------------------------------------------------------
|
||||
Copyright (C) 2011-2014 Claunia.com
|
||||
****************************************************************************/
|
||||
//$Id$
|
||||
|
||||
using System;
|
||||
using System.Text;
|
||||
using DiscImageChef;
|
||||
|
||||
namespace DiscImageChef.Plugins
|
||||
{
|
||||
class PCEnginePlugin : Plugin
|
||||
{
|
||||
public PCEnginePlugin(PluginBase Core)
|
||||
{
|
||||
Name = "PC Engine CD Plugin";
|
||||
PluginUUID = new Guid("e5ee6d7c-90fa-49bd-ac89-14ef750b8af3");
|
||||
}
|
||||
|
||||
public override bool Identify(ImagePlugins.ImagePlugin imagePlugin, ulong partitionStart, ulong partitionEnd)
|
||||
{
|
||||
if ((2 + partitionStart) >= imagePlugin.GetSectors())
|
||||
return false;
|
||||
|
||||
byte[] system_descriptor = new byte[23];
|
||||
byte[] sector = imagePlugin.ReadSector(1 + partitionStart);
|
||||
|
||||
Array.Copy(sector, 0x20, system_descriptor, 0, 23);
|
||||
|
||||
return Encoding.ASCII.GetString(system_descriptor) == "PC Engine CD-ROM SYSTEM";
|
||||
}
|
||||
|
||||
public override void GetInformation(ImagePlugins.ImagePlugin imagePlugin, ulong partitionStart, ulong partitionEnd, out string information)
|
||||
{
|
||||
information = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
/***************************************************************************
|
||||
The Disc Image Chef
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
Filename : Plugin.cs
|
||||
Version : 1.0
|
||||
Author(s) : Natalia Portillo
|
||||
|
||||
Component : Filesystem plugins
|
||||
|
||||
Revision : $Revision$
|
||||
Last change by : $Author$
|
||||
Date : $Date$
|
||||
|
||||
--[ Description ] ----------------------------------------------------------
|
||||
|
||||
Defines functions to be used by filesystem plugins and several constants.
|
||||
|
||||
--[ License ] --------------------------------------------------------------
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
----------------------------------------------------------------------------
|
||||
Copyright (C) 2011-2014 Claunia.com
|
||||
****************************************************************************/
|
||||
//$Id$
|
||||
|
||||
using System;
|
||||
|
||||
namespace DiscImageChef.Plugins
|
||||
{
|
||||
/// <summary>
|
||||
/// Abstract class to implement filesystem plugins.
|
||||
/// </summary>
|
||||
public abstract class Plugin
|
||||
{
|
||||
/// <summary>Plugin name.</summary>
|
||||
public string Name;
|
||||
/// <summary>Plugin UUID.</summary>
|
||||
public Guid PluginUUID;
|
||||
|
||||
protected Plugin()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Identifies the filesystem in the specified LBA
|
||||
/// </summary>
|
||||
/// <param name="imagePlugin">Disk image.</param>
|
||||
/// <param name="partitionStart">Partition start sector (LBA).</param>
|
||||
/// <param name="partitionEnd">Partition end sector (LBA).</param>
|
||||
/// <returns><c>true</c>, if the filesystem is recognized, <c>false</c> otherwise.</returns>
|
||||
public abstract bool Identify(ImagePlugins.ImagePlugin imagePlugin, ulong partitionStart, ulong partitionEnd);
|
||||
|
||||
/// <summary>
|
||||
/// Gets information about the identified filesystem.
|
||||
/// </summary>
|
||||
/// <param name="imagePlugin">Disk image.</param>
|
||||
/// <param name="partitionOffset">Partition offset (LBA).</param>
|
||||
/// <param name="information">Filesystem information.</param>
|
||||
public abstract void GetInformation(ImagePlugins.ImagePlugin imagePlugin, ulong partitionStart, ulong partitionEnd, out string information);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,536 +0,0 @@
|
||||
/***************************************************************************
|
||||
The Disc Image Chef
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
Filename : ProDOS.cs
|
||||
Version : 1.0
|
||||
Author(s) : Natalia Portillo
|
||||
|
||||
Component : Filesystem plugins
|
||||
|
||||
Revision : $Revision$
|
||||
Last change by : $Author$
|
||||
Date : $Date$
|
||||
|
||||
--[ Description ] ----------------------------------------------------------
|
||||
|
||||
Identifies Apple ProDOS and Apple SOS file systems.
|
||||
|
||||
--[ License ] --------------------------------------------------------------
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
----------------------------------------------------------------------------
|
||||
Copyright (C) 2011-2015 Claunia.com
|
||||
****************************************************************************/
|
||||
//$Id$
|
||||
|
||||
using System;
|
||||
using System.Text;
|
||||
using DiscImageChef;
|
||||
|
||||
// Information from Apple ProDOS 8 Technical Reference
|
||||
namespace DiscImageChef.Plugins
|
||||
{
|
||||
public class ProDOSPlugin : Plugin
|
||||
{
|
||||
const byte EmptyStorageType = 0x00;
|
||||
/// <summary>
|
||||
/// A file that occupies one block or less
|
||||
/// </summary>
|
||||
const byte SeedlingFileType = 0x01;
|
||||
/// <summary>
|
||||
/// A file that occupies between 2 and 256 blocks
|
||||
/// </summary>
|
||||
const byte SaplingFileType = 0x02;
|
||||
/// <summary>
|
||||
/// A file that occupies between 257 and 32768 blocks
|
||||
/// </summary>
|
||||
const byte TreeFileType = 0x03;
|
||||
const byte PascalAreaType = 0x04;
|
||||
const byte SubDirectoryType = 0x0D;
|
||||
const byte SubDirectoryHeaderType = 0x0E;
|
||||
const byte RootDirectoryType = 0x0F;
|
||||
|
||||
const byte ProDOSVersion1 = 0x00;
|
||||
|
||||
const UInt32 ProDOSYearMask = 0xFE000000;
|
||||
const UInt32 ProDOSMonthMask = 0x1E00000;
|
||||
const UInt32 ProDOSDayMask = 0x1F0000;
|
||||
const UInt32 ProDOSHourMask = 0x1F00;
|
||||
const UInt32 ProDOSMinuteMask = 0x3F;
|
||||
|
||||
const byte ProDOSDestroyAttribute = 0x80;
|
||||
const byte ProDOSRenameAttribute = 0x40;
|
||||
const byte ProDOSBackupAttribute = 0x20;
|
||||
const byte ProDOSWriteAttribute = 0x02;
|
||||
const byte ProDOSReadAttribute = 0x01;
|
||||
const byte ProDOSReservedAttributeMask = 0x1C;
|
||||
|
||||
const byte ProDOSStorageTypeMask = 0xF0;
|
||||
const byte ProDOSNameLengthMask = 0x0F;
|
||||
const byte ProDOSEntryLength = 0x27;
|
||||
const byte ProDOSEntriesPerBlock = 0x0D;
|
||||
|
||||
public ProDOSPlugin(PluginBase Core)
|
||||
{
|
||||
Name = "Apple ProDOS filesystem";
|
||||
PluginUUID = new Guid("43874265-7B8A-4739-BCF7-07F80D5932BF");
|
||||
}
|
||||
|
||||
public override bool Identify(ImagePlugins.ImagePlugin imagePlugin, ulong partitionStart, ulong partitionEnd)
|
||||
{
|
||||
if (imagePlugin.GetSectors() < 3)
|
||||
return false;
|
||||
|
||||
// Blocks 0 and 1 are boot code
|
||||
byte[] rootDirectoryKeyBlock = imagePlugin.ReadSector(2 + partitionStart);
|
||||
|
||||
UInt16 prePointer = BitConverter.ToUInt16(rootDirectoryKeyBlock, 0);
|
||||
if (prePointer != 0)
|
||||
return false;
|
||||
|
||||
byte storage_type = (byte)((rootDirectoryKeyBlock[0x04] & ProDOSStorageTypeMask) >> 4);
|
||||
if (storage_type != RootDirectoryType)
|
||||
return false;
|
||||
|
||||
byte entry_length = rootDirectoryKeyBlock[0x23];
|
||||
if (entry_length != ProDOSEntryLength)
|
||||
return false;
|
||||
|
||||
byte entries_per_block = rootDirectoryKeyBlock[0x24];
|
||||
if (entries_per_block != ProDOSEntriesPerBlock)
|
||||
return false;
|
||||
|
||||
UInt16 bit_map_pointer = BitConverter.ToUInt16(rootDirectoryKeyBlock, 0x27);
|
||||
if (bit_map_pointer > imagePlugin.GetSectors())
|
||||
return false;
|
||||
|
||||
UInt16 total_blocks = BitConverter.ToUInt16(rootDirectoryKeyBlock, 0x29);
|
||||
return total_blocks <= imagePlugin.GetSectors();
|
||||
}
|
||||
|
||||
public override void GetInformation(ImagePlugins.ImagePlugin imagePlugin, ulong partitionStart, ulong partitionEnd, out string information)
|
||||
{
|
||||
StringBuilder sbInformation = new StringBuilder();
|
||||
|
||||
// Blocks 0 and 1 are boot code
|
||||
byte[] rootDirectoryKeyBlockBytes = imagePlugin.ReadSector(2 + partitionStart);
|
||||
|
||||
ProDOSRootDirectoryKeyBlock rootDirectoryKeyBlock = new ProDOSRootDirectoryKeyBlock();
|
||||
rootDirectoryKeyBlock.header = new ProDOSRootDirectoryHeader();
|
||||
|
||||
byte[] temporal;
|
||||
int year, month, day, hour, minute;
|
||||
UInt16 temp_timestamp_left, temp_timestamp_right;
|
||||
UInt32 temp_timestamp;
|
||||
|
||||
rootDirectoryKeyBlock.zero = BitConverter.ToUInt16(rootDirectoryKeyBlockBytes, 0x00);
|
||||
rootDirectoryKeyBlock.next_pointer = BitConverter.ToUInt16(rootDirectoryKeyBlockBytes, 0x02);
|
||||
rootDirectoryKeyBlock.header.storage_type = (byte)((rootDirectoryKeyBlockBytes[0x04] & ProDOSStorageTypeMask) >> 4);
|
||||
rootDirectoryKeyBlock.header.name_length = (byte)(rootDirectoryKeyBlockBytes[0x04] & ProDOSNameLengthMask);
|
||||
temporal = new byte[rootDirectoryKeyBlock.header.name_length];
|
||||
Array.Copy(rootDirectoryKeyBlockBytes, 0x05, temporal, 0, rootDirectoryKeyBlock.header.name_length);
|
||||
rootDirectoryKeyBlock.header.volume_name = Encoding.ASCII.GetString(temporal);
|
||||
rootDirectoryKeyBlock.header.reserved = BitConverter.ToUInt64(rootDirectoryKeyBlockBytes, 0x14);
|
||||
|
||||
temp_timestamp_left = BitConverter.ToUInt16(rootDirectoryKeyBlockBytes, 0x1C);
|
||||
temp_timestamp_right = BitConverter.ToUInt16(rootDirectoryKeyBlockBytes, 0x1E);
|
||||
temp_timestamp = (uint)((temp_timestamp_left << 16) + temp_timestamp_right);
|
||||
year = (int)((temp_timestamp & ProDOSYearMask) >> 25);
|
||||
month = (int)((temp_timestamp & ProDOSMonthMask) >> 21);
|
||||
day = (int)((temp_timestamp & ProDOSDayMask) >> 16);
|
||||
hour = (int)((temp_timestamp & ProDOSHourMask) >> 8);
|
||||
minute = (int)(temp_timestamp & ProDOSMinuteMask);
|
||||
year += 1900;
|
||||
if (year < 1940)
|
||||
year += 100;
|
||||
if (MainClass.isDebug)
|
||||
{
|
||||
Console.WriteLine("DEBUG (ProDOS plugin): temp_timestamp_left = 0x{0:X4}", temp_timestamp_left);
|
||||
Console.WriteLine("DEBUG (ProDOS plugin): temp_timestamp_right = 0x{0:X4}", temp_timestamp_right);
|
||||
Console.WriteLine("DEBUG (ProDOS plugin): temp_timestamp = 0x{0:X8}", temp_timestamp);
|
||||
Console.WriteLine("DEBUG (ProDOS plugin): Datetime field year {0}, month {1}, day {2}, hour {3}, minute {4}.", year, month, day, hour, minute);
|
||||
}
|
||||
rootDirectoryKeyBlock.header.creation_time = new DateTime(year, month, day, hour, minute, 0);
|
||||
|
||||
rootDirectoryKeyBlock.header.version = rootDirectoryKeyBlockBytes[0x20];
|
||||
rootDirectoryKeyBlock.header.min_version = rootDirectoryKeyBlockBytes[0x21];
|
||||
rootDirectoryKeyBlock.header.access = rootDirectoryKeyBlockBytes[0x22];
|
||||
rootDirectoryKeyBlock.header.entry_length = rootDirectoryKeyBlockBytes[0x23];
|
||||
rootDirectoryKeyBlock.header.entries_per_block = rootDirectoryKeyBlockBytes[0x24];
|
||||
|
||||
rootDirectoryKeyBlock.header.file_count = BitConverter.ToUInt16(rootDirectoryKeyBlockBytes, 0x25);
|
||||
rootDirectoryKeyBlock.header.bit_map_pointer = BitConverter.ToUInt16(rootDirectoryKeyBlockBytes, 0x27);
|
||||
rootDirectoryKeyBlock.header.total_blocks = BitConverter.ToUInt16(rootDirectoryKeyBlockBytes, 0x29);
|
||||
|
||||
if (rootDirectoryKeyBlock.header.version != ProDOSVersion1 || rootDirectoryKeyBlock.header.min_version != ProDOSVersion1)
|
||||
{
|
||||
sbInformation.AppendLine("Warning! Detected unknown ProDOS version ProDOS filesystem.");
|
||||
sbInformation.AppendLine("All of the following information may be incorrect");
|
||||
}
|
||||
|
||||
if (rootDirectoryKeyBlock.header.version == ProDOSVersion1)
|
||||
sbInformation.AppendLine("ProDOS version 1 used to create this volume.");
|
||||
else
|
||||
sbInformation.AppendFormat("Unknown ProDOS version with field {0} used to create this volume.", rootDirectoryKeyBlock.header.version).AppendLine();
|
||||
|
||||
if (rootDirectoryKeyBlock.header.min_version == ProDOSVersion1)
|
||||
sbInformation.AppendLine("ProDOS version 1 at least required for reading this volume.");
|
||||
else
|
||||
sbInformation.AppendFormat("Unknown ProDOS version with field {0} is at least required for reading this volume.", rootDirectoryKeyBlock.header.min_version).AppendLine();
|
||||
|
||||
sbInformation.AppendFormat("Volume name is {0}", rootDirectoryKeyBlock.header.volume_name).AppendLine();
|
||||
sbInformation.AppendFormat("Volume created on {0}", rootDirectoryKeyBlock.header.creation_time).AppendLine();
|
||||
sbInformation.AppendFormat("{0} bytes per directory entry", rootDirectoryKeyBlock.header.entry_length).AppendLine();
|
||||
sbInformation.AppendFormat("{0} entries per directory block", rootDirectoryKeyBlock.header.entries_per_block).AppendLine();
|
||||
sbInformation.AppendFormat("{0} files in root directory", rootDirectoryKeyBlock.header.file_count).AppendLine();
|
||||
sbInformation.AppendFormat("{0} blocks in volume", rootDirectoryKeyBlock.header.total_blocks).AppendLine();
|
||||
sbInformation.AppendFormat("Bitmap starts at block {0}", rootDirectoryKeyBlock.header.bit_map_pointer).AppendLine();
|
||||
|
||||
if ((rootDirectoryKeyBlock.header.access & ProDOSReadAttribute) == ProDOSReadAttribute)
|
||||
sbInformation.AppendLine("Volume can be read");
|
||||
if ((rootDirectoryKeyBlock.header.access & ProDOSWriteAttribute) == ProDOSWriteAttribute)
|
||||
sbInformation.AppendLine("Volume can be written");
|
||||
if ((rootDirectoryKeyBlock.header.access & ProDOSRenameAttribute) == ProDOSRenameAttribute)
|
||||
sbInformation.AppendLine("Volume can be renamed");
|
||||
if ((rootDirectoryKeyBlock.header.access & ProDOSDestroyAttribute) == ProDOSDestroyAttribute)
|
||||
sbInformation.AppendLine("Volume can be destroyed");
|
||||
if ((rootDirectoryKeyBlock.header.access & ProDOSBackupAttribute) == ProDOSBackupAttribute)
|
||||
sbInformation.AppendLine("Volume must be backed up");
|
||||
|
||||
if (MainClass.isDebug)
|
||||
{
|
||||
if ((rootDirectoryKeyBlock.header.access & ProDOSReservedAttributeMask) != 0)
|
||||
sbInformation.AppendFormat("DEBUG(ProDOS plugin): Reserved attributes are set: {0:X2}", rootDirectoryKeyBlock.header.access).AppendLine();
|
||||
}
|
||||
|
||||
information = sbInformation.ToString();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// ProDOS directory entry, decoded structure
|
||||
/// </summary>
|
||||
struct ProDOSEntry
|
||||
{
|
||||
/// <summary>
|
||||
/// Type of file pointed by this entry
|
||||
/// Offset 0x00, mask 0xF0
|
||||
/// </summary>
|
||||
public byte storage_type;
|
||||
/// <summary>
|
||||
/// Length of name_length pascal string
|
||||
/// Offset 0x00, mask 0x0F
|
||||
/// </summary>
|
||||
public byte name_length;
|
||||
/// <summary>
|
||||
/// Pascal string of file name
|
||||
/// Offset 0x01, 15 bytes
|
||||
/// </summary>
|
||||
public string file_name;
|
||||
/// <summary>
|
||||
/// Descriptor of internal structure of the file
|
||||
/// Offset 0x10, 1 byte
|
||||
/// </summary>
|
||||
public byte file_type;
|
||||
/// <summary>
|
||||
/// Block address of master index block for tree files.
|
||||
/// Block address of index block for sapling files.
|
||||
/// Block address of block for seedling files.
|
||||
/// Offset 0x11, 2 bytes
|
||||
/// </summary>
|
||||
public UInt16 key_pointer;
|
||||
/// <summary>
|
||||
/// Blocks used by file or directory, including index blocks.
|
||||
/// Offset 0x13, 2 bytes
|
||||
/// </summary>
|
||||
public UInt16 blocks_used;
|
||||
/// <summary>
|
||||
/// Size of file in bytes
|
||||
/// Offset 0x15, 3 bytes
|
||||
/// </summary>
|
||||
public UInt32 EOF;
|
||||
/// <summary>
|
||||
/// File creation datetime
|
||||
/// Offset 0x18, 4 bytes
|
||||
/// </summary>
|
||||
public DateTime creation_time;
|
||||
/// <summary>
|
||||
/// Version of ProDOS that created this file
|
||||
/// Offset 0x1C, 1 byte
|
||||
/// </summary>
|
||||
public byte version;
|
||||
/// <summary>
|
||||
/// Minimum version of ProDOS needed to access this file
|
||||
/// Offset 0x1D, 1 byte
|
||||
/// </summary>
|
||||
public byte min_version;
|
||||
/// <summary>
|
||||
/// File permissions
|
||||
/// Offset 0x1E, 1 byte
|
||||
/// </summary>
|
||||
public byte access;
|
||||
/// <summary>
|
||||
/// General purpose field to store additional information about file format
|
||||
/// Offset 0x1F, 2 bytes
|
||||
/// </summary>
|
||||
public UInt16 aux_type;
|
||||
/// <summary>
|
||||
/// File last modification date time
|
||||
/// Offset 0x21, 4 bytes
|
||||
/// </summary>
|
||||
public DateTime last_mod;
|
||||
/// <summary>
|
||||
/// Block address pointer to key block of the directory containing this entry
|
||||
/// Offset 0x25, 2 bytes
|
||||
/// </summary>
|
||||
public UInt16 header_pointer;
|
||||
}
|
||||
|
||||
struct ProDOSRootDirectoryHeader
|
||||
{
|
||||
/// <summary>
|
||||
/// Constant 0x0F
|
||||
/// Offset 0x04, mask 0xF0
|
||||
/// </summary>
|
||||
public byte storage_type;
|
||||
/// <summary>
|
||||
/// Length of volume_name pascal string
|
||||
/// Offset 0x04, mask 0x0F
|
||||
/// </summary>
|
||||
public byte name_length;
|
||||
/// <summary>
|
||||
/// The name of the volume.
|
||||
/// Offset 0x05, 15 bytes
|
||||
/// </summary>
|
||||
public string volume_name;
|
||||
/// <summary>
|
||||
/// Reserved for future expansion
|
||||
/// Offset 0x14, 8 bytes
|
||||
/// </summary>
|
||||
public UInt64 reserved;
|
||||
/// <summary>
|
||||
/// Creation time of the volume
|
||||
/// Offset 0x1C, 4 bytes
|
||||
/// </summary>
|
||||
public DateTime creation_time;
|
||||
/// <summary>
|
||||
/// Version number of the volume format
|
||||
/// Offset 0x20, 1 byte
|
||||
/// </summary>
|
||||
public byte version;
|
||||
/// <summary>
|
||||
/// Reserved for future use
|
||||
/// Offset 0x21, 1 byte
|
||||
/// </summary>
|
||||
public byte min_version;
|
||||
/// <summary>
|
||||
/// Permissions for the volume
|
||||
/// Offset 0x22, 1 byte
|
||||
/// </summary>
|
||||
public byte access;
|
||||
/// <summary>
|
||||
/// Length of an entry in this directory
|
||||
/// Const 0x27
|
||||
/// Offset 0x23, 1 byte
|
||||
/// </summary>
|
||||
public byte entry_length;
|
||||
/// <summary>
|
||||
/// Number of entries per block
|
||||
/// Const 0x0D
|
||||
/// Offset 0x24, 1 byte
|
||||
/// </summary>
|
||||
public byte entries_per_block;
|
||||
/// <summary>
|
||||
/// Number of active files in this directory
|
||||
/// Offset 0x25, 2 bytes
|
||||
/// </summary>
|
||||
public UInt16 file_count;
|
||||
/// <summary>
|
||||
/// Block address of the first block of the volume's bitmap,
|
||||
/// one for every 4096 blocks or fraction
|
||||
/// Offset 0x27, 2 bytes
|
||||
/// </summary>
|
||||
public UInt16 bit_map_pointer;
|
||||
/// <summary>
|
||||
/// Total number of blocks in the volume
|
||||
/// Offset 0x29, 2 bytes
|
||||
/// </summary>
|
||||
public UInt16 total_blocks;
|
||||
}
|
||||
|
||||
struct ProDOSDirectoryHeader
|
||||
{
|
||||
/// <summary>
|
||||
/// Constant 0x0E
|
||||
/// Offset 0x04, mask 0xF0
|
||||
/// </summary>
|
||||
public byte storage_type;
|
||||
/// <summary>
|
||||
/// Length of volume_name pascal string
|
||||
/// Offset 0x04, mask 0x0F
|
||||
/// </summary>
|
||||
public byte name_length;
|
||||
/// <summary>
|
||||
/// The name of the directory.
|
||||
/// Offset 0x05, 15 bytes
|
||||
/// </summary>
|
||||
public string directory_name;
|
||||
/// <summary>
|
||||
/// Reserved for future expansion
|
||||
/// Offset 0x14, 8 bytes
|
||||
/// </summary>
|
||||
public UInt64 reserved;
|
||||
/// <summary>
|
||||
/// Creation time of the volume
|
||||
/// Offset 0x1C, 4 bytes
|
||||
/// </summary>
|
||||
public DateTime creation_time;
|
||||
/// <summary>
|
||||
/// Version number of the volume format
|
||||
/// Offset 0x20, 1 byte
|
||||
/// </summary>
|
||||
public byte version;
|
||||
/// <summary>
|
||||
/// Reserved for future use
|
||||
/// Offset 0x21, 1 byte
|
||||
/// </summary>
|
||||
public byte min_version;
|
||||
/// <summary>
|
||||
/// Permissions for the volume
|
||||
/// Offset 0x22, 1 byte
|
||||
/// </summary>
|
||||
public byte access;
|
||||
/// <summary>
|
||||
/// Length of an entry in this directory
|
||||
/// Const 0x27
|
||||
/// Offset 0x23, 1 byte
|
||||
/// </summary>
|
||||
public byte entry_length;
|
||||
/// <summary>
|
||||
/// Number of entries per block
|
||||
/// Const 0x0D
|
||||
/// Offset 0x24, 1 byte
|
||||
/// </summary>
|
||||
public byte entries_per_block;
|
||||
/// <summary>
|
||||
/// Number of active files in this directory
|
||||
/// Offset 0x25, 2 bytes
|
||||
/// </summary>
|
||||
public UInt16 file_count;
|
||||
/// <summary>
|
||||
/// Block address of parent directory block that contains this entry
|
||||
/// Offset 0x27, 2 bytes
|
||||
/// </summary>
|
||||
public UInt16 parent_pointer;
|
||||
/// <summary>
|
||||
/// Entry number within the block indicated in parent_pointer
|
||||
/// Offset 0x29, 1 byte
|
||||
/// </summary>
|
||||
public byte parent_entry_number;
|
||||
/// <summary>
|
||||
/// Length of the entry that holds this directory, in the parent entry
|
||||
/// Const 0x27
|
||||
/// Offset 0x2A, 1 byte
|
||||
/// </summary>
|
||||
public byte parent_entry_length;
|
||||
}
|
||||
|
||||
struct ProDOSDirectoryKeyBlock
|
||||
{
|
||||
/// <summary>
|
||||
/// Always 0
|
||||
/// Offset 0x00, 2 bytes
|
||||
/// </summary>
|
||||
public UInt16 zero;
|
||||
/// <summary>
|
||||
/// Pointer to next directory block, 0 if last
|
||||
/// Offset 0x02, 2 bytes
|
||||
/// </summary>
|
||||
public UInt16 next_pointer;
|
||||
/// <summary>
|
||||
/// Directory header
|
||||
/// Offset 0x04, 39 bytes
|
||||
/// </summary>
|
||||
public ProDOSDirectoryHeader header;
|
||||
/// <summary>
|
||||
/// Directory entries
|
||||
/// Offset 0x2F, 39 bytes each, 12 entries
|
||||
/// </summary>
|
||||
public ProDOSEntry[] entries;
|
||||
}
|
||||
|
||||
struct ProDOSRootDirectoryKeyBlock
|
||||
{
|
||||
/// <summary>
|
||||
/// Always 0
|
||||
/// Offset 0x00, 2 bytes
|
||||
/// </summary>
|
||||
public UInt16 zero;
|
||||
/// <summary>
|
||||
/// Pointer to next directory block, 0 if last
|
||||
/// Offset 0x02, 2 bytes
|
||||
/// </summary>
|
||||
public UInt16 next_pointer;
|
||||
/// <summary>
|
||||
/// Directory header
|
||||
/// Offset 0x04, 39 bytes
|
||||
/// </summary>
|
||||
public ProDOSRootDirectoryHeader header;
|
||||
/// <summary>
|
||||
/// Directory entries
|
||||
/// Offset 0x2F, 39 bytes each, 12 entries
|
||||
/// </summary>
|
||||
public ProDOSEntry[] entries;
|
||||
}
|
||||
|
||||
struct ProDOSDirectoryBlock
|
||||
{
|
||||
/// <summary>
|
||||
/// Pointer to previous directory block
|
||||
/// Offset 0x00, 2 bytes
|
||||
/// </summary>
|
||||
public UInt16 zero;
|
||||
/// <summary>
|
||||
/// Pointer to next directory block, 0 if last
|
||||
/// Offset 0x02, 2 bytes
|
||||
/// </summary>
|
||||
public UInt16 next_pointer;
|
||||
/// <summary>
|
||||
/// Directory entries
|
||||
/// Offset 0x2F, 39 bytes each, 13 entries
|
||||
/// </summary>
|
||||
public ProDOSEntry[] entries;
|
||||
}
|
||||
|
||||
struct ProDOSIndexBlock
|
||||
{
|
||||
/// <summary>
|
||||
/// Up to 256 pointers to blocks, 0 to indicate the block is sparsed (non-allocated)
|
||||
/// </summary>
|
||||
public UInt16[] block_pointer;
|
||||
}
|
||||
|
||||
struct ProDOSMasterIndexBlock
|
||||
{
|
||||
/// <summary>
|
||||
/// Up to 128 pointers to index blocks
|
||||
/// </summary>
|
||||
public UInt16[] index_block_pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,191 +0,0 @@
|
||||
/***************************************************************************
|
||||
The Disc Image Chef
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
Filename : SolarFS.cs
|
||||
Version : 1.0
|
||||
Author(s) : Natalia Portillo
|
||||
|
||||
Component : Filesystem plugins
|
||||
|
||||
Revision : $Revision$
|
||||
Last change by : $Author$
|
||||
Date : $Date$
|
||||
|
||||
--[ Description ] ----------------------------------------------------------
|
||||
|
||||
Identifies SolarOS filesystems and shows information.
|
||||
|
||||
--[ License ] --------------------------------------------------------------
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
----------------------------------------------------------------------------
|
||||
Copyright (C) 2011-2014 Claunia.com
|
||||
****************************************************************************/
|
||||
//$Id$
|
||||
|
||||
using System;
|
||||
using System.Text;
|
||||
using DiscImageChef;
|
||||
|
||||
// Based on FAT's BPB, cannot find a FAT or directory
|
||||
namespace DiscImageChef.Plugins
|
||||
{
|
||||
class SolarFS : Plugin
|
||||
{
|
||||
public SolarFS(PluginBase Core)
|
||||
{
|
||||
Name = "Solar_OS filesystem";
|
||||
PluginUUID = new Guid("EA3101C1-E777-4B4F-B5A3-8C57F50F6E65");
|
||||
}
|
||||
|
||||
public override bool Identify(ImagePlugins.ImagePlugin imagePlugin, ulong partitionStart, ulong partitionEnd)
|
||||
{
|
||||
if ((2 + partitionStart) >= imagePlugin.GetSectors())
|
||||
return false;
|
||||
|
||||
byte signature; // 0x29
|
||||
string fs_type; // "SOL_FS "
|
||||
|
||||
byte[] bpb = imagePlugin.ReadSector(0 + partitionStart);
|
||||
|
||||
byte[] fs_type_b = new byte[8];
|
||||
|
||||
signature = bpb[0x25];
|
||||
Array.Copy(bpb, 0x35, fs_type_b, 0, 8);
|
||||
fs_type = StringHandlers.CToString(fs_type_b);
|
||||
|
||||
if (signature == 0x29 && fs_type == "SOL_FS ")
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
public override void GetInformation(ImagePlugins.ImagePlugin imagePlugin, ulong partitionStart, ulong partitionEnd, out string information)
|
||||
{
|
||||
information = "";
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
byte[] bpb_sector = imagePlugin.ReadSector(0 + partitionStart);
|
||||
byte[] bpb_strings;
|
||||
|
||||
SolarOSParameterBlock BPB = new SolarOSParameterBlock();
|
||||
|
||||
bpb_strings = new byte[8];
|
||||
Array.Copy(bpb_sector, 0x03, bpb_strings, 0, 8);
|
||||
BPB.OEMName = StringHandlers.CToString(bpb_strings);
|
||||
BPB.bps = BitConverter.ToUInt16(bpb_sector, 0x0B);
|
||||
BPB.root_ent = BitConverter.ToUInt16(bpb_sector, 0x10);
|
||||
BPB.sectors = BitConverter.ToUInt16(bpb_sector, 0x12);
|
||||
BPB.media = bpb_sector[0x14];
|
||||
BPB.spfat = BitConverter.ToUInt16(bpb_sector, 0x15);
|
||||
BPB.sptrk = BitConverter.ToUInt16(bpb_sector, 0x17);
|
||||
BPB.heads = BitConverter.ToUInt16(bpb_sector, 0x19);
|
||||
BPB.signature = bpb_sector[0x25];
|
||||
bpb_strings = new byte[8];
|
||||
Array.Copy(bpb_sector, 0x2A, bpb_strings, 0, 11);
|
||||
BPB.vol_name = StringHandlers.CToString(bpb_strings);
|
||||
bpb_strings = new byte[8];
|
||||
Array.Copy(bpb_sector, 0x35, bpb_strings, 0, 8);
|
||||
BPB.fs_type = StringHandlers.CToString(bpb_strings);
|
||||
|
||||
if (MainClass.isDebug)
|
||||
{
|
||||
BPB.x86_jump = new byte[3];
|
||||
Array.Copy(bpb_sector, 0x00, BPB.x86_jump, 0, 3);
|
||||
BPB.unk1 = bpb_sector[0x0D];
|
||||
BPB.unk2 = BitConverter.ToUInt16(bpb_sector, 0x0E);
|
||||
BPB.unk3 = new byte[10];
|
||||
Array.Copy(bpb_sector, 0x1B, BPB.unk3, 0, 10);
|
||||
BPB.unk4 = BitConverter.ToUInt32(bpb_sector, 0x26);
|
||||
|
||||
Console.WriteLine("(SolarFS) BPB.x86_jump: 0x{0:X2}{1:X2}{2:X2}", BPB.x86_jump[0], BPB.x86_jump[1], BPB.x86_jump[2]);
|
||||
Console.WriteLine("(SolarFS) BPB.OEMName: \"{0}\"", BPB.OEMName);
|
||||
Console.WriteLine("(SolarFS) BPB.bps: {0}", BPB.bps);
|
||||
Console.WriteLine("(SolarFS) BPB.unk1: 0x{0:X2}", BPB.unk1);
|
||||
Console.WriteLine("(SolarFS) BPB.unk2: 0x{0:X4}", BPB.unk2);
|
||||
Console.WriteLine("(SolarFS) BPB.root_ent: {0}", BPB.root_ent);
|
||||
Console.WriteLine("(SolarFS) BPB.sectors: {0}", BPB.sectors);
|
||||
Console.WriteLine("(SolarFS) BPB.media: 0x{0:X2}", BPB.media);
|
||||
Console.WriteLine("(SolarFS) BPB.spfat: {0}", BPB.spfat);
|
||||
Console.WriteLine("(SolarFS) BPB.sptrk: {0}", BPB.sptrk);
|
||||
Console.WriteLine("(SolarFS) BPB.heads: {0}", BPB.heads);
|
||||
Console.WriteLine("(SolarFS) BPB.unk3: 0x{0:X2}{1:X2}{2:X2}{3:X2}{4:X2}{5:X2}{6:X2}{7:X2}{8:X2}{9:X2}", BPB.unk3[0], BPB.unk3[1], BPB.unk3[2], BPB.unk3[3], BPB.unk3[4], BPB.unk3[5], BPB.unk3[6], BPB.unk3[7], BPB.unk3[8], BPB.unk3[9]);
|
||||
Console.WriteLine("(SolarFS) BPB.signature: 0x{0:X2}", BPB.signature);
|
||||
Console.WriteLine("(SolarFS) BPB.unk4: 0x{0:X8}", BPB.unk4);
|
||||
Console.WriteLine("(SolarFS) BPB.vol_name: \"{0}\"", BPB.vol_name);
|
||||
Console.WriteLine("(SolarFS) BPB.fs_type: \"{0}\"", BPB.fs_type);
|
||||
}
|
||||
|
||||
sb.AppendLine("Solar_OS filesystem");
|
||||
sb.AppendFormat("Media descriptor: 0x{0:X2}", BPB.media).AppendLine();
|
||||
sb.AppendFormat("{0} bytes per sector", BPB.bps).AppendLine();
|
||||
if (imagePlugin.GetSectorSize() == 2336 || imagePlugin.GetSectorSize() == 2352 || imagePlugin.GetSectorSize() == 2448)
|
||||
{
|
||||
if (BPB.bps != imagePlugin.GetSectorSize())
|
||||
{
|
||||
sb.AppendFormat("WARNING: Filesystem describes a {0} bytes/sector, while device describes a {1} bytes/sector", BPB.bps, 2048).AppendLine();
|
||||
}
|
||||
}
|
||||
else if (BPB.bps != imagePlugin.GetSectorSize())
|
||||
{
|
||||
sb.AppendFormat("WARNING: Filesystem describes a {0} bytes/sector, while device describes a {1} bytes/sector", BPB.bps, imagePlugin.GetSectorSize()).AppendLine();
|
||||
}
|
||||
sb.AppendFormat("{0} sectors on volume ({1} bytes)", BPB.sectors, BPB.sectors * BPB.bps).AppendLine();
|
||||
if (BPB.sectors > imagePlugin.GetSectors())
|
||||
sb.AppendFormat("WARNING: Filesystem describes a {0} sectors volume, bigger than device ({1} sectors)", BPB.sectors, imagePlugin.GetSectors());
|
||||
sb.AppendFormat("{0} heads", BPB.heads).AppendLine();
|
||||
sb.AppendFormat("{0} sectors per track", BPB.sptrk).AppendLine();
|
||||
sb.AppendFormat("Volume name: {0}", BPB.vol_name).AppendLine();
|
||||
|
||||
information = sb.ToString();
|
||||
}
|
||||
|
||||
public struct SolarOSParameterBlock
|
||||
{
|
||||
public byte[] x86_jump;
|
||||
// 0x00, x86 jump (3 bytes), jumps to 0x60
|
||||
public string OEMName;
|
||||
// 0x03, 8 bytes, "SOLAR_OS"
|
||||
public UInt16 bps;
|
||||
// 0x0B, Bytes per sector
|
||||
public byte unk1;
|
||||
// 0x0D, unknown, 0x01
|
||||
public UInt16 unk2;
|
||||
// 0x0E, unknown, 0x0201
|
||||
public UInt16 root_ent;
|
||||
// 0x10, Number of entries on root directory ? (no root directory found)
|
||||
public UInt16 sectors;
|
||||
// 0x12, Sectors in volume
|
||||
public byte media;
|
||||
// 0x14, Media descriptor
|
||||
public UInt16 spfat;
|
||||
// 0x15, Sectors per FAT ? (no FAT found)
|
||||
public UInt16 sptrk;
|
||||
// 0x17, Sectors per track
|
||||
public UInt16 heads;
|
||||
// 0x19, Heads
|
||||
public byte[] unk3;
|
||||
// 0x1B, unknown, 10 bytes, zero-filled
|
||||
public byte signature;
|
||||
// 0x25, 0x29
|
||||
public UInt32 unk4;
|
||||
// 0x26, unknown, zero-filled
|
||||
public string vol_name;
|
||||
// 0x2A, 11 bytes, volume name, space-padded
|
||||
public string fs_type;
|
||||
// 0x35, 8 bytes, "SOL_FS "
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,373 +0,0 @@
|
||||
/***************************************************************************
|
||||
The Disc Image Chef
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
Filename : Symbian.cs
|
||||
Version : 1.0
|
||||
Author(s) : Natalia Portillo
|
||||
|
||||
Component : Filesystem plugins
|
||||
|
||||
Revision : $Revision$
|
||||
Last change by : $Author$
|
||||
Date : $Date$
|
||||
|
||||
--[ Description ] ----------------------------------------------------------
|
||||
|
||||
Identifies Symbian installer (.sis) packages and shows information.
|
||||
|
||||
--[ License ] --------------------------------------------------------------
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
----------------------------------------------------------------------------
|
||||
Copyright (C) 2011-2014 Claunia.com
|
||||
****************************************************************************/
|
||||
//$Id$
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using DiscImageChef;
|
||||
using System.Collections.Generic;
|
||||
|
||||
// Information from http://www.thoukydides.webspace.virginmedia.com/software/psifs/sis.html
|
||||
// TODO: Implement support for disc images
|
||||
/*
|
||||
|
||||
namespace DiscImageChef.Plugins
|
||||
{
|
||||
class SymbianIS : Plugin
|
||||
{
|
||||
// Magics
|
||||
private const UInt32 SymbianMagic = 0x10000419;
|
||||
private const UInt32 EPOCMagic = 0x1000006D;
|
||||
private const UInt32 EPOC6Magic = 0x10003A12;
|
||||
private const UInt32 Symbian9Magic = 0x10201A7A;
|
||||
|
||||
// Options
|
||||
private const UInt16 IsUnicode = 0x0001;
|
||||
private const UInt16 IsDistributable = 0x0002;
|
||||
private const UInt16 NoCompress = 0x0008;
|
||||
private const UInt16 ShutdownApps = 0x0010;
|
||||
|
||||
// Types
|
||||
private const UInt16 SISApp = 0x0000; // Application
|
||||
private const UInt16 SISSystem = 0x0001; // System component (library)
|
||||
private const UInt16 SISOption = 0x0002; // Optional component
|
||||
private const UInt16 SISConfig = 0x0003; // Configures an application
|
||||
private const UInt16 SISPatch = 0x0004; // Patch
|
||||
private const UInt16 SISUpgrade = 0x0005; // Upgrade
|
||||
|
||||
private enum LanguageCodes
|
||||
{
|
||||
Test,
|
||||
EN,
|
||||
FR,
|
||||
GE,
|
||||
SP,
|
||||
IT,
|
||||
SW,
|
||||
DA,
|
||||
NO,
|
||||
FI,
|
||||
AM,
|
||||
SF,
|
||||
SG,
|
||||
PO,
|
||||
TU,
|
||||
IC,
|
||||
RU,
|
||||
HU,
|
||||
DU,
|
||||
BL,
|
||||
AU,
|
||||
BF,
|
||||
AS,
|
||||
NZ,
|
||||
IF,
|
||||
CS,
|
||||
SK,
|
||||
PL,
|
||||
SL,
|
||||
TC,
|
||||
HK,
|
||||
ZH,
|
||||
JA,
|
||||
TH,
|
||||
AF,
|
||||
SQ,
|
||||
AH,
|
||||
AR,
|
||||
HY,
|
||||
TL,
|
||||
BE,
|
||||
BN,
|
||||
BG,
|
||||
MY,
|
||||
CA,
|
||||
HR,
|
||||
CE,
|
||||
IE,
|
||||
ZA,
|
||||
ET,
|
||||
FA,
|
||||
CF,
|
||||
GD,
|
||||
KA,
|
||||
EL,
|
||||
CG,
|
||||
GU,
|
||||
HE,
|
||||
HI,
|
||||
IN,
|
||||
GA,
|
||||
SZ,
|
||||
KN,
|
||||
KK,
|
||||
KM,
|
||||
KO,
|
||||
LO,
|
||||
LV,
|
||||
LT,
|
||||
MK,
|
||||
MS,
|
||||
ML,
|
||||
MR,
|
||||
MO,
|
||||
MN,
|
||||
NN,
|
||||
BP,
|
||||
PA,
|
||||
RO,
|
||||
SR,
|
||||
SI,
|
||||
SO,
|
||||
OS,
|
||||
LS,
|
||||
SH,
|
||||
FS,
|
||||
TA,
|
||||
TE,
|
||||
BO,
|
||||
TI,
|
||||
CT,
|
||||
TK,
|
||||
UK,
|
||||
UR,
|
||||
VI,
|
||||
CY,
|
||||
ZU
|
||||
};
|
||||
|
||||
public SymbianIS(PluginBase Core)
|
||||
{
|
||||
base.Name = "Symbian Installation File Plugin";
|
||||
base.PluginUUID = new Guid("0ec84ec7-eae6-4196-83fe-943b3fe48dbd");
|
||||
}
|
||||
|
||||
public override bool Identify(FileStream fileStream, long offset)
|
||||
{
|
||||
UInt32 uid1, uid2, uid3;
|
||||
BinaryReader br = new BinaryReader(fileStream);
|
||||
|
||||
br.BaseStream.Seek(0 + offset, SeekOrigin.Begin);
|
||||
|
||||
uid1 = br.ReadUInt32();
|
||||
uid2 = br.ReadUInt32();
|
||||
uid3 = br.ReadUInt32();
|
||||
|
||||
if(uid1 == Symbian9Magic)
|
||||
return true;
|
||||
else if(uid3 == SymbianMagic)
|
||||
{
|
||||
if(uid2 == EPOCMagic || uid2 == EPOC6Magic)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public override void GetInformation (FileStream fileStream, long offset, out string information)
|
||||
{
|
||||
information = "";
|
||||
StringBuilder description = new StringBuilder();
|
||||
List<string> languages = new List<string>();
|
||||
Dictionary<UInt32, UInt32> capabilities = new Dictionary<UInt32, UInt32>();
|
||||
int ENpos = 0;
|
||||
UInt32 comp_len;
|
||||
UInt32 comp_name_ptr;
|
||||
byte[] ComponentName_b;
|
||||
string ComponentName = "";
|
||||
|
||||
SymbianHeader sh = new SymbianHeader();
|
||||
BinaryReader br = new BinaryReader(fileStream);
|
||||
|
||||
br.BaseStream.Seek(0 + offset, SeekOrigin.Begin);
|
||||
|
||||
sh.uid1 = br.ReadUInt32();
|
||||
sh.uid2 = br.ReadUInt32();
|
||||
sh.uid3 = br.ReadUInt32();
|
||||
sh.uid4 = br.ReadUInt32();
|
||||
sh.crc16 = br.ReadUInt16();
|
||||
sh.languages = br.ReadUInt16();
|
||||
sh.files = br.ReadUInt16();
|
||||
sh.requisites = br.ReadUInt16();
|
||||
sh.inst_lang = br.ReadUInt16();
|
||||
sh.inst_files = br.ReadUInt16();
|
||||
sh.inst_drive = br.ReadUInt16();
|
||||
sh.capabilities = br.ReadUInt16();
|
||||
sh.inst_version = br.ReadUInt32();
|
||||
sh.options = br.ReadUInt16();
|
||||
sh.type = br.ReadUInt16();
|
||||
sh.major = br.ReadUInt16();
|
||||
sh.minor = br.ReadUInt16();
|
||||
sh.variant = br.ReadUInt32();
|
||||
sh.lang_ptr = br.ReadUInt32();
|
||||
sh.files_ptr = br.ReadUInt32();
|
||||
sh.reqs_ptr = br.ReadUInt32();
|
||||
sh.certs_ptr = br.ReadUInt32();
|
||||
sh.comp_ptr = br.ReadUInt32();
|
||||
sh.sig_ptr = br.ReadUInt32();
|
||||
sh.caps_ptr = br.ReadUInt32();
|
||||
sh.instspace = br.ReadUInt32();
|
||||
sh.maxinsspc = br.ReadUInt32();
|
||||
sh.reserved1 = br.ReadUInt64();
|
||||
sh.reserved2 = br.ReadUInt64();
|
||||
|
||||
// Go to enumerate languages
|
||||
br.BaseStream.Seek(sh.lang_ptr + offset, SeekOrigin.Begin);
|
||||
for(int i = 0; i < sh.languages; i++)
|
||||
{
|
||||
UInt16 language = br.ReadUInt16();
|
||||
if(language == 0x0001)
|
||||
ENpos = i;
|
||||
languages.Add(((LanguageCodes)language).ToString("G"));
|
||||
}
|
||||
|
||||
// Go to component record
|
||||
br.BaseStream.Seek(sh.comp_ptr + offset, SeekOrigin.Begin);
|
||||
for(int i = 0; i < sh.languages; i++)
|
||||
{
|
||||
comp_len = br.ReadUInt32();
|
||||
comp_name_ptr = br.ReadUInt32();
|
||||
if(i == ENpos)
|
||||
{
|
||||
br.BaseStream.Seek(comp_name_ptr + offset, SeekOrigin.Begin);
|
||||
ComponentName_b = new byte[comp_len];
|
||||
ComponentName_b = br.ReadBytes((int)comp_len);
|
||||
ComponentName = Encoding.ASCII.GetString(ComponentName_b);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Go to capabilities (???)
|
||||
br.BaseStream.Seek(sh.caps_ptr + offset, SeekOrigin.Begin);
|
||||
for(int i = 0; i < sh.capabilities; i++)
|
||||
{
|
||||
UInt32 cap_key = br.ReadUInt32();
|
||||
UInt32 cap_value = br.ReadUInt32();
|
||||
capabilities.Add(cap_key, cap_value);
|
||||
}
|
||||
|
||||
if(sh.uid1 == Symbian9Magic)
|
||||
{
|
||||
description.AppendLine("Symbian Installation File");
|
||||
description.AppendLine("SymbianOS 9.1 or later");
|
||||
description.AppendFormat("Application ID: 0x{0:X8}", sh.uid3).AppendLine();
|
||||
description.AppendFormat("UIDs checksum: 0x{0:X8}", sh.uid4).AppendLine();
|
||||
}
|
||||
else if(sh.uid3 == SymbianMagic)
|
||||
{
|
||||
description.AppendLine("Symbian Installation File");
|
||||
|
||||
if(sh.uid2 == EPOCMagic)
|
||||
description.AppendLine("SymbianOS 3 or later");
|
||||
else if (sh.uid2 == EPOC6Magic)
|
||||
description.AppendLine("SymbianOS 6 or later");
|
||||
else
|
||||
description.AppendFormat("Unknown EPOC magic 0x{0:X8}", sh.uid2).AppendLine();
|
||||
|
||||
description.AppendFormat("Application ID: 0x{0:X8}", sh.uid1).AppendLine();
|
||||
description.AppendFormat("UIDs checksum: 0x{0:X8}", sh.uid4).AppendLine();
|
||||
description.AppendFormat("CRC16 of header: 0x{0:X4}", sh.crc16).AppendLine();
|
||||
description.AppendLine();
|
||||
|
||||
switch(sh.type)
|
||||
{
|
||||
case SISApp:
|
||||
description.AppendLine("SIS contains an application");
|
||||
break;
|
||||
}
|
||||
|
||||
description.AppendFormat("Component: {0} v{1}.{2}", ComponentName, sh.major, sh.minor).AppendLine();
|
||||
|
||||
description.AppendFormat("File contains {0} languages:", sh.languages).AppendLine();
|
||||
for(int i = 0; i < languages.Count; i++)
|
||||
{
|
||||
if(i>0)
|
||||
description.Append(", ");
|
||||
description.AppendFormat("{0}", languages[i]);
|
||||
}
|
||||
description.AppendLine();
|
||||
|
||||
description.AppendFormat("File contains {0} files (pointer: {1})", sh.files, sh.files_ptr).AppendLine();
|
||||
description.AppendFormat("File contains {0} requisites", sh.requisites).AppendLine();
|
||||
// description.AppendLine("Capabilities:");
|
||||
// foreach(KeyValuePair<UInt32, UInt32> kvp in capabilities)
|
||||
// description.AppendFormat("{0} = {1}", kvp.Key, kvp.Value).AppendLine();
|
||||
}
|
||||
|
||||
information = description.ToString();
|
||||
}
|
||||
|
||||
private struct SymbianHeader
|
||||
{
|
||||
public UInt32 uid1; // Application UID before SymbianOS 9, magic after
|
||||
public UInt32 uid2; // EPOC release magic before SOS 9, NULLs after
|
||||
public UInt32 uid3; // Application UID after SOS 9, magic before
|
||||
public UInt32 uid4; // Checksum of UIDs 1 to 3
|
||||
public UInt16 crc16; // CRC16 of all header
|
||||
public UInt16 languages; // Number of languages
|
||||
public UInt16 files; // Number of files
|
||||
public UInt16 requisites; // Number of requisites
|
||||
public UInt16 inst_lang; // Installed language (only residual SIS)
|
||||
public UInt16 inst_files; // Installed files (only residual SIS)
|
||||
public UInt16 inst_drive; // Installed drive (only residual SIS), NULL or 0x0021
|
||||
public UInt16 capabilities; // Number of capabilities
|
||||
public UInt32 inst_version; // Version of Symbian Installer required
|
||||
public UInt16 options; // Option flags
|
||||
public UInt16 type; // Type
|
||||
public UInt16 major; // Major version of application
|
||||
public UInt16 minor; // Minor version of application
|
||||
public UInt32 variant; // Variant when SIS is a prerequisite for other SISs
|
||||
public UInt32 lang_ptr; // Pointer to language records
|
||||
public UInt32 files_ptr; // Pointer to file records
|
||||
public UInt32 reqs_ptr; // Pointer to requisite records
|
||||
public UInt32 certs_ptr; // Pointer to certificate records
|
||||
public UInt32 comp_ptr; // Pointer to component name record
|
||||
// From EPOC Release 6
|
||||
public UInt32 sig_ptr; // Pointer to signature record
|
||||
public UInt32 caps_ptr; // Pointer to capability records
|
||||
public UInt32 instspace; // Installed space (only residual SIS)
|
||||
public UInt32 maxinsspc; // Space required
|
||||
public UInt64 reserved1; // Reserved
|
||||
public UInt64 reserved2; // Reserved
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
||||
@@ -1,812 +0,0 @@
|
||||
/***************************************************************************
|
||||
The Disc Image Chef
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
Filename : SysV.cs
|
||||
Version : 1.0
|
||||
Author(s) : Natalia Portillo
|
||||
|
||||
Component : Filesystem plugins
|
||||
|
||||
Revision : $Revision$
|
||||
Last change by : $Author$
|
||||
Date : $Date$
|
||||
|
||||
--[ Description ] ----------------------------------------------------------
|
||||
|
||||
Identifies UNIX System V filesystems and shows information.
|
||||
|
||||
--[ License ] --------------------------------------------------------------
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
----------------------------------------------------------------------------
|
||||
Copyright (C) 2011-2014 Claunia.com
|
||||
****************************************************************************/
|
||||
//$Id$
|
||||
|
||||
using System;
|
||||
using System.Text;
|
||||
using DiscImageChef;
|
||||
|
||||
// Information from the Linux kernel
|
||||
namespace DiscImageChef.Plugins
|
||||
{
|
||||
class SysVfs : Plugin
|
||||
{
|
||||
const UInt32 XENIX_MAGIC = 0x002B5544;
|
||||
const UInt32 XENIX_CIGAM = 0x44552B00;
|
||||
const UInt32 SYSV_MAGIC = 0xFD187E20;
|
||||
const UInt32 SYSV_CIGAM = 0xFD187E20;
|
||||
// Rest have no magic.
|
||||
// Per a Linux kernel, Coherent fs has following:
|
||||
const string COH_FNAME = "nonamexxxxx ";
|
||||
const string COH_FPACK = "nopackxxxxx\n";
|
||||
// SCO AFS
|
||||
const UInt16 SCO_NFREE = 0xFFFF;
|
||||
// UNIX 7th Edition has nothing to detect it, so check for a valid filesystem is a must :(
|
||||
const UInt16 V7_NICINOD = 100;
|
||||
const UInt16 V7_NICFREE = 50;
|
||||
const UInt32 V7_MAXSIZE = 0x00FFFFFF;
|
||||
|
||||
public SysVfs(PluginBase Core)
|
||||
{
|
||||
Name = "UNIX System V filesystem";
|
||||
PluginUUID = new Guid("9B8D016A-8561-400E-A12A-A198283C211D");
|
||||
}
|
||||
|
||||
public override bool Identify(ImagePlugins.ImagePlugin imagePlugin, ulong partitionStart, ulong partitionEnd)
|
||||
{
|
||||
if ((2 + partitionStart) >= imagePlugin.GetSectors())
|
||||
return false;
|
||||
|
||||
UInt32 magic;
|
||||
string s_fname, s_fpack;
|
||||
UInt16 s_nfree, s_ninode;
|
||||
UInt32 s_fsize;
|
||||
|
||||
/*for(int j = 0; j<=(br.BaseStream.Length/0x200); j++)
|
||||
{
|
||||
br.BaseStream.Seek(offset + j*0x200 + 0x1F8, SeekOrigin.Begin); // System V magic location
|
||||
magic = br.ReadUInt32();
|
||||
|
||||
if(magic == SYSV_MAGIC || magic == SYSV_CIGAM)
|
||||
Console.WriteLine("0x{0:X8}: 0x{1:X8} FOUND", br.BaseStream.Position-4, magic);
|
||||
else
|
||||
Console.WriteLine("0x{0:X8}: 0x{1:X8}", br.BaseStream.Position-4, magic);
|
||||
}*/
|
||||
|
||||
/*UInt32 number;
|
||||
br.BaseStream.Seek(offset+0x3A00, SeekOrigin.Begin);
|
||||
while((br.BaseStream.Position) <= (offset+0x3C00))
|
||||
{
|
||||
number = br.ReadUInt32();
|
||||
|
||||
Console.WriteLine("@{0:X8}: 0x{1:X8} ({1})", br.BaseStream.Position-offset-4, number);
|
||||
}*/
|
||||
|
||||
byte sb_size_in_sectors;
|
||||
|
||||
if (imagePlugin.GetSectorSize() <= 0x400) // Check if underlying device sector size is smaller than SuperBlock size
|
||||
sb_size_in_sectors = (byte)(0x400 / imagePlugin.GetSectorSize());
|
||||
else
|
||||
sb_size_in_sectors = 1; // If not a single sector can store it
|
||||
|
||||
if (imagePlugin.GetSectors() <= (partitionStart + 4 * (ulong)sb_size_in_sectors + (ulong)sb_size_in_sectors)) // Device must be bigger than SB location + SB size + offset
|
||||
return false;
|
||||
|
||||
// Superblock can start on 0x000, 0x200, 0x600 and 0x800, not aligned, so we assume 16 (128 bytes/sector) sectors as a safe value
|
||||
for (int i = 0; i <= 16; i++)
|
||||
{
|
||||
byte[] sb_sector = imagePlugin.ReadSectors((ulong)i + partitionStart, sb_size_in_sectors);
|
||||
|
||||
magic = BitConverter.ToUInt32(sb_sector, 0x3F8); // XENIX magic location
|
||||
|
||||
if (magic == XENIX_MAGIC || magic == XENIX_CIGAM)
|
||||
return true;
|
||||
|
||||
magic = BitConverter.ToUInt32(sb_sector, 0x1F8); // System V magic location
|
||||
|
||||
if (magic == SYSV_MAGIC || magic == SYSV_CIGAM)
|
||||
return true;
|
||||
|
||||
byte[] coherent_string = new byte[6];
|
||||
Array.Copy(sb_sector, 0x1E8, coherent_string, 0, 6); // Coherent UNIX s_fname location
|
||||
s_fname = StringHandlers.CToString(coherent_string);
|
||||
Array.Copy(sb_sector, 0x1EE, coherent_string, 0, 6); // Coherent UNIX s_fpack location
|
||||
s_fpack = StringHandlers.CToString(coherent_string);
|
||||
|
||||
if (s_fname == COH_FNAME || s_fpack == COH_FPACK)
|
||||
return true;
|
||||
|
||||
// Now try to identify 7th edition
|
||||
s_fsize = BitConverter.ToUInt32(sb_sector, 0x002); // 7th edition's s_fsize
|
||||
s_nfree = BitConverter.ToUInt16(sb_sector, 0x006); // 7th edition's s_nfree
|
||||
s_ninode = BitConverter.ToUInt16(sb_sector, 0x0D0); // 7th edition's s_ninode
|
||||
|
||||
if (s_fsize > 0 && s_fsize < 0xFFFFFFFF && s_nfree > 0 && s_nfree < 0xFFFF && s_ninode > 0 && s_ninode < 0xFFFF)
|
||||
{
|
||||
if ((s_fsize & 0xFF) == 0x00 && (s_nfree & 0xFF) == 0x00 && (s_ninode & 0xFF) == 0x00)
|
||||
{
|
||||
// Byteswap
|
||||
s_fsize = ((s_fsize & 0xFF) << 24) + ((s_fsize & 0xFF00) << 8) + ((s_fsize & 0xFF0000) >> 8) + ((s_fsize & 0xFF000000) >> 24);
|
||||
s_nfree = (UInt16)(s_nfree >> 8);
|
||||
s_ninode = (UInt16)(s_ninode >> 8);
|
||||
}
|
||||
|
||||
if ((s_fsize & 0xFF000000) == 0x00 && (s_nfree & 0xFF00) == 0x00 && (s_ninode & 0xFF00) == 0x00)
|
||||
{
|
||||
if (s_fsize < V7_MAXSIZE && s_nfree < V7_NICFREE && s_ninode < V7_NICINOD)
|
||||
{
|
||||
if ((s_fsize * 1024) <= (imagePlugin.GetSectors() * imagePlugin.GetSectorSize()) || (s_fsize * 512) <= (imagePlugin.GetSectors() * imagePlugin.GetSectorSize()))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public override void GetInformation(ImagePlugins.ImagePlugin imagePlugin, ulong partitionStart, ulong partitionEnd, out string information)
|
||||
{
|
||||
information = "";
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
BigEndianBitConverter.IsLittleEndian = true; // Start in little endian until we know what are we handling here
|
||||
int start;
|
||||
UInt32 magic;
|
||||
string s_fname, s_fpack;
|
||||
UInt16 s_nfree, s_ninode;
|
||||
UInt32 s_fsize;
|
||||
bool xenix = false;
|
||||
bool sysv = false;
|
||||
bool sysvr4 = false;
|
||||
bool sys7th = false;
|
||||
bool coherent = false;
|
||||
byte[] sb_sector;
|
||||
byte sb_size_in_sectors;
|
||||
|
||||
if (imagePlugin.GetSectorSize() <= 0x400) // Check if underlying device sector size is smaller than SuperBlock size
|
||||
sb_size_in_sectors = (byte)(0x400 / imagePlugin.GetSectorSize());
|
||||
else
|
||||
sb_size_in_sectors = 1; // If not a single sector can store it
|
||||
|
||||
// Superblock can start on 0x000, 0x200, 0x600 and 0x800, not aligned, so we assume 16 (128 bytes/sector) sectors as a safe value
|
||||
for (start = 0; start <= 16; start++)
|
||||
{
|
||||
sb_sector = imagePlugin.ReadSectors((ulong)start + partitionStart, sb_size_in_sectors);
|
||||
magic = BigEndianBitConverter.ToUInt32(sb_sector, 0x3F8); // XENIX magic location
|
||||
|
||||
if (magic == XENIX_MAGIC)
|
||||
{
|
||||
BigEndianBitConverter.IsLittleEndian = true; // Little endian
|
||||
xenix = true;
|
||||
break;
|
||||
}
|
||||
if (magic == XENIX_CIGAM)
|
||||
{
|
||||
BigEndianBitConverter.IsLittleEndian = false; // Big endian
|
||||
xenix = true;
|
||||
break;
|
||||
}
|
||||
|
||||
magic = BigEndianBitConverter.ToUInt32(sb_sector, 0x1F8); // XENIX magic location
|
||||
|
||||
if (magic == SYSV_MAGIC)
|
||||
{
|
||||
BigEndianBitConverter.IsLittleEndian = true; // Little endian
|
||||
sysv = true;
|
||||
break;
|
||||
}
|
||||
if (magic == SYSV_CIGAM)
|
||||
{
|
||||
BigEndianBitConverter.IsLittleEndian = false; // Big endian
|
||||
sysv = true;
|
||||
break;
|
||||
}
|
||||
|
||||
byte[] coherent_string = new byte[6];
|
||||
Array.Copy(sb_sector, 0x1E8, coherent_string, 0, 6); // Coherent UNIX s_fname location
|
||||
s_fname = StringHandlers.CToString(coherent_string);
|
||||
Array.Copy(sb_sector, 0x1EE, coherent_string, 0, 6); // Coherent UNIX s_fpack location
|
||||
s_fpack = StringHandlers.CToString(coherent_string);
|
||||
|
||||
if (s_fname == COH_FNAME || s_fpack == COH_FPACK)
|
||||
{
|
||||
BigEndianBitConverter.IsLittleEndian = true; // Coherent is in PDP endianness, use helper for that
|
||||
coherent = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// Now try to identify 7th edition
|
||||
s_fsize = BitConverter.ToUInt32(sb_sector, 0x002); // 7th edition's s_fsize
|
||||
s_nfree = BitConverter.ToUInt16(sb_sector, 0x006); // 7th edition's s_nfree
|
||||
s_ninode = BitConverter.ToUInt16(sb_sector, 0x0D0); // 7th edition's s_ninode
|
||||
|
||||
if (s_fsize > 0 && s_fsize < 0xFFFFFFFF && s_nfree > 0 && s_nfree < 0xFFFF && s_ninode > 0 && s_ninode < 0xFFFF)
|
||||
{
|
||||
if ((s_fsize & 0xFF) == 0x00 && (s_nfree & 0xFF) == 0x00 && (s_ninode & 0xFF) == 0x00)
|
||||
{
|
||||
// Byteswap
|
||||
s_fsize = ((s_fsize & 0xFF) << 24) + ((s_fsize & 0xFF00) << 8) + ((s_fsize & 0xFF0000) >> 8) + ((s_fsize & 0xFF000000) >> 24);
|
||||
s_nfree = (UInt16)(s_nfree >> 8);
|
||||
s_ninode = (UInt16)(s_ninode >> 8);
|
||||
}
|
||||
|
||||
if ((s_fsize & 0xFF000000) == 0x00 && (s_nfree & 0xFF00) == 0x00 && (s_ninode & 0xFF00) == 0x00)
|
||||
{
|
||||
if (s_fsize < V7_MAXSIZE && s_nfree < V7_NICFREE && s_ninode < V7_NICINOD)
|
||||
{
|
||||
if ((s_fsize * 1024) <= (imagePlugin.GetSectors() * imagePlugin.GetSectorSize()) || (s_fsize * 512) <= (imagePlugin.GetSectors() * imagePlugin.GetSectorSize()))
|
||||
{
|
||||
sys7th = true;
|
||||
BigEndianBitConverter.IsLittleEndian = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!sys7th && !sysv && !coherent && !xenix)
|
||||
return;
|
||||
|
||||
if (xenix)
|
||||
{
|
||||
byte[] xenix_strings = new byte[6];
|
||||
XenixSuperBlock xnx_sb = new XenixSuperBlock();
|
||||
sb_sector = imagePlugin.ReadSectors((ulong)start + partitionStart, sb_size_in_sectors);
|
||||
|
||||
xnx_sb.s_isize = BigEndianBitConverter.ToUInt16(sb_sector, 0x000);
|
||||
xnx_sb.s_fsize = BigEndianBitConverter.ToUInt32(sb_sector, 0x002);
|
||||
xnx_sb.s_nfree = BigEndianBitConverter.ToUInt16(sb_sector, 0x006);
|
||||
xnx_sb.s_ninode = BigEndianBitConverter.ToUInt16(sb_sector, 0x198);
|
||||
xnx_sb.s_flock = sb_sector[0x262];
|
||||
xnx_sb.s_ilock = sb_sector[0x263];
|
||||
xnx_sb.s_fmod = sb_sector[0x264];
|
||||
xnx_sb.s_ronly = sb_sector[0x265];
|
||||
xnx_sb.s_time = BigEndianBitConverter.ToUInt32(sb_sector, 0x266);
|
||||
xnx_sb.s_tfree = BigEndianBitConverter.ToUInt32(sb_sector, 0x26A);
|
||||
xnx_sb.s_tinode = BigEndianBitConverter.ToUInt16(sb_sector, 0x26E);
|
||||
xnx_sb.s_cylblks = BigEndianBitConverter.ToUInt16(sb_sector, 0x270);
|
||||
xnx_sb.s_gapblks = BigEndianBitConverter.ToUInt16(sb_sector, 0x272);
|
||||
xnx_sb.s_dinfo0 = BigEndianBitConverter.ToUInt16(sb_sector, 0x274);
|
||||
xnx_sb.s_dinfo1 = BigEndianBitConverter.ToUInt16(sb_sector, 0x276);
|
||||
Array.Copy(sb_sector, 0x278, xenix_strings, 0, 6);
|
||||
xnx_sb.s_fname = StringHandlers.CToString(xenix_strings);
|
||||
Array.Copy(sb_sector, 0x27E, xenix_strings, 0, 6);
|
||||
xnx_sb.s_fpack = StringHandlers.CToString(xenix_strings);
|
||||
xnx_sb.s_clean = sb_sector[0x284];
|
||||
xnx_sb.s_magic = BigEndianBitConverter.ToUInt32(sb_sector, 0x3F8);
|
||||
xnx_sb.s_type = BigEndianBitConverter.ToUInt32(sb_sector, 0x3FC);
|
||||
|
||||
UInt32 bs = 512;
|
||||
sb.AppendLine("XENIX filesystem");
|
||||
switch (xnx_sb.s_type)
|
||||
{
|
||||
case 1:
|
||||
sb.AppendLine("512 bytes per block");
|
||||
break;
|
||||
case 2:
|
||||
sb.AppendLine("1024 bytes per block");
|
||||
bs = 1024;
|
||||
break;
|
||||
case 3:
|
||||
sb.AppendLine("2048 bytes per block");
|
||||
bs = 2048;
|
||||
break;
|
||||
default:
|
||||
sb.AppendFormat("Unknown s_type value: 0x{0:X8}", xnx_sb.s_type).AppendLine();
|
||||
break;
|
||||
}
|
||||
if (imagePlugin.GetSectorSize() == 2336 || imagePlugin.GetSectorSize() == 2352 || imagePlugin.GetSectorSize() == 2448)
|
||||
{
|
||||
if (bs != 2048)
|
||||
sb.AppendFormat("WARNING: Filesystem indicates {0} bytes/block while device indicates {1} bytes/sector", bs, 2048).AppendLine();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (bs != imagePlugin.GetSectorSize())
|
||||
sb.AppendFormat("WARNING: Filesystem indicates {0} bytes/block while device indicates {1} bytes/sector", bs, imagePlugin.GetSectorSize()).AppendLine();
|
||||
}
|
||||
sb.AppendFormat("{0} zones on volume ({1} bytes)", xnx_sb.s_fsize, xnx_sb.s_fsize * bs).AppendLine();
|
||||
sb.AppendFormat("{0} free zones on volume ({1} bytes)", xnx_sb.s_tfree, xnx_sb.s_tfree * bs).AppendLine();
|
||||
sb.AppendFormat("{0} free blocks on list ({1} bytes)", xnx_sb.s_nfree, xnx_sb.s_nfree * bs).AppendLine();
|
||||
sb.AppendFormat("{0} blocks per cylinder ({1} bytes)", xnx_sb.s_cylblks, xnx_sb.s_cylblks * bs).AppendLine();
|
||||
sb.AppendFormat("{0} blocks per gap ({1} bytes)", xnx_sb.s_gapblks, xnx_sb.s_gapblks * bs).AppendLine();
|
||||
sb.AppendFormat("First data zone: {0}", xnx_sb.s_isize).AppendLine();
|
||||
sb.AppendFormat("{0} free inodes on volume", xnx_sb.s_tinode).AppendLine();
|
||||
sb.AppendFormat("{0} free inodes on list", xnx_sb.s_ninode).AppendLine();
|
||||
if (xnx_sb.s_flock > 0)
|
||||
sb.AppendLine("Free block list is locked");
|
||||
if (xnx_sb.s_ilock > 0)
|
||||
sb.AppendLine("inode cache is locked");
|
||||
if (xnx_sb.s_fmod > 0)
|
||||
sb.AppendLine("Superblock is being modified");
|
||||
if (xnx_sb.s_ronly > 0)
|
||||
sb.AppendLine("Volume is mounted read-only");
|
||||
sb.AppendFormat("Superblock last updated on {0}", DateHandlers.UNIXUnsignedToDateTime(xnx_sb.s_time)).AppendLine();
|
||||
sb.AppendFormat("Volume name: {0}", xnx_sb.s_fname).AppendLine();
|
||||
sb.AppendFormat("Pack name: {0}", xnx_sb.s_fpack).AppendLine();
|
||||
if (xnx_sb.s_clean == 0x46)
|
||||
sb.AppendLine("Volume is clean");
|
||||
else
|
||||
sb.AppendLine("Volume is dirty");
|
||||
}
|
||||
|
||||
if (sysv)
|
||||
{
|
||||
sb_sector = imagePlugin.ReadSectors((ulong)start + partitionStart, sb_size_in_sectors);
|
||||
UInt16 pad0, pad1, pad2;
|
||||
byte[] sysv_strings = new byte[6];
|
||||
|
||||
pad0 = BigEndianBitConverter.ToUInt16(sb_sector, 0x002); // First padding
|
||||
pad1 = BigEndianBitConverter.ToUInt16(sb_sector, 0x00A); // Second padding
|
||||
pad2 = BigEndianBitConverter.ToUInt16(sb_sector, 0x0D6); // Third padding
|
||||
|
||||
// This detection is not working as expected
|
||||
sysvr4 |= pad0 == 0 && pad1 == 0 && pad2 == 0;
|
||||
|
||||
SystemVRelease4SuperBlock sysv_sb = new SystemVRelease4SuperBlock();
|
||||
|
||||
// Common offsets
|
||||
sysv_sb.s_isize = BigEndianBitConverter.ToUInt16(sb_sector, 0x000);
|
||||
sysv_sb.s_state = BigEndianBitConverter.ToUInt32(sb_sector, 0x1F4);
|
||||
sysv_sb.s_magic = BigEndianBitConverter.ToUInt32(sb_sector, 0x1F8);
|
||||
sysv_sb.s_type = BigEndianBitConverter.ToUInt32(sb_sector, 0x1FC);
|
||||
|
||||
if (sysvr4)
|
||||
{
|
||||
sysv_sb.s_fsize = BigEndianBitConverter.ToUInt32(sb_sector, 0x004);
|
||||
sysv_sb.s_nfree = BigEndianBitConverter.ToUInt16(sb_sector, 0x008);
|
||||
sysv_sb.s_ninode = BigEndianBitConverter.ToUInt16(sb_sector, 0x0D4);
|
||||
sysv_sb.s_flock = sb_sector[0x1A0];
|
||||
sysv_sb.s_ilock = sb_sector[0x1A1];
|
||||
sysv_sb.s_fmod = sb_sector[0x1A2];
|
||||
sysv_sb.s_ronly = sb_sector[0x1A3];
|
||||
sysv_sb.s_time = BigEndianBitConverter.ToUInt32(sb_sector, 0x1A4);
|
||||
sysv_sb.s_cylblks = BigEndianBitConverter.ToUInt16(sb_sector, 0x1A8);
|
||||
sysv_sb.s_gapblks = BigEndianBitConverter.ToUInt16(sb_sector, 0x1AA);
|
||||
sysv_sb.s_dinfo0 = BigEndianBitConverter.ToUInt16(sb_sector, 0x1AC);
|
||||
sysv_sb.s_dinfo1 = BigEndianBitConverter.ToUInt16(sb_sector, 0x1AE);
|
||||
sysv_sb.s_tfree = BigEndianBitConverter.ToUInt32(sb_sector, 0x1B0);
|
||||
sysv_sb.s_tinode = BigEndianBitConverter.ToUInt16(sb_sector, 0x1B4);
|
||||
Array.Copy(sb_sector, 0x1B8, sysv_strings, 0, 6);
|
||||
sysv_sb.s_fname = StringHandlers.CToString(sysv_strings);
|
||||
Array.Copy(sb_sector, 0x1BE, sysv_strings, 0, 6);
|
||||
sysv_sb.s_fpack = StringHandlers.CToString(sysv_strings);
|
||||
}
|
||||
else
|
||||
{
|
||||
sysv_sb.s_fsize = BigEndianBitConverter.ToUInt32(sb_sector, 0x002);
|
||||
sysv_sb.s_nfree = BigEndianBitConverter.ToUInt16(sb_sector, 0x006);
|
||||
sysv_sb.s_ninode = BigEndianBitConverter.ToUInt16(sb_sector, 0x0D0);
|
||||
sysv_sb.s_flock = sb_sector[0x19A];
|
||||
sysv_sb.s_ilock = sb_sector[0x19B];
|
||||
sysv_sb.s_fmod = sb_sector[0x19C];
|
||||
sysv_sb.s_ronly = sb_sector[0x19D];
|
||||
sysv_sb.s_time = BigEndianBitConverter.ToUInt32(sb_sector, 0x19E);
|
||||
sysv_sb.s_cylblks = BigEndianBitConverter.ToUInt16(sb_sector, 0x1A2);
|
||||
sysv_sb.s_gapblks = BigEndianBitConverter.ToUInt16(sb_sector, 0x1A4);
|
||||
sysv_sb.s_dinfo0 = BigEndianBitConverter.ToUInt16(sb_sector, 0x1A6);
|
||||
sysv_sb.s_dinfo1 = BigEndianBitConverter.ToUInt16(sb_sector, 0x1A8);
|
||||
sysv_sb.s_tfree = BigEndianBitConverter.ToUInt32(sb_sector, 0x1AA);
|
||||
sysv_sb.s_tinode = BigEndianBitConverter.ToUInt16(sb_sector, 0x1AE);
|
||||
Array.Copy(sb_sector, 0x1B0, sysv_strings, 0, 6);
|
||||
sysv_sb.s_fname = StringHandlers.CToString(sysv_strings);
|
||||
Array.Copy(sb_sector, 0x1B6, sysv_strings, 0, 6);
|
||||
sysv_sb.s_fpack = StringHandlers.CToString(sysv_strings);
|
||||
}
|
||||
|
||||
UInt32 bs = 512;
|
||||
if (sysvr4)
|
||||
sb.AppendLine("System V Release 4 filesystem");
|
||||
else
|
||||
sb.AppendLine("System V Release 2 filesystem");
|
||||
switch (sysv_sb.s_type)
|
||||
{
|
||||
case 1:
|
||||
sb.AppendLine("512 bytes per block");
|
||||
break;
|
||||
case 2:
|
||||
sb.AppendLine("1024 bytes per block");
|
||||
bs = 1024;
|
||||
break;
|
||||
case 3:
|
||||
sb.AppendLine("2048 bytes per block");
|
||||
bs = 2048;
|
||||
break;
|
||||
default:
|
||||
sb.AppendFormat("Unknown s_type value: 0x{0:X8}", sysv_sb.s_type).AppendLine();
|
||||
break;
|
||||
}
|
||||
if (imagePlugin.GetSectorSize() == 2336 || imagePlugin.GetSectorSize() == 2352 || imagePlugin.GetSectorSize() == 2448)
|
||||
{
|
||||
if (bs != 2048)
|
||||
sb.AppendFormat("WARNING: Filesystem indicates {0} bytes/block while device indicates {1} bytes/sector", bs, 2048).AppendLine();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (bs != imagePlugin.GetSectorSize())
|
||||
sb.AppendFormat("WARNING: Filesystem indicates {0} bytes/block while device indicates {1} bytes/sector", bs, imagePlugin.GetSectorSize()).AppendLine();
|
||||
}
|
||||
sb.AppendFormat("{0} zones on volume ({1} bytes)", sysv_sb.s_fsize, sysv_sb.s_fsize * bs).AppendLine();
|
||||
sb.AppendFormat("{0} free zones on volume ({1} bytes)", sysv_sb.s_tfree, sysv_sb.s_tfree * bs).AppendLine();
|
||||
sb.AppendFormat("{0} free blocks on list ({1} bytes)", sysv_sb.s_nfree, sysv_sb.s_nfree * bs).AppendLine();
|
||||
sb.AppendFormat("{0} blocks per cylinder ({1} bytes)", sysv_sb.s_cylblks, sysv_sb.s_cylblks * bs).AppendLine();
|
||||
sb.AppendFormat("{0} blocks per gap ({1} bytes)", sysv_sb.s_gapblks, sysv_sb.s_gapblks * bs).AppendLine();
|
||||
sb.AppendFormat("First data zone: {0}", sysv_sb.s_isize).AppendLine();
|
||||
sb.AppendFormat("{0} free inodes on volume", sysv_sb.s_tinode).AppendLine();
|
||||
sb.AppendFormat("{0} free inodes on list", sysv_sb.s_ninode).AppendLine();
|
||||
if (sysv_sb.s_flock > 0)
|
||||
sb.AppendLine("Free block list is locked");
|
||||
if (sysv_sb.s_ilock > 0)
|
||||
sb.AppendLine("inode cache is locked");
|
||||
if (sysv_sb.s_fmod > 0)
|
||||
sb.AppendLine("Superblock is being modified");
|
||||
if (sysv_sb.s_ronly > 0)
|
||||
sb.AppendLine("Volume is mounted read-only");
|
||||
sb.AppendFormat("Superblock last updated on {0}", DateHandlers.UNIXUnsignedToDateTime(sysv_sb.s_time)).AppendLine();
|
||||
sb.AppendFormat("Volume name: {0}", sysv_sb.s_fname).AppendLine();
|
||||
sb.AppendFormat("Pack name: {0}", sysv_sb.s_fpack).AppendLine();
|
||||
if (sysv_sb.s_state == (0x7C269D38 - sysv_sb.s_time))
|
||||
sb.AppendLine("Volume is clean");
|
||||
else
|
||||
sb.AppendLine("Volume is dirty");
|
||||
}
|
||||
|
||||
if (coherent)
|
||||
{
|
||||
sb_sector = imagePlugin.ReadSectors((ulong)start + partitionStart, sb_size_in_sectors);
|
||||
CoherentSuperBlock coh_sb = new CoherentSuperBlock();
|
||||
byte[] coh_strings = new byte[6];
|
||||
|
||||
coh_sb.s_isize = BigEndianBitConverter.ToUInt16(sb_sector, 0x000);
|
||||
coh_sb.s_fsize = Swapping.PDPFromLittleEndian(BigEndianBitConverter.ToUInt32(sb_sector, 0x002));
|
||||
coh_sb.s_nfree = BigEndianBitConverter.ToUInt16(sb_sector, 0x006);
|
||||
coh_sb.s_ninode = BigEndianBitConverter.ToUInt16(sb_sector, 0x108);
|
||||
coh_sb.s_flock = sb_sector[0x1D2];
|
||||
coh_sb.s_ilock = sb_sector[0x1D3];
|
||||
coh_sb.s_fmod = sb_sector[0x1D4];
|
||||
coh_sb.s_ronly = sb_sector[0x1D5];
|
||||
coh_sb.s_time = Swapping.PDPFromLittleEndian(BigEndianBitConverter.ToUInt32(sb_sector, 0x1D6));
|
||||
coh_sb.s_tfree = Swapping.PDPFromLittleEndian(BigEndianBitConverter.ToUInt32(sb_sector, 0x1DE));
|
||||
coh_sb.s_tinode = BigEndianBitConverter.ToUInt16(sb_sector, 0x1E2);
|
||||
coh_sb.s_int_m = BigEndianBitConverter.ToUInt16(sb_sector, 0x1E4);
|
||||
coh_sb.s_int_n = BigEndianBitConverter.ToUInt16(sb_sector, 0x1E6);
|
||||
Array.Copy(sb_sector, 0x1E8, coh_strings, 0, 6);
|
||||
coh_sb.s_fname = StringHandlers.CToString(coh_strings);
|
||||
Array.Copy(sb_sector, 0x1EE, coh_strings, 0, 6);
|
||||
coh_sb.s_fpack = StringHandlers.CToString(coh_strings);
|
||||
|
||||
sb.AppendLine("Coherent UNIX filesystem");
|
||||
if (imagePlugin.GetSectorSize() != 512)
|
||||
sb.AppendFormat("WARNING: Filesystem indicates {0} bytes/block while device indicates {1} bytes/sector", 512, 2048).AppendLine();
|
||||
sb.AppendFormat("{0} zones on volume ({1} bytes)", coh_sb.s_fsize, coh_sb.s_fsize * 512).AppendLine();
|
||||
sb.AppendFormat("{0} free zones on volume ({1} bytes)", coh_sb.s_tfree, coh_sb.s_tfree * 512).AppendLine();
|
||||
sb.AppendFormat("{0} free blocks on list ({1} bytes)", coh_sb.s_nfree, coh_sb.s_nfree * 512).AppendLine();
|
||||
sb.AppendFormat("First data zone: {0}", coh_sb.s_isize).AppendLine();
|
||||
sb.AppendFormat("{0} free inodes on volume", coh_sb.s_tinode).AppendLine();
|
||||
sb.AppendFormat("{0} free inodes on list", coh_sb.s_ninode).AppendLine();
|
||||
if (coh_sb.s_flock > 0)
|
||||
sb.AppendLine("Free block list is locked");
|
||||
if (coh_sb.s_ilock > 0)
|
||||
sb.AppendLine("inode cache is locked");
|
||||
if (coh_sb.s_fmod > 0)
|
||||
sb.AppendLine("Superblock is being modified");
|
||||
if (coh_sb.s_ronly > 0)
|
||||
sb.AppendLine("Volume is mounted read-only");
|
||||
sb.AppendFormat("Superblock last updated on {0}", DateHandlers.UNIXUnsignedToDateTime(coh_sb.s_time)).AppendLine();
|
||||
sb.AppendFormat("Volume name: {0}", coh_sb.s_fname).AppendLine();
|
||||
sb.AppendFormat("Pack name: {0}", coh_sb.s_fpack).AppendLine();
|
||||
}
|
||||
|
||||
if (sys7th)
|
||||
{
|
||||
sb_sector = imagePlugin.ReadSectors((ulong)start + partitionStart, sb_size_in_sectors);
|
||||
UNIX7thEditionSuperBlock v7_sb = new UNIX7thEditionSuperBlock();
|
||||
byte[] sys7_strings = new byte[6];
|
||||
|
||||
v7_sb.s_isize = BigEndianBitConverter.ToUInt16(sb_sector, 0x000);
|
||||
v7_sb.s_fsize = BigEndianBitConverter.ToUInt32(sb_sector, 0x002);
|
||||
v7_sb.s_nfree = BigEndianBitConverter.ToUInt16(sb_sector, 0x006);
|
||||
v7_sb.s_ninode = BigEndianBitConverter.ToUInt16(sb_sector, 0x0D0);
|
||||
v7_sb.s_flock = sb_sector[0x19A];
|
||||
v7_sb.s_ilock = sb_sector[0x19B];
|
||||
v7_sb.s_fmod = sb_sector[0x19C];
|
||||
v7_sb.s_ronly = sb_sector[0x19D];
|
||||
v7_sb.s_time = BigEndianBitConverter.ToUInt32(sb_sector, 0x19E);
|
||||
v7_sb.s_tfree = BigEndianBitConverter.ToUInt32(sb_sector, 0x1A2);
|
||||
v7_sb.s_tinode = BigEndianBitConverter.ToUInt16(sb_sector, 0x1A6);
|
||||
v7_sb.s_int_m = BigEndianBitConverter.ToUInt16(sb_sector, 0x1A8);
|
||||
v7_sb.s_int_n = BigEndianBitConverter.ToUInt16(sb_sector, 0x1AA);
|
||||
Array.Copy(sb_sector, 0x1AC, sys7_strings, 0, 6);
|
||||
v7_sb.s_fname = StringHandlers.CToString(sys7_strings);
|
||||
Array.Copy(sb_sector, 0x1B2, sys7_strings, 0, 6);
|
||||
v7_sb.s_fpack = StringHandlers.CToString(sys7_strings);
|
||||
|
||||
sb.AppendLine("UNIX 7th Edition filesystem");
|
||||
if (imagePlugin.GetSectorSize() != 512)
|
||||
sb.AppendFormat("WARNING: Filesystem indicates {0} bytes/block while device indicates {1} bytes/sector", 512, 2048).AppendLine();
|
||||
sb.AppendFormat("{0} zones on volume ({1} bytes)", v7_sb.s_fsize, v7_sb.s_fsize * 512).AppendLine();
|
||||
sb.AppendFormat("{0} free zones on volume ({1} bytes)", v7_sb.s_tfree, v7_sb.s_tfree * 512).AppendLine();
|
||||
sb.AppendFormat("{0} free blocks on list ({1} bytes)", v7_sb.s_nfree, v7_sb.s_nfree * 512).AppendLine();
|
||||
sb.AppendFormat("First data zone: {0}", v7_sb.s_isize).AppendLine();
|
||||
sb.AppendFormat("{0} free inodes on volume", v7_sb.s_tinode).AppendLine();
|
||||
sb.AppendFormat("{0} free inodes on list", v7_sb.s_ninode).AppendLine();
|
||||
if (v7_sb.s_flock > 0)
|
||||
sb.AppendLine("Free block list is locked");
|
||||
if (v7_sb.s_ilock > 0)
|
||||
sb.AppendLine("inode cache is locked");
|
||||
if (v7_sb.s_fmod > 0)
|
||||
sb.AppendLine("Superblock is being modified");
|
||||
if (v7_sb.s_ronly > 0)
|
||||
sb.AppendLine("Volume is mounted read-only");
|
||||
sb.AppendFormat("Superblock last updated on {0}", DateHandlers.UNIXUnsignedToDateTime(v7_sb.s_time)).AppendLine();
|
||||
sb.AppendFormat("Volume name: {0}", v7_sb.s_fname).AppendLine();
|
||||
sb.AppendFormat("Pack name: {0}", v7_sb.s_fpack).AppendLine();
|
||||
}
|
||||
|
||||
information = sb.ToString();
|
||||
|
||||
BigEndianBitConverter.IsLittleEndian = false; // Return to default (bigendian)
|
||||
}
|
||||
|
||||
struct XenixSuperBlock
|
||||
{
|
||||
public UInt16 s_isize;
|
||||
// 0x000, index of first data zone
|
||||
public UInt32 s_fsize;
|
||||
// 0x002, total number of zones of this volume
|
||||
// the start of the free block list:
|
||||
public UInt16 s_nfree;
|
||||
// 0x006, blocks in s_free, <=100
|
||||
public UInt32[] s_free;
|
||||
// 0x008, 100 entries, first free block list chunk
|
||||
// the cache of free inodes:
|
||||
public UInt16 s_ninode;
|
||||
// 0x198, number of inodes in s_inode, <= 100
|
||||
public UInt16[] s_inode;
|
||||
// 0x19A, 100 entries, some free inodes
|
||||
public byte s_flock;
|
||||
// 0x262, free block list manipulation lock
|
||||
public byte s_ilock;
|
||||
// 0x263, inode cache manipulation lock
|
||||
public byte s_fmod;
|
||||
// 0x264, superblock modification flag
|
||||
public byte s_ronly;
|
||||
// 0x265, read-only mounted flag
|
||||
public UInt32 s_time;
|
||||
// 0x266, time of last superblock update
|
||||
public UInt32 s_tfree;
|
||||
// 0x26A, total number of free zones
|
||||
public UInt16 s_tinode;
|
||||
// 0x26E, total number of free inodes
|
||||
public UInt16 s_cylblks;
|
||||
// 0x270, blocks per cylinder
|
||||
public UInt16 s_gapblks;
|
||||
// 0x272, blocks per gap
|
||||
public UInt16 s_dinfo0;
|
||||
// 0x274, device information ??
|
||||
public UInt16 s_dinfo1;
|
||||
// 0x276, device information ??
|
||||
public string s_fname;
|
||||
// 0x278, 6 bytes, volume name
|
||||
public string s_fpack;
|
||||
// 0x27E, 6 bytes, pack name
|
||||
public byte s_clean;
|
||||
// 0x284, 0x46 if volume is clean
|
||||
public byte[] s_fill;
|
||||
// 0x285, 371 bytes
|
||||
public UInt32 s_magic;
|
||||
// 0x3F8, magic
|
||||
public UInt32 s_type;
|
||||
// 0x3FC, filesystem type (1 = 512 bytes/blk, 2 = 1024 bytes/blk, 3 = 2048 bytes/blk)
|
||||
}
|
||||
|
||||
struct SystemVRelease4SuperBlock
|
||||
{
|
||||
public UInt16 s_isize;
|
||||
// 0x000, index of first data zone
|
||||
public UInt16 s_pad0;
|
||||
// 0x002, padding
|
||||
public UInt32 s_fsize;
|
||||
// 0x004, total number of zones of this volume
|
||||
// the start of the free block list:
|
||||
public UInt16 s_nfree;
|
||||
// 0x008, blocks in s_free, <=100
|
||||
public UInt16 s_pad1;
|
||||
// 0x00A, padding
|
||||
public UInt32[] s_free;
|
||||
// 0x00C, 50 entries, first free block list chunk
|
||||
// the cache of free inodes:
|
||||
public UInt16 s_ninode;
|
||||
// 0x0D4, number of inodes in s_inode, <= 100
|
||||
public UInt16 s_pad2;
|
||||
// 0x0D6, padding
|
||||
public UInt16[] s_inode;
|
||||
// 0x0D8, 100 entries, some free inodes
|
||||
public byte s_flock;
|
||||
// 0x1A0, free block list manipulation lock
|
||||
public byte s_ilock;
|
||||
// 0x1A1, inode cache manipulation lock
|
||||
public byte s_fmod;
|
||||
// 0x1A2, superblock modification flag
|
||||
public byte s_ronly;
|
||||
// 0x1A3, read-only mounted flag
|
||||
public UInt32 s_time;
|
||||
// 0x1A4, time of last superblock update
|
||||
public UInt16 s_cylblks;
|
||||
// 0x1A8, blocks per cylinder
|
||||
public UInt16 s_gapblks;
|
||||
// 0x1AA, blocks per gap
|
||||
public UInt16 s_dinfo0;
|
||||
// 0x1AC, device information ??
|
||||
public UInt16 s_dinfo1;
|
||||
// 0x1AE, device information ??
|
||||
public UInt32 s_tfree;
|
||||
// 0x1B0, total number of free zones
|
||||
public UInt16 s_tinode;
|
||||
// 0x1B4, total number of free inodes
|
||||
public UInt16 s_pad3;
|
||||
// 0x1B6, padding
|
||||
public string s_fname;
|
||||
// 0x1B8, 6 bytes, volume name
|
||||
public string s_fpack;
|
||||
// 0x1BE, 6 bytes, pack name
|
||||
public byte[] s_fill;
|
||||
// 0x1C4, 48 bytes
|
||||
public UInt32 s_state;
|
||||
// 0x1F4, if s_state == (0x7C269D38 - s_time) then filesystem is clean
|
||||
public UInt32 s_magic;
|
||||
// 0x1F8, magic
|
||||
public UInt32 s_type;
|
||||
// 0x1FC, filesystem type (1 = 512 bytes/blk, 2 = 1024 bytes/blk)
|
||||
}
|
||||
|
||||
struct SystemVRelease2SuperBlock
|
||||
{
|
||||
public UInt16 s_isize;
|
||||
// 0x000, index of first data zone
|
||||
public UInt32 s_fsize;
|
||||
// 0x002, total number of zones of this volume
|
||||
// the start of the free block list:
|
||||
public UInt16 s_nfree;
|
||||
// 0x006, blocks in s_free, <=100
|
||||
public UInt32[] s_free;
|
||||
// 0x008, 50 entries, first free block list chunk
|
||||
// the cache of free inodes:
|
||||
public UInt16 s_ninode;
|
||||
// 0x0D0, number of inodes in s_inode, <= 100
|
||||
public UInt16[] s_inode;
|
||||
// 0x0D2, 100 entries, some free inodes
|
||||
public byte s_flock;
|
||||
// 0x19A, free block list manipulation lock
|
||||
public byte s_ilock;
|
||||
// 0x19B, inode cache manipulation lock
|
||||
public byte s_fmod;
|
||||
// 0x19C, superblock modification flag
|
||||
public byte s_ronly;
|
||||
// 0x19D, read-only mounted flag
|
||||
public UInt32 s_time;
|
||||
// 0x19E, time of last superblock update
|
||||
public UInt16 s_cylblks;
|
||||
// 0x1A2, blocks per cylinder
|
||||
public UInt16 s_gapblks;
|
||||
// 0x1A4, blocks per gap
|
||||
public UInt16 s_dinfo0;
|
||||
// 0x1A6, device information ??
|
||||
public UInt16 s_dinfo1;
|
||||
// 0x1A8, device information ??
|
||||
public UInt32 s_tfree;
|
||||
// 0x1AA, total number of free zones
|
||||
public UInt16 s_tinode;
|
||||
// 0x1AE, total number of free inodes
|
||||
public string s_fname;
|
||||
// 0x1B0, 6 bytes, volume name
|
||||
public string s_fpack;
|
||||
// 0x1B6, 6 bytes, pack name
|
||||
public byte[] s_fill;
|
||||
// 0x1BC, 56 bytes
|
||||
public UInt32 s_state;
|
||||
// 0x1F4, if s_state == (0x7C269D38 - s_time) then filesystem is clean
|
||||
public UInt32 s_magic;
|
||||
// 0x1F8, magic
|
||||
public UInt32 s_type;
|
||||
// 0x1FC, filesystem type (1 = 512 bytes/blk, 2 = 1024 bytes/blk)
|
||||
}
|
||||
|
||||
struct UNIX7thEditionSuperBlock
|
||||
{
|
||||
public UInt16 s_isize;
|
||||
// 0x000, index of first data zone
|
||||
public UInt32 s_fsize;
|
||||
// 0x002, total number of zones of this volume
|
||||
// the start of the free block list:
|
||||
public UInt16 s_nfree;
|
||||
// 0x006, blocks in s_free, <=100
|
||||
public UInt32[] s_free;
|
||||
// 0x008, 50 entries, first free block list chunk
|
||||
// the cache of free inodes:
|
||||
public UInt16 s_ninode;
|
||||
// 0x0D0, number of inodes in s_inode, <= 100
|
||||
public UInt16[] s_inode;
|
||||
// 0x0D2, 100 entries, some free inodes
|
||||
public byte s_flock;
|
||||
// 0x19A, free block list manipulation lock
|
||||
public byte s_ilock;
|
||||
// 0x19B, inode cache manipulation lock
|
||||
public byte s_fmod;
|
||||
// 0x19C, superblock modification flag
|
||||
public byte s_ronly;
|
||||
// 0x19D, read-only mounted flag
|
||||
public UInt32 s_time;
|
||||
// 0x19E, time of last superblock update
|
||||
public UInt32 s_tfree;
|
||||
// 0x1A2, total number of free zones
|
||||
public UInt16 s_tinode;
|
||||
// 0x1A6, total number of free inodes
|
||||
public UInt16 s_int_m;
|
||||
// 0x1A8, interleave factor
|
||||
public UInt16 s_int_n;
|
||||
// 0x1AA, interleave factor
|
||||
public string s_fname;
|
||||
// 0x1AC, 6 bytes, volume name
|
||||
public string s_fpack;
|
||||
// 0x1B2, 6 bytes, pack name
|
||||
}
|
||||
|
||||
struct CoherentSuperBlock
|
||||
{
|
||||
public UInt16 s_isize;
|
||||
// 0x000, index of first data zone
|
||||
public UInt32 s_fsize;
|
||||
// 0x002, total number of zones of this volume
|
||||
// the start of the free block list:
|
||||
public UInt16 s_nfree;
|
||||
// 0x006, blocks in s_free, <=100
|
||||
public UInt32[] s_free;
|
||||
// 0x008, 64 entries, first free block list chunk
|
||||
// the cache of free inodes:
|
||||
public UInt16 s_ninode;
|
||||
// 0x108, number of inodes in s_inode, <= 100
|
||||
public UInt16[] s_inode;
|
||||
// 0x10A, 100 entries, some free inodes
|
||||
public byte s_flock;
|
||||
// 0x1D2, free block list manipulation lock
|
||||
public byte s_ilock;
|
||||
// 0x1D3, inode cache manipulation lock
|
||||
public byte s_fmod;
|
||||
// 0x1D4, superblock modification flag
|
||||
public byte s_ronly;
|
||||
// 0x1D5, read-only mounted flag
|
||||
public UInt32 s_time;
|
||||
// 0x1D6, time of last superblock update
|
||||
public UInt32 s_tfree;
|
||||
// 0x1DE, total number of free zones
|
||||
public UInt16 s_tinode;
|
||||
// 0x1E2, total number of free inodes
|
||||
public UInt16 s_int_m;
|
||||
// 0x1E4, interleave factor
|
||||
public UInt16 s_int_n;
|
||||
// 0x1E6, interleave factor
|
||||
public string s_fname;
|
||||
// 0x1E8, 6 bytes, volume name
|
||||
public string s_fpack;
|
||||
// 0x1EE, 6 bytes, pack name
|
||||
public UInt32 s_unique;
|
||||
// 0x1F4, zero-filled
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,133 +0,0 @@
|
||||
/***************************************************************************
|
||||
The Disc Image Chef
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
Filename : UNIXBFS.cs
|
||||
Version : 1.0
|
||||
Author(s) : Natalia Portillo
|
||||
|
||||
Component : Filesystem plugins
|
||||
|
||||
Revision : $Revision$
|
||||
Last change by : $Author$
|
||||
Date : $Date$
|
||||
|
||||
--[ Description ] ----------------------------------------------------------
|
||||
|
||||
Identifies UnixWare boot filesystems and shows information.
|
||||
|
||||
--[ License ] --------------------------------------------------------------
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
----------------------------------------------------------------------------
|
||||
Copyright (C) 2011-2014 Claunia.com
|
||||
****************************************************************************/
|
||||
//$Id$
|
||||
|
||||
using System;
|
||||
using System.Text;
|
||||
using DiscImageChef;
|
||||
|
||||
// Information from the Linux kernel
|
||||
namespace DiscImageChef.Plugins
|
||||
{
|
||||
class BFS : Plugin
|
||||
{
|
||||
const UInt32 BFS_MAGIC = 0x1BADFACE;
|
||||
|
||||
public BFS(PluginBase Core)
|
||||
{
|
||||
Name = "UNIX Boot filesystem";
|
||||
PluginUUID = new Guid("1E6E0DA6-F7E4-494C-80C6-CB5929E96155");
|
||||
}
|
||||
|
||||
public override bool Identify(ImagePlugins.ImagePlugin imagePlugin, ulong partitionStart, ulong partitionEnd)
|
||||
{
|
||||
if ((2 + partitionStart) >= imagePlugin.GetSectors())
|
||||
return false;
|
||||
|
||||
UInt32 magic;
|
||||
|
||||
magic = BitConverter.ToUInt32(imagePlugin.ReadSector(0 + partitionStart), 0);
|
||||
|
||||
return magic == BFS_MAGIC;
|
||||
}
|
||||
|
||||
public override void GetInformation(ImagePlugins.ImagePlugin imagePlugin, ulong partitionStart, ulong partitionEnd, out string information)
|
||||
{
|
||||
information = "";
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
byte[] bfs_sb_sector = imagePlugin.ReadSector(0 + partitionStart);
|
||||
byte[] sb_strings = new byte[6];
|
||||
|
||||
BFSSuperBlock bfs_sb = new BFSSuperBlock();
|
||||
|
||||
bfs_sb.s_magic = BitConverter.ToUInt32(bfs_sb_sector, 0x00);
|
||||
bfs_sb.s_start = BitConverter.ToUInt32(bfs_sb_sector, 0x04);
|
||||
bfs_sb.s_end = BitConverter.ToUInt32(bfs_sb_sector, 0x08);
|
||||
bfs_sb.s_from = BitConverter.ToUInt32(bfs_sb_sector, 0x0C);
|
||||
bfs_sb.s_to = BitConverter.ToUInt32(bfs_sb_sector, 0x10);
|
||||
bfs_sb.s_bfrom = BitConverter.ToInt32(bfs_sb_sector, 0x14);
|
||||
bfs_sb.s_bto = BitConverter.ToInt32(bfs_sb_sector, 0x18);
|
||||
Array.Copy(bfs_sb_sector, 0x1C, sb_strings, 0, 6);
|
||||
bfs_sb.s_fsname = StringHandlers.CToString(sb_strings);
|
||||
Array.Copy(bfs_sb_sector, 0x22, sb_strings, 0, 6);
|
||||
bfs_sb.s_volume = StringHandlers.CToString(sb_strings);
|
||||
|
||||
if (MainClass.isDebug)
|
||||
{
|
||||
Console.WriteLine("(BFS) bfs_sb.s_magic: 0x{0:X8}", bfs_sb.s_magic);
|
||||
Console.WriteLine("(BFS) bfs_sb.s_start: 0x{0:X8}", bfs_sb.s_start);
|
||||
Console.WriteLine("(BFS) bfs_sb.s_end: 0x{0:X8}", bfs_sb.s_end);
|
||||
Console.WriteLine("(BFS) bfs_sb.s_from: 0x{0:X8}", bfs_sb.s_from);
|
||||
Console.WriteLine("(BFS) bfs_sb.s_to: 0x{0:X8}", bfs_sb.s_to);
|
||||
Console.WriteLine("(BFS) bfs_sb.s_bfrom: 0x{0:X8}", bfs_sb.s_bfrom);
|
||||
Console.WriteLine("(BFS) bfs_sb.s_bto: 0x{0:X8}", bfs_sb.s_bto);
|
||||
Console.WriteLine("(BFS) bfs_sb.s_fsname: 0x{0}", bfs_sb.s_fsname);
|
||||
Console.WriteLine("(BFS) bfs_sb.s_volume: 0x{0}", bfs_sb.s_volume);
|
||||
}
|
||||
|
||||
sb.AppendLine("UNIX Boot filesystem");
|
||||
sb.AppendFormat("Volume goes from byte {0} to byte {1}, for {2} bytes", bfs_sb.s_start, bfs_sb.s_end, bfs_sb.s_end - bfs_sb.s_start).AppendLine();
|
||||
sb.AppendFormat("Filesystem name: {0}", bfs_sb.s_fsname).AppendLine();
|
||||
sb.AppendFormat("Volume name: {0}", bfs_sb.s_volume).AppendLine();
|
||||
|
||||
information = sb.ToString();
|
||||
}
|
||||
|
||||
struct BFSSuperBlock
|
||||
{
|
||||
public UInt32 s_magic;
|
||||
// 0x00, 0x1BADFACE
|
||||
public UInt32 s_start;
|
||||
// 0x04, start in bytes of volume
|
||||
public UInt32 s_end;
|
||||
// 0x08, end in bytes of volume
|
||||
public UInt32 s_from;
|
||||
// 0x0C, unknown :p
|
||||
public UInt32 s_to;
|
||||
// 0x10, unknown :p
|
||||
public Int32 s_bfrom;
|
||||
// 0x14, unknown :p
|
||||
public Int32 s_bto;
|
||||
// 0x18, unknown :p
|
||||
public string s_fsname;
|
||||
// 0x1C, 6 bytes, filesystem name
|
||||
public string s_volume;
|
||||
// 0x22, 6 bytes, volume name
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,878 +0,0 @@
|
||||
/***************************************************************************
|
||||
The Disc Image Chef
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
Filename : ext2FS.cs
|
||||
Version : 1.0
|
||||
Author(s) : Natalia Portillo
|
||||
|
||||
Component : Filesystem plugins
|
||||
|
||||
Revision : $Revision$
|
||||
Last change by : $Author$
|
||||
Date : $Date$
|
||||
|
||||
--[ Description ] ----------------------------------------------------------
|
||||
|
||||
Identifies ext2, ext3 and ext4 filesystems and shows information.
|
||||
|
||||
--[ License ] --------------------------------------------------------------
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
----------------------------------------------------------------------------
|
||||
Copyright (C) 2011-2014 Claunia.com
|
||||
****************************************************************************/
|
||||
//$Id$
|
||||
|
||||
using System;
|
||||
using System.Text;
|
||||
using DiscImageChef;
|
||||
|
||||
// Information from the Linux kernel
|
||||
namespace DiscImageChef.Plugins
|
||||
{
|
||||
class ext2FS : Plugin
|
||||
{
|
||||
public ext2FS(PluginBase Core)
|
||||
{
|
||||
Name = "Linux extended Filesystem 2, 3 and 4";
|
||||
PluginUUID = new Guid("6AA91B88-150B-4A7B-AD56-F84FB2DF4184");
|
||||
}
|
||||
|
||||
public override bool Identify(ImagePlugins.ImagePlugin imagePlugin, ulong partitionStart, ulong partitionEnd)
|
||||
{
|
||||
if ((2 + partitionStart) >= imagePlugin.GetSectors())
|
||||
return false;
|
||||
|
||||
byte[] sb_sector = imagePlugin.ReadSector(2 + partitionStart);
|
||||
|
||||
UInt16 magic = BitConverter.ToUInt16(sb_sector, 0x038);
|
||||
|
||||
if (magic == ext2FSMagic || magic == ext2OldFSMagic)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
public override void GetInformation(ImagePlugins.ImagePlugin imagePlugin, ulong partitionStart, ulong partitionEnd, out string information)
|
||||
{
|
||||
information = "";
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
ext2FSSuperBlock supblk = new ext2FSSuperBlock();
|
||||
byte[] forstrings;
|
||||
bool new_ext2 = false;
|
||||
bool ext3 = false;
|
||||
bool ext4 = false;
|
||||
|
||||
byte[] guid_a = new byte[16];
|
||||
byte[] guid_b = new byte[16];
|
||||
|
||||
uint sb_size_in_sectors;
|
||||
|
||||
if (imagePlugin.GetSectorSize() < 1024)
|
||||
sb_size_in_sectors = 1024 / imagePlugin.GetSectorSize();
|
||||
else
|
||||
sb_size_in_sectors = 1;
|
||||
|
||||
if (sb_size_in_sectors == 0)
|
||||
{
|
||||
information = "Error calculating size in sectors of ext2/3/4 superblocks";
|
||||
return;
|
||||
}
|
||||
|
||||
byte[] sb_sector = imagePlugin.ReadSectors(2 + partitionStart, sb_size_in_sectors);
|
||||
supblk.inodes = BitConverter.ToUInt32(sb_sector, 0x000);
|
||||
supblk.blocks = BitConverter.ToUInt32(sb_sector, 0x004);
|
||||
supblk.reserved_blocks = BitConverter.ToUInt32(sb_sector, 0x008);
|
||||
supblk.free_blocks = BitConverter.ToUInt32(sb_sector, 0x00C);
|
||||
supblk.free_inodes = BitConverter.ToUInt32(sb_sector, 0x010);
|
||||
supblk.first_block = BitConverter.ToUInt32(sb_sector, 0x014);
|
||||
supblk.block_size = BitConverter.ToUInt32(sb_sector, 0x018);
|
||||
supblk.frag_size = BitConverter.ToInt32(sb_sector, 0x01C);
|
||||
supblk.blocks_per_grp = BitConverter.ToUInt32(sb_sector, 0x020);
|
||||
supblk.flags_per_grp = BitConverter.ToUInt32(sb_sector, 0x024);
|
||||
supblk.inodes_per_grp = BitConverter.ToUInt32(sb_sector, 0x028);
|
||||
supblk.mount_t = BitConverter.ToUInt32(sb_sector, 0x02C);
|
||||
supblk.write_t = BitConverter.ToUInt32(sb_sector, 0x030);
|
||||
supblk.mount_c = BitConverter.ToUInt16(sb_sector, 0x034);
|
||||
supblk.max_mount_c = BitConverter.ToInt16(sb_sector, 0x036);
|
||||
supblk.magic = BitConverter.ToUInt16(sb_sector, 0x038);
|
||||
supblk.state = BitConverter.ToUInt16(sb_sector, 0x03A);
|
||||
supblk.err_behaviour = BitConverter.ToUInt16(sb_sector, 0x03C);
|
||||
supblk.minor_revision = BitConverter.ToUInt16(sb_sector, 0x03E);
|
||||
supblk.check_t = BitConverter.ToUInt32(sb_sector, 0x040);
|
||||
supblk.check_inv = BitConverter.ToUInt32(sb_sector, 0x044);
|
||||
// From 0.5a onward
|
||||
supblk.creator_os = BitConverter.ToUInt32(sb_sector, 0x048);
|
||||
supblk.revision = BitConverter.ToUInt32(sb_sector, 0x04C);
|
||||
supblk.default_uid = BitConverter.ToUInt16(sb_sector, 0x050);
|
||||
supblk.default_gid = BitConverter.ToUInt16(sb_sector, 0x052);
|
||||
// From 0.5b onward
|
||||
supblk.first_inode = BitConverter.ToUInt32(sb_sector, 0x054);
|
||||
supblk.inode_size = BitConverter.ToUInt16(sb_sector, 0x058);
|
||||
supblk.block_group_no = BitConverter.ToUInt16(sb_sector, 0x05A);
|
||||
supblk.ftr_compat = BitConverter.ToUInt32(sb_sector, 0x05C);
|
||||
supblk.ftr_incompat = BitConverter.ToUInt32(sb_sector, 0x060);
|
||||
supblk.ftr_ro_compat = BitConverter.ToUInt32(sb_sector, 0x064);
|
||||
// Volume UUID
|
||||
Array.Copy(sb_sector, 0x068, guid_a, 0, 16);
|
||||
guid_b[0] = guid_a[3];
|
||||
guid_b[1] = guid_a[2];
|
||||
guid_b[2] = guid_a[1];
|
||||
guid_b[3] = guid_a[0];
|
||||
guid_b[4] = guid_a[5];
|
||||
guid_b[5] = guid_a[4];
|
||||
guid_b[6] = guid_a[7];
|
||||
guid_b[7] = guid_a[6];
|
||||
guid_b[8] = guid_a[8];
|
||||
guid_b[9] = guid_a[9];
|
||||
guid_b[10] = guid_a[10];
|
||||
guid_b[11] = guid_a[11];
|
||||
guid_b[12] = guid_a[12];
|
||||
guid_b[13] = guid_a[13];
|
||||
guid_b[14] = guid_a[14];
|
||||
guid_b[15] = guid_a[15];
|
||||
supblk.uuid = new Guid(guid_b);
|
||||
// End of volume UUID
|
||||
forstrings = new byte[16];
|
||||
Array.Copy(sb_sector, 0x078, forstrings, 0, 16);
|
||||
supblk.volume_name = StringHandlers.CToString(forstrings);
|
||||
forstrings = new byte[64];
|
||||
Array.Copy(sb_sector, 0x088, forstrings, 0, 64);
|
||||
supblk.last_mount_dir = StringHandlers.CToString(forstrings);
|
||||
supblk.algo_usage_bmp = BitConverter.ToUInt32(sb_sector, 0x0C8);
|
||||
supblk.prealloc_blks = sb_sector[0x0CC];
|
||||
supblk.prealloc_dir_blks = sb_sector[0x0CD];
|
||||
supblk.rsrvd_gdt_blocks = BitConverter.ToUInt16(sb_sector, 0x0CE);
|
||||
// ext3
|
||||
Array.Copy(sb_sector, 0x0D0, guid_a, 0, 16);
|
||||
guid_b[0] = guid_a[3];
|
||||
guid_b[1] = guid_a[2];
|
||||
guid_b[2] = guid_a[1];
|
||||
guid_b[3] = guid_a[0];
|
||||
guid_b[4] = guid_a[5];
|
||||
guid_b[5] = guid_a[4];
|
||||
guid_b[6] = guid_a[7];
|
||||
guid_b[7] = guid_a[6];
|
||||
guid_b[8] = guid_a[8];
|
||||
guid_b[9] = guid_a[9];
|
||||
guid_b[10] = guid_a[10];
|
||||
guid_b[11] = guid_a[11];
|
||||
guid_b[12] = guid_a[12];
|
||||
guid_b[13] = guid_a[13];
|
||||
guid_b[14] = guid_a[14];
|
||||
guid_b[15] = guid_a[15];
|
||||
supblk.journal_uuid = new Guid(guid_b);
|
||||
supblk.journal_inode = BitConverter.ToUInt32(sb_sector, 0x0E0);
|
||||
supblk.journal_dev = BitConverter.ToUInt32(sb_sector, 0x0E4);
|
||||
supblk.last_orphan = BitConverter.ToUInt32(sb_sector, 0x0E8);
|
||||
supblk.hash_seed_1 = BitConverter.ToUInt32(sb_sector, 0x0EC);
|
||||
supblk.hash_seed_2 = BitConverter.ToUInt32(sb_sector, 0x0F0);
|
||||
supblk.hash_seed_3 = BitConverter.ToUInt32(sb_sector, 0x0F4);
|
||||
supblk.hash_seed_4 = BitConverter.ToUInt32(sb_sector, 0x0F8);
|
||||
supblk.hash_version = sb_sector[0x0FC];
|
||||
supblk.jnl_backup_type = sb_sector[0x0FD];
|
||||
supblk.desc_grp_size = BitConverter.ToUInt16(sb_sector, 0x0FE);
|
||||
supblk.default_mnt_opts = BitConverter.ToUInt32(sb_sector, 0x100);
|
||||
supblk.first_meta_bg = BitConverter.ToUInt32(sb_sector, 0x104);
|
||||
// ext4
|
||||
supblk.mkfs_t = BitConverter.ToUInt32(sb_sector, 0x108);
|
||||
supblk.blocks_hi = BitConverter.ToUInt32(sb_sector, 0x14C);
|
||||
supblk.reserved_blocks_hi = BitConverter.ToUInt32(sb_sector, 0x150);
|
||||
supblk.free_blocks_hi = BitConverter.ToUInt32(sb_sector, 0x154);
|
||||
supblk.min_inode_size = BitConverter.ToUInt16(sb_sector, 0x158);
|
||||
supblk.rsv_inode_size = BitConverter.ToUInt16(sb_sector, 0x15A);
|
||||
supblk.flags = BitConverter.ToUInt32(sb_sector, 0x15C);
|
||||
supblk.raid_stride = BitConverter.ToUInt16(sb_sector, 0x160);
|
||||
supblk.mmp_interval = BitConverter.ToUInt16(sb_sector, 0x162);
|
||||
supblk.mmp_block = BitConverter.ToUInt64(sb_sector, 0x164);
|
||||
supblk.raid_stripe_width = BitConverter.ToUInt32(sb_sector, 0x16C);
|
||||
supblk.flex_bg_grp_size = sb_sector[0x170];
|
||||
supblk.kbytes_written = BitConverter.ToUInt64(sb_sector, 0x174);
|
||||
supblk.snapshot_inum = BitConverter.ToUInt32(sb_sector, 0x17C);
|
||||
supblk.snapshot_id = BitConverter.ToUInt32(sb_sector, 0x180);
|
||||
supblk.snapshot_blocks = BitConverter.ToUInt64(sb_sector, 0x184);
|
||||
supblk.snapshot_list = BitConverter.ToUInt32(sb_sector, 0x18C);
|
||||
supblk.error_count = BitConverter.ToUInt32(sb_sector, 0x190);
|
||||
supblk.first_error_t = BitConverter.ToUInt32(sb_sector, 0x194);
|
||||
supblk.first_error_inode = BitConverter.ToUInt32(sb_sector, 0x198);
|
||||
supblk.first_error_block = BitConverter.ToUInt64(sb_sector, 0x19C);
|
||||
forstrings = new byte[32];
|
||||
Array.Copy(sb_sector, 0x1A0, forstrings, 0, 32);
|
||||
supblk.first_error_func = StringHandlers.CToString(forstrings);
|
||||
supblk.first_error_line = BitConverter.ToUInt32(sb_sector, 0x1B0);
|
||||
supblk.last_error_t = BitConverter.ToUInt32(sb_sector, 0x1B4);
|
||||
supblk.last_error_inode = BitConverter.ToUInt32(sb_sector, 0x1B8);
|
||||
supblk.last_error_line = BitConverter.ToUInt32(sb_sector, 0x1BC);
|
||||
supblk.last_error_block = BitConverter.ToUInt64(sb_sector, 0x1C0);
|
||||
forstrings = new byte[32];
|
||||
Array.Copy(sb_sector, 0x1C8, forstrings, 0, 32);
|
||||
supblk.last_error_func = StringHandlers.CToString(forstrings);
|
||||
forstrings = new byte[64];
|
||||
Array.Copy(sb_sector, 0x1D8, forstrings, 0, 64);
|
||||
supblk.mount_options = StringHandlers.CToString(forstrings);
|
||||
|
||||
if (supblk.magic == ext2OldFSMagic)
|
||||
{
|
||||
sb.AppendLine("ext2 (old) filesystem");
|
||||
}
|
||||
else if (supblk.magic == ext2FSMagic)
|
||||
{
|
||||
ext3 |= (supblk.ftr_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL) == EXT3_FEATURE_COMPAT_HAS_JOURNAL || (supblk.ftr_incompat & EXT3_FEATURE_INCOMPAT_RECOVER) == EXT3_FEATURE_INCOMPAT_RECOVER || (supblk.ftr_incompat & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) == EXT3_FEATURE_INCOMPAT_JOURNAL_DEV;
|
||||
|
||||
if ((supblk.ftr_ro_compat & EXT4_FEATURE_RO_COMPAT_HUGE_FILE) == EXT4_FEATURE_RO_COMPAT_HUGE_FILE ||
|
||||
(supblk.ftr_ro_compat & EXT4_FEATURE_RO_COMPAT_GDT_CSUM) == EXT4_FEATURE_RO_COMPAT_GDT_CSUM ||
|
||||
(supblk.ftr_ro_compat & EXT4_FEATURE_RO_COMPAT_DIR_NLINK) == EXT4_FEATURE_RO_COMPAT_DIR_NLINK ||
|
||||
(supblk.ftr_ro_compat & EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE) == EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE ||
|
||||
(supblk.ftr_incompat & EXT4_FEATURE_INCOMPAT_64BIT) == EXT4_FEATURE_INCOMPAT_64BIT ||
|
||||
(supblk.ftr_incompat & EXT4_FEATURE_INCOMPAT_MMP) == EXT4_FEATURE_INCOMPAT_MMP ||
|
||||
(supblk.ftr_incompat & EXT4_FEATURE_INCOMPAT_FLEX_BG) == EXT4_FEATURE_INCOMPAT_FLEX_BG ||
|
||||
(supblk.ftr_incompat & EXT4_FEATURE_INCOMPAT_EA_INODE) == EXT4_FEATURE_INCOMPAT_EA_INODE ||
|
||||
(supblk.ftr_incompat & EXT4_FEATURE_INCOMPAT_DIRDATA) == EXT4_FEATURE_INCOMPAT_DIRDATA)
|
||||
{
|
||||
ext3 = false;
|
||||
ext4 = true;
|
||||
}
|
||||
|
||||
new_ext2 |= !ext3 && !ext4;
|
||||
|
||||
if (new_ext2)
|
||||
sb.AppendLine("ext2 filesystem");
|
||||
if (ext3)
|
||||
sb.AppendLine("ext3 filesystem");
|
||||
if (ext4)
|
||||
sb.AppendLine("ext4 filesystem");
|
||||
}
|
||||
else
|
||||
{
|
||||
information = "Not a ext2/3/4 filesystem" + Environment.NewLine;
|
||||
return;
|
||||
}
|
||||
|
||||
string ext_os;
|
||||
switch (supblk.creator_os)
|
||||
{
|
||||
case EXT2_OS_FREEBSD:
|
||||
ext_os = "FreeBSD";
|
||||
break;
|
||||
case EXT2_OS_HURD:
|
||||
ext_os = "Hurd";
|
||||
break;
|
||||
case EXT2_OS_LINUX:
|
||||
ext_os = "Linux";
|
||||
break;
|
||||
case EXT2_OS_LITES:
|
||||
ext_os = "Lites";
|
||||
break;
|
||||
case EXT2_OS_MASIX:
|
||||
ext_os = "MasIX";
|
||||
break;
|
||||
default:
|
||||
ext_os = string.Format("Unknown OS ({0})", supblk.creator_os);
|
||||
break;
|
||||
}
|
||||
|
||||
if (supblk.mkfs_t > 0)
|
||||
sb.AppendFormat("Volume was created on {0} for {1}", DateHandlers.UNIXUnsignedToDateTime(supblk.mkfs_t), ext_os).AppendLine();
|
||||
else
|
||||
sb.AppendFormat("Volume was created for {0}", ext_os).AppendLine();
|
||||
|
||||
byte[] temp_lo, temp_hi;
|
||||
byte[] temp_bytes = new byte[8];
|
||||
UInt64 blocks, reserved, free;
|
||||
|
||||
if ((supblk.ftr_incompat & EXT4_FEATURE_INCOMPAT_64BIT) == EXT4_FEATURE_INCOMPAT_64BIT)
|
||||
{
|
||||
temp_lo = BitConverter.GetBytes(supblk.blocks);
|
||||
temp_hi = BitConverter.GetBytes(supblk.blocks_hi);
|
||||
temp_bytes[0] = temp_lo[0];
|
||||
temp_bytes[1] = temp_lo[1];
|
||||
temp_bytes[2] = temp_lo[2];
|
||||
temp_bytes[3] = temp_lo[3];
|
||||
temp_bytes[4] = temp_hi[0];
|
||||
temp_bytes[5] = temp_hi[1];
|
||||
temp_bytes[6] = temp_hi[2];
|
||||
temp_bytes[7] = temp_hi[3];
|
||||
blocks = BitConverter.ToUInt64(temp_bytes, 0);
|
||||
|
||||
temp_lo = BitConverter.GetBytes(supblk.reserved_blocks);
|
||||
temp_hi = BitConverter.GetBytes(supblk.reserved_blocks_hi);
|
||||
temp_bytes[0] = temp_lo[0];
|
||||
temp_bytes[1] = temp_lo[1];
|
||||
temp_bytes[2] = temp_lo[2];
|
||||
temp_bytes[3] = temp_lo[3];
|
||||
temp_bytes[4] = temp_hi[0];
|
||||
temp_bytes[5] = temp_hi[1];
|
||||
temp_bytes[6] = temp_hi[2];
|
||||
temp_bytes[7] = temp_hi[3];
|
||||
reserved = BitConverter.ToUInt64(temp_bytes, 0);
|
||||
|
||||
temp_lo = BitConverter.GetBytes(supblk.free_blocks);
|
||||
temp_hi = BitConverter.GetBytes(supblk.free_blocks_hi);
|
||||
temp_bytes[0] = temp_lo[0];
|
||||
temp_bytes[1] = temp_lo[1];
|
||||
temp_bytes[2] = temp_lo[2];
|
||||
temp_bytes[3] = temp_lo[3];
|
||||
temp_bytes[4] = temp_hi[0];
|
||||
temp_bytes[5] = temp_hi[1];
|
||||
temp_bytes[6] = temp_hi[2];
|
||||
temp_bytes[7] = temp_hi[3];
|
||||
free = BitConverter.ToUInt64(temp_bytes, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
blocks = supblk.blocks;
|
||||
reserved = supblk.reserved_blocks;
|
||||
free = supblk.free_blocks;
|
||||
}
|
||||
|
||||
if (supblk.block_size == 0) // Then it is 1024 bytes
|
||||
supblk.block_size = 1024;
|
||||
|
||||
sb.AppendFormat("Volume has {0} blocks of {1} bytes, for a total of {2} bytes", blocks, 1024<<(int)supblk.block_size, blocks * (ulong)(1024<<(int)supblk.block_size)).AppendLine();
|
||||
if (supblk.mount_t > 0 || supblk.mount_c > 0)
|
||||
{
|
||||
if (supblk.mount_t > 0)
|
||||
sb.AppendFormat("Last mounted on {0}", DateHandlers.UNIXUnsignedToDateTime(supblk.mount_t)).AppendLine();
|
||||
if (supblk.max_mount_c != -1)
|
||||
sb.AppendFormat("Volume has been mounted {0} times of a maximum of {1} mounts before checking", supblk.mount_c, supblk.max_mount_c).AppendLine();
|
||||
else
|
||||
sb.AppendFormat("Volume has been mounted {0} times with no maximum no. of mounts before checking", supblk.mount_c).AppendLine();
|
||||
if (supblk.last_mount_dir != "")
|
||||
sb.AppendFormat("Last mounted on: \"{0}\"", supblk.last_mount_dir).AppendLine();
|
||||
if (supblk.mount_options != "")
|
||||
sb.AppendFormat("Last used mount options were: {0}", supblk.mount_options).AppendLine();
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.AppendLine("Volume has never been mounted");
|
||||
if (supblk.max_mount_c != -1)
|
||||
sb.AppendFormat("Volume can be mounted {0} times before checking", supblk.max_mount_c).AppendLine();
|
||||
else
|
||||
sb.AppendLine("Volume has no maximum no. of mounts before checking");
|
||||
}
|
||||
|
||||
if (supblk.check_t > 0)
|
||||
{
|
||||
if (supblk.check_inv > 0)
|
||||
sb.AppendFormat("Last checked on {0} (should check every {1} seconds)", DateHandlers.UNIXUnsignedToDateTime(supblk.check_t), supblk.check_inv).AppendLine();
|
||||
else
|
||||
sb.AppendFormat("Last checked on {0}", DateHandlers.UNIXUnsignedToDateTime(supblk.check_t)).AppendLine();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (supblk.check_inv > 0)
|
||||
sb.AppendFormat("Volume has never been checked (should check every {0})", supblk.check_inv).AppendLine();
|
||||
else
|
||||
sb.AppendLine("Volume has never been checked");
|
||||
}
|
||||
|
||||
if (supblk.write_t > 0)
|
||||
sb.AppendFormat("Last written on {0}", DateHandlers.UNIXUnsignedToDateTime(supblk.write_t)).AppendLine();
|
||||
else
|
||||
sb.AppendLine("Volume has never been written");
|
||||
|
||||
switch (supblk.state)
|
||||
{
|
||||
case EXT2_VALID_FS:
|
||||
sb.AppendLine("Volume is clean");
|
||||
break;
|
||||
case EXT2_ERROR_FS:
|
||||
sb.AppendLine("Volume is dirty");
|
||||
break;
|
||||
case EXT3_ORPHAN_FS:
|
||||
sb.AppendLine("Volume is recovering orphan files");
|
||||
break;
|
||||
default:
|
||||
sb.AppendFormat("Volume is in an unknown state ({0})", supblk.state).AppendLine();
|
||||
break;
|
||||
}
|
||||
|
||||
if (supblk.volume_name != "")
|
||||
sb.AppendFormat("Volume name: \"{0}\"", supblk.volume_name).AppendLine();
|
||||
|
||||
switch (supblk.err_behaviour)
|
||||
{
|
||||
case EXT2_ERRORS_CONTINUE:
|
||||
sb.AppendLine("On errors, filesystem should continue");
|
||||
break;
|
||||
case EXT2_ERRORS_RO:
|
||||
sb.AppendLine("On errors, filesystem should remount read-only");
|
||||
break;
|
||||
case EXT2_ERRORS_PANIC:
|
||||
sb.AppendLine("On errors, filesystem should panic");
|
||||
break;
|
||||
default:
|
||||
sb.AppendFormat("On errors filesystem will do an unknown thing ({0})", supblk.err_behaviour).AppendLine();
|
||||
break;
|
||||
}
|
||||
|
||||
if (supblk.revision > 0)
|
||||
sb.AppendFormat("Filesystem revision: {0}.{1}", supblk.revision, supblk.minor_revision).AppendLine();
|
||||
|
||||
if (supblk.uuid != Guid.Empty)
|
||||
sb.AppendFormat("Volume UUID: {0}", supblk.uuid).AppendLine();
|
||||
|
||||
if (supblk.kbytes_written > 0)
|
||||
sb.AppendFormat("{0} KiB has been written on volume", supblk.kbytes_written).AppendLine();
|
||||
|
||||
sb.AppendFormat("{0} reserved and {1} free blocks", reserved, free).AppendLine();
|
||||
sb.AppendFormat("{0} inodes with {1} free inodes ({2}%)", supblk.inodes, supblk.free_inodes, supblk.free_inodes * 100 / supblk.inodes).AppendLine();
|
||||
if (supblk.first_inode > 0)
|
||||
sb.AppendFormat("First inode is {0}", supblk.first_inode).AppendLine();
|
||||
if (supblk.frag_size > 0)
|
||||
sb.AppendFormat("{0} bytes per fragment", supblk.frag_size).AppendLine();
|
||||
if (supblk.blocks_per_grp > 0 && supblk.flags_per_grp > 0 && supblk.inodes_per_grp > 0)
|
||||
sb.AppendFormat("{0} blocks, {1} flags and {2} inodes per group", supblk.blocks_per_grp, supblk.flags_per_grp, supblk.inodes_per_grp).AppendLine();
|
||||
if (supblk.first_block > 0)
|
||||
sb.AppendFormat("{0} is first data block", supblk.first_block).AppendLine();
|
||||
sb.AppendFormat("Default UID: {0}, GID: {1}", supblk.default_uid, supblk.default_gid).AppendLine();
|
||||
if (supblk.block_group_no > 0)
|
||||
sb.AppendFormat("Block group number is {0}", supblk.block_group_no).AppendLine();
|
||||
if (supblk.desc_grp_size > 0)
|
||||
sb.AppendFormat("Group descriptor size is {0} bytes", supblk.desc_grp_size).AppendLine();
|
||||
if (supblk.first_meta_bg > 0)
|
||||
sb.AppendFormat("First metablock group is {0}", supblk.first_meta_bg).AppendLine();
|
||||
if (supblk.raid_stride > 0)
|
||||
sb.AppendFormat("RAID stride: {0}", supblk.raid_stride).AppendLine();
|
||||
if (supblk.raid_stripe_width > 0)
|
||||
sb.AppendFormat("{0} blocks on all data disks", supblk.raid_stripe_width).AppendLine();
|
||||
if (supblk.mmp_interval > 0 && supblk.mmp_block > 0)
|
||||
sb.AppendFormat("{0} seconds for multi-mount protection wait, on block {1}", supblk.mmp_interval, supblk.mmp_block).AppendLine();
|
||||
if (supblk.flex_bg_grp_size > 0)
|
||||
sb.AppendFormat("{0} Flexible block group size", supblk.flex_bg_grp_size).AppendLine();
|
||||
if (supblk.hash_seed_1 > 0 && supblk.hash_seed_2 > 0 && supblk.hash_seed_3 > 0 && supblk.hash_seed_4 > 0)
|
||||
sb.AppendFormat("Hash seed: {0:X8}{1:X8}{2:X8}{3:X8}, version {4}", supblk.hash_seed_1, supblk.hash_seed_2, supblk.hash_seed_3, supblk.hash_seed_4, supblk.hash_version).AppendLine();
|
||||
|
||||
if ((supblk.ftr_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL) == EXT3_FEATURE_COMPAT_HAS_JOURNAL ||
|
||||
(supblk.ftr_incompat & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) == EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)
|
||||
{
|
||||
sb.AppendLine("Volume is journaled");
|
||||
if (supblk.journal_uuid != Guid.Empty)
|
||||
sb.AppendFormat("Journal UUID: {0}", supblk.journal_uuid).AppendLine();
|
||||
sb.AppendFormat("Journal has inode {0}", supblk.journal_inode).AppendLine();
|
||||
if ((supblk.ftr_compat & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) == EXT3_FEATURE_INCOMPAT_JOURNAL_DEV && supblk.journal_dev > 0)
|
||||
sb.AppendFormat("Journal is on device {0}", supblk.journal_dev).AppendLine();
|
||||
if (supblk.jnl_backup_type > 0)
|
||||
sb.AppendFormat("Journal backup type: {0}", supblk.jnl_backup_type).AppendLine();
|
||||
if (supblk.last_orphan > 0)
|
||||
sb.AppendFormat("Last orphaned inode is {0}", supblk.last_orphan).AppendLine();
|
||||
else
|
||||
sb.AppendLine("There are no orphaned inodes");
|
||||
}
|
||||
|
||||
if (ext4)
|
||||
{
|
||||
if (supblk.snapshot_id > 0)
|
||||
sb.AppendFormat("Active snapshot has ID {0}, on inode {1}, with {2} blocks reserved, list starting on block {3}", supblk.snapshot_id,
|
||||
supblk.snapshot_inum, supblk.snapshot_blocks, supblk.snapshot_list).AppendLine();
|
||||
|
||||
if (supblk.error_count > 0)
|
||||
{
|
||||
sb.AppendFormat("{0} errors registered", supblk.error_count).AppendLine();
|
||||
sb.AppendFormat("First error occurred on {0}, last on {1}", DateHandlers.UNIXUnsignedToDateTime(supblk.first_error_t), DateHandlers.UNIXUnsignedToDateTime(supblk.last_error_t)).AppendLine();
|
||||
sb.AppendFormat("First error inode is {0}, last is {1}", supblk.first_error_inode, supblk.last_error_inode).AppendLine();
|
||||
sb.AppendFormat("First error block is {0}, last is {1}", supblk.first_error_block, supblk.last_error_block).AppendLine();
|
||||
sb.AppendFormat("First error function is \"{0}\", last is \"{1}\"", supblk.first_error_func, supblk.last_error_func).AppendLine();
|
||||
}
|
||||
}
|
||||
|
||||
sb.AppendFormat("Flags…:").AppendLine();
|
||||
if ((supblk.flags & EXT2_FLAGS_SIGNED_HASH) == EXT2_FLAGS_SIGNED_HASH)
|
||||
sb.AppendLine("Signed directory hash is in use");
|
||||
if ((supblk.flags & EXT2_FLAGS_UNSIGNED_HASH) == EXT2_FLAGS_UNSIGNED_HASH)
|
||||
sb.AppendLine("Unsigned directory hash is in use");
|
||||
if ((supblk.flags & EXT2_FLAGS_TEST_FILESYS) == EXT2_FLAGS_TEST_FILESYS)
|
||||
sb.AppendLine("Volume is testing development code");
|
||||
if ((supblk.flags & 0xFFFFFFF8) != 0)
|
||||
sb.AppendFormat("Unknown set flags: {0:X8}", supblk.flags);
|
||||
|
||||
sb.AppendLine();
|
||||
|
||||
sb.AppendFormat("Default mount options…:").AppendLine();
|
||||
if ((supblk.default_mnt_opts & EXT2_DEFM_DEBUG) == EXT2_DEFM_DEBUG)
|
||||
sb.AppendLine("(debug): Enable debugging code");
|
||||
if ((supblk.default_mnt_opts & EXT2_DEFM_BSDGROUPS) == EXT2_DEFM_BSDGROUPS)
|
||||
sb.AppendLine("(bsdgroups): Emulate BSD behaviour when creating new files");
|
||||
if ((supblk.default_mnt_opts & EXT2_DEFM_XATTR_USER) == EXT2_DEFM_XATTR_USER)
|
||||
sb.AppendLine("(user_xattr): Enable user-specified extended attributes");
|
||||
if ((supblk.default_mnt_opts & EXT2_DEFM_ACL) == EXT2_DEFM_ACL)
|
||||
sb.AppendLine("(acl): Enable POSIX ACLs");
|
||||
if ((supblk.default_mnt_opts & EXT2_DEFM_UID16) == EXT2_DEFM_UID16)
|
||||
sb.AppendLine("(uid16): Disable 32bit UIDs and GIDs");
|
||||
if ((supblk.default_mnt_opts & EXT3_DEFM_JMODE_DATA) == EXT3_DEFM_JMODE_DATA)
|
||||
sb.AppendLine("(journal_data): Journal data and metadata");
|
||||
if ((supblk.default_mnt_opts & EXT3_DEFM_JMODE_ORDERED) == EXT3_DEFM_JMODE_ORDERED)
|
||||
sb.AppendLine("(journal_data_ordered): Write data before journaling metadata");
|
||||
if ((supblk.default_mnt_opts & EXT3_DEFM_JMODE_WBACK) == EXT3_DEFM_JMODE_WBACK)
|
||||
sb.AppendLine("(journal_data_writeback): Write journal before data");
|
||||
if ((supblk.default_mnt_opts & 0xFFFFFE20) != 0)
|
||||
sb.AppendFormat("Unknown set default mount options: {0:X8}", supblk.default_mnt_opts);
|
||||
|
||||
sb.AppendLine();
|
||||
|
||||
sb.AppendFormat("Compatible features…:").AppendLine();
|
||||
if ((supblk.ftr_compat & EXT2_FEATURE_COMPAT_DIR_PREALLOC) == EXT2_FEATURE_COMPAT_DIR_PREALLOC)
|
||||
sb.AppendLine("Pre-allocate directories");
|
||||
if ((supblk.ftr_compat & EXT2_FEATURE_COMPAT_IMAGIC_INODES) == EXT2_FEATURE_COMPAT_IMAGIC_INODES)
|
||||
sb.AppendLine("imagic inodes ?");
|
||||
if ((supblk.ftr_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL) == EXT3_FEATURE_COMPAT_HAS_JOURNAL)
|
||||
sb.AppendLine("Has journal (ext3)");
|
||||
if ((supblk.ftr_compat & EXT2_FEATURE_COMPAT_EXT_ATTR) == EXT2_FEATURE_COMPAT_EXT_ATTR)
|
||||
sb.AppendLine("Has extended attribute blocks");
|
||||
if ((supblk.ftr_compat & EXT2_FEATURE_COMPAT_RESIZE_INO) == EXT2_FEATURE_COMPAT_RESIZE_INO)
|
||||
sb.AppendLine("Has online filesystem resize reservations");
|
||||
if ((supblk.ftr_compat & EXT2_FEATURE_COMPAT_DIR_INDEX) == EXT2_FEATURE_COMPAT_DIR_INDEX)
|
||||
sb.AppendLine("Can use hashed indexes on directories");
|
||||
if ((supblk.ftr_compat & 0xFFFFFFC0) != 0)
|
||||
sb.AppendFormat("Unknown compatible features: {0:X8}", supblk.ftr_compat);
|
||||
|
||||
sb.AppendLine();
|
||||
|
||||
sb.AppendFormat("Compatible features if read-only…:").AppendLine();
|
||||
if ((supblk.ftr_ro_compat & EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER) == EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER)
|
||||
sb.AppendLine("Reduced number of superblocks");
|
||||
if ((supblk.ftr_ro_compat & EXT2_FEATURE_RO_COMPAT_LARGE_FILE) == EXT2_FEATURE_RO_COMPAT_LARGE_FILE)
|
||||
sb.AppendLine("Can have files bigger than 2GiB");
|
||||
if ((supblk.ftr_ro_compat & EXT2_FEATURE_RO_COMPAT_BTREE_DIR) == EXT2_FEATURE_RO_COMPAT_BTREE_DIR)
|
||||
sb.AppendLine("Uses B-Tree for directories");
|
||||
if ((supblk.ftr_ro_compat & EXT4_FEATURE_RO_COMPAT_HUGE_FILE) == EXT4_FEATURE_RO_COMPAT_HUGE_FILE)
|
||||
sb.AppendLine("Can have files bigger than 2TiB (ext4)");
|
||||
if ((supblk.ftr_ro_compat & EXT4_FEATURE_RO_COMPAT_GDT_CSUM) == EXT4_FEATURE_RO_COMPAT_GDT_CSUM)
|
||||
sb.AppendLine("Group descriptor checksums and sparse inode table (ext4)");
|
||||
if ((supblk.ftr_ro_compat & EXT4_FEATURE_RO_COMPAT_DIR_NLINK) == EXT4_FEATURE_RO_COMPAT_DIR_NLINK)
|
||||
sb.AppendLine("More than 32000 directory entries (ext4)");
|
||||
if ((supblk.ftr_ro_compat & EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE) == EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE)
|
||||
sb.AppendLine("Supports nanosecond timestamps and creation time (ext4)");
|
||||
if ((supblk.ftr_ro_compat & 0xFFFFFF80) != 0)
|
||||
sb.AppendFormat("Unknown read-only compatible features: {0:X8}", supblk.ftr_ro_compat);
|
||||
|
||||
sb.AppendLine();
|
||||
|
||||
sb.AppendFormat("Incompatible features…:").AppendLine();
|
||||
if ((supblk.ftr_incompat & EXT2_FEATURE_INCOMPAT_COMPRESSION) == EXT2_FEATURE_INCOMPAT_COMPRESSION)
|
||||
sb.AppendLine("Uses compression");
|
||||
if ((supblk.ftr_incompat & EXT2_FEATURE_INCOMPAT_FILETYPE) == EXT2_FEATURE_INCOMPAT_FILETYPE)
|
||||
sb.AppendLine("Filetype in directory entries");
|
||||
if ((supblk.ftr_incompat & EXT3_FEATURE_INCOMPAT_RECOVER) == EXT3_FEATURE_INCOMPAT_RECOVER)
|
||||
sb.AppendLine("Journal needs recovery (ext3)");
|
||||
if ((supblk.ftr_incompat & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) == EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)
|
||||
sb.AppendLine("Has journal on another device (ext3)");
|
||||
if ((supblk.ftr_incompat & EXT2_FEATURE_INCOMPAT_META_BG) == EXT2_FEATURE_INCOMPAT_META_BG)
|
||||
sb.AppendLine("Reduced block group backups");
|
||||
if ((supblk.ftr_incompat & EXT4_FEATURE_INCOMPAT_EXTENTS) == EXT4_FEATURE_INCOMPAT_EXTENTS)
|
||||
sb.AppendLine("Volume use extents (ext4)");
|
||||
if ((supblk.ftr_incompat & EXT4_FEATURE_INCOMPAT_64BIT) == EXT4_FEATURE_INCOMPAT_64BIT)
|
||||
sb.AppendLine("Supports volumes bigger than 2^32 blocks (ext4)");
|
||||
if ((supblk.ftr_incompat & EXT4_FEATURE_INCOMPAT_MMP) == EXT4_FEATURE_INCOMPAT_MMP)
|
||||
sb.AppendLine("Multi-mount protection (ext4)");
|
||||
if ((supblk.ftr_incompat & EXT4_FEATURE_INCOMPAT_FLEX_BG) == EXT4_FEATURE_INCOMPAT_FLEX_BG)
|
||||
sb.AppendLine("Flexible block group metadata location (ext4)");
|
||||
if ((supblk.ftr_incompat & EXT4_FEATURE_INCOMPAT_EA_INODE) == EXT4_FEATURE_INCOMPAT_EA_INODE)
|
||||
sb.AppendLine("Extended attributes can reside in inode (ext4)");
|
||||
if ((supblk.ftr_incompat & EXT4_FEATURE_INCOMPAT_DIRDATA) == EXT4_FEATURE_INCOMPAT_DIRDATA)
|
||||
sb.AppendLine("Data can reside in directory entry (ext4)");
|
||||
if ((supblk.ftr_incompat & 0xFFFFF020) != 0)
|
||||
sb.AppendFormat("Unknown incompatible features: {0:X8}", supblk.ftr_incompat);
|
||||
|
||||
information = sb.ToString();
|
||||
}
|
||||
|
||||
public const UInt16 ext2FSMagic = 0xEF53;
|
||||
// Same for ext3 and ext4
|
||||
public const UInt16 ext2OldFSMagic = 0xEF51;
|
||||
// Size = 536 bytes
|
||||
public struct ext2FSSuperBlock
|
||||
{
|
||||
public UInt32 inodes;
|
||||
// 0x000, inodes on volume
|
||||
public UInt32 blocks;
|
||||
// 0x004, blocks on volume
|
||||
public UInt32 reserved_blocks;
|
||||
// 0x008, reserved blocks
|
||||
public UInt32 free_blocks;
|
||||
// 0x00C, free blocks count
|
||||
public UInt32 free_inodes;
|
||||
// 0x010, free inodes count
|
||||
public UInt32 first_block;
|
||||
// 0x014, first data block
|
||||
public UInt32 block_size;
|
||||
// 0x018, block size
|
||||
public Int32 frag_size;
|
||||
// 0x01C, fragment size
|
||||
public UInt32 blocks_per_grp;
|
||||
// 0x020, blocks per group
|
||||
public UInt32 flags_per_grp;
|
||||
// 0x024, fragments per group
|
||||
public UInt32 inodes_per_grp;
|
||||
// 0x028, inodes per group
|
||||
public UInt32 mount_t;
|
||||
// 0x02C, last mount time
|
||||
public UInt32 write_t;
|
||||
// 0x030, last write time
|
||||
public UInt16 mount_c;
|
||||
// 0x034, mounts count
|
||||
public Int16 max_mount_c;
|
||||
// 0x036, max mounts
|
||||
public UInt16 magic;
|
||||
// 0x038, (little endian)
|
||||
public UInt16 state;
|
||||
// 0x03A, filesystem state
|
||||
public UInt16 err_behaviour;
|
||||
// 0x03C, behaviour on errors
|
||||
public UInt16 minor_revision;
|
||||
// 0x03E, From 0.5b onward
|
||||
public UInt32 check_t;
|
||||
// 0x040, last check time
|
||||
public UInt32 check_inv;
|
||||
// 0x044, max time between checks
|
||||
// From 0.5a onward
|
||||
public UInt32 creator_os;
|
||||
// 0x048, Creation OS
|
||||
public UInt32 revision;
|
||||
// 0x04C, Revison level
|
||||
public UInt16 default_uid;
|
||||
// 0x050, Default UID for reserved blocks
|
||||
public UInt16 default_gid;
|
||||
// 0x052, Default GID for reserved blocks
|
||||
// From 0.5b onward
|
||||
public UInt32 first_inode;
|
||||
// 0x054, First unreserved inode
|
||||
public UInt16 inode_size;
|
||||
// 0x058, inode size
|
||||
public UInt16 block_group_no;
|
||||
// 0x05A, Block group number of THIS superblock
|
||||
public UInt32 ftr_compat;
|
||||
// 0x05C, Compatible features set
|
||||
public UInt32 ftr_incompat;
|
||||
// 0x060, Incompatible features set
|
||||
// Found on Linux 2.0.40
|
||||
public UInt32 ftr_ro_compat;
|
||||
// 0x064, Read-only compatible features set
|
||||
// Found on Linux 2.1.132
|
||||
public Guid uuid;
|
||||
// 0x068, 16 bytes, UUID
|
||||
public string volume_name;
|
||||
// 0x078, 16 bytes, volume name
|
||||
public string last_mount_dir;
|
||||
// 0x088, 64 bytes, where last mounted
|
||||
public UInt32 algo_usage_bmp;
|
||||
// 0x0C8, Usage bitmap algorithm, for compression
|
||||
public byte prealloc_blks;
|
||||
// 0x0CC, Block to try to preallocate
|
||||
public byte prealloc_dir_blks;
|
||||
// 0x0CD, Blocks to try to preallocate for directories
|
||||
public UInt16 rsrvd_gdt_blocks;
|
||||
// 0x0CE, Per-group desc for online growth
|
||||
// Found on Linux 2.4
|
||||
// ext3
|
||||
public Guid journal_uuid;
|
||||
// 0x0D0, 16 bytes, UUID of journal superblock
|
||||
public UInt32 journal_inode;
|
||||
// 0x0E0, inode no. of journal file
|
||||
public UInt32 journal_dev;
|
||||
// 0x0E4, device no. of journal file
|
||||
public UInt32 last_orphan;
|
||||
// 0x0E8, Start of list of inodes to delete
|
||||
public UInt32 hash_seed_1;
|
||||
// 0x0EC, First byte of 128bit HTREE hash seed
|
||||
public UInt32 hash_seed_2;
|
||||
// 0x0F0, Second byte of 128bit HTREE hash seed
|
||||
public UInt32 hash_seed_3;
|
||||
// 0x0F4, Third byte of 128bit HTREE hash seed
|
||||
public UInt32 hash_seed_4;
|
||||
// 0x0F8, Fourth byte of 128bit HTREE hash seed
|
||||
public byte hash_version;
|
||||
// 0x0FC, Hash version
|
||||
public byte jnl_backup_type;
|
||||
// 0x0FD, Journal backup type
|
||||
public UInt16 desc_grp_size;
|
||||
// 0x0FE, Size of group descriptor
|
||||
public UInt32 default_mnt_opts;
|
||||
// 0x100, Default mount options
|
||||
public UInt32 first_meta_bg;
|
||||
// 0x104, First metablock block group
|
||||
// Introduced with ext4, some can be ext3
|
||||
public UInt32 mkfs_t;
|
||||
// 0x108, Filesystem creation time
|
||||
// Follows 17 uint32 (68 bytes) of journal inode backup
|
||||
// Following 3 fields are valid if EXT4_FEATURE_COMPAT_64BIT is set
|
||||
public UInt32 blocks_hi;
|
||||
// 0x14C, High 32bits of blocks no.
|
||||
public UInt32 reserved_blocks_hi;
|
||||
// 0x150, High 32bits of reserved blocks no.
|
||||
public UInt32 free_blocks_hi;
|
||||
// 0x154, High 32bits of free blocks no.
|
||||
public UInt16 min_inode_size;
|
||||
// 0x158, inodes minimal size in bytes
|
||||
public UInt16 rsv_inode_size;
|
||||
// 0x15A, Bytes reserved by new inodes
|
||||
public UInt32 flags;
|
||||
// 0x15C, Flags
|
||||
public UInt16 raid_stride;
|
||||
// 0x160, RAID stride
|
||||
public UInt16 mmp_interval;
|
||||
// 0x162, Waiting seconds in MMP check
|
||||
public UInt64 mmp_block;
|
||||
// 0x164, Block for multi-mount protection
|
||||
public UInt32 raid_stripe_width;
|
||||
// 0x16C, Blocks on all data disks (N*stride)
|
||||
public byte flex_bg_grp_size;
|
||||
// 0x170, FLEX_BG group size
|
||||
public byte padding;
|
||||
// 0x171
|
||||
public UInt16 padding2;
|
||||
// 0x172
|
||||
// Following are introduced with ext4
|
||||
public UInt64 kbytes_written;
|
||||
// 0x174, Kibibytes written in volume lifetime
|
||||
public UInt32 snapshot_inum;
|
||||
// 0x17C, Active snapshot inode number
|
||||
public UInt32 snapshot_id;
|
||||
// 0x180, Active snapshot sequential ID
|
||||
public UInt64 snapshot_blocks;
|
||||
// 0x184, Reserved blocks for active snapshot's future use
|
||||
public UInt32 snapshot_list;
|
||||
// 0x18C, inode number of the on-disk start of the snapshot list
|
||||
// Optional ext4 error-handling features
|
||||
public UInt32 error_count;
|
||||
// 0x190, total registered filesystem errors
|
||||
public UInt32 first_error_t;
|
||||
// 0x194, time on first error
|
||||
public UInt32 first_error_inode;
|
||||
// 0x198, inode involved in first error
|
||||
public UInt64 first_error_block;
|
||||
// 0x19C, block involved of first error
|
||||
public string first_error_func;
|
||||
// 0x1A0, 32 bytes, function where the error happened
|
||||
public UInt32 first_error_line;
|
||||
// 0x1B0, line number where error happened
|
||||
public UInt32 last_error_t;
|
||||
// 0x1B4, time of most recent error
|
||||
public UInt32 last_error_inode;
|
||||
// 0x1B8, inode involved in last error
|
||||
public UInt32 last_error_line;
|
||||
// 0x1BC, line number where error happened
|
||||
public UInt64 last_error_block;
|
||||
// 0x1C0, block involved of last error
|
||||
public string last_error_func;
|
||||
// 0x1C8, 32 bytes, function where the error happened
|
||||
// End of optional error-handling features
|
||||
public string mount_options;
|
||||
// 0x1D8, 64 bytes, last used mount options
|
||||
}
|
||||
// ext? filesystem states
|
||||
public const UInt16 EXT2_VALID_FS = 0x0001;
|
||||
// Cleanly-unmounted volume
|
||||
public const UInt16 EXT2_ERROR_FS = 0x0002;
|
||||
// Dirty volume
|
||||
public const UInt16 EXT3_ORPHAN_FS = 0x0004;
|
||||
// Recovering orphan files
|
||||
// ext? default mount flags
|
||||
public const UInt32 EXT2_DEFM_DEBUG = 0x000001;
|
||||
// Enable debugging messages
|
||||
public const UInt32 EXT2_DEFM_BSDGROUPS = 0x000002;
|
||||
// Emulates BSD behaviour on new file creation
|
||||
public const UInt32 EXT2_DEFM_XATTR_USER = 0x000004;
|
||||
// Enable user xattrs
|
||||
public const UInt32 EXT2_DEFM_ACL = 0x000008;
|
||||
// Enable POSIX ACLs
|
||||
public const UInt32 EXT2_DEFM_UID16 = 0x000010;
|
||||
// Use 16bit UIDs
|
||||
public const UInt32 EXT3_DEFM_JMODE_DATA = 0x000040;
|
||||
// Journal data mode
|
||||
public const UInt32 EXT3_DEFM_JMODE_ORDERED = 0x000080;
|
||||
// Journal ordered mode
|
||||
public const UInt32 EXT3_DEFM_JMODE_WBACK = 0x000100;
|
||||
// Journal writeback mode
|
||||
// Behaviour on errors
|
||||
public const UInt16 EXT2_ERRORS_CONTINUE = 1;
|
||||
// Continue execution
|
||||
public const UInt16 EXT2_ERRORS_RO = 2;
|
||||
// Remount fs read-only
|
||||
public const UInt16 EXT2_ERRORS_PANIC = 3;
|
||||
// Panic
|
||||
// OS codes
|
||||
public const UInt32 EXT2_OS_LINUX = 0;
|
||||
public const UInt32 EXT2_OS_HURD = 1;
|
||||
public const UInt32 EXT2_OS_MASIX = 2;
|
||||
public const UInt32 EXT2_OS_FREEBSD = 3;
|
||||
public const UInt32 EXT2_OS_LITES = 4;
|
||||
// Revision levels
|
||||
public const UInt32 EXT2_GOOD_OLD_REV = 0;
|
||||
/* The good old (original) format */
|
||||
public const UInt32 EXT2_DYNAMIC_REV = 1;
|
||||
/* V2 format w/ dynamic inode sizes */
|
||||
// Compatible features
|
||||
public const UInt32 EXT2_FEATURE_COMPAT_DIR_PREALLOC = 0x00000001;
|
||||
// Pre-allocate directories
|
||||
public const UInt32 EXT2_FEATURE_COMPAT_IMAGIC_INODES = 0x00000002;
|
||||
// imagic inodes ?
|
||||
public const UInt32 EXT3_FEATURE_COMPAT_HAS_JOURNAL = 0x00000004;
|
||||
// Has journal (it's ext3)
|
||||
public const UInt32 EXT2_FEATURE_COMPAT_EXT_ATTR = 0x00000008;
|
||||
// EA blocks
|
||||
public const UInt32 EXT2_FEATURE_COMPAT_RESIZE_INO = 0x00000010;
|
||||
// Online filesystem resize reservations
|
||||
public const UInt32 EXT2_FEATURE_COMPAT_DIR_INDEX = 0x00000020;
|
||||
// Can use hashed indexes on directories
|
||||
// Read-only compatible features
|
||||
public const UInt32 EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER = 0x00000001;
|
||||
// Reduced number of superblocks
|
||||
public const UInt32 EXT2_FEATURE_RO_COMPAT_LARGE_FILE = 0x00000002;
|
||||
// Can have files bigger than 2GiB
|
||||
public const UInt32 EXT2_FEATURE_RO_COMPAT_BTREE_DIR = 0x00000004;
|
||||
// Use B-Tree for directories
|
||||
public const UInt32 EXT4_FEATURE_RO_COMPAT_HUGE_FILE = 0x00000008;
|
||||
// Can have files bigger than 2TiB *ext4*
|
||||
public const UInt32 EXT4_FEATURE_RO_COMPAT_GDT_CSUM = 0x00000010;
|
||||
// Group descriptor checksums and sparse inode table *ext4*
|
||||
public const UInt32 EXT4_FEATURE_RO_COMPAT_DIR_NLINK = 0x00000020;
|
||||
// More than 32000 directory entries *ext4*
|
||||
public const UInt32 EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE = 0x00000040;
|
||||
// Nanosecond timestamps and creation time *ext4*
|
||||
// Incompatible features
|
||||
public const UInt32 EXT2_FEATURE_INCOMPAT_COMPRESSION = 0x00000001;
|
||||
// Uses compression
|
||||
public const UInt32 EXT2_FEATURE_INCOMPAT_FILETYPE = 0x00000002;
|
||||
// Filetype in directory entries
|
||||
public const UInt32 EXT3_FEATURE_INCOMPAT_RECOVER = 0x00000004;
|
||||
// Journal needs recovery *ext3*
|
||||
public const UInt32 EXT3_FEATURE_INCOMPAT_JOURNAL_DEV = 0x00000008;
|
||||
// Has journal on another device *ext3*
|
||||
public const UInt32 EXT2_FEATURE_INCOMPAT_META_BG = 0x00000010;
|
||||
// Reduced block group backups
|
||||
public const UInt32 EXT4_FEATURE_INCOMPAT_EXTENTS = 0x00000040;
|
||||
// Volume use extents *ext4*
|
||||
public const UInt32 EXT4_FEATURE_INCOMPAT_64BIT = 0x00000080;
|
||||
// Supports volumes bigger than 2^32 blocks *ext4*
|
||||
public const UInt32 EXT4_FEATURE_INCOMPAT_MMP = 0x00000100;
|
||||
// Multi-mount protection *ext4*
|
||||
public const UInt32 EXT4_FEATURE_INCOMPAT_FLEX_BG = 0x00000200;
|
||||
// Flexible block group metadata location *ext4*
|
||||
public const UInt32 EXT4_FEATURE_INCOMPAT_EA_INODE = 0x00000400;
|
||||
// EA in inode *ext4*
|
||||
public const UInt32 EXT4_FEATURE_INCOMPAT_DIRDATA = 0x00001000;
|
||||
// Data can reside in directory entry *ext4*
|
||||
// Miscellaneous filesystem flags
|
||||
public const UInt32 EXT2_FLAGS_SIGNED_HASH = 0x00000001;
|
||||
// Signed dirhash in use
|
||||
public const UInt32 EXT2_FLAGS_UNSIGNED_HASH = 0x00000002;
|
||||
// Unsigned dirhash in use
|
||||
public const UInt32 EXT2_FLAGS_TEST_FILESYS = 0x00000004;
|
||||
// Testing development code
|
||||
}
|
||||
}
|
||||
@@ -1,134 +0,0 @@
|
||||
/***************************************************************************
|
||||
The Disc Image Chef
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
Filename : extFS.cs
|
||||
Version : 1.0
|
||||
Author(s) : Natalia Portillo
|
||||
|
||||
Component : Filesystem plugins
|
||||
|
||||
Revision : $Revision$
|
||||
Last change by : $Author$
|
||||
Date : $Date$
|
||||
|
||||
--[ Description ] ----------------------------------------------------------
|
||||
|
||||
Identifies Linux extended filesystem and shows information.
|
||||
|
||||
--[ License ] --------------------------------------------------------------
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
----------------------------------------------------------------------------
|
||||
Copyright (C) 2011-2014 Claunia.com
|
||||
****************************************************************************/
|
||||
//$Id$
|
||||
|
||||
using System;
|
||||
using System.Text;
|
||||
using DiscImageChef;
|
||||
|
||||
// Information from the Linux kernel
|
||||
namespace DiscImageChef.Plugins
|
||||
{
|
||||
class extFS : Plugin
|
||||
{
|
||||
public extFS(PluginBase Core)
|
||||
{
|
||||
Name = "Linux extended Filesystem";
|
||||
PluginUUID = new Guid("076CB3A2-08C2-4D69-BC8A-FCAA2E502BE2");
|
||||
}
|
||||
|
||||
public override bool Identify(ImagePlugins.ImagePlugin imagePlugin, ulong partitionStart, ulong partitionEnd)
|
||||
{
|
||||
if ((2 + partitionStart) >= imagePlugin.GetSectors())
|
||||
return false;
|
||||
|
||||
byte[] sb_sector = imagePlugin.ReadSector(2 + partitionStart); // Superblock resides at 0x400
|
||||
|
||||
UInt16 magic = BitConverter.ToUInt16(sb_sector, 0x038); // Here should reside magic number
|
||||
|
||||
return magic == extFSMagic;
|
||||
}
|
||||
|
||||
public override void GetInformation(ImagePlugins.ImagePlugin imagePlugin, ulong partitionStart, ulong partitionEnd, out string information)
|
||||
{
|
||||
information = "";
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
byte[] sb_sector = imagePlugin.ReadSector(2 + partitionStart); // Superblock resides at 0x400
|
||||
extFSSuperBlock ext_sb = new extFSSuperBlock();
|
||||
|
||||
ext_sb.inodes = BitConverter.ToUInt32(sb_sector, 0x000);
|
||||
ext_sb.zones = BitConverter.ToUInt32(sb_sector, 0x004);
|
||||
ext_sb.firstfreeblk = BitConverter.ToUInt32(sb_sector, 0x008);
|
||||
ext_sb.freecountblk = BitConverter.ToUInt32(sb_sector, 0x00C);
|
||||
ext_sb.firstfreeind = BitConverter.ToUInt32(sb_sector, 0x010);
|
||||
ext_sb.freecountind = BitConverter.ToUInt32(sb_sector, 0x014);
|
||||
ext_sb.firstdatazone = BitConverter.ToUInt32(sb_sector, 0x018);
|
||||
ext_sb.logzonesize = BitConverter.ToUInt32(sb_sector, 0x01C);
|
||||
ext_sb.maxsize = BitConverter.ToUInt32(sb_sector, 0x020);
|
||||
|
||||
sb.AppendLine("ext filesystem");
|
||||
sb.AppendFormat("{0} zones on volume", ext_sb.zones);
|
||||
sb.AppendFormat("{0} free blocks ({1} bytes)", ext_sb.freecountblk, ext_sb.freecountblk * 1024);
|
||||
sb.AppendFormat("{0} inodes on volume, {1} free ({2}%)", ext_sb.inodes, ext_sb.freecountind, ext_sb.freecountind * 100 / ext_sb.inodes);
|
||||
sb.AppendFormat("First free inode is {0}", ext_sb.firstfreeind);
|
||||
sb.AppendFormat("First free block is {0}", ext_sb.firstfreeblk);
|
||||
sb.AppendFormat("First data zone is {0}", ext_sb.firstdatazone);
|
||||
sb.AppendFormat("Log zone size: {0}", ext_sb.logzonesize);
|
||||
sb.AppendFormat("Max zone size: {0}", ext_sb.maxsize);
|
||||
|
||||
information = sb.ToString();
|
||||
}
|
||||
|
||||
public const UInt16 extFSMagic = 0x137D;
|
||||
|
||||
public struct extFSSuperBlock
|
||||
{
|
||||
public UInt32 inodes;
|
||||
// 0x000, inodes on volume
|
||||
public UInt32 zones;
|
||||
// 0x004, zones on volume
|
||||
public UInt32 firstfreeblk;
|
||||
// 0x008, first free block
|
||||
public UInt32 freecountblk;
|
||||
// 0x00C, free blocks count
|
||||
public UInt32 firstfreeind;
|
||||
// 0x010, first free inode
|
||||
public UInt32 freecountind;
|
||||
// 0x014, free inodes count
|
||||
public UInt32 firstdatazone;
|
||||
// 0x018, first data zone
|
||||
public UInt32 logzonesize;
|
||||
// 0x01C, log zone size
|
||||
public UInt32 maxsize;
|
||||
// 0x020, max zone size
|
||||
public UInt32 reserved1;
|
||||
// 0x024, reserved
|
||||
public UInt32 reserved2;
|
||||
// 0x028, reserved
|
||||
public UInt32 reserved3;
|
||||
// 0x02C, reserved
|
||||
public UInt32 reserved4;
|
||||
// 0x030, reserved
|
||||
public UInt32 reserved5;
|
||||
// 0x034, reserved
|
||||
public UInt16 magic;
|
||||
// 0x038, 0x137D (little endian)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user