Rename project folder.

This commit is contained in:
2014-06-15 23:41:50 +01:00
parent 4e888f175c
commit ed86f9742b
46 changed files with 2 additions and 2 deletions

View File

@@ -0,0 +1,70 @@
/***************************************************************************
The Disc Image Chef
----------------------------------------------------------------------------
Filename : ArrayFill.cs
Version : 1.0
Author(s) : https://github.com/mykohsu
Component : Helpers
Revision : $Revision$
Last change by : $Author$
Date : $Date$
--[ Description ] ----------------------------------------------------------
Fills an array with a
--[ License ] --------------------------------------------------------------
No license specified by creator.
Published on https://github.com/mykohsu/Extensions/blob/master/ArrayExtensions.cs
Assuming open source.
----------------------------------------------------------------------------
Copyright (C) 2014 mykohsu
****************************************************************************/
//$Id$
using System;
namespace DiscImageChef
{
public static class ArrayHelpers
{
public static void ArrayFill<T>(T[] destinationArray, T value)
{
// if called with a single value, wrap the value in an array and call the main function
ArrayFill<T>(destinationArray, new T[] { value });
}
public static void ArrayFill<T>(T[] destinationArray, T[] value)
{
if (destinationArray == null)
{
throw new ArgumentNullException("destinationArray");
}
if (value.Length > destinationArray.Length)
{
throw new ArgumentException("Length of value array must not be more than length of destination");
}
// set the initial array value
Array.Copy(value, destinationArray, value.Length);
int arrayToFillHalfLength = destinationArray.Length / 2;
int copyLength;
for(copyLength = value.Length; copyLength < arrayToFillHalfLength; copyLength <<= 1)
{
Array.Copy(destinationArray, 0, destinationArray, copyLength, copyLength);
}
Array.Copy(destinationArray, 0, destinationArray, copyLength, destinationArray.Length - copyLength);
}
}
}

View File

