Move filesystems to a separate library.

This commit is contained in:
2015-10-05 20:04:05 +01:00
parent fda7fee90c
commit 80a1e37009
31 changed files with 243 additions and 81 deletions

View File

@@ -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:

View File

@@ -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>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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

View File

@@ -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)
}
}
}

View File

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

View File

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

View File

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

View File

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

View File

@@ -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)
}
}
}

View File

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

View File

@@ -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 = "";
}
}
}

View File

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

View File

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

View File

@@ -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 "
}
}
}

View File

@@ -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
}
}
}
*/

View File

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

View File

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

View File

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

View File

@@ -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)
}
}
}