@@ -0,0 +1,64 @@
/***************************************************************************
The Disc Image Chef
----------------------------------------------------------------------------
Filename : AssemblyInfo.cs
Version : 1.0
Author(s) : Natalia Portillo
Component : Main loop
Revision : $Revision$
Last change by : $Author$
Date : $Date$
--[ Description ] ----------------------------------------------------------
C# assembly definitions
--[ 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.Reflection;
// Information about this assembly is defined by the following attributes.
// Change them to the values specific to your project.
[assembly: AssemblyTitle("DiscImageChef")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("")]
[assembly: AssemblyCopyright("")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}".
// The form "{Major}.{Minor}.*" will automatically update the build and revision,
// and "{Major}.{Minor}.{Build}.*" will update just the revision.
[assembly: AssemblyVersion("1.0.*")]
// The following attributes are used to specify the signing key for the assembly,
// if desired. See the Mono documentation for more information about signing.
//[assembly: AssemblyDelaySign(false)]
//[assembly: AssemblyKeyFile("")]

View File

@@ -0,0 +1,649 @@
/***************************************************************************
The Disc Image Chef
----------------------------------------------------------------------------
Filename : BigEndianBitConverter.cs
Version : 1.0
Author(s) : Natalia Portillo
Component : Program tools
Revision : $Revision$
Last change by : $Author$
Date : $Date$
--[ Description ] ----------------------------------------------------------
Override of System.BitConverter that knows how to handle big-endian.
--[ 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.Linq;
namespace DiscImageChef
{
/// <summary>
/// Converts base data types to an array of bytes, and an array of bytes to base
/// data types.
/// All info taken from the meta data of System.BitConverter. This implementation
/// allows for Endianness consideration.
///</summary>
public static class BigEndianBitConverter
{
/// <summary>
/// Indicates the byte order ("endianess") in which data is stored in this computer
/// architecture.
///</summary>
public static bool IsLittleEndian { get; set; }
// should default to false, which is what we want for Empire
/// <summary>
/// Converts the specified double-precision floating point number to a 64-bit
/// signed integer.
///
/// Parameters:
/// value:
/// The number to convert.
///
/// Returns:
/// A 64-bit signed integer whose value is equivalent to value.
///</summary>
public static long DoubleToInt64Bits(double value)
{
throw new NotImplementedException();
}
///
/// <summary>
/// Returns the specified Boolean value as an array of bytes.
///
/// Parameters:
/// value:
/// A Boolean value.
///
/// Returns:
/// An array of bytes with length 1.
///</summary>
public static byte[] GetBytes(bool value)
{
return !IsLittleEndian ? BitConverter.GetBytes(value) : BitConverter.GetBytes(value).Reverse().ToArray();
}
///
/// <summary>
/// Returns the specified Unicode character value as an array of bytes.
///
/// Parameters:
/// value:
/// A character to convert.
///
/// Returns:
/// An array of bytes with length 2.
///</summary>
public static byte[] GetBytes(char value)
{
return !IsLittleEndian ? BitConverter.GetBytes(value) : BitConverter.GetBytes(value).Reverse().ToArray();
}
///
/// <summary>
/// Returns the specified double-precision floating point value as an array of
/// bytes.
///
/// Parameters:
/// value:
/// The number to convert.
///
/// Returns:
/// An array of bytes with length 8.
///</summary>
public static byte[] GetBytes(double value)
{
return !IsLittleEndian ? BitConverter.GetBytes(value) : BitConverter.GetBytes(value).Reverse().ToArray();
}
///
/// <summary>
/// Returns the specified single-precision floating point value as an array of
/// bytes.
///
/// Parameters:
/// value:
/// The number to convert.
///
/// Returns:
/// An array of bytes with length 4.
///</summary>
public static byte[] GetBytes(float value)
{
return !IsLittleEndian ? BitConverter.GetBytes(value) : BitConverter.GetBytes(value).Reverse().ToArray();
}
///
/// <summary>
/// Returns the specified 32-bit signed integer value as an array of bytes.
///
/// Parameters:
/// value:
/// The number to convert.
///
/// Returns:
/// An array of bytes with length 4.
///</summary>
public static byte[] GetBytes(int value)
{
return !IsLittleEndian ? BitConverter.GetBytes(value) : BitConverter.GetBytes(value).Reverse().ToArray();
}
///
/// <summary>
/// Returns the specified 64-bit signed integer value as an array of bytes.
///
/// Parameters:
/// value:
/// The number to convert.
///
/// Returns:
/// An array of bytes with length 8.
///</summary>
public static byte[] GetBytes(long value)
{
return !IsLittleEndian ? BitConverter.GetBytes(value) : BitConverter.GetBytes(value).Reverse().ToArray();
}
///
/// <summary>
/// Returns the specified 16-bit signed integer value as an array of bytes.
///
/// Parameters:
/// value:
/// The number to convert.
///
/// Returns:
/// An array of bytes with length 2.
///</summary>
public static byte[] GetBytes(short value)
{
return !IsLittleEndian ? BitConverter.GetBytes(value) : BitConverter.GetBytes(value).Reverse().ToArray();
}
///
/// <summary>
/// Returns the specified 32-bit unsigned integer value as an array of bytes.
///
/// Parameters:
/// value:
/// The number to convert.
///
/// Returns:
/// An array of bytes with length 4.
///</summary>
//[CLSCompliant(false)]
public static byte[] GetBytes(uint value)
{
return !IsLittleEndian ? BitConverter.GetBytes(value) : BitConverter.GetBytes(value).Reverse().ToArray();
}
///
/// <summary>
/// Returns the specified 64-bit unsigned integer value as an array of bytes.
///
/// Parameters:
/// value:
/// The number to convert.
///
/// Returns:
/// An array of bytes with length 8.
///</summary>
//[CLSCompliant(false)]
public static byte[] GetBytes(ulong value)
{
return !IsLittleEndian ? BitConverter.GetBytes(value) : BitConverter.GetBytes(value).Reverse().ToArray();
}
///
/// <summary>
/// Returns the specified 16-bit unsigned integer value as an array of bytes.
///
/// Parameters:
/// value:
/// The number to convert.
///
/// Returns:
/// An array of bytes with length 2.
///</summary>
public static byte[] GetBytes(ushort value)
{
return !IsLittleEndian ? BitConverter.GetBytes(value) : BitConverter.GetBytes(value).Reverse().ToArray();
}
///
/// <summary>
/// Converts the specified 64-bit signed integer to a double-precision floating
/// point number.
///
/// Parameters:
/// value:
/// The number to convert.
///
/// Returns:
/// A double-precision floating point number whose value is equivalent to value.
///</summary>
public static double Int64BitsToDouble(long value)
{
throw new NotImplementedException();
}
///
/// <summary>
/// Returns a Boolean value converted from one byte at a specified position in
/// a byte array.
///
/// Parameters:
/// value:
/// An array of bytes.
///
/// startIndex:
/// The starting position within value.
///
/// Returns:
/// true if the byte at startIndex in value is nonzero; otherwise, false.
///
/// Exceptions:
/// System.ArgumentNullException:
/// value is null.
///
/// System.ArgumentOutOfRangeException:
/// startIndex is less than zero or greater than the length of value minus 1.
///</summary>
public static bool ToBoolean(byte[] value, int startIndex)
{
throw new NotImplementedException();
}
///
/// <summary>
/// Returns a Unicode character converted from two bytes at a specified position
/// in a byte array.
///
/// Parameters:
/// value:
/// An array.
///
/// startIndex:
/// The starting position within value.
///
/// Returns:
/// A character formed by two bytes beginning at startIndex.
///
/// Exceptions:
/// System.ArgumentException:
/// startIndex equals the length of value minus 1.
///
/// System.ArgumentNullException:
/// value is null.
///
/// System.ArgumentOutOfRangeException:
/// startIndex is less than zero or greater than the length of value minus 1.
///</summary>
public static char ToChar(byte[] value, int startIndex)
{
throw new NotImplementedException();
}
///
/// <summary>
/// Returns a double-precision floating point number converted from eight bytes
/// at a specified position in a byte array.
///
/// Parameters:
/// value:
/// An array of bytes.
///
/// startIndex:
/// The starting position within value.
///
/// Returns:
/// A double precision floating point number formed by eight bytes beginning
/// at startIndex.
///
/// Exceptions:
/// System.ArgumentException:
/// startIndex is greater than or equal to the length of value minus 7, and is
/// less than or equal to the length of value minus 1.
///
/// System.ArgumentNullException:
/// value is null.
///
/// System.ArgumentOutOfRangeException:
/// startIndex is less than zero or greater than the length of value minus 1.
///</summary>
public static double ToDouble(byte[] value, int startIndex)
{
throw new NotImplementedException();
}
///
/// <summary>
/// Returns a 16-bit signed integer converted from two bytes at a specified position
/// in a byte array.
///
/// Parameters:
/// value:
/// An array of bytes.
///
/// startIndex:
/// The starting position within value.
///
/// Returns:
/// A 16-bit signed integer formed by two bytes beginning at startIndex.
///
/// Exceptions:
/// System.ArgumentException:
/// startIndex equals the length of value minus 1.
///
/// System.ArgumentNullException:
/// value is null.
///
/// System.ArgumentOutOfRangeException:
/// startIndex is less than zero or greater than the length of value minus 1.
///</summary>
public static short ToInt16(byte[] value, int startIndex)
{
return !IsLittleEndian ? BitConverter.ToInt16(value, startIndex) : BitConverter.ToInt16(value.Reverse().ToArray(), value.Length - sizeof(Int16) - startIndex);
}
///
/// <summary>
/// Returns a 32-bit signed integer converted from four bytes at a specified
/// position in a byte array.
///
/// Parameters:
/// value:
/// An array of bytes.
///
/// startIndex:
/// The starting position within value.
///
/// Returns:
/// A 32-bit signed integer formed by four bytes beginning at startIndex.
///
/// Exceptions:
/// System.ArgumentException:
/// startIndex is greater than or equal to the length of value minus 3, and is
/// less than or equal to the length of value minus 1.
///
/// System.ArgumentNullException:
/// value is null.
///
/// System.ArgumentOutOfRangeException:
/// startIndex is less than zero or greater than the length of value minus 1.
///</summary>
public static int ToInt32(byte[] value, int startIndex)
{
return !IsLittleEndian ? BitConverter.ToInt32(value, startIndex) : BitConverter.ToInt32(value.Reverse().ToArray(), value.Length - sizeof(Int32) - startIndex);
}
///
/// <summary>
/// Returns a 64-bit signed integer converted from eight bytes at a specified
/// position in a byte array.
///
/// Parameters:
/// value:
/// An array of bytes.
///
/// startIndex:
/// The starting position within value.
///
/// Returns:
/// A 64-bit signed integer formed by eight bytes beginning at startIndex.
///
/// Exceptions:
/// System.ArgumentException:
/// startIndex is greater than or equal to the length of value minus 7, and is
/// less than or equal to the length of value minus 1.
///
/// System.ArgumentNullException:
/// value is null.
///
/// System.ArgumentOutOfRangeException:
/// startIndex is less than zero or greater than the length of value minus 1.
///</summary>
public static long ToInt64(byte[] value, int startIndex)
{
return !IsLittleEndian ? BitConverter.ToInt64(value, startIndex) : BitConverter.ToInt64(value.Reverse().ToArray(), value.Length - sizeof(Int64) - startIndex);
}
///
/// <summary>
/// Returns a single-precision floating point number converted from four bytes
/// at a specified position in a byte array.
///
/// Parameters:
/// value:
/// An array of bytes.
///
/// startIndex:
/// The starting position within value.
///
/// Returns:
/// A single-precision floating point number formed by four bytes beginning at
/// startIndex.
///
/// Exceptions:
/// System.ArgumentException:
/// startIndex is greater than or equal to the length of value minus 3, and is
/// less than or equal to the length of value minus 1.
///
/// System.ArgumentNullException:
/// value is null.
///
/// System.ArgumentOutOfRangeException:
/// startIndex is less than zero or greater than the length of value minus 1.
///</summary>
public static float ToSingle(byte[] value, int startIndex)
{
return !IsLittleEndian ? BitConverter.ToSingle(value, startIndex) : BitConverter.ToSingle(value.Reverse().ToArray(), value.Length - sizeof(Single) - startIndex);
}
///
/// <summary>
/// Converts the numeric value of each element of a specified array of bytes
/// to its equivalent hexadecimal string representation.
///
/// Parameters:
/// value:
/// An array of bytes.
///
/// Returns:
/// A System.String of hexadecimal pairs separated by hyphens, where each pair
/// represents the corresponding element in value; for example, "7F-2C-4A".
///
/// Exceptions:
/// System.ArgumentNullException:
/// value is null.
///</summary>
public static string ToString(byte[] value)
{
return !IsLittleEndian ? BitConverter.ToString(value) : BitConverter.ToString(value.Reverse().ToArray());
}
///
/// <summary>
/// Converts the numeric value of each element of a specified subarray of bytes
/// to its equivalent hexadecimal string representation.
///
/// Parameters:
/// value:
/// An array of bytes.
///
/// startIndex:
/// The starting position within value.
///
/// Returns:
/// A System.String of hexadecimal pairs separated by hyphens, where each pair
/// represents the corresponding element in a subarray of value; for example,
/// "7F-2C-4A".
///
/// Exceptions:
/// System.ArgumentNullException:
/// value is null.
///
/// System.ArgumentOutOfRangeException:
/// startIndex is less than zero or greater than the length of value minus 1.
///</summary>
public static string ToString(byte[] value, int startIndex)
{
return !IsLittleEndian ? BitConverter.ToString(value, startIndex) : BitConverter.ToString(value.Reverse().ToArray(), startIndex);
}
///
/// <summary>
/// Converts the numeric value of each element of a specified subarray of bytes
/// to its equivalent hexadecimal string representation.
///
/// Parameters:
/// value:
/// An array of bytes.
///
/// startIndex:
/// The starting position within value.
///
/// length:
/// The number of array elements in value to convert.
///
/// Returns:
/// A System.String of hexadecimal pairs separated by hyphens, where each pair
/// represents the corresponding element in a subarray of value; for example,
/// "7F-2C-4A".
///
/// Exceptions:
/// System.ArgumentNullException:
/// value is null.
///
/// System.ArgumentOutOfRangeException:
/// startIndex or length is less than zero. -or- startIndex is greater than
/// zero and is greater than or equal to the length of value.
///
/// System.ArgumentException:
/// The combination of startIndex and length does not specify a position within
/// value; that is, the startIndex parameter is greater than the length of value
/// minus the length parameter.
///</summary>
public static string ToString(byte[] value, int startIndex, int length)
{
return !IsLittleEndian ? BitConverter.ToString(value, startIndex, length) : BitConverter.ToString(value.Reverse().ToArray(), startIndex, length);
}
///
/// <summary>
/// Returns a 16-bit unsigned integer converted from two bytes at a specified
/// position in a byte array.
///
/// Parameters:
/// value:
/// The array of bytes.
///
/// startIndex:
/// The starting position within value.
///
/// Returns:
/// A 16-bit unsigned integer formed by two bytes beginning at startIndex.
///
/// Exceptions:
/// System.ArgumentException:
/// startIndex equals the length of value minus 1.
///
/// System.ArgumentNullException:
/// value is null.
///
/// System.ArgumentOutOfRangeException:
/// startIndex is less than zero or greater than the length of value minus 1.
///</summary>
public static ushort ToUInt16(byte[] value, int startIndex)
{
return !IsLittleEndian ? BitConverter.ToUInt16(value, startIndex) : BitConverter.ToUInt16(value.Reverse().ToArray(), value.Length - sizeof(UInt16) - startIndex);
}
///
/// <summary>
/// Returns a 32-bit unsigned integer converted from four bytes at a specified
/// position in a byte array.
///
/// Parameters:
/// value:
/// An array of bytes.
///
/// startIndex:
/// The starting position within value.
///
/// Returns:
/// A 32-bit unsigned integer formed by four bytes beginning at startIndex.
///
/// Exceptions:
/// System.ArgumentException:
/// startIndex is greater than or equal to the length of value minus 3, and is
/// less than or equal to the length of value minus 1.
///
/// System.ArgumentNullException:
/// value is null.
///
/// System.ArgumentOutOfRangeException:
/// startIndex is less than zero or greater than the length of value minus 1.
///</summary>
public static uint ToUInt32(byte[] value, int startIndex)
{
return !IsLittleEndian ? BitConverter.ToUInt32(value, startIndex) : BitConverter.ToUInt32(value.Reverse().ToArray(), value.Length - sizeof(UInt32) - startIndex);
}
///
/// <summary>
/// Returns a 64-bit unsigned integer converted from eight bytes at a specified
/// position in a byte array.
///
/// Parameters:
/// value:
/// An array of bytes.
///
/// startIndex:
/// The starting position within value.
///
/// Returns:
/// A 64-bit unsigned integer formed by the eight bytes beginning at startIndex.
///
/// Exceptions:
/// System.ArgumentException:
/// startIndex is greater than or equal to the length of value minus 7, and is
/// less than or equal to the length of value minus 1.
///
/// System.ArgumentNullException:
/// value is null.
///
/// System.ArgumentOutOfRangeException:
/// startIndex is less than zero or greater than the length of value minus 1.
///</summary>
public static ulong ToUInt64(byte[] value, int startIndex)
{
return !IsLittleEndian ? BitConverter.ToUInt64(value, startIndex) : BitConverter.ToUInt64(value.Reverse().ToArray(), value.Length - sizeof(UInt64) - startIndex);
}
}
}

456
DiscImageChef/ChangeLog Normal file
View File

@@ -0,0 +1,456 @@
2014-04-21 Natalia Portillo <claunia@claunia.com>
* ImagePlugins/TeleDisk.cs:
Start to implement OpenImage(), decode comment block.
2014-04-21 Natalia Portillo <claunia@claunia.com>
* ImagePlugins/TeleDisk.cs:
Added CRC calculation method and check of header using CRC
to return a positive identification.
2014-04-19 Natalia Portillo <claunia@claunia.com>
* ImagePlugins/TeleDisk.cs:
* FileSystemIDandChk.csproj:
Started Sydex TeleDisk implementation, with structs,
constants and initial Identify() implementation.
2014-04-19 Natalia Portillo <claunia@claunia.com>
* LICENSE:
* Main.cs:
* Plugins.cs:
* Swapping.cs:
* Plugins/BFS.cs:
* Plugins/FFS.cs:
* Plugins/ODS.cs:
* Plugins/FAT.cs:
* Plugins/SysV.cs:
* Plugins/NTFS.cs:
* AssemblyInfo.cs:
* Plugins/HPFS.cs:
* DateHandlers.cs:
* Plugins/Opera.cs:
* Plugins/extFS.cs:
* Plugins/ext2FS.cs:
* Plugins/LisaFS.cs:
* StringHandlers.cs:
* Plugins/Plugin.cs:
* Plugins/MinixFS.cs:
* Plugins/UNIXBFS.cs:
* Plugins/ISO9660.cs:
* Plugins/Symbian.cs:
* Plugins/SolarFS.cs:
* PartPlugins/MBR.cs:
* PartPlugins/NeXT.cs:
* Plugins/AppleMFS.cs:
* Plugins/PCEngine.cs:
* Plugins/AppleHFS.cs:
* ImagePlugins/CDRWin.cs:
* Plugins/AppleHFSPlus.cs:
* PartPlugins/AppleMap.cs:
* BigEndianBitConverter.cs:
* PartPlugins/PartPlugin.cs:
* EndianAwareBinaryReader.cs:
* ImagePlugins/DiskCopy42.cs:
* ImagePlugins/ImagePlugin.cs:
Change license from AGPLv3 to GPLv3 to make some good
friends happier, and be able to use code from Linux if ever
*ever* needed.
2014-04-17 Natalia Portillo <claunia@claunia.com>
* TODO:
* LICENSE:
* Main.cs:
* README.md:
* FileSystemIDandChk.csproj:
Add documentation and license and prepare for publication
2014-04-17 Natalia Portillo <claunia@claunia.com>
* Main.cs:
* Plugins.cs:
* Swapping.cs:
* Plugins/ODS.cs:
* Plugins/FFS.cs:
* Plugins/FAT.cs:
* Plugins/BFS.cs:
* Plugins/SysV.cs:
* DateHandlers.cs:
* Plugins/NTFS.cs:
* AssemblyInfo.cs:
* Plugins/HPFS.cs:
* Plugins/Opera.cs:
* Plugins/extFS.cs:
* Plugins/Plugin.cs:
* Plugins/LisaFS.cs:
* StringHandlers.cs:
* Plugins/ext2FS.cs:
* PartPlugins/MBR.cs:
* Plugins/MinixFS.cs:
* Plugins/UNIXBFS.cs:
* Plugins/ISO9660.cs:
* Plugins/Symbian.cs:
* Plugins/SolarFS.cs:
* Plugins/PCEngine.cs:
* Plugins/AppleHFS.cs:
* PartPlugins/NeXT.cs:
* Plugins/AppleMFS.cs:
* ImagePlugins/CDRWin.cs:
* Plugins/AppleHFSPlus.cs:
* PartPlugins/AppleMap.cs:
* BigEndianBitConverter.cs:
* PartPlugins/PartPlugin.cs:
* ImagePlugins/DiskCopy42.cs:
* EndianAwareBinaryReader.cs:
* ImagePlugins/ImagePlugin.cs:
Added information and license header.
2014-04-17 Natalia Portillo <claunia@claunia.com>
* DateHandlers.cs:
Lisa epoch is 1901 not 1904
* Plugins/LisaFS.cs:
Typos corrected, now works perfectly
2014-04-17 Natalia Portillo <claunia@claunia.com>
* DateHandlers.cs:
lisatime_t is unsigned
* Plugins/LisaFS.cs:
Added code to search for MDDF, check some variables to be
sure it's a real MDDF, and get information about it.
2014-04-17 Natalia Portillo <claunia@claunia.com>
* Plugins/LisaFS.cs:
* FileSystemIDandChk.csproj:
Added LisaFS skeleton with Lisa's MDDF and tag structs
* DateHandlers.cs:
Added convert function from Lisa timestamp fields to C#
DateTime
2014-04-17 Natalia Portillo <claunia@claunia.com>
* ImagePlugins/DiskCopy42.cs:
* ImagePlugins/ImagePlugin.cs:
Added support for Apple FileWare (aka Twiggy) disks as
dumped by Sigma Seven's BLU
2014-04-17 Natalia Portillo <claunia@claunia.com>
* Plugins/AppleMFS.cs:
Corrected alignment failure because of incorrect type
definition on MDB struct.
2014-04-17 Natalia Portillo <claunia@claunia.com>
* ImagePlugins/DiskCopy42.cs:
Correct typos, misalignment of field and
BigEndianBitConverter behaviour
2014-04-15 Natalia Portillo <claunia@claunia.com>
* FileSystemIDandChk.csproj:
* ImagePlugins/DiskCopy42.cs:
Added support for Apple DiskCopy 4.2 format
* ImagePlugins/ImagePlugin.cs:
Added standard IBM, DEC and Apple floppy formats
2014-04-14 Natalia Portillo <claunia@claunia.com>
* Main.cs:
* Plugins.cs:
* Swapping.cs:
* Plugins/BFS.cs:
* Plugins/FAT.cs:
* Plugins/FFS.cs:
* Plugins/ODS.cs:
* Plugins/NTFS.cs:
* Plugins/HPFS.cs:
* DateHandlers.cs:
* Plugins/SysV.cs:
* Plugins/extFS.cs:
* Plugins/Opera.cs:
* Plugins/Plugin.cs:
* StringHandlers.cs:
* Plugins/ext2FS.cs:
* Plugins/SolarFS.cs:
* Plugins/UNIXBFS.cs:
* Plugins/MinixFS.cs:
* Plugins/ISO9660.cs:
* PartPlugins/MBR.cs:
* Plugins/AppleMFS.cs:
* PartPlugins/NeXT.cs:
* Plugins/PCEngine.cs:
* Plugins/AppleHFS.cs:
* ImagePlugins/CDRWin.cs:
* PartPlugins/AppleMap.cs:
* Plugins/AppleHFSPlus.cs:
* BigEndianBitConverter.cs:
* FileSystemIDandChk.csproj:
* EndianAwareBinaryReader.cs:
* ImagePlugins/ImagePlugin.cs:
Refactor and reformat code
2014-04-14 Natalia Portillo <claunia@claunia.com>
* Main.cs:
* ImagePlugins/CDRWin.cs:
Constrain debug information to debug mode
2014-04-14 Natalia Portillo <claunia@claunia.com>
* BigEndianBitConverter.cs:
Added BitConverter for BigEndian
* FileSystemIDandChk.csproj:
FileSystemIDandChk/BigEndianBitConverter.cs
* ImagePlugins/CDRWin.cs:
Corrected parsing
Implemented all ImagePlugin methods
* ImagePlugins/ImagePlugin.cs:
Used document auto formatting
* Main.cs:
* Plugins/FAT.cs:
* Plugins/BFS.cs:
* Plugins/FFS.cs:
* Plugins/ODS.cs:
* Plugins/HPFS.cs:
* Plugins/SysV.cs:
* Plugins/NTFS.cs:
* Plugins/extFS.cs:
* Plugins/Opera.cs:
* Plugins/ext2FS.cs:
* Plugins/Plugin.cs:
* Plugins/UNIXBFS.cs:
* Plugins/SolarFS.cs:
* PartPlugins/MBR.cs:
* Plugins/MinixFS.cs:
* Plugins/ISO9660.cs:
* Plugins/PCEngine.cs:
* Plugins/AppleHFS.cs:
* PartPlugins/NeXT.cs:
* Plugins/AppleMFS.cs:
* PartPlugins/AppleMap.cs:
* Plugins/AppleHFSPlus.cs:
Added support for disc image plugins
* PartPlugins/PartPlugin.cs:
Added support for disc image plugins
Added start sector and length in sectors to partitions
* Plugins/Symbian.cs:
Commented til code is adapted for disc image plugins
2012-08-07 Natalia Portillo <claunia@claunia.com>
* Plugins/SysV.cs:
* FileSystemIDandChk.csproj:
Added support for System V filesystem
* PartPlugins/MBR.cs:
UnixWare is not the only one using the UNIX disklabel
Corrected UNIX disklabel sector.
Enhanced UNIX disklabel with structs and consts.
Added support for old UNIX disklabels.
* Swapping.cs:
Added code for middle-endian (PDP-endian)
2012-08-06 Natalia Portillo <claunia@claunia.com>
* Plugins/UNIXBFS.cs:
* FileSystemIDandChk.csproj:
Added UNIX Boot filesystem.
* Plugins/FAT.cs:
Don't seek to FAT if value is bigger than volume size.
2012-08-06 Natalia Portillo <claunia@claunia.com>
* Plugins/SolarFS.cs:
* FileSystemIDandChk.csproj:
Added code for detection Solar_OS filesystem
2012-08-05 Natalia Portillo <claunia@claunia.com>
* Plugins/FAT.cs:
Add debug information.
De-hardcode FAT location, use correct data from BPB or
hardcode in case data is empty.
Show volume size in bytes also.
Added offset of PB entries on comments.
2012-08-05 Natalia Portillo <claunia@claunia.com>
* Plugins/MinixFS.cs:
* FileSystemIDandChk.csproj:
Added Minix V1, V2 and V3 filesystems.
2012-08-05 Natalia Portillo <claunia@claunia.com>
* DateHandlers.cs:
Added debug information and prevent malformed datetime
strings crash ISO9660ToDateTime class
2012-08-05 Natalia Portillo <claunia@claunia.com>
* Plugins/ISO9660.cs:
Added code preventing it to be run on each partition,
because this filesystem will be once and only. Now it runs
only one time whenever there are partitions or how many.
* Plugins/FAT.cs:
Added code to handle false positives (FATs can be 1 or 2,
maybe 0 in the wild, never bigger).
Modified for BinaryReader class.
* Plugins/BFS.cs:
Missed negation operand
* PartPlugins/NeXT.cs:
* PartPlugins/AppleMap.cs:
Added constants and modified for EndianAwareBinaryReader
class.
2012-08-05 Natalia Portillo <claunia@claunia.com>
* Plugins/ODS.cs:
Use StringHandlers class to prevent garbage coming from
strings (even if they are not C strings, it does not hurt).
* Plugins/AppleHFS.cs:
Use constants.
* Plugins/BFS.cs:
* Plugins/AppleMFS.cs:
* Plugins/AppleHFSPlus.cs:
Use constants and EndianAwareBinaryReader class.
* Plugins/Opera.cs:
Use a superblock structure and EndianAwareBinaryReader
class, reduces lots of code.
2012-08-04 Natalia Portillo <claunia@claunia.com>
* CToString.cs:
Renamed to StringHandlers.cs
* Plugins/AppleHFS.cs:
Modified to use EndianAwareBinaryReader and PascalToString
classes
* FileSystemIDandChk.csproj:
CToString.cs renamed to StringHandlers.cs
* StringHandlers.cs:
Added code to convert Pascal string to .NET String
2012-08-04 Natalia Portillo <claunia@claunia.com>
* Plugins/FFS.cs:
Added code for detecting 42BSD, 43BSD, 44BSD, SunOS,
SunOS/x86, UFS and UFS2 filesystems. Block size is incorrect
on NeXTStep's CD UFSs, but there is no way to check for it.
* Main.cs:
Disable debug by default
* FileSystemIDandChk.csproj:
Moved to .NET 4 and added EndianAwareBinaryReader class
* EndianAwareBinaryReader.cs:
Override of BinaryReader class with the ability to
automatically swap endianness
2012-08-03 Natalia Portillo <claunia@claunia.com>
* Plugins/ISO9660.cs:
When Joliet is present, show both Joliet and Primary volume
descriptors, as they may not be in sync
2012-08-03 Natalia Portillo <claunia@claunia.com>
* Plugins/ODS.cs:
* Plugins/HPFS.cs:
* Plugins/ISO9660.cs:
* Plugins/AppleMFS.cs:
* Plugins/AppleHFS.cs:
* Plugins/AppleHFSPlus.cs:
Moved datetime conversion to DateHandlers class.
* Plugins/Symbian.cs:
Identifies .SIS files. Yes I know it's not a filesystem but
I needed it so.
* Main.cs:
Corrected typo
* FileSystemIDandChk.csproj:
Added datetime conversion handling class, Symbian .SIS
installers, ext filesystem and ext2/3/4 filesystems.
* Plugins/ext2FS.cs:
Detects ext2, ext3 and ext4 filesystems up to Linux 3.1
kernel.
* Plugins/extFS.cs:
Detects ext filesystems. Untested as no Linux 2.0 was
available at time :p
* DateHandlers.cs:
Moved all datetime convertions from plugins to central
class.
2011-06-02 Natalia Portillo <claunia@claunia.com>
* Added VMS ODS
2011-03-29 Natalia Portillo <claunia@claunia.com>
* Added NTFS
2011-03-28 Natalia Portillo <claunia@claunia.com>
* Added HPFS
2011-03-28 Natalia Portillo <claunia@claunia.com>
* Added Be filesystem
2011-03-28 Natalia Portillo <claunia@claunia.com>
* Use FOBOS guids
2011-03-25 Natalia Portillo <claunia@claunia.com>
* Added NeXT disklabels and unidentify MBR with 0 entries
2011-03-25 Natalia Portillo <claunia@claunia.com>
* ISO9660 should always check from offset 0, needs to be sure it runs only once
2011-03-25 Natalia Portillo <claunia@claunia.com>
* Added MBR partition scheme.
2011-03-06 Natalia Portillo <claunia@claunia.com>
* Added skeleton for BSD FFS.
* Added HFS+.
* If HFS detects it has wrapped a HFS+ volume, inform that it's not its filesystem.
* Added a workaround in calculation with UInt32 and ulong that made HFS and MFS show a bad date.
2011-03-203 Natalia Portillo <claunia@claunia.com>
* First commit to SVN

View File

@@ -0,0 +1,150 @@
/***************************************************************************
The Disc Image Chef
----------------------------------------------------------------------------
Filename : DateHandlers.cs
Version : 1.0
Author(s) : Natalia Portillo
Component : Program tools
Revision : $Revision$
Last change by : $Author$
Date : $Date$
--[ Description ] ----------------------------------------------------------
Convert several timestamp formats to C# DateTime.
--[ 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
{
public static class DateHandlers
{
static readonly DateTime LisaEpoch = new DateTime(1901, 1, 1, 0, 0, 0);
static readonly DateTime MacEpoch = new DateTime(1904, 1, 1, 0, 0, 0);
static readonly DateTime UNIXEpoch = new DateTime(1970, 1, 1, 0, 0, 0);
// Day 0 of Julian Date system
static readonly DateTime JulianEpoch = new DateTime(1858, 11, 17, 0, 0, 0);
public static DateTime MacToDateTime(ulong MacTimeStamp)
{
return MacEpoch.AddTicks((long)(MacTimeStamp * 10000000));
}
public static DateTime LisaToDateTime(UInt32 LisaTimeStamp)
{
return LisaEpoch.AddSeconds(LisaTimeStamp);
}
public static DateTime UNIXToDateTime(Int32 UNIXTimeStamp)
{
return UNIXEpoch.AddSeconds(UNIXTimeStamp);
}
public static DateTime UNIXUnsignedToDateTime(UInt32 UNIXTimeStamp)
{
return UNIXEpoch.AddSeconds(UNIXTimeStamp);
}
public static DateTime ISO9660ToDateTime(byte[] VDDateTime)
{
int year, month, day, hour, minute, second, hundredths;
byte[] twocharvalue = new byte[2];
byte[] fourcharvalue = new byte[4];
fourcharvalue[0] = VDDateTime[0];
fourcharvalue[1] = VDDateTime[1];
fourcharvalue[2] = VDDateTime[2];
fourcharvalue[3] = VDDateTime[3];
if (MainClass.isDebug)
Console.WriteLine("DEBUG (ISO9600ToDateTime handler): year = \"{0}\"", StringHandlers.CToString(fourcharvalue));
if (!Int32.TryParse(StringHandlers.CToString(fourcharvalue), out year))
year = 0;
// year = Convert.ToInt32(StringHandlers.CToString(fourcharvalue));
twocharvalue[0] = VDDateTime[4];
twocharvalue[1] = VDDateTime[5];
if (MainClass.isDebug)
Console.WriteLine("DEBUG (ISO9600ToDateTime handler): month = \"{0}\"", StringHandlers.CToString(twocharvalue));
if (!Int32.TryParse(StringHandlers.CToString(twocharvalue), out month))
month = 0;
// month = Convert.ToInt32(StringHandlers.CToString(twocharvalue));
twocharvalue[0] = VDDateTime[6];
twocharvalue[1] = VDDateTime[7];
if (MainClass.isDebug)
Console.WriteLine("DEBUG (ISO9600ToDateTime handler): day = \"{0}\"", StringHandlers.CToString(twocharvalue));
if (!Int32.TryParse(StringHandlers.CToString(twocharvalue), out day))
day = 0;
// day = Convert.ToInt32(StringHandlers.CToString(twocharvalue));
twocharvalue[0] = VDDateTime[8];
twocharvalue[1] = VDDateTime[9];
if (MainClass.isDebug)
Console.WriteLine("DEBUG (ISO9600ToDateTime handler): hour = \"{0}\"", StringHandlers.CToString(twocharvalue));
if (!Int32.TryParse(StringHandlers.CToString(twocharvalue), out hour))
hour = 0;
// hour = Convert.ToInt32(StringHandlers.CToString(twocharvalue));
twocharvalue[0] = VDDateTime[10];
twocharvalue[1] = VDDateTime[11];
if (MainClass.isDebug)
Console.WriteLine("DEBUG (ISO9600ToDateTime handler): minute = \"{0}\"", StringHandlers.CToString(twocharvalue));
if (!Int32.TryParse(StringHandlers.CToString(twocharvalue), out minute))
minute = 0;
// minute = Convert.ToInt32(StringHandlers.CToString(twocharvalue));
twocharvalue[0] = VDDateTime[12];
twocharvalue[1] = VDDateTime[13];
if (MainClass.isDebug)
Console.WriteLine("DEBUG (ISO9600ToDateTime handler): second = \"{0}\"", StringHandlers.CToString(twocharvalue));
if (!Int32.TryParse(StringHandlers.CToString(twocharvalue), out second))
second = 0;
// second = Convert.ToInt32(StringHandlers.CToString(twocharvalue));
twocharvalue[0] = VDDateTime[14];
twocharvalue[1] = VDDateTime[15];
if (MainClass.isDebug)
Console.WriteLine("DEBUG (ISO9600ToDateTime handler): hundredths = \"{0}\"", StringHandlers.CToString(twocharvalue));
if (!Int32.TryParse(StringHandlers.CToString(twocharvalue), out hundredths))
hundredths = 0;
// hundredths = Convert.ToInt32(StringHandlers.CToString(twocharvalue));
if (MainClass.isDebug)
Console.WriteLine("DEBUG (ISO9600ToDateTime handler): decodedDT = new DateTime({0}, {1}, {2}, {3}, {4}, {5}, {6}, DateTimeKind.Unspecified);", year, month, day, hour, minute, second, hundredths * 10);
DateTime decodedDT = new DateTime(year, month, day, hour, minute, second, hundredths * 10, DateTimeKind.Unspecified);
return decodedDT;
}
// C# works in UTC, VMS on Julian Date, some displacement may occur on disks created outside UTC
public static DateTime VMSToDateTime(UInt64 vmsDate)
{
double delta = vmsDate * 0.0001; // Tenths of microseconds to milliseconds, will lose some detail
return JulianEpoch.AddMilliseconds(delta);
}
}
}

View File

@@ -0,0 +1,163 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">x86</Platform>
<ProductVersion>8.0.30703</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{7A4B05BE-73C9-4F34-87FE-E80CCF1F732D}</ProjectGuid>
<OutputType>Exe</OutputType>
<RootNamespace>DiscImageChef</RootNamespace>
<AssemblyName>DiscImageChef</AssemblyName>
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
<ReleaseVersion>1.10</ReleaseVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
<DebugSymbols>True</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>False</Optimize>
<OutputPath>bin\Debug</OutputPath>
<DefineConstants>DEBUG</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<PlatformTarget>x86</PlatformTarget>
<Externalconsole>True</Externalconsole>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
<DebugType>none</DebugType>
<Optimize>False</Optimize>
<OutputPath>bin\Release</OutputPath>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<PlatformTarget>x86</PlatformTarget>
<Externalconsole>True</Externalconsole>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
</ItemGroup>
<ItemGroup>
<Compile Include="Main.cs" />
<Compile Include="AssemblyInfo.cs" />
<Compile Include="Plugins\AppleMFS.cs" />
<Compile Include="Swapping.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="PartPlugins\PartPlugin.cs" />
<Compile Include="PartPlugins\AppleMap.cs" />
<Compile Include="Plugins\FFS.cs" />
<Compile Include="Plugins\AppleHFSPlus.cs" />
<Compile Include="PartPlugins\MBR.cs" />
<Compile Include="PartPlugins\NeXT.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="DateHandlers.cs" />
<Compile Include="EndianAwareBinaryReader.cs" />
<Compile Include="StringHandlers.cs" />
<Compile Include="Plugins\MinixFS.cs" />
<Compile Include="Plugins\SolarFS.cs" />
<Compile Include="Plugins\UNIXBFS.cs" />
<Compile Include="Plugins\SysV.cs" />
<Compile Include="ImagePlugins\ImagePlugin.cs" />
<Compile Include="ImagePlugins\CDRWin.cs" />
<Compile Include="BigEndianBitConverter.cs" />
<Compile Include="ImagePlugins\DiskCopy42.cs" />
<Compile Include="Plugins\LisaFS.cs" />
<Compile Include="ImagePlugins\TeleDisk.cs" />
<Compile Include="ArrayFill.cs" />
<Compile Include="PrintHex.cs" />
<Compile Include="ImagePlugins\ZZZRawImage.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ItemGroup>
<Folder Include="Plugins\" />
<Folder Include="PartPlugins\" />
<Folder Include="ImagePlugins\" />
</ItemGroup>
<ProjectExtensions>
<MonoDevelop>
<Properties>
<Policies>
<VersionControlPolicy inheritsSet="Mono">
<CommitMessageStyle Indent=" " LastFilePostfix=":&#xA; " IncludeDirectoryPaths="True" />
</VersionControlPolicy>
<ChangeLogPolicy UpdateMode="ProjectRoot" VcsIntegration="RequireEntry" inheritsSet="Mono">
<MessageStyle LastFilePostfix=":&#xA; " IncludeDirectoryPaths="True" />
</ChangeLogPolicy>
<DotNetNamingPolicy DirectoryNamespaceAssociation="PrefixedHierarchical" ResourceNamePolicy="MSBuild" />
<TextStylePolicy inheritsSet="VisualStudio" inheritsScope="text/plain" scope="text/x-csharp" />
<CSharpFormattingPolicy IndentSwitchBody="True" AnonymousMethodBraceStyle="NextLine" PropertyBraceStyle="NextLine" PropertyGetBraceStyle="NextLine" PropertySetBraceStyle="NextLine" EventBraceStyle="NextLine" EventAddBraceStyle="NextLine" EventRemoveBraceStyle="NextLine" StatementBraceStyle="NextLine" ElseNewLinePlacement="NewLine" CatchNewLinePlacement="NewLine" FinallyNewLinePlacement="NewLine" WhileNewLinePlacement="DoNotCare" ArrayInitializerWrapping="DoNotChange" ArrayInitializerBraceStyle="NextLine" BeforeMethodDeclarationParentheses="False" BeforeMethodCallParentheses="False" BeforeConstructorDeclarationParentheses="False" BeforeDelegateDeclarationParentheses="False" NewParentheses="False" SpacesBeforeBrackets="False" inheritsSet="Mono" inheritsScope="text/x-csharp" scope="text/x-csharp" />
<TextStylePolicy inheritsSet="VisualStudio" inheritsScope="text/plain" scope="text/plain" />
<NameConventionPolicy>
<Rules>
<NamingRule Name="Namespaces" AffectedEntity="Namespace" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True" />
<NamingRule Name="Types" AffectedEntity="Class, Struct, Enum, Delegate" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True" />
<NamingRule Name="Interfaces" AffectedEntity="Interface" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True">
<RequiredPrefixes>
<String>I</String>
</RequiredPrefixes>
</NamingRule>
<NamingRule Name="Attributes" AffectedEntity="CustomAttributes" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True">
<RequiredSuffixes>
<String>Attribute</String>
</RequiredSuffixes>
</NamingRule>
<NamingRule Name="Event Arguments" AffectedEntity="CustomEventArgs" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True">
<RequiredSuffixes>
<String>EventArgs</String>
</RequiredSuffixes>
</NamingRule>
<NamingRule Name="Exceptions" AffectedEntity="CustomExceptions" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True">
<RequiredSuffixes>
<String>Exception</String>
</RequiredSuffixes>
</NamingRule>
<NamingRule Name="Methods" AffectedEntity="Methods" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True" />
<NamingRule Name="Static Readonly Fields" AffectedEntity="ReadonlyField" VisibilityMask="Internal, Protected, Public" NamingStyle="PascalCase" IncludeInstanceMembers="False" IncludeStaticEntities="True" />
<NamingRule Name="Fields (Non Private)" AffectedEntity="Field" VisibilityMask="Internal, Protected, Public" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True" />
<NamingRule Name="ReadOnly Fields (Non Private)" AffectedEntity="ReadonlyField" VisibilityMask="Internal, Protected, Public" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="False" />
<NamingRule Name="Fields (Private)" AffectedEntity="Field, ReadonlyField" VisibilityMask="Private" NamingStyle="CamelCase" IncludeInstanceMembers="True" IncludeStaticEntities="False">
<AllowedPrefixes>
<String>_</String>
<String>m_</String>
</AllowedPrefixes>
</NamingRule>
<NamingRule Name="Static Fields (Private)" AffectedEntity="Field" VisibilityMask="Private" NamingStyle="CamelCase" IncludeInstanceMembers="False" IncludeStaticEntities="True" />
<NamingRule Name="ReadOnly Fields (Private)" AffectedEntity="ReadonlyField" VisibilityMask="Private" NamingStyle="CamelCase" IncludeInstanceMembers="True" IncludeStaticEntities="False">
<AllowedPrefixes>
<String>_</String>
<String>m_</String>
</AllowedPrefixes>
</NamingRule>
<NamingRule Name="Constant Fields" AffectedEntity="ConstantField" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True" />
<NamingRule Name="Properties" AffectedEntity="Property" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True" />
<NamingRule Name="Events" AffectedEntity="Event" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True" />
<NamingRule Name="Enum Members" AffectedEntity="EnumMember" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True" />
<NamingRule Name="Parameters" AffectedEntity="Parameter" VisibilityMask="VisibilityMask" NamingStyle="CamelCase" IncludeInstanceMembers="True" IncludeStaticEntities="True" />
<NamingRule Name="Type Parameters" AffectedEntity="TypeParameter" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True">
<RequiredPrefixes>
<String>T</String>
</RequiredPrefixes>
</NamingRule>
</Rules>
</NameConventionPolicy>
</Policies>
</Properties>
</MonoDevelop>
</ProjectExtensions>
<ItemGroup>
<None Include="TODO" />
<None Include="LICENSE" />
<None Include="README.md" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,162 @@
/***************************************************************************
The Disc Image Chef
----------------------------------------------------------------------------
Filename : EndianAwareBinaryReader.cs
Version : 1.0
Author(s) : Natalia Portillo
Component : Program tools
Revision : $Revision$
Last change by : $Author$
Date : $Date$
--[ Description ] ----------------------------------------------------------
Override for System.IO.Binary.Reader that knows how to handle big-endian.
--[ 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.Linq;
using System.Text;
namespace DiscImageChef
{
public class EndianAwareBinaryReader : BinaryReader
{
byte[] buffer = new byte[8];
public EndianAwareBinaryReader(Stream input, Encoding encoding, bool isLittleEndian)
: base(input, encoding)
{
IsLittleEndian = isLittleEndian;
}
public EndianAwareBinaryReader(Stream input, bool isLittleEndian)
: this(input, Encoding.UTF8, isLittleEndian)
{
}
public bool IsLittleEndian
{
get;
set;
}
public override double ReadDouble()
{
if (IsLittleEndian)
return base.ReadDouble();
FillMyBuffer(8);
return BitConverter.ToDouble(buffer.Take(8).Reverse().ToArray(), 0);
}
public override short ReadInt16()
{
if (IsLittleEndian)
return base.ReadInt16();
FillMyBuffer(2);
return BitConverter.ToInt16(buffer.Take(2).Reverse().ToArray(), 0);
}
public override int ReadInt32()
{
if (IsLittleEndian)
return base.ReadInt32();
FillMyBuffer(4);
return BitConverter.ToInt32(buffer.Take(4).Reverse().ToArray(), 0);
}
public override long ReadInt64()
{
if (IsLittleEndian)
return base.ReadInt64();
FillMyBuffer(8);
return BitConverter.ToInt64(buffer.Take(8).Reverse().ToArray(), 0);
}
public override float ReadSingle()
{
if (IsLittleEndian)
return base.ReadSingle();
FillMyBuffer(4);
return BitConverter.ToSingle(buffer.Take(4).Reverse().ToArray(), 0);
}
public override ushort ReadUInt16()
{
if (IsLittleEndian)
return base.ReadUInt16();
FillMyBuffer(2);
return BitConverter.ToUInt16(buffer.Take(2).Reverse().ToArray(), 0);
}
public override uint ReadUInt32()
{
if (IsLittleEndian)
return base.ReadUInt32();
FillMyBuffer(4);
return BitConverter.ToUInt32(buffer.Take(4).Reverse().ToArray(), 0);
}
public override ulong ReadUInt64()
{
if (IsLittleEndian)
return base.ReadUInt64();
FillMyBuffer(8);
return BitConverter.ToUInt64(buffer.Take(8).Reverse().ToArray(), 0);
}
void FillMyBuffer(int numBytes)
{
int offset = 0;
int num2;
if (numBytes == 1)
{
num2 = BaseStream.ReadByte();
if (num2 == -1)
{
throw new EndOfStreamException("Attempted to read past the end of the stream.");
}
buffer[0] = (byte)num2;
}
else
{
do
{
num2 = BaseStream.Read(buffer, offset, numBytes - offset);
if (num2 == 0)
{
throw new EndOfStreamException("Attempted to read past the end of the stream.");
}
offset += num2;
}
while (offset < numBytes);
}
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,597 @@
/***************************************************************************
The Disc Image Chef
----------------------------------------------------------------------------
Filename : DiskCopy42.cs
Version : 1.0
Author(s) : Natalia Portillo
Component : Disc image plugins
Revision : $Revision$
Last change by : $Author$
Date : $Date$
--[ Description ] ----------------------------------------------------------
Manages Apple DiskCopy 4.2 disc images, including unofficial modifications.
--[ 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.Collections.Generic;
namespace DiscImageChef.ImagePlugins
{
// Checked using several images and strings inside Apple's DiskImages.framework
class DiskCopy42 : ImagePlugin
{
#region Internal Structures
// DiskCopy 4.2 header, big-endian, data-fork, start of file, 84 bytes
struct DC42Header
{
// 0x00, 64 bytes, pascal string, disk name or "-not a Macintosh disk-", filled with garbage
public string diskName;
// 0x40, size of data in bytes (usually sectors*512)
public UInt32 dataSize;
// 0x44, size of tags in bytes (usually sectors*12)
public UInt32 tagSize;
// 0x48, checksum of data bytes
public UInt32 dataChecksum;
// 0x4C, checksum of tag bytes
public UInt32 tagChecksum;
// 0x50, format of disk, see constants
public byte format;
// 0x51, format of sectors, see constants
public byte fmtByte;
// 0x52, is disk image valid? always 0x01
public byte valid;
// 0x53, reserved, always 0x00
public byte reserved;
}
#endregion
#region Internal Constants
// format byte
// 3.5", single side, double density, GCR
const byte kSonyFormat400K = 0x00;
// 3.5", double side, double density, GCR
const byte kSonyFormat800K = 0x01;
// 3.5", double side, double density, MFM
const byte kSonyFormat720K = 0x02;
// 3.5", double side, high density, MFM
const byte kSonyFormat1440K = 0x03;
// 3.5", double side, high density, MFM, 21 sectors/track (aka, Microsoft DMF)
// Unchecked value
const byte kSonyFormat1680K = 0x04;
// Defined by Sigma Seven's BLU
const byte kSigmaFormatTwiggy = 0x54;
// There should be a value for Apple HD20 hard disks, unknown...
// fmyByte byte
// Based on GCR nibble
// Always 0x02 for MFM disks
// Unknown for Apple HD20
// Defined by Sigma Seven's BLU
const byte kSignaFmtByteTwiggy = 0x01;
// 3.5" single side double density GCR and MFM all use same code
const byte kSonyFmtByte400K = 0x02;
const byte kSonyFmtByte720K = kSonyFmtByte400K;
const byte kSonyFmtByte1440K = kSonyFmtByte400K;
const byte kSonyFmtByte1680K = kSonyFmtByte400K;
// 3.5" double side double density GCR, 512 bytes/sector, interleave 2:1
const byte kSonyFmtByte800K = 0x22;
// 3.5" double side double density GCR, 512 bytes/sector, interleave 2:1, incorrect value (but appears on official documentation)
const byte kSonyFmtByte800KIncorrect = 0x12;
// 3.5" double side double density GCR, ProDOS format, interleave 4:1
const byte kSonyFmtByteProDos = 0x24;
// Unformatted sectors
const byte kInvalidFmtByte = 0x96;
#endregion
#region Internal variables
// Start of data sectors in disk image, should be 0x58
UInt32 dataOffset;
// Start of tags in disk image, after data sectors
UInt32 tagOffset;
// Sectors
UInt32 sectors;
// Bytes per sector, should be 512
UInt32 bps;
// Bytes per tag, should be 12
UInt32 bptag;
// Header of opened image
DC42Header header;
// Disk image file
string dc42ImagePath;
#endregion
public DiskCopy42(PluginBase Core)
{
Name = "Apple DiskCopy 4.2";
PluginUUID = new Guid("0240B7B1-E959-4CDC-B0BD-386D6E467B88");
}
public override bool IdentifyImage(string imagePath)
{
FileStream stream = new FileStream(imagePath, FileMode.Open, FileAccess.Read);
stream.Seek(0, SeekOrigin.Begin);
byte[] buffer = new byte[0x58];
byte[] pString = new byte[64];
stream.Read(buffer, 0, 0x58);
// Incorrect pascal string length, not DC42
if (buffer[0] > 63)
return false;
DC42Header tmp_header = new DC42Header();
Array.Copy(buffer, 0, pString, 0, 64);
BigEndianBitConverter.IsLittleEndian = BitConverter.IsLittleEndian;
tmp_header.diskName = StringHandlers.PascalToString(pString);
tmp_header.dataSize = BigEndianBitConverter.ToUInt32(buffer, 0x40);
tmp_header.tagSize = BigEndianBitConverter.ToUInt32(buffer, 0x44);
tmp_header.dataChecksum = BigEndianBitConverter.ToUInt32(buffer, 0x48);
tmp_header.tagChecksum = BigEndianBitConverter.ToUInt32(buffer, 0x4C);
tmp_header.format = buffer[0x50];
tmp_header.fmtByte = buffer[0x51];
tmp_header.valid = buffer[0x52];
tmp_header.reserved = buffer[0x53];
if (MainClass.isDebug)
{
Console.WriteLine("DEBUG (DC42 plugin): tmp_header.diskName = \"{0}\"", tmp_header.diskName);
Console.WriteLine("DEBUG (DC42 plugin): tmp_header.dataSize = {0} bytes", tmp_header.dataSize);
Console.WriteLine("DEBUG (DC42 plugin): tmp_header.tagSize = {0} bytes", tmp_header.tagSize);
Console.WriteLine("DEBUG (DC42 plugin): tmp_header.dataChecksum = 0x{0:X8}", tmp_header.dataChecksum);
Console.WriteLine("DEBUG (DC42 plugin): tmp_header.tagChecksum = 0x{0:X8}", tmp_header.tagChecksum);
Console.WriteLine("DEBUG (DC42 plugin): tmp_header.format = 0x{0:X2}", tmp_header.format);
Console.WriteLine("DEBUG (DC42 plugin): tmp_header.fmtByte = 0x{0:X2}", tmp_header.fmtByte);
Console.WriteLine("DEBUG (DC42 plugin): tmp_header.valid = {0}", tmp_header.valid);
Console.WriteLine("DEBUG (DC42 plugin): tmp_header.reserved = {0}", tmp_header.reserved);
}
if (tmp_header.valid != 1 || tmp_header.reserved != 0)
return false;
FileInfo fi = new FileInfo(imagePath);
if (tmp_header.dataSize + tmp_header.tagSize + 0x54 != fi.Length && tmp_header.format != kSigmaFormatTwiggy)
return false;
if (tmp_header.format != kSonyFormat400K && tmp_header.format != kSonyFormat800K && tmp_header.format != kSonyFormat720K &&
tmp_header.format != kSonyFormat1440K && tmp_header.format != kSonyFormat1680K && tmp_header.format != kSigmaFormatTwiggy)
{
if (MainClass.isDebug)
Console.WriteLine("Unknown tmp_header.format = 0x{0:X2} value", tmp_header.format);
return false;
}
if (tmp_header.fmtByte != kSonyFmtByte400K && tmp_header.fmtByte != kSonyFmtByte800K && tmp_header.fmtByte != kSonyFmtByte800KIncorrect &&
tmp_header.fmtByte != kSonyFmtByteProDos && tmp_header.fmtByte != kInvalidFmtByte && tmp_header.fmtByte != kSignaFmtByteTwiggy)
{
if (MainClass.isDebug)
Console.WriteLine("Unknown tmp_header.fmtByte = 0x{0:X2} value", tmp_header.fmtByte);
return false;
}
if (tmp_header.fmtByte == kInvalidFmtByte)
{
if (MainClass.isDebug)
Console.WriteLine("Image says it's unformatted");
return false;
}
return true;
}
public override bool OpenImage(string imagePath)
{
FileStream stream = new FileStream(imagePath, FileMode.Open, FileAccess.Read);
stream.Seek(0, SeekOrigin.Begin);
byte[] buffer = new byte[0x58];
byte[] pString = new byte[64];
stream.Read(buffer, 0, 0x58);
// Incorrect pascal string length, not DC42
if (buffer[0] > 63)
return false;
header = new DC42Header();
BigEndianBitConverter.IsLittleEndian = BitConverter.IsLittleEndian;
Array.Copy(buffer, 0, pString, 0, 64);
header.diskName = StringHandlers.PascalToString(pString);
header.dataSize = BigEndianBitConverter.ToUInt32(buffer, 0x40);
header.tagSize = BigEndianBitConverter.ToUInt32(buffer, 0x44);
header.dataChecksum = BigEndianBitConverter.ToUInt32(buffer, 0x48);
header.tagChecksum = BigEndianBitConverter.ToUInt32(buffer, 0x4C);
header.format = buffer[0x50];
header.fmtByte = buffer[0x51];
header.valid = buffer[0x52];
header.reserved = buffer[0x53];
if (MainClass.isDebug)
{
Console.WriteLine("DEBUG (DC42 plugin): header.diskName = \"{0}\"", header.diskName);
Console.WriteLine("DEBUG (DC42 plugin): header.dataSize = {0} bytes", header.dataSize);
Console.WriteLine("DEBUG (DC42 plugin): header.tagSize = {0} bytes", header.tagSize);
Console.WriteLine("DEBUG (DC42 plugin): header.dataChecksum = 0x{0:X8}", header.dataChecksum);
Console.WriteLine("DEBUG (DC42 plugin): header.tagChecksum = 0x{0:X8}", header.tagChecksum);
Console.WriteLine("DEBUG (DC42 plugin): header.format = 0x{0:X2}", header.format);
Console.WriteLine("DEBUG (DC42 plugin): header.fmtByte = 0x{0:X2}", header.fmtByte);
Console.WriteLine("DEBUG (DC42 plugin): header.valid = {0}", header.valid);
Console.WriteLine("DEBUG (DC42 plugin): header.reserved = {0}", header.reserved);
}
if (header.valid != 1 || header.reserved != 0)
return false;
FileInfo fi = new FileInfo(imagePath);
if (header.dataSize + header.tagSize + 0x54 != fi.Length && header.format != kSigmaFormatTwiggy)
return false;
if (header.format != kSonyFormat400K && header.format != kSonyFormat800K && header.format != kSonyFormat720K &&
header.format != kSonyFormat1440K && header.format != kSonyFormat1680K && header.format != kSigmaFormatTwiggy)
{
if (MainClass.isDebug)
Console.WriteLine("DEBUG (DC42 plugin): Unknown header.format = 0x{0:X2} value", header.format);
return false;
}
if (header.fmtByte != kSonyFmtByte400K && header.fmtByte != kSonyFmtByte800K && header.fmtByte != kSonyFmtByte800KIncorrect &&
header.fmtByte != kSonyFmtByteProDos && header.fmtByte != kInvalidFmtByte && header.fmtByte != kSignaFmtByteTwiggy)
{
if (MainClass.isDebug)
Console.WriteLine("DEBUG (DC42 plugin): Unknown tmp_header.fmtByte = 0x{0:X2} value", header.fmtByte);
return false;
}
if (header.fmtByte == kInvalidFmtByte)
{
if (MainClass.isDebug)
Console.WriteLine("DEBUG (DC42 plugin): Image says it's unformatted");
return false;
}
dataOffset = 0x54;
tagOffset = header.tagSize != 0 ? 0x54 + header.dataSize : 0;
bps = 512;
bptag = (uint)(header.tagSize != 0 ? 12 : 0);
dc42ImagePath = imagePath;
sectors = header.dataSize / 512;
if (header.tagSize != 0)
{
if (header.tagSize / 12 != sectors)
{
if (MainClass.isDebug)
Console.WriteLine("DEBUG (DC42 plugin): header.tagSize / 12 != sectors");
return false;
}
}
return true;
}
public override bool ImageHasPartitions()
{
return false;
}
public override UInt64 GetImageSize()
{
return sectors * bps + sectors * bptag;
}
public override UInt64 GetSectors()
{
return sectors;
}
public override UInt32 GetSectorSize()
{
return bps;
}
public override byte[] ReadSector(UInt64 sectorAddress)
{
return ReadSectors(sectorAddress, 1);
}
public override byte[] ReadSectorTag(UInt64 sectorAddress, SectorTagType tag)
{
return ReadSectorsTag(sectorAddress, 1, tag);
}
public override byte[] ReadSectors(UInt64 sectorAddress, UInt32 length)
{
if (sectorAddress > sectors - 1)
throw new ArgumentOutOfRangeException("sectorAddress", "Sector address not found");
if (sectorAddress + length > sectors)
throw new ArgumentOutOfRangeException("length", "Requested more sectors than available");
byte[] buffer = new byte[length * bps];
FileStream stream = new FileStream(dc42ImagePath, FileMode.Open, FileAccess.Read);
stream.Seek((long)(dataOffset + sectorAddress * bps), SeekOrigin.Begin);
stream.Read(buffer, 0, (int)(length * bps));
return buffer;
}
public override byte[] ReadSectorsTag(UInt64 sectorAddress, UInt32 length, SectorTagType tag)
{
if (tag != SectorTagType.AppleSectorTag)
throw new FeatureUnsupportedImageException(String.Format("Tag {0} not supported by image format", tag));
if (header.tagSize == 0)
throw new FeatureNotPresentImageException("Disk image does not have tags");
if (sectorAddress > sectors - 1)
throw new ArgumentOutOfRangeException("sectorAddress", "Sector address not found");
if (sectorAddress + length > sectors)
throw new ArgumentOutOfRangeException("length", "Requested more sectors than available");
byte[] buffer = new byte[length * bptag];
FileStream stream = new FileStream(dc42ImagePath, FileMode.Open, FileAccess.Read);
stream.Seek((long)(tagOffset + sectorAddress * bptag), SeekOrigin.Begin);
stream.Read(buffer, 0, (int)(length * bptag));
return buffer;
}
public override byte[] ReadSectorLong(UInt64 sectorAddress)
{
return ReadSectorsLong(sectorAddress, 1);
}
public override byte[] ReadSectorsLong(UInt64 sectorAddress, UInt32 length)
{
if (sectorAddress > sectors - 1)
throw new ArgumentOutOfRangeException("sectorAddress", "Sector address not found");
if (sectorAddress + length > sectors)
throw new ArgumentOutOfRangeException("length", "Requested more sectors than available");
byte[] data = ReadSectors(sectorAddress, length);
byte[] tags = ReadSectorsTag(sectorAddress, length, SectorTagType.AppleSectorTag);
byte[] buffer = new byte[data.Length + tags.Length];
for (uint i = 0; i < length; i++)
{
Array.Copy(data, i * (bps), buffer, i * (bps + bptag), bps);
Array.Copy(tags, i * (bptag), buffer, i * (bps + bptag) + bps, bptag);
}
return buffer;
}
public override string GetImageFormat()
{
return "Apple DiskCopy 4.2";
}
public override string GetImageVersion()
{
return "4.2";
}
public override string GetImageApplication()
{
return "Apple DiskCopy";
}
public override string GetImageApplicationVersion()
{
return "4.2";
}
public override DateTime GetImageCreationTime()
{
FileInfo fi = new FileInfo(dc42ImagePath);
return fi.CreationTimeUtc;
}
public override DateTime GetImageLastModificationTime()
{
FileInfo fi = new FileInfo(dc42ImagePath);
return fi.LastWriteTimeUtc;
}
public override string GetImageName()
{
return header.diskName;
}
public override DiskType GetDiskType()
{
switch (header.format)
{
case kSonyFormat400K:
return DiskType.AppleSonySS;
case kSonyFormat800K:
return DiskType.AppleSonyDS;
case kSonyFormat720K:
return DiskType.DOS_35_DS_DD_9;
case kSonyFormat1440K:
return DiskType.DOS_35_HD;
case kSonyFormat1680K:
return DiskType.DMF;
case kSigmaFormatTwiggy:
return DiskType.AppleFileWare;
default:
return DiskType.Unknown;
}
}
#region Unsupported features
public override byte[] ReadDiskTag(DiskTagType tag)
{
throw new FeatureUnsupportedImageException("Feature not supported by image format");
}
public override string GetImageCreator()
{
throw new FeatureUnsupportedImageException("Feature not supported by image format");
}
public override string GetImageComments()
{
throw new FeatureUnsupportedImageException("Feature not supported by image format");
}
public override string GetDiskManufacturer()
{
throw new FeatureUnsupportedImageException("Feature not supported by image format");
}
public override string GetDiskModel()
{
throw new FeatureUnsupportedImageException("Feature not supported by image format");
}
public override string GetDiskSerialNumber()
{
throw new FeatureUnsupportedImageException("Feature not supported by image format");
}
public override string GetDiskBarcode()
{
throw new FeatureUnsupportedImageException("Feature not supported by image format");
}
public override string GetDiskPartNumber()
{
throw new FeatureUnsupportedImageException("Feature not supported by image format");
}
public override int GetDiskSequence()
{
throw new FeatureUnsupportedImageException("Feature not supported by image format");
}
public override int GetLastDiskSequence()
{
throw new FeatureUnsupportedImageException("Feature not supported by image format");
}
public override string GetDriveManufacturer()
{
throw new FeatureUnsupportedImageException("Feature not supported by image format");
}
public override string GetDriveModel()
{
throw new FeatureUnsupportedImageException("Feature not supported by image format");
}
public override string GetDriveSerialNumber()
{
throw new FeatureUnsupportedImageException("Feature not supported by image format");
}
public override List<PartPlugins.Partition> GetPartitions()
{
throw new FeatureUnsupportedImageException("Feature not supported by image format");
}
public override List<Track> GetTracks()
{
throw new FeatureUnsupportedImageException("Feature not supported by image format");
}
public override List<Track> GetSessionTracks(Session session)
{
throw new FeatureUnsupportedImageException("Feature not supported by image format");
}
public override List<Track> GetSessionTracks(UInt16 session)
{
throw new FeatureUnsupportedImageException("Feature not supported by image format");
}
public override List<Session> GetSessions()
{
throw new FeatureUnsupportedImageException("Feature not supported by image format");
}
public override byte[] ReadSector(UInt64 sectorAddress, UInt32 track)
{
throw new FeatureUnsupportedImageException("Feature not supported by image format");
}
public override byte[] ReadSectorTag(UInt64 sectorAddress, UInt32 track, SectorTagType tag)
{
throw new FeatureUnsupportedImageException("Feature not supported by image format");
}
public override byte[] ReadSectors(UInt64 sectorAddress, UInt32 length, UInt32 track)
{
throw new FeatureUnsupportedImageException("Feature not supported by image format");
}
public override byte[] ReadSectorsTag(UInt64 sectorAddress, UInt32 length, UInt32 track, SectorTagType tag)
{
throw new FeatureUnsupportedImageException("Feature not supported by image format");
}
public override byte[] ReadSectorLong(UInt64 sectorAddress, UInt32 track)
{
throw new FeatureUnsupportedImageException("Feature not supported by image format");
}
public override byte[] ReadSectorsLong(UInt64 sectorAddress, UInt32 length, UInt32 track)
{
throw new FeatureUnsupportedImageException("Feature not supported by image format");
}
#endregion Unsupported features
}
}

View File

@@ -0,0 +1,947 @@
/***************************************************************************
The Disc Image Chef
----------------------------------------------------------------------------
Filename : ImagePlugin.cs
Version : 1.0
Author(s) : Natalia Portillo
Component : Disc image plugins
Revision : $Revision$
Last change by : $Author$
Date : $Date$
--[ Description ] ----------------------------------------------------------
Defines functions to be used by disc image 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;
using System.Collections.Generic;
namespace DiscImageChef.ImagePlugins
{
/// <summary>
/// Abstract class to implement disk image reading plugins.
/// </summary>
public abstract class ImagePlugin
{
/// <summary>Plugin name.</summary>
public string Name;
/// <summary>Plugin UUID.</summary>
public Guid PluginUUID;
protected ImagePlugin()
{
}
// Basic image handling functions
/// <summary>
/// Identifies the image.
/// </summary>
/// <returns><c>true</c>, if image was identified, <c>false</c> otherwise.</returns>
/// <param name="imagePath">Image path.</param>
public abstract bool IdentifyImage(string imagePath);
/// <summary>
/// Opens the image.
/// </summary>
/// <returns><c>true</c>, if image was opened, <c>false</c> otherwise.</returns>
/// <param name="imagePath">Image path.</param>
public abstract bool OpenImage(string imagePath);
/// <summary>
/// Asks the disk image plugin if the image contains partitions
/// </summary>
/// <returns><c>true</c>, if the image contains partitions, <c>false</c> otherwise.</returns>
public abstract bool ImageHasPartitions();
// Image size functions
/// <summary>
/// Gets the size of the image, without headers.
/// </summary>
/// <returns>The image size.</returns>
public abstract UInt64 GetImageSize();
/// <summary>
/// Gets the number of sectors in the image.
/// </summary>
/// <returns>Sectors in image.</returns>
public abstract UInt64 GetSectors();
/// <summary>
/// Returns the size of the biggest sector, counting user data only.
/// </summary>
/// <returns>Biggest sector size (user data only).</returns>
public abstract UInt32 GetSectorSize();
// Image reading functions
/// <summary>
/// Reads a disk tag.
/// </summary>
/// <returns>Disk tag</returns>
/// <param name="tag">Tag type to read.</param>
public abstract byte[] ReadDiskTag(DiskTagType tag);
// Gets a disk tag
/// <summary>
/// Reads a sector's user data.
/// </summary>
/// <returns>The sector's user data.</returns>
/// <param name="sectorAddress">Sector address (LBA).</param>
public abstract byte[] ReadSector(UInt64 sectorAddress);
/// <summary>
/// Reads a sector's tag.
/// </summary>
/// <returns>The sector's tag.</returns>
/// <param name="sectorAddress">Sector address (LBA).</param>
/// <param name="tag">Tag type.</param>
public abstract byte[] ReadSectorTag(UInt64 sectorAddress, SectorTagType tag);
/// <summary>
/// Reads a sector's user data, relative to track.
/// </summary>
/// <returns>The sector's user data.</returns>
/// <param name="sectorAddress">Sector address (relative LBA).</param>
/// <param name="track">Track.</param>
public abstract byte[] ReadSector(UInt64 sectorAddress, UInt32 track);
/// <summary>
/// Reads a sector's tag, relative to track.
/// </summary>
/// <returns>The sector's tag.</returns>
/// <param name="sectorAddress">Sector address (relative LBA).</param>
/// <param name="track">Track.</param>
/// <param name="tag">Tag type.</param>
public abstract byte[] ReadSectorTag(UInt64 sectorAddress, UInt32 track, SectorTagType tag);
/// <summary>
/// Reads user data from several sectors.
/// </summary>
/// <returns>The sectors user data.</returns>
/// <param name="sectorAddress">Starting sector address (LBA).</param>
/// <param name="length">How many sectors to read.</param>
public abstract byte[] ReadSectors(UInt64 sectorAddress, UInt32 length);
/// <summary>
/// Reads tag from several sectors.
/// </summary>
/// <returns>The sectors tag.</returns>
/// <param name="sectorAddress">Starting sector address (LBA).</param>
/// <param name="length">How many sectors to read.</param>
/// <param name="tag">Tag type.</param>
public abstract byte[] ReadSectorsTag(UInt64 sectorAddress, UInt32 length, SectorTagType tag);
/// <summary>
/// Reads user data from several sectors, relative to track.
/// </summary>
/// <returns>The sectors user data.</returns>
/// <param name="sectorAddress">Starting sector address (relative LBA).</param>
/// <param name="length">How many sectors to read.</param>
/// <param name="track">Track.</param>
public abstract byte[] ReadSectors(UInt64 sectorAddress, UInt32 length, UInt32 track);
/// <summary>
/// Reads tag from several sectors, relative to track.
/// </summary>
/// <returns>The sectors tag.</returns>
/// <param name="sectorAddress">Starting sector address (relative LBA).</param>
/// <param name="length">How many sectors to read.</param>
/// <param name="track">Track.</param>
/// <param name="tag">Tag type.</param>
public abstract byte[] ReadSectorsTag(UInt64 sectorAddress, UInt32 length, UInt32 track, SectorTagType tag);
/// <summary>
/// Reads a complete sector (user data + all tags).
/// </summary>
/// <returns>The complete sector. Format depends on disk type.</returns>
/// <param name="sectorAddress">Sector address (LBA).</param>
public abstract byte[] ReadSectorLong(UInt64 sectorAddress);
/// <summary>
/// Reads a complete sector (user data + all tags), relative to track.
/// </summary>
/// <returns>The complete sector. Format depends on disk type.</returns>
/// <param name="sectorAddress">Sector address (relative LBA).</param>
/// <param name="track">Track.</param>
public abstract byte[] ReadSectorLong(UInt64 sectorAddress, UInt32 track);
/// <summary>
/// Reads several complete sector (user data + all tags).
/// </summary>
/// <returns>The complete sectors. Format depends on disk type.</returns>
/// <param name="sectorAddress">Starting sector address (LBA).</param>
/// <param name="length">How many sectors to read.</param>
public abstract byte[] ReadSectorsLong(UInt64 sectorAddress, UInt32 length);
/// <summary>
/// Reads several complete sector (user data + all tags), relative to track.
/// </summary>
/// <returns>The complete sectors. Format depends on disk type.</returns>
/// <param name="sectorAddress">Starting sector address (relative LBA).</param>
/// <param name="length">How many sectors to read.</param>
/// <param name="track">Track.</param>
public abstract byte[] ReadSectorsLong(UInt64 sectorAddress, UInt32 length, UInt32 track);
// Image information functions
/// <summary>
/// Gets the image format.
/// </summary>
/// <returns>The image format.</returns>
public abstract string GetImageFormat();
/// <summary>
/// Gets the image version.
/// </summary>
/// <returns>The image version.</returns>
public abstract string GetImageVersion();
/// <summary>
/// Gets the application that created the image.
/// </summary>
/// <returns>The application that created the image.</returns>
public abstract string GetImageApplication();
/// <summary>
/// Gets the version of the application that created the image.
/// </summary>
/// <returns>The version of the application that created the image.</returns>
public abstract string GetImageApplicationVersion();
/// <summary>
/// Gets the image creator.
/// </summary>
/// <returns>Who created the image.</returns>
public abstract string GetImageCreator();
/// <summary>
/// Gets the image creation time.
/// </summary>
/// <returns>The image creation time.</returns>
public abstract DateTime GetImageCreationTime();
/// <summary>
/// Gets the image last modification time.
/// </summary>
/// <returns>The image last modification time.</returns>
public abstract DateTime GetImageLastModificationTime();
/// <summary>
/// Gets the name of the image.
/// </summary>
/// <returns>The image name.</returns>
public abstract string GetImageName();
/// <summary>
/// Gets the image comments.
/// </summary>
/// <returns>The image comments.</returns>
public abstract string GetImageComments();
// Functions to get information from disk represented by image
/// <summary>
/// Gets the disk manufacturer.
/// </summary>
/// <returns>The disk manufacturer.</returns>
public abstract string GetDiskManufacturer();
/// <summary>
/// Gets the disk model.
/// </summary>
/// <returns>The disk model.</returns>
public abstract string GetDiskModel();
/// <summary>
/// Gets the disk serial number.
/// </summary>
/// <returns>The disk serial number.</returns>
public abstract string GetDiskSerialNumber();
/// <summary>
/// Gets the disk (or product) barcode.
/// </summary>
/// <returns>The disk barcode.</returns>
public abstract string GetDiskBarcode();
/// <summary>
/// Gets the disk part number.
/// </summary>
/// <returns>The disk part number.</returns>
public abstract string GetDiskPartNumber();
/// <summary>
/// Gets the type of the disk.
/// </summary>
/// <returns>The disk type.</returns>
public abstract DiskType GetDiskType();
/// <summary>
/// Gets the disk sequence.
/// </summary>
/// <returns>The disk sequence, starting at 1.</returns>
public abstract int GetDiskSequence();
/// <summary>
/// Gets the last disk in the sequence.
/// </summary>
/// <returns>The last disk in the sequence.</returns>
public abstract int GetLastDiskSequence();
// Functions to get information from drive used to create image
/// <summary>
/// Gets the manufacturer of the drive used to create the image.
/// </summary>
/// <returns>The drive manufacturer.</returns>
public abstract string GetDriveManufacturer();
/// <summary>
/// Gets the model of the drive used to create the image.
/// </summary>
/// <returns>The drive model.</returns>
public abstract string GetDriveModel();
/// <summary>
/// Gets the serial number of the drive used to create the image.
/// </summary>
/// <returns>The drive serial number.</returns>
public abstract string GetDriveSerialNumber();
// Partitioning functions
/// <summary>
/// Gets an array partitions. Typically only useful for optical disc
/// images where each track and index means a different partition, as
/// reads can be relative to them.
/// </summary>
/// <returns>The partitions.</returns>
public abstract List<PartPlugins.Partition> GetPartitions();
/// <summary>
/// Gets the disc track extents (start, length).
/// </summary>
/// <returns>The track extents.</returns>
public abstract List<Track> GetTracks();
/// <summary>
/// Gets the disc track extents for a specified session.
/// </summary>
/// <returns>The track exents for that session.</returns>
/// <param name="session">Session.</param>
public abstract List<Track> GetSessionTracks(Session session);
/// <summary>
/// Gets the disc track extents for a specified session.
/// </summary>
/// <returns>The track exents for that session.</returns>
/// <param name="session">Session.</param>
public abstract List<Track> GetSessionTracks(UInt16 session);
/// <summary>
/// Gets the sessions (optical discs only).
/// </summary>
/// <returns>The sessions.</returns>
public abstract List<Session> GetSessions();
// Returns disc sessions
// CD flags bitmask
/// <summary>Track is quadraphonic.</summary>
public const byte CDFlagsFourChannel = 0x20;
/// <summary>Track is non-audio (data).</summary>
public const byte CDFlagsDataTrack = 0x10;
/// <summary>Track is copy protected.</summary>
public const byte CDFlagsCopyPrevent = 0x08;
/// <summary>Track has pre-emphasis.</summary>
public const byte CDFlagsPreEmphasis = 0x04;
}
// Disk types
public enum DiskType
{
/// <summary>Unknown disk type</summary>
Unknown,
// Somewhat standard Compact Disc formats
/// <summary>CD Digital Audio (Red Book)</summary>
CDDA,
/// <summary>CD+G (Red Book)</summary>
CDG,
/// <summary>CD+EG (Red Book)</summary>
CDEG,
/// <summary>CD-i (Green Book)</summary>
CDI,
/// <summary>CD-ROM (Yellow Book)</summary>
CDROM,
/// <summary>CD-ROM XA (Yellow Book)</summary>
CDROMXA,
/// <summary>CD+ (Blue Book)</summary>
CDPLUS,
/// <summary>CD-MO (Orange Book)</summary>
CDMO,
/// <summary>CD-Recordable (Orange Book)</summary>
CDR,
/// <summary>CD-ReWritable (Orange Book)</summary>
CDRW,
/// <summary>Mount-Rainier CD-RW</summary>
CDMRW,
/// <summary>Video CD (White Book)</summary>
VCD,
/// <summary>Super Video CD (White Book)</summary>
SVCD,
/// <summary>Photo CD (Beige Book)</summary>
PCD,
/// <summary>Super Audio CD (Scarlet Book)</summary>
SACD,
/// <summary>Double-Density CD-ROM (Purple Book)</summary>
DDCD,
/// <summary>DD CD-R (Purple Book)</summary>
DDCDR,
/// <summary>DD CD-RW (Purple Book)</summary>
DDCDRW,
/// <summary>DTS audio CD (non-standard)</summary>
DTSCD,
/// <summary>CD-MIDI (Red Book)</summary>
CDMIDI,
/// <summary>Any unknown or standard violating CD</summary>
CD,
// Standard DVD formats
/// <summary>DVD-ROM (applies to DVD Video and DVD Audio)</summary>
DVDROM,
/// <summary>DVD-R</summary>
DVDR,
/// <summary>DVD-RW</summary>
DVDRW,
/// <summary>DVD+R</summary>
DVDPR,
/// <summary>DVD+RW</summary>
DVDPRW,
/// <summary>DVD+RW DL</summary>
DVDPRWDL,
/// <summary>DVD-R DL</summary>
DVDRDL,
/// <summary>DVD+R DL</summary>
DVDPRDL,
/// <summary>DVD-RAM</summary>
DVDRAM,
// Standard HD-DVD formats
/// <summary>HD DVD-ROM (applies to HD DVD Video)</summary>
HDDVDROM,
/// <summary>HD DVD-RAM</summary>
HDDVDRAM,
/// <summary>HD DVD-R</summary>
HDDVDR,
/// <summary>HD DVD-RW</summary>
HDDVDRW,
// Standard Blu-ray formats
/// <summary>BD-ROM (and BD Video)</summary>
BDROM,
/// <summary>BD-R</summary>
BDR,
/// <summary>BD-RE</summary>
BDRE,
/// <summary>BD-R XL</summary>
BDRXL,
/// <summary>BD-RE XL</summary>
BDREXL,
// Rare or uncommon standards
/// <summary>Enhanced Versatile Disc</summary>
EVD,
/// <summary>Forward Versatile Disc</summary>
FVD,
/// <summary>Holographic Versatile Disc</summary>
HVD,
/// <summary>China Blue High Definition</summary>
CBHD,
/// <summary>High Definition Versatile Multilayer Disc</summary>
HDVMD,
/// <summary>Versatile Compact Disc High Density</summary>
VCDHD,
/// <summary>Pioneer LaserDisc</summary>
LD,
/// <summary>Pioneer LaserDisc data</summary>
LDROM,
/// <summary>Sony MiniDisc</summary>
MD,
/// <summary>Sony Hi-MD</summary>
HiMD,
/// <summary>Ultra Density Optical</summary>
UDO,
/// <summary>Stacked Volumetric Optical Disc</summary>
SVOD,
/// <summary>Five Dimensional disc</summary>
FDDVD,
// Propietary game discs
/// <summary>Sony PlayStation game CD</summary>
PS1CD,
/// <summary>Sony PlayStation 2 game CD</summary>
PS2CD,
/// <summary>Sony PlayStation 2 game DVD</summary>
PS2DVD,
/// <summary>Sony PlayStation 3 game DVD</summary>
PS3DVD,
/// <summary>Sony PlayStation 3 game Blu-ray</summary>
PS3BD,
/// <summary>Sony PlayStation 4 game Blu-ray</summary>
PS4BD,
/// <summary>Sony PlayStation Portable Universal Media Disc (ECMA-365)</summary>
UMD,
/// <summary>Nintendo GameCube Optical Disc</summary>
GOD,
/// <summary>Nintendo Wii Optical Disc</summary>
WOD,
/// <summary>Nintendo Wii U Optical Disc</summary>
WUOD,
/// <summary>Microsoft X-box Game Disc</summary>
XGD,
/// <summary>Microsoft X-box 360 Game Disc</summary>
XGD2,
/// <summary>Microsoft X-box 360 Game Disc</summary>
XGD3,
/// <summary>Microsoft X-box One Game Disc</summary>
XGD4,
/// <summary>Sega MegaCD</summary>
MEGACD,
/// <summary>Sega Saturn disc</summary>
SATURNCD,
/// <summary>Sega/Yamaha Gigabyte Disc</summary>
GDROM,
/// <summary>Sega/Yamaha recordable Gigabyte Disc}}</summary>
GDR,
// Apple standard floppy format
/// <summary>5.25", SS, DD, 35 tracks, 13 spt, 256 bytes/sector, GCR</summary>
Apple32SS,
/// <summary>5.25", DS, DD, 35 tracks, 13 spt, 256 bytes/sector, GCR</summary>
Apple32DS,
/// <summary>5.25", SS, DD, 35 tracks, 16 spt, 256 bytes/sector, GCR</summary>
Apple33SS,
/// <summary>5.25", DS, DD, 35 tracks, 16 spt, 256 bytes/sector, GCR</summary>
Apple33DS,
/// <summary>3.5", SS, DD, 80 tracks, 8 to 12 spt, 512 bytes/sector, GCR</summary>
AppleSonySS,
/// <summary>3.5", DS, DD, 80 tracks, 8 to 12 spt, 512 bytes/sector, GCR</summary>
AppleSonyDS,
/// <summary>5.25", DS, ?D, ?? tracks, ?? spt, 512 bytes/sector, GCR, opposite side heads, aka Twiggy</summary>
AppleFileWare,
// IBM/Microsoft PC standard floppy formats
/// <summary>5.25", SS, DD, 40 tracks, 8 spt, 512 bytes/sector, MFM</summary>
DOS_525_SS_DD_8,
/// <summary>5.25", SS, DD, 40 tracks, 9 spt, 512 bytes/sector, MFM</summary>
DOS_525_SS_DD_9,
/// <summary>5.25", DS, DD, 40 tracks, 8 spt, 512 bytes/sector, MFM</summary>
DOS_525_DS_DD_8,
/// <summary>5.25", DS, DD, 40 tracks, 9 spt, 512 bytes/sector, MFM</summary>
DOS_525_DS_DD_9,
/// <summary>5.25", DS, HD, 80 tracks, 15 spt, 512 bytes/sector, MFM</summary>
DOS_525_HD,
/// <summary>3.5", SS, DD, 80 tracks, 8 spt, 512 bytes/sector, MFM</summary>
DOS_35_SS_DD_8,
/// <summary>3.5", SS, DD, 80 tracks, 9 spt, 512 bytes/sector, MFM</summary>
DOS_35_SS_DD_9,
/// <summary>3.5", DS, DD, 80 tracks, 8 spt, 512 bytes/sector, MFM</summary>
DOS_35_DS_DD_8,
/// <summary>3.5", DS, DD, 80 tracks, 9 spt, 512 bytes/sector, MFM</summary>
DOS_35_DS_DD_9,
/// <summary>3.5", DS, HD, 80 tracks, 18 spt, 512 bytes/sector, MFM</summary>
DOS_35_HD,
/// <summary>3.5", DS, ED, 80 tracks, 36 spt, 512 bytes/sector, MFM</summary>
DOS_35_ED,
// Microsoft non standard floppy formats
/// <summary>3.5", DS, DD, 80 tracks, 21 spt, 512 bytes/sector, MFM</summary>
DMF,
/// <summary>3.5", DS, DD, 82 tracks, 21 spt, 512 bytes/sector, MFM</summary>
DMF_82,
// IBM non standard floppy formats
XDF_525,
XDF_35,
// IBM standard floppy formats
/// <summary>8", SS, SD, 32 tracks, 8 spt, 319 bytes/sector, FM</summary>
IBM23FD,
/// <summary>8", SS, SD, 73 tracks, 26 spt, 128 bytes/sector, FM</summary>
IBM33FD_128,
/// <summary>8", SS, SD, 74 tracks, 15 spt, 256 bytes/sector, FM, track 0 = 26 sectors, 128 bytes/sector</summary>
IBM33FD_256,
/// <summary>8", SS, SD, 74 tracks, 8 spt, 512 bytes/sector, FM, track 0 = 26 sectors, 128 bytes/sector</summary>
IBM33FD_512,
/// <summary>8", DS, SD, 74 tracks, 26 spt, 128 bytes/sector, FM, track 0 = 26 sectors, 128 bytes/sector</summary>
IBM43FD_128,
/// <summary>8", DS, SD, 74 tracks, 26 spt, 256 bytes/sector, FM, track 0 = 26 sectors, 128 bytes/sector</summary>
IBM43FD_256,
/// <summary>8", DS, DD, 74 tracks, 26 spt, 256 bytes/sector, MFM, track 0 side 0 = 26 sectors, 128 bytes/sector, track 0 side 1 = 26 sectors, 256 bytes/sector</summary>
IBM53FD_256,
/// <summary>8", DS, DD, 74 tracks, 15 spt, 512 bytes/sector, MFM, track 0 side 0 = 26 sectors, 128 bytes/sector, track 0 side 1 = 26 sectors, 256 bytes/sector</summary>
IBM53FD_512,
/// <summary>8", DS, DD, 74 tracks, 8 spt, 1024 bytes/sector, MFM, track 0 side 0 = 26 sectors, 128 bytes/sector, track 0 side 1 = 26 sectors, 256 bytes/sector</summary>
IBM53FD_1024,
// DEC standard floppy formats
/// <summary>8", SS, DD, 77 tracks, 26 spt, 128 bytes/sector, FM</summary>
RX01,
/// <summary>8", SS, DD, 77 tracks, 26 spt, 256 bytes/sector, FM/MFM</summary>
RX02,
// Acorn standard floppy formats
/// <summary>5,25", SS, SD, 40 tracks, 10 spt, 256 bytes/sector, FM</summary>
ACORN_525_SS_SD_40,
/// <summary>5,25", SS, SD, 80 tracks, 10 spt, 256 bytes/sector, FM</summary>
ACORN_525_SS_SD_80,
/// <summary>5,25", SS, DD, 40 tracks, 16 spt, 256 bytes/sector, MFM</summary>
ACORN_525_SS_DD_40,
/// <summary>5,25", SS, DD, 80 tracks, 16 spt, 256 bytes/sector, MFM</summary>
ACORN_525_SS_DD_80,
/// <summary>5,25", DS, DD, 80 tracks, 16 spt, 256 bytes/sector, MFM</summary>
ACORN_525_DS_DD,
// Atari standard floppy formats
/// <summary>5,25", SS, SD, 40 tracks, 18 spt, 128 bytes/sector, FM</summary>
ATARI_525_SD,
/// <summary>5,25", SS, ED, 40 tracks, 26 spt, 128 bytes/sector, MFM</summary>
ATARI_525_ED,
/// <summary>5,25", SS, DD, 40 tracks, 18 spt, 256 bytes/sector, MFM</summary>
ATARI_525_DD,
// Commodore standard floppy formats
/// <summary>3,5", DS, DD, 80 tracks, 10 spt, 512 bytes/sector, MFM</summary>
CBM_35_DD,
/// <summary>3,5", DS, DD, 80 tracks, 11 spt, 512 bytes/sector, MFM (Amiga)</summary>
CBM_AMIGA_35_DD,
/// <summary>3,5", DS, HD, 80 tracks, 22 spt, 512 bytes/sector, MFM (Amiga)</summary>
CBM_AMIGA_35_HD,
// NEC standard floppy formats
/// <summary>8", SS, SD, 77 tracks, 26 spt, 128 bytes/sector, FM</summary>
NEC_8_SD,
/// <summary>8", DS, DD, 77 tracks, 8 spt, 1024 bytes/sector, MFM</summary>
NEC_8_DD,
/// <summary>5,25", DS, HD, 80 tracks, 8 spt, 1024 bytes/sector, MFM</summary>
NEC_525_HD,
/// <summary>3,5", DS, HD, 80 tracks, 8 spt, 1024 bytes/sector, MFM</summary>
NEC_35_HD_8,
/// <summary>3,5", DS, HD, 80 tracks, 15 spt, 512 bytes/sector, MFM</summary>
NEC_35_HD_15,
// SHARP standard floppy formats
/// <summary>5,25", DS, DD, 77 tracks, 8 spt, 1024 bytes/sector, FM</summary>
SHARP_525,
/// <summary>3,5", DS, DD, 77 tracks, 8 spt, 1024 bytes/sector, FM</summary>
SHARP_35,
// ECMA standards
/// <summary>5,25", DS, DD, 80 tracks, 8 spt, 1024 bytes/sector, MFM, track 0 side 0 = 26 sectors, 128 bytes/sector, track 0 side 1 = 26 sectors, 256 bytes/sector</summary>
ECMA_99_8,
/// <summary>5,25", DS, DD, 77 tracks, 15 spt, 512 bytes/sector, MFM, track 0 side 0 = 26 sectors, 128 bytes/sector, track 0 side 1 = 26 sectors, 256 bytes/sector</summary>
ECMA_99_15,
/// <summary>5,25", DS, DD, 77 tracks, 26 spt, 256 bytes/sector, MFM, track 0 side 0 = 26 sectors, 128 bytes/sector, track 0 side 1 = 26 sectors, 256 bytes/sector</summary>
ECMA_99_26,
/// <summary>3,5", DS, DD, 80 tracks, 9 spt, 512 bytes/sector, MFM</summary>
ECMA_100,
/// <summary>3,5", DS, HD, 80 tracks, 18 spt, 512 bytes/sector, MFM</summary>
ECMA_125,
/// <summary>3,5", DS, ED, 80 tracks, 36 spt, 512 bytes/sector, MFM</summary>
ECMA_147,
/// <summary>8", SS, SD, 77 tracks, 26 spt, 128 bytes/sector, FM</summary>
ECMA_54,
/// <summary>8", DS, SD, 77 tracks, 26 spt, 128 bytes/sector, FM</summary>
ECMA_59,
/// <summary>5,25", SS, DD, 35 tracks, 9 spt, 256 bytes/sector, FM, track 0 side 0 = 16 sectors, 128 bytes/sector</summary>
ECMA_66,
/// <summary>8", DS, DD, 77 tracks, 8 spt, 1024 bytes/sector, FM, track 0 side 0 = 26 sectors, 128 bytes/sector, track 0 side 1 = 26 sectors, 256 bytes/sector</summary>
ECMA_69_8,
/// <summary>8", DS, DD, 77 tracks, 15 spt, 512 bytes/sector, FM, track 0 side 0 = 26 sectors, 128 bytes/sector, track 0 side 1 = 26 sectors, 256 bytes/sector</summary>
ECMA_69_15,
/// <summary>8", DS, DD, 77 tracks, 26 spt, 256 bytes/sector, FM, track 0 side 0 = 26 sectors, 128 bytes/sector, track 0 side 1 = 26 sectors, 256 bytes/sector</summary>
ECMA_69_26,
/// <summary>5,25", DS, DD, 40 tracks, 16 spt, 256 bytes/sector, FM, track 0 side 0 = 16 sectors, 128 bytes/sector, track 0 side 1 = 16 sectors, 256 bytes/sector</summary>
ECMA_70,
/// <summary>5,25", DS, DD, 80 tracks, 16 spt, 256 bytes/sector, FM, track 0 side 0 = 16 sectors, 128 bytes/sector, track 0 side 1 = 16 sectors, 256 bytes/sector</summary>
ECMA_78,
/// <summary>5,25", DS, DD, 80 tracks, 9 spt, 512 bytes/sector, FM</summary>
ECMA_78_2,
/// <summary>3,5", M.O., 250000 sectors, 512 bytes/sector</summary>
ECMA_154,
/// <summary>5,25", M.O., 940470 sectors, 512 bytes/sector</summary>
ECMA_183_512,
/// <summary>5,25", M.O., 520902 sectors, 1024 bytes/sector</summary>
ECMA_183_1024,
/// <summary>5,25", M.O., 1165600 sectors, 512 bytes/sector</summary>
ECMA_184_512,
/// <summary>5,25", M.O., 639200 sectors, 1024 bytes/sector</summary>
ECMA_184_1024,
/// <summary>3,5", M.O., 448500 sectors, 512 bytes/sector</summary>
ECMA_201,
// FDFORMAT, non-standard floppy formats
/// <summary>5,25", DS, DD, 82 tracks, 10 spt, 512 bytes/sector, MFM</summary>
FDFORMAT_525_DD,
/// <summary>5,25", DS, HD, 82 tracks, 17 spt, 512 bytes/sector, MFM</summary>
FDFORMAT_525_HD,
/// <summary>5,25", DS, DD, 82 tracks, 10 spt, 512 bytes/sector, MFM</summary>
FDFORMAT_35_DD,
/// <summary>5,25", DS, HD, 82 tracks, 21 spt, 512 bytes/sector, MFM</summary>
FDFORMAT_35_HD,
// Generic hard disks
GENERIC_HDD
};
/// <summary>
/// Track (as partitioning element) types.
/// </summary>
public enum TrackType
{
/// <summary>Audio track</summary>
Audio,
/// <summary>Data track (not any of the below defined ones)</summary>
Data,
/// <summary>Data track, compact disc mode 1</summary>
CDMode1,
/// <summary>Data track, compact disc mode 2, formless</summary>
CDMode2Formless,
/// <summary>Data track, compact disc mode 2, form 1</summary>
CDMode2Form1,
/// <summary>Data track, compact disc mode 2, form 2</summary>
CDMode2Form2
};
/// <summary>
/// Track defining structure.
/// </summary>
public struct Track
{
/// <summary>Track number, 1-started</summary>
public UInt32 TrackSequence;
/// <summary>Partition type</summary>
public TrackType TrackType;
/// <summary>Track starting sector</summary>
public UInt64 TrackStartSector;
/// <summary>Track ending sector</summary>
public UInt64 TrackEndSector;
/// <summary>Track pre-gap</summary>
public UInt64 TrackPregap;
/// <summary>Session this track belongs to</summary>
public UInt16 TrackSession;
/// <summary>Information that does not find space in this struct</summary>
public string TrackDescription;
/// <summary>Indexes, 00 to 99 and sector offset</summary>
public Dictionary<int, UInt64> Indexes;
}
/// <summary>
/// Session defining structure.
/// </summary>
public struct Session
{
/// <summary>Session number, 1-started</summary>
public UInt16 SessionSequence;
/// <summary>First track present on this session</summary>
public UInt32 StartTrack;
/// <summary>Last track present on this session</summary>
public UInt32 EndTrack;
/// <summary>First sector present on this session</summary>
public UInt64 StartSector;
/// <summary>Last sector present on this session</summary>
public UInt64 EndSector;
}
/// <summary>
/// Metadata present for each sector (aka, "tag").
/// </summary>
public enum SectorTagType
{
/// <summary>Apple's GCR sector tags, 12 bytes</summary>
AppleSectorTag,
/// <summary>Sync frame from CD sector, 12 bytes</summary>
CDSectorSync,
/// <summary>CD sector header, 4 bytes</summary>
CDSectorHeader,
/// <summary>CD mode 2 sector subheader</summary>
CDSectorSubHeader,
/// <summary>CD sector EDC, 4 bytes</summary>
CDSectorEDC,
/// <summary>CD sector ECC P, 172 bytes</summary>
CDSectorECC_P,
/// <summary>CD sector ECC Q, 104 bytes</summary>
CDSectorECC_Q,
/// <summary>CD sector ECC (P and Q), 276 bytes</summary>
CDSectorECC,
/// <summary>CD sector subchannel, 96 bytes</summary>
CDSectorSubchannel,
/// <summary>CD track ISRC, string, 12 bytes</summary>
CDTrackISRC,
/// <summary>CD track text, string, 13 bytes</summary>
CDTrackText,
/// <summary>CD track flags, 1 byte</summary>
CDTrackFlags,
/// <summary>DVD sector copyright information</summary>
DVD_CMI
};
/// <summary>
/// Metadata present for each disk.
/// </summary>
public enum DiskTagType
{
/// <summary>CD PMA</summary>
CD_PMA,
/// <summary>CD Adress-Time-In-Pregroove</summary>
CD_ATIP,
/// <summary>CD-Text</summary>
CD_TEXT,
/// <summary>CD Media Catalogue Number</summary>
CD_MCN,
/// <summary>DVD Burst Cutting Area</summary>
DVD_BCA,
/// <summary>DVD Physical Format Information</summary>
DVD_PFI,
/// <summary>DVD Copyright Management Information</summary>
DVD_CMI,
/// <summary>DVD Disc Manufacturer Information</summary>
DVD_DMI
};
/// <summary>
/// Feature is supported by image but not implemented yet.
/// </summary>
[Serializable]
public class FeatureSupportedButNotImplementedImageException : Exception
{
public FeatureSupportedButNotImplementedImageException(string message, Exception inner) : base(message, inner)
{
}
public FeatureSupportedButNotImplementedImageException(string message) : base(message)
{
}
protected FeatureSupportedButNotImplementedImageException(System.Runtime.Serialization.SerializationInfo info,
System.Runtime.Serialization.StreamingContext context)
{
if (info == null)
throw new ArgumentNullException("info");
}
}
/// <summary>
/// Feature is not supported by image.
/// </summary>
[Serializable]
public class FeatureUnsupportedImageException : Exception
{
public FeatureUnsupportedImageException(string message, Exception inner) : base(message, inner)
{
}
public FeatureUnsupportedImageException(string message) : base(message)
{
}
protected FeatureUnsupportedImageException(System.Runtime.Serialization.SerializationInfo info,
System.Runtime.Serialization.StreamingContext context)
{
if (info == null)
throw new ArgumentNullException("info");
}
}
/// <summary>
/// Feature is supported by image but not present on it.
/// </summary>
[Serializable]
public class FeatureNotPresentImageException : Exception
{
public FeatureNotPresentImageException(string message, Exception inner) : base(message, inner)
{
}
public FeatureNotPresentImageException(string message) : base(message)
{
}
protected FeatureNotPresentImageException(System.Runtime.Serialization.SerializationInfo info,
System.Runtime.Serialization.StreamingContext context)
{
if (info == null)
throw new ArgumentNullException("info");
}
}
/// <summary>
/// Feature is supported by image but not by the disc it represents.
/// </summary>
[Serializable]
public class FeaturedNotSupportedByDiscImageException : Exception
{
public FeaturedNotSupportedByDiscImageException(string message, Exception inner) : base(message, inner)
{
}
public FeaturedNotSupportedByDiscImageException(string message) : base(message)
{
}
protected FeaturedNotSupportedByDiscImageException(System.Runtime.Serialization.SerializationInfo info,
System.Runtime.Serialization.StreamingContext context)
{
if (info == null)
throw new ArgumentNullException("info");
}
}
/// <summary>
/// Corrupt, incorrect or unhandled feature found on image
/// </summary>
[Serializable]
public class ImageNotSupportedException : Exception
{
public ImageNotSupportedException(string message, Exception inner) : base(message, inner)
{
}
public ImageNotSupportedException(string message) : base(message)
{
}
protected ImageNotSupportedException(System.Runtime.Serialization.SerializationInfo info,
System.Runtime.Serialization.StreamingContext context)
{
if (info == null)
throw new ArgumentNullException("info");
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,618 @@
/***************************************************************************
The Disc Image Chef
----------------------------------------------------------------------------
Filename : ZZZRawImage.cs
Version : 1.0
Author(s) : Natalia Portillo
Component : Disc image plugins
Revision : $Revision$
Last change by : $Author$
Date : $Date$
--[ Description ] ----------------------------------------------------------
Manages raw image, that is, user data sector by sector copy.
--[ 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.Collections.Generic;
namespace DiscImageChef.ImagePlugins
{
// Checked using several images and strings inside Apple's DiskImages.framework
class ZZZRawImage : ImagePlugin
{
#region Internal variables
UInt64 imageSize;
UInt64 sectors;
UInt32 sectorSize;
DateTime creationTime;
DateTime modificationTime;
string imageName;
string rawImagePath;
bool differentTrackZeroSize;
#endregion
public ZZZRawImage(PluginBase Core)
{
Name = "Raw Disk Image";
// Non-random UUID to recognize this specific plugin
PluginUUID = new Guid("12345678-AAAA-BBBB-CCCC-123456789000");
}
public override bool IdentifyImage(string imagePath)
{
FileInfo fi = new FileInfo(imagePath);
// Check if file is not multiple of 512
if ((fi.Length % 512) != 0)
{
// Check known disk sizes with sectors smaller than 512
switch (fi.Length)
{
case 81664:
case 116480:
case 242944:
case 256256:
case 287488:
case 306432:
case 495872:
case 988416:
case 995072:
case 1021696:
case 1146624:
case 1177344:
case 1222400:
case 1304320:
case 1255168:
return true;
default:
return false;
}
}
return true;
}
public override bool OpenImage(string imagePath)
{
FileStream stream = new FileStream(imagePath, FileMode.Open, FileAccess.Read);
stream.Seek(0, SeekOrigin.Begin);
FileInfo fi = new FileInfo(imagePath);
string extension = Path.GetExtension(imagePath).ToLower();
if (extension == ".iso" && (fi.Length % 2048) == 0)
sectorSize = 2048;
else
{
switch (fi.Length)
{
case 242944:
case 256256:
case 495872:
case 92160:
case 133120:
sectorSize = 128;
break;
case 116480:
case 287488: // T0S0 = 128bps
case 988416: // T0S0 = 128bps
case 995072: // T0S0 = 128bps, T0S1 = 256bps
case 1021696: // T0S0 = 128bps, T0S1 = 256bps
case 232960:
case 143360:
case 286720:
case 512512:
case 102400:
case 204800:
case 163840:
case 327680:
case 655360:
case 80384: // T0S0 = 128bps
case 325632: // T0S0 = 128bps, T0S1 = 256bps
case 653312: // T0S0 = 128bps, T0S1 = 256bps
sectorSize = 256;
break;
case 81664:
sectorSize = 319;
break;
case 306432: // T0S0 = 128bps
case 1146624: // T0S0 = 128bps, T0S1 = 256bps
case 1177344: // T0S0 = 128bps, T0S1 = 256bps
sectorSize = 512;
break;
case 1222400: // T0S0 = 128bps, T0S1 = 256bps
case 1304320: // T0S0 = 128bps, T0S1 = 256bps
case 1255168: // T0S0 = 128bps, T0S1 = 256bps
case 1261568:
case 1310720:
sectorSize = 1024;
break;
default:
sectorSize = 512;
break;
}
}
imageSize = (ulong)fi.Length;
creationTime = fi.CreationTimeUtc;
modificationTime = fi.LastWriteTimeUtc;
imageName = Path.GetFileNameWithoutExtension(imagePath);
differentTrackZeroSize = false;
rawImagePath = imagePath;
switch (fi.Length)
{
case 242944:
sectors = 1898;
break;
case 256256:
sectors = 2002;
break;
case 495872:
sectors = 3874;
break;
case 116480:
sectors = 455;
break;
case 287488: // T0S0 = 128bps
sectors = 1136;
differentTrackZeroSize = true;
break;
case 988416: // T0S0 = 128bps
sectors = 3874;
differentTrackZeroSize = true;
break;
case 995072: // T0S0 = 128bps, T0S1 = 256bps
sectors = 3900;
differentTrackZeroSize = true;
break;
case 1021696: // T0S0 = 128bps, T0S1 = 256bps
sectors = 4004;
differentTrackZeroSize = true;
break;
case 81664:
sectors = 256;
break;
case 306432: // T0S0 = 128bps
sectors = 618;
differentTrackZeroSize = true;
break;
case 1146624: // T0S0 = 128bps, T0S1 = 256bps
sectors = 2272;
differentTrackZeroSize = true;
break;
case 1177344: // T0S0 = 128bps, T0S1 = 256bps
sectors = 2332;
differentTrackZeroSize = true;
break;
case 1222400: // T0S0 = 128bps, T0S1 = 256bps
sectors = 1236;
differentTrackZeroSize = true;
break;
case 1304320: // T0S0 = 128bps, T0S1 = 256bps
sectors = 1316;
differentTrackZeroSize = true;
break;
case 1255168: // T0S0 = 128bps, T0S1 = 256bps
sectors = 1268;
differentTrackZeroSize = true;
break;
case 80384: // T0S0 = 128bps
sectors = 322;
differentTrackZeroSize = true;
break;
case 325632: // T0S0 = 128bps, T0S1 = 256bps
sectors = 1280;
differentTrackZeroSize = true;
break;
case 653312: // T0S0 = 128bps, T0S1 = 256bps
sectors = 2560;
differentTrackZeroSize = true;
break;
case 1880064: // IBM XDF, 3,5", real number of sectors
sectors = 670;
sectorSize = 8192; // Biggest sector size
differentTrackZeroSize = true;
break;
default:
sectors = imageSize / sectorSize;
break;
}
return true;
}
public override bool ImageHasPartitions()
{
return false;
}
public override UInt64 GetImageSize()
{
return imageSize;
}
public override UInt64 GetSectors()
{
return sectors;
}
public override UInt32 GetSectorSize()
{
return sectorSize;
}
public override byte[] ReadSector(UInt64 sectorAddress)
{
return ReadSectors(sectorAddress, 1);
}
public override byte[] ReadSectors(UInt64 sectorAddress, UInt32 length)
{
if (differentTrackZeroSize)
{
throw new NotImplementedException("Not yet implemented");
}
else
{
if (sectorAddress > sectors - 1)
throw new ArgumentOutOfRangeException("sectorAddress", "Sector address not found");
if (sectorAddress + length > sectors)
throw new ArgumentOutOfRangeException("length", "Requested more sectors than available");
byte[] buffer = new byte[length * sectorSize];
FileStream stream = new FileStream(rawImagePath, FileMode.Open, FileAccess.Read);
stream.Seek((long)(sectorAddress * sectorSize), SeekOrigin.Begin);
stream.Read(buffer, 0, (int)(length * sectorSize));
return buffer;
}
}
public override string GetImageFormat()
{
return "Raw disk image (sector by sector copy)";
}
public override DateTime GetImageCreationTime()
{
return creationTime;
}
public override DateTime GetImageLastModificationTime()
{
return modificationTime;
}
public override string GetImageName()
{
return imageName;
}
public override DiskType GetDiskType()
{
if (sectorSize == 2048)
{
if (sectors <= 360000)
return DiskType.CD;
if (sectors <= 2295104)
return DiskType.DVDPR;
if (sectors <= 2298496)
return DiskType.DVDR;
if (sectors <= 4171712)
return DiskType.DVDRDL;
if (sectors <= 4173824)
return DiskType.DVDPRDL;
if (sectors <= 24438784)
return DiskType.BDR;
if (sectors <= 62500864)
return DiskType.BDRXL;
return DiskType.Unknown;
}
else
{
switch (imageSize)
{
case 80384:
return DiskType.ECMA_66;
case 81664:
return DiskType.IBM23FD;
case 92160:
return DiskType.ATARI_525_SD;
case 102400:
return DiskType.ACORN_525_SS_SD_40;
case 116480:
return DiskType.Apple32SS;
case 133120:
return DiskType.ATARI_525_ED;
case 143360:
return DiskType.Apple33SS;
case 163840:
return DiskType.DOS_525_SS_DD_8;
case 184320:
return DiskType.DOS_525_SS_DD_9;
case 204800:
return DiskType.ACORN_525_SS_SD_80;
case 232960:
return DiskType.Apple32DS;
case 242944:
return DiskType.IBM33FD_128;
case 256256:
return DiskType.ECMA_54;
case 286720:
return DiskType.Apple33DS;
case 287488:
return DiskType.IBM33FD_256;
case 306432:
return DiskType.IBM33FD_512;
case 325632:
return DiskType.ECMA_70;
case 327680:
return DiskType.DOS_525_DS_DD_8;
case 368640:
return DiskType.DOS_525_DS_DD_9;
case 409600:
return DiskType.AppleSonySS;
case 495872:
return DiskType.IBM43FD_128;
case 512512:
return DiskType.ECMA_59;
case 653312:
return DiskType.ECMA_78;
case 655360:
return DiskType.ACORN_525_DS_DD;
case 737280:
return DiskType.DOS_35_DS_DD_9;
case 819200:
return DiskType.AppleSonyDS;
case 839680:
return DiskType.FDFORMAT_35_DD;
case 901120:
return DiskType.CBM_AMIGA_35_DD;
case 988416:
return DiskType.IBM43FD_256;
case 995072:
return DiskType.IBM53FD_256;
case 1021696:
return DiskType.ECMA_99_26;
case 1146624:
return DiskType.IBM53FD_512;
case 1177344:
return DiskType.ECMA_99_15;
case 1222400:
return DiskType.IBM53FD_1024;
case 1228800:
return DiskType.DOS_525_HD;
case 1255168:
return DiskType.ECMA_69_8;
case 1261568:
return DiskType.NEC_8_DD;
case 1304320:
return DiskType.ECMA_99_8;
case 1310720:
return DiskType.NEC_525_HD;
case 1427456:
return DiskType.FDFORMAT_525_HD;
case 1474560:
return DiskType.DOS_35_HD;
case 1720320:
return DiskType.DMF;
case 1763328:
return DiskType.FDFORMAT_35_HD;
case 1802240:
return DiskType.CBM_AMIGA_35_HD;
case 1880064:
return DiskType.XDF_35;
case 1884160:
return DiskType.XDF_35;
case 2949120:
return DiskType.DOS_35_ED;
case 128000000:
return DiskType.ECMA_154;
case 229632000:
return DiskType.ECMA_201;
case 481520640:
return DiskType.ECMA_183_512;
case 533403648:
return DiskType.ECMA_183_1024;
case 596787200:
return DiskType.ECMA_184_512;
case 654540800:
return DiskType.ECMA_184_1024;
default:
return DiskType.GENERIC_HDD;
}
}
}
#region Unsupported features
public override byte[] ReadSectorTag(UInt64 sectorAddress, SectorTagType tag)
{
throw new FeatureUnsupportedImageException("Feature not supported by image format");
}
public override byte[] ReadSectorsTag(UInt64 sectorAddress, UInt32 length, SectorTagType tag)
{
throw new FeatureUnsupportedImageException("Feature not supported by image format");
}
public override byte[] ReadSectorLong(UInt64 sectorAddress)
{
throw new FeatureUnsupportedImageException("Feature not supported by image format");
}
public override byte[] ReadSectorsLong(UInt64 sectorAddress, UInt32 length)
{
throw new FeatureUnsupportedImageException("Feature not supported by image format");
}
public override string GetImageVersion()
{
throw new FeatureUnsupportedImageException("Feature not supported by image format");
}
public override string GetImageApplication()
{
throw new FeatureUnsupportedImageException("Feature not supported by image format");
}
public override string GetImageApplicationVersion()
{
throw new FeatureUnsupportedImageException("Feature not supported by image format");
}
public override byte[] ReadDiskTag(DiskTagType tag)
{
throw new FeatureUnsupportedImageException("Feature not supported by image format");
}
public override string GetImageCreator()
{
throw new FeatureUnsupportedImageException("Feature not supported by image format");
}
public override string GetImageComments()
{
throw new FeatureUnsupportedImageException("Feature not supported by image format");
}
public override string GetDiskManufacturer()
{
throw new FeatureUnsupportedImageException("Feature not supported by image format");
}
public override string GetDiskModel()
{
throw new FeatureUnsupportedImageException("Feature not supported by image format");
}
public override string GetDiskSerialNumber()
{
throw new FeatureUnsupportedImageException("Feature not supported by image format");
}
public override string GetDiskBarcode()
{
throw new FeatureUnsupportedImageException("Feature not supported by image format");
}
public override string GetDiskPartNumber()
{
throw new FeatureUnsupportedImageException("Feature not supported by image format");
}
public override int GetDiskSequence()
{
throw new FeatureUnsupportedImageException("Feature not supported by image format");
}
public override int GetLastDiskSequence()
{
throw new FeatureUnsupportedImageException("Feature not supported by image format");
}
public override string GetDriveManufacturer()
{
throw new FeatureUnsupportedImageException("Feature not supported by image format");
}
public override string GetDriveModel()
{
throw new FeatureUnsupportedImageException("Feature not supported by image format");
}
public override string GetDriveSerialNumber()
{
throw new FeatureUnsupportedImageException("Feature not supported by image format");
}
public override List<PartPlugins.Partition> GetPartitions()
{
throw new FeatureUnsupportedImageException("Feature not supported by image format");
}
public override List<Track> GetTracks()
{
throw new FeatureUnsupportedImageException("Feature not supported by image format");
}
public override List<Track> GetSessionTracks(Session session)
{
throw new FeatureUnsupportedImageException("Feature not supported by image format");
}
public override List<Track> GetSessionTracks(UInt16 session)
{
throw new FeatureUnsupportedImageException("Feature not supported by image format");
}
public override List<Session> GetSessions()
{
throw new FeatureUnsupportedImageException("Feature not supported by image format");
}
public override byte[] ReadSector(UInt64 sectorAddress, UInt32 track)
{
throw new FeatureUnsupportedImageException("Feature not supported by image format");
}
public override byte[] ReadSectorTag(UInt64 sectorAddress, UInt32 track, SectorTagType tag)
{
throw new FeatureUnsupportedImageException("Feature not supported by image format");
}
public override byte[] ReadSectors(UInt64 sectorAddress, UInt32 length, UInt32 track)
{
throw new FeatureUnsupportedImageException("Feature not supported by image format");
}
public override byte[] ReadSectorsTag(UInt64 sectorAddress, UInt32 length, UInt32 track, SectorTagType tag)
{
throw new FeatureUnsupportedImageException("Feature not supported by image format");
}
public override byte[] ReadSectorLong(UInt64 sectorAddress, UInt32 track)
{
throw new FeatureUnsupportedImageException("Feature not supported by image format");
}
public override byte[] ReadSectorsLong(UInt64 sectorAddress, UInt32 length, UInt32 track)
{
throw new FeatureUnsupportedImageException("Feature not supported by image format");
}
#endregion Unsupported features
}
}

674
DiscImageChef/LICENSE Normal file
View File

@@ -0,0 +1,674 @@
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
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/>.
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
<program> Copyright (C) <year> <name of author>
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<http://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<http://www.gnu.org/philosophy/why-not-lgpl.html>.

350
DiscImageChef/Main.cs Normal file
View File

@@ -0,0 +1,350 @@
/***************************************************************************
The Disc Image Chef
----------------------------------------------------------------------------
Filename : Main.cs
Version : 1.0
Author(s) : Natalia Portillo
Component : Main program loop.
Revision : $Revision$
Last change by : $Author$
Date : $Date$
--[ Description ] ----------------------------------------------------------
Contains the main program loop.
--[ 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.Collections.Generic;
using DiscImageChef.ImagePlugins;
using DiscImageChef.PartPlugins;
using DiscImageChef.Plugins;
namespace DiscImageChef
{
class MainClass
{
static PluginBase plugins;
public static bool chkPartitions;
public static bool chkFilesystems;
public static bool isDebug;
public static void Main(string[] args)
{
plugins = new PluginBase();
chkPartitions = true;
chkFilesystems = true;
// RELEASE
isDebug = false;
// DEBUG
//isDebug = true;
Console.WriteLine("Filesystem Identifier and Checker");
Console.WriteLine("Copyright (C) 2011-2014 Natalia Portillo");
// For debug
if (isDebug)
{
plugins.RegisterAllPlugins();
Runner("");
}
else
{
if (args.Length == 0)
{
Usage();
}
else if (args.Length == 1)
{
plugins.RegisterAllPlugins();
if (args[0] == "--formats")
{
Console.WriteLine("Supported images:");
foreach (KeyValuePair<string, ImagePlugin> kvp in plugins.ImagePluginsList)
Console.WriteLine(kvp.Value.Name);
Console.WriteLine();
Console.WriteLine("Supported filesystems:");
foreach (KeyValuePair<string, Plugin> kvp in plugins.PluginsList)
Console.WriteLine(kvp.Value.Name);
Console.WriteLine();
Console.WriteLine("Supported partitions:");
foreach (KeyValuePair<string, PartPlugin> kvp in plugins.PartPluginsList)
Console.WriteLine(kvp.Value.Name);
}
else
Runner(args[0]);
}
else
{
for (int i = 0; i < args.Length - 1; i++)
{
switch (args[i])
{
case "--filesystems":
chkFilesystems = true;
chkPartitions = false;
break;
case "--partitions":
chkFilesystems = false;
chkPartitions = true;
break;
case "--all":
chkFilesystems = true;
chkPartitions = true;
break;
case "--debug":
isDebug = true;
break;
}
}
Runner(args[args.Length - 1]);
}
}
}
static void Runner(string filename)
{
List<string> id_plugins;
Plugin _plugin;
string information;
bool checkraw = false;
ImagePlugin _imageFormat;
try
{
_imageFormat = null;
// Check all but RAW plugin
foreach (ImagePlugin _imageplugin in plugins.ImagePluginsList.Values)
{
if(_imageplugin.PluginUUID != new Guid("12345678-AAAA-BBBB-CCCC-123456789000"))
{
if (_imageplugin.IdentifyImage(filename))
{
_imageFormat = _imageplugin;
Console.WriteLine("Image format identified by {0}.", _imageplugin.Name);
break;
}
}
}
// Check only RAW plugin
if (_imageFormat == null)
{
foreach (ImagePlugin _imageplugin in plugins.ImagePluginsList.Values)
{
if(_imageplugin.PluginUUID == new Guid("12345678-AAAA-BBBB-CCCC-123456789000"))
{
if (_imageplugin.IdentifyImage(filename))
{
_imageFormat = _imageplugin;
Console.WriteLine("Image format identified by {0}.", _imageplugin.Name);
break;
}
}
}
}
// Still not recognized
if (_imageFormat == null)
{
Console.WriteLine("Image format not identified, not proceeding.");
return;
}
try
{
if (!_imageFormat.OpenImage(filename))
{
Console.WriteLine("Unable to open image format");
Console.WriteLine("No error given");
return;
}
if (isDebug)
{
Console.WriteLine("DEBUG: Correctly opened image file.");
Console.WriteLine("DEBUG: Image without headers is {0} bytes.", _imageFormat.GetImageSize());
Console.WriteLine("DEBUG: Image has {0} sectors.", _imageFormat.GetSectors());
Console.WriteLine("DEBUG: Image identifies disk type as {0}.", _imageFormat.GetDiskType());
}
}
catch (Exception ex)
{
Console.WriteLine("Unable to open image format");
Console.WriteLine("Error: {0}", ex.Message);
return;
}
Console.WriteLine("Image identified as {0}.", _imageFormat.GetImageFormat());
if (chkPartitions)
{
List<Partition> partitions = new List<Partition>();
string partition_scheme = "";
// TODO: Solve possibility of multiple partition schemes (CUE + MBR, MBR + RDB, CUE + APM, etc)
foreach (PartPlugin _partplugin in plugins.PartPluginsList.Values)
{
List<Partition> _partitions;
if (_partplugin.GetInformation(_imageFormat, out _partitions))
{
partition_scheme = _partplugin.Name;
partitions = _partitions;
break;
}
}
if (_imageFormat.ImageHasPartitions())
{
partition_scheme = _imageFormat.GetImageFormat();
partitions = _imageFormat.GetPartitions();
}
if (partition_scheme == "")
{
if(MainClass.isDebug)
Console.WriteLine("DEBUG: No partitions found");
if (!chkFilesystems)
{
Console.WriteLine("No partitions founds, not searching for filesystems");
return;
}
checkraw = true;
}
else
{
Console.WriteLine("Partition scheme identified as {0}", partition_scheme);
Console.WriteLine("{0} partitions found.", partitions.Count);
for (int i = 0; i < partitions.Count; i++)
{
Console.WriteLine();
Console.WriteLine("Partition {0}:", partitions[i].PartitionSequence);
Console.WriteLine("Partition name: {0}", partitions[i].PartitionName);
Console.WriteLine("Partition type: {0}", partitions[i].PartitionType);
Console.WriteLine("Partition start: sector {0}, byte {1}", partitions[i].PartitionStartSector, partitions[i].PartitionStart);
Console.WriteLine("Partition length: {0} sectors, {1} bytes", partitions[i].PartitionSectors, partitions[i].PartitionLength);
Console.WriteLine("Partition description:");
Console.WriteLine(partitions[i].PartitionDescription);
if (chkFilesystems)
{
Console.WriteLine("Identifying filesystem on partition");
Identify(_imageFormat, out id_plugins, partitions[i].PartitionStartSector);
if (id_plugins.Count == 0)
Console.WriteLine("Filesystem not identified");
else if (id_plugins.Count > 1)
{
Console.WriteLine(String.Format("Identified by {0} plugins", id_plugins.Count));
foreach (string plugin_name in id_plugins)
{
if (plugins.PluginsList.TryGetValue(plugin_name, out _plugin))
{
Console.WriteLine(String.Format("As identified by {0}.", _plugin.Name));
_plugin.GetInformation(_imageFormat, partitions[i].PartitionStartSector, out information);
Console.Write(information);
}
}
}
else
{
plugins.PluginsList.TryGetValue(id_plugins[0], out _plugin);
Console.WriteLine(String.Format("Identified by {0}.", _plugin.Name));
_plugin.GetInformation(_imageFormat, partitions[i].PartitionStartSector, out information);
Console.Write(information);
}
}
}
}
}
if (checkraw)
{
Identify(_imageFormat, out id_plugins, 0);
if (id_plugins.Count == 0)
Console.WriteLine("Filesystem not identified");
else if (id_plugins.Count > 1)
{
Console.WriteLine(String.Format("Identified by {0} plugins", id_plugins.Count));
foreach (string plugin_name in id_plugins)
{
if (plugins.PluginsList.TryGetValue(plugin_name, out _plugin))
{
Console.WriteLine(String.Format("As identified by {0}.", _plugin.Name));
_plugin.GetInformation(_imageFormat, 0, out information);
Console.Write(information);
}
}
}
else
{
plugins.PluginsList.TryGetValue(id_plugins[0], out _plugin);
Console.WriteLine(String.Format("Identified by {0}.", _plugin.Name));
_plugin.GetInformation(_imageFormat, 0, out information);
Console.Write(information);
}
}
}
catch (Exception ex)
{
Console.WriteLine(String.Format("Error reading file: {0}", ex.Message));
if (isDebug)
Console.WriteLine(ex.StackTrace);
}
}
static void Identify(ImagePlugin imagePlugin, out List<string> id_plugins, ulong partitionOffset)
{
id_plugins = new List<string>();
foreach (Plugin _plugin in plugins.PluginsList.Values)
{
if (_plugin.Identify(imagePlugin, partitionOffset))
id_plugins.Add(_plugin.Name.ToLower());
}
}
static void Usage()
{
Console.WriteLine("Usage: filesystemidandchk [options] file");
Console.WriteLine();
Console.WriteLine(" --formats List all suported partition and filesystems");
Console.WriteLine(" --debug Show debug information");
Console.WriteLine(" --partitions Check only for partitions");
Console.WriteLine(" --filesystems Check only for filesystems");
Console.WriteLine(" --all Check for partitions and filesystems (default)");
Console.WriteLine();
}
}
}

View File

@@ -0,0 +1,276 @@
/***************************************************************************
The Disc Image Chef
----------------------------------------------------------------------------
Filename : AppleMap.cs
Version : 1.0
Author(s) : Natalia Portillo
Component : Partitioning scheme plugins
Revision : $Revision$
Last change by : $Author$
Date : $Date$
--[ Description ] ----------------------------------------------------------
Manages Apple Partition Map.
--[ 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 System.Collections.Generic;
using DiscImageChef;
// Information about structures learnt from Inside Macintosh
// Constants from image testing
namespace DiscImageChef.PartPlugins
{
class AppleMap : PartPlugin
{
// "ER"
const UInt16 APM_MAGIC = 0x4552;
// "PM"
const UInt16 APM_ENTRY = 0x504D;
// "TS", old entry magic
const UInt16 APM_OLDENT = 0x5453;
public AppleMap(PluginBase Core)
{
Name = "Apple Partition Map";
PluginUUID = new Guid("36405F8D-4F1A-07F5-209C-223D735D6D22");
}
public override bool GetInformation(ImagePlugins.ImagePlugin imagePlugin, out List<Partition> partitions)
{
byte[] cString;
ulong apm_entries;
uint sector_size;
if (imagePlugin.GetSectorSize() == 2352 || imagePlugin.GetSectorSize() == 2448)
sector_size = 2048;
else
sector_size = imagePlugin.GetSectorSize();
partitions = new List<Partition>();
AppleMapBootEntry APMB = new AppleMapBootEntry();
AppleMapPartitionEntry APMEntry = new AppleMapPartitionEntry();
byte[] APMB_sector = imagePlugin.ReadSector(0);
APMB.signature = BigEndianBitConverter.ToUInt16(APMB_sector, 0x00);
APMB.sector_size = BigEndianBitConverter.ToUInt16(APMB_sector, 0x02);
APMB.sectors = BigEndianBitConverter.ToUInt32(APMB_sector, 0x04);
APMB.reserved1 = BigEndianBitConverter.ToUInt16(APMB_sector, 0x08);
APMB.reserved2 = BigEndianBitConverter.ToUInt16(APMB_sector, 0x0A);
APMB.reserved3 = BigEndianBitConverter.ToUInt32(APMB_sector, 0x0C);
APMB.driver_entries = BigEndianBitConverter.ToUInt16(APMB_sector, 0x10);
APMB.first_driver_blk = BigEndianBitConverter.ToUInt32(APMB_sector, 0x12);
APMB.driver_size = BigEndianBitConverter.ToUInt16(APMB_sector, 0x16);
APMB.operating_system = BigEndianBitConverter.ToUInt16(APMB_sector, 0x18);
ulong first_sector = 0;
if (APMB.signature == APM_MAGIC) // APM boot block found, APM starts in next sector
first_sector = 1;
// Read first entry
byte[] APMEntry_sector = imagePlugin.ReadSector(first_sector);
APMEntry.signature = BigEndianBitConverter.ToUInt16(APMEntry_sector, 0x00);
APMEntry.reserved1 = BigEndianBitConverter.ToUInt16(APMEntry_sector, 0x02);
APMEntry.entries = BigEndianBitConverter.ToUInt32(APMEntry_sector, 0x04);
APMEntry.start = BigEndianBitConverter.ToUInt32(APMEntry_sector, 0x08);
APMEntry.sectors = BigEndianBitConverter.ToUInt32(APMEntry_sector, 0x0C);
cString = new byte[32];
Array.Copy(APMEntry_sector, 0x10, cString, 0, 32);
APMEntry.name = StringHandlers.CToString(cString);
cString = new byte[32];
Array.Copy(APMEntry_sector, 0x30, cString, 0, 32);
APMEntry.type = StringHandlers.CToString(cString);
APMEntry.first_data_block = BigEndianBitConverter.ToUInt32(APMEntry_sector, 0x50);
APMEntry.data_sectors = BigEndianBitConverter.ToUInt32(APMEntry_sector, 0x54);
APMEntry.status = BigEndianBitConverter.ToUInt32(APMEntry_sector, 0x58);
APMEntry.first_boot_block = BigEndianBitConverter.ToUInt32(APMEntry_sector, 0x5C);
APMEntry.boot_size = BigEndianBitConverter.ToUInt32(APMEntry_sector, 0x60);
APMEntry.load_address = BigEndianBitConverter.ToUInt32(APMEntry_sector, 0x64);
APMEntry.reserved2 = BigEndianBitConverter.ToUInt32(APMEntry_sector, 0x68);
APMEntry.entry_point = BigEndianBitConverter.ToUInt32(APMEntry_sector, 0x6C);
APMEntry.reserved3 = BigEndianBitConverter.ToUInt32(APMEntry_sector, 0x70);
APMEntry.checksum = BigEndianBitConverter.ToUInt32(APMEntry_sector, 0x74);
cString = new byte[16];
Array.Copy(APMEntry_sector, 0x78, cString, 0, 16);
APMEntry.processor = StringHandlers.CToString(cString);
if (APMEntry.signature != APM_ENTRY && APMEntry.signature != APM_OLDENT)
return false;
if (APMEntry.entries <= 1)
return false;
apm_entries = APMEntry.entries;
for (ulong i = 0; i < apm_entries; i++) // For each partition
{
APMEntry = new AppleMapPartitionEntry();
APMEntry_sector = imagePlugin.ReadSector(first_sector + i);
APMEntry.signature = BigEndianBitConverter.ToUInt16(APMEntry_sector, 0x00);
APMEntry.reserved1 = BigEndianBitConverter.ToUInt16(APMEntry_sector, 0x02);
APMEntry.entries = BigEndianBitConverter.ToUInt32(APMEntry_sector, 0x04);
APMEntry.start = BigEndianBitConverter.ToUInt32(APMEntry_sector, 0x08);
APMEntry.sectors = BigEndianBitConverter.ToUInt32(APMEntry_sector, 0x0C);
cString = new byte[32];
Array.Copy(APMEntry_sector, 0x10, cString, 0, 32);
APMEntry.name = StringHandlers.CToString(cString);
cString = new byte[32];
Array.Copy(APMEntry_sector, 0x30, cString, 0, 32);
APMEntry.type = StringHandlers.CToString(cString);
APMEntry.first_data_block = BigEndianBitConverter.ToUInt32(APMEntry_sector, 0x50);
APMEntry.data_sectors = BigEndianBitConverter.ToUInt32(APMEntry_sector, 0x54);
APMEntry.status = BigEndianBitConverter.ToUInt32(APMEntry_sector, 0x58);
APMEntry.first_boot_block = BigEndianBitConverter.ToUInt32(APMEntry_sector, 0x5C);
APMEntry.boot_size = BigEndianBitConverter.ToUInt32(APMEntry_sector, 0x60);
APMEntry.load_address = BigEndianBitConverter.ToUInt32(APMEntry_sector, 0x64);
APMEntry.reserved2 = BigEndianBitConverter.ToUInt32(APMEntry_sector, 0x68);
APMEntry.entry_point = BigEndianBitConverter.ToUInt32(APMEntry_sector, 0x6C);
APMEntry.reserved3 = BigEndianBitConverter.ToUInt32(APMEntry_sector, 0x70);
APMEntry.checksum = BigEndianBitConverter.ToUInt32(APMEntry_sector, 0x74);
cString = new byte[16];
Array.Copy(APMEntry_sector, 0x78, cString, 0, 16);
APMEntry.processor = StringHandlers.CToString(cString);
if (APMEntry.signature == APM_ENTRY || APMEntry.signature == APM_OLDENT) // It should have partition entry signature
{
Partition _partition = new Partition();
StringBuilder sb = new StringBuilder();
_partition.PartitionSequence = i;
_partition.PartitionType = APMEntry.type;
_partition.PartitionName = APMEntry.name;
_partition.PartitionStart = APMEntry.start * sector_size;
_partition.PartitionLength = APMEntry.sectors * sector_size;
_partition.PartitionStartSector = APMEntry.start;
_partition.PartitionSectors = APMEntry.sectors;
sb.AppendLine("Partition flags:");
if ((APMEntry.status & 0x01) == 0x01)
sb.AppendLine("Partition is valid.");
if ((APMEntry.status & 0x02) == 0x02)
sb.AppendLine("Partition entry is not available.");
if ((APMEntry.status & 0x04) == 0x04)
sb.AppendLine("Partition is mounted.");
if ((APMEntry.status & 0x08) == 0x08)
sb.AppendLine("Partition is bootable.");
if ((APMEntry.status & 0x10) == 0x10)
sb.AppendLine("Partition is readable.");
if ((APMEntry.status & 0x20) == 0x20)
sb.AppendLine("Partition is writable.");
if ((APMEntry.status & 0x40) == 0x40)
sb.AppendLine("Partition's boot code is position independent.");
if ((APMEntry.status & 0x08) == 0x08)
{
sb.AppendFormat("First boot sector: {0}", APMEntry.first_boot_block).AppendLine();
sb.AppendFormat("Boot is {0} bytes.", APMEntry.boot_size).AppendLine();
sb.AppendFormat("Boot load address: 0x{0:X8}", APMEntry.load_address).AppendLine();
sb.AppendFormat("Boot entry point: 0x{0:X8}", APMEntry.entry_point).AppendLine();
sb.AppendFormat("Boot code checksum: 0x{0:X8}", APMEntry.checksum).AppendLine();
sb.AppendFormat("Processor: {0}", APMEntry.processor).AppendLine();
}
_partition.PartitionDescription = sb.ToString();
if ((APMEntry.status & 0x01) == 0x01)
if (APMEntry.type != "Apple_partition_map")
partitions.Add(_partition);
}
}
return true;
}
public struct AppleMapBootEntry
{
// Signature ("ER")
public UInt16 signature;
// Byter per sector
public UInt16 sector_size;
// Sectors of the disk
public UInt32 sectors;
// Reserved
public UInt16 reserved1;
// Reserved
public UInt16 reserved2;
// Reserved
public UInt32 reserved3;
// Number of entries of the driver descriptor
public UInt16 driver_entries;
// First sector of the driver
public UInt32 first_driver_blk;
// Size in 512bytes sectors of the driver
public UInt16 driver_size;
// Operating system (MacOS = 1)
public UInt16 operating_system;
}
public struct AppleMapPartitionEntry
{
// Signature ("PM" or "TS")
public UInt16 signature;
// Reserved
public UInt16 reserved1;
// Number of entries on the partition map, each one sector
public UInt32 entries;
// First sector of the partition
public UInt32 start;
// Number of sectos of the partition
public UInt32 sectors;
// Partition name, 32 bytes, null-padded
public string name;
// Partition type. 32 bytes, null-padded
public string type;
// First sector of the data area
public UInt32 first_data_block;
// Number of sectors of the data area
public UInt32 data_sectors;
// Partition status
public UInt32 status;
// First sector of the boot code
public UInt32 first_boot_block;
// Size in bytes of the boot code
public UInt32 boot_size;
// Load address of the boot code
public UInt32 load_address;
// Reserved
public UInt32 reserved2;
// Entry point of the boot code
public UInt32 entry_point;
// Reserved
public UInt32 reserved3;
// Boot code checksum
public UInt32 checksum;
// Processor type, 16 bytes, null-padded
public string processor;
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,202 @@
/***************************************************************************
The Disc Image Chef
----------------------------------------------------------------------------
Filename : NeXT.cs
Version : 1.0
Author(s) : Natalia Portillo
Component : Partitioning scheme plugins
Revision : $Revision$
Last change by : $Author$
Date : $Date$
--[ Description ] ----------------------------------------------------------
Manages NeXTStep and OpenStep partitions.
--[ 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.Collections.Generic;
using System.Text;
using DiscImageChef;
// Information learnt from XNU source and testing against real disks
namespace DiscImageChef.PartPlugins
{
class NeXTDisklabel : PartPlugin
{
const UInt32 NEXT_MAGIC1 = 0x4E655854;
// "NeXT"
const UInt32 NEXT_MAGIC2 = 0x646C5632;
// "dlV2"
const UInt32 NEXT_MAGIC3 = 0x646C5633;
// "dlV3"
const UInt16 disktabStart = 0xB4;
// 180
const UInt16 disktabEntrySize = 0x2C;
// 44
public NeXTDisklabel(PluginBase Core)
{
Name = "NeXT Disklabel";
PluginUUID = new Guid("246A6D93-4F1A-1F8A-344D-50187A5513A9");
}
public override bool GetInformation(ImagePlugins.ImagePlugin imagePlugin, out List<Partition> partitions)
{
byte[] cString;
bool magic_found;
byte[] entry_sector;
UInt32 magic;
UInt32 sector_size;
UInt16 front_porch;
if (imagePlugin.GetSectorSize() == 2352 || imagePlugin.GetSectorSize() == 2448)
sector_size = 2048;
else
sector_size = imagePlugin.GetSectorSize();
partitions = new List<Partition>();
entry_sector = imagePlugin.ReadSector(0); // Starts on sector 0 on NeXT machines, CDs and floppies
magic = BigEndianBitConverter.ToUInt32(entry_sector, 0x00);
if (magic == NEXT_MAGIC1 || magic == NEXT_MAGIC2 || magic == NEXT_MAGIC3)
magic_found = true;
else
{
entry_sector = imagePlugin.ReadSector(15); // Starts on sector 15 on MBR machines
magic = BigEndianBitConverter.ToUInt32(entry_sector, 0x00);
if (magic == NEXT_MAGIC1 || magic == NEXT_MAGIC2 || magic == NEXT_MAGIC3)
magic_found = true;
else
{
if (sector_size == 2048)
entry_sector = imagePlugin.ReadSector(4); // Starts on sector 4 on RISC CDs
else
entry_sector = imagePlugin.ReadSector(16); // Starts on sector 16 on RISC disks
magic = BigEndianBitConverter.ToUInt32(entry_sector, 0x00);
if (magic == NEXT_MAGIC1 || magic == NEXT_MAGIC2 || magic == NEXT_MAGIC3)
magic_found = true;
else
return false;
}
}
front_porch = BigEndianBitConverter.ToUInt16(entry_sector, 0x6A);
if (magic_found)
{
for (int i = 0; i < 8; i++)
{
NeXTEntry entry = new NeXTEntry();
entry.start = BigEndianBitConverter.ToUInt32(entry_sector, disktabStart + disktabEntrySize * i + 0x00);
entry.sectors = BigEndianBitConverter.ToUInt32(entry_sector, disktabStart + disktabEntrySize * i + 0x04);
entry.block_size = BigEndianBitConverter.ToUInt16(entry_sector, disktabStart + disktabEntrySize * i + 0x08);
entry.frag_size = BigEndianBitConverter.ToUInt16(entry_sector, disktabStart + disktabEntrySize * i + 0x0A);
entry.optimization = entry_sector[disktabStart + disktabEntrySize * i + 0x0C];
entry.cpg = BigEndianBitConverter.ToUInt16(entry_sector, disktabStart + disktabEntrySize * i + 0x0D);
entry.bpi = BigEndianBitConverter.ToUInt16(entry_sector, disktabStart + disktabEntrySize * i + 0x0F);
entry.freemin = entry_sector[disktabStart + disktabEntrySize * i + 0x11];
entry.newfs = entry_sector[disktabStart + disktabEntrySize * i + 0x12];
cString = new byte[16];
Array.Copy(entry_sector, disktabStart + disktabEntrySize * i + 0x13, cString, 0, 16);
entry.mount_point = StringHandlers.CToString(cString);
entry.automount = entry_sector[disktabStart + disktabEntrySize * i + 0x23];
cString = new byte[8];
Array.Copy(entry_sector, disktabStart + disktabEntrySize * i + 0x24, cString, 0, 8);
entry.type = StringHandlers.CToString(cString);
if (entry.sectors > 0 && entry.sectors < 0xFFFFFFFF && entry.start < 0xFFFFFFFF)
{
Partition part = new Partition();
StringBuilder sb = new StringBuilder();
part.PartitionLength = (ulong)entry.sectors * sector_size;
part.PartitionStart = ((ulong)entry.start + front_porch) * sector_size;
part.PartitionType = entry.type;
part.PartitionSequence = (ulong)i;
part.PartitionName = entry.mount_point;
part.PartitionSectors = (ulong)entry.sectors;
part.PartitionStartSector = ((ulong)entry.start + front_porch);
sb.AppendFormat("{0} bytes per block", entry.block_size).AppendLine();
sb.AppendFormat("{0} bytes per fragment", entry.frag_size).AppendLine();
if (entry.optimization == 's')
sb.AppendLine("Space optimized");
else if (entry.optimization == 't')
sb.AppendLine("Time optimized");
else
sb.AppendFormat("Unknown optimization {0:X2}", entry.optimization).AppendLine();
sb.AppendFormat("{0} cylinders per group", entry.cpg).AppendLine();
sb.AppendFormat("{0} bytes per inode", entry.bpi).AppendLine();
sb.AppendFormat("{0}% of space must be free at minimum", entry.freemin).AppendLine();
if (entry.newfs != 1) // Seems to indicate newfs has been already run
sb.AppendLine("Filesystem should be formatted at start");
if (entry.automount == 1)
sb.AppendLine("Filesystem should be automatically mounted");
part.PartitionDescription = sb.ToString();
partitions.Add(part);
}
}
return true;
}
return false;
}
struct NeXTEntry
{
public UInt32 start;
// Sector of start, counting from front porch
public UInt32 sectors;
// Length in sectors
public UInt16 block_size;
// Filesystem's block size
public UInt16 frag_size;
// Filesystem's fragment size
public byte optimization;
// 's'pace or 't'ime
public UInt16 cpg;
// Cylinders per group
public UInt16 bpi;
// Bytes per inode
public byte freemin;
// % of minimum free space
public byte newfs;
// Should newfs be run on first start?
public string mount_point;
// Mount point or empty if mount where you want
public byte automount;
// Should automount
public string type;
// Filesystem type, always "4.3BSD"?
}
}
}

View File

@@ -0,0 +1,89 @@
/***************************************************************************
The Disc Image Chef
----------------------------------------------------------------------------
Filename : PartPlugin.cs
Version : 1.0
Author(s) : Natalia Portillo
Component : Partitioning scheme plugins
Revision : $Revision$
Last change by : $Author$
Date : $Date$
--[ Description ] ----------------------------------------------------------
Defines functions to be used by partitioning scheme 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;
using System.Collections.Generic;
namespace DiscImageChef.PartPlugins
{
/// <summary>
/// Abstract class to implement partitioning schemes interpreting plugins.
/// </summary>
public abstract class PartPlugin
{
/// <summary>Plugin name.</summary>
public string Name;
/// <summary>Plugin UUID.</summary>
public Guid PluginUUID;
protected PartPlugin()
{
}
/// <summary>
/// Interprets a partitioning scheme.
/// </summary>
/// <returns><c>true</c>, if partitioning scheme is recognized, <c>false</c> otherwise.</returns>
/// <param name="imagePlugin">Disk image.</param>
/// <param name="partitions">Returns list of partitions.</param>
public abstract bool GetInformation(ImagePlugins.ImagePlugin imagePlugin, out List<Partition> partitions);
}
/// <summary>
/// Partition structure.
/// </summary>
public struct Partition
{
/// <summary>Partition number, 0-started</summary>
public ulong PartitionSequence;
/// <summary>Partition type</summary>
public string PartitionType;
/// <summary>Partition name (if the scheme supports it)</summary>
public string PartitionName;
/// <summary>Start of the partition, in bytes</summary>
public ulong PartitionStart;
/// <summary>LBA of partition start</summary>
public ulong PartitionStartSector;
/// <summary>Length in bytes of the partition</summary>
public ulong PartitionLength;
/// <summary>Length in sectors of the partition</summary>
public ulong PartitionSectors;
/// <summary>Information that does not find space in this struct</summary>
public string PartitionDescription;
}
}

118
DiscImageChef/Plugins.cs Normal file
View File

@@ -0,0 +1,118 @@
/***************************************************************************
The Disc Image Chef
----------------------------------------------------------------------------
Filename : Plugins.cs
Version : 1.0
Author(s) : Natalia Portillo
Component : Plugins
Revision : $Revision$
Last change by : $Author$
Date : $Date$
--[ Description ] ----------------------------------------------------------
Base methods for plugins.
--[ 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.Collections.Generic;
using System.Reflection;
using DiscImageChef.ImagePlugins;
using DiscImageChef.PartPlugins;
using DiscImageChef.Plugins;
namespace DiscImageChef
{
public class PluginBase
{
public Dictionary<string, Plugin> PluginsList;
public Dictionary<string, PartPlugin> PartPluginsList;
public Dictionary<string, ImagePlugin> ImagePluginsList;
public PluginBase()
{
PluginsList = new Dictionary<string, Plugin>();
PartPluginsList = new Dictionary<string, PartPlugin>();
ImagePluginsList = new Dictionary<string, ImagePlugin>();
}
public void RegisterAllPlugins()
{
Assembly assembly = Assembly.GetExecutingAssembly();
foreach (Type type in assembly.GetTypes())
{
try
{
if (type.IsSubclassOf(typeof(ImagePlugin)))
{
ImagePlugin plugin = (ImagePlugin)type.GetConstructor(new [] { typeof(PluginBase) }).Invoke(new object[] { this });
RegisterImagePlugin(plugin);
}
if (type.IsSubclassOf(typeof(Plugin)))
{
Plugin plugin = (Plugin)type.GetConstructor(new [] { typeof(PluginBase) }).Invoke(new object[] { this });
RegisterPlugin(plugin);
}
else if (type.IsSubclassOf(typeof(PartPlugin)))
{
PartPlugin partplugin = (PartPlugin)type.GetConstructor(new [] { typeof(PluginBase) }).Invoke(new object[] { this });
RegisterPartPlugin(partplugin);
}
}
catch (Exception exception)
{
Console.WriteLine(exception);
}
}
}
void RegisterImagePlugin(ImagePlugin plugin)
{
if (!ImagePluginsList.ContainsKey(plugin.Name.ToLower()))
{
ImagePluginsList.Add(plugin.Name.ToLower(), plugin);
}
}
void RegisterPlugin(Plugin plugin)
{
if (!PluginsList.ContainsKey(plugin.Name.ToLower()))
{
PluginsList.Add(plugin.Name.ToLower(), plugin);
}
}
void RegisterPartPlugin(PartPlugin partplugin)
{
if (!PartPluginsList.ContainsKey(partplugin.Name.ToLower()))
{
PartPluginsList.Add(partplugin.Name.ToLower(), partplugin);
}
}
}
}

View File

@@ -0,0 +1,415 @@
/***************************************************************************
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 partitionOffset)
{
byte[] mdb_sector = imagePlugin.ReadSector(2 + partitionOffset);
UInt16 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 partitionOffset, 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 = imagePlugin.ReadSector(2 + partitionOffset); // BB's first sector
byte[] mdb_sector = imagePlugin.ReadSector(2 + partitionOffset); // MDB sector
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();
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;
}
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

@@ -0,0 +1,529 @@
/***************************************************************************
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 partitionOffset)
{
UInt16 drSigWord;
UInt16 xdrStABNt;
UInt16 drAlBlSt;
UInt32 drAlBlkSiz;
byte[] vh_sector;
ulong hfsp_offset;
vh_sector = imagePlugin.ReadSector(2 + partitionOffset); // 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 + partitionOffset + 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 partitionOffset, 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 + partitionOffset); // 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 + partitionOffset + 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

@@ -0,0 +1,272 @@
/***************************************************************************
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 partitionOffset)
{
UInt16 drSigWord;
byte[] mdb_sector = imagePlugin.ReadSector(2 + partitionOffset);
drSigWord = BigEndianBitConverter.ToUInt16(mdb_sector, 0x000);
return drSigWord == MFS_MAGIC;
}
public override void GetInformation(ImagePlugins.ImagePlugin imagePlugin, ulong partitionOffset, 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 + partitionOffset);
byte[] bb_sector = imagePlugin.ReadSector(0 + partitionOffset);
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

@@ -0,0 +1,251 @@
/***************************************************************************
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 partitionOffset)
{
UInt32 magic;
UInt32 magic_be;
byte[] sb_sector = imagePlugin.ReadSector(0 + partitionOffset);
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 + partitionOffset);
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 partitionOffset, out string information)
{
information = "";
byte[] name_bytes = new byte[32];
StringBuilder sb = new StringBuilder();
BeSuperBlock besb = new BeSuperBlock();
byte[] sb_sector = imagePlugin.ReadSector(0 + partitionOffset);
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 + partitionOffset);
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

@@ -0,0 +1,463 @@
/***************************************************************************
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 partitionOffset)
{
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 + partitionOffset);
byte[] fat_sector = imagePlugin.ReadSector(1 + partitionOffset);
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 + partitionOffset))
fat_sector = imagePlugin.ReadSector(rsectors + partitionOffset); // 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 + partitionOffset);
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 partitionOffset, 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 + partitionOffset);
byte[] fat_sector = imagePlugin.ReadSector(1 + partitionOffset);
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 + partitionOffset))
fat_sector = imagePlugin.ReadSector(rsectors + partitionOffset); // 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>
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;
}
}
}

1071
DiscImageChef/Plugins/FFS.cs Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,379 @@
/***************************************************************************
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 partitionOffset)
{
UInt32 magic1, magic2;
byte[] hpfs_sb_sector = imagePlugin.ReadSector(16 + partitionOffset); // 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 partitionOffset, 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 + partitionOffset); // Seek to BIOS parameter block, on logical sector 0
byte[] hpfs_sb_sector = imagePlugin.ReadSector(16 + partitionOffset); // Seek to superblock, on logical sector 16
byte[] hpfs_sp_sector = imagePlugin.ReadSector(17 + partitionOffset); // 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

@@ -0,0 +1,899 @@
/***************************************************************************
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 partitionOffset)
{
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)
return false;
// Read to Volume Descriptor
byte[] vd_sector = imagePlugin.ReadSector(16 + partitionOffset);
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 partitionOffset, 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)
{
// Seek to Volume Descriptor
byte[] vd_sector = imagePlugin.ReadSector(16 + counter + partitionOffset);
VDType = vd_sector[0];
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);
byte[] path_table = imagePlugin.ReadSector(i + partitionOffset);
Array.Copy(path_table, 2, RootDirectoryLocation, 0, 4);
// Check for Rock Ridge
byte[] root_dir = imagePlugin.ReadSector((ulong)BitConverter.ToInt32(RootDirectoryLocation, 0) + partitionOffset);
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 + partitionOffset);
Array.Copy(ipbin_sector, 0x000, SegaHardwareID, 0, 16);
switch (Encoding.ASCII.GetString(SegaHardwareID))
{
case "SEGADISCSYSTEM ":
case "SEGADATADISC ":
case "SEGAOS ":
{
SegaCD = true; // Ok, this contains 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
// 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;
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
// 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;
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[4]; // 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
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, 4); // Supported peripherals, bitwise
Array.Copy(ipbin_sector, 0x03C, product_no, 0, 10); // Product number
Array.Copy(ipbin_sector, 0x046, product_version, 0, 6); // Product version
Array.Copy(ipbin_sector, 0x04C, release_date, 0, 8); // YYYYMMDD
Array.Copy(ipbin_sector, 0x054, spare_space3, 0, 8); // " "
Array.Copy(ipbin_sector, 0x05C, boot_filename, 0, 12); // Usually "1ST_READ.BIN" or "0WINCE.BIN "
Array.Copy(ipbin_sector, 0x068, producer, 0, 16); // Game producer, space-filled
Array.Copy(ipbin_sector, 0x078, product_name, 0, 128); // Game name, space-filled
// 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 = BitConverter.ToInt32(peripherals, 0);
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

@@ -0,0 +1,572 @@
/***************************************************************************
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 partitionOffset)
{
try
{
// 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 partitionOffset, out string information)
{
information = "";
StringBuilder sb = new StringBuilder();
try
{
// 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

@@ -0,0 +1,283 @@
/***************************************************************************
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 partitionOffset)
{
UInt16 magic;
byte[] minix_sb_sector = imagePlugin.ReadSector(2 + partitionOffset);
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 partitionOffset, out string information)
{
information = "";
StringBuilder sb = new StringBuilder();
bool minix3 = false;
int filenamesize;
string minixVersion;
UInt16 magic;
byte[] minix_sb_sector = imagePlugin.ReadSector(2 + partitionOffset);
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

@@ -0,0 +1,238 @@
/***************************************************************************
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 partitionOffset)
{
byte[] eigth_bytes = new byte[8];
byte signature1, fats_no;
UInt16 spfat, signature2;
string oem_name;
byte[] ntfs_bpb = imagePlugin.ReadSector(0 + partitionOffset);
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 partitionOffset, out string information)
{
information = "";
StringBuilder sb = new StringBuilder();
byte[] ntfs_bpb = imagePlugin.ReadSector(0 + partitionOffset);
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

@@ -0,0 +1,356 @@
/***************************************************************************
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 partitionOffset)
{
if (imagePlugin.GetSectorSize() < 512)
return false;
byte[] magic_b = new byte[12];
string magic;
byte[] hb_sector = imagePlugin.ReadSector(1 + partitionOffset);
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 partitionOffset, 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 + partitionOffset);
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

@@ -0,0 +1,163 @@
/***************************************************************************
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 partitionOffset)
{
byte[] sb_sector = imagePlugin.ReadSector(0 + partitionOffset);
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 partitionOffset, out string information)
{
information = "";
StringBuilder SuperBlockMetadata = new StringBuilder();
byte[] sb_sector = imagePlugin.ReadSector(0 + partitionOffset);
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

@@ -0,0 +1,68 @@
/***************************************************************************
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 partitionOffset)
{
byte[] system_descriptor = new byte[23];
byte[] sector = imagePlugin.ReadSector(1 + partitionOffset);
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 partitionOffset, out string information)
{
information = "";
}
}
}

View File

@@ -0,0 +1,74 @@
/***************************************************************************
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="partitionOffset">Partition offset (LBA).</param>
/// <returns><c>true</c>, if the filesystem is recognized, <c>false</c> otherwise.</returns>
public abstract bool Identify(ImagePlugins.ImagePlugin imagePlugin, ulong partitionOffset);
/// <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 partitionOffset, out string information);
}
}

View File

@@ -0,0 +1,188 @@
/***************************************************************************
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 partitionOffset)
{
byte signature; // 0x29
string fs_type; // "SOL_FS "
byte[] bpb = imagePlugin.ReadSector(0 + partitionOffset);
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 partitionOffset, out string information)
{
information = "";
StringBuilder sb = new StringBuilder();
byte[] bpb_sector = imagePlugin.ReadSector(0 + partitionOffset);
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

@@ -0,0 +1,373 @@
/***************************************************************************
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

@@ -0,0 +1,809 @@
/***************************************************************************
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 partitionOffset)
{
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() <= (partitionOffset + 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 + partitionOffset, 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 partitionOffset, 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 + partitionOffset, 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 + partitionOffset, 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 + partitionOffset, 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 + partitionOffset, 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 + partitionOffset, 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

@@ -0,0 +1,130 @@
/***************************************************************************
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 partitionOffset)
{
UInt32 magic;
magic = BitConverter.ToUInt32(imagePlugin.ReadSector(0 + partitionOffset), 0);
return magic == BFS_MAGIC;
}
public override void GetInformation(ImagePlugins.ImagePlugin imagePlugin, ulong partitionOffset, out string information)
{
information = "";
StringBuilder sb = new StringBuilder();
byte[] bfs_sb_sector = imagePlugin.ReadSector(0 + partitionOffset);
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

@@ -0,0 +1,875 @@
/***************************************************************************
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 partitionOffset)
{
byte[] sb_sector = imagePlugin.ReadSector(2 + partitionOffset);
UInt16 magic = BitConverter.ToUInt16(sb_sector, 0x038);
if (magic == ext2FSMagic || magic == ext2OldFSMagic)
return true;
return false;
}
public override void GetInformation(ImagePlugins.ImagePlugin imagePlugin, ulong partitionOffset, 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 + partitionOffset, 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

@@ -0,0 +1,131 @@
/***************************************************************************
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 partitionOffset)
{
byte[] sb_sector = imagePlugin.ReadSector(2 + partitionOffset); // 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 partitionOffset, out string information)
{
information = "";
StringBuilder sb = new StringBuilder();
byte[] sb_sector = imagePlugin.ReadSector(2 + partitionOffset); // 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)
}
}
}

84
DiscImageChef/PrintHex.cs Normal file
View File

@@ -0,0 +1,84 @@
/***************************************************************************
The Disc Image Chef
----------------------------------------------------------------------------
Filename : PrintHex.cs
Version : 1.0
Author(s) : Natalia Portillo
Component : Helpers
Revision : $Revision$
Last change by : $Author$
Date : $Date$
--[ Description ] ----------------------------------------------------------
Prints a byte array as hexadecimal in console.
--[ 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
{
public static class PrintHex
{
public static void PrintHexArray(byte[] array, int width)
{
int counter = 0;
int subcounter = 0;
for (long i = 0; i < array.LongLength; i++)
{
if (counter == 0)
{
Console.WriteLine();
Console.Write("{0:X16} ", i);
}
else
{
if (subcounter == 3 )
{
Console.Write(" ");
subcounter = 0;
}
else
{
Console.Write(" ");
subcounter++;
}
}
Console.Write("{0:X2}", array[i]);
if (counter == width - 1)
{
counter = 0;
subcounter = 0;
}
else
counter++;
}
Console.WriteLine();
Console.WriteLine();
}
}
}

33
DiscImageChef/README.md Normal file
View File

@@ -0,0 +1,33 @@
DiscImageChef v1.10
===================
Filesystem identifier and checker.
Copyright © 2011-2014 Natalia Portillo <claunia@claunia.com>
Usage
=====
DiscImageChef.exe
And read help.
Works under any operating system where there is Mono or .NET Framework. Tested with Mono 2.0.
Features
========
* Supports reading CDRWin cue/bin cuesheets, Apple DiskCopy 4.2 and TeleDisk disk images.
* Supports reading all raw (sector by sector copy) disk images with a multiple of 512 bytes/sector, and a few known formats that are 256, 128 and variable bytes per sector.
* Supports traversing MBR, Apple and NeXT partitioning schemes.
* Identifies HFS, HFS+, MFS, BeFS, ext/2/3/4, FAT12/16/32, FFS/UFS/UFS2, HPFS, ISO9660, LisaFS, MinixFS, NTFS, ODS11, Opera, PCEngine, SolarFS, System V and UnixWare boot filesystem.
Changelog
=========
See Changelog file.
To-Do
=====
See TODO file.

View File

@@ -0,0 +1,76 @@
/***************************************************************************
The Disc Image Chef
----------------------------------------------------------------------------
Filename : StringHandlers.cs
Version : 1.0
Author(s) : Natalia Portillo
Component : Program tools
Revision : $Revision$
Last change by : $Author$
Date : $Date$
--[ Description ] ----------------------------------------------------------
Convert byte arrays to C# strings.
--[ 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;
namespace DiscImageChef
{
public static class StringHandlers
{
public static string CToString(byte[] CString)
{
StringBuilder sb = new StringBuilder();
for (int i = 0; i < CString.Length; i++)
{
if (CString[i] == 0)
break;
sb.Append(Encoding.ASCII.GetString(CString, i, 1));
}
return sb.ToString();
}
public static string PascalToString(byte[] PascalString)
{
StringBuilder sb = new StringBuilder();
byte length = PascalString[0];
for (int i = 1; i < length + 1; i++)
{
sb.Append(Encoding.ASCII.GetString(PascalString, i, 1));
}
return sb.ToString();
}
}
}

111
DiscImageChef/Swapping.cs Normal file
View File

@@ -0,0 +1,111 @@
/***************************************************************************
The Disc Image Chef
----------------------------------------------------------------------------
Filename : Swapping.cs
Version : 1.0
Author(s) : Natalia Portillo
Component : Program tools
Revision : $Revision$
Last change by : $Author$
Date : $Date$
--[ Description ] ----------------------------------------------------------
Byte-swapping methods
--[ 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
{
static class Swapping
{
public static byte[] SwapTenBytes(byte[] source)
{
byte[] destination = new byte[8];
destination[0] = source[9];
destination[1] = source[8];
destination[2] = source[7];
destination[3] = source[6];
destination[4] = source[5];
destination[5] = source[4];
destination[6] = source[3];
destination[7] = source[2];
destination[8] = source[1];
destination[9] = source[0];
return destination;
}
public static byte[] SwapEightBytes(byte[] source)
{
byte[] destination = new byte[8];
destination[0] = source[7];
destination[1] = source[6];
destination[2] = source[5];
destination[3] = source[4];
destination[4] = source[3];
destination[5] = source[2];
destination[6] = source[1];
destination[7] = source[0];
return destination;
}
public static byte[] SwapFourBytes(byte[] source)
{
byte[] destination = new byte[4];
destination[0] = source[3];
destination[1] = source[2];
destination[2] = source[1];
destination[3] = source[0];
return destination;
}
public static byte[] SwapTwoBytes(byte[] source)
{
byte[] destination = new byte[2];
destination[0] = source[1];
destination[1] = source[0];
return destination;
}
public static UInt32 PDPFromLittleEndian(UInt32 x)
{
return ((x & 0xffff) << 16) | ((x & 0xffff0000) >> 16);
}
public static UInt32 PDPFromBigEndian(UInt32 x)
{
return ((x & 0xff00ff) << 8) | ((x & 0xff00ff00) >> 8);
}
}
}

71
DiscImageChef/TODO Normal file
View File

@@ -0,0 +1,71 @@
Disc image plugins:
--- Add support for BlindWrite images
--- Add support for CloneCD images
--- Add support for DiscJuggler images
--- Add support for Alcohol images
--- Add support for Nero images
--- Add support for cdrdao images
--- Add support for dump(8) images
--- Add support for IMD images
--- Add support for Kryoflux images
--- Add support for DiscFerret images
--- Add support for MAME CHDs
--- Add support for Apple NDIF images
--- Add support for Apple UDIF images
--- Add support for XPACK images
--- Add support for QEMU QCOW and QCOW2 images
--- Add support for VHD and VHDX images
--- Add support for VirtualBox images
--- Add support for VMWare images
--- Add support foe QEMU QED images
Filesystem plugins:
--- Add support for AmigaOS filesystems
--- Add support for SFS filesystem
--- Add support for PFS3 filesystem
--- Add support for Acorn filesystems
--- Add support for Apple DOS filesystems
--- Add support for Apple ProDOS filesystem
--- Add support for UCSD/Pascal filesystem
--- Add support for AMSDOS filesystem
--- Add support for CP/M filesystem
--- Add support for CBM filesystem
--- Add support for btrfs
--- Add support for ZFS
--- Add support for UDF
--- Add support for CramFS
--- Add support for VxFS
--- Add support for VMWare filesystem
--- Add support for NwFS
--- Add support for JFS
--- Add support for Reiser filesystems
--- Add support for QNX filesystems
--- Add support for Squashfs
--- Add support for X-Box filesystems
--- Add support for exFAT
--- Add support for FAT+
--- Add support for ReFS
--- Add support for ECMA-67
Partitioning scheme plugins:
--- Add support for Acorn partitions
--- Add support for Amiga's RDB
--- Add support for Atari partitions
--- Add support for AIX partitions
--- Add support for EFI GPT
--- Add support for SGI partitions
--- Add support for Sun partitions
--- Add support for Ultrix partitions
Things to test/debug:
--- After moving to disc images, HFS CDs with 512 bytes/sector are not detected anymore
Other things:
--- Surprise!
Teledisk plugin:
--- Add support for "advanced compression"
--- Handle variable sectors per track situation. Teledisk seems to be able to read garbage from previous formattings.
RAW plugin:
--- Finish support for reading sectors of variable bytes/sector images