diff --git a/FileSystemIDandChk/BigEndianBitConverter.cs b/FileSystemIDandChk/BigEndianBitConverter.cs new file mode 100644 index 000000000..f93324867 --- /dev/null +++ b/FileSystemIDandChk/BigEndianBitConverter.cs @@ -0,0 +1,572 @@ +using System; +using System.Linq; + +namespace FileSystemIDandChk +{ + /// + /// 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. + /// + public static class BigEndianBitConverter + { + /// + /// Indicates the byte order ("endianess") in which data is stored in this computer + /// architecture. + /// + public static bool IsLittleEndian { get; set; } // should default to false, which is what we want for Empire + + /// + /// 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. + /// + public static long DoubleToInt64Bits(double value) { throw new NotImplementedException(); } + /// + /// + /// Returns the specified Boolean value as an array of bytes. + /// + /// Parameters: + /// value: + /// A Boolean value. + /// + /// Returns: + /// An array of bytes with length 1. + /// + public static byte[] GetBytes(bool value) + { + return !IsLittleEndian ? BitConverter.GetBytes(value) : BitConverter.GetBytes(value).Reverse().ToArray(); + } + /// + /// + /// 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. + /// + public static byte[] GetBytes(char value) + { + return !IsLittleEndian ? BitConverter.GetBytes(value) : BitConverter.GetBytes(value).Reverse().ToArray(); + } + /// + /// + /// 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. + /// + public static byte[] GetBytes(double value) + { + return !IsLittleEndian ? BitConverter.GetBytes(value) : BitConverter.GetBytes(value).Reverse().ToArray(); + } + /// + /// + /// 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. + /// + public static byte[] GetBytes(float value) + { + return !IsLittleEndian ? BitConverter.GetBytes(value) : BitConverter.GetBytes(value).Reverse().ToArray(); + } + /// + /// + /// 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. + /// + public static byte[] GetBytes(int value) + { + return !IsLittleEndian ? BitConverter.GetBytes(value) : BitConverter.GetBytes(value).Reverse().ToArray(); + } + /// + /// + /// 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. + /// + public static byte[] GetBytes(long value) + { + return !IsLittleEndian ? BitConverter.GetBytes(value) : BitConverter.GetBytes(value).Reverse().ToArray(); + } + /// + /// + /// 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. + /// + public static byte[] GetBytes(short value) + { + return !IsLittleEndian ? BitConverter.GetBytes(value) : BitConverter.GetBytes(value).Reverse().ToArray(); + } + /// + /// + /// 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. + /// + [CLSCompliant(false)] + public static byte[] GetBytes(uint value) + { + return !IsLittleEndian ? BitConverter.GetBytes(value) : BitConverter.GetBytes(value).Reverse().ToArray(); + } + /// + /// + /// 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. + /// + [CLSCompliant(false)] + public static byte[] GetBytes(ulong value) + { + return !IsLittleEndian ? BitConverter.GetBytes(value) : BitConverter.GetBytes(value).Reverse().ToArray(); + } + /// + /// + /// 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. + /// + public static byte[] GetBytes(ushort value) + { + return !IsLittleEndian ? BitConverter.GetBytes(value) : BitConverter.GetBytes(value).Reverse().ToArray(); + } + /// + /// + /// 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. + /// + public static double Int64BitsToDouble(long value) { throw new NotImplementedException(); } + /// + /// + /// 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. + /// + public static bool ToBoolean(byte[] value, int startIndex) { throw new NotImplementedException(); } + /// + /// + /// 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. + /// + public static char ToChar(byte[] value, int startIndex) { throw new NotImplementedException(); } + /// + /// + /// 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. + /// + public static double ToDouble(byte[] value, int startIndex) { throw new NotImplementedException(); } + /// + /// + /// 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. + /// + public static short ToInt16(byte[] value, int startIndex) + { + return !IsLittleEndian ? BitConverter.ToInt16(value, startIndex) : BitConverter.ToInt16(value.Reverse().ToArray(), value.Length - sizeof(Int16) - startIndex); + } + /// + /// + /// 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. + /// + public static int ToInt32(byte[] value, int startIndex) + { + return !IsLittleEndian ? BitConverter.ToInt32(value, startIndex) : BitConverter.ToInt32(value.Reverse().ToArray(), value.Length - sizeof(Int32) - startIndex); + } + /// + /// + /// 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. + /// + public static long ToInt64(byte[] value, int startIndex) + { + return !IsLittleEndian ? BitConverter.ToInt64(value, startIndex) : BitConverter.ToInt64(value.Reverse().ToArray(), value.Length - sizeof(Int64) - startIndex); + } + /// + /// + /// 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. + /// + public static float ToSingle(byte[] value, int startIndex) + { + return !IsLittleEndian ? BitConverter.ToSingle(value, startIndex) : BitConverter.ToSingle(value.Reverse().ToArray(), value.Length - sizeof(Single) - startIndex); + } + /// + /// + /// 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. + /// + public static string ToString(byte[] value) + { + return !IsLittleEndian ? BitConverter.ToString(value) : BitConverter.ToString(value.Reverse().ToArray()); + } + /// + /// + /// 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. + /// + public static string ToString(byte[] value, int startIndex) + { + return !IsLittleEndian ? BitConverter.ToString(value, startIndex) : BitConverter.ToString(value.Reverse().ToArray(), startIndex); + } + /// + /// + /// 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. + /// + public static string ToString(byte[] value, int startIndex, int length) + { + return !IsLittleEndian ? BitConverter.ToString(value, startIndex, length) : BitConverter.ToString(value.Reverse().ToArray(), startIndex, length); + } + /// + /// + /// 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. + /// + public static ushort ToUInt16(byte[] value, int startIndex) + { + return !IsLittleEndian ? BitConverter.ToUInt16(value, startIndex) : BitConverter.ToUInt16(value.Reverse().ToArray(), value.Length - sizeof(UInt16) - startIndex); + } + /// + /// + /// 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. + /// + public static uint ToUInt32(byte[] value, int startIndex) + { + return !IsLittleEndian ? BitConverter.ToUInt32(value, startIndex) : BitConverter.ToUInt32(value.Reverse().ToArray(), value.Length - sizeof(UInt32) - startIndex); + } + /// + /// + /// 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. + /// + public static ulong ToUInt64(byte[] value, int startIndex) + { + return !IsLittleEndian ? BitConverter.ToUInt64(value, startIndex) : BitConverter.ToUInt64(value.Reverse().ToArray(), value.Length - sizeof(UInt64) - startIndex); + } + } +} \ No newline at end of file diff --git a/FileSystemIDandChk/ChangeLog b/FileSystemIDandChk/ChangeLog index 147f5125c..53faac0c5 100644 --- a/FileSystemIDandChk/ChangeLog +++ b/FileSystemIDandChk/ChangeLog @@ -1,3 +1,51 @@ +2014-04-14 Natalia Portillo + + * 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 * Plugins/SysV.cs: diff --git a/FileSystemIDandChk/FileSystemIDandChk.csproj b/FileSystemIDandChk/FileSystemIDandChk.csproj index a7311deb0..cf98534c7 100644 --- a/FileSystemIDandChk/FileSystemIDandChk.csproj +++ b/FileSystemIDandChk/FileSystemIDandChk.csproj @@ -69,6 +69,7 @@ + @@ -83,7 +84,7 @@ - + diff --git a/FileSystemIDandChk/ImagePlugins/CDRWin.cs b/FileSystemIDandChk/ImagePlugins/CDRWin.cs index 6dbc5613d..bcb04fb22 100644 --- a/FileSystemIDandChk/ImagePlugins/CDRWin.cs +++ b/FileSystemIDandChk/ImagePlugins/CDRWin.cs @@ -9,153 +9,251 @@ namespace FileSystemIDandChk.ImagePlugins { class CDRWin : ImagePlugin { -#region Internal structures - private struct CDRWinTrackFile + #region Internal structures + + struct CDRWinTrackFile { - public UInt32 sequence; // Track # - public string datafile; // Path of file containing track - public UInt64 offset; // Offset of track start in file - public string filetype; // Type of file + public UInt32 sequence; + // Track # + public string datafile; + // Path of file containing track + public UInt64 offset; + // Offset of track start in file + public string filetype; + // Type of file } - private struct CDRWinTrack + struct CDRWinTrack { - public UInt32 sequence; // Track # - public string title; // Track title (from CD-Text) - public string genre; // Track genre (from CD-Text) - public string arranger; // Track arranger (from CD-Text) - public string composer; // Track composer (from CD-Text) - public string performer; // Track performer (from CD-Text) - public string songwriter; // Track song writer (from CD-Text) - public string isrc; // Track ISRC - public CDRWinTrackFile trackfile; // File struct for this track - public List indexes; // Indexes on this track - public UInt32 pregap; // Track pre-gap in sectors - public UInt32 postgap; // Track post-gap in sectors - public bool flag_dcp; // Digical Copy Permitted - public bool flag_4ch; // Track is quadraphonic - public bool flag_pre; // Track has preemphasis - public bool flag_scms; // Track has SCMS - } -#endregion - - private struct CDRWinDisc - { - public string title; // Disk title (from CD-Text) - public string genre; // Disk genre (from CD-Text) - public string arranger; // Disk arranger (from CD-Text) - public string composer; // Disk composer (from CD-Text) - public string performer; // Disk performer (from CD-Text) - public string songwriter; // Disk song writer (from CD-Text) - public string mcn; // Media catalog number - public DiskType disktype; // Disk type - public string disktypestr; // Disk type string - public string disk_id; // Disk CDDB ID - public string barcode; // Disk UPC/EAN - public List sessions; // Sessions - public List tracks; // Tracks - public string comment; // Disk comment - public string cdtextfile; // File containing CD-Text + public UInt32 sequence; + // Track # + public string title; + // Track title (from CD-Text) + public string genre; + // Track genre (from CD-Text) + public string arranger; + // Track arranger (from CD-Text) + public string composer; + // Track composer (from CD-Text) + public string performer; + // Track performer (from CD-Text) + public string songwriter; + // Track song writer (from CD-Text) + public string isrc; + // Track ISRC + public CDRWinTrackFile trackfile; + // File struct for this track + public Dictionary indexes; + // Indexes on this track + public UInt64 pregap; + // Track pre-gap in sectors + public UInt64 postgap; + // Track post-gap in sectors + public bool flag_dcp; + // Digical Copy Permitted + public bool flag_4ch; + // Track is quadraphonic + public bool flag_pre; + // Track has preemphasis + public bool flag_scms; + // Track has SCMS + public UInt16 bps; + // Bytes per sector + public UInt64 sectors; + // Sectors in track + public string tracktype; + // Track type + public UInt16 session; + // Track session } -#region Internal consts + #endregion + + struct CDRWinDisc + { + public string title; + // Disk title (from CD-Text) + public string genre; + // Disk genre (from CD-Text) + public string arranger; + // Disk arranger (from CD-Text) + public string composer; + // Disk composer (from CD-Text) + public string performer; + // Disk performer (from CD-Text) + public string songwriter; + // Disk song writer (from CD-Text) + public string mcn; + // Media catalog number + public DiskType disktype; + // Disk type + public string disktypestr; + // Disk type string + public string disk_id; + // Disk CDDB ID + public string barcode; + // Disk UPC/EAN + public List sessions; + // Sessions + public List tracks; + // Tracks + public string comment; + // Disk comment + public string cdtextfile; + // File containing CD-Text + } + + #region Internal consts + // Type for FILE entity - private const string CDRWinDiskTypeLittleEndian = "BINARY"; // Data as-is in little-endian - private const string CDRWinDiskTypeBigEndian = "MOTOROLA"; // Data as-is in big-endian - private const string CDRWinDiskTypeAIFF = "AIFF"; // Audio in Apple AIF file - private const string CDRWinDiskTypeRIFF = "WAVE"; // Audio in Microsoft WAV file - private const string CDRWinDiskTypeMP3 = "MP3"; // Audio in MP3 file - + const string CDRWinDiskTypeLittleEndian = "BINARY"; + // Data as-is in little-endian + const string CDRWinDiskTypeBigEndian = "MOTOROLA"; + // Data as-is in big-endian + const string CDRWinDiskTypeAIFF = "AIFF"; + // Audio in Apple AIF file + const string CDRWinDiskTypeRIFF = "WAVE"; + // Audio in Microsoft WAV file + const string CDRWinDiskTypeMP3 = "MP3"; + // Audio in MP3 file // Type for TRACK entity - private const string CDRWinTrackTypeAudio = "AUDIO"; // Audio track, 2352 bytes/sector - private const string CDRWinTrackTypeCDG = "CDG"; // CD+G track, 2448 bytes/sector (audio+subchannel) - private const string CDRWinTrackTypeMode1 = "MODE1/2048"; // Mode 1 track, cooked, 2048 bytes/sector - private const string CDRWinTrackTypeMode1Raw = "MODE1/2352"; // Mode 1 track, raw, 2352 bytes/sector - private const string CDRWinTrackTypeMode2Form1 = "MODE2/2048"; // Mode 2 form 1 track, cooked, 2048 bytes/sector - private const string CDRWinTrackTypeMode2Form2 = "MODE2/2324"; // Mode 2 form 2 track, cooked, 2324 bytes/sector - private const string CDRWinTrackTypeMode2Formless = "MODE2/2336"; // Mode 2 formless track, cooked, 2336 bytes/sector - private const string CDRWinTrackTypeMode2Raw = "MODE2/2352"; // Mode 2 track, raw, 2352 bytes/sector - private const string CDRWinTrackTypeCDI = "CDI/2336"; // CD-i track, cooked, 2336 bytes/sector - private const string CDRWinTrackTypeCDIRaw = "CDI/2352"; // CD-i track, raw, 2352 bytes/sector - + const string CDRWinTrackTypeAudio = "AUDIO"; + // Audio track, 2352 bytes/sector + const string CDRWinTrackTypeCDG = "CDG"; + // CD+G track, 2448 bytes/sector (audio+subchannel) + const string CDRWinTrackTypeMode1 = "MODE1/2048"; + // Mode 1 track, cooked, 2048 bytes/sector + const string CDRWinTrackTypeMode1Raw = "MODE1/2352"; + // Mode 1 track, raw, 2352 bytes/sector + const string CDRWinTrackTypeMode2Form1 = "MODE2/2048"; + // Mode 2 form 1 track, cooked, 2048 bytes/sector + const string CDRWinTrackTypeMode2Form2 = "MODE2/2324"; + // Mode 2 form 2 track, cooked, 2324 bytes/sector + const string CDRWinTrackTypeMode2Formless = "MODE2/2336"; + // Mode 2 formless track, cooked, 2336 bytes/sector + const string CDRWinTrackTypeMode2Raw = "MODE2/2352"; + // Mode 2 track, raw, 2352 bytes/sector + const string CDRWinTrackTypeCDI = "CDI/2336"; + // CD-i track, cooked, 2336 bytes/sector + const string CDRWinTrackTypeCDIRaw = "CDI/2352"; + // CD-i track, raw, 2352 bytes/sector // Type for REM ORIGINAL MEDIA-TYPE entity - private const string CDRWinDiskTypeCD = "CD"; // DiskType.CD - private const string CDRWinDiskTypeCDRW = "CD-RW"; // DiskType.CDRW - private const string CDRWinDiskTypeCDMRW = "CD-MRW"; // DiskType.CDMRW - private const string CDRWinDiskTypeCDMRW2 = "CD-(MRW)"; // DiskType.CDMRW - private const string CDRWinDiskTypeDVD = "DVD"; // DiskType.DVDROM - private const string CDRWinDiskTypeDVDPMRW = "DVD+MRW"; // DiskType.DVDPRW - private const string CDRWinDiskTypeDVDPMRW2 = "DVD+(MRW)"; // DiskType.DVDPRW - private const string CDRWinDiskTypeDVDPMRWDL = "DVD+MRW DL"; // DiskType.DVDPRWDL - private const string CDRWinDiskTypeDVDPMRWDL2 = "DVD+(MRW) DL"; // DiskType.DVDPRWDL - private const string CDRWinDiskTypeDVDPR = "DVD+R"; // DiskType.DVDPR - private const string CDRWinDiskTypeDVDPRDL = "DVD+R DL"; // DiskType.DVDPRDL - private const string CDRWinDiskTypeDVDPRW = "DVD+RW"; // DiskType.DVDPRW - private const string CDRWinDiskTypeDVDPRWDL = "DVD+RW DL"; // DiskType.DVDPRWDL - private const string CDRWinDiskTypeDVDPVR = "DVD+VR"; // DiskType.DVDPR - private const string CDRWinDiskTypeDVDRAM = "DVD-RAM"; // DiskType.DVDRAM - private const string CDRWinDiskTypeDVDR = "DVD-R"; // DiskType.DVDR - private const string CDRWinDiskTypeDVDRDL = "DVD-R DL"; // DiskType.DVDRDL - private const string CDRWinDiskTypeDVDRW = "DVD-RW"; // DiskType.DVDRW - private const string CDRWinDiskTypeDVDRWDL = "DVD-RW DL"; // DiskType.DVDRWDL - private const string CDRWinDiskTypeDVDVR = "DVD-VR"; // DiskType.DVDR - private const string CDRWinDiskTypeDVDRW2 = "DVDRW"; // DiskType.DVDRW - private const string CDRWinDiskTypeHDDVD = "HD DVD"; // DiskType.HDDVDROM - private const string CDRWinDiskTypeHDDVDRAM = "HD DVD-RAM"; // DiskType.HDDVDRAM - private const string CDRWinDiskTypeHDDVDR = "HD DVD-R"; // DiskType.HDDVDR - private const string CDRWinDiskTypeHDDVDRDL = "HD DVD-R DL"; // DiskType.HDDVDR - private const string CDRWinDiskTypeHDDVDRW = "HD DVD-RW"; // DiskType.HDDVDRW - private const string CDRWinDiskTypeHDDVDRWDL = "HD DVD-RW DL"; // DiskType.HDDVDRW - private const string CDRWinDiskTypeBD = "BD"; // DiskType.BDROM - private const string CDRWinDiskTypeBDR = "BD-R"; // DiskType.BDR - private const string CDRWinDiskTypeBDRE = "BD-RE"; // DiskType.BDRE - private const string CDRWinDiskTypeBDRDL = "BD-R DL"; // DiskType.BDR - private const string CDRWinDiskTypeBDREDL = "BD-RE DL"; // DiskType.BDRE + const string CDRWinDiskTypeCD = "CD"; + // DiskType.CD + const string CDRWinDiskTypeCDRW = "CD-RW"; + // DiskType.CDRW + const string CDRWinDiskTypeCDMRW = "CD-MRW"; + // DiskType.CDMRW + const string CDRWinDiskTypeCDMRW2 = "CD-(MRW)"; + // DiskType.CDMRW + const string CDRWinDiskTypeDVD = "DVD"; + // DiskType.DVDROM + const string CDRWinDiskTypeDVDPMRW = "DVD+MRW"; + // DiskType.DVDPRW + const string CDRWinDiskTypeDVDPMRW2 = "DVD+(MRW)"; + // DiskType.DVDPRW + const string CDRWinDiskTypeDVDPMRWDL = "DVD+MRW DL"; + // DiskType.DVDPRWDL + const string CDRWinDiskTypeDVDPMRWDL2 = "DVD+(MRW) DL"; + // DiskType.DVDPRWDL + const string CDRWinDiskTypeDVDPR = "DVD+R"; + // DiskType.DVDPR + const string CDRWinDiskTypeDVDPRDL = "DVD+R DL"; + // DiskType.DVDPRDL + const string CDRWinDiskTypeDVDPRW = "DVD+RW"; + // DiskType.DVDPRW + const string CDRWinDiskTypeDVDPRWDL = "DVD+RW DL"; + // DiskType.DVDPRWDL + const string CDRWinDiskTypeDVDPVR = "DVD+VR"; + // DiskType.DVDPR + const string CDRWinDiskTypeDVDRAM = "DVD-RAM"; + // DiskType.DVDRAM + const string CDRWinDiskTypeDVDR = "DVD-R"; + // DiskType.DVDR + const string CDRWinDiskTypeDVDRDL = "DVD-R DL"; + // DiskType.DVDRDL + const string CDRWinDiskTypeDVDRW = "DVD-RW"; + // DiskType.DVDRW + const string CDRWinDiskTypeDVDRWDL = "DVD-RW DL"; + // DiskType.DVDRWDL + const string CDRWinDiskTypeDVDVR = "DVD-VR"; + // DiskType.DVDR + const string CDRWinDiskTypeDVDRW2 = "DVDRW"; + // DiskType.DVDRW + const string CDRWinDiskTypeHDDVD = "HD DVD"; + // DiskType.HDDVDROM + const string CDRWinDiskTypeHDDVDRAM = "HD DVD-RAM"; + // DiskType.HDDVDRAM + const string CDRWinDiskTypeHDDVDR = "HD DVD-R"; + // DiskType.HDDVDR + const string CDRWinDiskTypeHDDVDRDL = "HD DVD-R DL"; + // DiskType.HDDVDR + const string CDRWinDiskTypeHDDVDRW = "HD DVD-RW"; + // DiskType.HDDVDRW + const string CDRWinDiskTypeHDDVDRWDL = "HD DVD-RW DL"; + // DiskType.HDDVDRW + const string CDRWinDiskTypeBD = "BD"; + // DiskType.BDROM + const string CDRWinDiskTypeBDR = "BD-R"; + // DiskType.BDR + const string CDRWinDiskTypeBDRE = "BD-RE"; + // DiskType.BDRE + const string CDRWinDiskTypeBDRDL = "BD-R DL"; + // DiskType.BDR + const string CDRWinDiskTypeBDREDL = "BD-RE DL"; + // DiskType.BDRE -#endregion + #endregion -#region Internal variables - private bool initialized; - private string imagePath; - private StreamReader cueStream; - private FileStream imageStream; - private Dictionary trackFiles; // Dictionary, index is track #, value is TrackFile - private CDRWinDisc discimage; -#endregion + #region Internal variables -#region Parsing regexs - private const string SessionRegEx = "REM\\s+SESSION\\s+(?\\d+)$"; - private const string DiskTypeRegEx = "REM\\s+ORIGINAL MEDIA-TYPE:\\s+(?.+)$"; - private const string LeadOutRegEx = "REM\\s+LEAD-OUT\\s+(?[\\d]+:[\\d]+:[\\d]+)$"; - private const string LBARegEx = "REM MSF:\\s+(?[\\d]+:[\\d]+:[\\d]+)\\s+=\\s+LBA:\\s+(?[\\d]+)$"; // Not checked - private const string DiskIDRegEx = "DISC_ID\\s+(?[\\da-f]{8})$"; - private const string BarCodeRegEx = "UPC_EAN\\s+(?[\\d]{12,13})$"; - private const string CommentRegEx = "REM\\s+(?.+)$"; - private const string CDTextRegEx = "CDTEXTFILE\\s+(?.+)$"; - private const string MCNRegEx = "CATALOG\\s+(?\\d{13})$"; - private const string TitleRegEx = "TITLE\\s+(?.+)$"; - private const string GenreRegEx = "GENRE\\s+(?<genre>.+)$"; - private const string ArrangerRegEx = "ARRANGER\\s+(?<arranger>.+)$"; - private const string ComposerRegEx = "COMPOSER\\s+(?<composer>.+)$"; - private const string PerformerRegEx = "PERFORMER\\s+(?<performer>.+)$"; - private const string SongWriterRegEx = "SONGWRITER\\s+(?<songwriter>.+)$"; - private const string FileRegEx = "FILE\\s+(?<filename>.+)\\s+(?<type>\\S+)$"; - private const string TrackRegEx = "TRACK\\s+(?<number>\\d+)\\s+(?<type>\\S+)$"; - private const string ISRCRegEx = "ISRC\\s+(?<isrc>\\w{12})$"; - private const string IndexRegEx = "INDEX\\s+(?<index>\\d+)\\s+(?<msf>[\\d]+:[\\d]+:[\\d]+)$"; - private const string PregapRegEx = "PREGAP\\s+(?<msf>[\\d]+:[\\d]+:[\\d]+)$"; - private const string PostgapRegex = "POSTGAP\\s+(?<msf>[\\d]+:[\\d]+:[\\d]+)$"; - private const string FlagsRegEx = "FLAGS\\s+(((?<dcp>DCP)|(?<quad>4CH)|(?<pre>PRE)|(?<scms>SCMS))\\s*)+$"; -#endregion + bool initialized; + string imagePath; + StreamReader cueStream; + FileStream imageStream; + Dictionary<UInt32, UInt64> offsetmap; + // Dictionary, index is track #, value is TrackFile + CDRWinDisc discimage; + List<PartPlugins.Partition> partitions; -#region Methods - public CDRWin (PluginBase Core) + #endregion + + #region Parsing regexs + + const string SessionRegEx = "REM\\s+SESSION\\s+(?<number>\\d+).*$"; + const string DiskTypeRegEx = "REM\\s+ORIGINAL MEDIA-TYPE:\\s+(?<mediatype>.+)$"; + const string LeadOutRegEx = "REM\\s+LEAD-OUT\\s+(?<msf>[\\d]+:[\\d]+:[\\d]+)$"; + const string LBARegEx = "REM MSF:\\s+(?<msf>[\\d]+:[\\d]+:[\\d]+)\\s+=\\s+LBA:\\s+(?<lba>[\\d]+)$"; + // Not checked + const string DiskIDRegEx = "DISC_ID\\s+(?<diskid>[\\da-f]{8})$"; + const string BarCodeRegEx = "UPC_EAN\\s+(?<barcode>[\\d]{12,13})$"; + const string CommentRegEx = "REM\\s+(?<comment>.+)$"; + const string CDTextRegEx = "CDTEXTFILE\\s+(?<filename>.+)$"; + const string MCNRegEx = "CATALOG\\s+(?<catalog>\\d{13})$"; + const string TitleRegEx = "TITLE\\s+(?<title>.+)$"; + const string GenreRegEx = "GENRE\\s+(?<genre>.+)$"; + const string ArrangerRegEx = "ARRANGER\\s+(?<arranger>.+)$"; + const string ComposerRegEx = "COMPOSER\\s+(?<composer>.+)$"; + const string PerformerRegEx = "PERFORMER\\s+(?<performer>.+)$"; + const string SongWriterRegEx = "SONGWRITER\\s+(?<songwriter>.+)$"; + const string FileRegEx = "FILE\\s+(?<filename>.+)\\s+(?<type>\\S+)$"; + const string TrackRegEx = "TRACK\\s+(?<number>\\d+)\\s+(?<type>\\S+)$"; + const string ISRCRegEx = "ISRC\\s+(?<isrc>\\w{12})$"; + const string IndexRegEx = "INDEX\\s+(?<index>\\d+)\\s+(?<msf>[\\d]+:[\\d]+:[\\d]+)$"; + const string PregapRegEx = "PREGAP\\s+(?<msf>[\\d]+:[\\d]+:[\\d]+)$"; + const string PostgapRegex = "POSTGAP\\s+(?<msf>[\\d]+:[\\d]+:[\\d]+)$"; + const string FlagsRegEx = "FLAGS\\s+(((?<dcp>DCP)|(?<quad>4CH)|(?<pre>PRE)|(?<scms>SCMS))\\s*)+$"; + + #endregion + + #region Methods + + public CDRWin(PluginBase Core) { - base.Name = "CDRWin cuesheet handler"; - base.PluginUUID = new Guid("664568B2-15D4-4E64-8A7A-20BDA8B8386F"); - this.imagePath = ""; + Name = "CDRWin cuesheet handler"; + PluginUUID = new Guid("664568B2-15D4-4E64-8A7A-20BDA8B8386F"); + imagePath = ""; } - // Due to .cue format, this method must parse whole file, ignoring errors (those will be thrown by OpenImage()). public override bool IdentifyImage(string imagePath) { @@ -163,13 +261,13 @@ namespace FileSystemIDandChk.ImagePlugins try { - this.cueStream = new StreamReader(this.imagePath); + cueStream = new StreamReader(this.imagePath); int line = 0; - while (this.cueStream.Peek() >= 0) + while (cueStream.Peek() >= 0) { line++; - string _line = this.cueStream.ReadLine(); + string _line = cueStream.ReadLine(); Regex Sr = new Regex(SessionRegEx); Regex Rr = new Regex(CommentRegEx); @@ -187,15 +285,14 @@ namespace FileSystemIDandChk.ImagePlugins Cm = Cr.Match(_line); Fm = Fr.Match(_line); - if(!Sm.Success && !Rm.Success && !Cm.Success && !Fm.Success) + if (!Sm.Success && !Rm.Success && !Cm.Success && !Fm.Success) return false; - else - return true; + return true; } return false; } - catch(Exception ex) + catch (Exception ex) { Console.WriteLine("Exception trying to identify image file {0}", this.imagePath); Console.WriteLine("Exception: {0}", ex.Message); @@ -204,20 +301,20 @@ namespace FileSystemIDandChk.ImagePlugins } } - public override bool OpenImage(string filename) + public override bool OpenImage(string imagePath) { - if (filename == "") + if (imagePath == null) + return false; + if (imagePath == "") return false; this.imagePath = imagePath; try { - this.cueStream = new StreamReader(this.imagePath); + cueStream = new StreamReader(imagePath); int line = 0; bool intrack = false; - string currentfile = ""; - string currentfileformat = ""; byte currentsession = 1; // Initialize all RegExs @@ -269,16 +366,47 @@ namespace FileSystemIDandChk.ImagePlugins Match MatchFlags; // Initialize disc - this.discimage = new CDRWinDisc(); - this.discimage.sessions = new List<Session>(); - this.discimage.tracks = new List<CDRWinTrack>(); + discimage = new CDRWinDisc(); + discimage.sessions = new List<Session>(); + discimage.tracks = new List<CDRWinTrack>(); + discimage.comment = ""; CDRWinTrack currenttrack = new CDRWinTrack(); + currenttrack.indexes = new Dictionary<int, ulong>(); + CDRWinTrackFile currentfile = new CDRWinTrackFile(); + ulong currentfileoffsetsector = 0; - while (this.cueStream.Peek() >= 0) + CDRWinTrack[] cuetracks; + int track_count = 0; + + while (cueStream.Peek() >= 0) { line++; - string _line = this.cueStream.ReadLine(); + string _line = cueStream.ReadLine(); + + MatchTrack = RegexTrack.Match(_line); + if (MatchTrack.Success) + { + uint track_seq = uint.Parse(MatchTrack.Groups[1].Value); + if (track_count + 1 != track_seq) + throw new FeatureUnsupportedImageException(String.Format("Found TRACK {0} out of order in line {1}", track_seq, line)); + + track_count++; + } + } + + if (track_count == 0) + throw new FeatureUnsupportedImageException("No tracks found"); + + cuetracks = new CDRWinTrack[track_count]; + + line = 0; + cueStream.BaseStream.Seek(0, SeekOrigin.Begin); + + while (cueStream.Peek() >= 0) + { + line++; + string _line = cueStream.ReadLine(); MatchSession = RegexSession.Match(_line); MatchDiskType = RegexDiskType.Match(_line); @@ -286,36 +414,39 @@ namespace FileSystemIDandChk.ImagePlugins MatchLBA = RegexLBA.Match(_line); // Unhandled, just ignored MatchLeadOut = RegexLeadOut.Match(_line); // Unhandled, just ignored - if(MatchDiskType.Success && intrack == false) + if (MatchDiskType.Success && !intrack) { Console.WriteLine("DEBUG (CDRWin plugin): Found REM ORIGINAL MEDIA TYPE at line {0}", line); - this.discimage.disktypestr = MatchDiskType.Groups[1].Value; + discimage.disktypestr = MatchDiskType.Groups[1].Value; } - else if(MatchSession.Success && intrack == false) + else if (MatchDiskType.Success && intrack) + { + throw new FeatureUnsupportedImageException(String.Format("Found REM ORIGINAL MEDIA TYPE field after a track in line {0}", line)); + } + else if (MatchSession.Success) { Console.WriteLine("DEBUG (CDRWin plugin): Found REM SESSION at line {0}", line); currentsession = Byte.Parse(MatchSession.Groups[1].Value); // What happens between sessions } - else if(MatchLBA.Success) + else if (MatchLBA.Success) { Console.WriteLine("DEBUG (CDRWin plugin): Found REM MSF at line {0}", line); // Just ignored } - else if(MatchLeadOut.Success) + else if (MatchLeadOut.Success) { Console.WriteLine("DEBUG (CDRWin plugin): Found REM LEAD-OUT at line {0}", line); // Just ignored } - else if(MatchComment.Success && intrack == false) + else if (MatchComment.Success) { Console.WriteLine("DEBUG (CDRWin plugin): Found REM at line {0}", line); - this.discimage.comment = MatchComment.Groups[1].Value; - } - else if((MatchComment.Success || MatchSession.Success || MatchDiskType.Success) && intrack == true) - { - throw new FeatureUnsupportedImageException(String.Format("Found comment/session/disktype field after a track in line {0}", line)); + if (discimage.comment == "") + discimage.comment = MatchComment.Groups[1].Value; // First comment + else + discimage.comment += Environment.NewLine + MatchComment.Groups[1].Value; // Append new comments as new lines } else { @@ -337,165 +468,661 @@ namespace FileSystemIDandChk.ImagePlugins MatchBarCode = RegexBarCode.Match(_line); MatchArranger = RegexArranger.Match(_line); - if(MatchArranger.Success) + if (MatchArranger.Success) { Console.WriteLine("DEBUG (CDRWin plugin): Found ARRANGER at line {0}", line); - if(intrack == true) + if (intrack) currenttrack.arranger = MatchArranger.Groups[1].Value; else - this.discimage.arranger = MatchArranger.Groups[1].Value; + discimage.arranger = MatchArranger.Groups[1].Value; } - else if(MatchBarCode.Success) + else if (MatchBarCode.Success) { - Console.WriteLine("DEBUG (CDRWin plugin): Found CATALOG at line {0}", line); - if(intrack == false) - this.discimage.barcode = MatchBarCode.Groups[1].Value; + Console.WriteLine("DEBUG (CDRWin plugin): Found UPC_EAN at line {0}", line); + if (!intrack) + discimage.barcode = MatchBarCode.Groups[1].Value; else throw new FeatureUnsupportedImageException(String.Format("Found barcode field in incorrect place at line {0}", line)); } - else if(MatchCDText.Success) + else if (MatchCDText.Success) { Console.WriteLine("DEBUG (CDRWin plugin): Found CDTEXTFILE at line {0}", line); - if(intrack == false) - this.discimage.cdtextfile = MatchCDText.Groups[1].Value; + if (!intrack) + discimage.cdtextfile = MatchCDText.Groups[1].Value; else throw new FeatureUnsupportedImageException(String.Format("Found CD-Text file field in incorrect place at line {0}", line)); } - else if(MatchComposer.Success) + else if (MatchComposer.Success) { Console.WriteLine("DEBUG (CDRWin plugin): Found COMPOSER at line {0}", line); - if(intrack == true) + if (intrack) currenttrack.arranger = MatchComposer.Groups[1].Value; else - this.discimage.arranger = MatchComposer.Groups[1].Value; + discimage.arranger = MatchComposer.Groups[1].Value; } - else if(MatchDiskID.Success) + else if (MatchDiskID.Success) { Console.WriteLine("DEBUG (CDRWin plugin): Found DISC_ID at line {0}", line); - if(intrack == false) - this.discimage.disk_id = MatchDiskID.Groups[1].Value; + if (!intrack) + discimage.disk_id = MatchDiskID.Groups[1].Value; else throw new FeatureUnsupportedImageException(String.Format("Found CDDB ID field in incorrect place at line {0}", line)); } - else if(MatchFile.Success) + else if (MatchFile.Success) { Console.WriteLine("DEBUG (CDRWin plugin): Found FILE at line {0}", line); - currentfile = MatchFile.Groups[1].Value; - currentfileformat = MatchFile.Groups[2].Value; + + if (currenttrack.sequence != 0) + { + currentfile.sequence = currenttrack.sequence; + currenttrack.trackfile = currentfile; + FileInfo finfo = new FileInfo(currentfile.datafile); + currenttrack.sectors = ((ulong)finfo.Length - currentfile.offset) / CDRWinTrackTypeToBytesPerSector(currenttrack.tracktype); + cuetracks[currenttrack.sequence - 1] = currenttrack; + intrack = false; + currenttrack = new CDRWinTrack(); + } + + + currentfile.datafile = MatchFile.Groups[1].Value; + currentfile.filetype = MatchFile.Groups[2].Value; + + // Check if file path is quoted + if (currentfile.datafile[0] == '"' && currentfile.datafile[currentfile.datafile.Length - 1] == '"') + { + currentfile.datafile = currentfile.datafile.Substring(1, currentfile.datafile.Length - 2); // Unquote it + } + + // Check if file exists + if (!File.Exists(currentfile.datafile)) + { + if (currentfile.datafile[0] == '/' || (currentfile.datafile[0] == '/' && currentfile.datafile[1] == '.')) // UNIX absolute path + { + Regex unixpath = new Regex("^(.+)/([^/]+)$"); + Match unixpathmatch = unixpath.Match(currentfile.datafile); + + if (unixpathmatch.Success) + { + currentfile.datafile = unixpathmatch.Groups[1].Value; + + if (!File.Exists(currentfile.datafile)) + { + string path = Path.GetPathRoot(imagePath); + currentfile.datafile = path + Path.PathSeparator + currentfile.datafile; + + if (!File.Exists(currentfile.datafile)) + throw new FeatureUnsupportedImageException(String.Format("File \"{0}\" not found.", MatchFile.Groups[1].Value)); + } + } + else + throw new FeatureUnsupportedImageException(String.Format("File \"{0}\" not found.", MatchFile.Groups[1].Value)); + } + else if ((currentfile.datafile[1] == ':' && currentfile.datafile[2] == '\\') || + (currentfile.datafile[0] == '\\' && currentfile.datafile[1] == '\\') || + ((currentfile.datafile[0] == '.' && currentfile.datafile[1] == '\\'))) // Windows absolute path + { + Regex winpath = new Regex("^(?:[a-zA-Z]\\:(\\\\|\\/)|file\\:\\/\\/|\\\\\\\\|\\.(\\/|\\\\))([^\\\\\\/\\:\\*\\?\\<\\>\\\"\\|]+(\\\\|\\/){0,1})+$"); + Match winpathmatch = winpath.Match(currentfile.datafile); + if (winpathmatch.Success) + { + currentfile.datafile = winpathmatch.Groups[1].Value; + + if (!File.Exists(currentfile.datafile)) + { + string path = Path.GetPathRoot(imagePath); + currentfile.datafile = path + Path.PathSeparator + currentfile.datafile; + + if (!File.Exists(currentfile.datafile)) + throw new FeatureUnsupportedImageException(String.Format("File \"{0}\" not found.", MatchFile.Groups[1].Value)); + } + } + else + throw new FeatureUnsupportedImageException(String.Format("File \"{0}\" not found.", MatchFile.Groups[1].Value)); + } + else + { + string path = Path.GetDirectoryName(imagePath); + currentfile.datafile = path + Path.DirectorySeparatorChar + currentfile.datafile; + + if (!File.Exists(currentfile.datafile)) + throw new FeatureUnsupportedImageException(String.Format("File \"{0}\" not found.", MatchFile.Groups[1].Value)); + } + } + + // File does exist, process it + Console.WriteLine("DEBUG (CDRWin plugin): File \"{0}\" found", currentfile.datafile); + + switch (currentfile.filetype) + { + case CDRWinDiskTypeLittleEndian: + break; + case CDRWinDiskTypeBigEndian: + case CDRWinDiskTypeAIFF: + case CDRWinDiskTypeRIFF: + case CDRWinDiskTypeMP3: + throw new FeatureSupportedButNotImplementedImageException(String.Format("Unsupported file type {0}", currentfile.filetype)); + default: + throw new FeatureUnsupportedImageException(String.Format("Unknown file type {0}", currentfile.filetype)); + } + + Console.WriteLine("DEBUG (CDRWin plugin): Sets currentfile.offset to 0 at line 514"); + currentfile.offset = 0; + currentfile.sequence = 0; } - else if(MatchFlags.Success) + else if (MatchFlags.Success) { Console.WriteLine("DEBUG (CDRWin plugin): Found FLAGS at line {0}", line); - if(intrack == false) + if (!intrack) throw new FeatureUnsupportedImageException(String.Format("Found FLAGS field in incorrect place at line {0}", line)); - else - { - // Not yet implemented - } + // TODO: Implement FLAGS support. } - else if(MatchGenre.Success) + else if (MatchGenre.Success) { Console.WriteLine("DEBUG (CDRWin plugin): Found GENRE at line {0}", line); - if(intrack == true) + if (intrack) currenttrack.genre = MatchGenre.Groups[1].Value; else - this.discimage.genre = MatchGenre.Groups[1].Value; + discimage.genre = MatchGenre.Groups[1].Value; } - else if(MatchIndex.Success) + else if (MatchIndex.Success) { Console.WriteLine("DEBUG (CDRWin plugin): Found INDEX at line {0}", line); - if(intrack == false) + if (!intrack) throw new FeatureUnsupportedImageException(String.Format("Found INDEX before a track {0}", line)); else { - // Not yet implemented + int index = int.Parse(MatchIndex.Groups[1].Value); + ulong offset = CDRWinMSFToLBA(MatchIndex.Groups[2].Value); + + if ((index != 0 && index != 1) && currenttrack.indexes.Count == 0) + throw new FeatureUnsupportedImageException(String.Format("Found INDEX {0} before INDEX 00 or INDEX 01", index)); + + if ((index == 0 || (index == 1 && !currenttrack.indexes.ContainsKey(0)))) + { + if ((int)(currenttrack.sequence - 2) >= 0 && offset > 1) + { + cuetracks[currenttrack.sequence - 2].sectors = offset - currentfileoffsetsector; + currentfile.offset += cuetracks[currenttrack.sequence - 2].sectors * cuetracks[currenttrack.sequence - 2].bps; + Console.WriteLine("DEBUG (CDRWin plugin): Sets currentfile.offset to {0} at line 553", currentfile.offset); + Console.WriteLine("DEBUG (CDRWin plugin): cuetracks[currenttrack.sequence-2].sectors = {0}", cuetracks[currenttrack.sequence - 2].sectors); + Console.WriteLine("DEBUG (CDRWin plugin): cuetracks[currenttrack.sequence-2].bps = {0}", cuetracks[currenttrack.sequence - 2].bps); + } + } + + if ((index == 0 || (index == 1 && !currenttrack.indexes.ContainsKey(0))) && currenttrack.sequence == 1) + { + Console.WriteLine("DEBUG (CDRWin plugin): Sets currentfile.offset to {0} at line 559", offset * currenttrack.bps); + currentfile.offset = offset * currenttrack.bps; + } + + currentfileoffsetsector = offset; + currenttrack.indexes.Add(index, offset); } } - else if(MatchISRC.Success) + else if (MatchISRC.Success) { Console.WriteLine("DEBUG (CDRWin plugin): Found ISRC at line {0}", line); - if(intrack == false) + if (!intrack) throw new FeatureUnsupportedImageException(String.Format("Found ISRC before a track {0}", line)); - else - currenttrack.isrc = MatchISRC.Groups[1].Value; + currenttrack.isrc = MatchISRC.Groups[1].Value; } - else if(MatchMCN.Success) + else if (MatchMCN.Success) { Console.WriteLine("DEBUG (CDRWin plugin): Found CATALOG at line {0}", line); - if(intrack == false) - this.discimage.mcn = MatchMCN.Groups[1].Value; + if (!intrack) + discimage.mcn = MatchMCN.Groups[1].Value; else throw new FeatureUnsupportedImageException(String.Format("Found CATALOG field in incorrect place at line {0}", line)); } - else if(MatchPerformer.Success) + else if (MatchPerformer.Success) { Console.WriteLine("DEBUG (CDRWin plugin): Found PERFORMER at line {0}", line); - if(intrack == true) + if (intrack) currenttrack.performer = MatchPerformer.Groups[1].Value; else - this.discimage.performer = MatchPerformer.Groups[1].Value; + discimage.performer = MatchPerformer.Groups[1].Value; } - else if(MatchPostgap.Success) + else if (MatchPostgap.Success) { Console.WriteLine("DEBUG (CDRWin plugin): Found POSTGAP at line {0}", line); - if(intrack == true) + if (intrack) { - // Not yet implemented + currenttrack.postgap = CDRWinMSFToLBA(MatchPostgap.Groups[1].Value); } else throw new FeatureUnsupportedImageException(String.Format("Found POSTGAP field before a track at line {0}", line)); } - else if(MatchPregap.Success) + else if (MatchPregap.Success) { Console.WriteLine("DEBUG (CDRWin plugin): Found PREGAP at line {0}", line); - if(intrack == true) + if (intrack) { - // Not yet implemented + currenttrack.pregap = CDRWinMSFToLBA(MatchPregap.Groups[1].Value); } else throw new FeatureUnsupportedImageException(String.Format("Found PREGAP field before a track at line {0}", line)); } - else if(MatchSongWriter.Success) + else if (MatchSongWriter.Success) { Console.WriteLine("DEBUG (CDRWin plugin): Found SONGWRITER at line {0}", line); - if(intrack == true) + if (intrack) currenttrack.songwriter = MatchSongWriter.Groups[1].Value; else - this.discimage.songwriter = MatchSongWriter.Groups[1].Value; + discimage.songwriter = MatchSongWriter.Groups[1].Value; } - else if(MatchTitle.Success) + else if (MatchTitle.Success) { Console.WriteLine("DEBUG (CDRWin plugin): Found TITLE at line {0}", line); - if(intrack == true) + if (intrack) currenttrack.title = MatchTitle.Groups[1].Value; else - this.discimage.title = MatchTitle.Groups[1].Value; + discimage.title = MatchTitle.Groups[1].Value; } - else if(MatchTrack.Success) + else if (MatchTrack.Success) { Console.WriteLine("DEBUG (CDRWin plugin): Found TRACK at line {0}", line); - if(currentfile == "") + if (currentfile.datafile == "") throw new FeatureUnsupportedImageException(String.Format("Found TRACK field before a file is defined at line {0}", line)); - else + if (intrack) { - if(intrack == true) + if (currenttrack.indexes.ContainsKey(0) && currenttrack.pregap == 0) { - this.discimage.tracks.Add(currenttrack); + currenttrack.indexes.TryGetValue(0, out currenttrack.pregap); } - currenttrack = new CDRWinTrack(); - intrack = true; - - // TODO + currentfile.sequence = currenttrack.sequence; + currenttrack.trackfile = currentfile; + cuetracks[currenttrack.sequence - 1] = currenttrack; } + currenttrack = new CDRWinTrack(); + currenttrack.indexes = new Dictionary<int, ulong>(); + currenttrack.sequence = uint.Parse(MatchTrack.Groups[1].Value); + Console.WriteLine("DEBUG (CDRWin plugin): Setting currenttrack.sequence to {0}", currenttrack.sequence); + currentfile.sequence = currenttrack.sequence; + currenttrack.bps = CDRWinTrackTypeToBytesPerSector(MatchTrack.Groups[2].Value); + currenttrack.tracktype = MatchTrack.Groups[2].Value; + currenttrack.session = currentsession; + intrack = true; + + // TODO + } + else if (_line == "") // Empty line, ignore it + { + + } + else // Non-empty unknown field + { + throw new FeatureUnsupportedImageException(String.Format("Found unknown field defined at line {0}: \"{1}\"", line, _line)); } } } - return false; + if (currenttrack.sequence != 0) + { + currentfile.sequence = currenttrack.sequence; + currenttrack.trackfile = currentfile; + FileInfo finfo = new FileInfo(currentfile.datafile); + currenttrack.sectors = ((ulong)finfo.Length - currentfile.offset) / CDRWinTrackTypeToBytesPerSector(currenttrack.tracktype); + cuetracks[currenttrack.sequence - 1] = currenttrack; + } + + Session[] _sessions = new Session[currentsession]; + for (int s = 1; s <= _sessions.Length; s++) + { + _sessions[s - 1].SessionSequence = 1; + ulong _session_offset; + + if (s > 1) + _sessions[s - 1].StartSector = _sessions[s - 2].EndSector + 1; + else + _sessions[s - 1].StartSector = 0; + + ulong session_sectors = 0; + bool first_session_track = true; + int last_session_track = 0; + + for (int i = 0; i < cuetracks.Length; i++) + { + if (cuetracks[i].session == s) + { + session_sectors += cuetracks[i].sectors; + if (i > last_session_track) + last_session_track = i; + } + } + + _sessions[s - 1].EndTrack = cuetracks[last_session_track].sequence; + _sessions[s - 1].EndSector = session_sectors - 1; + } + + for (int s = 1; s <= _sessions.Length; s++) + discimage.sessions.Add(_sessions[s - 1]); + + for (int t = 1; t <= cuetracks.Length; t++) + discimage.tracks.Add(cuetracks[t - 1]); + + discimage.disktype = CDRWinIsoBusterDiscTypeToDiskType(discimage.disktypestr); + + if (discimage.disktype == DiskType.Unknown || discimage.disktype == DiskType.CD) + { + bool data = false; + bool cdg = false; + bool cdi = false; + bool mode2 = false; + bool firstaudio = false; + bool firstdata = false; + bool audio = false; + + for (int i = 0; i < discimage.tracks.Count; i++) + { + // First track is audio + firstaudio |= i == 0 && discimage.tracks[i].tracktype == CDRWinTrackTypeAudio; + + // First track is data + firstdata |= i == 0 && discimage.tracks[i].tracktype != CDRWinTrackTypeAudio; + + // Any non first track is data + data |= i != 0 && discimage.tracks[i].tracktype != CDRWinTrackTypeAudio; + + // Any non first track is audio + audio |= i != 0 && discimage.tracks[i].tracktype == CDRWinTrackTypeAudio; + + switch (discimage.tracks[i].tracktype) + { + case CDRWinTrackTypeCDG: + cdg = true; + break; + case CDRWinTrackTypeCDI: + case CDRWinTrackTypeCDIRaw: + cdi = true; + break; + case CDRWinTrackTypeMode2Form1: + case CDRWinTrackTypeMode2Form2: + case CDRWinTrackTypeMode2Formless: + case CDRWinTrackTypeMode2Raw: + mode2 = true; + break; + } + } + + if (!data && !firstdata) + discimage.disktype = DiskType.CDDA; + else if (cdg) + discimage.disktype = DiskType.CDG; + else if (cdi) + discimage.disktype = DiskType.CDI; + else if (firstaudio && data && discimage.sessions.Count > 1 && mode2) + discimage.disktype = DiskType.CDPLUS; + else if ((firstdata && !data) || mode2) + discimage.disktype = DiskType.CDROMXA; + else if (!audio) + discimage.disktype = DiskType.CDROM; + else + discimage.disktype = DiskType.CD; + } + + // DEBUG information + Console.WriteLine("DEBUG (CDRWin plugin): Disc image parsing results"); + Console.WriteLine("DEBUG (CDRWin plugin): Disc CD-TEXT:"); + if (discimage.arranger == null) + Console.WriteLine("DEBUG (CDRWin plugin): \tArranger is not set."); + else + Console.WriteLine("DEBUG (CDRWin plugin): \tArranger: {0}", discimage.arranger); + if (discimage.composer == null) + Console.WriteLine("DEBUG (CDRWin plugin): \tComposer is not set."); + else + Console.WriteLine("DEBUG (CDRWin plugin): \tComposer: {0}", discimage.composer); + if (discimage.genre == null) + Console.WriteLine("DEBUG (CDRWin plugin): \tGenre is not set."); + else + Console.WriteLine("DEBUG (CDRWin plugin): \tGenre: {0}", discimage.genre); + if (discimage.performer == null) + Console.WriteLine("DEBUG (CDRWin plugin): \tPerformer is not set."); + else + Console.WriteLine("DEBUG (CDRWin plugin): \tPerformer: {0}", discimage.performer); + if (discimage.songwriter == null) + Console.WriteLine("DEBUG (CDRWin plugin): \tSongwriter is not set."); + else + Console.WriteLine("DEBUG (CDRWin plugin): \tSongwriter: {0}", discimage.songwriter); + if (discimage.title == null) + Console.WriteLine("DEBUG (CDRWin plugin): \tTitle is not set."); + else + Console.WriteLine("DEBUG (CDRWin plugin): \tTitle: {0}", discimage.title); + if (discimage.cdtextfile == null) + Console.WriteLine("DEBUG (CDRWin plugin): \tCD-TEXT binary file not set."); + else + Console.WriteLine("DEBUG (CDRWin plugin): \tCD-TEXT binary file: {0}", discimage.cdtextfile); + Console.WriteLine("DEBUG (CDRWin plugin): Disc information:"); + if (discimage.disktypestr == null) + Console.WriteLine("DEBUG (CDRWin plugin): \tISOBuster disc type not set."); + else + Console.WriteLine("DEBUG (CDRWin plugin): \tISOBuster disc type: {0}", discimage.disktypestr); + Console.WriteLine("DEBUG (CDRWin plugin): \tGuessed disk type: {0}", discimage.disktype); + if (discimage.barcode == null) + Console.WriteLine("DEBUG (CDRWin plugin): \tBarcode not set."); + else + Console.WriteLine("DEBUG (CDRWin plugin): \tBarcode: {0}", discimage.barcode); + if (discimage.disk_id == null) + Console.WriteLine("DEBUG (CDRWin plugin): \tDisc ID not set."); + else + Console.WriteLine("DEBUG (CDRWin plugin): \tDisc ID: {0}", discimage.disk_id); + if (discimage.mcn == null) + Console.WriteLine("DEBUG (CDRWin plugin): \tMCN not set."); + else + Console.WriteLine("DEBUG (CDRWin plugin): \tMCN: {0}", discimage.mcn); + if (discimage.comment == null) + Console.WriteLine("DEBUG (CDRWin plugin): \tComment not set."); + else + Console.WriteLine("DEBUG (CDRWin plugin): \tComment: \"{0}\"", discimage.comment); + Console.WriteLine("DEBUG (CDRWin plugin): Session information:"); + Console.WriteLine("DEBUG (CDRWin plugin): \tDisc contains {0} sessions", discimage.sessions.Count); + for (int i = 0; i < discimage.sessions.Count; i++) + { + Console.WriteLine("DEBUG (CDRWin plugin): \tSession {0} information:", i + 1); + Console.WriteLine("DEBUG (CDRWin plugin): \t\tStarting track: {0}", discimage.sessions[i].StartTrack); + Console.WriteLine("DEBUG (CDRWin plugin): \t\tStarting sector: {0}", discimage.sessions[i].StartSector); + Console.WriteLine("DEBUG (CDRWin plugin): \t\tEnding track: {0}", discimage.sessions[i].EndTrack); + Console.WriteLine("DEBUG (CDRWin plugin): \t\tEnding sector: {0}", discimage.sessions[i].EndSector); + } + Console.WriteLine("DEBUG (CDRWin plugin): Track information:"); + Console.WriteLine("DEBUG (CDRWin plugin): \tDisc contains {0} tracks", discimage.tracks.Count); + for (int i = 0; i < discimage.tracks.Count; i++) + { + Console.WriteLine("DEBUG (CDRWin plugin): \tTrack {0} information:", discimage.tracks[i].sequence); + + Console.WriteLine("DEBUG (CDRWin plugin): \t\t{0} bytes per sector", discimage.tracks[i].bps); + Console.WriteLine("DEBUG (CDRWin plugin): \t\tPregap: {0} sectors", discimage.tracks[i].pregap); + Console.WriteLine("DEBUG (CDRWin plugin): \t\tData: {0} sectors", discimage.tracks[i].sectors); + Console.WriteLine("DEBUG (CDRWin plugin): \t\tPostgap: {0} sectors", discimage.tracks[i].postgap); + + if (discimage.tracks[i].flag_4ch) + Console.WriteLine("DEBUG (CDRWin plugin): \t\tTrack is flagged as quadraphonic"); + if (discimage.tracks[i].flag_dcp) + Console.WriteLine("DEBUG (CDRWin plugin): \t\tTrack allows digital copy"); + if (discimage.tracks[i].flag_pre) + Console.WriteLine("DEBUG (CDRWin plugin): \t\tTrack has pre-emphasis applied"); + if (discimage.tracks[i].flag_scms) + Console.WriteLine("DEBUG (CDRWin plugin): \t\tTrack has SCMS"); + + Console.WriteLine("DEBUG (CDRWin plugin): \t\tTrack resides in file {0}, type defined as {1}, starting at byte {2}", + discimage.tracks[i].trackfile.datafile, discimage.tracks[i].trackfile.filetype, discimage.tracks[i].trackfile.offset); + + Console.WriteLine("DEBUG (CDRWin plugin): \t\tIndexes:"); + foreach (KeyValuePair<int, ulong> kvp in discimage.tracks[i].indexes) + Console.WriteLine("DEBUG (CDRWin plugin): \t\t\tIndex {0} starts at sector {1}", kvp.Key, kvp.Value); + + if (discimage.tracks[i].isrc == null) + Console.WriteLine("DEBUG (CDRWin plugin): \t\tISRC is not set."); + else + Console.WriteLine("DEBUG (CDRWin plugin): \t\tISRC: {0}", discimage.tracks[i].isrc); + + if (discimage.tracks[i].arranger == null) + Console.WriteLine("DEBUG (CDRWin plugin): \t\tArranger is not set."); + else + Console.WriteLine("DEBUG (CDRWin plugin): \t\tArranger: {0}", discimage.tracks[i].arranger); + if (discimage.tracks[i].composer == null) + Console.WriteLine("DEBUG (CDRWin plugin): \t\tComposer is not set."); + else + Console.WriteLine("DEBUG (CDRWin plugin): \t\tComposer: {0}", discimage.tracks[i].composer); + if (discimage.tracks[i].genre == null) + Console.WriteLine("DEBUG (CDRWin plugin): \t\tGenre is not set."); + else + Console.WriteLine("DEBUG (CDRWin plugin): \t\tGenre: {0}", discimage.tracks[i].genre); + if (discimage.tracks[i].performer == null) + Console.WriteLine("DEBUG (CDRWin plugin): \t\tPerformer is not set."); + else + Console.WriteLine("DEBUG (CDRWin plugin): \t\tPerformer: {0}", discimage.tracks[i].performer); + if (discimage.tracks[i].songwriter == null) + Console.WriteLine("DEBUG (CDRWin plugin): \t\tSongwriter is not set."); + else + Console.WriteLine("DEBUG (CDRWin plugin): \t\tSongwriter: {0}", discimage.tracks[i].songwriter); + if (discimage.tracks[i].title == null) + Console.WriteLine("DEBUG (CDRWin plugin): \t\tTitle is not set."); + else + Console.WriteLine("DEBUG (CDRWin plugin): \t\tTitle: {0}", discimage.tracks[i].title); + } + + Console.WriteLine("DEBUG (CDRWin plugin): Building offset map"); + + partitions = new List<FileSystemIDandChk.PartPlugins.Partition>(); + + ulong byte_offset = 0; + ulong sector_offset = 0; + ulong partitionSequence = 0; + ulong index_zero_offset = 0; + ulong index_one_offset = 0; + bool index_zero = false; + + offsetmap = new Dictionary<uint, ulong>(); + + for (int i = 0; i < discimage.tracks.Count; i++) + { + if (discimage.tracks[i].sequence == 1 && i != 0) + throw new ImageNotSupportedException("Unordered tracks"); + + PartPlugins.Partition partition = new FileSystemIDandChk.PartPlugins.Partition(); + + if (discimage.tracks[i].pregap > 0) + { + partition.PartitionDescription = String.Format("Track {0} pregap.", discimage.tracks[i].sequence); + partition.PartitionName = discimage.tracks[i].title; + partition.PartitionStartSector = sector_offset; + partition.PartitionLength = discimage.tracks[i].pregap * discimage.tracks[i].bps; + partition.PartitionSectors = discimage.tracks[i].pregap; + partition.PartitionSequence = partitionSequence; + partition.PartitionStart = byte_offset; + partition.PartitionType = discimage.tracks[i].tracktype; + + sector_offset += partition.PartitionSectors; + byte_offset += partition.PartitionLength; + partitionSequence++; + + if(!offsetmap.ContainsKey(discimage.tracks[i].sequence)) + offsetmap.Add(discimage.tracks[i].sequence, partition.PartitionStartSector); + else + { + ulong old_start; + offsetmap.TryGetValue(discimage.tracks[i].sequence, out old_start); + + if(partition.PartitionStartSector < old_start) + { + offsetmap.Remove(discimage.tracks[i].sequence); + offsetmap.Add(discimage.tracks[i].sequence, partition.PartitionStartSector); + } + } + + partitions.Add(partition); + partition = new FileSystemIDandChk.PartPlugins.Partition(); + } + + index_zero |= discimage.tracks[i].indexes.TryGetValue(0, out index_zero_offset); + + if (!discimage.tracks[i].indexes.TryGetValue(1, out index_one_offset)) + throw new ImageNotSupportedException(String.Format("Track {0} lacks index 01", discimage.tracks[i].sequence)); + + if (index_zero && index_one_offset > index_zero_offset) + { + partition.PartitionDescription = String.Format("Track {0} index 00.", discimage.tracks[i].sequence); + partition.PartitionName = discimage.tracks[i].title; + partition.PartitionStartSector = sector_offset; + partition.PartitionLength = (index_one_offset - index_zero_offset) * discimage.tracks[i].bps; + partition.PartitionSectors = index_one_offset - index_zero_offset; + partition.PartitionSequence = partitionSequence; + partition.PartitionStart = byte_offset; + partition.PartitionType = discimage.tracks[i].tracktype; + + sector_offset += partition.PartitionSectors; + byte_offset += partition.PartitionLength; + partitionSequence++; + + if(!offsetmap.ContainsKey(discimage.tracks[i].sequence)) + offsetmap.Add(discimage.tracks[i].sequence, partition.PartitionStartSector); + else + { + ulong old_start; + offsetmap.TryGetValue(discimage.tracks[i].sequence, out old_start); + + if(partition.PartitionStartSector < old_start) + { + offsetmap.Remove(discimage.tracks[i].sequence); + offsetmap.Add(discimage.tracks[i].sequence, partition.PartitionStartSector); + } + } + + partitions.Add(partition); + partition = new FileSystemIDandChk.PartPlugins.Partition(); + } + + // Index 01 + partition.PartitionDescription = String.Format("Track {0}.", discimage.tracks[i].sequence); + partition.PartitionName = discimage.tracks[i].title; + partition.PartitionStartSector = sector_offset; + partition.PartitionLength = (discimage.tracks[i].sectors - (index_one_offset - index_zero_offset)) * discimage.tracks[i].bps; + partition.PartitionSectors = (discimage.tracks[i].sectors - (index_one_offset - index_zero_offset)); + partition.PartitionSequence = partitionSequence; + partition.PartitionStart = byte_offset; + partition.PartitionType = discimage.tracks[i].tracktype; + + sector_offset += partition.PartitionSectors; + byte_offset += partition.PartitionLength; + partitionSequence++; + + if(!offsetmap.ContainsKey(discimage.tracks[i].sequence)) + offsetmap.Add(discimage.tracks[i].sequence, partition.PartitionStartSector); + else + { + ulong old_start; + offsetmap.TryGetValue(discimage.tracks[i].sequence, out old_start); + + if(partition.PartitionStartSector < old_start) + { + offsetmap.Remove(discimage.tracks[i].sequence); + offsetmap.Add(discimage.tracks[i].sequence, partition.PartitionStartSector); + } + } + + partitions.Add(partition); + partition = new FileSystemIDandChk.PartPlugins.Partition(); + } + + // Print offset map + Console.WriteLine("DEBUG (CDRWin plugin) printing partition map"); + foreach(FileSystemIDandChk.PartPlugins.Partition partition in partitions) + { + Console.WriteLine ("DEBUG (CDRWin plugin): Partition sequence: {0}", partition.PartitionSequence); + Console.WriteLine ("DEBUG (CDRWin plugin): \tPartition name: {0}", partition.PartitionName); + Console.WriteLine ("DEBUG (CDRWin plugin): \tPartition description: {0}", partition.PartitionDescription); + Console.WriteLine ("DEBUG (CDRWin plugin): \tPartition type: {0}", partition.PartitionType); + Console.WriteLine ("DEBUG (CDRWin plugin): \tPartition starting sector: {0}", partition.PartitionStartSector); + Console.WriteLine ("DEBUG (CDRWin plugin): \tPartition sectors: {0}", partition.PartitionSectors); + Console.WriteLine ("DEBUG (CDRWin plugin): \tPartition starting offset: {0}", partition.PartitionStart); + Console.WriteLine ("DEBUG (CDRWin plugin): \tPartition size in bytes: {0}", partition.PartitionLength); + } + + return true; } - catch(Exception ex) + catch (Exception ex) { - Console.WriteLine("Exception trying to identify image file {0}", this.imagePath); + Console.WriteLine("Exception trying to identify image file {0}", imagePath); Console.WriteLine("Exception: {0}", ex.Message); Console.WriteLine("Stack trace: {0}", ex.StackTrace); return false; @@ -510,95 +1137,569 @@ namespace FileSystemIDandChk.ImagePlugins public override UInt64 GetImageSize() { - throw new FeatureSupportedButNotImplementedImageException("Feature not yet implemented"); + UInt64 size; + + size = 0; + foreach (CDRWinTrack track in discimage.tracks) + size += track.bps * track.sectors; + + return size; } + public override UInt64 GetSectors() { - throw new FeatureSupportedButNotImplementedImageException("Feature not yet implemented"); + UInt64 sectors; + + sectors = 0; + foreach (CDRWinTrack track in discimage.tracks) + sectors += track.sectors; + + return sectors; } + public override UInt32 GetSectorSize() { - throw new FeatureSupportedButNotImplementedImageException("Feature not yet implemented"); + if (discimage.disktype == DiskType.CDG || discimage.disktype == DiskType.CDEG || discimage.disktype == DiskType.CDMIDI) + return 2448; // CD+G subchannels ARE user data, as CD+G are useless without them + if (discimage.disktype != DiskType.CDROMXA && discimage.disktype != DiskType.CDDA && discimage.disktype != DiskType.CDI && discimage.disktype != DiskType.CDPLUS) + return 2048; // Only data tracks + return 2352; // All others } public override byte[] ReadDiskTag(DiskTagType tag) { - throw new FeatureSupportedButNotImplementedImageException("Feature not yet implemented"); + switch (tag) + { + case DiskTagType.CD_MCN: + { + if (discimage.mcn != null) + { + return Encoding.ASCII.GetBytes(discimage.mcn); + } + throw new FeatureNotPresentImageException("Image does not contain MCN information."); + } + case DiskTagType.CD_TEXT: + { + if (discimage.cdtextfile != null) + // TODO: Check that binary text file exists, open it, read it, send it to caller. + throw new FeatureSupportedButNotImplementedImageException("Feature not yet implemented"); + throw new FeatureNotPresentImageException("Image does not contain CD-TEXT information."); + } + default: + throw new FeatureSupportedButNotImplementedImageException("Feature not supported by image format"); + } } - public override byte[] ReadSector(UInt64 SectorAddress) + public override byte[] ReadSector(UInt64 sectorAddress) { - throw new FeatureSupportedButNotImplementedImageException("Feature not yet implemented"); + return ReadSectors(sectorAddress, 1); } - public override byte[] ReadSectorTag(UInt64 SectorAddress, SectorTagType tag) + public override byte[] ReadSectorTag(UInt64 sectorAddress, SectorTagType tag) { - throw new FeatureSupportedButNotImplementedImageException("Feature not yet implemented"); + return ReadSectorsTag(sectorAddress, 1, tag); } - public override byte[] ReadSector(UInt64 SectorAddress, UInt32 track) + public override byte[] ReadSector(UInt64 sectorAddress, UInt32 track) { - throw new FeatureSupportedButNotImplementedImageException("Feature not yet implemented"); + return ReadSectors(sectorAddress, 1, track); } - public override byte[] ReadSectorTag(UInt64 SectorAddress, UInt32 track, SectorTagType tag) + public override byte[] ReadSectorTag(UInt64 sectorAddress, UInt32 track, SectorTagType tag) { - throw new FeatureSupportedButNotImplementedImageException("Feature not yet implemented"); + return ReadSectorsTag(sectorAddress, 1, track, tag); } - public override byte[] ReadSectors(UInt64 SectorAddress, UInt32 length) + public override byte[] ReadSectors(UInt64 sectorAddress, UInt32 length) { - throw new FeatureSupportedButNotImplementedImageException("Feature not yet implemented"); + foreach (KeyValuePair<uint, ulong> kvp in offsetmap) + { + if (sectorAddress >= kvp.Value) + { + foreach (CDRWinTrack cdrwin_track in discimage.tracks) + { + if (cdrwin_track.sequence == kvp.Key) + { + if((sectorAddress - kvp.Value) < cdrwin_track.sectors) + return ReadSectors((sectorAddress - kvp.Value), length, kvp.Key); + } + } + } + } + + throw new ArgumentOutOfRangeException("sectorAddress", "Sector address not found"); } - public override byte[] ReadSectorsTag(UInt64 SectorAddress, UInt32 length, SectorTagType tag) + public override byte[] ReadSectorsTag(UInt64 sectorAddress, UInt32 length, SectorTagType tag) { - throw new FeatureSupportedButNotImplementedImageException("Feature not yet implemented"); + foreach (KeyValuePair<uint, ulong> kvp in offsetmap) + { + if (sectorAddress >= kvp.Value) + { + foreach (CDRWinTrack cdrwin_track in discimage.tracks) + { + if (cdrwin_track.sequence == kvp.Key) + { + if((sectorAddress - kvp.Value) < cdrwin_track.sectors) + return ReadSectorsTag((sectorAddress - kvp.Value), length, kvp.Key, tag); + } + } + } + } + + throw new ArgumentOutOfRangeException("sectorAddress", "Sector address not found"); } - public override byte[] ReadSectors(UInt64 SectorAddress, UInt32 length, UInt32 track) + public override byte[] ReadSectors(UInt64 sectorAddress, UInt32 length, UInt32 track) { - throw new FeatureSupportedButNotImplementedImageException("Feature not yet implemented"); + CDRWinTrack _track = new CDRWinTrack(); + + _track.sequence = 0; + + foreach (CDRWinTrack cdrwin_track in discimage.tracks) + { + if (cdrwin_track.sequence == track) + { + _track = cdrwin_track; + break; + } + } + + if (_track.sequence == 0) + throw new ArgumentOutOfRangeException("track", "Track does not exist in disc image"); + + if (length > _track.sectors) + throw new ArgumentOutOfRangeException("length", "Requested more sectors than present in track, won't cross tracks"); + + uint sector_offset; + uint sector_size; + uint sector_skip; + + switch (_track.tracktype) + { + case CDRWinTrackTypeMode1: + case CDRWinTrackTypeMode2Form1: + { + sector_offset = 0; + sector_size = 2048; + sector_skip = 0; + break; + } + case CDRWinTrackTypeMode2Form2: + { + sector_offset = 0; + sector_size = 2324; + sector_skip = 0; + break; + } + case CDRWinTrackTypeMode2Formless: + case CDRWinTrackTypeCDI: + { + sector_offset = 0; + sector_size = 2336; + sector_skip = 0; + break; + } + case CDRWinTrackTypeAudio: + { + sector_offset = 0; + sector_size = 2352; + sector_skip = 0; + break; + } + case CDRWinTrackTypeMode1Raw: + { + sector_offset = 16; + sector_size = 2048; + sector_skip = 288; + break; + } + case CDRWinTrackTypeMode2Raw: + { + sector_offset = 16; + sector_size = 2336; + sector_skip = 0; + break; + } + case CDRWinTrackTypeCDIRaw: + { + sector_offset = 16; + sector_size = 2336; + sector_skip = 0; + break; + } + case CDRWinTrackTypeCDG: + { + sector_offset = 0; + sector_size = 2352; + sector_skip = 96; + break; + } + default: + throw new FeatureSupportedButNotImplementedImageException("Unsupported track type"); + } + + byte[] buffer = new byte[sector_size * length]; + + this.imageStream = new FileStream(_track.trackfile.datafile, FileMode.Open, FileAccess.Read); + BinaryReader br = new BinaryReader(this.imageStream); + + br.BaseStream.Seek((long)_track.trackfile.offset + (long)(sectorAddress*(sector_offset + sector_size + sector_skip)), SeekOrigin.Begin); + + if (sector_offset == 0 && sector_skip == 0) + buffer = br.ReadBytes((int)(sector_size * length)); + else + { + for (int i = 0; i < length; i++) + { + byte[] sector = new byte[sector_size]; + br.BaseStream.Seek(sector_offset, SeekOrigin.Current); + sector = br.ReadBytes((int)sector_size); + br.BaseStream.Seek(sector_skip, SeekOrigin.Current); + + System.Array.Copy(sector, 0, buffer, i * sector_size, sector_size); + } + } + + return buffer; } - public override byte[] ReadSectorsTag(UInt64 SectorAddress, UInt32 length, UInt32 track, SectorTagType tag) + public override byte[] ReadSectorsTag(UInt64 sectorAddress, UInt32 length, UInt32 track, SectorTagType tag) { - throw new FeatureSupportedButNotImplementedImageException("Feature not yet implemented"); + CDRWinTrack _track = new CDRWinTrack(); + + _track.sequence = 0; + + foreach (CDRWinTrack cdrwin_track in discimage.tracks) + { + if (cdrwin_track.sequence == track) + { + _track = cdrwin_track; + break; + } + } + + if (_track.sequence == 0) + throw new ArgumentOutOfRangeException("track", "Track does not exist in disc image"); + + if (length > _track.sectors) + throw new ArgumentOutOfRangeException("length", "Requested more sectors than present in track, won't cross tracks"); + + uint sector_offset; + uint sector_size; + uint sector_skip; + + switch (tag) + { + case SectorTagType.CDSectorECC: + case SectorTagType.CDSectorECC_P: + case SectorTagType.CDSectorECC_Q: + case SectorTagType.CDSectorEDC: + case SectorTagType.CDSectorHeader: + case SectorTagType.CDSectorSubchannel: + case SectorTagType.CDSectorSubHeader: + case SectorTagType.CDSectorSync: + break; + case SectorTagType.CDTrackFlags: + { + byte[] flags = new byte[1]; + + if (_track.tracktype != CDRWinTrackTypeAudio && _track.tracktype != CDRWinTrackTypeCDG) + flags[0] += 0x40; + + if (_track.flag_dcp) + flags[0] += 0x20; + + if (_track.flag_pre) + flags[0] += 0x10; + + return flags; + } + case SectorTagType.CDTrackISRC: + return Encoding.UTF8.GetBytes(_track.isrc); + case SectorTagType.CDTrackText: + throw new FeatureSupportedButNotImplementedImageException("Feature not yet implemented"); + default: + throw new ArgumentException("Unsupported tag requested", "tag"); + } + + switch (_track.tracktype) + { + case CDRWinTrackTypeMode1: + case CDRWinTrackTypeMode2Form1: + case CDRWinTrackTypeMode2Form2: + throw new ArgumentException("No tags in image for requested track", "tag"); + case CDRWinTrackTypeMode2Formless: + case CDRWinTrackTypeCDI: + { + switch (tag) + { + case SectorTagType.CDSectorSync: + case SectorTagType.CDSectorHeader: + case SectorTagType.CDSectorSubchannel: + case SectorTagType.CDSectorECC: + case SectorTagType.CDSectorECC_P: + case SectorTagType.CDSectorECC_Q: + throw new ArgumentException("Unsupported tag requested for this track", "tag"); + case SectorTagType.CDSectorSubHeader: + { + sector_offset = 0; + sector_size = 8; + sector_skip = 2328; + break; + } + case SectorTagType.CDSectorEDC: + { + sector_offset = 2332; + sector_size = 4; + sector_skip = 0; + break; + } + default: + throw new ArgumentException("Unsupported tag requested", "tag"); + } + break; + } + case CDRWinTrackTypeAudio: + throw new ArgumentException("There are no tags on audio tracks", "tag"); + case CDRWinTrackTypeMode1Raw: + { + switch (tag) + { + case SectorTagType.CDSectorSync: + { + sector_offset = 0; + sector_size = 12; + sector_skip = 2340; + break; + } + case SectorTagType.CDSectorHeader: + { + sector_offset = 12; + sector_size = 4; + sector_skip = 2336; + break; + } + case SectorTagType.CDSectorSubchannel: + case SectorTagType.CDSectorSubHeader: + throw new ArgumentException("Unsupported tag requested for this track", "tag"); + case SectorTagType.CDSectorECC: + { + sector_offset = 2076; + sector_size = 276; + sector_skip = 0; + break; + } + case SectorTagType.CDSectorECC_P: + { + sector_offset = 2076; + sector_size = 172; + sector_skip = 104; + break; + } + case SectorTagType.CDSectorECC_Q: + { + sector_offset = 2248; + sector_size = 104; + sector_skip = 0; + break; + } + case SectorTagType.CDSectorEDC: + { + sector_offset = 2064; + sector_size = 4; + sector_skip = 284; + break; + } + default: + throw new ArgumentException("Unsupported tag requested", "tag"); + } + break; + } + case CDRWinTrackTypeMode2Raw: // Requires reading sector + case CDRWinTrackTypeCDIRaw: + throw new FeatureSupportedButNotImplementedImageException("Feature not yet implemented"); + case CDRWinTrackTypeCDG: + { + if(tag != SectorTagType.CDSectorSubchannel) + throw new ArgumentException("Unsupported tag requested for this track", "tag"); + + sector_offset = 2352; + sector_size = 96; + sector_skip = 0; + break; + } + default: + throw new FeatureSupportedButNotImplementedImageException("Unsupported track type"); + } + + byte[] buffer = new byte[sector_size * length]; + + this.imageStream = new FileStream(_track.trackfile.datafile, FileMode.Open, FileAccess.Read); + BinaryReader br = new BinaryReader(this.imageStream); + + br.BaseStream.Seek((long)_track.trackfile.offset + (long)(sectorAddress*(sector_offset + sector_size + sector_skip)), SeekOrigin.Begin); + + if (sector_offset == 0 && sector_skip == 0) + buffer = br.ReadBytes((int)(sector_size * length)); + else + { + for (int i = 0; i < length; i++) + { + byte[] sector = new byte[sector_size]; + br.BaseStream.Seek(sector_offset, SeekOrigin.Current); + sector = br.ReadBytes((int)sector_size); + br.BaseStream.Seek(sector_skip, SeekOrigin.Current); + + System.Array.Copy(sector, 0, buffer, i * sector_size, sector_size); + } + } + + return buffer; } - public override byte[] ReadSectorLong(UInt64 SectorAddress) + public override byte[] ReadSectorLong(UInt64 sectorAddress) { - throw new FeatureSupportedButNotImplementedImageException("Feature not yet implemented"); + return ReadSectorsLong(sectorAddress, 1); } - public override byte[] ReadSectorLong(UInt64 SectorAddress, UInt32 track) + public override byte[] ReadSectorLong(UInt64 sectorAddress, UInt32 track) { - throw new FeatureSupportedButNotImplementedImageException("Feature not yet implemented"); + return ReadSectorsLong(sectorAddress, 1, track); } - public override byte[] ReadSectorsLong(UInt64 SectorAddress, UInt32 length) + public override byte[] ReadSectorsLong(UInt64 sectorAddress, UInt32 length) { - throw new FeatureSupportedButNotImplementedImageException("Feature not yet implemented"); + foreach (KeyValuePair<uint, ulong> kvp in offsetmap) + { + if (sectorAddress >= kvp.Value) + { + foreach (CDRWinTrack cdrwin_track in discimage.tracks) + { + if (cdrwin_track.sequence == kvp.Key) + { + if((sectorAddress - kvp.Value) < cdrwin_track.sectors) + return ReadSectorsLong((sectorAddress - kvp.Value), length, kvp.Key); + } + } + } + } + + throw new ArgumentOutOfRangeException("sectorAddress", "Sector address not found"); } - public override byte[] ReadSectorsLong(UInt64 SectorAddress, UInt32 length, UInt32 track) + public override byte[] ReadSectorsLong(UInt64 sectorAddress, UInt32 length, UInt32 track) { - throw new FeatureSupportedButNotImplementedImageException("Feature not yet implemented"); + CDRWinTrack _track = new CDRWinTrack(); + + _track.sequence = 0; + + foreach (CDRWinTrack cdrwin_track in discimage.tracks) + { + if (cdrwin_track.sequence == track) + { + _track = cdrwin_track; + break; + } + } + + if (_track.sequence == 0) + throw new ArgumentOutOfRangeException("track", "Track does not exist in disc image"); + + if (length > _track.sectors) + throw new ArgumentOutOfRangeException("length", "Requested more sectors than present in track, won't cross tracks"); + + uint sector_offset; + uint sector_size; + uint sector_skip; + + switch (_track.tracktype) + { + case CDRWinTrackTypeMode1: + case CDRWinTrackTypeMode2Form1: + { + sector_offset = 0; + sector_size = 2048; + sector_skip = 0; + break; + } + case CDRWinTrackTypeMode2Form2: + { + sector_offset = 0; + sector_size = 2324; + sector_skip = 0; + break; + } + case CDRWinTrackTypeMode2Formless: + case CDRWinTrackTypeCDI: + { + sector_offset = 0; + sector_size = 2336; + sector_skip = 0; + break; + } + case CDRWinTrackTypeMode1Raw: + case CDRWinTrackTypeMode2Raw: + case CDRWinTrackTypeCDIRaw: + case CDRWinTrackTypeAudio: + { + sector_offset = 0; + sector_size = 2352; + sector_skip = 0; + break; + } + case CDRWinTrackTypeCDG: + { + sector_offset = 0; + sector_size = 2448; + sector_skip = 0; + break; + } + default: + throw new FeatureSupportedButNotImplementedImageException("Unsupported track type"); + } + + byte[] buffer = new byte[sector_size * length]; + + this.imageStream = new FileStream(_track.trackfile.datafile, FileMode.Open, FileAccess.Read); + BinaryReader br = new BinaryReader(this.imageStream); + + br.BaseStream.Seek((long)_track.trackfile.offset + (long)(sectorAddress*(sector_offset + sector_size + sector_skip)), SeekOrigin.Begin); + + if (sector_offset == 0 && sector_skip == 0) + buffer = br.ReadBytes((int)(sector_size * length)); + else + { + for (int i = 0; i < length; i++) + { + byte[] sector = new byte[sector_size]; + br.BaseStream.Seek(sector_offset, SeekOrigin.Current); + sector = br.ReadBytes((int)sector_size); + br.BaseStream.Seek(sector_skip, SeekOrigin.Current); + + System.Array.Copy(sector, 0, buffer, i * sector_size, sector_size); + } + } + + return buffer; } public override string GetImageFormat() { - throw new FeatureSupportedButNotImplementedImageException("Feature not yet implemented"); + return "CDRWin CUESheet"; } public override string GetImageVersion() { - throw new FeatureSupportedButNotImplementedImageException("Feature not yet implemented"); + return null; } public override string GetImageApplication() { - throw new FeatureSupportedButNotImplementedImageException("Feature not yet implemented"); + // Detect ISOBuster extensions + if (discimage.disktypestr != null || discimage.comment.ToLower().Contains("isobuster") || discimage.sessions.Count > 1) + return "ISOBuster"; + return "CDRWin"; } public override string GetImageApplicationVersion() @@ -608,111 +1709,290 @@ namespace FileSystemIDandChk.ImagePlugins public override DateTime GetImageCreationTime() { - throw new FeatureSupportedButNotImplementedImageException("Feature not yet implemented"); + FileInfo fi = new FileInfo(discimage.tracks[0].trackfile.datafile); + + return fi.CreationTimeUtc; } public override DateTime GetImageLastModificationTime() { - throw new FeatureSupportedButNotImplementedImageException("Feature not yet implemented"); + FileInfo fi = new FileInfo(discimage.tracks[0].trackfile.datafile); + + return fi.LastWriteTimeUtc; } public override string GetImageComments() { - throw new FeatureSupportedButNotImplementedImageException("Feature not yet implemented"); + return discimage.comment; } public override string GetDiskSerialNumber() { - return this.GetDiskBarcode(); + return discimage.mcn; } public override string GetDiskBarcode() { - throw new FeatureSupportedButNotImplementedImageException("Feature not yet implemented"); + return discimage.barcode; } public override DiskType GetDiskType() { - throw new FeatureSupportedButNotImplementedImageException("Feature not yet implemented"); + return discimage.disktype; } public override List<PartPlugins.Partition> GetPartitions() { - throw new FeatureSupportedButNotImplementedImageException("Feature not yet implemented"); + return partitions; } public override List<Track> GetTracks() { - throw new FeatureSupportedButNotImplementedImageException("Feature not yet implemented"); + List<Track> tracks = new List<Track>(); + + foreach (CDRWinTrack cdr_track in discimage.tracks) + { + Track _track = new Track(); + + _track.Indexes = cdr_track.indexes; + _track.TrackDescription = cdr_track.title; + if (!cdr_track.indexes.TryGetValue(0, out _track.TrackStartSector)) + cdr_track.indexes.TryGetValue(1, out _track.TrackStartSector); + _track.TrackEndSector = _track.TrackStartSector + cdr_track.sectors - 1; + _track.TrackPregap = cdr_track.pregap; + _track.TrackSession = cdr_track.session; + _track.TrackSequence = cdr_track.sequence; + _track.TrackType = CDRWinTrackTypeToTrackType(cdr_track.tracktype); + + tracks.Add(_track); + } + + return tracks; } - public override List<Track> GetSessionTracks(Session Session) + public override List<Track> GetSessionTracks(Session session) { - throw new FeatureSupportedButNotImplementedImageException("Feature not yet implemented"); + if (discimage.sessions.Contains(session)) + { + return GetSessionTracks(session.SessionSequence); + } + else + throw new ImageNotSupportedException("Session does not exist in disc image"); } - public override List<Track> GetSessionTracks(UInt16 Session) + public override List<Track> GetSessionTracks(UInt16 session) { - throw new FeatureSupportedButNotImplementedImageException("Feature not yet implemented"); + List<Track> tracks = new List<Track>(); + + foreach (CDRWinTrack cdr_track in discimage.tracks) + { + if (cdr_track.session == session) + { + Track _track = new Track(); + + _track.Indexes = cdr_track.indexes; + _track.TrackDescription = cdr_track.title; + if (!cdr_track.indexes.TryGetValue(0, out _track.TrackStartSector)) + cdr_track.indexes.TryGetValue(1, out _track.TrackStartSector); + _track.TrackEndSector = _track.TrackStartSector + cdr_track.sectors - 1; + _track.TrackPregap = cdr_track.pregap; + _track.TrackSession = cdr_track.session; + _track.TrackSequence = cdr_track.sequence; + _track.TrackType = CDRWinTrackTypeToTrackType(cdr_track.tracktype); + + tracks.Add(_track); + } + } + + return tracks; } public override List<Session> GetSessions() { - throw new FeatureSupportedButNotImplementedImageException("Feature not yet implemented"); + return discimage.sessions; } -#endregion -#region Unsupported features + #endregion + + #region Private methods + + static UInt64 CDRWinMSFToLBA(string MSF) + { + string[] MSFElements; + UInt64 minute, second, frame, sectors; + + MSFElements = MSF.Split(':'); + minute = UInt64.Parse(MSFElements[0]); + second = UInt64.Parse(MSFElements[1]); + frame = UInt64.Parse(MSFElements[2]); + + sectors = (minute * 60 * 75) + (second * 75) + frame; + + return sectors; + } + + static UInt16 CDRWinTrackTypeToBytesPerSector(string trackType) + { + switch (trackType) + { + case CDRWinTrackTypeMode1: + case CDRWinTrackTypeMode2Form1: + return 2048; + case CDRWinTrackTypeMode2Form2: + return 2324; + case CDRWinTrackTypeMode2Formless: + case CDRWinTrackTypeCDI: + return 2336; + case CDRWinTrackTypeAudio: + case CDRWinTrackTypeMode1Raw: + case CDRWinTrackTypeMode2Raw: + case CDRWinTrackTypeCDIRaw: + return 2352; + case CDRWinTrackTypeCDG: + return 2448; + default: + return 0; + } + } + + static TrackType CDRWinTrackTypeToTrackType(string trackType) + { + switch (trackType) + { + case CDRWinTrackTypeMode1: + case CDRWinTrackTypeMode1Raw: + return TrackType.CDMode1; + case CDRWinTrackTypeMode2Form1: + return TrackType.CDMode2Form1; + case CDRWinTrackTypeMode2Form2: + return TrackType.CDMode2Form2; + case CDRWinTrackTypeCDIRaw: + case CDRWinTrackTypeCDI: + case CDRWinTrackTypeMode2Raw: + case CDRWinTrackTypeMode2Formless: + return TrackType.CDMode2Formless; + case CDRWinTrackTypeAudio: + case CDRWinTrackTypeCDG: + return TrackType.Audio; + default: + return TrackType.Data; + } + } + + static DiskType CDRWinIsoBusterDiscTypeToDiskType(string discType) + { + switch (discType) + { + case CDRWinDiskTypeCD: + return DiskType.CD; + case CDRWinDiskTypeCDRW: + case CDRWinDiskTypeCDMRW: + case CDRWinDiskTypeCDMRW2: + return DiskType.CDRW; + case CDRWinDiskTypeDVD: + return DiskType.DVDROM; + case CDRWinDiskTypeDVDPRW: + case CDRWinDiskTypeDVDPMRW: + case CDRWinDiskTypeDVDPMRW2: + return DiskType.DVDPRW; + case CDRWinDiskTypeDVDPRWDL: + case CDRWinDiskTypeDVDPMRWDL: + case CDRWinDiskTypeDVDPMRWDL2: + return DiskType.DVDPRWDL; + case CDRWinDiskTypeDVDPR: + case CDRWinDiskTypeDVDPVR: + return DiskType.DVDPR; + case CDRWinDiskTypeDVDPRDL: + return DiskType.DVDPRDL; + case CDRWinDiskTypeDVDRAM: + return DiskType.DVDRAM; + case CDRWinDiskTypeDVDVR: + case CDRWinDiskTypeDVDR: + return DiskType.DVDR; + case CDRWinDiskTypeDVDRDL: + return DiskType.DVDRDL; + case CDRWinDiskTypeDVDRW: + case CDRWinDiskTypeDVDRWDL: + case CDRWinDiskTypeDVDRW2: + return DiskType.DVDRW; + case CDRWinDiskTypeHDDVD: + return DiskType.HDDVDROM; + case CDRWinDiskTypeHDDVDRAM: + return DiskType.HDDVDRAM; + case CDRWinDiskTypeHDDVDR: + case CDRWinDiskTypeHDDVDRDL: + return DiskType.HDDVDR; + case CDRWinDiskTypeHDDVDRW: + case CDRWinDiskTypeHDDVDRWDL: + return DiskType.HDDVDRW; + case CDRWinDiskTypeBD: + return DiskType.BDROM; + case CDRWinDiskTypeBDR: + case CDRWinDiskTypeBDRDL: + return DiskType.BDR; + case CDRWinDiskTypeBDRE: + case CDRWinDiskTypeBDREDL: + return DiskType.BDRE; + default: + return DiskType.Unknown; + } + } + + #endregion + + #region Unsupported features + public override int GetDiskSequence() { - throw new FeatureSupportedButNotImplementedImageException("Feature not supported by image format"); + throw new FeatureUnsupportedImageException("Feature not supported by image format"); } public override int GetLastDiskSequence() { - throw new FeatureSupportedButNotImplementedImageException("Feature not supported by image format"); + throw new FeatureUnsupportedImageException("Feature not supported by image format"); } public override string GetDriveManufacturer() { - throw new FeatureSupportedButNotImplementedImageException("Feature not supported by image format"); + throw new FeatureUnsupportedImageException("Feature not supported by image format"); } public override string GetDriveModel() { - throw new FeatureSupportedButNotImplementedImageException("Feature not supported by image format"); + throw new FeatureUnsupportedImageException("Feature not supported by image format"); } public override string GetDriveSerialNumber() { - throw new FeatureSupportedButNotImplementedImageException("Feature not supported by image format"); + throw new FeatureUnsupportedImageException("Feature not supported by image format"); } public override string GetDiskPartNumber() { - throw new FeatureSupportedButNotImplementedImageException("Feature not supported by image format"); + throw new FeatureUnsupportedImageException("Feature not supported by image format"); } public override string GetDiskManufacturer() { - throw new FeatureSupportedButNotImplementedImageException("Feature not supported by image format"); + throw new FeatureUnsupportedImageException("Feature not supported by image format"); } public override string GetDiskModel() { - throw new FeatureSupportedButNotImplementedImageException("Feature not supported by image format"); + throw new FeatureUnsupportedImageException("Feature not supported by image format"); } public override string GetImageName() { - throw new FeatureSupportedButNotImplementedImageException("Feature not supported by image format"); + throw new FeatureUnsupportedImageException("Feature not supported by image format"); } public override string GetImageCreator() { - throw new FeatureSupportedButNotImplementedImageException("Feature not supported by image format"); + throw new FeatureUnsupportedImageException("Feature not supported by image format"); } -#endregion + + #endregion } } diff --git a/FileSystemIDandChk/ImagePlugins/ImagePlugin.cs b/FileSystemIDandChk/ImagePlugins/ImagePlugin.cs index 5dddb1877..491600368 100644 --- a/FileSystemIDandChk/ImagePlugins/ImagePlugin.cs +++ b/FileSystemIDandChk/ImagePlugins/ImagePlugin.cs @@ -9,283 +9,454 @@ namespace FileSystemIDandChk.ImagePlugins public string Name; public Guid PluginUUID; - protected ImagePlugin () + protected ImagePlugin() { } - // Basic image handling functions - public abstract bool IdentifyImage(string imagepath); // Returns true if the plugin can handle the given image file - public abstract bool OpenImage(string imagepath); // Initialize internal plugin structures to handle image - public abstract bool ImageHasPartitions(); // Image has different partitions (sessions, tracks) - + public abstract bool IdentifyImage(string imagePath); + // Returns true if the plugin can handle the given image file + public abstract bool OpenImage(string imagePath); + // Initialize internal plugin structures to handle image + public abstract bool ImageHasPartitions(); + // Image has different partitions (sessions, tracks) // Image size functions - public abstract UInt64 GetImageSize(); // Returns image size, without headers, in bytes - public abstract UInt64 GetSectors(); // Returns image size in sectors - public abstract UInt32 GetSectorSize(); // Returns sector size in bytes (user data only) - + public abstract UInt64 GetImageSize(); + // Returns image size, without headers, in bytes + public abstract UInt64 GetSectors(); + // Returns image size in sectors + public abstract UInt32 GetSectorSize(); + // Returns sector size in bytes (user data only) // Image reading functions - public abstract byte[] ReadDiskTag(DiskTagType tag); // Gets a disk tag - public abstract byte[] ReadSector(UInt64 SectorAddress); // Reads a sector (user data only) - public abstract byte[] ReadSectorTag(UInt64 SectorAddress, SectorTagType tag); // Reads specified tag from sector - public abstract byte[] ReadSector(UInt64 SectorAddress, UInt32 track); // Reads a sector (user data only), relative to track - public abstract byte[] ReadSectorTag(UInt64 SectorAddress, UInt32 track, SectorTagType tag); // Reads specified tag from sector - public abstract byte[] ReadSectors(UInt64 SectorAddress, UInt32 length); // Reads sector (user data only) - public abstract byte[] ReadSectorsTag(UInt64 SectorAddress, UInt32 length, SectorTagType tag); // Reads specified tag from sector - public abstract byte[] ReadSectors(UInt64 SectorAddress, UInt32 length, UInt32 track); // Reads a sector (user data only), relative to track - public abstract byte[] ReadSectorsTag(UInt64 SectorAddress, UInt32 length, UInt32 track, SectorTagType tag); // Reads specified tag from sector, relative to track - public abstract byte[] ReadSectorLong(UInt64 SectorAddress); // Reads a sector (user data + tags) - public abstract byte[] ReadSectorLong(UInt64 SectorAddress, UInt32 track); // Reads a sector (user data + tags), relative to track - public abstract byte[] ReadSectorsLong(UInt64 SectorAddress, UInt32 length); // Reads sector (user data + tags) - public abstract byte[] ReadSectorsLong(UInt64 SectorAddress, UInt32 length, UInt32 track); // Reads sectors (user data + tags), relative to track - + public abstract byte[] ReadDiskTag(DiskTagType tag); + // Gets a disk tag + public abstract byte[] ReadSector(UInt64 sectorAddress); + // Reads a sector (user data only) + public abstract byte[] ReadSectorTag(UInt64 sectorAddress, SectorTagType tag); + // Reads specified tag from sector + public abstract byte[] ReadSector(UInt64 sectorAddress, UInt32 track); + // Reads a sector (user data only), relative to track + public abstract byte[] ReadSectorTag(UInt64 sectorAddress, UInt32 track, SectorTagType tag); + // Reads specified tag from sector + public abstract byte[] ReadSectors(UInt64 sectorAddress, UInt32 length); + // Reads sector (user data only) + public abstract byte[] ReadSectorsTag(UInt64 sectorAddress, UInt32 length, SectorTagType tag); + // Reads specified tag from sector + public abstract byte[] ReadSectors(UInt64 sectorAddress, UInt32 length, UInt32 track); + // Reads a sector (user data only), relative to track + public abstract byte[] ReadSectorsTag(UInt64 sectorAddress, UInt32 length, UInt32 track, SectorTagType tag); + // Reads specified tag from sector, relative to track + public abstract byte[] ReadSectorLong(UInt64 sectorAddress); + // Reads a sector (user data + tags) + public abstract byte[] ReadSectorLong(UInt64 sectorAddress, UInt32 track); + // Reads a sector (user data + tags), relative to track + public abstract byte[] ReadSectorsLong(UInt64 sectorAddress, UInt32 length); + // Reads sector (user data + tags) + public abstract byte[] ReadSectorsLong(UInt64 sectorAddress, UInt32 length, UInt32 track); + // Reads sectors (user data + tags), relative to track // Image information functions - public abstract string GetImageFormat(); // Gets image format - public abstract string GetImageVersion(); // Gets format's version - public abstract string GetImageApplication(); // Gets application that created this image - public abstract string GetImageApplicationVersion(); // Gets application version - public abstract string GetImageCreator(); // Gets image creator (person) - public abstract DateTime GetImageCreationTime(); // Gets image creation time - public abstract DateTime GetImageLastModificationTime(); // Gets image last modification time - public abstract string GetImageName(); // Gets image name - public abstract string GetImageComments(); // Gets image comments - + public abstract string GetImageFormat(); + // Gets image format + public abstract string GetImageVersion(); + // Gets format's version + public abstract string GetImageApplication(); + // Gets application that created this image + public abstract string GetImageApplicationVersion(); + // Gets application version + public abstract string GetImageCreator(); + // Gets image creator (person) + public abstract DateTime GetImageCreationTime(); + // Gets image creation time + public abstract DateTime GetImageLastModificationTime(); + // Gets image last modification time + public abstract string GetImageName(); + // Gets image name + public abstract string GetImageComments(); + // Gets image comments // Functions to get information from disk represented by image - public abstract string GetDiskManufacturer(); // Gets disk manufacturer - public abstract string GetDiskModel(); // Gets disk model - public abstract string GetDiskSerialNumber(); // Gets disk serial number - public abstract string GetDiskBarcode(); // Gets disk (or product) - public abstract string GetDiskPartNumber(); // Gets disk part no. as manufacturer set - public abstract DiskType GetDiskType(); // Gets disk type - public abstract int GetDiskSequence(); // Gets disk sequence number, 1-starting - public abstract int GetLastDiskSequence(); // Gets last disk sequence number - + public abstract string GetDiskManufacturer(); + // Gets disk manufacturer + public abstract string GetDiskModel(); + // Gets disk model + public abstract string GetDiskSerialNumber(); + // Gets disk serial number + public abstract string GetDiskBarcode(); + // Gets disk (or product) + public abstract string GetDiskPartNumber(); + // Gets disk part no. as manufacturer set + public abstract DiskType GetDiskType(); + // Gets disk type + public abstract int GetDiskSequence(); + // Gets disk sequence number, 1-starting + public abstract int GetLastDiskSequence(); + // Gets last disk sequence number // Functions to get information from drive used to create image - public abstract string GetDriveManufacturer(); // Gets drive manufacturer - public abstract string GetDriveModel(); // Gets drive model - public abstract string GetDriveSerialNumber(); // Gets drive serial number - + public abstract string GetDriveManufacturer(); + // Gets drive manufacturer + public abstract string GetDriveModel(); + // Gets drive model + public abstract string GetDriveSerialNumber(); + // Gets drive serial number // Partitioning functions - public abstract List<PartPlugins.Partition> GetPartitions(); // Returns disc partitions, tracks, sessions, as partition extents - public abstract List<Track> GetTracks(); // Returns disc track extents - public abstract List<Track> GetSessionTracks(Session Session); // Returns disc track extensts for a session - public abstract List<Track> GetSessionTracks(UInt16 Session); // Returns disc track extensts for a session - public abstract List<Session> GetSessions(); // Returns disc sessions - + public abstract List<PartPlugins.Partition> GetPartitions(); + // Returns disc partitions, tracks, sessions, as partition extents + public abstract List<Track> GetTracks(); + // Returns disc track extents + public abstract List<Track> GetSessionTracks(Session session); + // Returns disc track extensts for a session + public abstract List<Track> GetSessionTracks(UInt16 session); + // Returns disc track extensts for a session + public abstract List<Session> GetSessions(); + // Returns disc sessions // CD flags bitmask public const byte CDFlagsFourChannel = 0x20; - public const byte CDFlagsDataTrack = 0x10; + public const byte CDFlagsDataTrack = 0x10; public const byte CDFlagsCopyPrevent = 0x08; public const byte CDFlagsPreEmphasis = 0x04; } - // Disk types public enum DiskType { Unknown, // Somewhat standard Compact Disc formats - CDDA, // CD Digital Audio (Red Book) - CDG, // CD+G (Red Book) - CDEG, // CD+EG (Red Book) - CDI, // CD-i (Green Book) - CDROM, // CD-ROM (Yellow Book) - CDROMXA, // CD-ROM XA (Yellow Book) - CDPLUS, // CD+ (Blue Book) - CDMO, // CD-MO (Orange Book) - CDR, // CD-Recordable (Orange Book) - CDRW, // CD-ReWritable (Orange Book) - CDMRW, // Mount-Rainier CD-RW - VCD, // Video CD (White Book) - SVCD, // Super Video CD (White Book) - PCD, // Photo CD (Beige Book) - SACD, // Super Audio CD (Scarlet Book) - DDCD, // Double-Density CD-ROM (Purple Book) - DDCDR, // DD CD-R (Purple Book) - DDCDRW, // DD CD-RW (Purple Book) - DTSCD, // DTS audio CD (non-standard) - CDMIDI, // CD-MIDI (Red Book) - CD, // Any unknown or standard violating CD + CDDA, + // CD Digital Audio (Red Book) + CDG, + // CD+G (Red Book) + CDEG, + // CD+EG (Red Book) + CDI, + // CD-i (Green Book) + CDROM, + // CD-ROM (Yellow Book) + CDROMXA, + // CD-ROM XA (Yellow Book) + CDPLUS, + // CD+ (Blue Book) + CDMO, + // CD-MO (Orange Book) + CDR, + // CD-Recordable (Orange Book) + CDRW, + // CD-ReWritable (Orange Book) + CDMRW, + // Mount-Rainier CD-RW + VCD, + // Video CD (White Book) + SVCD, + // Super Video CD (White Book) + PCD, + // Photo CD (Beige Book) + SACD, + // Super Audio CD (Scarlet Book) + DDCD, + // Double-Density CD-ROM (Purple Book) + DDCDR, + // DD CD-R (Purple Book) + DDCDRW, + // DD CD-RW (Purple Book) + DTSCD, + // DTS audio CD (non-standard) + CDMIDI, + // CD-MIDI (Red Book) + CD, + // Any unknown or standard violating CD // Standard DVD formats - DVDROM, // DVD-ROM (applies to DVD Video and DVD Audio) - DVDR, // DVD-R - DVDRW, // DVD-RW - DVDPR, // DVD+R - DVDPRW, // DVD+RW - DVDPRWDL, // DVD+RW DL - DVDRDL, // DVD-R DL - DVDPRDL, // DVD+R DL - DVDRAM, // DVD-RAM + DVDROM, + // DVD-ROM (applies to DVD Video and DVD Audio) + DVDR, + // DVD-R + DVDRW, + // DVD-RW + DVDPR, + // DVD+R + DVDPRW, + // DVD+RW + DVDPRWDL, + // DVD+RW DL + DVDRDL, + // DVD-R DL + DVDPRDL, + // DVD+R DL + DVDRAM, + // DVD-RAM // Standard HD-DVD formats - HDDVDROM, // HD DVD-ROM (applies to HD DVD Video) - HDDVDRAM, // HD DVD-RAM - HDDVDR, // HD DVD-R - HDDVDRW, // HD DVD-RW + HDDVDROM, + // HD DVD-ROM (applies to HD DVD Video) + HDDVDRAM, + // HD DVD-RAM + HDDVDR, + // HD DVD-R + HDDVDRW, + // HD DVD-RW // Standard Blu-ray formats - BDROM, // BD-ROM (and BD Video) - BDR, // BD-R - BDRE, // BD-RE + BDROM, + // BD-ROM (and BD Video) + BDR, + // BD-R + BDRE, + // BD-RE // Rare or uncommon standards - EVD, // Enhanced Versatile Disc - FVD, // Forward Versatile Disc - HVD, // Holographic Versatile Disc - CBHD, // China Blue High Definition - HDVMD, // High Definition Versatile Multilayer Disc - VCDHD, // Versatile Compact Disc High Density - LD, // Pioneer LaserDisc - LDROM, // Pioneer LaserDisc data - MD, // Sony MiniDisc - HiMD, // Sony Hi-MD - UDO, // Ultra Density Optical - SVOD, // Stacked Volumetric Optical Disc - FDDVD, // Five Dimensional disc + EVD, + // Enhanced Versatile Disc + FVD, + // Forward Versatile Disc + HVD, + // Holographic Versatile Disc + CBHD, + // China Blue High Definition + HDVMD, + // High Definition Versatile Multilayer Disc + VCDHD, + // Versatile Compact Disc High Density + LD, + // Pioneer LaserDisc + LDROM, + // Pioneer LaserDisc data + MD, + // Sony MiniDisc + HiMD, + // Sony Hi-MD + UDO, + // Ultra Density Optical + SVOD, + // Stacked Volumetric Optical Disc + FDDVD, + // Five Dimensional disc // Propietary game discs - PS1CD, // Sony PlayStation game CD - PS2CD, // Sony PlayStation 2 game CD - PS2DVD, // Sony PlayStation 2 game DVD - PS3DVD, // Sony PlayStation 3 game DVD - PS3BD, // Sony PlayStation 3 game Blu-ray - PS4BD, // Sony PlayStation 4 game Blu-ray - UMD, // Sony PlayStation Portable Universal Media Disc (ECMA-365) - GOD, // Nintendo GameCube Optical Disc - WOD, // Nintendo Wii Optical Disc - WUOD, // Nintendo Wii U Optical Disc - XGD, // Microsoft X-box Game Disc - XGD2, // Microsoft X-box 360 Game Disc - XGD3, // Microsoft X-box 360 Game Disc - XGD4, // Microsoft X-box One Game Disc - MEGACD, // Sega MegaCD - SATURNCD, // Sega Saturn disc - GDROM, // Sega/Yamaha Gigabyte Disc - GDR // Sega/Yamaha recordable Gigabyte Disc - }; + PS1CD, + // Sony PlayStation game CD + PS2CD, + // Sony PlayStation 2 game CD + PS2DVD, + // Sony PlayStation 2 game DVD + PS3DVD, + // Sony PlayStation 3 game DVD + PS3BD, + // Sony PlayStation 3 game Blu-ray + PS4BD, + // Sony PlayStation 4 game Blu-ray + UMD, + // Sony PlayStation Portable Universal Media Disc (ECMA-365) + GOD, + // Nintendo GameCube Optical Disc + WOD, + // Nintendo Wii Optical Disc + WUOD, + // Nintendo Wii U Optical Disc + XGD, + // Microsoft X-box Game Disc + XGD2, + // Microsoft X-box 360 Game Disc + XGD3, + // Microsoft X-box 360 Game Disc + XGD4, + // Microsoft X-box One Game Disc + MEGACD, + // Sega MegaCD + SATURNCD, + // Sega Saturn disc + GDROM, + // Sega/Yamaha Gigabyte Disc + GDR + // Sega/Yamaha recordable Gigabyte Disc}} + }; // Track (as partitioning element) types public enum TrackType { - Audio, // Audio track - Data, // Data track (not any of the below defined ones) - CDMode1, // Data track, compact disc mode 1 - CDMode2Formless, // Data track, compact disc mode 2, formless - CDMode2Form1, // Data track, compact disc mode 2, form 1 - CDMode2Form2 // Data track, compact disc mode 2, form 2 - }; + Audio, + // Audio track + Data, + // Data track (not any of the below defined ones) + CDMode1, + // Data track, compact disc mode 1 + CDMode2Formless, + // Data track, compact disc mode 2, formless + CDMode2Form1, + // Data track, compact disc mode 2, form 1 + CDMode2Form2 + // Data track, compact disc mode 2, form 2}} + }; // Track defining structure public struct Track { - public UInt32 TrackSequence; // Track number, 1-started - public TrackType TrackType; // Partition type - public UInt64 TrackStartSector; // Track starting sector - public UInt64 TrackEndSector; // Track ending sector - public UInt64 TrackPregap; // Track pre-gap - public UInt16 TrackSession; // Session this track belongs to - public string TrackDescription; // Information that does not find space in this struct + public UInt32 TrackSequence; + // Track number, 1-started + public TrackType TrackType; + // Partition type + public UInt64 TrackStartSector; + // Track starting sector + public UInt64 TrackEndSector; + // Track ending sector + public UInt64 TrackPregap; + // Track pre-gap + public UInt16 TrackSession; + // Session this track belongs to + public string TrackDescription; + // Information that does not find space in this struct + public Dictionary<int, UInt64> Indexes; + // Indexes, 00 to 99 and sector offset } - - // Track index (subpartitioning) - public struct TrackIndex - { - public byte IndexSequence; // Index number (00 to 99) - public UInt64 IndexOffset; // Index sector - } - // Session defining structure public struct Session { - public UInt16 SessionSequence; // Session number, 1-started - public UInt32 StartTrack; // First track present on this session - public UInt32 EndTrack; // Last track present on this session - public UInt64 StartSector; // First sector present on this session - public UInt64 EndSector; // Last sector present on this session + public UInt16 SessionSequence; + // Session number, 1-started + public UInt32 StartTrack; + // First track present on this session + public UInt32 EndTrack; + // Last track present on this session + public UInt64 StartSector; + // First sector present on this session + public UInt64 EndSector; + // Last sector present on this session } - // Metadata present for each sector (aka, "tag") public enum SectorTagType { - AppleSectorTag, // Apple's GCR sector tags, 20 bytes - CDSectorSync, // Sync frame from CD sector, 12 bytes - CDSectorHeader, // CD sector header, 4 bytes - CDSectorSubHeader, // CD mode 2 sector subheader - CDSectorEDC, // CD sector EDC, 4 bytes - CDSectorECC_P, // CD sector ECC P, 172 bytes - CDSectorECC_Q, // CD sector ECC Q, 104 bytes - CDSectorECC, // CD sector ECC (P and Q), 276 bytes - CDSectorSubchannel, // CD sector subchannel, 96 bytes - CDTrackISRC, // CD track ISRC, string, 12 bytes - CDTrackText, // CD track text, string, 13 bytes - CDTrackFlags, // CD track flags, 1 byte - DVD_CMI // DVD sector copyright information - }; + AppleSectorTag, + // Apple's GCR sector tags, 20 bytes + CDSectorSync, + // Sync frame from CD sector, 12 bytes + CDSectorHeader, + // CD sector header, 4 bytes + CDSectorSubHeader, + // CD mode 2 sector subheader + CDSectorEDC, + // CD sector EDC, 4 bytes + CDSectorECC_P, + // CD sector ECC P, 172 bytes + CDSectorECC_Q, + // CD sector ECC Q, 104 bytes + CDSectorECC, + // CD sector ECC (P and Q), 276 bytes + CDSectorSubchannel, + // CD sector subchannel, 96 bytes + CDTrackISRC, + // CD track ISRC, string, 12 bytes + CDTrackText, + // CD track text, string, 13 bytes + CDTrackFlags, + // CD track flags, 1 byte + DVD_CMI + // DVD sector copyright information}} + }; // Metadata present for each disk public enum DiskTagType { - CD_PMA, // CD PMA - CD_ATIP, // CD Adress-Time-In-Pregroove - CD_TEXT, // CD-Text - CD_MCN, // CD Media Catalogue Number - DVD_BCA, // DVD Burst Cutting Area - DVD_PFI, // DVD Physical Format Information - DVD_CMI, // DVD Copyright Management Information - DVD_DMI // DVD Disc Manufacturer Information - }; + CD_PMA, + // CD PMA + CD_ATIP, + // CD Adress-Time-In-Pregroove + CD_TEXT, + // CD-Text + CD_MCN, + // CD Media Catalogue Number + DVD_BCA, + // DVD Burst Cutting Area + DVD_PFI, + // DVD Physical Format Information + DVD_CMI, + // DVD Copyright Management Information + DVD_DMI + // DVD Disc Manufacturer Information}} + }; // Feature is supported by image but not implemented yet - [Serializable()] - public class FeatureSupportedButNotImplementedImageException : System.Exception + [Serializable] + public class FeatureSupportedButNotImplementedImageException : Exception { - public FeatureSupportedButNotImplementedImageException() : base() { } - public FeatureSupportedButNotImplementedImageException(string message) : base(message) { } - public FeatureSupportedButNotImplementedImageException(string message, System.Exception inner) : base(message, inner) { } + 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) { } + System.Runtime.Serialization.StreamingContext context) + { + if (info == null) + throw new ArgumentNullException("info"); + } } - // Feature is not supported by image - [Serializable()] - public class FeatureUnsupportedImageException : System.Exception + [Serializable] + public class FeatureUnsupportedImageException : Exception { - public FeatureUnsupportedImageException() : base() { } - public FeatureUnsupportedImageException(string message) : base(message) { } - public FeatureUnsupportedImageException(string message, System.Exception inner) : base(message, inner) { } + 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) { } + System.Runtime.Serialization.StreamingContext context) + { + if (info == null) + throw new ArgumentNullException("info"); + } } - // Feature is supported by image but not present on it - [Serializable()] - public class FeatureNotPresentImageException : System.Exception + [Serializable] + public class FeatureNotPresentImageException : Exception { - public FeatureNotPresentImageException() : base() { } - public FeatureNotPresentImageException(string message) : base(message) { } - public FeatureNotPresentImageException(string message, System.Exception inner) : base(message, inner) { } + 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) { } + System.Runtime.Serialization.StreamingContext context) + { + if (info == null) + throw new ArgumentNullException("info"); + } } - // Feature is supported by image but not by the disc it represents - [Serializable()] - public class FeaturedNotSupportedByDiscImageException : System.Exception + [Serializable] + public class FeaturedNotSupportedByDiscImageException : Exception { - public FeaturedNotSupportedByDiscImageException() : base() { } - public FeaturedNotSupportedByDiscImageException(string message) : base(message) { } - public FeaturedNotSupportedByDiscImageException(string message, System.Exception inner) : base(message, inner) { } + 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) { } + System.Runtime.Serialization.StreamingContext context) + { + if (info == null) + throw new ArgumentNullException("info"); + } } - // Corrupt, incorrect or unhandled feature found on image - [Serializable()] - public class ImageNotSupportedException : System.Exception + [Serializable] + public class ImageNotSupportedException : Exception { - public ImageNotSupportedException() : base() { } - public ImageNotSupportedException(string message) : base(message) { } - public ImageNotSupportedException(string message, System.Exception inner) : base(message, inner) { } + 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) { } + System.Runtime.Serialization.StreamingContext context) + { + if (info == null) + throw new ArgumentNullException("info"); + } } } \ No newline at end of file diff --git a/FileSystemIDandChk/Main.cs b/FileSystemIDandChk/Main.cs index aea737fe9..7edb44fcd 100644 --- a/FileSystemIDandChk/Main.cs +++ b/FileSystemIDandChk/Main.cs @@ -20,70 +20,76 @@ namespace FileSystemIDandChk chkPartitions = true; chkFilesystems = true; - isDebug = false; + // RELEASE + //isDebug = false; + // DEBUG + isDebug = true; Console.WriteLine ("Filesystem Identifier and Checker"); Console.WriteLine ("Copyright (C) Natalia Portillo, All Rights Reserved"); // For debug - plugins.RegisterAllPlugins(); - Runner(""); - - /* - if(args.Length==0) - { - Usage(); - } - else if(args.Length==1) - { - plugins.RegisterAllPlugins(); + if (isDebug) + { + plugins.RegisterAllPlugins(); + Runner("/Users/claunia/Desktop/disk_images/cdrom.cue"); + } + 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; - default: - break; - } - } + 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; + default: + break; + } + } - Runner(args[args.Length-1]); - } - */ + Runner(args[args.Length - 1]); + } + } } private static void Runner (string filename) @@ -101,9 +107,6 @@ namespace FileSystemIDandChk foreach(ImagePlugin _imageplugin in plugins.ImagePluginsList.Values) { - // DEBUG - filename = "/Users/claunia/Desktop/disk_images/cdrom.cue"; - if(_imageplugin.IdentifyImage(filename)) { _imageFormat = _imageplugin; @@ -123,7 +126,9 @@ namespace FileSystemIDandChk if(_imageFormat.OpenImage(filename)) { Console.WriteLine("DEBUG: Correctly opened image file."); - return; + + Console.WriteLine("DEBUG: Image without headers is {0} bytes.", _imageFormat.GetImageSize()); + Console.WriteLine("DEBUG: Image has {0} sectors.", _imageFormat.GetSectors()); } else { @@ -139,29 +144,35 @@ namespace FileSystemIDandChk return; } - // All commented until image formats are implemented correctly. - /* - stream = File.OpenRead(filename); - + 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(stream, out _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=="") { + Console.WriteLine("DEBUG: No partitions found"); if(!chkFilesystems) { Console.WriteLine("No partitions founds, not searching for filesystems"); @@ -190,7 +201,7 @@ namespace FileSystemIDandChk { Console.WriteLine("Identifying filesystem on partition"); - Identify(stream, out id_plugins, partitions[i].PartitionStart); + Identify(_imageFormat, out id_plugins, partitions[i].PartitionStart); if(id_plugins.Count==0) Console.WriteLine("Filesystem not identified"); else if(id_plugins.Count>1) @@ -202,7 +213,7 @@ namespace FileSystemIDandChk if(plugins.PluginsList.TryGetValue(plugin_name, out _plugin)) { Console.WriteLine(String.Format("As identified by {0}.", _plugin.Name)); - _plugin.GetInformation(stream, partitions[i].PartitionStart, out information); + _plugin.GetInformation(_imageFormat, partitions[i].PartitionStart, out information); Console.Write(information); } } @@ -211,7 +222,7 @@ namespace FileSystemIDandChk { plugins.PluginsList.TryGetValue(id_plugins[0], out _plugin); Console.WriteLine(String.Format("Identified by {0}.", _plugin.Name)); - _plugin.GetInformation(stream, partitions[i].PartitionStart, out information); + _plugin.GetInformation(_imageFormat, partitions[i].PartitionStart, out information); Console.Write(information); } } @@ -219,9 +230,9 @@ namespace FileSystemIDandChk } } - if(checkraw) + if(checkraw) { - Identify(stream, out id_plugins, 0); + Identify(_imageFormat, out id_plugins, 0); if(id_plugins.Count==0) Console.WriteLine("Filesystem not identified"); else if(id_plugins.Count>1) @@ -233,7 +244,7 @@ namespace FileSystemIDandChk if(plugins.PluginsList.TryGetValue(plugin_name, out _plugin)) { Console.WriteLine(String.Format("As identified by {0}.", _plugin.Name)); - _plugin.GetInformation(stream, 0, out information); + _plugin.GetInformation(_imageFormat, 0, out information); Console.Write(information); } } @@ -242,11 +253,10 @@ namespace FileSystemIDandChk { plugins.PluginsList.TryGetValue(id_plugins[0], out _plugin); Console.WriteLine(String.Format("Identified by {0}.", _plugin.Name)); - _plugin.GetInformation(stream, 0, out information); + _plugin.GetInformation(_imageFormat, 0, out information); Console.Write(information); } } - */ } catch(Exception ex) { @@ -260,13 +270,13 @@ namespace FileSystemIDandChk } } - private static void Identify (FileStream stream, out List<string> id_plugins, long offset) + private static void Identify (ImagePlugins.ImagePlugin imagePlugin, out List<string> id_plugins, ulong partitionOffset) { id_plugins = new List<string>(); foreach (Plugin _plugin in plugins.PluginsList.Values) { - if (_plugin.Identify(stream, offset)) + if (_plugin.Identify(imagePlugin, partitionOffset)) id_plugins.Add(_plugin.Name.ToLower()); } } diff --git a/FileSystemIDandChk/PartPlugins/AppleMap.cs b/FileSystemIDandChk/PartPlugins/AppleMap.cs index 42341d629..45187bf60 100644 --- a/FileSystemIDandChk/PartPlugins/AppleMap.cs +++ b/FileSystemIDandChk/PartPlugins/AppleMap.cs @@ -14,121 +14,121 @@ namespace FileSystemIDandChk.PartPlugins public AppleMap (PluginBase Core) { - base.Name = "Apple Partition Map"; - base.PluginUUID = new Guid("36405F8D-4F1A-07F5-209C-223D735D6D22"); + Name = "Apple Partition Map"; + PluginUUID = new Guid("36405F8D-4F1A-07F5-209C-223D735D6D22"); } - public override bool GetInformation (FileStream stream, out List<Partition> partitions) + 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(); - EndianAwareBinaryReader eabr = new EndianAwareBinaryReader(stream, false); // BigEndian - eabr.BaseStream.Seek(0, SeekOrigin.Begin); - APMB.signature = eabr.ReadUInt16(); - - if(APMB.signature == APM_MAGIC) - { - APMB.sector_size = eabr.ReadUInt16(); - } - else - APMB.sector_size = 512; // Some disks omit the boot entry + byte[] APMB_sector = imagePlugin.ReadSector(0); - if(APMB.sector_size == 2048) // A CD, search if buggy (aligns in 512 bytes blocks) first - { - eabr.BaseStream.Seek(512, SeekOrigin.Begin); // Seek to first entry - APMEntry.signature = eabr.ReadUInt16(); - if(APMEntry.signature != APM_ENTRY && APMEntry.signature != APM_OLDENT) // It should have partition entry signature if buggy - { - eabr.BaseStream.Seek(2048, SeekOrigin.Begin); // Seek to first entry considering 2048 bytes blocks. Unbuggy. - APMEntry.signature = eabr.ReadUInt16(); - if(APMEntry.signature != APM_ENTRY && APMEntry.signature != APM_OLDENT) - return false; - else - APMB.sector_size = 2048; - } - else - APMB.sector_size = 512; - } - else - { - eabr.BaseStream.Seek(APMB.sector_size, SeekOrigin.Begin); // Seek to first entry - APMEntry.signature = eabr.ReadUInt16(); - if(APMEntry.signature != APM_ENTRY && APMEntry.signature != APM_OLDENT) // It should have partition entry signature if buggy - { - eabr.BaseStream.Seek(512, SeekOrigin.Begin); // Seek to first entry considering 512 bytes blocks. Buggy. - APMEntry.signature = eabr.ReadUInt16(); - if(APMEntry.signature != APM_ENTRY && APMEntry.signature != APM_OLDENT) - return false; - else - APMB.sector_size = 512; - } - } + 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); - eabr.BaseStream.Seek(2, SeekOrigin.Current); // Skip reserved1 - APMEntry.entries = eabr.ReadUInt32(); - if(APMEntry.entries <= 1) // It should have more than one entry - return false; + 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; -// eabr.BaseStream.Seek(4, SeekOrigin.Current); // Skip start, we don't need it -// eabr.BaseStream.Seek(4, SeekOrigin.Current); // Skip sectors, we don't need it -// eabr.BaseStream.Seek(32, SeekOrigin.Current); // Skip name, we don't ned it - -// cString = eabr.ReadBytes(32); -// APMEntry.type = StringHandlers.CToString(cString); -// if(APMEntry.type != "Apple_partition_map") // APM self-describes, if not, this is incorrect -// return false; - - apm_entries = APMEntry.entries; - - for(ulong i = 1; i <= apm_entries; i++) // For each partition + for(ulong i = 0; i < apm_entries; i++) // For each partition { - APMEntry = new AppleMapPartitionEntry(); - - eabr.BaseStream.Seek((long)(APMB.sector_size*i), SeekOrigin.Begin); // Seek to partition descriptor - //eabr.BaseStream.Seek((long)(0x200*i), SeekOrigin.Begin); // Seek to partition descriptor - - APMEntry.signature = eabr.ReadUInt16(); - if(APMEntry.signature == APM_ENTRY || APMEntry.signature == APM_OLDENT) // It should have partition entry signature + 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(); - eabr.BaseStream.Seek(2, SeekOrigin.Current); // Skip reserved1 - eabr.BaseStream.Seek(4, SeekOrigin.Current); // Skip entries - - APMEntry.start = eabr.ReadUInt32(); - APMEntry.sectors = eabr.ReadUInt32(); - cString = eabr.ReadBytes(32); - APMEntry.name = StringHandlers.CToString(cString); - cString = eabr.ReadBytes(32); - APMEntry.type = StringHandlers.CToString(cString); - APMEntry.first_data_block = eabr.ReadUInt32(); - APMEntry.data_sectors = eabr.ReadUInt32(); - APMEntry.status = eabr.ReadUInt32(); - APMEntry.first_boot_block = eabr.ReadUInt32(); - APMEntry.boot_size = eabr.ReadUInt32(); - APMEntry.load_address = eabr.ReadUInt32(); - eabr.BaseStream.Seek(4, SeekOrigin.Current); - APMEntry.entry_point = eabr.ReadUInt32(); - eabr.BaseStream.Seek(4, SeekOrigin.Current); - APMEntry.checksum = eabr.ReadUInt32(); - cString = eabr.ReadBytes(16); - APMEntry.processor = StringHandlers.CToString(cString); - _partition.PartitionSequence = i; _partition.PartitionType = APMEntry.type; _partition.PartitionName = APMEntry.name; -// _partition.PartitionStart = APMEntry.start * 0x200; // This seems to be hardcoded - _partition.PartitionStart = APMEntry.start * APMB.sector_size; -// _partition.PartitionLength = APMEntry.sectors * 0x200; // This seems to be hardcoded - _partition.PartitionLength = APMEntry.sectors * APMB.sector_size; + _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) diff --git a/FileSystemIDandChk/PartPlugins/MBR.cs b/FileSystemIDandChk/PartPlugins/MBR.cs index b063928e4..4423c7c6c 100644 --- a/FileSystemIDandChk/PartPlugins/MBR.cs +++ b/FileSystemIDandChk/PartPlugins/MBR.cs @@ -4,300 +4,325 @@ using System.Text; using System.Collections.Generic; using FileSystemIDandChk; +// TODO: Support AAP, AST, SpeedStor and Ontrack extensions namespace FileSystemIDandChk.PartPlugins { - class MBR : PartPlugin - { - public MBR (PluginBase Core) - { + class MBR : PartPlugin + { + const UInt16 MBRSignature = 0xAA55; + + public MBR(PluginBase Core) + { base.Name = "Master Boot Record"; - base.PluginUUID = new Guid("5E8A34E8-4F1A-59E6-4BF7-7EA647063A76"); - } - - public override bool GetInformation (FileStream stream, out List<Partition> partitions) - { - byte cyl_sect1, cyl_sect2; // For decoding cylinder and sector - UInt16 signature; - UInt32 serial; - ulong counter = 0; + base.PluginUUID = new Guid("5E8A34E8-4F1A-59E6-4BF7-7EA647063A76"); + } + + public override bool GetInformation(ImagePlugins.ImagePlugin imagePlugin, out List<Partition> partitions) + { + byte cyl_sect1, cyl_sect2; // For decoding cylinder and sector + UInt16 signature; + UInt32 serial; + ulong counter = 0; - partitions = new List<Partition>(); + partitions = new List<Partition>(); - BinaryReader br = new BinaryReader(stream); + byte[] sector = imagePlugin.ReadSector(0); - br.BaseStream.Seek(0x01FE, SeekOrigin.Begin); - signature = br.ReadUInt16(); + signature = BitConverter.ToUInt16(sector, 0x1FE); - if(signature != 0xAA55) - return false; // Not MBR + if (signature != MBRSignature) + return false; // Not MBR - br.BaseStream.Seek(0x01B8, SeekOrigin.Begin); - serial = br.ReadUInt32(); // Not useful right now + serial = BitConverter.ToUInt32(sector, 0x1B8); - br.BaseStream.Seek(0x01BE, SeekOrigin.Begin); - for(int i = 0; i < 4; i ++) - { - MBRPartitionEntry entry = new MBRPartitionEntry(); + for (int i = 0; i < 4; i++) + { + MBRPartitionEntry entry = new MBRPartitionEntry(); - entry.status = br.ReadByte(); - entry.start_head = br.ReadByte(); - - cyl_sect1 = br.ReadByte(); - cyl_sect2 = br.ReadByte(); - - entry.start_sector = (byte)(cyl_sect1 & 0x3F); - entry.start_cylinder = (ushort)(((cyl_sect1 & 0xC0) << 2) | cyl_sect2); - - entry.type = br.ReadByte(); - entry.end_head = br.ReadByte(); + entry.status = sector[0x1BE + 16 * i + 0x00]; + entry.start_head = sector[0x1BE + 16 * i + 0x00]; - cyl_sect1 = br.ReadByte(); - cyl_sect2 = br.ReadByte(); - - entry.end_sector = (byte)(cyl_sect1 & 0x3F); - entry.end_cylinder = (ushort)(((cyl_sect1 & 0xC0) << 2) | cyl_sect2); - - entry.lba_start = br.ReadUInt32(); - entry.lba_sectors = br.ReadUInt32(); - - // Let's start the fun... - - bool valid = true; - bool extended = false; - bool disklabel = false; + cyl_sect1 = sector[0x1BE + 16 * i + 0x00]; + cyl_sect2 = sector[0x1BE + 16 * i + 0x00]; - if(entry.status != 0x00 && entry.status != 0x80) - return false; // Maybe a FAT filesystem - if(entry.type == 0x00) - valid = false; - if(entry.type == 0xEE || entry.type == 0xEF) - return false; // This is a GPT - if(entry.type == 0x05 || entry.type == 0x0F || entry.type == 0x85) - { - valid = false; - extended = true; // Extended partition - } - if(entry.type == 0x82 || entry.type == 0xBF || entry.type == 0xA5 || entry.type == 0xA6 || entry.type == 0xA9 || - entry.type == 0xB7 || entry.type == 0x81 || entry.type == 0x63) - { - valid = false; - disklabel = true; - } + entry.start_sector = (byte)(cyl_sect1 & 0x3F); + entry.start_cylinder = (ushort)(((cyl_sect1 & 0xC0) << 2) | cyl_sect2); - if(disklabel) - { - long currentPos = br.BaseStream.Position; - long disklabel_start = entry.lba_start * 512; + entry.type = sector[0x1BE + 16 * i + 0x00]; + entry.end_head = sector[0x1BE + 16 * i + 0x00]; + + cyl_sect1 = sector[0x1BE + 16 * i + 0x00]; + cyl_sect2 = sector[0x1BE + 16 * i + 0x00]; + + entry.end_sector = (byte)(cyl_sect1 & 0x3F); + entry.end_cylinder = (ushort)(((cyl_sect1 & 0xC0) << 2) | cyl_sect2); + + entry.lba_start = BitConverter.ToUInt32(sector, 0x1BE + 16 * i + 0x00); + entry.lba_sectors = BitConverter.ToUInt32(sector, 0x1BE + 16 * i + 0x00); + + // Let's start the fun... + + bool valid = true; + bool extended = false; + bool disklabel = false; + + if (entry.status != 0x00 && entry.status != 0x80) + return false; // Maybe a FAT filesystem + if (entry.type == 0x00) + valid = false; + if (entry.type == 0xEE || entry.type == 0xEF) + return false; // This is a GPT + if (entry.type == 0x05 || entry.type == 0x0F || entry.type == 0x85) + { + valid = false; + extended = true; // Extended partition + } + if (entry.type == 0x82 || entry.type == 0xBF || entry.type == 0xA5 || entry.type == 0xA6 || entry.type == 0xA9 || + entry.type == 0xB7 || entry.type == 0x81 || entry.type == 0x63) + { + valid = false; + disklabel = true; + } + + if (entry.lba_start == 0 && entry.lba_sectors == 0 && entry.start_cylinder == 0 && entry.start_head == 0 && entry.start_sector == 0 && entry.end_cylinder == 0 && entry.end_head == 0 && entry.end_sector == 0) + valid = false; + if (entry.lba_start == 0 && entry.lba_sectors == 0 && valid) + { + entry.lba_start = CHStoLBA(entry.start_cylinder, entry.start_head, entry.start_sector); + entry.lba_sectors = CHStoLBA(entry.end_cylinder, entry.end_head, entry.end_sector) - entry.lba_start; + } + + if (entry.lba_start > imagePlugin.GetSectors() || entry.lba_start + entry.lba_sectors > imagePlugin.GetSectors()) + { + valid = false; + disklabel = false; + extended = false; + } + + if (disklabel) + { + byte[] disklabel_sector = imagePlugin.ReadSector(entry.lba_start); - br.BaseStream.Seek(disklabel_start, SeekOrigin.Begin); - - switch(entry.type) - { - case 0xA5: - case 0xA6: - case 0xA9: - case 0xB7: // BSD disklabels - { - UInt32 magic; - magic = br.ReadUInt32(); + switch (entry.type) + { + case 0xA5: + case 0xA6: + case 0xA9: + case 0xB7: // BSD disklabels + { + UInt32 magic = BitConverter.ToUInt32(disklabel_sector, 0); - if(magic == 0x82564557) - { - br.BaseStream.Seek(126, SeekOrigin.Current); - UInt16 no_parts = br.ReadUInt16(); - br.BaseStream.Seek(8, SeekOrigin.Current); - - for(int j = 0; j < no_parts; j++) - { - Partition part = new Partition(); - byte bsd_type; - - part.PartitionLength = br.ReadUInt32()*512; - part.PartitionStart = br.ReadUInt32()*512; - br.BaseStream.Seek(4, SeekOrigin.Current); - bsd_type = br.ReadByte(); - br.BaseStream.Seek(3, SeekOrigin.Current); - - part.PartitionType = String.Format("BSD: {0}", bsd_type); - part.PartitionName = decodeBSDType(bsd_type); - - part.PartitionSequence = counter; - part.PartitionDescription = "Partition inside a BSD disklabel."; - - if(bsd_type!=0) - { - partitions.Add(part); - counter++; - } - } - } - else - valid=true; - break; - } - case 0x63: // UNIX disklabel - { - UInt32 magic; - br.BaseStream.Seek(29*0x200 + 4, SeekOrigin.Current); // Starts on sector 29 of partition - magic = br.ReadUInt32(); - - if(magic == UNIXDiskLabel_MAGIC) - { - UNIXDiskLabel dl = new UNIXDiskLabel(); - bool isNewDL = false; - - dl.version = br.ReadUInt32(); - dl.serial = StringHandlers.CToString(br.ReadBytes(12)); - dl.cyls = br.ReadUInt32(); - dl.trks = br.ReadUInt32(); - dl.secs = br.ReadUInt32(); - dl.bps = br.ReadUInt32(); - dl.start = br.ReadUInt32(); - dl.unknown1 = br.ReadBytes(48); - dl.alt_tbl = br.ReadUInt32(); - dl.alt_len = br.ReadUInt32(); - dl.phys_cyl = br.ReadUInt32(); - - if(dl.phys_cyl != UNIXVTOC_MAGIC) // Old version VTOC starts here - { - isNewDL = true; - dl.phys_trk = br.ReadUInt32(); - dl.phys_sec = br.ReadUInt32(); - dl.phys_bytes = br.ReadUInt32(); - dl.unknown2 = br.ReadUInt32(); - dl.unknown3 = br.ReadUInt32(); - dl.pad = br.ReadBytes(48); - } - else - br.BaseStream.Seek(-4, SeekOrigin.Current); // Return to old VTOC magic - - UNIXVTOC vtoc = new UNIXVTOC(); - - vtoc.magic = br.ReadUInt32(); - - if(vtoc.magic == UNIXVTOC_MAGIC) - { - vtoc.version = br.ReadUInt32(); - vtoc.name = StringHandlers.CToString(br.ReadBytes(8)); - vtoc.slices = br.ReadUInt16(); - vtoc.unknown = br.ReadUInt16(); - vtoc.reserved = br.ReadBytes(40); - - for(int j = 0; j < vtoc.slices; j++) - { - UNIXVTOCEntry vtoc_ent = new UNIXVTOCEntry(); - - vtoc_ent.tag = br.ReadUInt16(); - vtoc_ent.flags = br.ReadUInt16(); - vtoc_ent.start = br.ReadUInt32(); - vtoc_ent.length = br.ReadUInt32(); - - if((vtoc_ent.flags & 0x200) == 0x200 && vtoc_ent.tag != UNIX_TAG_EMPTY && vtoc_ent.tag != UNIX_TAG_WHOLE) - { - Partition part = new Partition(); - part.PartitionStart = vtoc_ent.start * dl.bps; - part.PartitionLength = vtoc_ent.length * dl.bps; - part.PartitionSequence = counter; - part.PartitionType = String.Format("UNIX: {0}", decodeUNIXTAG(vtoc_ent.tag, isNewDL)); - - string info = ""; - - if((vtoc_ent.flags & 0x01) == 0x01) - info += " (do not mount)"; - if((vtoc_ent.flags & 0x10) == 0x10) - info += " (do not mount)"; - - part.PartitionDescription = "UNIX slice" + info + "."; + if (magic == 0x82564557) + { + UInt16 no_parts = BitConverter.ToUInt16(disklabel_sector, 126); - partitions.Add(part); - counter++; - } - } - } - } - else - valid = true; - break; - } - case 0x82: - case 0xBF: // Solaris disklabel - { - UInt32 magic; - UInt32 version; - br.BaseStream.Seek(12, SeekOrigin.Current); - magic = br.ReadUInt32(); - version = br.ReadUInt32(); - - if(magic == 0x600DDEEE && version == 1) - { - br.BaseStream.Seek(52, SeekOrigin.Current); - for(int j = 0; j < 16; j++) - { - Partition part = new Partition(); - br.BaseStream.Seek(4, SeekOrigin.Current); - part.PartitionStart = (entry.lba_start + br.ReadInt32()) * 512; - part.PartitionLength = br.ReadInt32()*512; - part.PartitionDescription = "Solaris slice."; - - part.PartitionSequence = counter; + // TODO: Handle disklabels bigger than 1 sector or search max no_parts + for (int j = 0; j < no_parts; j++) + { + Partition part = new Partition(); + byte bsd_type; + + part.PartitionSectors = BitConverter.ToUInt32(disklabel_sector, 134 + j * 16 + 4); + part.PartitionStartSector = BitConverter.ToUInt32(disklabel_sector, 134 + j * 16 + 0); + part.PartitionLength = part.PartitionSectors * imagePlugin.GetSectorSize(); + part.PartitionStart = part.PartitionStartSector * imagePlugin.GetSectorSize(); + bsd_type = disklabel_sector[134 + j * 16 + 8]; + + part.PartitionType = String.Format("BSD: {0}", bsd_type); + part.PartitionName = decodeBSDType(bsd_type); - if(part.PartitionLength > 0) - { - partitions.Add(part); - counter++; - } - } - } - else - valid = true; - break; - } - case 0x81: // Minix subpartitions - { - bool minix_subs = false; - byte type; - - br.BaseStream.Seek(0x01BE, SeekOrigin.Current); - for(int j = 0; j < 4; j++) - { - br.BaseStream.Seek(4, SeekOrigin.Current); - type = br.ReadByte(); + part.PartitionSequence = counter; + part.PartitionDescription = "Partition inside a BSD disklabel."; - if(type==0x81) - { - Partition part = new Partition(); - minix_subs = true; - br.BaseStream.Seek(3, SeekOrigin.Current); - part.PartitionDescription = "Minix subpartition"; - part.PartitionType = "Minix"; - part.PartitionStart = br.ReadUInt32()*512; - part.PartitionLength = br.ReadUInt32()*512; - part.PartitionSequence = counter; - partitions.Add(part); - counter++; - } - } - if(!minix_subs) - valid = true; + if (bsd_type != 0) + { + partitions.Add(part); + counter++; + } + } + } + else + valid = true; + break; + } + case 0x63: // UNIX disklabel + { + UInt32 magic; + byte[] unix_dl_sector = imagePlugin.ReadSector(entry.lba_start + 29); // UNIX disklabel starts on sector 29 of partition + magic = BitConverter.ToUInt32(unix_dl_sector, 4); + + if (magic == UNIXDiskLabel_MAGIC) + { + UNIXDiskLabel dl = new UNIXDiskLabel(); + UNIXVTOC vtoc = new UNIXVTOC(); // old/new + bool isNewDL = false; + int vtocoffset = 0; + + vtoc.magic = BitConverter.ToUInt32(unix_dl_sector, 172); + if (vtoc.magic == UNIXVTOC_MAGIC) + { + isNewDL = true; + vtocoffset = 72; + } + else + { + vtoc.magic = BitConverter.ToUInt32(unix_dl_sector, 172); + if (vtoc.magic != UNIXDiskLabel_MAGIC) + { + valid = true; + break; + } + } + + dl.version = BitConverter.ToUInt32(unix_dl_sector, 8); // 8 + byte[] dl_serial = new byte[12]; + Array.Copy(unix_dl_sector, 12, dl_serial, 0, 12); + dl.serial = StringHandlers.CToString(dl_serial); // 12 + dl.cyls = BitConverter.ToUInt32(unix_dl_sector, 24); // 24 + dl.trks = BitConverter.ToUInt32(unix_dl_sector, 28); // 28 + dl.secs = BitConverter.ToUInt32(unix_dl_sector, 32); // 32 + dl.bps = BitConverter.ToUInt32(unix_dl_sector, 36); // 36 + dl.start = BitConverter.ToUInt32(unix_dl_sector, 40); // 40 + //dl.unknown1 = br.ReadBytes(48); // 44 + dl.alt_tbl = BitConverter.ToUInt32(unix_dl_sector, 92); // 92 + dl.alt_len = BitConverter.ToUInt32(unix_dl_sector, 96); // 96 + + if (isNewDL) // Old version VTOC starts here + { + dl.phys_cyl = BitConverter.ToUInt32(unix_dl_sector, 100); // 100 + dl.phys_trk = BitConverter.ToUInt32(unix_dl_sector, 104); // 104 + dl.phys_sec = BitConverter.ToUInt32(unix_dl_sector, 108); // 108 + dl.phys_bytes = BitConverter.ToUInt32(unix_dl_sector, 112); // 112 + dl.unknown2 = BitConverter.ToUInt32(unix_dl_sector, 116); // 116 + dl.unknown3 = BitConverter.ToUInt32(unix_dl_sector, 120); // 120 + //dl.pad = br.ReadBytes(48); // 124 + } + + if (vtoc.magic == UNIXVTOC_MAGIC) + { + vtoc.version = BitConverter.ToUInt32(unix_dl_sector, 104 + vtocoffset); // 104/176 + byte[] vtoc_name = new byte[8]; + Array.Copy(unix_dl_sector, 108 + vtocoffset, vtoc_name, 0, 8); + vtoc.name = StringHandlers.CToString(vtoc_name); // 108/180 + vtoc.slices = BitConverter.ToUInt16(unix_dl_sector, 116 + vtocoffset); // 116/188 + vtoc.unknown = BitConverter.ToUInt16(unix_dl_sector, 118 + vtocoffset); // 118/190 + //vtoc.reserved = br.ReadBytes(40); // 120/192 - break; - } - default: - valid = true; - break; - } - - br.BaseStream.Seek(currentPos, SeekOrigin.Begin); - } + // TODO: What if number of slices overlaps sector (>23)? + for (int j = 0; j < vtoc.slices; j++) + { + UNIXVTOCEntry vtoc_ent = new UNIXVTOCEntry(); + + vtoc_ent.tag = BitConverter.ToUInt16(unix_dl_sector, 160 + vtocoffset + j * 12 + 0); // 160/232 + j*12 + vtoc_ent.flags = BitConverter.ToUInt16(unix_dl_sector, 160 + vtocoffset + j * 12 + 2); // 162/234 + j*12 + vtoc_ent.start = BitConverter.ToUInt32(unix_dl_sector, 160 + vtocoffset + j * 12 + 6); // 166/238 + j*12 + vtoc_ent.length = BitConverter.ToUInt32(unix_dl_sector, 160 + vtocoffset + j * 12 + 10); // 170/242 + j*12 + + if ((vtoc_ent.flags & 0x200) == 0x200 && vtoc_ent.tag != UNIX_TAG_EMPTY && vtoc_ent.tag != UNIX_TAG_WHOLE) + { + Partition part = new Partition(); + // TODO: Check if device bps == disklabel bps + part.PartitionStartSector = vtoc_ent.start; + part.PartitionSectors = vtoc_ent.length; + part.PartitionStart = vtoc_ent.start * dl.bps; + part.PartitionLength = vtoc_ent.length * dl.bps; + part.PartitionSequence = counter; + part.PartitionType = String.Format("UNIX: {0}", decodeUNIXTAG(vtoc_ent.tag, isNewDL)); + + string info = ""; + + if ((vtoc_ent.flags & 0x01) == 0x01) + info += " (do not mount)"; + if ((vtoc_ent.flags & 0x10) == 0x10) + info += " (do not mount)"; + + part.PartitionDescription = "UNIX slice" + info + "."; + + partitions.Add(part); + counter++; + } + } + } + } + else + valid = true; + break; + } + case 0x82: + case 0xBF: // Solaris disklabel + { + UInt32 magic = BitConverter.ToUInt32(disklabel_sector, 12); // 12 + UInt32 version = BitConverter.ToUInt32(disklabel_sector, 16); // 16 + + if (magic == 0x600DDEEE && version == 1) + { + for (int j = 0; j < 16; j++) + { + Partition part = new Partition(); + part.PartitionStartSector = BitConverter.ToUInt32(disklabel_sector, 68 + j * 12 + 4); + part.PartitionSectors = BitConverter.ToUInt32(disklabel_sector, 68 + j * 12 + 8); + part.PartitionStart = part.PartitionStartSector * imagePlugin.GetSectorSize(); // 68+4+j*12 + part.PartitionLength = part.PartitionSectors * imagePlugin.GetSectorSize(); // 68+8+j*12 + part.PartitionDescription = "Solaris slice."; + + part.PartitionSequence = counter; + + if (part.PartitionLength > 0) + { + partitions.Add(part); + counter++; + } + } + } + else + valid = true; + break; + } + case 0x81: // Minix subpartitions + { + bool minix_subs = false; + byte type; + + for (int j = 0; j < 4; j++) + { + type = disklabel_sector[0x1BE + j * 16 + 4]; + + if (type == 0x81) + { + Partition part = new Partition(); + minix_subs = true; + part.PartitionDescription = "Minix subpartition"; + part.PartitionType = "Minix"; + part.PartitionStartSector = BitConverter.ToUInt32(disklabel_sector, 0x1BE + j * 16 + 8); + part.PartitionSectors = BitConverter.ToUInt32(disklabel_sector, 0x1BE + j * 16 + 12); + part.PartitionStart = part.PartitionStartSector * imagePlugin.GetSectorSize(); + part.PartitionLength = part.PartitionSectors * imagePlugin.GetSectorSize(); + part.PartitionSequence = counter; + partitions.Add(part); + counter++; + } + } + if (!minix_subs) + valid = true; + + break; + } + default: + valid = true; + break; + } + } - if(valid) - { - Partition part = new Partition(); - if(entry.lba_start > 0 && entry.lba_sectors > 0) - { - part.PartitionStart = (long)entry.lba_start * 512; - part.PartitionLength = (long)entry.lba_sectors * 512; - } + if (valid) + { + Partition part = new Partition(); + if (entry.lba_start > 0 && entry.lba_sectors > 0) + { + part.PartitionStartSector = entry.lba_start; + part.PartitionSectors = entry.lba_sectors; + part.PartitionStart = part.PartitionStartSector * imagePlugin.GetSectorSize(); + part.PartitionLength = part.PartitionSectors * imagePlugin.GetSectorSize(); + } /* else if(entry.start_head < 255 && entry.end_head < 255 && entry.start_sector > 0 && entry.start_sector < 64 && entry.end_sector > 0 && entry.end_sector < 64 && @@ -306,300 +331,307 @@ namespace FileSystemIDandChk.PartPlugins } */ // As we don't know the maxium cyl, head or sect of the device we need LBA else - valid = false; + valid = false; - if(valid) - { - part.PartitionType = String.Format("0x{0:X2}", entry.type); - part.PartitionName = decodeMBRType(entry.type); - part.PartitionSequence = counter; - if(entry.status==0x80) - part.PartitionDescription = "Partition is bootable."; - else - part.PartitionDescription = ""; + if (valid) + { + part.PartitionType = String.Format("0x{0:X2}", entry.type); + part.PartitionName = decodeMBRType(entry.type); + part.PartitionSequence = counter; + if (entry.status == 0x80) + part.PartitionDescription = "Partition is bootable."; + else + part.PartitionDescription = ""; - counter++; + counter++; - partitions.Add(part); - } - } + partitions.Add(part); + } + } - if(extended) // Let's extend the fun - { - long pre_ext_Pos = br.BaseStream.Position; - bool ext_valid = true; - bool ext_disklabel = false; - bool processing_extended = true; - - br.BaseStream.Seek((long)entry.lba_start*512, SeekOrigin.Begin); + if (extended) // Let's extend the fun + { + bool ext_valid = true; + bool ext_disklabel = false; + bool processing_extended = true; - while(processing_extended) - { - br.BaseStream.Seek(0x01BE, SeekOrigin.Current); - - for(int l = 0; l < 2; l++) - { - bool ext_extended = false; + sector = imagePlugin.ReadSector(entry.lba_start); + + while (processing_extended) + { + for (int l = 0; l < 2; l++) + { + bool ext_extended = false; - MBRPartitionEntry entry2 = new MBRPartitionEntry(); + MBRPartitionEntry entry2 = new MBRPartitionEntry(); - entry2.status = br.ReadByte(); - entry2.start_head = br.ReadByte(); + entry2.status = sector[0x1BE + 16 * i + 0x00]; + entry2.start_head = sector[0x1BE + 16 * i + 0x00]; - cyl_sect1 = br.ReadByte(); - cyl_sect2 = br.ReadByte(); + cyl_sect1 = sector[0x1BE + 16 * i + 0x00]; + cyl_sect2 = sector[0x1BE + 16 * i + 0x00]; - entry2.start_sector = (byte)(cyl_sect1 & 0x3F); - entry2.start_cylinder = (ushort)(((cyl_sect1 & 0xC0) << 2) | cyl_sect2); + entry2.start_sector = (byte)(cyl_sect1 & 0x3F); + entry2.start_cylinder = (ushort)(((cyl_sect1 & 0xC0) << 2) | cyl_sect2); - entry2.type = br.ReadByte(); - entry2.end_head = br.ReadByte(); - - cyl_sect1 = br.ReadByte(); - cyl_sect2 = br.ReadByte(); + entry2.type = sector[0x1BE + 16 * i + 0x00]; + entry2.end_head = sector[0x1BE + 16 * i + 0x00]; - entry2.end_sector = (byte)(cyl_sect1 & 0x3F); - entry2.end_cylinder = (ushort)(((cyl_sect1 & 0xC0) << 2) | cyl_sect2); + cyl_sect1 = sector[0x1BE + 16 * i + 0x00]; + cyl_sect2 = sector[0x1BE + 16 * i + 0x00]; - entry2.lba_start = br.ReadUInt32() + entry.lba_start; - entry2.lba_sectors = br.ReadUInt32(); + entry2.end_sector = (byte)(cyl_sect1 & 0x3F); + entry2.end_cylinder = (ushort)(((cyl_sect1 & 0xC0) << 2) | cyl_sect2); - // Let's start the fun... + entry2.lba_start = BitConverter.ToUInt32(sector, 0x1BE + 16 * i + 0x00); + entry2.lba_sectors = BitConverter.ToUInt32(sector, 0x1BE + 16 * i + 0x00); + + // Let's start the fun... - if(entry2.status != 0x00 && entry2.status != 0x80) - ext_valid = false; - if(entry2.type == 0x00) - valid = false; - if(entry2.type == 0x82 || entry2.type == 0xBF || entry2.type == 0xA5 || entry2.type == 0xA6 || - entry2.type == 0xA9 || entry2.type == 0xB7 || entry2.type == 0x81 || entry2.type == 0x63) - { - ext_valid = false; - ext_disklabel = true; - } - if(entry2.type == 0x05 || entry2.type == 0x0F || entry2.type == 0x85) - { - ext_valid = false; - ext_disklabel = false; - ext_extended = true; // Extended partition - } - else if(l==1) - processing_extended=false; + if (entry2.status != 0x00 && entry2.status != 0x80) + ext_valid = false; + if (entry2.type == 0x00) + valid = false; + if (entry2.type == 0x82 || entry2.type == 0xBF || entry2.type == 0xA5 || entry2.type == 0xA6 || + entry2.type == 0xA9 || entry2.type == 0xB7 || entry2.type == 0x81 || entry2.type == 0x63) + { + ext_valid = false; + ext_disklabel = true; + } + if (entry2.type == 0x05 || entry2.type == 0x0F || entry2.type == 0x85) + { + ext_valid = false; + ext_disklabel = false; + ext_extended = true; // Extended partition + } + else if (l == 1) + processing_extended = false; - if(ext_disklabel) - { - long currentPos = br.BaseStream.Position; - long disklabel_start = entry2.lba_start * 512; - - br.BaseStream.Seek(disklabel_start, SeekOrigin.Begin); - - switch(entry2.type) - { - case 0xA5: - case 0xA6: - case 0xA9: - case 0xB7: // BSD disklabels - { - UInt32 magic; - magic = br.ReadUInt32(); - - if(magic == 0x82564557) - { - br.BaseStream.Seek(126, SeekOrigin.Current); - UInt16 no_parts = br.ReadUInt16(); - br.BaseStream.Seek(8, SeekOrigin.Current); - - for(int j = 0; j < no_parts; j++) - { - Partition part = new Partition(); - byte bsd_type; - - part.PartitionLength = br.ReadUInt32()*512; - part.PartitionStart = br.ReadUInt32()*512; - br.BaseStream.Seek(4, SeekOrigin.Current); - bsd_type = br.ReadByte(); - br.BaseStream.Seek(3, SeekOrigin.Current); - - part.PartitionType = String.Format("BSD: {0}", bsd_type); - part.PartitionName = decodeBSDType(bsd_type); - - part.PartitionSequence = counter; - part.PartitionDescription = "Partition inside a BSD disklabel."; - - if(bsd_type!=0) - { - partitions.Add(part); - counter++; - } - } - } - else - ext_valid=true; - break; - } - case 0x63: // UNIX disklabel - { - UInt32 magic; - br.BaseStream.Seek(29*0x200 + 4, SeekOrigin.Current); // Starts on sector 29 of partition - magic = br.ReadUInt32(); - - if(magic == UNIXDiskLabel_MAGIC) - { - UNIXDiskLabel dl = new UNIXDiskLabel(); - bool isNewDL = false; - - dl.version = br.ReadUInt32(); - dl.serial = StringHandlers.CToString(br.ReadBytes(12)); - dl.cyls = br.ReadUInt32(); - dl.trks = br.ReadUInt32(); - dl.secs = br.ReadUInt32(); - dl.bps = br.ReadUInt32(); - dl.start = br.ReadUInt32(); - dl.unknown1 = br.ReadBytes(48); - dl.alt_tbl = br.ReadUInt32(); - dl.alt_len = br.ReadUInt32(); - dl.phys_cyl = br.ReadUInt32(); - - if(dl.phys_cyl != UNIXVTOC_MAGIC) // Old version VTOC starts here - { - isNewDL = true; - dl.phys_trk = br.ReadUInt32(); - dl.phys_sec = br.ReadUInt32(); - dl.phys_bytes = br.ReadUInt32(); - dl.unknown2 = br.ReadUInt32(); - dl.unknown3 = br.ReadUInt32(); - dl.pad = br.ReadBytes(48); - } - else - br.BaseStream.Seek(-4, SeekOrigin.Current); // Return to old VTOC magic - - UNIXVTOC vtoc = new UNIXVTOC(); - - vtoc.magic = br.ReadUInt32(); - - if(vtoc.magic == UNIXVTOC_MAGIC) - { - vtoc.version = br.ReadUInt32(); - vtoc.name = StringHandlers.CToString(br.ReadBytes(8)); - vtoc.slices = br.ReadUInt16(); - vtoc.unknown = br.ReadUInt16(); - vtoc.reserved = br.ReadBytes(40); - - for(int j = 0; j < vtoc.slices; j++) - { - UNIXVTOCEntry vtoc_ent = new UNIXVTOCEntry(); - - vtoc_ent.tag = br.ReadUInt16(); - vtoc_ent.flags = br.ReadUInt16(); - vtoc_ent.start = br.ReadUInt32(); - vtoc_ent.length = br.ReadUInt32(); - - if((vtoc_ent.flags & 0x200) == 0x200 && vtoc_ent.tag != UNIX_TAG_EMPTY && vtoc_ent.tag != UNIX_TAG_WHOLE) - { - Partition part = new Partition(); - part.PartitionStart = vtoc_ent.start * dl.bps; - part.PartitionLength = vtoc_ent.length * dl.bps; - part.PartitionSequence = counter; - part.PartitionType = String.Format("UNIX: {0}", decodeUNIXTAG(vtoc_ent.tag, isNewDL)); - - string info = ""; - - if((vtoc_ent.flags & 0x01) == 0x01) - info += " (do not mount)"; - if((vtoc_ent.flags & 0x10) == 0x10) - info += " (do not mount)"; - - part.PartitionDescription = "UNIX slice" + info + "."; - - partitions.Add(part); - counter++; - } - } - } - } - else - ext_valid = true; - break; - } - case 0x82: - case 0xBF: // Solaris disklabel - { - UInt32 magic; - UInt32 version; - br.BaseStream.Seek(12, SeekOrigin.Current); - magic = br.ReadUInt32(); - version = br.ReadUInt32(); + if (ext_disklabel) + { + byte[] disklabel_sector = imagePlugin.ReadSector(entry2.lba_start); + + switch (entry2.type) + { + case 0xA5: + case 0xA6: + case 0xA9: + case 0xB7: // BSD disklabels + { + UInt32 magic = BitConverter.ToUInt32(disklabel_sector, 0); - if(magic == 0x600DDEEE && version == 1) - { - br.BaseStream.Seek(52, SeekOrigin.Current); - for(int j = 0; j < 16; j++) - { - Partition part = new Partition(); - br.BaseStream.Seek(4, SeekOrigin.Current); - part.PartitionStart = (entry2.lba_start + br.ReadInt32()) * 512; - part.PartitionLength = br.ReadInt32()*512; - part.PartitionDescription = "Solaris slice."; - - part.PartitionSequence = counter; - - if(part.PartitionLength > 0) - { - partitions.Add(part); - counter++; - } - } - } - else - ext_valid = true; - break; - } - case 0x81: // Minix subpartitions - { - bool minix_subs = false; - byte type; - - br.BaseStream.Seek(0x01BE, SeekOrigin.Current); - for(int j = 0; j < 4; j++) - { - br.BaseStream.Seek(4, SeekOrigin.Current); - type = br.ReadByte(); - - if(type==0x81) - { - Partition part = new Partition(); - minix_subs = true; - br.BaseStream.Seek(3, SeekOrigin.Current); - part.PartitionDescription = "Minix subpartition"; - part.PartitionType = "Minix"; - part.PartitionStart = br.ReadUInt32()*512; - part.PartitionLength = br.ReadUInt32()*512; - part.PartitionSequence = counter; - partitions.Add(part); - counter++; - } - } - if(!minix_subs) - ext_valid = true; + if (magic == 0x82564557) + { + UInt16 no_parts = BitConverter.ToUInt16(disklabel_sector, 126); - break; - } - default: - ext_valid = true; - break; - } + // TODO: Handle disklabels bigger than 1 sector or search max no_parts + for (int j = 0; j < no_parts; j++) + { + Partition part = new Partition(); + byte bsd_type; + + part.PartitionSectors = BitConverter.ToUInt32(disklabel_sector, 134 + j * 16 + 4); + part.PartitionStartSector = BitConverter.ToUInt32(disklabel_sector, 134 + j * 16 + 0); + part.PartitionLength = part.PartitionSectors * imagePlugin.GetSectorSize(); + part.PartitionStart = part.PartitionStartSector * imagePlugin.GetSectorSize(); + bsd_type = disklabel_sector[134 + j * 16 + 8]; + + part.PartitionType = String.Format("BSD: {0}", bsd_type); + part.PartitionName = decodeBSDType(bsd_type); + + part.PartitionSequence = counter; + part.PartitionDescription = "Partition inside a BSD disklabel."; + + if (bsd_type != 0) + { + partitions.Add(part); + counter++; + } + } + } + else + ext_valid = true; + break; + } + case 0x63: // UNIX disklabel + { + UInt32 magic; + byte[] unix_dl_sector = imagePlugin.ReadSector(entry.lba_start + 29); // UNIX disklabel starts on sector 29 of partition + magic = BitConverter.ToUInt32(unix_dl_sector, 4); + + if (magic == UNIXDiskLabel_MAGIC) + { + UNIXDiskLabel dl = new UNIXDiskLabel(); + UNIXVTOC vtoc = new UNIXVTOC(); // old/new + bool isNewDL = false; + int vtocoffset = 0; + + vtoc.magic = BitConverter.ToUInt32(unix_dl_sector, 172); + if (vtoc.magic == UNIXVTOC_MAGIC) + { + isNewDL = true; + vtocoffset = 72; + } + else + { + vtoc.magic = BitConverter.ToUInt32(unix_dl_sector, 172); + if (vtoc.magic != UNIXDiskLabel_MAGIC) + { + valid = true; + break; + } + } + + dl.version = BitConverter.ToUInt32(unix_dl_sector, 8); // 8 + byte[] dl_serial = new byte[12]; + Array.Copy(unix_dl_sector, 12, dl_serial, 0, 12); + dl.serial = StringHandlers.CToString(dl_serial); // 12 + dl.cyls = BitConverter.ToUInt32(unix_dl_sector, 24); // 24 + dl.trks = BitConverter.ToUInt32(unix_dl_sector, 28); // 28 + dl.secs = BitConverter.ToUInt32(unix_dl_sector, 32); // 32 + dl.bps = BitConverter.ToUInt32(unix_dl_sector, 36); // 36 + dl.start = BitConverter.ToUInt32(unix_dl_sector, 40); // 40 + //dl.unknown1 = br.ReadBytes(48); // 44 + dl.alt_tbl = BitConverter.ToUInt32(unix_dl_sector, 92); // 92 + dl.alt_len = BitConverter.ToUInt32(unix_dl_sector, 96); // 96 + + if (isNewDL) // Old version VTOC starts here + { + dl.phys_cyl = BitConverter.ToUInt32(unix_dl_sector, 100); // 100 + dl.phys_trk = BitConverter.ToUInt32(unix_dl_sector, 104); // 104 + dl.phys_sec = BitConverter.ToUInt32(unix_dl_sector, 108); // 108 + dl.phys_bytes = BitConverter.ToUInt32(unix_dl_sector, 112); // 112 + dl.unknown2 = BitConverter.ToUInt32(unix_dl_sector, 116); // 116 + dl.unknown3 = BitConverter.ToUInt32(unix_dl_sector, 120); // 120 + //dl.pad = br.ReadBytes(48); // 124 + } + + if (vtoc.magic == UNIXVTOC_MAGIC) + { + vtoc.version = BitConverter.ToUInt32(unix_dl_sector, 104 + vtocoffset); // 104/176 + byte[] vtoc_name = new byte[8]; + Array.Copy(unix_dl_sector, 108 + vtocoffset, vtoc_name, 0, 8); + vtoc.name = StringHandlers.CToString(vtoc_name); // 108/180 + vtoc.slices = BitConverter.ToUInt16(unix_dl_sector, 116 + vtocoffset); // 116/188 + vtoc.unknown = BitConverter.ToUInt16(unix_dl_sector, 118 + vtocoffset); // 118/190 + //vtoc.reserved = br.ReadBytes(40); // 120/192 + + // TODO: What if number of slices overlaps sector (>23)? + for (int j = 0; j < vtoc.slices; j++) + { + UNIXVTOCEntry vtoc_ent = new UNIXVTOCEntry(); + + vtoc_ent.tag = BitConverter.ToUInt16(unix_dl_sector, 160 + vtocoffset + j * 12 + 0); // 160/232 + j*12 + vtoc_ent.flags = BitConverter.ToUInt16(unix_dl_sector, 160 + vtocoffset + j * 12 + 2); // 162/234 + j*12 + vtoc_ent.start = BitConverter.ToUInt32(unix_dl_sector, 160 + vtocoffset + j * 12 + 6); // 166/238 + j*12 + vtoc_ent.length = BitConverter.ToUInt32(unix_dl_sector, 160 + vtocoffset + j * 12 + 10); // 170/242 + j*12 + + if ((vtoc_ent.flags & 0x200) == 0x200 && vtoc_ent.tag != UNIX_TAG_EMPTY && vtoc_ent.tag != UNIX_TAG_WHOLE) + { + Partition part = new Partition(); + // TODO: Check if device bps == disklabel bps + part.PartitionStartSector = vtoc_ent.start; + part.PartitionSectors = vtoc_ent.length; + part.PartitionStart = vtoc_ent.start * dl.bps; + part.PartitionLength = vtoc_ent.length * dl.bps; + part.PartitionSequence = counter; + part.PartitionType = String.Format("UNIX: {0}", decodeUNIXTAG(vtoc_ent.tag, isNewDL)); + + string info = ""; + + if ((vtoc_ent.flags & 0x01) == 0x01) + info += " (do not mount)"; + if ((vtoc_ent.flags & 0x10) == 0x10) + info += " (do not mount)"; + + part.PartitionDescription = "UNIX slice" + info + "."; + + partitions.Add(part); + counter++; + } + } + } + } + else + ext_valid = true; + break; + } + case 0x82: + case 0xBF: // Solaris disklabel + { + UInt32 magic = BitConverter.ToUInt32(disklabel_sector, 12); // 12 + UInt32 version = BitConverter.ToUInt32(disklabel_sector, 16); // 16 + + if (magic == 0x600DDEEE && version == 1) + { + for (int j = 0; j < 16; j++) + { + Partition part = new Partition(); + part.PartitionStartSector = BitConverter.ToUInt32(disklabel_sector, 68 + j * 12 + 4); + part.PartitionSectors = BitConverter.ToUInt32(disklabel_sector, 68 + j * 12 + 8); + part.PartitionStart = part.PartitionStartSector * imagePlugin.GetSectorSize(); // 68+4+j*12 + part.PartitionLength = part.PartitionSectors * imagePlugin.GetSectorSize(); // 68+8+j*12 + part.PartitionDescription = "Solaris slice."; + + part.PartitionSequence = counter; + + if (part.PartitionLength > 0) + { + partitions.Add(part); + counter++; + } + } + } + else + ext_valid = true; + break; + } + case 0x81: // Minix subpartitions + { + bool minix_subs = false; + byte type; + + for (int j = 0; j < 4; j++) + { + type = disklabel_sector[0x1BE + j * 16 + 4]; + + if (type == 0x81) + { + Partition part = new Partition(); + minix_subs = true; + part.PartitionDescription = "Minix subpartition"; + part.PartitionType = "Minix"; + part.PartitionStartSector = BitConverter.ToUInt32(disklabel_sector, 0x1BE + j * 16 + 8); + part.PartitionSectors = BitConverter.ToUInt32(disklabel_sector, 0x1BE + j * 16 + 12); + part.PartitionStart = part.PartitionStartSector * imagePlugin.GetSectorSize(); + part.PartitionLength = part.PartitionSectors * imagePlugin.GetSectorSize(); + part.PartitionSequence = counter; + partitions.Add(part); + counter++; + } + } + if (!minix_subs) + ext_valid = true; + + break; + } + default: + ext_valid = true; + break; + } - br.BaseStream.Seek(currentPos, SeekOrigin.Begin); - } + } - if(ext_valid) - { - Partition part = new Partition(); - if(entry2.lba_start > 0 && entry2.lba_sectors > 0) - { - part.PartitionStart = (long)entry2.lba_start * 512; - part.PartitionLength = (long)entry2.lba_sectors * 512; - Console.WriteLine("{0} start", entry2.lba_start); - } + if (ext_valid) + { + Partition part = new Partition(); + if (entry2.lba_start > 0 && entry2.lba_sectors > 0) + { + part.PartitionStartSector = entry2.lba_start; + part.PartitionSectors = entry2.lba_sectors; + part.PartitionStart = part.PartitionStartSector * imagePlugin.GetSectorSize(); + part.PartitionLength = part.PartitionSectors * imagePlugin.GetSectorSize(); + } /* else if(entry2.start_head < 255 && entry2.end_head < 255 && entry2.start_sector > 0 && entry2.start_sector < 64 && entry2.end_sector > 0 && entry2.end_sector < 64 && @@ -608,538 +640,598 @@ namespace FileSystemIDandChk.PartPlugins } */ // As we don't know the maxium cyl, head or sect of the device we need LBA else - ext_valid = false; + ext_valid = false; - if(ext_valid) - { - part.PartitionType = String.Format("0x{0:X2}", entry2.type); - part.PartitionName = decodeMBRType(entry2.type); - part.PartitionSequence = counter; - if(entry2.status==0x80) - part.PartitionDescription = "Partition is bootable."; - else - part.PartitionDescription = ""; + if (ext_valid) + { + part.PartitionType = String.Format("0x{0:X2}", entry2.type); + part.PartitionName = decodeMBRType(entry2.type); + part.PartitionSequence = counter; + if (entry2.status == 0x80) + part.PartitionDescription = "Partition is bootable."; + else + part.PartitionDescription = ""; - counter++; + counter++; - partitions.Add(part); - } - } + partitions.Add(part); + } + } - if(ext_extended) - { - br.BaseStream.Seek((long)entry2.lba_start*512, SeekOrigin.Begin); - break; - } - } - - br.BaseStream.Seek(2, SeekOrigin.Current); - } - - br.BaseStream.Seek(pre_ext_Pos, SeekOrigin.Begin); - } - } + if (ext_extended) + { + break; + } + } + } + } + } - // An empty MBR may exist, NeXT creates one and then hardcodes its disklabel - if(partitions.Count==0) - return false; - else - return true; - } - - private string decodeBSDType(byte type) - { - switch(type) - { - case 1: - return "Swap"; - case 2: - return "UNIX Version 6"; - case 3: - return "UNIX Version 7"; - case 4: - return "System V"; - case 5: - return "4.1BSD"; - case 6: - return "UNIX Eigth Edition"; - case 7: - return "4.2BSD"; - case 8: - return "MS-DOS"; - case 9: - return "4.4LFS"; - case 11: - return "HPFS"; - case 12: - return "ISO9660"; - case 13: - return "Boot"; - case 14: - return "Amiga FFS"; - case 15: - return "Apple HFS"; - default: - return "Unknown"; - } - } - - private string decodeMBRType(byte type) - { - switch(type) - { - case 0x01: - return "FAT12"; - case 0x02: - return "XENIX root"; - case 0x03: - return "XENIX /usr"; - case 0x04: - return "FAT16 < 32 MiB"; - case 0x05: - return "Extended"; - case 0x06: - return "FAT16"; - case 0x07: - return "IFS (HPFS/NTFS)"; - case 0x08: - return "AIX boot, OS/2, Commodore DOS"; - case 0x09: - return "AIX data, Coherent, QNX"; - case 0x0A: - return "Coherent swap, OPUS, OS/2 Boot Manager"; - case 0x0B: - return "FAT32"; - case 0x0C: - return "FAT32 (LBA)"; - case 0x0E: - return "FAT16 (LBA)"; - case 0x0F: - return "Extended (LBA)"; - case 0x10: - return "OPUS"; - case 0x11: - return "Hidden FAT12"; - case 0x12: - return "Compaq diagnostics, recovery partition"; - case 0x14: - return "Hidden FAT16 < 32 MiB, AST-DOS"; - case 0x16: - return "Hidden FAT16"; - case 0x17: - return "Hidden IFS (HPFS/NTFS)"; - case 0x18: - return "AST-Windows swap"; - case 0x19: - return "Willowtech Photon coS"; - case 0x1B: - return "Hidden FAT32"; - case 0x1C: - return "Hidden FAT32 (LBA)"; - case 0x1E: - return "Hidden FAT16 (LBA)"; - case 0x20: - return "Willowsoft Overture File System"; - case 0x21: - return "Oxygen FSo2"; - case 0x22: - return "Oxygen Extended "; - case 0x23: - return "SpeedStor reserved"; - case 0x24: - return "NEC-DOS"; - case 0x26: - return "SpeedStor reserved"; - case 0x27: - return "Hidden NTFS"; - case 0x31: - return "SpeedStor reserved"; - case 0x33: - return "SpeedStor reserved"; - case 0x34: - return "SpeedStor reserved"; - case 0x36: - return "SpeedStor reserved"; - case 0x38: - return "Theos"; - case 0x39: - return "Plan 9"; - case 0x3C: - return "Partition Magic"; - case 0x3D: - return "Hidden NetWare"; - case 0x40: - return "VENIX 80286"; - case 0x41: - return "PReP Boot"; - case 0x42: - return "Secure File System"; - case 0x43: - return "PTS-DOS"; - case 0x45: - return "Priam, EUMEL/Elan"; - case 0x46: - return "EUMEL/Elan"; - case 0x47: - return "EUMEL/Elan"; - case 0x48: - return "EUMEL/Elan"; - case 0x4A: - return "ALFS/THIN lightweight filesystem for DOS"; - case 0x4D: - return "QNX 4"; - case 0x4E: - return "QNX 4"; - case 0x4F: - return "QNX 4, Oberon"; - case 0x50: - return "Ontrack DM, R/O, FAT"; - case 0x51: - return "Ontrack DM, R/W, FAT"; - case 0x52: - return "CP/M, Microport UNIX"; - case 0x53: - return "Ontrack DM 6"; - case 0x54: - return "Ontrack DM 6"; - case 0x55: - return "EZ-Drive"; - case 0x56: - return "Golden Bow VFeature"; - case 0x5C: - return "Priam EDISK"; - case 0x61: - return "SpeedStor"; - case 0x63: - return "GNU Hurd, System V, 386/ix"; - case 0x64: - return "NetWare 286"; - case 0x65: - return "NetWare"; - case 0x66: - return "NetWare 386"; - case 0x67: - return "NetWare"; - case 0x68: - return "NetWare"; - case 0x69: - return "NetWare NSS"; - case 0x70: - return "DiskSecure Multi-Boot"; - case 0x72: - return "UNIX 7th Edition"; - case 0x75: - return "IBM PC/IX"; - case 0x80: - return "Old MINIX"; - case 0x81: - return "MINIX, Old Linux"; - case 0x82: - return "Linux swap, Solaris"; - case 0x83: - return "Linux"; - case 0x84: - return "Hidden by OS/2, APM hibernation"; - case 0x85: - return "Linux extended"; - case 0x86: - return "NT Stripe Set"; - case 0x87: - return "NT Stripe Set"; - case 0x88: - return "Linux Plaintext"; - case 0x8E: - return "Linux LVM"; - case 0x93: - return "Amoeba, Hidden Linux"; - case 0x94: - return "Amoeba bad blocks"; - case 0x99: - return "Mylex EISA SCSI"; - case 0x9F: - return "BSD/OS"; - case 0xA0: - return "Hibernation"; - case 0xA1: - return "HP Volume Expansion"; - case 0xA3: - return "HP Volume Expansion"; - case 0xA4: - return "HP Volume Expansion"; - case 0xA5: - return "FreeBSD"; - case 0xA6: - return "OpenBSD"; - case 0xA7: - return "NeXTStep"; - case 0xA8: - return "Apple UFS"; - case 0xA9: - return "NetBSD"; - case 0xAA: - return "Olivetti DOS FAT12"; - case 0xAB: - return "Apple Boot"; - case 0xAF: - return "Apple HFS"; - case 0xB0: - return "BootStar"; - case 0xB1: - return "HP Volume Expansion"; - case 0xB3: - return "HP Volume Expansion"; - case 0xB4: - return "HP Volume Expansion"; - case 0xB6: - return "HP Volume Expansion"; - case 0xB7: - return "BSDi"; - case 0xB8: - return "BSDi swap"; - case 0xBB: - return "PTS BootWizard"; - case 0xBE: - return "Solaris boot"; - case 0xBF: - return "Solaris"; - case 0xC0: - return "Novell DOS, DR-DOS secured"; - case 0xC1: - return "DR-DOS secured FAT12"; - case 0xC2: - return "DR-DOS reserved"; - case 0xC3: - return "DR-DOS reserved"; - case 0xC4: - return "DR-DOS secured FAT16 < 32 MiB"; - case 0xC6: - return "DR-DOS secured FAT16"; - case 0xC7: - return "Syrinx"; - case 0xC8: - return "DR-DOS reserved"; - case 0xC9: - return "DR-DOS reserved"; - case 0xCA: - return "DR-DOS reserved"; - case 0xCB: - return "DR-DOS secured FAT32"; - case 0xCC: - return "DR-DOS secured FAT32 (LBA)"; - case 0xCD: - return "DR-DOS reserved"; - case 0xCE: - return "DR-DOS secured FAT16 (LBA)"; - case 0xCF: - return "DR-DOS secured extended (LBA)"; - case 0xD0: - return "Multiuser DOS secured FAT12"; - case 0xD1: - return "Multiuser DOS secured FAT12"; - case 0xD4: - return "Multiuser DOS secured FAT16 < 32 MiB"; - case 0xD5: - return "Multiuser DOS secured extended"; - case 0xD6: - return "Multiuser DOS secured FAT16"; - case 0xD8: - return "CP/M"; - case 0xDA: - return "Filesystem-less data"; - case 0xDB: - return "CP/M, CCP/M, CTOS"; - case 0xDE: - return "Dell partition"; - case 0xDF: - return "BootIt EMBRM"; - case 0xE1: - return "SpeedStor"; - case 0xE2: - return "DOS read/only"; - case 0xE3: - return "SpeedStor"; - case 0xE4: - return "SpeedStor"; - case 0xE5: - return "Tandy DOS"; - case 0xE6: - return "SpeedStor"; - case 0xEB: - return "BeOS"; - case 0xED: - return "Spryt*x"; - case 0xEE: - return "Guid Partition Table"; - case 0xEF: - return "EFI system partition"; - case 0xF0: - return "Linux boot"; - case 0xF1: - return "SpeedStor"; - case 0xF2: - return "DOS 3.3 secondary, Unisys DOS"; - case 0xF3: - return "SpeedStor"; - case 0xF4: - return "SpeedStor"; - case 0xF5: - return "Prologue"; - case 0xF6: - return "SpeedStor"; - case 0xFB: - return "VMWare VMFS"; - case 0xFC: - return "VMWare VMKCORE"; - case 0xFD: - return "Linux RAID, FreeDOS"; - case 0xFE: - return "SpeedStor, LANStep, PS/2 IML"; - case 0xFF: - return "Xenix bad block"; - default: - return "Unknown"; - } - } - - public struct MBRPartitionEntry - { - public byte status; // Partition status, 0x80 or 0x00, else invalid - public byte start_head; // Starting head [0,254] - public byte start_sector; // Starting sector [1,63] - public UInt16 start_cylinder; // Starting cylinder [0,1023] - public byte type; // Partition type - public byte end_head; // Ending head [0,254] - public byte end_sector; // Ending sector [1,63] - public UInt16 end_cylinder; // Ending cylinder [0,1023] - public UInt32 lba_start; // Starting absolute sector - public UInt32 lba_sectors; // Total sectors - } + // An empty MBR may exist, NeXT creates one and then hardcodes its disklabel + if (partitions.Count == 0) + return false; + else + return true; + } - private const UInt32 UNIXDiskLabel_MAGIC = 0xCA5E600D; - private const UInt32 UNIXVTOC_MAGIC = 0x600DDEEE; // Same as Solaris VTOC + private UInt32 CHStoLBA(ushort cyl, byte head, byte sector) + { + return (((UInt32)cyl * 16) + (UInt32)head) * 63 + (UInt32)sector - 1; + } - private struct UNIXDiskLabel - { - public UInt32 type; // Drive type, seems always 0 - public UInt32 magic; // UNIXDiskLabel_MAGIC - public UInt32 version; // Only seen 1 - public string serial; // 12 bytes, serial number of the device - public UInt32 cyls; // data cylinders per device - public UInt32 trks; // data tracks per cylinder - public UInt32 secs; // data sectors per track - public UInt32 bps; // data bytes per sector - public UInt32 start; // first sector of this partition - public byte[] unknown1; // 48 bytes - public UInt32 alt_tbl; // byte offset of alternate table - public UInt32 alt_len; // byte length of alternate table - // From onward here, is not on old version - public UInt32 phys_cyl; // physical cylinders per device - public UInt32 phys_trk; // physical tracks per cylinder - public UInt32 phys_sec; // physical sectors per track - public UInt32 phys_bytes; // physical bytes per sector - public UInt32 unknown2; // - public UInt32 unknown3; // - public byte[] pad; // 32bytes - } + private string decodeBSDType(byte type) + { + switch (type) + { + case 1: + return "Swap"; + case 2: + return "UNIX Version 6"; + case 3: + return "UNIX Version 7"; + case 4: + return "System V"; + case 5: + return "4.1BSD"; + case 6: + return "UNIX Eigth Edition"; + case 7: + return "4.2BSD"; + case 8: + return "MS-DOS"; + case 9: + return "4.4LFS"; + case 11: + return "HPFS"; + case 12: + return "ISO9660"; + case 13: + return "Boot"; + case 14: + return "Amiga FFS"; + case 15: + return "Apple HFS"; + default: + return "Unknown"; + } + } - private struct UNIXVTOC - { - public UInt32 magic; // UNIXVTOC_MAGIC - public UInt32 version; // 1 - public string name; // 8 bytes - public UInt32 slices; // # of slices - public UInt32 unknown; // - public byte[] reserved; // 40 bytes - } + private string decodeMBRType(byte type) + { + switch (type) + { + case 0x01: + return "FAT12"; + case 0x02: + return "XENIX root"; + case 0x03: + return "XENIX /usr"; + case 0x04: + return "FAT16 < 32 MiB"; + case 0x05: + return "Extended"; + case 0x06: + return "FAT16"; + case 0x07: + return "IFS (HPFS/NTFS)"; + case 0x08: + return "AIX boot, OS/2, Commodore DOS"; + case 0x09: + return "AIX data, Coherent, QNX"; + case 0x0A: + return "Coherent swap, OPUS, OS/2 Boot Manager"; + case 0x0B: + return "FAT32"; + case 0x0C: + return "FAT32 (LBA)"; + case 0x0E: + return "FAT16 (LBA)"; + case 0x0F: + return "Extended (LBA)"; + case 0x10: + return "OPUS"; + case 0x11: + return "Hidden FAT12"; + case 0x12: + return "Compaq diagnostics, recovery partition"; + case 0x14: + return "Hidden FAT16 < 32 MiB, AST-DOS"; + case 0x16: + return "Hidden FAT16"; + case 0x17: + return "Hidden IFS (HPFS/NTFS)"; + case 0x18: + return "AST-Windows swap"; + case 0x19: + return "Willowtech Photon coS"; + case 0x1B: + return "Hidden FAT32"; + case 0x1C: + return "Hidden FAT32 (LBA)"; + case 0x1E: + return "Hidden FAT16 (LBA)"; + case 0x20: + return "Willowsoft Overture File System"; + case 0x21: + return "Oxygen FSo2"; + case 0x22: + return "Oxygen Extended "; + case 0x23: + return "SpeedStor reserved"; + case 0x24: + return "NEC-DOS"; + case 0x26: + return "SpeedStor reserved"; + case 0x27: + return "Hidden NTFS"; + case 0x31: + return "SpeedStor reserved"; + case 0x33: + return "SpeedStor reserved"; + case 0x34: + return "SpeedStor reserved"; + case 0x36: + return "SpeedStor reserved"; + case 0x38: + return "Theos"; + case 0x39: + return "Plan 9"; + case 0x3C: + return "Partition Magic"; + case 0x3D: + return "Hidden NetWare"; + case 0x40: + return "VENIX 80286"; + case 0x41: + return "PReP Boot"; + case 0x42: + return "Secure File System"; + case 0x43: + return "PTS-DOS"; + case 0x45: + return "Priam, EUMEL/Elan"; + case 0x46: + return "EUMEL/Elan"; + case 0x47: + return "EUMEL/Elan"; + case 0x48: + return "EUMEL/Elan"; + case 0x4A: + return "ALFS/THIN lightweight filesystem for DOS"; + case 0x4D: + return "QNX 4"; + case 0x4E: + return "QNX 4"; + case 0x4F: + return "QNX 4, Oberon"; + case 0x50: + return "Ontrack DM, R/O, FAT"; + case 0x51: + return "Ontrack DM, R/W, FAT"; + case 0x52: + return "CP/M, Microport UNIX"; + case 0x53: + return "Ontrack DM 6"; + case 0x54: + return "Ontrack DM 6"; + case 0x55: + return "EZ-Drive"; + case 0x56: + return "Golden Bow VFeature"; + case 0x5C: + return "Priam EDISK"; + case 0x61: + return "SpeedStor"; + case 0x63: + return "GNU Hurd, System V, 386/ix"; + case 0x64: + return "NetWare 286"; + case 0x65: + return "NetWare"; + case 0x66: + return "NetWare 386"; + case 0x67: + return "NetWare"; + case 0x68: + return "NetWare"; + case 0x69: + return "NetWare NSS"; + case 0x70: + return "DiskSecure Multi-Boot"; + case 0x72: + return "UNIX 7th Edition"; + case 0x75: + return "IBM PC/IX"; + case 0x80: + return "Old MINIX"; + case 0x81: + return "MINIX, Old Linux"; + case 0x82: + return "Linux swap, Solaris"; + case 0x83: + return "Linux"; + case 0x84: + return "Hidden by OS/2, APM hibernation"; + case 0x85: + return "Linux extended"; + case 0x86: + return "NT Stripe Set"; + case 0x87: + return "NT Stripe Set"; + case 0x88: + return "Linux Plaintext"; + case 0x8E: + return "Linux LVM"; + case 0x93: + return "Amoeba, Hidden Linux"; + case 0x94: + return "Amoeba bad blocks"; + case 0x99: + return "Mylex EISA SCSI"; + case 0x9F: + return "BSD/OS"; + case 0xA0: + return "Hibernation"; + case 0xA1: + return "HP Volume Expansion"; + case 0xA3: + return "HP Volume Expansion"; + case 0xA4: + return "HP Volume Expansion"; + case 0xA5: + return "FreeBSD"; + case 0xA6: + return "OpenBSD"; + case 0xA7: + return "NeXTStep"; + case 0xA8: + return "Apple UFS"; + case 0xA9: + return "NetBSD"; + case 0xAA: + return "Olivetti DOS FAT12"; + case 0xAB: + return "Apple Boot"; + case 0xAF: + return "Apple HFS"; + case 0xB0: + return "BootStar"; + case 0xB1: + return "HP Volume Expansion"; + case 0xB3: + return "HP Volume Expansion"; + case 0xB4: + return "HP Volume Expansion"; + case 0xB6: + return "HP Volume Expansion"; + case 0xB7: + return "BSDi"; + case 0xB8: + return "BSDi swap"; + case 0xBB: + return "PTS BootWizard"; + case 0xBE: + return "Solaris boot"; + case 0xBF: + return "Solaris"; + case 0xC0: + return "Novell DOS, DR-DOS secured"; + case 0xC1: + return "DR-DOS secured FAT12"; + case 0xC2: + return "DR-DOS reserved"; + case 0xC3: + return "DR-DOS reserved"; + case 0xC4: + return "DR-DOS secured FAT16 < 32 MiB"; + case 0xC6: + return "DR-DOS secured FAT16"; + case 0xC7: + return "Syrinx"; + case 0xC8: + return "DR-DOS reserved"; + case 0xC9: + return "DR-DOS reserved"; + case 0xCA: + return "DR-DOS reserved"; + case 0xCB: + return "DR-DOS secured FAT32"; + case 0xCC: + return "DR-DOS secured FAT32 (LBA)"; + case 0xCD: + return "DR-DOS reserved"; + case 0xCE: + return "DR-DOS secured FAT16 (LBA)"; + case 0xCF: + return "DR-DOS secured extended (LBA)"; + case 0xD0: + return "Multiuser DOS secured FAT12"; + case 0xD1: + return "Multiuser DOS secured FAT12"; + case 0xD4: + return "Multiuser DOS secured FAT16 < 32 MiB"; + case 0xD5: + return "Multiuser DOS secured extended"; + case 0xD6: + return "Multiuser DOS secured FAT16"; + case 0xD8: + return "CP/M"; + case 0xDA: + return "Filesystem-less data"; + case 0xDB: + return "CP/M, CCP/M, CTOS"; + case 0xDE: + return "Dell partition"; + case 0xDF: + return "BootIt EMBRM"; + case 0xE1: + return "SpeedStor"; + case 0xE2: + return "DOS read/only"; + case 0xE3: + return "SpeedStor"; + case 0xE4: + return "SpeedStor"; + case 0xE5: + return "Tandy DOS"; + case 0xE6: + return "SpeedStor"; + case 0xEB: + return "BeOS"; + case 0xED: + return "Spryt*x"; + case 0xEE: + return "Guid Partition Table"; + case 0xEF: + return "EFI system partition"; + case 0xF0: + return "Linux boot"; + case 0xF1: + return "SpeedStor"; + case 0xF2: + return "DOS 3.3 secondary, Unisys DOS"; + case 0xF3: + return "SpeedStor"; + case 0xF4: + return "SpeedStor"; + case 0xF5: + return "Prologue"; + case 0xF6: + return "SpeedStor"; + case 0xFB: + return "VMWare VMFS"; + case 0xFC: + return "VMWare VMKCORE"; + case 0xFD: + return "Linux RAID, FreeDOS"; + case 0xFE: + return "SpeedStor, LANStep, PS/2 IML"; + case 0xFF: + return "Xenix bad block"; + default: + return "Unknown"; + } + } - private struct UNIXVTOCEntry - { - public UInt16 tag; // TAG - public UInt16 flags; // Flags (see below) - public UInt32 start; // Start sector - public UInt32 length; // Length of slice in sectors - } + public struct MBRPartitionEntry + { + public byte status; + // Partition status, 0x80 or 0x00, else invalid + public byte start_head; + // Starting head [0,254] + public byte start_sector; + // Starting sector [1,63] + public UInt16 start_cylinder; + // Starting cylinder [0,1023] + public byte type; + // Partition type + public byte end_head; + // Ending head [0,254] + public byte end_sector; + // Ending sector [1,63] + public UInt16 end_cylinder; + // Ending cylinder [0,1023] + public UInt32 lba_start; + // Starting absolute sector + public UInt32 lba_sectors; + // Total sectors + } - private const UInt16 UNIX_TAG_EMPTY = 0x0000; // empty - private const UInt16 UNIX_TAG_BOOT = 0x0001; // boot - private const UInt16 UNIX_TAG_ROOT = 0x0002; // root - private const UInt16 UNIX_TAG_SWAP = 0x0003; // swap - private const UInt16 UNIX_TAG_USER = 0x0004; // /usr - private const UInt16 UNIX_TAG_WHOLE = 0x0005; // whole disk - private const UInt16 UNIX_TAG_STAND = 0x0006; // stand partition ?? - private const UInt16 UNIX_TAG_ALT_S = 0x0006; // alternate sector space - private const UInt16 UNIX_TAG_VAR = 0x0007; // /var - private const UInt16 UNIX_TAG_OTHER = 0x0007; // non UNIX - private const UInt16 UNIX_TAG_HOME = 0x0008; // /home - private const UInt16 UNIX_TAG_ALT_T = 0x0008; // alternate track space - private const UInt16 UNIX_TAG_ALT_ST = 0x0009; // alternate sector track - private const UInt16 UNIX_TAG_NEW_STAND = 0x0009; // stand partition ?? - private const UInt16 UNIX_TAG_CACHE = 0x000A; // cache - private const UInt16 UNIX_TAG_NEW_VAR = 0x000A; // /var - private const UInt16 UNIX_TAG_RESERVED = 0x000B; // reserved - private const UInt16 UNIX_TAG_NEW_HOME = 0x000B; // /home - private const UInt16 UNIX_TAG_DUMP = 0x000C; // dump partition - private const UInt16 UNIX_TAG_NEW_ALT_ST = 0x000D; // alternate sector track - private const UInt16 UNIX_TAG_VM_PUBLIC = 0x000E; // volume mgt public partition - private const UInt16 UNIX_TAG_VM_PRIVATE = 0x000F; // volume mgt private partition + private const UInt32 UNIXDiskLabel_MAGIC = 0xCA5E600D; + private const UInt32 UNIXVTOC_MAGIC = 0x600DDEEE; + // Same as Solaris VTOC + private struct UNIXDiskLabel + { + public UInt32 type; + // Drive type, seems always 0 + public UInt32 magic; + // UNIXDiskLabel_MAGIC + public UInt32 version; + // Only seen 1 + public string serial; + // 12 bytes, serial number of the device + public UInt32 cyls; + // data cylinders per device + public UInt32 trks; + // data tracks per cylinder + public UInt32 secs; + // data sectors per track + public UInt32 bps; + // data bytes per sector + public UInt32 start; + // first sector of this partition + public byte[] unknown1; + // 48 bytes + public UInt32 alt_tbl; + // byte offset of alternate table + public UInt32 alt_len; + // byte length of alternate table + // From onward here, is not on old version + public UInt32 phys_cyl; + // physical cylinders per device + public UInt32 phys_trk; + // physical tracks per cylinder + public UInt32 phys_sec; + // physical sectors per track + public UInt32 phys_bytes; + // physical bytes per sector + public UInt32 unknown2; + // + public UInt32 unknown3; + // + public byte[] pad; + // 32bytes + } - private string decodeUNIXTAG(UInt16 type, bool isNew) - { - switch(type) - { - case UNIX_TAG_EMPTY: - return "Unused"; - case UNIX_TAG_BOOT: - return "Boot"; - case UNIX_TAG_ROOT: - return "/"; - case UNIX_TAG_SWAP: - return "Swap"; - case UNIX_TAG_USER: - return "/usr"; - case UNIX_TAG_WHOLE: - return "Whole disk"; - case UNIX_TAG_STAND: - if(isNew) - return "Stand"; - else - return "Alternate sector space"; - case UNIX_TAG_VAR: - if(isNew) - return "/var"; - else - return "non UNIX"; - case UNIX_TAG_HOME: - if(isNew) - return "/home"; - else - return "Alternate track space"; - case UNIX_TAG_ALT_ST: - if(isNew) - return "Alternate sector track"; - else - return "Stand"; - case UNIX_TAG_CACHE: - if(isNew) - return "Cache"; - else - return "/var"; - case UNIX_TAG_RESERVED: - if(isNew) - return "Reserved"; - else - return "/home"; - case UNIX_TAG_DUMP: - return "dump"; - case UNIX_TAG_NEW_ALT_ST: - return "Alternate sector track"; - case UNIX_TAG_VM_PUBLIC: - return "volume mgt public partition"; - case UNIX_TAG_VM_PRIVATE: - return "volume mgt private partition"; - default: - return String.Format ("Unknown TAG: 0x{0:X4}", type); - } - } - } + private struct UNIXVTOC + { + public UInt32 magic; + // UNIXVTOC_MAGIC + public UInt32 version; + // 1 + public string name; + // 8 bytes + public UInt16 slices; + // # of slices + public UInt16 unknown; + // + public byte[] reserved; + // 40 bytes + } + + private struct UNIXVTOCEntry + { + public UInt16 tag; + // TAG + public UInt16 flags; + // Flags (see below) + public UInt32 start; + // Start sector + public UInt32 length; + // Length of slice in sectors + } + + private const UInt16 UNIX_TAG_EMPTY = 0x0000; + // empty + private const UInt16 UNIX_TAG_BOOT = 0x0001; + // boot + private const UInt16 UNIX_TAG_ROOT = 0x0002; + // root + private const UInt16 UNIX_TAG_SWAP = 0x0003; + // swap + private const UInt16 UNIX_TAG_USER = 0x0004; + // /usr + private const UInt16 UNIX_TAG_WHOLE = 0x0005; + // whole disk + private const UInt16 UNIX_TAG_STAND = 0x0006; + // stand partition ?? + private const UInt16 UNIX_TAG_ALT_S = 0x0006; + // alternate sector space + private const UInt16 UNIX_TAG_VAR = 0x0007; + // /var + private const UInt16 UNIX_TAG_OTHER = 0x0007; + // non UNIX + private const UInt16 UNIX_TAG_HOME = 0x0008; + // /home + private const UInt16 UNIX_TAG_ALT_T = 0x0008; + // alternate track space + private const UInt16 UNIX_TAG_ALT_ST = 0x0009; + // alternate sector track + private const UInt16 UNIX_TAG_NEW_STAND = 0x0009; + // stand partition ?? + private const UInt16 UNIX_TAG_CACHE = 0x000A; + // cache + private const UInt16 UNIX_TAG_NEW_VAR = 0x000A; + // /var + private const UInt16 UNIX_TAG_RESERVED = 0x000B; + // reserved + private const UInt16 UNIX_TAG_NEW_HOME = 0x000B; + // /home + private const UInt16 UNIX_TAG_DUMP = 0x000C; + // dump partition + private const UInt16 UNIX_TAG_NEW_ALT_ST = 0x000D; + // alternate sector track + private const UInt16 UNIX_TAG_VM_PUBLIC = 0x000E; + // volume mgt public partition + private const UInt16 UNIX_TAG_VM_PRIVATE = 0x000F; + // volume mgt private partition + private string decodeUNIXTAG(UInt16 type, bool isNew) + { + switch (type) + { + case UNIX_TAG_EMPTY: + return "Unused"; + case UNIX_TAG_BOOT: + return "Boot"; + case UNIX_TAG_ROOT: + return "/"; + case UNIX_TAG_SWAP: + return "Swap"; + case UNIX_TAG_USER: + return "/usr"; + case UNIX_TAG_WHOLE: + return "Whole disk"; + case UNIX_TAG_STAND: + if (isNew) + return "Stand"; + else + return "Alternate sector space"; + case UNIX_TAG_VAR: + if (isNew) + return "/var"; + else + return "non UNIX"; + case UNIX_TAG_HOME: + if (isNew) + return "/home"; + else + return "Alternate track space"; + case UNIX_TAG_ALT_ST: + if (isNew) + return "Alternate sector track"; + else + return "Stand"; + case UNIX_TAG_CACHE: + if (isNew) + return "Cache"; + else + return "/var"; + case UNIX_TAG_RESERVED: + if (isNew) + return "Reserved"; + else + return "/home"; + case UNIX_TAG_DUMP: + return "dump"; + case UNIX_TAG_NEW_ALT_ST: + return "Alternate sector track"; + case UNIX_TAG_VM_PUBLIC: + return "volume mgt public partition"; + case UNIX_TAG_VM_PRIVATE: + return "volume mgt private partition"; + default: + return String.Format("Unknown TAG: 0x{0:X4}", type); + } + } + } } \ No newline at end of file diff --git a/FileSystemIDandChk/PartPlugins/NeXT.cs b/FileSystemIDandChk/PartPlugins/NeXT.cs index 2d67b8ca6..67c0e81dd 100644 --- a/FileSystemIDandChk/PartPlugins/NeXT.cs +++ b/FileSystemIDandChk/PartPlugins/NeXT.cs @@ -6,140 +6,159 @@ using FileSystemIDandChk; namespace FileSystemIDandChk.PartPlugins { - class NeXTDisklabel : PartPlugin - { - public const UInt32 NEXT_MAGIC1 = 0x4E655854; // "NeXT" - public const UInt32 NEXT_MAGIC2 = 0x646C5632; // "dlV2" - public const UInt32 NEXT_MAGIC3 = 0x646C5633; // "dlV3" + class NeXTDisklabel : PartPlugin + { + const UInt32 NEXT_MAGIC1 = 0x4E655854; + // "NeXT" + const UInt32 NEXT_MAGIC2 = 0x646C5632; + // "dlV2" + const UInt32 NEXT_MAGIC3 = 0x646C5633; + // "dlV3" - public NeXTDisklabel (PluginBase Core) - { - base.Name = "NeXT Disklabel"; - base.PluginUUID = new Guid("246A6D93-4F1A-1F8A-344D-50187A5513A9"); - } - - public override bool GetInformation (FileStream stream, out List<Partition> partitions) - { - byte[] cString; - bool magic_found = false; - - UInt32 magic; - UInt32 sector_size; - UInt16 front_porch; - - partitions = new List<Partition>(); + const UInt16 disktabStart = 0xB4; // 180 + const UInt16 disktabEntrySize = 0x2C; // 44 - EndianAwareBinaryReader eabr = new EndianAwareBinaryReader(stream, false); // BigEndian + 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; - eabr.BaseStream.Seek(0, SeekOrigin.Begin); // Starts on sector 0 on NeXT machines, CDs and floppies - magic = eabr.ReadUInt32(); + UInt32 magic; + UInt32 sector_size; + UInt16 front_porch; + + if (imagePlugin.GetSectorSize() == 2352 || imagePlugin.GetSectorSize() == 2448) + sector_size = 2048; + else + sector_size = imagePlugin.GetSectorSize(); - if(magic == NEXT_MAGIC1 || magic == NEXT_MAGIC2 || magic == NEXT_MAGIC3) - magic_found = true; - else - { - eabr.BaseStream.Seek(0x1E00, SeekOrigin.Begin); // Starts on sector 15 on MBR machines - magic = eabr.ReadUInt32(); - - if(magic == NEXT_MAGIC1 || magic == NEXT_MAGIC2 || magic == NEXT_MAGIC3) - magic_found = true; - else - { - eabr.BaseStream.Seek(0x2000, SeekOrigin.Begin); // Starts on sector 16 (4 on CD) on RISC disks - magic = eabr.ReadUInt32(); + 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; - } - } + if (magic == NEXT_MAGIC1 || magic == NEXT_MAGIC2 || magic == NEXT_MAGIC3) + magic_found = true; + else + return false; + } + } - if(magic_found) - { - eabr.BaseStream.Seek(88, SeekOrigin.Current); // Seek to sector size - sector_size = eabr.ReadUInt32(); - eabr.BaseStream.Seek(16, SeekOrigin.Current); // Seek to front porch - front_porch = eabr.ReadUInt16(); - - eabr.BaseStream.Seek(76, SeekOrigin.Current); // Seek to first partition entry - - for(int i = 0; i < 8; i ++) - { - NeXTEntry entry = new NeXTEntry(); + front_porch = BigEndianBitConverter.ToUInt16(entry_sector, 0x6A); - entry.start = eabr.ReadUInt32(); - entry.sectors = eabr.ReadUInt32(); - entry.block_size = eabr.ReadUInt16(); - entry.frag_size = eabr.ReadUInt16(); - entry.optimization = eabr.ReadByte(); - entry.cpg = eabr.ReadUInt16(); - entry.bpi = eabr.ReadUInt16(); - entry.freemin = eabr.ReadByte(); - entry.unknown = eabr.ReadByte(); - entry.newfs = eabr.ReadByte(); - cString = eabr.ReadBytes(16); - entry.mount_point = StringHandlers.CToString(cString); - entry.automount = eabr.ReadByte(); - cString = eabr.ReadBytes(8); - entry.type = StringHandlers.CToString(cString); - entry.unknown2 = eabr.ReadByte(); - - if(entry.sectors > 0 && entry.sectors < 0xFFFFFFFF && entry.start < 0xFFFFFFFF) - { - Partition part = new Partition(); - StringBuilder sb = new StringBuilder(); + 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 = (long)entry.sectors * sector_size; - part.PartitionStart = ((long)entry.start + front_porch) * sector_size; - part.PartitionType = entry.type; - part.PartitionSequence = (ulong)i; - part.PartitionName = entry.mount_point; + 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 news has been already run + 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"); + if (entry.automount == 1) + sb.AppendLine("Filesystem should be automatically mounted"); - part.PartitionDescription = sb.ToString(); + part.PartitionDescription = sb.ToString(); - partitions.Add(part); - } - } + partitions.Add(part); + } + } - return true; - } - else - return false; - } - - private 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 unknown; // Unknown - 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"? - public byte unknown2; // Unknown - } - } + 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"? + } + } } \ No newline at end of file diff --git a/FileSystemIDandChk/PartPlugins/PartPlugin.cs b/FileSystemIDandChk/PartPlugins/PartPlugin.cs index ae2411cc7..696d8df8f 100644 --- a/FileSystemIDandChk/PartPlugins/PartPlugin.cs +++ b/FileSystemIDandChk/PartPlugins/PartPlugin.cs @@ -4,25 +4,35 @@ using System.Collections.Generic; namespace FileSystemIDandChk.PartPlugins { - public abstract class PartPlugin - { - public string Name; + public abstract class PartPlugin + { + public string Name; public Guid PluginUUID; - - protected PartPlugin () - { - } - - public abstract bool GetInformation(FileStream stream, out List<Partition> partitions); - } - - public struct Partition - { - public ulong PartitionSequence; // Partition number, 0-started - public string PartitionType; // Partition type - public string PartitionName; // Partition name (if the scheme supports it) - public long PartitionStart; // Start of the partition, in bytes - public long PartitionLength; // Length in bytes of the partition - public string PartitionDescription; // Information that does not find space in this struct - } + + protected PartPlugin() + { + } + + public abstract bool GetInformation(ImagePlugins.ImagePlugin imagePlugin, out List<Partition> partitions); + } + + public struct Partition + { + public ulong PartitionSequence; + // Partition number, 0-started + public string PartitionType; + // Partition type + public string PartitionName; + // Partition name (if the scheme supports it) + public ulong PartitionStart; + // Start of the partition, in bytes + public ulong PartitionStartSector; + // LBA of partition start + public ulong PartitionLength; + // Length in bytes of the partition + public ulong PartitionSectors; + // Length in sectors of the partition + public string PartitionDescription; + // Information that does not find space in this struct + } } \ No newline at end of file diff --git a/FileSystemIDandChk/Plugins/AppleHFS.cs b/FileSystemIDandChk/Plugins/AppleHFS.cs index 0daec9444..eab4b0cea 100644 --- a/FileSystemIDandChk/Plugins/AppleHFS.cs +++ b/FileSystemIDandChk/Plugins/AppleHFS.cs @@ -4,7 +4,7 @@ using System.Text; using FileSystemIDandChk; // Information from Inside Macintosh - +// https://developer.apple.com/legacy/library/documentation/mac/pdf/Files/File_Manager.pdf namespace FileSystemIDandChk.Plugins { class AppleHFS : Plugin @@ -19,20 +19,14 @@ namespace FileSystemIDandChk.Plugins base.PluginUUID = new Guid("36405F8D-0D26-6ECC-0BBB-1D5225FF404F"); } - public override bool Identify(FileStream stream, long offset) + public override bool Identify(ImagePlugins.ImagePlugin imagePlugin, ulong partitionOffset) { - byte[] signature = new byte[2]; - UInt16 drSigWord; + byte[] mdb_sector = imagePlugin.ReadSector(2 + partitionOffset); + UInt16 drSigWord = BigEndianBitConverter.ToUInt16(mdb_sector, 0); - EndianAwareBinaryReader eabr = new EndianAwareBinaryReader(stream, false); // BigEndian - eabr.BaseStream.Seek(0x400 + offset, SeekOrigin.Begin); - - drSigWord = eabr.ReadUInt16(); - if(drSigWord == HFS_MAGIC) { - eabr.BaseStream.Seek(0x47C + offset, SeekOrigin.Begin); // Seek to embedded HFS+ signature - drSigWord = eabr.ReadUInt16(); + drSigWord = BigEndianBitConverter.ToUInt16(mdb_sector, 0x7C); // Seek to embedded HFS+ signature if(drSigWord == HFSP_MAGIC) // "H+" return false; @@ -43,7 +37,7 @@ namespace FileSystemIDandChk.Plugins return false; } - public override void GetInformation (FileStream stream, long offset, out string information) + public override void GetInformation (ImagePlugins.ImagePlugin imagePlugin, ulong partitionOffset, out string information) { information = ""; @@ -54,85 +48,95 @@ namespace FileSystemIDandChk.Plugins byte[] pString; - EndianAwareBinaryReader eabr = new EndianAwareBinaryReader(stream, false); // BigEndian - eabr.BaseStream.Seek(0x400 + offset, SeekOrigin.Begin); - MDB.drSigWord = eabr.ReadUInt16(); + 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 = eabr.ReadUInt32(); - MDB.drLsMod = eabr.ReadUInt32(); - MDB.drAtrb = eabr.ReadUInt16(); - MDB.drNmFls = eabr.ReadUInt16(); - MDB.drVBMSt = eabr.ReadUInt16(); - MDB.drAllocPtr = eabr.ReadUInt16(); - MDB.drNmAlBlks = eabr.ReadUInt16(); - MDB.drAlBlkSiz = eabr.ReadUInt32(); - MDB.drClpSiz = eabr.ReadUInt32(); - MDB.drAlBlSt = eabr.ReadUInt16(); - MDB.drNxtCNID = eabr.ReadUInt32(); - MDB.drFreeBks = eabr.ReadUInt16(); - pString = eabr.ReadBytes(28); + 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 = eabr.ReadUInt32(); - MDB.drVSeqNum = eabr.ReadUInt16(); - MDB.drWrCnt = eabr.ReadUInt32(); - MDB.drXTClpSiz = eabr.ReadUInt32(); - MDB.drCTClpSiz = eabr.ReadUInt32(); - MDB.drNmRtDirs = eabr.ReadUInt16(); - MDB.drFilCnt = eabr.ReadUInt32(); - MDB.drDirCnt = eabr.ReadUInt32(); + 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 = eabr.ReadUInt32(); - MDB.drFndrInfo1 = eabr.ReadUInt32(); - MDB.drFndrInfo2 = eabr.ReadUInt32(); - MDB.drFndrInfo3 = eabr.ReadUInt32(); - MDB.drFndrInfo4 = eabr.ReadUInt32(); - MDB.drFndrInfo5 = eabr.ReadUInt32(); - MDB.drFndrInfo6 = eabr.ReadUInt32(); - MDB.drFndrInfo7 = eabr.ReadUInt32(); + 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.drEmbedSigWord = eabr.ReadUInt16(); - MDB.xdrStABNt = eabr.ReadUInt16(); - MDB.xdrNumABlks = eabr.ReadUInt16(); + MDB.drXTFlSize = BigEndianBitConverter.ToUInt32(mdb_sector, 0x082); + MDB.drCTFlSize = BigEndianBitConverter.ToUInt32(mdb_sector, 0x092); - MDB.drXTFlSize = eabr.ReadUInt32(); - eabr.BaseStream.Seek(12, SeekOrigin.Current); - MDB.drCTFlSize = eabr.ReadUInt32(); - eabr.BaseStream.Seek(12, SeekOrigin.Current); - - eabr.BaseStream.Seek(0 + offset, SeekOrigin.Begin); - BB.signature = eabr.ReadUInt16(); + BB.signature = BigEndianBitConverter.ToUInt16(bb_sector, 0x000); if(BB.signature == HFSBB_MAGIC) { - BB.branch = eabr.ReadUInt32(); - BB.boot_flags = eabr.ReadByte(); - BB.boot_version = eabr.ReadByte(); + BB.branch = BigEndianBitConverter.ToUInt32(bb_sector, 0x002); + BB.boot_flags = bb_sector[0x006]; + BB.boot_version = bb_sector[0x007]; - BB.sec_sv_pages = eabr.ReadInt16(); + BB.sec_sv_pages = BigEndianBitConverter.ToInt16(bb_sector, 0x008); - pString = eabr.ReadBytes(16); + pString = new byte[16]; + Array.Copy(bb_sector, 0x00A, pString, 0, 16); BB.system_name = StringHandlers.PascalToString(pString); - pString = eabr.ReadBytes(16); + pString = new byte[16]; + Array.Copy(bb_sector, 0x01A, pString, 0, 16); BB.finder_name = StringHandlers.PascalToString(pString); - pString = eabr.ReadBytes(16); + pString = new byte[16]; + Array.Copy(bb_sector, 0x02A, pString, 0, 16); BB.debug_name = StringHandlers.PascalToString(pString); - pString = eabr.ReadBytes(16); + pString = new byte[16]; + Array.Copy(bb_sector, 0x03A, pString, 0, 16); BB.disasm_name = StringHandlers.PascalToString(pString); - pString = eabr.ReadBytes(16); + pString = new byte[16]; + Array.Copy(bb_sector, 0x04A, pString, 0, 16); BB.stupscr_name = StringHandlers.PascalToString(pString); - pString = eabr.ReadBytes(16); + pString = new byte[16]; + Array.Copy(bb_sector, 0x05A, pString, 0, 16); BB.bootup_name = StringHandlers.PascalToString(pString); - pString = eabr.ReadBytes(16); + pString = new byte[16]; + Array.Copy(bb_sector, 0x06A, pString, 0, 16); BB.clipbrd_name = StringHandlers.PascalToString(pString); - BB.max_files = eabr.ReadUInt16(); - BB.queue_size = eabr.ReadUInt16(); - BB.heap_128k = eabr.ReadUInt32(); - BB.heap_256k = eabr.ReadUInt32(); - BB.heap_512k = eabr.ReadUInt32(); + 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; @@ -202,6 +206,12 @@ namespace FileSystemIDandChk.Plugins 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) { @@ -243,67 +253,72 @@ namespace FileSystemIDandChk.Plugins return; } - private struct HFS_MasterDirectoryBlock // Should be offset 0x0400 bytes in volume + private struct HFS_MasterDirectoryBlock // Should be sector 2 in volume { - public UInt16 drSigWord; // Signature, 0x4244 - public ulong drCrDate; // Volume creation date - public ulong drLsMod; // Volume last modification date - public UInt16 drAtrb; // Volume attributes - public UInt16 drNmFls; // Files in root directory - public UInt16 drVBMSt; // Start 512-byte sector of volume bitmap - public UInt16 drAllocPtr; // Allocation block to begin next allocation - public UInt16 drNmAlBlks; // Allocation blocks - public UInt32 drAlBlkSiz; // Bytes per allocation block - public UInt32 drClpSiz; // Bytes to allocate when extending a file - public UInt16 drAlBlSt; // Start 512-byte sector of first allocation block - public UInt32 drNxtCNID; // CNID for next file - public UInt16 drFreeBks; // Free allocation blocks - public string drVN; // Volume name (28 bytes) - public ulong drVolBkUp; // Volume last backup time - public UInt16 drVSeqNum; // Volume backup sequence number - public UInt32 drWrCnt; // Filesystem write count - public UInt32 drXTClpSiz; // Bytes to allocate when extending the extents B-Tree - public UInt32 drCTClpSiz; // Bytes to allocate when extending the catalog B-Tree - public UInt16 drNmRtDirs; // Number of directories in root directory - public UInt32 drFilCnt; // Number of files in the volume - public UInt32 drDirCnt; // Number of directories in the volume - public UInt32 drFndrInfo0; // finderInfo[0], CNID for bootable system's directory - public UInt32 drFndrInfo1; // finderInfo[1], CNID of the directory containing the boot application - public UInt32 drFndrInfo2; // finderInfo[2], CNID of the directory that should be opened on boot - public UInt32 drFndrInfo3; // finderInfo[3], CNID for Mac OS 8 or 9 directory - public UInt32 drFndrInfo4; // finderInfo[4], Reserved - public UInt32 drFndrInfo5; // finderInfo[5], CNID for Mac OS X directory - public UInt32 drFndrInfo6; // finderInfo[6], first part of Mac OS X volume ID - public UInt32 drFndrInfo7; // finderInfo[7], second part of Mac OS X volume ID - public UInt16 drEmbedSigWord; // Embedded volume signature, "H+" if HFS+ is embedded ignore following two fields if not - public UInt16 xdrStABNt; // Starting block number of embedded HFS+ volume - public UInt16 xdrNumABlks; // Allocation blocks used by embedded volume - public UInt32 drXTFlSize; // Bytes in the extents B-Tree + 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; // Bytes in the catalog B-Tree + public UInt32 drCTFlSize; // 0x092, Bytes in the catalog B-Tree // 3 HFS extents following, 32 bits each } - private struct HFS_BootBlock // Should be offset 0x0000 bytes in volume + private struct HFS_BootBlock // Should be sectors 0 and 1 in volume { - public UInt16 signature; // Signature, 0x4C4B if bootable - public UInt32 branch; // Branch - public byte boot_flags; // Boot block flags - public byte boot_version; // Boot block version - public Int16 sec_sv_pages; // Allocate secondary buffers - public string system_name; // System file name (10 bytes) - public string finder_name; // Finder file name (10 bytes) - public string debug_name; // Debugger file name (10 bytes) - public string disasm_name; // Disassembler file name (10 bytes) - public string stupscr_name; // Startup screen file name (10 bytes) - public string bootup_name; // First program to execute on boot (10 bytes) - public string clipbrd_name; // Clipboard file name (10 bytes) - public UInt16 max_files; // 1/4 of maximum opened at a time files - public UInt16 queue_size; // Event queue size - public UInt32 heap_128k; // Heap size on a Mac with 128KiB of RAM - public UInt32 heap_256k; // Heap size on a Mac with 256KiB of RAM - public UInt32 heap_512k; // Heap size on a Mac with 512KiB of RAM or more + 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 } } - diff --git a/FileSystemIDandChk/Plugins/AppleHFSPlus.cs b/FileSystemIDandChk/Plugins/AppleHFSPlus.cs index 4d2a1ebbe..5e1cff416 100644 --- a/FileSystemIDandChk/Plugins/AppleHFSPlus.cs +++ b/FileSystemIDandChk/Plugins/AppleHFSPlus.cs @@ -3,8 +3,7 @@ using System.IO; using System.Text; using FileSystemIDandChk; -// Information from Inside Macintosh - +// Information from Apple TechNote 1150: https://developer.apple.com/legacy/library/technotes/tn/tn1150.html namespace FileSystemIDandChk.Plugins { class AppleHFSPlus : Plugin @@ -19,36 +18,33 @@ namespace FileSystemIDandChk.Plugins base.PluginUUID = new Guid("36405F8D-0D26-6EBE-436F-62F0586B4F08"); } - public override bool Identify(FileStream stream, long offset) + public override bool Identify(ImagePlugins.ImagePlugin imagePlugin, ulong partitionOffset) { UInt16 drSigWord; UInt16 xdrStABNt; UInt16 drAlBlSt; UInt32 drAlBlkSiz; - long hfsp_offset; + byte[] vh_sector; + ulong hfsp_offset; - EndianAwareBinaryReader eabr = new EndianAwareBinaryReader(stream, false); // BigEndian - eabr.BaseStream.Seek(0x400 + offset, SeekOrigin.Begin); + vh_sector = imagePlugin.ReadSector(2 + partitionOffset); // Read volume header, of HFS Wrapper MDB - drSigWord = eabr.ReadUInt16(); + drSigWord = BigEndianBitConverter.ToUInt16(vh_sector, 0); // Check for HFS Wrapper MDB if(drSigWord == HFS_MAGIC) // "BD" { - eabr.BaseStream.Seek(0x47C + offset, SeekOrigin.Begin); // Seek to embedded HFS+ signature - drSigWord = eabr.ReadUInt16(); + drSigWord = BigEndianBitConverter.ToUInt16(vh_sector, 0x07C); // Read embedded HFS+ signature if(drSigWord == HFSP_MAGIC) // "H+" { - xdrStABNt = eabr.ReadUInt16(); + xdrStABNt = BigEndianBitConverter.ToUInt16(vh_sector, 0x07E); // Starting block number of embedded HFS+ volume - eabr.BaseStream.Seek(0x414 + offset, SeekOrigin.Begin); - drAlBlkSiz = eabr.ReadUInt32(); + drAlBlkSiz = BigEndianBitConverter.ToUInt32(vh_sector, 0x014); // Block size - eabr.BaseStream.Seek(0x41C + offset, SeekOrigin.Begin); - drAlBlSt = eabr.ReadUInt16(); + drAlBlSt = BigEndianBitConverter.ToUInt16(vh_sector, 0x01C); // Start of allocated blocks (in 512-byte/block) - hfsp_offset = (drAlBlSt + xdrStABNt * (drAlBlkSiz / 512))*512; + hfsp_offset = (drAlBlSt + xdrStABNt * (drAlBlkSiz / 512))*(imagePlugin.GetSectorSize() / 512); } else { @@ -60,16 +56,16 @@ namespace FileSystemIDandChk.Plugins hfsp_offset = 0; } - eabr.BaseStream.Seek(0x400 + offset + hfsp_offset, SeekOrigin.Begin); + vh_sector = imagePlugin.ReadSector(2 + partitionOffset + hfsp_offset); // Read volume header - drSigWord = eabr.ReadUInt16(); + drSigWord = BigEndianBitConverter.ToUInt16(vh_sector, 0); if(drSigWord == HFSP_MAGIC || drSigWord == HFSX_MAGIC) return true; else return false; } - public override void GetInformation (FileStream stream, long offset, out string information) + public override void GetInformation (ImagePlugins.ImagePlugin imagePlugin, ulong partitionOffset, out string information) { information = ""; @@ -79,30 +75,27 @@ namespace FileSystemIDandChk.Plugins UInt32 drAlBlkSiz; HFSPlusVolumeHeader HPVH = new HFSPlusVolumeHeader(); - long hfsp_offset; + ulong hfsp_offset; bool wrapped = false; - EndianAwareBinaryReader eabr = new EndianAwareBinaryReader(stream, false); // BigEndian + byte[] vh_sector; - eabr.BaseStream.Seek(0x400 + offset, SeekOrigin.Begin); - - drSigWord = eabr.ReadUInt16(); + 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" { - eabr.BaseStream.Seek(0x47C + offset, SeekOrigin.Begin); // Seek to embedded HFS+ signature - drSigWord = eabr.ReadUInt16(); + drSigWord = BigEndianBitConverter.ToUInt16(vh_sector, 0x07C); // Read embedded HFS+ signature if(drSigWord == HFSP_MAGIC) // "H+" { - xdrStABNt = eabr.ReadUInt16(); - - eabr.BaseStream.Seek(0x414 + offset, SeekOrigin.Begin); - drAlBlkSiz = eabr.ReadUInt32(); - - eabr.BaseStream.Seek(0x41C + offset, SeekOrigin.Begin); - drAlBlSt = eabr.ReadUInt16(); - - hfsp_offset = (drAlBlSt + xdrStABNt * (drAlBlkSiz / 512))*512; + 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 @@ -117,9 +110,9 @@ namespace FileSystemIDandChk.Plugins wrapped = false; } - eabr.BaseStream.Seek(0x400 + offset + hfsp_offset, SeekOrigin.Begin); + vh_sector = imagePlugin.ReadSector(2 + partitionOffset + hfsp_offset); // Read volume header - HPVH.signature = eabr.ReadUInt16(); + HPVH.signature = BigEndianBitConverter.ToUInt16(vh_sector, 0x000); if(HPVH.signature == HFSP_MAGIC || HPVH.signature == HFSX_MAGIC) { StringBuilder sb = new StringBuilder(); @@ -131,53 +124,48 @@ namespace FileSystemIDandChk.Plugins if(wrapped) sb.AppendLine("Volume is wrapped inside an HFS volume."); - HPVH.version = eabr.ReadUInt16(); + HPVH.version = BigEndianBitConverter.ToUInt16(vh_sector, 0x002); if(HPVH.version == 4 || HPVH.version == 5) { - HPVH.attributes = eabr.ReadUInt32(); - byte[] lastMountedVersion_b = eabr.ReadBytes(4); + 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 = eabr.ReadUInt32(); + HPVH.journalInfoBlock = BigEndianBitConverter.ToUInt32(vh_sector, 0x00C); - HPVH.createDate = eabr.ReadUInt32(); - HPVH.modifyDate = eabr.ReadUInt32(); - HPVH.backupDate = eabr.ReadUInt32(); - HPVH.checkedDate = eabr.ReadUInt32(); + 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 = eabr.ReadUInt32(); - HPVH.folderCount = eabr.ReadUInt32(); + HPVH.fileCount = BigEndianBitConverter.ToUInt32(vh_sector, 0x030); + HPVH.folderCount = BigEndianBitConverter.ToUInt32(vh_sector, 0x034); - HPVH.blockSize = eabr.ReadUInt32(); - HPVH.totalBlocks = eabr.ReadUInt32(); - HPVH.freeBlocks = eabr.ReadUInt32(); + HPVH.blockSize = BigEndianBitConverter.ToUInt32(vh_sector, 0x038); + HPVH.totalBlocks = BigEndianBitConverter.ToUInt32(vh_sector, 0x03C); + HPVH.freeBlocks = BigEndianBitConverter.ToUInt32(vh_sector, 0x040); - HPVH.nextAllocation = eabr.ReadUInt32(); - HPVH.rsrcClumpSize = eabr.ReadUInt32(); - HPVH.dataClumpSize = eabr.ReadUInt32(); - HPVH.nextCatalogID = eabr.ReadUInt32(); + 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 = eabr.ReadUInt32(); - eabr.BaseStream.Seek(8,SeekOrigin.Current); // Skipping encoding bitmap + HPVH.writeCount = BigEndianBitConverter.ToUInt32(vh_sector, 0x054); - HPVH.drFndrInfo0 = eabr.ReadUInt32(); - HPVH.drFndrInfo1 = eabr.ReadUInt32(); - HPVH.drFndrInfo2 = eabr.ReadUInt32(); - HPVH.drFndrInfo3 = eabr.ReadUInt32(); - eabr.BaseStream.Seek(4, SeekOrigin.Current); // Skipping reserved finder info - HPVH.drFndrInfo5 = eabr.ReadUInt32(); - HPVH.drFndrInfo6 = eabr.ReadUInt32(); - HPVH.drFndrInfo7 = eabr.ReadUInt32(); + 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 = eabr.ReadUInt64(); - eabr.BaseStream.Seek(72, SeekOrigin.Current); // Skip to next file info - HPVH.extentsFile_logicalSize = eabr.ReadUInt64(); - eabr.BaseStream.Seek(72, SeekOrigin.Current); // Skip to next file info - HPVH.catalogFile_logicalSize = eabr.ReadUInt64(); - eabr.BaseStream.Seek(72, SeekOrigin.Current); // Skip to next file info - HPVH.attributesFile_logicalSize = eabr.ReadUInt64(); - eabr.BaseStream.Seek(72, SeekOrigin.Current); // Skip to next file info - HPVH.startupFile_logicalSize = eabr.ReadUInt64(); + 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(); @@ -239,150 +227,150 @@ namespace FileSystemIDandChk.Plugins else return; } - + + // Size = 532 bytes private struct HFSPlusVolumeHeader // Should be offset 0x0400 bytes in volume { - public UInt16 signature; // "H+" for HFS+, "HX" for HFSX - public UInt16 version; // 4 for HFS+, 5 for HFSX - public UInt32 attributes; // Volume attributes - public string lastMountedVersion; // Implementation that last mounted the 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; // Allocation block number containing the journal + public UInt32 journalInfoBlock; // 0x00C, Allocation block number containing the journal - public ulong createDate; // Date of volume creation - public ulong modifyDate; // Date of last volume modification - public ulong backupDate; // Date of last backup - public ulong checkedDate; // Date of last consistency check + 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; // File on the volume - public UInt32 folderCount; // Folders on the volume + public UInt32 fileCount; // 0x030, File on the volume + public UInt32 folderCount; // 0x034, Folders on the volume - public UInt32 blockSize; // Bytes per allocation block - public UInt32 totalBlocks; // Allocation blocks on the volume - public UInt32 freeBlocks; // Free allocation blocks + 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; // Hint for next allocation block - public UInt32 rsrcClumpSize; // Resource fork clump size - public UInt32 dataClumpSize; // Data fork clump size - public UInt32 nextCatalogID; // Next unused CNID + 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; // Times that the volume has been mounted writable - public UInt64 encodingsBitmap; // Used text encoding hints + public UInt32 writeCount; // 0x054, Times that the volume has been mounted writable + public UInt64 encodingsBitmap; // 0x058, Used text encoding hints - public UInt32 drFndrInfo0; // finderInfo[0], CNID for bootable system's directory - public UInt32 drFndrInfo1; // finderInfo[1], CNID of the directory containing the boot application - public UInt32 drFndrInfo2; // finderInfo[2], CNID of the directory that should be opened on boot - public UInt32 drFndrInfo3; // finderInfo[3], CNID for Mac OS 8 or 9 directory - public UInt32 drFndrInfo4; // finderInfo[4], Reserved - public UInt32 drFndrInfo5; // finderInfo[5], CNID for Mac OS X directory - public UInt32 drFndrInfo6; // finderInfo[6], first part of Mac OS X volume ID - public UInt32 drFndrInfo7; // finderInfo[7], second part of Mac OS X volume ID + 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; - public UInt32 allocationFile_clumpSize; - public UInt32 allocationFile_totalBlocks; - public UInt32 allocationFile_extents_startBlock0; - public UInt32 allocationFile_extents_blockCount0; - public UInt32 allocationFile_extents_startBlock1; - public UInt32 allocationFile_extents_blockCount1; - public UInt32 allocationFile_extents_startBlock2; - public UInt32 allocationFile_extents_blockCount2; - public UInt32 allocationFile_extents_startBlock3; - public UInt32 allocationFile_extents_blockCount3; - public UInt32 allocationFile_extents_startBlock4; - public UInt32 allocationFile_extents_blockCount4; - public UInt32 allocationFile_extents_startBlock5; - public UInt32 allocationFile_extents_blockCount5; - public UInt32 allocationFile_extents_startBlock6; - public UInt32 allocationFile_extents_blockCount6; - public UInt32 allocationFile_extents_startBlock7; - public UInt32 allocationFile_extents_blockCount7; + 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; - public UInt32 extentsFile_clumpSize; - public UInt32 extentsFile_totalBlocks; - public UInt32 extentsFile_extents_startBlock0; - public UInt32 extentsFile_extents_blockCount0; - public UInt32 extentsFile_extents_startBlock1; - public UInt32 extentsFile_extents_blockCount1; - public UInt32 extentsFile_extents_startBlock2; - public UInt32 extentsFile_extents_blockCount2; - public UInt32 extentsFile_extents_startBlock3; - public UInt32 extentsFile_extents_blockCount3; - public UInt32 extentsFile_extents_startBlock4; - public UInt32 extentsFile_extents_blockCount4; - public UInt32 extentsFile_extents_startBlock5; - public UInt32 extentsFile_extents_blockCount5; - public UInt32 extentsFile_extents_startBlock6; - public UInt32 extentsFile_extents_blockCount6; - public UInt32 extentsFile_extents_startBlock7; - public UInt32 extentsFile_extents_blockCount7; + 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; - public UInt32 catalogFile_clumpSize; - public UInt32 catalogFile_totalBlocks; - public UInt32 catalogFile_extents_startBlock0; - public UInt32 catalogFile_extents_blockCount0; - public UInt32 catalogFile_extents_startBlock1; - public UInt32 catalogFile_extents_blockCount1; - public UInt32 catalogFile_extents_startBlock2; - public UInt32 catalogFile_extents_blockCount2; - public UInt32 catalogFile_extents_startBlock3; - public UInt32 catalogFile_extents_blockCount3; - public UInt32 catalogFile_extents_startBlock4; - public UInt32 catalogFile_extents_blockCount4; - public UInt32 catalogFile_extents_startBlock5; - public UInt32 catalogFile_extents_blockCount5; - public UInt32 catalogFile_extents_startBlock6; - public UInt32 catalogFile_extents_blockCount6; - public UInt32 catalogFile_extents_startBlock7; - public UInt32 catalogFile_extents_blockCount7; + 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; - public UInt32 attributesFile_clumpSize; - public UInt32 attributesFile_totalBlocks; - public UInt32 attributesFile_extents_startBlock0; - public UInt32 attributesFile_extents_blockCount0; - public UInt32 attributesFile_extents_startBlock1; - public UInt32 attributesFile_extents_blockCount1; - public UInt32 attributesFile_extents_startBlock2; - public UInt32 attributesFile_extents_blockCount2; - public UInt32 attributesFile_extents_startBlock3; - public UInt32 attributesFile_extents_blockCount3; - public UInt32 attributesFile_extents_startBlock4; - public UInt32 attributesFile_extents_blockCount4; - public UInt32 attributesFile_extents_startBlock5; - public UInt32 attributesFile_extents_blockCount5; - public UInt32 attributesFile_extents_startBlock6; - public UInt32 attributesFile_extents_blockCount6; - public UInt32 attributesFile_extents_startBlock7; - public UInt32 attributesFile_extents_blockCount7; + 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; - public UInt32 startupFile_clumpSize; - public UInt32 startupFile_totalBlocks; - public UInt32 startupFile_extents_startBlock0; - public UInt32 startupFile_extents_blockCount0; - public UInt32 startupFile_extents_startBlock1; - public UInt32 startupFile_extents_blockCount1; - public UInt32 startupFile_extents_startBlock2; - public UInt32 startupFile_extents_blockCount2; - public UInt32 startupFile_extents_startBlock3; - public UInt32 startupFile_extents_blockCount3; - public UInt32 startupFile_extents_startBlock4; - public UInt32 startupFile_extents_blockCount4; - public UInt32 startupFile_extents_startBlock5; - public UInt32 startupFile_extents_blockCount5; - public UInt32 startupFile_extents_startBlock6; - public UInt32 startupFile_extents_blockCount6; - public UInt32 startupFile_extents_startBlock7; - public UInt32 startupFile_extents_blockCount7; + 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 } } } - diff --git a/FileSystemIDandChk/Plugins/AppleMFS.cs b/FileSystemIDandChk/Plugins/AppleMFS.cs index b70bca6c7..41fbc957b 100644 --- a/FileSystemIDandChk/Plugins/AppleMFS.cs +++ b/FileSystemIDandChk/Plugins/AppleMFS.cs @@ -4,7 +4,8 @@ using System.Text; using FileSystemIDandChk; // Information from Inside Macintosh - +// TODO: Implement support for disc images +/* namespace FileSystemIDandChk.Plugins { class AppleMFS : Plugin @@ -164,43 +165,43 @@ namespace FileSystemIDandChk.Plugins private struct MFS_MasterDirectoryBlock // Should be offset 0x0400 bytes in volume { - public UInt16 drSigWord; // Signature, 0xD2D7 - public ulong drCrDate; // Volume creation date - public ulong drLsBkUp; // Volume last backup date - public UInt16 drAtrb; // Volume attributes - public UInt16 drNmFls; // Volume number of files - public UInt16 drDirSt; // First directory block - public UInt16 drBlLen; // Length of directory in blocks - public UInt16 drNmAlBlks; // Volume allocation blocks - public UInt32 drAlBlkSiz; // Size of allocation blocks - public UInt32 drClpSiz; // Number of bytes to allocate - public UInt16 drAlBlSt; // First allocation block in block map - public UInt32 drNxtFNum; // Next unused file number - public UInt16 drFreeBks; // Number of unused allocation blocks - public byte drVNSiz; // Length of volume name - public string drVN; // Characters of volume name + public UInt16 drSigWord; // 0x000, Signature, 0xD2D7 + public ulong drCrDate; // 0x002, Volume creation date + public ulong drLsBkUp; // 0x00A, Volume last backup date + public UInt16 drAtrb; // 0x012, Volume attributes + public UInt16 drNmFls; // 0x014, Volume number of files + public UInt16 drDirSt; // 0x016, First directory block + public UInt16 drBlLen; // 0x018, Length of directory in blocks + public UInt16 drNmAlBlks; // 0x01A, Volume allocation blocks + public UInt32 drAlBlkSiz; // 0x01C, Size of allocation blocks + public UInt32 drClpSiz; // 0x020, Number of bytes to allocate + public UInt16 drAlBlSt; // 0x024, First allocation block in block map + public UInt32 drNxtFNum; // 0x026. Next unused file number + public UInt16 drFreeBks; // 0x02A, Number of unused allocation blocks + public byte drVNSiz; // 0x02C, Length of volume name + public string drVN; // 0x02D, Characters of volume name } private struct MFS_BootBlock // Should be offset 0x0000 bytes in volume { - public UInt16 signature; // Signature, 0x4C4B if bootable - public UInt32 branch; // Branch - public byte boot_flags; // Boot block flags - public byte boot_version; // Boot block version - public short sec_sv_pages; // Allocate secondary buffers - public string system_name; // System file name (10 bytes) - public string finder_name; // Finder file name (10 bytes) - public string debug_name; // Debugger file name (10 bytes) - public string disasm_name; // Disassembler file name (10 bytes) - public string stupscr_name; // Startup screen file name (10 bytes) - public string bootup_name; // First program to execute on boot (10 bytes) - public string clipbrd_name; // Clipboard file name (10 bytes) - public UInt16 max_files; // 1/4 of maximum opened at a time files - public UInt16 queue_size; // Event queue size - public UInt32 heap_128k; // Heap size on a Mac with 128KiB of RAM - public UInt32 heap_256k; // Heap size on a Mac with 256KiB of RAM - public UInt32 heap_512k; // Heap size on a Mac with 512KiB of RAM or more + 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 (10 bytes) + public string finder_name; // 0x014, Finder file name (10 bytes) + public string debug_name; // 0x01E, Debugger file name (10 bytes) + public string disasm_name; // 0x028, Disassembler file name (10 bytes) + public string stupscr_name; // 0x032, Startup screen file name (10 bytes) + public string bootup_name; // 0x03C, First program to execute on boot (10 bytes) + public string clipbrd_name; // 0x046, Clipboard file name (10 bytes) + public UInt16 max_files; // 0x050, 1/4 of maximum opened at a time files + public UInt16 queue_size; // 0x052, Event queue size + public UInt32 heap_128k; // 0x054, Heap size on a Mac with 128KiB of RAM + public UInt32 heap_256k; // 0x058, Heap size on a Mac with 256KiB of RAM + public UInt32 heap_512k; // 0x05C, Heap size on a Mac with 512KiB of RAM or more } // Follows boot code } } - +*/ diff --git a/FileSystemIDandChk/Plugins/BFS.cs b/FileSystemIDandChk/Plugins/BFS.cs index 41f1ec28d..69c829bab 100644 --- a/FileSystemIDandChk/Plugins/BFS.cs +++ b/FileSystemIDandChk/Plugins/BFS.cs @@ -3,8 +3,6 @@ using System.IO; using System.Text; using FileSystemIDandChk; -// Information from Inside Macintosh - namespace FileSystemIDandChk.Plugins { class BeFS : Plugin @@ -29,100 +27,93 @@ namespace FileSystemIDandChk.Plugins base.PluginUUID = new Guid("dc8572b3-b6ad-46e4-8de9-cbe123ff6672"); } - public override bool Identify(FileStream stream, long offset) + public override bool Identify(ImagePlugins.ImagePlugin imagePlugin, ulong partitionOffset) { UInt32 magic; - - BinaryReader br = new BinaryReader(stream); - - br.BaseStream.Seek(32 + offset, SeekOrigin.Begin); // Seek to magic - - magic = br.ReadUInt32(); - - if(magic == BEFS_MAGIC1) // Little-endian BFS - return true; - else if(magic == BEFS_CIGAM1) // Big-endian BFS + 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; else { - br.BaseStream.Seek(32 + 512 + offset, SeekOrigin.Begin); // Seek to magic, skip boot + sb_sector = imagePlugin.ReadSector (1 + partitionOffset); + + magic = BitConverter.ToUInt32 (sb_sector, 0x20); + magic_be = BigEndianBitConverter.ToUInt32 (sb_sector, 0x20); - magic = br.ReadUInt32(); - - if(magic == BEFS_MAGIC1) // Little-endian BFS - return true; - else if(magic == BEFS_CIGAM1) // Big-endian BFS + if(magic == BEFS_MAGIC1 || magic_be == BEFS_MAGIC1) return true; else return false; } } - public override void GetInformation (FileStream stream, long offset, out string information) + public override void GetInformation (ImagePlugins.ImagePlugin imagePlugin, ulong partitionOffset, out string information) { information = ""; byte[] name_bytes = new byte[32]; - bool littleendian = true; - + StringBuilder sb = new StringBuilder(); BeSuperBlock besb = new BeSuperBlock(); - - BinaryReader br = new BinaryReader(stream); - - br.BaseStream.Seek(32 + offset, SeekOrigin.Begin); // Seek to magic - besb.magic1 = br.ReadUInt32(); + + 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 { - br.BaseStream.Seek(offset, SeekOrigin.Begin); if(besb.magic1 == BEFS_CIGAM1) - littleendian = false; + BigEndianBitConverter.IsLittleEndian = false; } else { - br.BaseStream.Seek(32 + 512 + offset, SeekOrigin.Begin); // Seek to magic - besb.magic1 = br.ReadUInt32(); + 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 { - br.BaseStream.Seek(offset + 512, SeekOrigin.Begin); if(besb.magic1 == BEFS_CIGAM1) - littleendian = false; + BigEndianBitConverter.IsLittleEndian = false; } else return; } - EndianAwareBinaryReader eabr = new EndianAwareBinaryReader(stream, littleendian); - name_bytes = eabr.ReadBytes(32); - + Array.Copy (sb_sector, 0x000, name_bytes, 0, 0x20); besb.name = StringHandlers.CToString(name_bytes); - besb.magic1 = eabr.ReadUInt32(); - besb.fs_byte_order = eabr.ReadUInt32(); - besb.block_size = eabr.ReadUInt32(); - besb.block_shift = eabr.ReadUInt32(); - besb.num_blocks = eabr.ReadInt64(); - besb.used_blocks = eabr.ReadInt64(); - besb.inode_size = eabr.ReadInt32(); - besb.magic2 = eabr.ReadUInt32(); - besb.blocks_per_ag = eabr.ReadInt32(); - besb.ag_shift = eabr.ReadInt32(); - besb.num_ags = eabr.ReadInt32(); - besb.flags = eabr.ReadUInt32(); - besb.log_blocks_ag = eabr.ReadInt32(); - besb.log_blocks_start = eabr.ReadUInt16(); - besb.log_blocks_len = eabr.ReadUInt16(); - besb.log_start = eabr.ReadInt64(); - besb.log_end = eabr.ReadInt64(); - besb.magic3 = eabr.ReadUInt32(); - besb.root_dir_ag = eabr.ReadInt32(); - besb.root_dir_start = eabr.ReadUInt16(); - besb.root_dir_len = eabr.ReadUInt16(); - besb.indices_ag = eabr.ReadInt32(); - besb.indices_start = eabr.ReadUInt16(); - besb.indices_len = eabr.ReadUInt16(); + 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(!littleendian) // Big-endian filesystem + if(!BigEndianBitConverter.IsLittleEndian) // Big-endian filesystem sb.AppendLine("Big-endian BeFS"); else sb.AppendLine("Little-endian BeFS"); @@ -175,32 +166,31 @@ namespace FileSystemIDandChk.Plugins private struct BeSuperBlock { - public string name; // Volume name, 32 bytes - public UInt32 magic1; // "BFS1", 0x42465331 - public UInt32 fs_byte_order; // "BIGE", 0x42494745 - public UInt32 block_size; // Bytes per block - public UInt32 block_shift; // 1 << block_shift == block_size - public Int64 num_blocks; // Blocks in volume - public Int64 used_blocks; // Used blocks in volume - public Int32 inode_size; // Bytes per inode - public UInt32 magic2; // 0xDD121031 - public Int32 blocks_per_ag; // Blocks per allocation group - public Int32 ag_shift; // 1 << ag_shift == blocks_per_ag - public Int32 num_ags; // Allocation groups in volume - public UInt32 flags; // 0x434c454e if clean, 0x44495254 if dirty - public Int32 log_blocks_ag; // Allocation group of journal - public UInt16 log_blocks_start; // Start block of journal, inside ag - public UInt16 log_blocks_len; // Length in blocks of journal, inside ag - public Int64 log_start; // Start of journal - public Int64 log_end; // End of journal - public UInt32 magic3; // 0x15B6830E - public Int32 root_dir_ag; // Allocation group where root folder's i-node resides - public UInt16 root_dir_start; // Start in ag of root folder's i-node - public UInt16 root_dir_len; // As this is part of inode_addr, this is 1 - public Int32 indices_ag; // Allocation group where indices' i-node resides - public UInt16 indices_start; // Start in ag of indices' i-node - public UInt16 indices_len; // As this is part of inode_addr, this is 1 + 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 } } -} - +} \ No newline at end of file diff --git a/FileSystemIDandChk/Plugins/FAT.cs b/FileSystemIDandChk/Plugins/FAT.cs index f8bac0d23..4c339d947 100644 --- a/FileSystemIDandChk/Plugins/FAT.cs +++ b/FileSystemIDandChk/Plugins/FAT.cs @@ -3,8 +3,8 @@ using System.IO; using System.Text; using FileSystemIDandChk; -// Information from Inside Macintosh - +// TODO: Implement detecting DOS bootable disks +// TODO: Implement detecting Atari TOS bootable disks and printing corresponding fields namespace FileSystemIDandChk.Plugins { class FAT : Plugin @@ -15,7 +15,7 @@ namespace FileSystemIDandChk.Plugins base.PluginUUID = new Guid("33513B2C-0D26-0D2D-32C3-79D8611158E0"); } - public override bool Identify(FileStream stream, long offset) + 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 @@ -23,27 +23,23 @@ namespace FileSystemIDandChk.Plugins UInt32 first_fat_entry; // No matter FAT size we read 4 bytes for checking UInt16 bps, rsectors; - BinaryReader br = new BinaryReader(stream); + byte[] bpb_sector = imagePlugin.ReadSector (0 + partitionOffset); + byte[] fat_sector; - br.BaseStream.Seek(0x10 + offset, SeekOrigin.Begin); // FATs, 1 or 2, maybe 0, never bigger - fats_no = br.ReadByte(); - br.BaseStream.Seek(0x15 + offset, SeekOrigin.Begin); // Media Descriptor if present is in 0x15 - media_descriptor = br.ReadByte(); - br.BaseStream.Seek(0x52 + offset, SeekOrigin.Begin); // FAT32 signature, if present, is in 0x52 - fat32_signature = br.ReadBytes(8); - br.BaseStream.Seek(0x0B + offset, SeekOrigin.Begin); // Bytes per sector - bps = br.ReadUInt16(); + 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; - br.BaseStream.Seek(0x0E + offset, SeekOrigin.Begin); // Sectors between BPB and FAT, including the BPB sector => [BPB,FAT) - rsectors = br.ReadUInt16(); + rsectors = BitConverter.ToUInt16 (bpb_sector, 0x00E); // Sectors between BPB and FAT, including the BPB sector => [BPB,FAT) if(rsectors==0) rsectors=1; - if((ulong)br.BaseStream.Length > (ulong)(bps*rsectors + offset)) - br.BaseStream.Seek(bps*rsectors + offset, SeekOrigin.Begin); // First FAT entry + if(imagePlugin.GetSectors() > ((ulong)rsectors + partitionOffset)) + fat_sector = imagePlugin.ReadSector(rsectors + partitionOffset); // First FAT entry else return false; - first_fat_entry = br.ReadUInt32(); // Easier to manage + first_fat_entry = BitConverter.ToUInt32 (fat_sector, 0); // Easier to manage if(MainClass.isDebug) { @@ -75,12 +71,11 @@ namespace FileSystemIDandChk.Plugins return false; } - public override void GetInformation (FileStream stream, long offset, out string information) + public override void GetInformation (ImagePlugins.ImagePlugin imagePlugin, ulong partitionOffset, out string information) { information = ""; StringBuilder sb = new StringBuilder(); - BinaryReader br = new BinaryReader(stream); byte[] dosString; // Space-padded bool isFAT32 = false; @@ -89,23 +84,22 @@ namespace FileSystemIDandChk.Plugins string fat32_signature; UInt16 bps, rsectors; - br.BaseStream.Seek(0x10 + offset, SeekOrigin.Begin); // Media Descriptor if present is in 0x15 - fats_no = br.ReadByte(); - br.BaseStream.Seek(0x15 + offset, SeekOrigin.Begin); // Media Descriptor if present is in 0x15 - media_descriptor =(byte) stream.ReadByte(); - br.BaseStream.Seek(0x52 + offset, SeekOrigin.Begin); // FAT32 signature, if present, is in 0x52 - dosString = br.ReadBytes(8); - fat32_signature = Encoding.ASCII.GetString(dosString); - br.BaseStream.Seek(0x0B + offset, SeekOrigin.Begin); // Bytes per sector - bps = br.ReadUInt16(); + byte[] bpb_sector = imagePlugin.ReadSector (0 + partitionOffset); + byte[] fat_sector; + + 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; - br.BaseStream.Seek(0x0E + offset, SeekOrigin.Begin); // Sectors between BPB and FAT, including the BPB sector => [BPB,FAT) - rsectors = br.ReadUInt16(); + rsectors = BitConverter.ToUInt16 (bpb_sector, 0x00E); // Sectors between BPB and FAT, including the BPB sector => [BPB,FAT) if(rsectors==0) rsectors=1; - br.BaseStream.Seek(bps*rsectors + offset, SeekOrigin.Begin); // First FAT entry - first_fat_entry = br.ReadUInt32(); // Easier to manage + fat_sector = imagePlugin.ReadSector(rsectors + partitionOffset); // First FAT entry + 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; @@ -133,49 +127,52 @@ namespace FileSystemIDandChk.Plugins ExtendedParameterBlock EPB = new ExtendedParameterBlock(); FAT32ParameterBlock FAT32PB = new FAT32ParameterBlock(); - - br.BaseStream.Seek(3 + offset, SeekOrigin.Begin); - dosString = br.ReadBytes(8); + dosString = new byte[8]; + Array.Copy (bpb_sector, 0x03, dosString, 0, 8); BPB.OEMName = Encoding.ASCII.GetString(dosString); - BPB.bps = br.ReadUInt16(); - BPB.spc = br.ReadByte(); - BPB.rsectors = br.ReadUInt16(); - BPB.fats_no = br.ReadByte(); - BPB.root_ent = br.ReadUInt16(); - BPB.sectors = br.ReadUInt16(); - BPB.media = br.ReadByte(); - BPB.spfat = br.ReadUInt16(); - BPB.sptrk = br.ReadUInt16(); - BPB.heads = br.ReadUInt16(); - BPB.hsectors = br.ReadUInt32(); - BPB.big_sectors = br.ReadUInt32(); + 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 = br.ReadUInt32(); - FAT32PB.fat_flags = br.ReadUInt16(); - FAT32PB.version = br.ReadUInt16(); - FAT32PB.root_cluster = br.ReadUInt32(); - FAT32PB.fsinfo_sector = br.ReadUInt16(); - FAT32PB.backup_sector = br.ReadUInt16(); - FAT32PB.drive_no = br.ReadByte(); - FAT32PB.nt_flags = br.ReadByte(); - FAT32PB.signature = br.ReadByte(); - FAT32PB.serial_no = br.ReadUInt32(); - dosString = br.ReadBytes(11); + 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 = br.ReadBytes(8); + dosString = new byte[8]; + Array.Copy (bpb_sector, 0x52, dosString, 0, 8); FAT32PB.fs_type = Encoding.ASCII.GetString(dosString); } else { - EPB.drive_no = br.ReadByte(); - EPB.nt_flags = br.ReadByte(); - EPB.signature = br.ReadByte(); - EPB.serial_no = br.ReadUInt32(); - dosString = br.ReadBytes(11); + 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 = br.ReadBytes(8); + dosString = new byte[8]; + Array.Copy (bpb_sector, 0x36, dosString, 0, 8); EPB.fs_type = Encoding.ASCII.GetString(dosString); } @@ -299,5 +296,4 @@ namespace FileSystemIDandChk.Plugins public string fs_type; // 0x52, Filesystem type, 8 bytes, space-padded, must be "FAT32 " } } -} - +} \ No newline at end of file diff --git a/FileSystemIDandChk/Plugins/FFS.cs b/FileSystemIDandChk/Plugins/FFS.cs index 3012c8b52..de7f41492 100644 --- a/FileSystemIDandChk/Plugins/FFS.cs +++ b/FileSystemIDandChk/Plugins/FFS.cs @@ -4,7 +4,6 @@ using System.Text; using FileSystemIDandChk; // Using information from Linux kernel headers - namespace FileSystemIDandChk.Plugins { public class FFSPlugin : Plugin @@ -15,42 +14,48 @@ namespace FileSystemIDandChk.Plugins base.PluginUUID = new Guid("CC90D342-05DB-48A8-988C-C1FE000034A3"); } - public override bool Identify(FileStream fileStream, long offset) + public override bool Identify(ImagePlugins.ImagePlugin imagePlugin, ulong partitionOffset) { UInt32 magic; - BinaryReader br = new BinaryReader(fileStream); + uint sb_size_in_sectors; + byte[] ufs_sb_sectors; - if(fileStream.Length > (offset + sb_start_floppy + 0x055C)) + if(imagePlugin.GetSectorSize() == 2336 || imagePlugin.GetSectorSize() == 2352 ||imagePlugin.GetSectorSize() == 2448) + sb_size_in_sectors = block_size / 2048; + else + sb_size_in_sectors = block_size / imagePlugin.GetSectorSize(); + + if(imagePlugin.GetSectors() > (partitionOffset + sb_start_floppy*sb_size_in_sectors + sb_size_in_sectors)) { - br.BaseStream.Seek(offset + sb_start_floppy + 0x055C, SeekOrigin.Begin); - magic = br.ReadUInt32(); + ufs_sb_sectors = imagePlugin.ReadSectors(partitionOffset + sb_start_floppy * sb_size_in_sectors, sb_size_in_sectors); + magic = BigEndianBitConverter.ToUInt32(ufs_sb_sectors, 0x055C); if (magic == UFS_MAGIC || magic == UFS_MAGIC_BW || magic == UFS2_MAGIC || magic == UFS_CIGAM || magic == UFS_BAD_MAGIC) return true; } - if(fileStream.Length > (offset + sb_start_ufs1 + 0x055C)) + if(imagePlugin.GetSectors() > (partitionOffset + sb_start_ufs1*sb_size_in_sectors + sb_size_in_sectors)) { - br.BaseStream.Seek(offset + sb_start_ufs1 + 0x055C, SeekOrigin.Begin); - magic = br.ReadUInt32(); + ufs_sb_sectors = imagePlugin.ReadSectors(partitionOffset + sb_start_ufs1 * sb_size_in_sectors, sb_size_in_sectors); + magic = BigEndianBitConverter.ToUInt32(ufs_sb_sectors, 0x055C); if (magic == UFS_MAGIC || magic == UFS_MAGIC_BW || magic == UFS2_MAGIC || magic == UFS_CIGAM || magic == UFS_BAD_MAGIC) return true; } - if(fileStream.Length > (offset + sb_start_ufs2 + 0x055C)) + if(imagePlugin.GetSectors() > (partitionOffset + sb_start_ufs2*sb_size_in_sectors + sb_size_in_sectors)) { - br.BaseStream.Seek(offset + sb_start_ufs2 + 0x055C, SeekOrigin.Begin); - magic = br.ReadUInt32(); + ufs_sb_sectors = imagePlugin.ReadSectors(partitionOffset + sb_start_ufs2 * sb_size_in_sectors, sb_size_in_sectors); + magic = BigEndianBitConverter.ToUInt32(ufs_sb_sectors, 0x055C); if (magic == UFS_MAGIC || magic == UFS_MAGIC_BW || magic == UFS2_MAGIC || magic == UFS_CIGAM || magic == UFS_BAD_MAGIC) return true; } - if(fileStream.Length > (offset + sb_start_piggy + 0x055C)) + if(imagePlugin.GetSectors() > (partitionOffset + sb_start_piggy*sb_size_in_sectors + sb_size_in_sectors)) { - br.BaseStream.Seek(offset + sb_start_piggy + 0x055C, SeekOrigin.Begin); - magic = br.ReadUInt32(); + ufs_sb_sectors = imagePlugin.ReadSectors(partitionOffset + sb_start_piggy * sb_size_in_sectors, sb_size_in_sectors); + magic = BigEndianBitConverter.ToUInt32(ufs_sb_sectors, 0x055C); if (magic == UFS_MAGIC || magic == UFS_MAGIC_BW || magic == UFS2_MAGIC || magic == UFS_CIGAM || magic == UFS_BAD_MAGIC) return true; @@ -59,14 +64,15 @@ namespace FileSystemIDandChk.Plugins return false; } - public override void GetInformation (FileStream fileStream, long offset, out string information) + public override void GetInformation (ImagePlugins.ImagePlugin imagePlugin, ulong partitionOffset, out string information) { information = ""; StringBuilder sbInformation = new StringBuilder(); UInt32 magic = 0; - BinaryReader br = new BinaryReader(fileStream); - long sb_offset = offset; + uint sb_size_in_sectors; + byte[] ufs_sb_sectors; + ulong sb_offset = partitionOffset; bool fs_type_42bsd = false; bool fs_type_43bsd = false; bool fs_type_44bsd = false; @@ -74,47 +80,52 @@ namespace FileSystemIDandChk.Plugins bool fs_type_ufs2 = false; bool fs_type_sun = false; bool fs_type_sun86 = false; + + if(imagePlugin.GetSectorSize() == 2336 || imagePlugin.GetSectorSize() == 2352 ||imagePlugin.GetSectorSize() == 2448) + sb_size_in_sectors = block_size / 2048; + else + sb_size_in_sectors = block_size / imagePlugin.GetSectorSize(); - if(fileStream.Length > (offset + sb_start_floppy + 0x055C) && magic == 0) + if(imagePlugin.GetSectors() > (partitionOffset + sb_start_floppy*sb_size_in_sectors + sb_size_in_sectors) && magic == 0) { - br.BaseStream.Seek(offset + sb_start_floppy + 0x055C, SeekOrigin.Begin); - magic = br.ReadUInt32(); + ufs_sb_sectors = imagePlugin.ReadSectors(partitionOffset + sb_start_floppy * sb_size_in_sectors, sb_size_in_sectors); + magic = BigEndianBitConverter.ToUInt32(ufs_sb_sectors, 0x055C); if (magic == UFS_MAGIC || magic == UFS_MAGIC_BW || magic == UFS2_MAGIC || magic == UFS_CIGAM || magic == UFS_BAD_MAGIC) - sb_offset = offset + sb_start_floppy; + sb_offset = partitionOffset + sb_start_floppy * sb_size_in_sectors; else magic = 0; } - if(fileStream.Length > (offset + sb_start_ufs1 + 0x055C) && magic == 0) + if(imagePlugin.GetSectors() > (partitionOffset + sb_start_ufs1*sb_size_in_sectors + sb_size_in_sectors) && magic == 0) { - br.BaseStream.Seek(offset + sb_start_ufs1 + 0x055C, SeekOrigin.Begin); - magic = br.ReadUInt32(); + ufs_sb_sectors = imagePlugin.ReadSectors(partitionOffset + sb_start_ufs1 * sb_size_in_sectors, sb_size_in_sectors); + magic = BigEndianBitConverter.ToUInt32(ufs_sb_sectors, 0x055C); if (magic == UFS_MAGIC || magic == UFS_MAGIC_BW || magic == UFS2_MAGIC || magic == UFS_CIGAM || magic == UFS_BAD_MAGIC) - sb_offset = offset + sb_start_ufs1; + sb_offset = partitionOffset + sb_start_ufs1 * sb_size_in_sectors; else magic = 0; } - if(fileStream.Length > (offset + sb_start_ufs2 + 0x055C) && magic == 0) + if(imagePlugin.GetSectors() > (partitionOffset + sb_start_ufs2*sb_size_in_sectors + sb_size_in_sectors) && magic == 0) { - br.BaseStream.Seek(offset + sb_start_ufs2 + 0x055C, SeekOrigin.Begin); - magic = br.ReadUInt32(); + ufs_sb_sectors = imagePlugin.ReadSectors(partitionOffset + sb_start_ufs2 * sb_size_in_sectors, sb_size_in_sectors); + magic = BigEndianBitConverter.ToUInt32(ufs_sb_sectors, 0x055C); if (magic == UFS_MAGIC || magic == UFS_MAGIC_BW || magic == UFS2_MAGIC || magic == UFS_CIGAM || magic == UFS_BAD_MAGIC) - sb_offset = offset + sb_start_ufs2; + sb_offset = partitionOffset + sb_start_ufs2 * sb_size_in_sectors; else magic = 0; } - if(fileStream.Length > (offset + sb_start_piggy + 0x055C) && magic == 0) + if(imagePlugin.GetSectors() > (partitionOffset + sb_start_piggy*sb_size_in_sectors + sb_size_in_sectors) && magic == 0) { - br.BaseStream.Seek(offset + sb_start_piggy + 0x055C, SeekOrigin.Begin); - magic = br.ReadUInt32(); + ufs_sb_sectors = imagePlugin.ReadSectors(partitionOffset + sb_start_piggy * sb_size_in_sectors, sb_size_in_sectors); + magic = BigEndianBitConverter.ToUInt32(ufs_sb_sectors, 0x055C); if (magic == UFS_MAGIC || magic == UFS_MAGIC_BW || magic == UFS2_MAGIC || magic == UFS_CIGAM || magic == UFS_BAD_MAGIC) - sb_offset = offset + sb_start_piggy; + sb_offset = partitionOffset + sb_start_piggy * sb_size_in_sectors; else magic = 0; } @@ -147,196 +158,191 @@ namespace FileSystemIDandChk.Plugins break; } - EndianAwareBinaryReader eabr; - if(magic == UFS_CIGAM) - eabr = new EndianAwareBinaryReader(fileStream, false); // Big-endian UFS + if (magic == UFS_CIGAM) + BigEndianBitConverter.IsLittleEndian = false; // Big-endian UFS else - eabr = new EndianAwareBinaryReader(fileStream, true); // Little-endian UFS + BigEndianBitConverter.IsLittleEndian = true; // Little-endian UFS // Are there any other cases to detect big-endian UFS? // Fun with seeking follows on superblock reading! UFSSuperBlock ufs_sb = new UFSSuperBlock(); byte[] strings_b; - eabr.BaseStream.Seek(sb_offset, SeekOrigin.Begin); + ufs_sb_sectors = imagePlugin.ReadSectors(sb_offset, sb_size_in_sectors); - ufs_sb.fs_link_42bsd = eabr.ReadUInt32(); + ufs_sb.fs_link_42bsd = BigEndianBitConverter.ToUInt32(ufs_sb_sectors, 0x0000); // 0x0000 ufs_sb.fs_state_sun = ufs_sb.fs_link_42bsd; - ufs_sb.fs_rlink = eabr.ReadUInt32(); // 0x0004 UNUSED - ufs_sb.fs_sblkno = eabr.ReadUInt32(); // 0x0008 addr of super-block in filesys - ufs_sb.fs_cblkno = eabr.ReadUInt32(); // 0x000C offset of cyl-block in filesys - ufs_sb.fs_iblkno = eabr.ReadUInt32(); // 0x0010 offset of inode-blocks in filesys - ufs_sb.fs_dblkno = eabr.ReadUInt32(); // 0x0014 offset of first data after cg - ufs_sb.fs_cgoffset = eabr.ReadUInt32(); // 0x0018 cylinder group offset in cylinder - ufs_sb.fs_cgmask = eabr.ReadUInt32(); // 0x001C used to calc mod fs_ntrak - ufs_sb.fs_time_t = eabr.ReadUInt32(); // 0x0020 last time written -- time_t - ufs_sb.fs_size = eabr.ReadUInt32(); // 0x0024 number of blocks in fs - ufs_sb.fs_dsize = eabr.ReadUInt32(); // 0x0028 number of data blocks in fs - ufs_sb.fs_ncg = eabr.ReadUInt32(); // 0x002C number of cylinder groups - ufs_sb.fs_bsize = eabr.ReadUInt32(); // 0x0030 size of basic blocks in fs - ufs_sb.fs_fsize = eabr.ReadUInt32(); // 0x0034 size of frag blocks in fs - ufs_sb.fs_frag = eabr.ReadUInt32(); // 0x0038 number of frags in a block in fs + ufs_sb.fs_rlink = BigEndianBitConverter.ToUInt32(ufs_sb_sectors, 0x0004); // 0x0004 UNUSED + ufs_sb.fs_sblkno = BigEndianBitConverter.ToUInt32(ufs_sb_sectors, 0x0008); // 0x0008 addr of super-block in filesys + ufs_sb.fs_cblkno = BigEndianBitConverter.ToUInt32(ufs_sb_sectors, 0x000C); // 0x000C offset of cyl-block in filesys + ufs_sb.fs_iblkno = BigEndianBitConverter.ToUInt32(ufs_sb_sectors, 0x0010); // 0x0010 offset of inode-blocks in filesys + ufs_sb.fs_dblkno = BigEndianBitConverter.ToUInt32(ufs_sb_sectors, 0x0014); // 0x0014 offset of first data after cg + ufs_sb.fs_cgoffset = BigEndianBitConverter.ToUInt32(ufs_sb_sectors, 0x0018); // 0x0018 cylinder group offset in cylinder + ufs_sb.fs_cgmask = BigEndianBitConverter.ToUInt32(ufs_sb_sectors, 0x001C); // 0x001C used to calc mod fs_ntrak + ufs_sb.fs_time_t = BigEndianBitConverter.ToUInt32(ufs_sb_sectors, 0x0020); // 0x0020 last time written -- time_t + ufs_sb.fs_size = BigEndianBitConverter.ToUInt32(ufs_sb_sectors, 0x0024); // 0x0024 number of blocks in fs + ufs_sb.fs_dsize = BigEndianBitConverter.ToUInt32(ufs_sb_sectors, 0x0028); // 0x0028 number of data blocks in fs + ufs_sb.fs_ncg = BigEndianBitConverter.ToUInt32(ufs_sb_sectors, 0x002C); // 0x002C number of cylinder groups + ufs_sb.fs_bsize = BigEndianBitConverter.ToUInt32(ufs_sb_sectors, 0x0030); // 0x0030 size of basic blocks in fs + ufs_sb.fs_fsize = BigEndianBitConverter.ToUInt32(ufs_sb_sectors, 0x0034); // 0x0034 size of frag blocks in fs + ufs_sb.fs_frag = BigEndianBitConverter.ToUInt32(ufs_sb_sectors, 0x0038); // 0x0038 number of frags in a block in fs // these are configuration parameters - ufs_sb.fs_minfree = eabr.ReadUInt32(); // 0x003C minimum percentage of free blocks - ufs_sb.fs_rotdelay = eabr.ReadUInt32(); // 0x0040 num of ms for optimal next block - ufs_sb.fs_rps = eabr.ReadUInt32(); // 0x0044 disk revolutions per second + ufs_sb.fs_minfree = BigEndianBitConverter.ToUInt32(ufs_sb_sectors, 0x003C); // 0x003C minimum percentage of free blocks + ufs_sb.fs_rotdelay = BigEndianBitConverter.ToUInt32(ufs_sb_sectors, 0x0040); // 0x0040 num of ms for optimal next block + ufs_sb.fs_rps = BigEndianBitConverter.ToUInt32(ufs_sb_sectors, 0x0044); // 0x0044 disk revolutions per second // these fields can be computed from the others - ufs_sb.fs_bmask = eabr.ReadUInt32(); // 0x0048 ``blkoff'' calc of blk offsets - ufs_sb.fs_fmask = eabr.ReadUInt32(); // 0x004C ``fragoff'' calc of frag offsets - ufs_sb.fs_bshift = eabr.ReadUInt32(); // 0x0050 ``lblkno'' calc of logical blkno - ufs_sb.fs_fshift = eabr.ReadUInt32(); // 0x0054 ``numfrags'' calc number of frags + ufs_sb.fs_bmask = BigEndianBitConverter.ToUInt32(ufs_sb_sectors, 0x0048); // 0x0048 ``blkoff'' calc of blk offsets + ufs_sb.fs_fmask = BigEndianBitConverter.ToUInt32(ufs_sb_sectors, 0x004C); // 0x004C ``fragoff'' calc of frag offsets + ufs_sb.fs_bshift = BigEndianBitConverter.ToUInt32(ufs_sb_sectors, 0x0050); // 0x0050 ``lblkno'' calc of logical blkno + ufs_sb.fs_fshift = BigEndianBitConverter.ToUInt32(ufs_sb_sectors, 0x0054); // 0x0054 ``numfrags'' calc number of frags // these are configuration parameters - ufs_sb.fs_maxcontig = eabr.ReadUInt32(); // 0x0058 max number of contiguous blks - ufs_sb.fs_maxbpg = eabr.ReadUInt32(); // 0x005C max number of blks per cyl group + ufs_sb.fs_maxcontig = BigEndianBitConverter.ToUInt32(ufs_sb_sectors, 0x0058); // 0x0058 max number of contiguous blks + ufs_sb.fs_maxbpg = BigEndianBitConverter.ToUInt32(ufs_sb_sectors, 0x005C); // 0x005C max number of blks per cyl group // these fields can be computed from the others - ufs_sb.fs_fragshift = eabr.ReadUInt32(); // 0x0060 block to frag shift - ufs_sb.fs_fsbtodb = eabr.ReadUInt32(); // 0x0064 fsbtodb and dbtofsb shift constant - ufs_sb.fs_sbsize = eabr.ReadUInt32(); // 0x0068 actual size of super block - ufs_sb.fs_csmask = eabr.ReadUInt32(); // 0x006C csum block offset - ufs_sb.fs_csshift = eabr.ReadUInt32(); // 0x0070 csum block number - ufs_sb.fs_nindir = eabr.ReadUInt32(); // 0x0074 value of NINDIR - ufs_sb.fs_inopb = eabr.ReadUInt32(); // 0x0078 value of INOPB - ufs_sb.fs_nspf = eabr.ReadUInt32(); // 0x007C value of NSPF + ufs_sb.fs_fragshift = BigEndianBitConverter.ToUInt32(ufs_sb_sectors, 0x0060); // 0x0060 block to frag shift + ufs_sb.fs_fsbtodb = BigEndianBitConverter.ToUInt32(ufs_sb_sectors, 0x0064); // 0x0064 fsbtodb and dbtofsb shift constant + ufs_sb.fs_sbsize = BigEndianBitConverter.ToUInt32(ufs_sb_sectors, 0x0068); // 0x0068 actual size of super block + ufs_sb.fs_csmask = BigEndianBitConverter.ToUInt32(ufs_sb_sectors, 0x006C); // 0x006C csum block offset + ufs_sb.fs_csshift = BigEndianBitConverter.ToUInt32(ufs_sb_sectors, 0x0070); // 0x0070 csum block number + ufs_sb.fs_nindir = BigEndianBitConverter.ToUInt32(ufs_sb_sectors, 0x0074); // 0x0074 value of NINDIR + ufs_sb.fs_inopb = BigEndianBitConverter.ToUInt32(ufs_sb_sectors, 0x0078); // 0x0078 value of INOPB + ufs_sb.fs_nspf = BigEndianBitConverter.ToUInt32(ufs_sb_sectors, 0x007C); // 0x007C value of NSPF // yet another configuration parameter - ufs_sb.fs_optim = eabr.ReadUInt32(); // 0x0080 optimization preference, see below + ufs_sb.fs_optim = BigEndianBitConverter.ToUInt32(ufs_sb_sectors, 0x0080); // 0x0080 optimization preference, see below // these fields are derived from the hardware #region Sun - ufs_sb.fs_npsect_sun = eabr.ReadUInt32(); // 0x0084 # sectors/track including spares + ufs_sb.fs_npsect_sun = BigEndianBitConverter.ToUInt32(ufs_sb_sectors, 0x0084); // 0x0084 # sectors/track including spares #endregion Sun #region Sunx86 - eabr.BaseStream.Seek(sb_offset + 0x0084, SeekOrigin.Begin); - ufs_sb.fs_state_t_sun86 = eabr.ReadUInt32(); // 0x0084 file system state time stamp + ufs_sb.fs_state_t_sun86 = BigEndianBitConverter.ToUInt32(ufs_sb_sectors, 0x0084); // 0x0084 file system state time stamp #endregion Sunx86 #region COMMON - ufs_sb.fs_interleave = eabr.ReadUInt32(); // 0x0088 hardware sector interleave - ufs_sb.fs_trackskew = eabr.ReadUInt32(); // 0x008C sector 0 skew, per track + ufs_sb.fs_interleave = BigEndianBitConverter.ToUInt32(ufs_sb_sectors, 0x0088); // 0x0088 hardware sector interleave + ufs_sb.fs_trackskew = BigEndianBitConverter.ToUInt32(ufs_sb_sectors, 0x008C); // 0x008C sector 0 skew, per track #endregion COMMON // a unique id for this filesystem (currently unused and unmaintained) // In 4.3 Tahoe this space is used by fs_headswitch and fs_trkseek // Neither of those fields is used in the Tahoe code right now but // there could be problems if they are. #region COMMON - ufs_sb.fs_id_1 = eabr.ReadUInt32(); // 0x0090 - ufs_sb.fs_id_2 = eabr.ReadUInt32(); // 0x0094 + ufs_sb.fs_id_1 = BigEndianBitConverter.ToUInt32(ufs_sb_sectors, 0x0090); // 0x0090 + ufs_sb.fs_id_2 = BigEndianBitConverter.ToUInt32(ufs_sb_sectors, 0x0094); // 0x0094 #endregion COMMON #region 43BSD - eabr.BaseStream.Seek(sb_offset + 0x0090, SeekOrigin.Begin); - ufs_sb.fs_headswitch_43bsd = eabr.ReadUInt32(); // 0x0090 - ufs_sb.fs_trkseek_43bsd = eabr.ReadUInt32(); // 0x0094 + ufs_sb.fs_headswitch_43bsd = BigEndianBitConverter.ToUInt32(ufs_sb_sectors, 0x0090); // 0x0090 + ufs_sb.fs_trkseek_43bsd = BigEndianBitConverter.ToUInt32(ufs_sb_sectors, 0x0094); // 0x0094 #endregion 43BSD #region COMMON // sizes determined by number of cylinder groups and their sizes - ufs_sb.fs_csaddr = eabr.ReadUInt32(); // 0x0098 blk addr of cyl grp summary area - ufs_sb.fs_cssize = eabr.ReadUInt32(); // 0x009C size of cyl grp summary area - ufs_sb.fs_cgsize = eabr.ReadUInt32(); // 0x00A0 cylinder group size + ufs_sb.fs_csaddr = BigEndianBitConverter.ToUInt32(ufs_sb_sectors, 0x0098); // 0x0098 blk addr of cyl grp summary area + ufs_sb.fs_cssize = BigEndianBitConverter.ToUInt32(ufs_sb_sectors, 0x009C); // 0x009C size of cyl grp summary area + ufs_sb.fs_cgsize = BigEndianBitConverter.ToUInt32(ufs_sb_sectors, 0x00A0); // 0x00A0 cylinder group size // these fields are derived from the hardware - ufs_sb.fs_ntrak = eabr.ReadUInt32(); // 0x00A4 tracks per cylinder - ufs_sb.fs_nsect = eabr.ReadUInt32(); // 0x00A8 sectors per track - ufs_sb.fs_spc = eabr.ReadUInt32(); // 0x00AC sectors per cylinder + ufs_sb.fs_ntrak = BigEndianBitConverter.ToUInt32(ufs_sb_sectors, 0x00A4); // 0x00A4 tracks per cylinder + ufs_sb.fs_nsect = BigEndianBitConverter.ToUInt32(ufs_sb_sectors, 0x00A8); // 0x00A8 sectors per track + ufs_sb.fs_spc = BigEndianBitConverter.ToUInt32(ufs_sb_sectors, 0x00AC); // 0x00AC sectors per cylinder // this comes from the disk driver partitioning - ufs_sb.fs_ncyl = eabr.ReadUInt32(); // 0x00B0 cylinders in file system + ufs_sb.fs_ncyl = BigEndianBitConverter.ToUInt32(ufs_sb_sectors, 0x00B0); // 0x00B0 cylinders in file system // these fields can be computed from the others - ufs_sb.fs_cpg = eabr.ReadUInt32(); // 0x00B4 cylinders per group - ufs_sb.fs_ipg = eabr.ReadUInt32(); // 0x00B8 inodes per cylinder group - ufs_sb.fs_fpg = eabr.ReadUInt32(); // 0x00BC blocks per group * fs_frag + ufs_sb.fs_cpg = BigEndianBitConverter.ToUInt32(ufs_sb_sectors, 0x00B4); // 0x00B4 cylinders per group + ufs_sb.fs_ipg = BigEndianBitConverter.ToUInt32(ufs_sb_sectors, 0x00B8); // 0x00B8 inodes per cylinder group + ufs_sb.fs_fpg = BigEndianBitConverter.ToUInt32(ufs_sb_sectors, 0x00BC); // 0x00BC blocks per group * fs_frag // this data must be re-computed after crashes - // struct ufs_csum fs_cstotal = eabr.ReadUInt32(); // cylinder summary information - ufs_sb.fs_cstotal_ndir = eabr.ReadUInt32(); // 0x00C0 number of directories - ufs_sb.fs_cstotal_nbfree = eabr.ReadUInt32(); // 0x00C4 number of free blocks - ufs_sb.fs_cstotal_nifree = eabr.ReadUInt32(); // 0x00C8 number of free inodes - ufs_sb.fs_cstotal_nffree = eabr.ReadUInt32(); // 0x00CC number of free frags + // struct ufs_csum fs_cstotal = BigEndianBitConverter.ToUInt32(ufs_sb_sectors, 0x0000); // cylinder summary information + ufs_sb.fs_cstotal_ndir = BigEndianBitConverter.ToUInt32(ufs_sb_sectors, 0x00C0); // 0x00C0 number of directories + ufs_sb.fs_cstotal_nbfree = BigEndianBitConverter.ToUInt32(ufs_sb_sectors, 0x00C4); // 0x00C4 number of free blocks + ufs_sb.fs_cstotal_nifree = BigEndianBitConverter.ToUInt32(ufs_sb_sectors, 0x00C8); // 0x00C8 number of free inodes + ufs_sb.fs_cstotal_nffree = BigEndianBitConverter.ToUInt32(ufs_sb_sectors, 0x00CC); // 0x00CC number of free frags // these fields are cleared at mount time - ufs_sb.fs_fmod = eabr.ReadByte(); // 0x00D0 super block modified flag - ufs_sb.fs_clean = eabr.ReadByte(); // 0x00D1 file system is clean flag - ufs_sb.fs_ronly = eabr.ReadByte(); // 0x00D2 mounted read-only flag - ufs_sb.fs_flags = eabr.ReadByte(); // 0x00D3 + ufs_sb.fs_fmod = ufs_sb_sectors[0x00D0]; // 0x00D0 super block modified flag + ufs_sb.fs_clean = ufs_sb_sectors[0x00D1]; // 0x00D1 file system is clean flag + ufs_sb.fs_ronly = ufs_sb_sectors[0x00D2]; // 0x00D2 mounted read-only flag + ufs_sb.fs_flags = ufs_sb_sectors[0x00D3]; // 0x00D3 #endregion COMMON #region UFS1 - strings_b = eabr.ReadBytes(512); + strings_b = new byte[512]; + Array.Copy(ufs_sb_sectors, 0x00D4, strings_b, 0, 512); ufs_sb.fs_fsmnt_ufs1 = StringHandlers.CToString(strings_b); // 0x00D4, 512 bytes, name mounted on - ufs_sb.fs_cgrotor_ufs1 = eabr.ReadUInt32(); // 0x02D4 last cg searched - ufs_sb.fs_cs_ufs1 = eabr.ReadBytes(124); // 0x02D8, 124 bytes, UInt32s, list of fs_cs info buffers - ufs_sb.fs_maxcluster_ufs1 = eabr.ReadUInt32(); // 0x0354 - ufs_sb.fs_cpc_ufs1 = eabr.ReadUInt32(); // 0x0358 cyl per cycle in postbl - ufs_sb.fs_opostbl_ufs1 = eabr.ReadBytes(256); // 0x035C, 256 bytes, [16][8] matrix of UInt16s, old rotation block list head + ufs_sb.fs_cgrotor_ufs1 = BigEndianBitConverter.ToUInt32(ufs_sb_sectors, 0x0000); // 0x02D4 last cg searched + Array.Copy(ufs_sb_sectors, 0x02D8, ufs_sb.fs_cs_ufs1, 0, 124); // 0x02D8, 124 bytes, UInt32s, list of fs_cs info buffers + ufs_sb.fs_maxcluster_ufs1 = BigEndianBitConverter.ToUInt32(ufs_sb_sectors, 0x0354); // 0x0354 + ufs_sb.fs_cpc_ufs1 = BigEndianBitConverter.ToUInt32(ufs_sb_sectors, 0x0358); // 0x0358 cyl per cycle in postbl + Array.Copy(ufs_sb_sectors, 0x035C, ufs_sb.fs_opostbl_ufs1, 0, 256); // 0x035C, 256 bytes, [16][8] matrix of UInt16s, old rotation block list head #endregion UFS1 #region UFS2 - eabr.BaseStream.Seek(sb_offset + 0x00D4, SeekOrigin.Begin); - strings_b = eabr.ReadBytes(468); + strings_b = new byte[468]; + Array.Copy(ufs_sb_sectors, 0x00D4, strings_b, 0, 468); ufs_sb.fs_fsmnt_ufs2 = StringHandlers.CToString(strings_b); // 0x00D4, 468 bytes, name mounted on - strings_b = eabr.ReadBytes(32); + strings_b = new byte[32]; + Array.Copy(ufs_sb_sectors, 0x02A8, strings_b, 0, 32); ufs_sb.fs_volname_ufs2 = StringHandlers.CToString(strings_b); // 0x02A8, 32 bytes, volume name - ufs_sb.fs_swuid_ufs2 = eabr.ReadUInt32(); // 0x02C8 system-wide uid - ufs_sb.fs_pad_ufs2 = eabr.ReadUInt32(); // 0x02D0 due to alignment of fs_swuid - ufs_sb.fs_cgrotor_ufs2 = eabr.ReadUInt32(); // 0x02D4 last cg searched - ufs_sb.fs_ocsp_ufs2 = eabr.ReadBytes(112); // 0x02D8, 112 bytes, UInt32s, list of fs_cs info buffers - ufs_sb.fs_contigdirs_ufs2 = eabr.ReadUInt32(); // 0x0348 # of contiguously allocated dirs - ufs_sb.fs_csp_ufs2 = eabr.ReadUInt32(); // 0x034C cg summary info buffer for fs_cs - ufs_sb.fs_maxcluster_ufs2 = eabr.ReadUInt32(); // 0x0350 - ufs_sb.fs_active_ufs2 = eabr.ReadUInt32(); // 0x0354 used by snapshots to track fs - ufs_sb.fs_old_cpc_ufs2 = eabr.ReadUInt32(); // 0x0358 cyl per cycle in postbl - ufs_sb.fs_maxbsize_ufs2 = eabr.ReadUInt32(); // 0x035C maximum blocking factor permitted - ufs_sb.fs_sparecon64_ufs2 = eabr.ReadBytes(136); // 0x0360, 136 bytes, UInt64s, old rotation block list head - ufs_sb.fs_sblockloc_ufs2 = eabr.ReadUInt64(); // 0x03E8 byte offset of standard superblock + ufs_sb.fs_swuid_ufs2 = BigEndianBitConverter.ToUInt32(ufs_sb_sectors, 0x02C8); // 0x02C8 system-wide uid + ufs_sb.fs_pad_ufs2 = BigEndianBitConverter.ToUInt32(ufs_sb_sectors, 0x02D0); // 0x02D0 due to alignment of fs_swuid + ufs_sb.fs_cgrotor_ufs2 = BigEndianBitConverter.ToUInt32(ufs_sb_sectors, 0x02D4); // 0x02D4 last cg searched + Array.Copy(ufs_sb_sectors, 0x02D8, ufs_sb.fs_ocsp_ufs2, 0, 112); // 0x02D8, 112 bytes, UInt32s, list of fs_cs info buffers + ufs_sb.fs_contigdirs_ufs2 = BigEndianBitConverter.ToUInt32(ufs_sb_sectors, 0x0348); // 0x0348 # of contiguously allocated dirs + ufs_sb.fs_csp_ufs2 = BigEndianBitConverter.ToUInt32(ufs_sb_sectors, 0x034C); // 0x034C cg summary info buffer for fs_cs + ufs_sb.fs_maxcluster_ufs2 = BigEndianBitConverter.ToUInt32(ufs_sb_sectors, 0x0350); // 0x0350 + ufs_sb.fs_active_ufs2 = BigEndianBitConverter.ToUInt32(ufs_sb_sectors, 0x0354); // 0x0354 used by snapshots to track fs + ufs_sb.fs_old_cpc_ufs2 = BigEndianBitConverter.ToUInt32(ufs_sb_sectors, 0x0358); // 0x0358 cyl per cycle in postbl + ufs_sb.fs_maxbsize_ufs2 = BigEndianBitConverter.ToUInt32(ufs_sb_sectors, 0x035C); // 0x035C maximum blocking factor permitted + Array.Copy(ufs_sb_sectors, 0x0360, ufs_sb.fs_sparecon64_ufs2, 0, 136); // 0x0360, 136 bytes, UInt64s, old rotation block list head + ufs_sb.fs_sblockloc_ufs2 = BigEndianBitConverter.ToUInt64(ufs_sb_sectors, 0x03E8); // 0x03E8 byte offset of standard superblock //cylinder summary information*/ - ufs_sb.fs_cstotal_ndir_ufs2 = eabr.ReadUInt64(); // 0x03F0 number of directories - ufs_sb.fs_cstotal_nbfree_ufs2 = eabr.ReadUInt64(); // 0x03F8 number of free blocks - ufs_sb.fs_cstotal_nifree_ufs2 = eabr.ReadUInt64(); // 0x0400 number of free inodes - ufs_sb.fs_cstotal_nffree_ufs2 = eabr.ReadUInt64(); // 0x0408 number of free frags - ufs_sb.fs_cstotal_numclusters_ufs2 = eabr.ReadUInt64(); // 0x0410 number of free clusters - ufs_sb.fs_cstotal_spare0_ufs2 = eabr.ReadUInt64(); // 0x0418 future expansion - ufs_sb.fs_cstotal_spare1_ufs2 = eabr.ReadUInt64(); // 0x0420 future expansion - ufs_sb.fs_cstotal_spare2_ufs2 = eabr.ReadUInt64(); // 0x0428 future expansion - ufs_sb.fs_time_sec_ufs2 = eabr.ReadUInt32(); // 0x0430 last time written - ufs_sb.fs_time_usec_ufs2 = eabr.ReadUInt32(); // 0x0434 last time written - ufs_sb.fs_size_ufs2 = eabr.ReadUInt64(); // 0x0438 number of blocks in fs - ufs_sb.fs_dsize_ufs2 = eabr.ReadUInt64(); // 0x0440 number of data blocks in fs - ufs_sb.fs_csaddr_ufs2 = eabr.ReadUInt64(); // 0x0448 blk addr of cyl grp summary area - ufs_sb.fs_pendingblocks_ufs2 = eabr.ReadUInt64(); // 0x0450 blocks in process of being freed - ufs_sb.fs_pendinginodes_ufs2 = eabr.ReadUInt32(); // 0x0458 inodes in process of being freed + ufs_sb.fs_cstotal_ndir_ufs2 = BigEndianBitConverter.ToUInt64(ufs_sb_sectors, 0x03F0); // 0x03F0 number of directories + ufs_sb.fs_cstotal_nbfree_ufs2 = BigEndianBitConverter.ToUInt64(ufs_sb_sectors, 0x03F8); // 0x03F8 number of free blocks + ufs_sb.fs_cstotal_nifree_ufs2 = BigEndianBitConverter.ToUInt64(ufs_sb_sectors, 0x0400); // 0x0400 number of free inodes + ufs_sb.fs_cstotal_nffree_ufs2 = BigEndianBitConverter.ToUInt64(ufs_sb_sectors, 0x0408); // 0x0408 number of free frags + ufs_sb.fs_cstotal_numclusters_ufs2 = BigEndianBitConverter.ToUInt64(ufs_sb_sectors, 0x0410); // 0x0410 number of free clusters + ufs_sb.fs_cstotal_spare0_ufs2 = BigEndianBitConverter.ToUInt64(ufs_sb_sectors, 0x0418); // 0x0418 future expansion + ufs_sb.fs_cstotal_spare1_ufs2 = BigEndianBitConverter.ToUInt64(ufs_sb_sectors, 0x0420); // 0x0420 future expansion + ufs_sb.fs_cstotal_spare2_ufs2 = BigEndianBitConverter.ToUInt64(ufs_sb_sectors, 0x0428); // 0x0428 future expansion + ufs_sb.fs_time_sec_ufs2 = BigEndianBitConverter.ToUInt32(ufs_sb_sectors, 0x0430); // 0x0430 last time written + ufs_sb.fs_time_usec_ufs2 = BigEndianBitConverter.ToUInt32(ufs_sb_sectors, 0x0434); // 0x0434 last time written + ufs_sb.fs_size_ufs2 = BigEndianBitConverter.ToUInt64(ufs_sb_sectors, 0x0438); // 0x0438 number of blocks in fs + ufs_sb.fs_dsize_ufs2 = BigEndianBitConverter.ToUInt64(ufs_sb_sectors, 0x0440); // 0x0440 number of data blocks in fs + ufs_sb.fs_csaddr_ufs2 = BigEndianBitConverter.ToUInt64(ufs_sb_sectors, 0x0448); // 0x0448 blk addr of cyl grp summary area + ufs_sb.fs_pendingblocks_ufs2 = BigEndianBitConverter.ToUInt64(ufs_sb_sectors, 0x0450); // 0x0450 blocks in process of being freed + ufs_sb.fs_pendinginodes_ufs2 = BigEndianBitConverter.ToUInt32(ufs_sb_sectors, 0x0458); // 0x0458 inodes in process of being freed #endregion UFS2 #region Sun - ufs_sb.fs_sparecon_sun = eabr.ReadBytes(212); // 0x045C, 212 bytes, reserved for future constants - ufs_sb.fs_reclaim_sun = eabr.ReadUInt32(); // 0x0530 - ufs_sb.fs_sparecon2_sun = eabr.ReadUInt32(); // 0x0534 - ufs_sb.fs_state_t_sun = eabr.ReadUInt32(); // 0x0538 file system state time stamp - ufs_sb.fs_qbmask0_sun = eabr.ReadUInt32(); // 0x053C ~usb_bmask - ufs_sb.fs_qbmask1_sun = eabr.ReadUInt32(); // 0x0540 ~usb_bmask - ufs_sb.fs_qfmask0_sun = eabr.ReadUInt32(); // 0x0544 ~usb_fmask - ufs_sb.fs_qfmask1_sun = eabr.ReadUInt32(); // 0x0548 ~usb_fmask + Array.Copy(ufs_sb_sectors, 0x045C, ufs_sb.fs_sparecon_sun, 0, 212); // 0x045C, 212 bytes, reserved for future constants + ufs_sb.fs_reclaim_sun = BigEndianBitConverter.ToUInt32(ufs_sb_sectors, 0x0530); // 0x0530 + ufs_sb.fs_sparecon2_sun = BigEndianBitConverter.ToUInt32(ufs_sb_sectors, 0x0534); // 0x0534 + ufs_sb.fs_state_t_sun = BigEndianBitConverter.ToUInt32(ufs_sb_sectors, 0x0538); // 0x0538 file system state time stamp + ufs_sb.fs_qbmask0_sun = BigEndianBitConverter.ToUInt32(ufs_sb_sectors, 0x053C); // 0x053C ~usb_bmask + ufs_sb.fs_qbmask1_sun = BigEndianBitConverter.ToUInt32(ufs_sb_sectors, 0x0540); // 0x0540 ~usb_bmask + ufs_sb.fs_qfmask0_sun = BigEndianBitConverter.ToUInt32(ufs_sb_sectors, 0x0544); // 0x0544 ~usb_fmask + ufs_sb.fs_qfmask1_sun = BigEndianBitConverter.ToUInt32(ufs_sb_sectors, 0x0548); // 0x0548 ~usb_fmask #endregion Sun #region Sunx86 - eabr.BaseStream.Seek(sb_offset + 0x045C, SeekOrigin.Begin); - ufs_sb.fs_sparecon_sun86 = eabr.ReadBytes(212); // 0x045C, 212 bytes, reserved for future constants - ufs_sb.fs_reclaim_sun86 = eabr.ReadUInt32(); // 0x0530 - ufs_sb.fs_sparecon2_sun86 = eabr.ReadUInt32(); // 0x0534 - ufs_sb.fs_npsect_sun86 = eabr.ReadUInt32(); // 0x0538 # sectors/track including spares - ufs_sb.fs_qbmask0_sun86 = eabr.ReadUInt32(); // 0x053C ~usb_bmask - ufs_sb.fs_qbmask1_sun86 = eabr.ReadUInt32(); // 0x0540 ~usb_bmask - ufs_sb.fs_qfmask0_sun86 = eabr.ReadUInt32(); // 0x0544 ~usb_fmask - ufs_sb.fs_qfmask1_sun86 = eabr.ReadUInt32(); // 0x0548 ~usb_fmask + Array.Copy(ufs_sb_sectors, 0x045C, ufs_sb.fs_sparecon_sun86, 0, 212); // 0x045C, 212 bytes, reserved for future constants + ufs_sb.fs_reclaim_sun86 = BigEndianBitConverter.ToUInt32(ufs_sb_sectors, 0x0530); // 0x0530 + ufs_sb.fs_sparecon2_sun86 = BigEndianBitConverter.ToUInt32(ufs_sb_sectors, 0x0534); // 0x0534 + ufs_sb.fs_npsect_sun86 = BigEndianBitConverter.ToUInt32(ufs_sb_sectors, 0x0538); // 0x0538 # sectors/track including spares + ufs_sb.fs_qbmask0_sun86 = BigEndianBitConverter.ToUInt32(ufs_sb_sectors, 0x053C); // 0x053C ~usb_bmask + ufs_sb.fs_qbmask1_sun86 = BigEndianBitConverter.ToUInt32(ufs_sb_sectors, 0x0540); // 0x0540 ~usb_bmask + ufs_sb.fs_qfmask0_sun86 = BigEndianBitConverter.ToUInt32(ufs_sb_sectors, 0x0544); // 0x0544 ~usb_fmask + ufs_sb.fs_qfmask1_sun86 = BigEndianBitConverter.ToUInt32(ufs_sb_sectors, 0x0548); // 0x0548 ~usb_fmask #endregion Sunx86 #region 44BSD - eabr.BaseStream.Seek(sb_offset + 0x045C, SeekOrigin.Begin); - ufs_sb.fs_sparecon_44bsd = eabr.ReadBytes(200); // 0x045C, 200 bytes - ufs_sb.fs_contigsumsize_44bsd = eabr.ReadUInt32(); // 0x0524 size of cluster summary array - ufs_sb.fs_maxsymlinklen_44bsd = eabr.ReadUInt32(); // 0x0528 max length of an internal symlink - ufs_sb.fs_inodefmt_44bsd = eabr.ReadUInt32(); // 0x052C format of on-disk inodes - ufs_sb.fs_maxfilesize0_44bsd = eabr.ReadUInt32(); // 0x0530 max representable file size - ufs_sb.fs_maxfilesize1_44bsd = eabr.ReadUInt32(); // 0x0534 max representable file size - ufs_sb.fs_qbmask0_44bsd = eabr.ReadUInt32(); // 0x0538 ~usb_bmask - ufs_sb.fs_qbmask1_44bsd = eabr.ReadUInt32(); // 0x053C ~usb_bmask - ufs_sb.fs_qfmask0_44bsd = eabr.ReadUInt32(); // 0x0540 ~usb_fmask - ufs_sb.fs_qfmask1_44bsd = eabr.ReadUInt32(); // 0x0544 ~usb_fmask - ufs_sb.fs_state_t_44bsd = eabr.ReadUInt32(); // 0x0548 file system state time stamp + Array.Copy(ufs_sb_sectors, 0x045C, ufs_sb.fs_sparecon_44bsd, 0, 200); // 0x045C, 200 bytes + ufs_sb.fs_contigsumsize_44bsd = BigEndianBitConverter.ToUInt32(ufs_sb_sectors, 0x0524); // 0x0524 size of cluster summary array + ufs_sb.fs_maxsymlinklen_44bsd = BigEndianBitConverter.ToUInt32(ufs_sb_sectors, 0x0528); // 0x0528 max length of an internal symlink + ufs_sb.fs_inodefmt_44bsd = BigEndianBitConverter.ToUInt32(ufs_sb_sectors, 0x052C); // 0x052C format of on-disk inodes + ufs_sb.fs_maxfilesize0_44bsd = BigEndianBitConverter.ToUInt32(ufs_sb_sectors, 0x0530); // 0x0530 max representable file size + ufs_sb.fs_maxfilesize1_44bsd = BigEndianBitConverter.ToUInt32(ufs_sb_sectors, 0x0534); // 0x0534 max representable file size + ufs_sb.fs_qbmask0_44bsd = BigEndianBitConverter.ToUInt32(ufs_sb_sectors, 0x0538); // 0x0538 ~usb_bmask + ufs_sb.fs_qbmask1_44bsd = BigEndianBitConverter.ToUInt32(ufs_sb_sectors, 0x053C); // 0x053C ~usb_bmask + ufs_sb.fs_qfmask0_44bsd = BigEndianBitConverter.ToUInt32(ufs_sb_sectors, 0x0540); // 0x0540 ~usb_fmask + ufs_sb.fs_qfmask1_44bsd = BigEndianBitConverter.ToUInt32(ufs_sb_sectors, 0x0544); // 0x0544 ~usb_fmask + ufs_sb.fs_state_t_44bsd = BigEndianBitConverter.ToUInt32(ufs_sb_sectors, 0x0548); // 0x0548 file system state time stamp #endregion 44BSD - ufs_sb.fs_postblformat = eabr.ReadUInt32(); // 0x054C format of positional layout tables - ufs_sb.fs_nrpos = eabr.ReadUInt32(); // 0x0550 number of rotational positions - ufs_sb.fs_postbloff = eabr.ReadUInt32(); // 0x0554 (__s16) rotation block list head - ufs_sb.fs_rotbloff = eabr.ReadUInt32(); // 0x0558 (__u8) blocks for each rotation - ufs_sb.fs_magic = eabr.ReadUInt32(); // 0x055C magic number - ufs_sb.fs_space = eabr.ReadByte(); // 0x0560 list of blocks for each rotation - if(eabr.BaseStream.Position != (sb_offset + 0x0561) && MainClass.isDebug) - Console.WriteLine("Error reading superblock, out of alignment 0x{0:X8}, expected 0x{1:X8}", eabr.BaseStream.Position, (sb_offset + 0x0561)); + ufs_sb.fs_postblformat = BigEndianBitConverter.ToUInt32(ufs_sb_sectors, 0x054C); // 0x054C format of positional layout tables + ufs_sb.fs_nrpos = BigEndianBitConverter.ToUInt32(ufs_sb_sectors, 0x0550); // 0x0550 number of rotational positions + ufs_sb.fs_postbloff = BigEndianBitConverter.ToUInt32(ufs_sb_sectors, 0x0554); // 0x0554 (__s16) rotation block list head + ufs_sb.fs_rotbloff = BigEndianBitConverter.ToUInt32(ufs_sb_sectors, 0x0558); // 0x0558 (__u8) blocks for each rotation + ufs_sb.fs_magic = BigEndianBitConverter.ToUInt32(ufs_sb_sectors, 0x055C); // 0x055C magic number + ufs_sb.fs_space = ufs_sb_sectors[0x0560]; // 0x0560 list of blocks for each rotation if(MainClass.isDebug) { @@ -655,13 +661,13 @@ namespace FileSystemIDandChk.Plugins information = sbInformation.ToString(); } - private const int block_size = 8192; + private const uint block_size = 8192; // As specified in FreeBSD source code, FFS/UFS can start in any of four places - private const long sb_start_floppy = 0; // For floppies, start at offset 0 - private const long sb_start_ufs1 = block_size; // For normal devices, start at offset 8192 - private const long sb_start_ufs2 = block_size*8; // For UFS2, start at offset 65536 - private const long sb_start_piggy = block_size*32; // For piggy devices (?), start at offset 262144 + private const ulong sb_start_floppy = 0; // For floppies, start at offset 0 + private const ulong sb_start_ufs1 = 1; // For normal devices, start at offset 8192 + private const ulong sb_start_ufs2 = 8; // For UFS2, start at offset 65536 + private const ulong sb_start_piggy = 32; // For piggy devices (?), start at offset 262144 // MAGICs private const UInt32 UFS_MAGIC = 0x00011954; // UFS magic @@ -674,6 +680,7 @@ namespace FileSystemIDandChk.Plugins // There is no clear way to detect which one is correct // And as C# does not support unions this struct will clearly appear quite dirty :p // To clean up things a little, comment starts with relative superblock offset of field + // Biggest sized supleblock would be 1377 bytes public struct UFSSuperBlock { #region 42BSD diff --git a/FileSystemIDandChk/Plugins/HPFS.cs b/FileSystemIDandChk/Plugins/HPFS.cs index 3a5af3455..16ccd46e6 100644 --- a/FileSystemIDandChk/Plugins/HPFS.cs +++ b/FileSystemIDandChk/Plugins/HPFS.cs @@ -3,8 +3,6 @@ using System.IO; using System.Text; using FileSystemIDandChk; -// Information from Inside Macintosh - namespace FileSystemIDandChk.Plugins { class HPFS : Plugin @@ -15,22 +13,13 @@ namespace FileSystemIDandChk.Plugins base.PluginUUID = new Guid("33513B2C-f590-4acb-8bf2-0b1d5e19dec5"); } - public override bool Identify(FileStream stream, long offset) + public override bool Identify(ImagePlugins.ImagePlugin imagePlugin, ulong partitionOffset) { - UInt16 bps; UInt32 magic1, magic2; - BinaryReader br = new BinaryReader(stream); - - br.BaseStream.Seek(offset + 3 + 8, SeekOrigin.Begin); // Seek to bps - bps = br.ReadUInt16(); - - if(br.BaseStream.Length < offset + (16 * bps)) - return false; - - br.BaseStream.Seek(offset + (16 * bps), SeekOrigin.Begin); // Seek to superblock, on logical sector 16 - magic1 = br.ReadUInt32(); - magic2 = br.ReadUInt32(); + 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; @@ -38,14 +27,12 @@ namespace FileSystemIDandChk.Plugins return false; } - public override void GetInformation (FileStream stream, long offset, out string information) + public override void GetInformation (ImagePlugins.ImagePlugin imagePlugin, ulong partitionOffset, out string information) { information = ""; StringBuilder sb = new StringBuilder(); - BinaryReader br = new BinaryReader(stream); - HPFS_BIOSParameterBlock hpfs_bpb = new HPFS_BIOSParameterBlock(); HPFS_SuperBlock hpfs_sb = new HPFS_SuperBlock(); HPFS_SpareBlock hpfs_sp = new HPFS_SpareBlock(); @@ -53,73 +40,73 @@ namespace FileSystemIDandChk.Plugins byte[] oem_name = new byte[8]; byte[] volume_name = new byte[11]; - br.BaseStream.Seek(offset, SeekOrigin.Begin); // Seek to BPB - hpfs_bpb.jmp1 = br.ReadByte(); - hpfs_bpb.jmp2 = br.ReadUInt16(); - oem_name = br.ReadBytes(8); + 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 = br.ReadUInt16(); - hpfs_bpb.spc = br.ReadByte(); - hpfs_bpb.rsectors = br.ReadUInt16(); - hpfs_bpb.fats_no = br.ReadByte(); - hpfs_bpb.root_ent = br.ReadUInt16(); - hpfs_bpb.sectors = br.ReadUInt16(); - hpfs_bpb.media = br.ReadByte(); - hpfs_bpb.spfat = br.ReadUInt16(); - hpfs_bpb.sptrk = br.ReadUInt16(); - hpfs_bpb.heads = br.ReadUInt16(); - hpfs_bpb.hsectors = br.ReadUInt32(); - hpfs_bpb.big_sectors = br.ReadUInt32(); - hpfs_bpb.drive_no = br.ReadByte(); - hpfs_bpb.nt_flags = br.ReadByte(); - hpfs_bpb.signature = br.ReadByte(); - hpfs_bpb.serial_no = br.ReadUInt32(); - volume_name = br.ReadBytes(11); + 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); - oem_name = br.ReadBytes(8); + Array.Copy(hpfs_bpb_sector, 0x03A, oem_name, 0, 8); hpfs_bpb.fs_type = StringHandlers.CToString(oem_name); - br.BaseStream.Seek((16*hpfs_bpb.bps) + offset, SeekOrigin.Begin); // Seek to SuperBlock - - hpfs_sb.magic1 = br.ReadUInt32(); - hpfs_sb.magic2 = br.ReadUInt32(); - hpfs_sb.version = br.ReadByte(); - hpfs_sb.func_version = br.ReadByte(); - hpfs_sb.dummy = br.ReadUInt16(); - hpfs_sb.root_fnode = br.ReadUInt32(); - hpfs_sb.sectors = br.ReadUInt32(); - hpfs_sb.badblocks = br.ReadUInt32(); - hpfs_sb.bitmap_lsn = br.ReadUInt32(); - hpfs_sb.zero1 = br.ReadUInt32(); - hpfs_sb.badblock_lsn = br.ReadUInt32(); - hpfs_sb.zero2 = br.ReadUInt32(); - hpfs_sb.last_chkdsk = br.ReadInt32(); - hpfs_sb.last_optim = br.ReadInt32(); - hpfs_sb.dband_sectors = br.ReadUInt32(); - hpfs_sb.dband_start = br.ReadUInt32(); - hpfs_sb.dband_last = br.ReadUInt32(); - hpfs_sb.dband_bitmap = br.ReadUInt32(); - hpfs_sb.zero3 = br.ReadUInt64(); - hpfs_sb.zero4 = br.ReadUInt64(); - hpfs_sb.zero5 = br.ReadUInt64(); - hpfs_sb.zero6 = br.ReadUInt64(); + 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); - br.BaseStream.Seek((17*hpfs_bpb.bps) + offset, SeekOrigin.Begin); // Seek to SuperBlock - - hpfs_sp.magic1 = br.ReadUInt32(); - hpfs_sp.magic2 = br.ReadUInt32(); - hpfs_sp.flags1 = br.ReadByte(); - hpfs_sp.flags2 = br.ReadByte(); - hpfs_sp.dummy = br.ReadUInt16(); - hpfs_sp.hotfix_start = br.ReadUInt32(); - hpfs_sp.hotfix_used = br.ReadUInt32(); - hpfs_sp.hotfix_entries = br.ReadUInt32(); - hpfs_sp.spare_dnodes_free = br.ReadUInt32(); - hpfs_sp.spare_dnodes = br.ReadUInt32(); - hpfs_sp.codepage_lsn = br.ReadUInt32(); - hpfs_sp.codepages = br.ReadUInt32(); - hpfs_sp.sb_crc32 = br.ReadUInt32(); - hpfs_sp.sp_crc32 = br.ReadUInt32(); + 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 || @@ -225,73 +212,72 @@ namespace FileSystemIDandChk.Plugins private struct HPFS_BIOSParameterBlock // Sector 0 { - public byte jmp1; // Jump to boot code - public UInt16 jmp2; // ...; - public string OEMName; // OEM Name, 8 bytes, space-padded - public UInt16 bps; // Bytes per sector - public byte spc; // Sectors per cluster - public UInt16 rsectors; // Reserved sectors between BPB and... does it have sense in HPFS? - public byte fats_no; // Number of FATs... seriously? - public UInt16 root_ent; // Number of entries on root directory... ok - public UInt16 sectors; // Sectors in volume... doubt it - public byte media; // Media descriptor - public UInt16 spfat; // Sectors per FAT... again - public UInt16 sptrk; // Sectors per track... you're kidding - public UInt16 heads; // Heads... stop! - public UInt32 hsectors; // Hidden sectors before BPB - public UInt32 big_sectors; // Sectors in volume if > 65535... - public byte drive_no; // Drive number - public byte nt_flags; // Volume flags? - public byte signature; // EPB signature, 0x29 - public UInt32 serial_no; // Volume serial number - public string volume_label; // Volume label, 11 bytes, space-padded - public string fs_type; // Filesystem type, 8 bytes, space-padded ("HPFS ") + 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 ") } private struct HPFS_SuperBlock // Sector 16 { - public UInt32 magic1; // 0xF995E849 - public UInt32 magic2; // 0xFA53E9C5 - public byte version; // HPFS version - public byte func_version; // 2 if <= 4 GiB, 3 if > 4 GiB - public UInt16 dummy; // Alignment - public UInt32 root_fnode; // LSN pointer to root fnode - public UInt32 sectors; // Sectors on volume - public UInt32 badblocks; // Bad blocks on volume - public UInt32 bitmap_lsn; // LSN pointer to volume bitmap - public UInt32 zero1; // 0 - public UInt32 badblock_lsn; // LSN pointer to badblock directory - public UInt32 zero2; // 0 - public Int32 last_chkdsk; // Time of last CHKDSK - public Int32 last_optim; // Time of last optimization - public UInt32 dband_sectors; // Sectors of dir band - public UInt32 dband_start; // Start sector of dir band - public UInt32 dband_last; // Last sector of dir band - public UInt32 dband_bitmap; // LSN of free space bitmap - public UInt64 zero3; // Can be used for volume name (32 bytes) - public UInt64 zero4; // ... - public UInt64 zero5; // ... - public UInt64 zero6; // ...; - public UInt32 acl_start; // LSN pointer to ACLs (only HPFS386) + 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) } private struct HPFS_SpareBlock // Sector 17 { - public UInt32 magic1; // 0xF9911849 - public UInt32 magic2; // 0xFA5229C5 - public byte flags1; // HPFS flags - public byte flags2; // HPFS386 flags - public UInt16 dummy; // Alignment - public UInt32 hotfix_start; // LSN of hotfix directory - public UInt32 hotfix_used; // Used hotfixes - public UInt32 hotfix_entries; // Total hotfixes available - public UInt32 spare_dnodes_free; // Unused spare dnodes - public UInt32 spare_dnodes; // Length of spare dnodes list - public UInt32 codepage_lsn; // LSN of codepage directory - public UInt32 codepages; // Number of codepages used - public UInt32 sb_crc32; // SuperBlock CRC32 (only HPFS386) - public UInt32 sp_crc32; // SpareBlock CRC32 (only HPFS386) + 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) } } } - diff --git a/FileSystemIDandChk/Plugins/ISO9660.cs b/FileSystemIDandChk/Plugins/ISO9660.cs index 79a19b2de..e4e75528e 100644 --- a/FileSystemIDandChk/Plugins/ISO9660.cs +++ b/FileSystemIDandChk/Plugins/ISO9660.cs @@ -7,6 +7,7 @@ using FileSystemIDandChk; // 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 FileSystemIDandChk.Plugins { @@ -38,7 +39,7 @@ namespace FileSystemIDandChk.Plugins public DateTime EffectiveTime; } - public override bool Identify(FileStream fileStream, long offset) + public override bool Identify(ImagePlugins.ImagePlugin imagePlugin, ulong partitionOffset) { if(alreadyLaunched) return false; @@ -47,22 +48,25 @@ namespace FileSystemIDandChk.Plugins byte VDType; - // ISO9660 Primary Volume Descriptor starts at 32768, so that's minimal size. - if (fileStream.Length < 32768) + // ISO9660 is designed for 2048 bytes/sector devices + if (imagePlugin.GetSectorSize() < 2048) return false; - - // Seek to Volume Descriptor - fileStream.Seek(32768, SeekOrigin.Begin); - VDType = (byte)fileStream.ReadByte(); + // 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; - if (fileStream.Read(VDMagic, 0, 5) != 5) - return false; // Something bad happened + 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. return false; @@ -70,7 +74,7 @@ namespace FileSystemIDandChk.Plugins return true; } - public override void GetInformation (FileStream fileStream, long offset, out string information) + public override void GetInformation (ImagePlugins.ImagePlugin imagePlugin, ulong partitionOffset, out string information) { information = ""; StringBuilder ISOMetadata = new StringBuilder(); @@ -108,20 +112,22 @@ namespace FileSystemIDandChk.Plugins byte[] VDPathTableStart = new byte[4]; byte[] RootDirectoryLocation = new byte[4]; - fileStream.Seek(0, SeekOrigin.Begin); - - // ISO9660 Primary Volume Descriptor starts at 32768, so that's minimal size. - if (fileStream.Length < 32768) + // ISO9660 is designed for 2048 bytes/sector devices + if (imagePlugin.GetSectorSize() < 2048) return; - int counter = 0; + // 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 - fileStream.Seek(32768+(2048*counter), SeekOrigin.Begin); + byte[] vd_sector = imagePlugin.ReadSector(16 + counter + partitionOffset); - VDType = (byte)fileStream.ReadByte(); + VDType = vd_sector[0]; if (VDType == 255) // Supposedly we are in the PVD. { @@ -130,12 +136,7 @@ namespace FileSystemIDandChk.Plugins break; } - if (fileStream.Read(VDMagic, 0, 5) != 5) - { - if (counter == 0) - return; // Something bad happened - 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. { @@ -151,11 +152,8 @@ namespace FileSystemIDandChk.Plugins Bootable = true; BootSpec = "Unknown"; - // Seek to boot system identifier - fileStream.Seek(32775 + (2048 * counter), SeekOrigin.Begin); - - if (fileStream.Read(BootSysId, 0, 32) != 32) - break; // Something bad happened + // 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"; @@ -164,56 +162,31 @@ namespace FileSystemIDandChk.Plugins } case 1: { - // Seek to first identifiers - fileStream.Seek(32776 + (2048 * counter), SeekOrigin.Begin); - - if (fileStream.Read(VDSysId, 0, 32) != 32) - break; // Something bad happened - if (fileStream.Read(VDVolId, 0, 32) != 32) - break; // Something bad happened + // Read first identifiers + Array.Copy(vd_sector, 0x008, VDSysId, 0, 32); + Array.Copy(vd_sector, 0x028, VDVolId, 0, 32); // Get path table start - fileStream.Seek(32908 + (2048 * counter), SeekOrigin.Begin); + Array.Copy(vd_sector, 0x08C, VDPathTableStart, 0, 4); - if (fileStream.Read(VDPathTableStart, 0, 4) != 4) - break; // Something bad happened + // 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); - // Seek to next identifiers - fileStream.Seek(32958 + (2048 * counter), SeekOrigin.Begin); - - if (fileStream.Read(VDVolSetId, 0, 128) != 128) - break; // Something bad happened - if (fileStream.Read(VDPubId, 0, 128) != 128) - break; // Something bad happened - if (fileStream.Read(VDDataPrepId, 0, 128) != 128) - break; // Something bad happened - if (fileStream.Read(VDAppId, 0, 128) != 128) - break; // Something bad happened - - // Seek to dates - fileStream.Seek(33581 + (2048 * counter), SeekOrigin.Begin); - - if (fileStream.Read(VCTime, 0, 17) != 17) - break; // Something bad happened - if (fileStream.Read(VMTime, 0, 17) != 17) - break; // Something bad happened - if (fileStream.Read(VXTime, 0, 17) != 17) - break; // Something bad happened - if (fileStream.Read(VETime, 0, 17) != 17) - break; // Something bad happened + // 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 - fileStream.Seek(32856 + (2048 * counter), SeekOrigin.Begin); - - if (fileStream.Read(JolietMagic, 0, 3) != 3) - { - break; // Something bad happened - } - + Array.Copy(vd_sector, 0x058, JolietMagic, 0, 3); if (JolietMagic[0] == '%' && JolietMagic[1] == '/') { if (JolietMagic[2] == '@' || JolietMagic[2] == 'C' || JolietMagic[2] == 'E') @@ -228,37 +201,21 @@ namespace FileSystemIDandChk.Plugins else break; - // Seek to first identifiers - fileStream.Seek(32776 + (2048 * counter), SeekOrigin.Begin); + // Read first identifiers + Array.Copy(vd_sector, 0x008, JolietSysId, 0, 32); + Array.Copy(vd_sector, 0x028, JolietVolId, 0, 32); - if (fileStream.Read(JolietSysId, 0, 32) != 32) - break; // Something bad happened - if (fileStream.Read(JolietVolId, 0, 32) != 32) - break; // Something bad happened + // 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); - // Seek to next identifiers - fileStream.Seek(32958 + (2048 * counter), SeekOrigin.Begin); - - if (fileStream.Read(JolietVolSetId, 0, 128) != 128) - break; // Something bad happened - if (fileStream.Read(JolietPubId, 0, 128) != 128) - break; // Something bad happened - if (fileStream.Read(JolietDataPrepId, 0, 128) != 128) - break; // Something bad happened - if (fileStream.Read(JolietAppId, 0, 128) != 128) - break; // Something bad happened - - // Seek to dates - fileStream.Seek(33581 + (2048 * counter), SeekOrigin.Begin); - - if (fileStream.Read(JolietCTime, 0, 17) != 17) - break; // Something bad happened - if (fileStream.Read(JolietMTime, 0, 17) != 17) - break; // Something bad happened - if (fileStream.Read(JolietXTime, 0, 17) != 17) - break; // Something bad happened - if (fileStream.Read(JolietETime, 0, 17) != 17) - break; // Something bad happened + // 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; } @@ -275,27 +232,23 @@ namespace FileSystemIDandChk.Plugins decodedJolietVD = DecodeJolietDescriptor(JolietSysId, JolietVolId, JolietVolSetId, JolietPubId, JolietDataPrepId, JolietAppId, JolietCTime, JolietMTime, JolietXTime, JolietETime); - int i = BitConverter.ToInt32(VDPathTableStart, 0); - - fileStream.Seek((i * 2048)+2, SeekOrigin.Begin); // Seek to first path table location field + 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 - if (fileStream.Read(RootDirectoryLocation, 0, 4) == 4) + 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") { - fileStream.Seek((BitConverter.ToInt32(RootDirectoryLocation,0) * 2048)+34, SeekOrigin.Begin); // Seek to root directory, first entry, system use field - - byte[] SUSPMagic = new byte[2]; - byte[] RRMagic = new byte[2]; - - fileStream.Read(SUSPMagic, 0, 2); - if (Encoding.ASCII.GetString(SUSPMagic) == "SP") + Array.Copy(root_dir, 0x29, RRMagic, 0, 2); + if (Encoding.ASCII.GetString(RRMagic) == "RR") { - fileStream.Seek(5, SeekOrigin.Current); // Seek for rock ridge magic - fileStream.Read(RRMagic, 0, 2); - if (Encoding.ASCII.GetString(RRMagic) == "RR") - { - RockRidge = true; - } + RockRidge = true; } } @@ -307,8 +260,8 @@ namespace FileSystemIDandChk.Plugins StringBuilder IPBinInformation = new StringBuilder(); byte[] SegaHardwareID = new byte[16]; - fileStream.Seek(0, SeekOrigin.Begin); // Seek to start (again) - fileStream.Read(SegaHardwareID, 0, 16); + byte[] ipbin_sector = imagePlugin.ReadSector(0 + partitionOffset); + Array.Copy(ipbin_sector, 0x000, SegaHardwareID, 0, 16); switch (Encoding.ASCII.GetString(SegaHardwareID)) { @@ -323,85 +276,80 @@ namespace FileSystemIDandChk.Plugins IPBinInformation.AppendLine("--------------------------------"); // Definitions following - byte[] volume_name = new byte[11]; // Varies - byte[] spare_space1 = new byte[1]; // 0x00 - byte[] volume_version = new byte[2]; // Volume version in BCD. <100 = Prerelease. - byte[] volume_type = new byte[2]; // Bit 0 = 1 => CD-ROM. Rest should be 0. - byte[] system_name = new byte[11]; // Unknown, varies! - byte[] spare_space2 = new byte[1]; // 0x00 - byte[] system_version = new byte[2]; // Should be 1 - byte[] spare_space3 = new byte[2]; // 0x0000 - byte[] ip_address = new byte[4]; // Initial program address - byte[] ip_loadsize = new byte[4]; // Load size of initial program - byte[] ip_entry_address = new byte[4]; // Initial program entry address - byte[] ip_work_ram_size = new byte[4]; // Initial program work RAM size in bytes - byte[] sp_address = new byte[4]; // System program address - byte[] sp_loadsize = new byte[4]; // Load size of system program - byte[] sp_entry_address = new byte[4]; // System program entry address - byte[] sp_work_ram_size = new byte[4]; // System program work RAM size in bytes - byte[] release_date = new byte[8]; // MMDDYYYY - byte[] unknown1 = new byte[7]; // Seems to be all 0x20s - byte[] spare_space4 = new byte[1]; // 0x00 ? - byte[] system_reserved = new byte[160]; // System Reserved Area - byte[] hardware_id = new byte[16]; // Hardware ID - byte[] copyright = new byte[3]; // "(C)" -- Can be the developer code directly!, if that is the code release date will be displaced - byte[] developer_code = new byte[5]; // "SEGA" or "T-xx" - byte[] unknown2 = new byte[1]; // Seems to be part of developer code, need to get a SEGA disc to check - byte[] release_date2 = new byte[8]; // Another release date, this with month in letters? - byte[] domestic_title = new byte[48]; // Domestic version of the game title - byte[] overseas_title = new byte[48]; // Overseas version of the game title - byte[] application_type = new byte[2]; // Application type - byte[] space_space5 = new byte[1]; // 0x20 - byte[] product_code = new byte[13]; // Official product code - byte[] peripherals = new byte[16]; // Supported peripherals, see above - byte[] spare_space6 = new byte[16]; // 0x20 - byte[] spare_space7 = new byte[64]; // Inside here should be modem information, but I need to get a modem-enabled game - byte[] region_codes = new byte[16]; // Region codes, space-filled + 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 - fileStream.Read(volume_name, 0, 11); // Varies - fileStream.Read(spare_space1, 0, 1); // 0x00 - fileStream.Read(volume_version, 0, 2); // Volume version in BCD. <100 = Prerelease. - fileStream.Read(volume_type, 0, 2); // Bit 0 = 1 => CD-ROM. Rest should be 0. - fileStream.Read(system_name, 0, 11); // Unknown, varies! - fileStream.Read(spare_space2, 0, 1); // 0x00 - fileStream.Read(system_version, 0, 2); // Should be 1 - fileStream.Read(spare_space3, 0, 2); // 0x0000 - fileStream.Read(ip_address, 0, 4); // Initial program address - fileStream.Read(ip_loadsize, 0, 4); // Load size of initial program - fileStream.Read(ip_entry_address, 0, 4); // Initial program entry address - fileStream.Read(ip_work_ram_size, 0, 4); // Initial program work RAM size in bytes - fileStream.Read(sp_address, 0, 4); // System program address - fileStream.Read(sp_loadsize, 0, 4); // Load size of system program - fileStream.Read(sp_entry_address, 0, 4); // System program entry address - fileStream.Read(sp_work_ram_size, 0, 4); // System program work RAM size in bytes - fileStream.Read(release_date, 0, 8); // MMDDYYYY - fileStream.Read(unknown1, 0, 7); // Seems to be all 0x20s - fileStream.Read(spare_space4, 0, 1); // 0x00 ? - fileStream.Read(system_reserved, 0, 160); // System Reserved Area - fileStream.Read(hardware_id, 0, 16); // Hardware ID - fileStream.Read(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)") - fileStream.Seek(-3, SeekOrigin.Current); - fileStream.Read(developer_code, 0, 5); // "SEGA" or "T-xx" - if (Encoding.ASCII.GetString(copyright) != "(C)") - fileStream.Seek(1, SeekOrigin.Current); - fileStream.Read(release_date2, 0, 8); // Another release date, this with month in letters? - if (Encoding.ASCII.GetString(copyright) != "(C)") - fileStream.Seek(2, SeekOrigin.Current); - fileStream.Read(domestic_title, 0, 48); // Domestic version of the game title - fileStream.Read(overseas_title, 0, 48); // Overseas version of the game title - fileStream.Read(application_type, 0, 2); // Application type - fileStream.Read(space_space5, 0, 1); // 0x20 - fileStream.Read(product_code, 0, 13); // Official product code - fileStream.Read(peripherals, 0, 16); // Supported peripherals, see above - fileStream.Read(spare_space6, 0, 16); // 0x20 - fileStream.Read(spare_space7, 0, 64); // Inside here should be modem information, but I need to get a modem-enabled game - fileStream.Read(region_codes, 0, 16); // Region codes, space-filled + 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 = new DateTime(); CultureInfo provider = CultureInfo.InvariantCulture; ipbindate = DateTime.ParseExact(Encoding.ASCII.GetString(release_date), "MMddyyyy", provider); + /* switch (Encoding.ASCII.GetString(application_type)) { case "GM": @@ -414,6 +362,7 @@ namespace FileSystemIDandChk.Plugins 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(); @@ -513,33 +462,31 @@ namespace FileSystemIDandChk.Plugins IPBinInformation.AppendLine("--------------------------------"); // Definitions following - byte[] maker_id = new byte[16]; // "SEGA ENTERPRISES" - byte[] product_no = new byte[10]; // Product number - byte[] product_version = new byte[6]; // Product version - byte[] release_date = new byte[8]; // YYYYMMDD - byte[] saturn_media = new byte[3]; // "CD-" - byte[] disc_no = new byte[1]; // Disc number - byte[] disc_no_separator = new byte[1]; // '/' - byte[] disc_total_nos = new byte[1]; // Total number of discs - byte[] spare_space1 = new byte[2]; // " " - byte[] region_codes = new byte[10]; // Region codes, space-filled - byte[] spare_space2 = new byte[6]; // " " - byte[] peripherals = new byte[16]; // Supported peripherals, see above - byte[] product_name = new byte[112]; // Game name, space-filled + 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 - fileStream.Read(maker_id, 0, 16); // "SEGA ENTERPRISES" - fileStream.Read(product_no, 0, 10); // Product number - fileStream.Read(product_version, 0, 6); // Product version - fileStream.Read(release_date, 0, 8); // YYYYMMDD - fileStream.Read(saturn_media, 0, 3); // "CD-" - fileStream.Read(disc_no, 0, 1); // Disc number - fileStream.Read(disc_no_separator, 0, 1); // '/' - fileStream.Read(disc_total_nos, 0, 1); // Total number of discs - fileStream.Read(spare_space1, 0, 2); // " " - fileStream.Read(region_codes, 0, 10); // Region codes, space-filled - fileStream.Read(spare_space2, 0, 6); // " " - fileStream.Read(peripherals, 0, 16); // Supported peripherals, see above - fileStream.Read(product_name, 0, 112); // Game name, space-filled + 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 = new DateTime(); CultureInfo provider = CultureInfo.InvariantCulture; @@ -616,41 +563,41 @@ namespace FileSystemIDandChk.Plugins IPBinInformation.AppendLine("--------------------------------"); // Declarations following - byte[] maker_id = new byte[16]; // "SEGA ENTERPRISES" - byte[] dreamcast_crc = new byte[4]; // CRC of product_no and product_version - byte[] spare_space1 = new byte[1]; // " " - byte[] dreamcast_media = new byte[6]; // "GD-ROM" - byte[] disc_no = new byte[1]; // Disc number - byte[] disc_no_separator = new byte[1]; // '/' - byte[] disc_total_nos = new byte[1]; // Total number of discs - byte[] spare_space2 = new byte[2]; // " " - byte[] region_codes = new byte[8]; // Region codes, space-filled - byte[] peripherals = new byte[4]; // Supported peripherals, bitwise - byte[] product_no = new byte[10]; // Product number - byte[] product_version = new byte[6]; // Product version - byte[] release_date = new byte[8]; // YYYYMMDD - byte[] spare_space3 = new byte[8]; // " " - byte[] boot_filename = new byte[12]; // Usually "1ST_READ.BIN" or "0WINCE.BIN " - byte[] producer = new byte[16]; // Game producer, space-filled - byte[] product_name = new byte[128]; // Game name, space-filled + 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 - fileStream.Read(maker_id, 0, 16); // "SEGA ENTERPRISES" - fileStream.Read(dreamcast_crc, 0, 4); // CRC of product_no and product_version - fileStream.Read(spare_space1, 0, 1); // " " - fileStream.Read(dreamcast_media, 0, 6); // "GD-ROM" - fileStream.Read(disc_no, 0, 1); // Disc number - fileStream.Read(disc_no_separator, 0, 1); // '/' - fileStream.Read(disc_total_nos, 0, 1); // Total number of discs - fileStream.Read(spare_space2, 0, 2); // " " - fileStream.Read(region_codes, 0, 8); // Region codes, space-filled - fileStream.Read(peripherals, 0, 4); // Supported peripherals, bitwise - fileStream.Read(product_no, 0, 10); // Product number - fileStream.Read(product_version, 0, 6); // Product version - fileStream.Read(release_date, 0, 8); // YYYYMMDD - fileStream.Read(spare_space3, 0, 8); // " " - fileStream.Read(boot_filename, 0, 12); // Usually "1ST_READ.BIN" or "0WINCE.BIN " - fileStream.Read(producer, 0, 16); // Game producer, space-filled - fileStream.Read(product_name, 0, 128); // Game name, space-filled + 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 = new DateTime(); CultureInfo provider = CultureInfo.InvariantCulture; @@ -920,4 +867,4 @@ namespace FileSystemIDandChk.Plugins return decodedVD; } } -} +} \ No newline at end of file diff --git a/FileSystemIDandChk/Plugins/MinixFS.cs b/FileSystemIDandChk/Plugins/MinixFS.cs index f1ded5e21..382342220 100644 --- a/FileSystemIDandChk/Plugins/MinixFS.cs +++ b/FileSystemIDandChk/Plugins/MinixFS.cs @@ -3,8 +3,6 @@ using System.IO; using System.Text; using FileSystemIDandChk; -// Information from Inside Macintosh - namespace FileSystemIDandChk.Plugins { class MinixFS : Plugin @@ -28,21 +26,19 @@ namespace FileSystemIDandChk.Plugins base.PluginUUID = new Guid("FE248C3B-B727-4AE5-A39F-79EA9A07D4B3"); } - public override bool Identify(FileStream stream, long offset) + public override bool Identify(ImagePlugins.ImagePlugin imagePlugin, ulong partitionOffset) { UInt16 magic; - BinaryReader br = new BinaryReader(stream); + byte[] minix_sb_sector = imagePlugin.ReadSector(2 + partitionOffset); - br.BaseStream.Seek(0x400 + 0x10 + offset, SeekOrigin.Begin); // Here should reside magic number on Minix V1 & V2 - magic = br.ReadUInt16(); + 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; else { - br.BaseStream.Seek(0x400 + 0x18 + offset, SeekOrigin.Begin); // Here should reside magic number on Minix V1 & V2 - magic = br.ReadUInt16(); + magic = BitConverter.ToUInt16(minix_sb_sector, 0x018); // Here should reside magic number on Minix V3 if(magic == MINIX3_MAGIC || magic == MINIX3_CIGAM) return true; @@ -51,7 +47,7 @@ namespace FileSystemIDandChk.Plugins } } - public override void GetInformation (FileStream stream, long offset, out string information) + public override void GetInformation (ImagePlugins.ImagePlugin imagePlugin, ulong partitionOffset, out string information) { information = ""; @@ -62,10 +58,9 @@ namespace FileSystemIDandChk.Plugins int filenamesize = 0; string minixVersion; UInt16 magic; - EndianAwareBinaryReader eabr = new EndianAwareBinaryReader(stream, littleendian); + byte[] minix_sb_sector = imagePlugin.ReadSector(2 + partitionOffset); - eabr.BaseStream.Seek(0x400 + 0x18 + offset, SeekOrigin.Begin); - magic = eabr.ReadUInt16(); + magic = BigEndianBitConverter.ToUInt16(minix_sb_sector, 0x018); if(magic == MINIX3_MAGIC || magic == MINIX3_CIGAM) { @@ -80,50 +75,49 @@ namespace FileSystemIDandChk.Plugins } else { - eabr.BaseStream.Seek(0x400 + 0x10 + offset, SeekOrigin.Begin); - magic = eabr.ReadUInt16(); + magic = BigEndianBitConverter.ToUInt16(minix_sb_sector, 0x010); switch(magic) { case MINIX_MAGIC: filenamesize = 14; minixVersion = "Minix V1 filesystem"; - littleendian = true; + BigEndianBitConverter.IsLittleEndian = true; break; case MINIX_MAGIC2: filenamesize = 30; minixVersion = "Minix V1 filesystem"; - littleendian = true; + BigEndianBitConverter.IsLittleEndian = true; break; case MINIX2_MAGIC: filenamesize = 14; minixVersion = "Minix V2 filesystem"; - littleendian = true; + BigEndianBitConverter.IsLittleEndian = true; break; case MINIX2_MAGIC2: filenamesize = 30; minixVersion = "Minix V2 filesystem"; - littleendian = true; + BigEndianBitConverter.IsLittleEndian = true; break; case MINIX_CIGAM: filenamesize = 14; minixVersion = "Minix V1 filesystem"; - littleendian = false; + BigEndianBitConverter.IsLittleEndian = false; break; case MINIX_CIGAM2: filenamesize = 30; minixVersion = "Minix V1 filesystem"; - littleendian = false; + BigEndianBitConverter.IsLittleEndian = false; break; case MINIX2_CIGAM: filenamesize = 14; minixVersion = "Minix V2 filesystem"; - littleendian = false; + BigEndianBitConverter.IsLittleEndian = false; break; case MINIX2_CIGAM2: filenamesize = 30; minixVersion = "Minix V2 filesystem"; - littleendian = false; + BigEndianBitConverter.IsLittleEndian = false; break; default: return; @@ -131,26 +125,23 @@ namespace FileSystemIDandChk.Plugins } } - eabr = new EndianAwareBinaryReader(stream, littleendian); - eabr.BaseStream.Seek(0x400 + offset, SeekOrigin.Begin); - if(minix3) { Minix3SuperBlock mnx_sb = new Minix3SuperBlock(); - mnx_sb.s_ninodes = eabr.ReadUInt32(); - mnx_sb.s_pad0 = eabr.ReadUInt16(); - mnx_sb.s_imap_blocks = eabr.ReadUInt16(); - mnx_sb.s_zmap_blocks = eabr.ReadUInt16(); - mnx_sb.s_firstdatazone = eabr.ReadUInt16(); - mnx_sb.s_log_zone_size = eabr.ReadUInt16(); - mnx_sb.s_pad1 = eabr.ReadUInt16(); - mnx_sb.s_max_size = eabr.ReadUInt32(); - mnx_sb.s_zones = eabr.ReadUInt32(); - mnx_sb.s_magic = eabr.ReadUInt16(); - mnx_sb.s_pad2 = eabr.ReadUInt16(); - mnx_sb.s_blocksize = eabr.ReadUInt16(); - mnx_sb.s_disk_version = eabr.ReadByte(); + 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(); @@ -168,16 +159,16 @@ namespace FileSystemIDandChk.Plugins { MinixSuperBlock mnx_sb = new MinixSuperBlock(); - mnx_sb.s_ninodes = eabr.ReadUInt16(); - mnx_sb.s_nzones = eabr.ReadUInt16(); - mnx_sb.s_imap_blocks = eabr.ReadUInt16(); - mnx_sb.s_zmap_blocks = eabr.ReadUInt16(); - mnx_sb.s_firstdatazone = eabr.ReadUInt16(); - mnx_sb.s_log_zone_size = eabr.ReadUInt16(); - mnx_sb.s_max_size = eabr.ReadUInt32(); - mnx_sb.s_magic = eabr.ReadUInt16(); - mnx_sb.s_state = eabr.ReadUInt16(); - mnx_sb.s_zones = eabr.ReadUInt32(); + 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(); diff --git a/FileSystemIDandChk/Plugins/NTFS.cs b/FileSystemIDandChk/Plugins/NTFS.cs index 2b1e93e96..47129e4a4 100644 --- a/FileSystemIDandChk/Plugins/NTFS.cs +++ b/FileSystemIDandChk/Plugins/NTFS.cs @@ -3,8 +3,6 @@ using System.IO; using System.Text; using FileSystemIDandChk; -// Information from Inside Macintosh - namespace FileSystemIDandChk.Plugins { class NTFS : Plugin @@ -15,42 +13,37 @@ namespace FileSystemIDandChk.Plugins base.PluginUUID = new Guid("33513B2C-1e6d-4d21-a660-0bbc789c3871"); } - public override bool Identify(FileStream stream, long offset) + 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; - BinaryReader br = new BinaryReader(stream); + byte[] ntfs_bpb = imagePlugin.ReadSector(0 + partitionOffset); - br.BaseStream.Seek(3 + offset, SeekOrigin.Begin); - eigth_bytes = br.ReadBytes(8); + Array.Copy(ntfs_bpb, 0x003, eigth_bytes, 0, 8); oem_name = StringHandlers.CToString(eigth_bytes); if(oem_name != "NTFS ") return false; - br.BaseStream.Seek(0x10 + offset, SeekOrigin.Begin); - fats_no = br.ReadByte(); + fats_no = ntfs_bpb[0x010]; if(fats_no != 0) return false; - br.BaseStream.Seek(0x16 + offset, SeekOrigin.Begin); - spfat = br.ReadUInt16(); + spfat = BitConverter.ToUInt16(ntfs_bpb, 0x016); if(spfat != 0) return false; - br.BaseStream.Seek(0x26 + offset, SeekOrigin.Begin); - signature1 = br.ReadByte(); + signature1 = ntfs_bpb[0x026]; if(signature1 != 0x80) return false; - br.BaseStream.Seek(0x1FE + offset, SeekOrigin.Begin); - signature2 = br.ReadUInt16(); + signature2 = BitConverter.ToUInt16(ntfs_bpb, 0x1FE); if(signature2 != 0xAA55) return false; @@ -58,52 +51,49 @@ namespace FileSystemIDandChk.Plugins return true; } - public override void GetInformation (FileStream stream, long offset, out string information) + public override void GetInformation (ImagePlugins.ImagePlugin imagePlugin, ulong partitionOffset, out string information) { information = ""; StringBuilder sb = new StringBuilder(); - BinaryReader br = new BinaryReader(stream); - - br.BaseStream.Seek(offset, SeekOrigin.Begin); + byte[] ntfs_bpb = imagePlugin.ReadSector(0 + partitionOffset); NTFS_BootBlock ntfs_bb = new NTFS_BootBlock(); byte[] oem_name = new byte[8]; - ntfs_bb.jmp1 = br.ReadByte(); - ntfs_bb.jmp2 = br.ReadUInt16(); - oem_name = br.ReadBytes(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 = br.ReadUInt16(); - ntfs_bb.spc = br.ReadByte(); - ntfs_bb.rsectors = br.ReadUInt16(); - ntfs_bb.fats_no = br.ReadByte(); - ntfs_bb.root_ent = br.ReadUInt16(); - ntfs_bb.sml_sectors = br.ReadUInt16(); - ntfs_bb.media = br.ReadByte(); - ntfs_bb.spfat = br.ReadUInt16(); - ntfs_bb.sptrk = br.ReadUInt16(); - ntfs_bb.heads = br.ReadUInt16(); - ntfs_bb.hsectors = br.ReadUInt32(); - ntfs_bb.big_sectors = br.ReadUInt32(); - ntfs_bb.drive_no = br.ReadByte(); - ntfs_bb.nt_flags = br.ReadByte(); - ntfs_bb.signature1 = br.ReadByte(); - ntfs_bb.dummy = br.ReadByte(); - ntfs_bb.sectors = br.ReadInt64(); - ntfs_bb.mft_lsn = br.ReadInt64(); - ntfs_bb.mftmirror_lsn = br.ReadInt64(); - ntfs_bb.mft_rc_clusters = br.ReadSByte(); - ntfs_bb.dummy2 = br.ReadByte(); - ntfs_bb.dummy3 = br.ReadUInt16(); - ntfs_bb.index_blk_cts = br.ReadSByte(); - ntfs_bb.dummy4 = br.ReadByte(); - ntfs_bb.dummy5 = br.ReadUInt16(); - ntfs_bb.serial_no = br.ReadUInt64(); - br.BaseStream.Seek(430, SeekOrigin.Current); - ntfs_bb.signature2 = br.ReadUInt16(); + 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(); @@ -144,40 +134,39 @@ namespace FileSystemIDandChk.Plugins private struct NTFS_BootBlock // Sector 0 { // BIOS Parameter Block - public byte jmp1; // Jump to boot code - public UInt16 jmp2; // ...; - public string OEMName; // OEM Name, 8 bytes, space-padded, must be "NTFS " - public UInt16 bps; // Bytes per sector - public byte spc; // Sectors per cluster - public UInt16 rsectors; // Reserved sectors, seems 0 - public byte fats_no; // Number of FATs... obviously, 0 - public UInt16 root_ent; // Number of entries on root directory... 0 - public UInt16 sml_sectors; // Sectors in volume... 0 - public byte media; // Media descriptor - public UInt16 spfat; // Sectors per FAT... 0 - public UInt16 sptrk; // Sectors per track, required to boot - public UInt16 heads; // Heads... required to boot - public UInt32 hsectors; // Hidden sectors before BPB - public UInt32 big_sectors; // Sectors in volume if > 65535... 0 - public byte drive_no; // Drive number - public byte nt_flags; // 0 - public byte signature1; // EPB signature, 0x80 - public byte dummy; // Alignment + 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; // Sectors on volume - public Int64 mft_lsn; // LSN of $MFT - public Int64 mftmirror_lsn; // LSN of $MFTMirror - public sbyte mft_rc_clusters; // Clusters per MFT record - public byte dummy2; // Alignment - public UInt16 dummy3; // Alignment - public sbyte index_blk_cts; // Clusters per index block - public byte dummy4; // Alignment - public UInt16 dummy5; // Alignment - public UInt64 serial_no; // Volume serial number - // End of NTFS superblock, followed by 426 bytes of boot code - public UInt16 signature2; // 0xAA55 + 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 } } } - diff --git a/FileSystemIDandChk/Plugins/ODS.cs b/FileSystemIDandChk/Plugins/ODS.cs index 889368ce2..05450ff6a 100644 --- a/FileSystemIDandChk/Plugins/ODS.cs +++ b/FileSystemIDandChk/Plugins/ODS.cs @@ -14,6 +14,8 @@ using FileSystemIDandChk; // Time is a 64 bit unsigned integer, tenths of microseconds since 1858/11/17 00:00:00. +// TODO: Implement checksum + namespace FileSystemIDandChk.Plugins { class ODS : Plugin @@ -24,17 +26,13 @@ namespace FileSystemIDandChk.Plugins base.PluginUUID = new Guid("de20633c-8021-4384-aeb0-83b0df14491f"); } - public override bool Identify(FileStream stream, long offset) + public override bool Identify(ImagePlugins.ImagePlugin imagePlugin, ulong partitionOffset) { byte[] magic_b = new byte[12]; string magic; - - BinaryReader br = new BinaryReader(stream); - - br.BaseStream.Seek(0x200 + offset, SeekOrigin.Begin); // Seek to home block - br.BaseStream.Seek(0x1F0, SeekOrigin.Current); // Seek to format - - br.BaseStream.Read(magic_b, 0, 12); + byte[] hb_sector = imagePlugin.ReadSector(1 + partitionOffset); + + Array.Copy(hb_sector, 0x1F0, magic_b, 0, 12); magic = Encoding.ASCII.GetString(magic_b); if(magic == "DECFILE11A " || magic == "DECFILE11B ") @@ -43,70 +41,66 @@ namespace FileSystemIDandChk.Plugins return false; } - public override void GetInformation (FileStream stream, long offset, out string information) + public override void GetInformation (ImagePlugins.ImagePlugin imagePlugin, ulong partitionOffset, out string information) { information = ""; StringBuilder sb = new StringBuilder(); - BinaryReader br = new BinaryReader(stream); ODSHomeBlock homeblock = new ODSHomeBlock(); byte[] temp_string = new byte[12]; homeblock.min_class = new byte[20]; homeblock.max_class = new byte[20]; - homeblock.reserved1 = new byte[302]; - br.BaseStream.Seek(0x200 + offset, SeekOrigin.Begin); + byte[] hb_sector = imagePlugin.ReadSector(1 + partitionOffset); - homeblock.homelbn = br.ReadUInt32(); - homeblock.alhomelbn = br.ReadUInt32(); - homeblock.altidxlbn = br.ReadUInt32(); - homeblock.struclev = br.ReadUInt16(); - homeblock.cluster = br.ReadUInt16(); - homeblock.homevbn = br.ReadUInt16(); - homeblock.alhomevbn = br.ReadUInt16(); - homeblock.altidxvbn = br.ReadUInt16(); - homeblock.ibmapvbn = br.ReadUInt16(); - homeblock.ibmaplbn = br.ReadUInt32(); - homeblock.maxfiles = br.ReadUInt32(); - homeblock.ibmapsize = br.ReadUInt16(); - homeblock.resfiles = br.ReadUInt16(); - homeblock.devtype = br.ReadUInt16(); - homeblock.rvn = br.ReadUInt16(); - homeblock.setcount = br.ReadUInt16(); - homeblock.volchar = br.ReadUInt16(); - homeblock.volowner = br.ReadUInt32(); - homeblock.sec_mask = br.ReadUInt32(); - homeblock.protect = br.ReadUInt16(); - homeblock.fileprot = br.ReadUInt16(); - homeblock.recprot = br.ReadUInt16(); - homeblock.checksum1 = br.ReadUInt16(); - homeblock.credate = br.ReadUInt64(); - homeblock.window = br.ReadByte(); - homeblock.lru_lim = br.ReadByte(); - homeblock.extend = br.ReadUInt16(); - homeblock.retainmin = br.ReadUInt64(); - homeblock.retainmax = br.ReadUInt64(); - homeblock.revdate = br.ReadUInt64(); - homeblock.min_class = br.ReadBytes(20); - homeblock.max_class = br.ReadBytes(20); - homeblock.filetab_fid1 = br.ReadUInt16(); - homeblock.filetab_fid2 = br.ReadUInt16(); - homeblock.filetab_fid3 = br.ReadUInt16(); - homeblock.lowstruclev = br.ReadUInt16(); - homeblock.highstruclev = br.ReadUInt16(); - homeblock.copydate = br.ReadUInt64(); - homeblock.reserved1 = br.ReadBytes(302); - homeblock.serialnum = br.ReadUInt32(); - temp_string = br.ReadBytes(12); + 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); - temp_string = br.ReadBytes(12); + Array.Copy(hb_sector, 0x1D8, temp_string, 0, 12); homeblock.volname = StringHandlers.CToString(temp_string); - temp_string = br.ReadBytes(12); + Array.Copy(hb_sector, 0x1E4, temp_string, 0, 12); homeblock.ownername = StringHandlers.CToString(temp_string); - temp_string = br.ReadBytes(12); + Array.Copy(hb_sector, 0x1F0, temp_string, 0, 12); homeblock.format = StringHandlers.CToString(temp_string); - homeblock.reserved2 = br.ReadUInt16(); - homeblock.checksum2 = br.ReadUInt16(); + 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."); @@ -233,53 +227,52 @@ namespace FileSystemIDandChk.Plugins private struct ODSHomeBlock { - public UInt32 homelbn; // LBN of THIS home block - public UInt32 alhomelbn; // LBN of the secondary home block - public UInt32 altidxlbn; // LBN of backup INDEXF.SYS;1 - public UInt16 struclev; // High byte contains filesystem version (1, 2 or 5), low byte contains revision (1) - public UInt16 cluster; // Number of blocks each bit of the volume bitmap represents - public UInt16 homevbn; // VBN of THIS home block - public UInt16 alhomevbn; // VBN of the secondary home block - public UInt16 altidxvbn; // VBN of backup INDEXF.SYS;1 - public UInt16 ibmapvbn; // VBN of the bitmap - public UInt32 ibmaplbn; // LBN of the bitmap - public UInt32 maxfiles; // Max files on volume - public UInt16 ibmapsize; // Bitmap size in sectors - public UInt16 resfiles; // Reserved files, 5 at minimum - public UInt16 devtype; // Device type, ODS-2 defines it as always 0 - public UInt16 rvn; // Relative volume number (number of the volume in a set) - public UInt16 setcount; // Total number of volumes in the set this volume is - public UInt16 volchar; // Flags - public UInt32 volowner; // User ID of the volume owner - public UInt32 sec_mask; // Security mask (??) - public UInt16 protect; // Volume permissions (system, owner, group and other) - public UInt16 fileprot; // Default file protection, unsupported in ODS-2 - public UInt16 recprot; // Default file record protection - public UInt16 checksum1; // Checksum of all preceding entries - public UInt64 credate; // Creation date - public byte window; // Window size (pointers for the window) - public byte lru_lim; // Directories to be stored in cache - public UInt16 extend; // Default allocation size in blocks - public UInt64 retainmin; // Minimum file retention period - public UInt64 retainmax; // Maximum file retention period - public UInt64 revdate; // Last modification date - public byte[] min_class; // Minimum security class, 20 bytes - public byte[] max_class; // Maximum security class, 20 bytes - public UInt16 filetab_fid1; // File lookup table FID - public UInt16 filetab_fid2; // File lookup table FID - public UInt16 filetab_fid3; // File lookup table FID - public UInt16 lowstruclev; // Lowest structure level on the volume - public UInt16 highstruclev; // Highest structure level on the volume - public UInt64 copydate; // Volume copy date (??) - public byte[] reserved1; // 302 bytes - public UInt32 serialnum; // Physical drive serial number - public string strucname; // Name of the volume set, 12 bytes - public string volname; // Volume label, 12 bytes - public string ownername; // Name of the volume owner, 12 bytes - public string format; // ODS-2 defines it as "DECFILE11B", 12 bytes - public UInt16 reserved2; // Reserved - public UInt16 checksum2; // Checksum of preceding 255 words (16 bit units) + 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) } } -} - +} \ No newline at end of file diff --git a/FileSystemIDandChk/Plugins/Opera.cs b/FileSystemIDandChk/Plugins/Opera.cs index 25722638a..ff7bf6a6e 100644 --- a/FileSystemIDandChk/Plugins/Opera.cs +++ b/FileSystemIDandChk/Plugins/Opera.cs @@ -3,7 +3,6 @@ using System.IO; using System.Text; using FileSystemIDandChk; -// Information from Inside Macintosh namespace FileSystemIDandChk.Plugins { @@ -15,17 +14,17 @@ namespace FileSystemIDandChk.Plugins base.PluginUUID = new Guid("0ec84ec7-eae6-4196-83fe-943b3fe46dbd"); } - public override bool Identify(FileStream fileStream, long offset) + public override bool Identify(ImagePlugins.ImagePlugin imagePlugin, ulong partitionOffset) { - fileStream.Seek(0 + offset, SeekOrigin.Begin); + byte[] sb_sector = imagePlugin.ReadSector(0 + partitionOffset); byte record_type; byte[] sync_bytes = new byte[5]; byte record_version; - record_type = (byte)fileStream.ReadByte(); - fileStream.Read(sync_bytes, 0, 5); - record_version = (byte)fileStream.ReadByte(); + 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; @@ -35,32 +34,32 @@ namespace FileSystemIDandChk.Plugins return true; } - public override void GetInformation (FileStream fileStream, long offset, out string information) + public override void GetInformation (ImagePlugins.ImagePlugin imagePlugin, ulong partitionOffset, out string information) { information = ""; StringBuilder SuperBlockMetadata = new StringBuilder(); - fileStream.Seek(0 + offset, SeekOrigin.Begin); + byte[] sb_sector = imagePlugin.ReadSector(0 + partitionOffset); - EndianAwareBinaryReader eabr = new EndianAwareBinaryReader(fileStream, false); // BigEndian OperaSuperBlock sb = new OperaSuperBlock(); - byte[] cString; + byte[] cString = new byte[32]; + sb.sync_bytes = new byte[5]; - sb.record_type = eabr.ReadByte(); - sb.sync_bytes = eabr.ReadBytes(5); - sb.record_version = eabr.ReadByte(); - sb.volume_flags = eabr.ReadByte(); - cString = eabr.ReadBytes(32); + 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); - cString = eabr.ReadBytes(32); + Array.Copy(sb_sector, 0x028, cString, 0, 32); sb.volume_label = StringHandlers.CToString(cString); - sb.volume_id = eabr.ReadInt32(); - sb.block_size = eabr.ReadInt32(); - sb.block_count = eabr.ReadInt32(); - sb.root_dirid = eabr.ReadInt32(); - sb.rootdir_blocks = eabr.ReadInt32(); - sb.rootdir_bsize = eabr.ReadInt32(); - sb.last_root_copy = eabr.ReadInt32(); + 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; @@ -78,7 +77,16 @@ namespace FileSystemIDandChk.Plugins 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(); @@ -89,20 +97,19 @@ namespace FileSystemIDandChk.Plugins private struct OperaSuperBlock { - public byte record_type; // Record type, must be 1 - public byte[] sync_bytes; // 5 bytes, "ZZZZZ" = new byte[5]; - public byte record_version; // Record version, must be 1 - public byte volume_flags; // Volume flags - public string volume_comment; // 32 bytes, volume comment - public string volume_label; // 32 bytes, volume label - public Int32 volume_id; // Volume ID - public Int32 block_size; // Block size in bytes - public Int32 block_count; // Blocks in volume - public Int32 root_dirid; // Root directory ID - public Int32 rootdir_blocks; // Root directory blocks - public Int32 rootdir_bsize; // Root directory block size - public Int32 last_root_copy; // Last root directory copy + 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 } } -} - +} \ No newline at end of file diff --git a/FileSystemIDandChk/Plugins/PCEngine.cs b/FileSystemIDandChk/Plugins/PCEngine.cs index eea17d365..749d4a274 100644 --- a/FileSystemIDandChk/Plugins/PCEngine.cs +++ b/FileSystemIDandChk/Plugins/PCEngine.cs @@ -3,8 +3,6 @@ using System.IO; using System.Text; using FileSystemIDandChk; -// Information from Inside Macintosh - namespace FileSystemIDandChk.Plugins { class PCEnginePlugin : Plugin @@ -15,13 +13,12 @@ namespace FileSystemIDandChk.Plugins base.PluginUUID = new Guid("e5ee6d7c-90fa-49bd-ac89-14ef750b8af3"); } - public override bool Identify(FileStream stream, long offset) + public override bool Identify(ImagePlugins.ImagePlugin imagePlugin, ulong partitionOffset) { byte[] system_descriptor = new byte[23]; + byte[] sector = imagePlugin.ReadSector(1 + partitionOffset); - stream.Seek(2080 + offset, SeekOrigin.Begin); - - stream.Read(system_descriptor, 0, 23); + Array.Copy(sector, 0x20, system_descriptor, 0, 23); if(Encoding.ASCII.GetString(system_descriptor) == "PC Engine CD-ROM SYSTEM") return true; @@ -29,10 +26,9 @@ namespace FileSystemIDandChk.Plugins return false; } - public override void GetInformation (FileStream stream, long offset, out string information) + public override void GetInformation (ImagePlugins.ImagePlugin imagePlugin, ulong partitionOffset, out string information) { information = ""; } } -} - +} \ No newline at end of file diff --git a/FileSystemIDandChk/Plugins/Plugin.cs b/FileSystemIDandChk/Plugins/Plugin.cs index adb9136ea..f49b4d5a2 100644 --- a/FileSystemIDandChk/Plugins/Plugin.cs +++ b/FileSystemIDandChk/Plugins/Plugin.cs @@ -12,8 +12,8 @@ namespace FileSystemIDandChk.Plugins { } - public abstract bool Identify(FileStream stream, long offset); - public abstract void GetInformation(FileStream stream, long offset, out string information); + public abstract bool Identify(ImagePlugins.ImagePlugin imagePlugin, ulong partitionOffset); + public abstract void GetInformation(ImagePlugins.ImagePlugin imagePlugin, ulong partitionOffset, out string information); } } diff --git a/FileSystemIDandChk/Plugins/SolarFS.cs b/FileSystemIDandChk/Plugins/SolarFS.cs index 45197987f..e88a278c6 100644 --- a/FileSystemIDandChk/Plugins/SolarFS.cs +++ b/FileSystemIDandChk/Plugins/SolarFS.cs @@ -4,7 +4,6 @@ using System.Text; using FileSystemIDandChk; // Based on FAT's BPB, cannot find a FAT or directory - namespace FileSystemIDandChk.Plugins { class SolarFS : Plugin @@ -15,17 +14,18 @@ namespace FileSystemIDandChk.Plugins base.PluginUUID = new Guid("EA3101C1-E777-4B4F-B5A3-8C57F50F6E65"); } - public override bool Identify(FileStream stream, long offset) + public override bool Identify(ImagePlugins.ImagePlugin imagePlugin, ulong partitionOffset) { byte signature; // 0x29 string fs_type; // "SOL_FS " - BinaryReader br = new BinaryReader(stream); + byte[] bpb = imagePlugin.ReadSector (0 + partitionOffset); - br.BaseStream.Seek(0x25 + offset, SeekOrigin.Begin); // FATs, 1 or 2, maybe 0, never bigger - signature = br.ReadByte(); - br.BaseStream.Seek(0x35 + offset, SeekOrigin.Begin); // Media Descriptor if present is in 0x15 - fs_type = StringHandlers.CToString(br.ReadBytes(8)); + 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; @@ -33,35 +33,44 @@ namespace FileSystemIDandChk.Plugins return false; } - public override void GetInformation (FileStream stream, long offset, out string information) + public override void GetInformation (ImagePlugins.ImagePlugin imagePlugin, ulong partitionOffset, out string information) { information = ""; StringBuilder sb = new StringBuilder(); - BinaryReader br = new BinaryReader(stream); + byte[] bpb_sector = imagePlugin.ReadSector(0 + partitionOffset); + byte[] bpb_strings; SolarOSParameterBlock BPB = new SolarOSParameterBlock(); - br.BaseStream.Seek(offset, SeekOrigin.Begin); - BPB.x86_jump = br.ReadBytes(3); - BPB.OEMName = StringHandlers.CToString(br.ReadBytes(8)); - BPB.bps = br.ReadUInt16(); - BPB.unk1 = br.ReadByte(); - BPB.unk2 = br.ReadUInt16(); - BPB.root_ent = br.ReadUInt16(); - BPB.sectors = br.ReadUInt16(); - BPB.media = br.ReadByte(); - BPB.spfat = br.ReadUInt16(); - BPB.sptrk = br.ReadUInt16(); - BPB.heads = br.ReadUInt16(); - BPB.unk3 = br.ReadBytes(10); - BPB.signature = br.ReadByte(); - BPB.unk4 = br.ReadUInt32(); - BPB.vol_name = StringHandlers.CToString(br.ReadBytes(11)); - BPB.fs_type = StringHandlers.CToString(br.ReadBytes(8)); + 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); @@ -83,7 +92,21 @@ namespace FileSystemIDandChk.Plugins 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(); @@ -111,5 +134,4 @@ namespace FileSystemIDandChk.Plugins public string fs_type; // 0x35, 8 bytes, "SOL_FS " } } -} - +} \ No newline at end of file diff --git a/FileSystemIDandChk/Plugins/Symbian.cs b/FileSystemIDandChk/Plugins/Symbian.cs index 309f0f500..73157635c 100644 --- a/FileSystemIDandChk/Plugins/Symbian.cs +++ b/FileSystemIDandChk/Plugins/Symbian.cs @@ -5,6 +5,8 @@ using FileSystemIDandChk; using System.Collections.Generic; // Information from http://www.thoukydides.webspace.virginmedia.com/software/psifs/sis.html +// TODO: Implement support for disc images +/* namespace FileSystemIDandChk.Plugins { @@ -330,3 +332,4 @@ namespace FileSystemIDandChk.Plugins } } +*/ \ No newline at end of file diff --git a/FileSystemIDandChk/Plugins/SysV.cs b/FileSystemIDandChk/Plugins/SysV.cs index c5afea3ab..2cb5b9702 100644 --- a/FileSystemIDandChk/Plugins/SysV.cs +++ b/FileSystemIDandChk/Plugins/SysV.cs @@ -28,15 +28,13 @@ namespace FileSystemIDandChk.Plugins base.PluginUUID = new Guid("9B8D016A-8561-400E-A12A-A198283C211D"); } - public override bool Identify(FileStream stream, long offset) + public override bool Identify(ImagePlugins.ImagePlugin imagePlugin, ulong partitionOffset) { UInt32 magic; string s_fname, s_fpack; UInt16 s_nfree, s_ninode; UInt32 s_fsize; - BinaryReader br = new BinaryReader(stream); - /*for(int j = 0; j<=(br.BaseStream.Length/0x200); j++) { br.BaseStream.Seek(offset + j*0x200 + 0x1F8, SeekOrigin.Begin); // System V magic location @@ -57,37 +55,44 @@ namespace FileSystemIDandChk.Plugins Console.WriteLine("@{0:X8}: 0x{1:X8} ({1})", br.BaseStream.Position-offset-4, number); }*/ - for(int i = 0; i<=4; i++) // Check on 0x0000, 0x0200, 0x0600, 0x0800 + offset - { - if((ulong)br.BaseStream.Length <= (ulong)(offset + i*0x200 + 0x400)) // Stream must be bigger than SB location + SB size + offset - return false; + byte sb_size_in_sectors; - br.BaseStream.Seek(offset + i*0x200 + 0x3F8, SeekOrigin.Begin); // XENIX magic location - magic = br.ReadUInt32(); + 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; - br.BaseStream.Seek(offset + i*0x200 + 0x1F8, SeekOrigin.Begin); // System V magic location - magic = br.ReadUInt32(); + magic = BitConverter.ToUInt32(sb_sector, 0x1F8); // System V magic location if(magic == SYSV_MAGIC || magic == SYSV_CIGAM) return true; - br.BaseStream.Seek(offset + i*0x200 + 0x1E8, SeekOrigin.Begin); // Coherent UNIX s_fname location - s_fname = StringHandlers.CToString(br.ReadBytes(6)); - s_fpack = StringHandlers.CToString(br.ReadBytes(6)); + 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 - br.BaseStream.Seek(offset + i*0x200 + 0x002, SeekOrigin.Begin); - s_fsize = br.ReadUInt32(); - br.BaseStream.Seek(offset + i*0x200 + 0x006, SeekOrigin.Begin); - s_nfree = br.ReadUInt16(); - br.BaseStream.Seek(offset + i*0x200 + 0x0D0, SeekOrigin.Begin); - s_ninode = br.ReadUInt16(); + 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) { @@ -103,7 +108,7 @@ namespace FileSystemIDandChk.Plugins { if(s_fsize < V7_MAXSIZE && s_nfree < V7_NICFREE && s_ninode < V7_NICINOD) { - if((s_fsize * 1024) <= (br.BaseStream.Length-offset) || (s_fsize * 512) <= (br.BaseStream.Length-offset)) + if((s_fsize * 1024) <= (imagePlugin.GetSectors() * imagePlugin.GetSectorSize()) || (s_fsize * 512) <= (imagePlugin.GetSectors() * imagePlugin.GetSectorSize())) return true; } } @@ -113,13 +118,13 @@ namespace FileSystemIDandChk.Plugins return false; } - public override void GetInformation (FileStream stream, long offset, out string information) + public override void GetInformation (ImagePlugins.ImagePlugin imagePlugin, ulong partitionOffset, out string information) { information = ""; StringBuilder sb = new StringBuilder(); bool littleendian = true; - EndianAwareBinaryReader eabr = new EndianAwareBinaryReader(stream, littleendian); // Start in little endian until we know what are we handling here + BigEndianBitConverter.IsLittleEndian = true; // Start in little endian until we know what are we handling here int start; UInt32 magic; string s_fname, s_fpack; @@ -131,59 +136,65 @@ namespace FileSystemIDandChk.Plugins bool sysvr4 = false; bool sys7th = false; bool coherent = false; + byte[] sb_sector; + byte sb_size_in_sectors; - for(start = 0; start<=4; start++) // Check on 0x0000, 0x0200, 0x0600, 0x0800 + offset + 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++) { - eabr.BaseStream.Seek(offset + start*0x200 + 0x3F8, SeekOrigin.Begin); // XENIX magic location - magic = eabr.ReadUInt32(); + sb_sector = imagePlugin.ReadSectors((ulong)start + partitionOffset, sb_size_in_sectors); + magic = BigEndianBitConverter.ToUInt32(sb_sector, 0x3F8); // XENIX magic location if(magic == XENIX_MAGIC) { - littleendian = true; + BigEndianBitConverter.IsLittleEndian = true; // Little endian xenix = true; break; } else if(magic == XENIX_CIGAM) { - littleendian = false; + BigEndianBitConverter.IsLittleEndian = false; // Big endian xenix = true; break; } - eabr.BaseStream.Seek(offset + start*0x200 + 0x1F8, SeekOrigin.Begin); // System V magic location - magic = eabr.ReadUInt32(); + magic = BigEndianBitConverter.ToUInt32(sb_sector, 0x1F8); // XENIX magic location if(magic == SYSV_MAGIC) { - littleendian = true; + BigEndianBitConverter.IsLittleEndian = true; // Little endian sysv = true; break; } else if(magic == SYSV_CIGAM) { - littleendian = false; + BigEndianBitConverter.IsLittleEndian = false; // Big endian sysv = true; break; } - eabr.BaseStream.Seek(offset + start*0x200 + 0x1E8, SeekOrigin.Begin); // Coherent UNIX s_fname location - s_fname = StringHandlers.CToString(eabr.ReadBytes(6)); - s_fpack = StringHandlers.CToString(eabr.ReadBytes(6)); + 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) { - littleendian = true; // Coherent is in PDP endianness, use helper for that + BigEndianBitConverter.IsLittleEndian = true; // Coherent is in PDP endianness, use helper for that coherent = true; break; } // Now try to identify 7th edition - eabr.BaseStream.Seek(offset + start*0x200 + 0x002, SeekOrigin.Begin); - s_fsize = eabr.ReadUInt32(); - eabr.BaseStream.Seek(offset + start*0x200 + 0x006, SeekOrigin.Begin); - s_nfree = eabr.ReadUInt16(); - eabr.BaseStream.Seek(offset + start*0x200 + 0x0D0, SeekOrigin.Begin); - s_ninode = eabr.ReadUInt16(); + 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) { @@ -201,10 +212,10 @@ namespace FileSystemIDandChk.Plugins { if(s_fsize < V7_MAXSIZE && s_nfree < V7_NICFREE && s_ninode < V7_NICINOD) { - if((s_fsize * 1024) <= (eabr.BaseStream.Length-offset) || (s_fsize * 512) <= (eabr.BaseStream.Length-offset)) + if((s_fsize * 1024) <= (imagePlugin.GetSectors() * imagePlugin.GetSectorSize()) || (s_fsize * 512) <= (imagePlugin.GetSectors() * imagePlugin.GetSectorSize())) { sys7th = true; - littleendian = true; + BigEndianBitConverter.IsLittleEndian = true; break; } } @@ -216,32 +227,32 @@ namespace FileSystemIDandChk.Plugins if(xenix) { - eabr = new EndianAwareBinaryReader(stream, littleendian); + byte[] xenix_strings = new byte[6]; XenixSuperBlock xnx_sb = new XenixSuperBlock(); - eabr.BaseStream.Seek(offset + start*0x200, SeekOrigin.Begin); - xnx_sb.s_isize = eabr.ReadUInt16(); - xnx_sb.s_fsize = eabr.ReadUInt32(); - xnx_sb.s_nfree = eabr.ReadUInt16(); - eabr.BaseStream.Seek(400, SeekOrigin.Current); // Skip free block list - xnx_sb.s_ninode = eabr.ReadUInt16(); - eabr.BaseStream.Seek(200, SeekOrigin.Current); // Skip free inode list - xnx_sb.s_flock = eabr.ReadByte(); - xnx_sb.s_ilock = eabr.ReadByte(); - xnx_sb.s_fmod = eabr.ReadByte(); - xnx_sb.s_ronly = eabr.ReadByte(); - xnx_sb.s_time = eabr.ReadUInt32(); - xnx_sb.s_tfree = eabr.ReadUInt32(); - xnx_sb.s_tinode = eabr.ReadUInt16(); - xnx_sb.s_cylblks = eabr.ReadUInt16(); - xnx_sb.s_gapblks = eabr.ReadUInt16(); - xnx_sb.s_dinfo0 = eabr.ReadUInt16(); - xnx_sb.s_dinfo1 = eabr.ReadUInt16(); - xnx_sb.s_fname = StringHandlers.CToString(eabr.ReadBytes(6)); - xnx_sb.s_fpack = StringHandlers.CToString(eabr.ReadBytes(6)); - xnx_sb.s_clean = eabr.ReadByte(); - xnx_sb.s_magic = eabr.ReadUInt32(); - eabr.BaseStream.Seek(371, SeekOrigin.Current); // Skip fill zone - xnx_sb.s_type = eabr.ReadUInt32(); + 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"); @@ -262,6 +273,16 @@ namespace FileSystemIDandChk.Plugins 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(); @@ -289,17 +310,14 @@ namespace FileSystemIDandChk.Plugins if(sysv) { - eabr = new EndianAwareBinaryReader(stream, littleendian); + sb_sector = imagePlugin.ReadSectors((ulong)start + partitionOffset, sb_size_in_sectors); UInt16 pad0, pad1, pad2, pad3; + byte[] sysv_strings = new byte[6]; - eabr.BaseStream.Seek(offset + start*0x200 + 0x002, SeekOrigin.Begin); // First padding - pad0 = eabr.ReadUInt16(); - eabr.BaseStream.Seek(offset + start*0x200 + 0x00A, SeekOrigin.Begin); // Second padding - pad1 = eabr.ReadUInt16(); - eabr.BaseStream.Seek(offset + start*0x200 + 0x0D6, SeekOrigin.Begin); // Third padding - pad2 = eabr.ReadUInt16(); - eabr.BaseStream.Seek(offset + start*0x200 + 0x1B6, SeekOrigin.Begin); // Fourth padding - pad3 = eabr.ReadUInt16(); + pad0 = BigEndianBitConverter.ToUInt16(sb_sector, 0x002); // First padding + pad1 = BigEndianBitConverter.ToUInt16(sb_sector, 0x00A); // Second padding + pad2 = BigEndianBitConverter.ToUInt16(sb_sector, 0x0D6); // Third padding + pad3 = BigEndianBitConverter.ToUInt16(sb_sector, 0x1B6); // Fourth padding // This detection is not working as expected if(pad0 == 0 && pad1 == 0 && pad2 == 0) @@ -308,43 +326,55 @@ namespace FileSystemIDandChk.Plugins sysvr2 = true; SystemVRelease4SuperBlock sysv_sb = new SystemVRelease4SuperBlock(); - eabr.BaseStream.Seek(offset + start*0x200, SeekOrigin.Begin); - sysv_sb.s_isize = eabr.ReadUInt16(); - if(sysvr4) - eabr.BaseStream.Seek(2, SeekOrigin.Current); // Skip padding - sysv_sb.s_fsize = eabr.ReadUInt32(); - sysv_sb.s_nfree = eabr.ReadUInt16(); - if(sysvr4) - eabr.BaseStream.Seek(2, SeekOrigin.Current); // Skip padding - eabr.BaseStream.Seek(200, SeekOrigin.Current); // Skip free block list - sysv_sb.s_ninode = eabr.ReadUInt16(); - if(sysvr4) - eabr.BaseStream.Seek(2, SeekOrigin.Current); // Skip padding - eabr.BaseStream.Seek(200, SeekOrigin.Current); // Skip free inode list - sysv_sb.s_flock = eabr.ReadByte(); - sysv_sb.s_ilock = eabr.ReadByte(); - sysv_sb.s_fmod = eabr.ReadByte(); - sysv_sb.s_ronly = eabr.ReadByte(); - sysv_sb.s_time = eabr.ReadUInt32(); - sysv_sb.s_cylblks = eabr.ReadUInt16(); - sysv_sb.s_gapblks = eabr.ReadUInt16(); - sysv_sb.s_dinfo0 = eabr.ReadUInt16(); - sysv_sb.s_dinfo1 = eabr.ReadUInt16(); - sysv_sb.s_tfree = eabr.ReadUInt32(); - sysv_sb.s_tinode = eabr.ReadUInt16(); - if(sysvr4 && pad3 == 0) - eabr.BaseStream.Seek(2, SeekOrigin.Current); // Skip padding - sysv_sb.s_fname = StringHandlers.CToString(eabr.ReadBytes(6)); - sysv_sb.s_fpack = StringHandlers.CToString(eabr.ReadBytes(6)); - if(sysvr4 && pad3 == 0) - eabr.BaseStream.Seek(50, SeekOrigin.Current); // Skip fill zone - else if(sysvr4) - eabr.BaseStream.Seek(50, SeekOrigin.Current); // Skip fill zone - else - eabr.BaseStream.Seek(56, SeekOrigin.Current); // Skip fill zone - sysv_sb.s_state = eabr.ReadUInt32(); - sysv_sb.s_magic = eabr.ReadUInt32(); - sysv_sb.s_type = eabr.ReadUInt32(); + + // 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) @@ -368,6 +398,16 @@ namespace FileSystemIDandChk.Plugins 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(); @@ -395,28 +435,31 @@ namespace FileSystemIDandChk.Plugins if(coherent) { - eabr = new EndianAwareBinaryReader(stream, true); + sb_sector = imagePlugin.ReadSectors((ulong)start + partitionOffset, sb_size_in_sectors); CoherentSuperBlock coh_sb = new CoherentSuperBlock(); - eabr.BaseStream.Seek(offset + start*0x200, SeekOrigin.Begin); - coh_sb.s_isize = eabr.ReadUInt16(); - coh_sb.s_fsize = Swapping.PDPFromLittleEndian(eabr.ReadUInt32()); - coh_sb.s_nfree = eabr.ReadUInt16(); - eabr.BaseStream.Seek(256, SeekOrigin.Current); // Skip free block list - coh_sb.s_ninode = eabr.ReadUInt16(); - eabr.BaseStream.Seek(200, SeekOrigin.Current); // Skip free inode list - coh_sb.s_flock = eabr.ReadByte(); - coh_sb.s_ilock = eabr.ReadByte(); - coh_sb.s_fmod = eabr.ReadByte(); - coh_sb.s_ronly = eabr.ReadByte(); - coh_sb.s_time = Swapping.PDPFromLittleEndian(eabr.ReadUInt32()); - coh_sb.s_tfree = Swapping.PDPFromLittleEndian(eabr.ReadUInt32()); - coh_sb.s_tinode = eabr.ReadUInt16(); - coh_sb.s_int_m = eabr.ReadUInt16(); - coh_sb.s_int_n = eabr.ReadUInt16(); - coh_sb.s_fname = StringHandlers.CToString(eabr.ReadBytes(6)); - coh_sb.s_fpack = StringHandlers.CToString(eabr.ReadBytes(6)); + 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(); @@ -438,28 +481,31 @@ namespace FileSystemIDandChk.Plugins if(sys7th) { - eabr = new EndianAwareBinaryReader(stream, littleendian); - UNIX7thEditionSuperBlock v7_sb = new UNIX7thEditionSuperBlock(); - eabr.BaseStream.Seek(offset + start*0x200, SeekOrigin.Begin); - v7_sb.s_isize = eabr.ReadUInt16(); - v7_sb.s_fsize = eabr.ReadUInt32(); - v7_sb.s_nfree = eabr.ReadUInt16(); - eabr.BaseStream.Seek(200, SeekOrigin.Current); // Skip free block list - v7_sb.s_ninode = eabr.ReadUInt16(); - eabr.BaseStream.Seek(200, SeekOrigin.Current); // Skip free inode list - v7_sb.s_flock = eabr.ReadByte(); - v7_sb.s_ilock = eabr.ReadByte(); - v7_sb.s_fmod = eabr.ReadByte(); - v7_sb.s_ronly = eabr.ReadByte(); - v7_sb.s_time = eabr.ReadUInt32(); - v7_sb.s_tfree = eabr.ReadUInt32(); - v7_sb.s_tinode = eabr.ReadUInt16(); - v7_sb.s_int_m = eabr.ReadUInt16(); - v7_sb.s_int_n = eabr.ReadUInt16(); - v7_sb.s_fname = StringHandlers.CToString(eabr.ReadBytes(6)); - v7_sb.s_fpack = StringHandlers.CToString(eabr.ReadBytes(6)); + 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(); @@ -480,6 +526,8 @@ namespace FileSystemIDandChk.Plugins } information = sb.ToString(); + + BigEndianBitConverter.IsLittleEndian = false; // Return to default (bigendian) } private struct XenixSuperBlock @@ -620,5 +668,4 @@ namespace FileSystemIDandChk.Plugins public UInt32 s_unique; // 0x1F4, zero-filled } } -} - +} \ No newline at end of file diff --git a/FileSystemIDandChk/Plugins/UNIXBFS.cs b/FileSystemIDandChk/Plugins/UNIXBFS.cs index 7e0eaa358..19756e0b2 100644 --- a/FileSystemIDandChk/Plugins/UNIXBFS.cs +++ b/FileSystemIDandChk/Plugins/UNIXBFS.cs @@ -15,39 +15,39 @@ namespace FileSystemIDandChk.Plugins base.PluginUUID = new Guid("1E6E0DA6-F7E4-494C-80C6-CB5929E96155"); } - public override bool Identify(FileStream stream, long offset) + public override bool Identify(ImagePlugins.ImagePlugin imagePlugin, ulong partitionOffset) { UInt32 magic; - BinaryReader br = new BinaryReader(stream); - br.BaseStream.Seek(offset, SeekOrigin.Begin); + magic = BitConverter.ToUInt32 (imagePlugin.ReadSector (0 + partitionOffset), 0); - magic = br.ReadUInt32(); if(magic == BFS_MAGIC) return true; else return false; } - public override void GetInformation (FileStream stream, long offset, out string information) + public override void GetInformation (ImagePlugins.ImagePlugin imagePlugin, ulong partitionOffset, out string information) { information = ""; StringBuilder sb = new StringBuilder(); - BinaryReader br = new BinaryReader(stream); + byte[] bfs_sb_sector = imagePlugin.ReadSector (0 + partitionOffset); + byte[] sb_strings = new byte[6]; BFSSuperBlock bfs_sb = new BFSSuperBlock(); - br.BaseStream.Seek(offset, SeekOrigin.Begin); - bfs_sb.s_magic = br.ReadUInt32(); - bfs_sb.s_start = br.ReadUInt32(); - bfs_sb.s_end = br.ReadUInt32(); - bfs_sb.s_from = br.ReadUInt32(); - bfs_sb.s_to = br.ReadUInt32(); - bfs_sb.s_bfrom = br.ReadInt32(); - bfs_sb.s_bto = br.ReadInt32(); - bfs_sb.s_fsname = StringHandlers.CToString(br.ReadBytes(6)); - bfs_sb.s_volume = StringHandlers.CToString(br.ReadBytes(6)); + 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) { @@ -83,5 +83,4 @@ namespace FileSystemIDandChk.Plugins public string s_volume; // 0x22, 6 bytes, volume name } } -} - +} \ No newline at end of file diff --git a/FileSystemIDandChk/Plugins/ext2FS.cs b/FileSystemIDandChk/Plugins/ext2FS.cs index 060671404..2fa866d5b 100644 --- a/FileSystemIDandChk/Plugins/ext2FS.cs +++ b/FileSystemIDandChk/Plugins/ext2FS.cs @@ -3,8 +3,6 @@ using System.IO; using System.Text; using FileSystemIDandChk; -// Information from Inside Macintosh - namespace FileSystemIDandChk.Plugins { class ext2FS : Plugin @@ -15,14 +13,11 @@ namespace FileSystemIDandChk.Plugins base.PluginUUID = new Guid("6AA91B88-150B-4A7B-AD56-F84FB2DF4184"); } - public override bool Identify(FileStream stream, long offset) + public override bool Identify(ImagePlugins.ImagePlugin imagePlugin, ulong partitionOffset) { - byte[] magic_b = new byte[2]; - ushort magic; + byte[] sb_sector = imagePlugin.ReadSector (2 + partitionOffset); - stream.Seek(0x400 + 56 + offset, SeekOrigin.Begin); // Here should reside magic number - stream.Read(magic_b, 0, 2); - magic = BitConverter.ToUInt16(magic_b, 0); + UInt16 magic = BitConverter.ToUInt16(sb_sector, 0x038); if(magic == ext2FSMagic || magic == ext2OldFSMagic) return true; @@ -30,13 +25,12 @@ namespace FileSystemIDandChk.Plugins return false; } - public override void GetInformation (FileStream stream, long offset, out string information) + public override void GetInformation (ImagePlugins.ImagePlugin imagePlugin, ulong partitionOffset, out string information) { information = ""; StringBuilder sb = new StringBuilder(); - BinaryReader br = new BinaryReader(stream); ext2FSSuperBlock supblk = new ext2FSSuperBlock(); byte[] forstrings; bool old_ext2 = false; @@ -47,42 +41,54 @@ namespace FileSystemIDandChk.Plugins byte[] guid_a = new byte[16]; byte[] guid_b = new byte[16]; - br.BaseStream.Seek (0x400 + offset, SeekOrigin.Begin); - supblk.inodes = br.ReadUInt32(); - supblk.blocks = br.ReadUInt32(); - supblk.reserved_blocks = br.ReadUInt32(); - supblk.free_blocks = br.ReadUInt32(); - supblk.free_inodes = br.ReadUInt32(); - supblk.first_block = br.ReadUInt32(); - supblk.block_size = br.ReadUInt32(); - supblk.frag_size = br.ReadInt32(); - supblk.blocks_per_grp = br.ReadUInt32(); - supblk.flags_per_grp = br.ReadUInt32(); - supblk.inodes_per_grp = br.ReadUInt32(); - supblk.mount_t = br.ReadUInt32(); - supblk.write_t = br.ReadUInt32(); - supblk.mount_c = br.ReadUInt16(); - supblk.max_mount_c = br.ReadInt16(); - supblk.magic = br.ReadUInt16(); - supblk.state = br.ReadUInt16(); - supblk.err_behaviour = br.ReadUInt16(); - supblk.minor_revision = br.ReadUInt16(); - supblk.check_t = br.ReadUInt32(); - supblk.check_inv = br.ReadUInt32(); + uint sb_size_in_sectors = 0; + + 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 = br.ReadUInt32(); - supblk.revision = br.ReadUInt32(); - supblk.default_uid = br.ReadUInt16(); - supblk.default_gid = br.ReadUInt16(); + 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 = br.ReadUInt32(); - supblk.inode_size = br.ReadUInt16(); - supblk.block_group_no = br.ReadUInt16(); - supblk.ftr_compat = br.ReadUInt32(); - supblk.ftr_incompat = br.ReadUInt32(); - supblk.ftr_ro_compat = br.ReadUInt32(); + 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 - guid_a = br.ReadBytes(16); + 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]; @@ -102,17 +108,17 @@ namespace FileSystemIDandChk.Plugins supblk.uuid = new Guid(guid_b); // End of volume UUID forstrings = new byte[16]; - forstrings = br.ReadBytes(16); + Array.Copy (sb_sector, 0x078, forstrings, 0, 16); supblk.volume_name = StringHandlers.CToString(forstrings); forstrings = new byte[64]; - forstrings = br.ReadBytes(64); + Array.Copy (sb_sector, 0x088, forstrings, 0, 64); supblk.last_mount_dir = StringHandlers.CToString(forstrings); - supblk.algo_usage_bmp = br.ReadUInt32(); - supblk.prealloc_blks = br.ReadByte(); - supblk.prealloc_dir_blks = br.ReadByte(); - supblk.rsrvd_gdt_blocks = br.ReadUInt16(); + 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 - guid_a = br.ReadBytes(16); + 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]; @@ -130,56 +136,53 @@ namespace FileSystemIDandChk.Plugins guid_b[14] = guid_a[14]; guid_b[15] = guid_a[15]; supblk.journal_uuid = new Guid(guid_b); - supblk.journal_inode = br.ReadUInt32(); - supblk.journal_dev = br.ReadUInt32(); - supblk.last_orphan = br.ReadUInt32(); - supblk.hash_seed_1 = br.ReadUInt32(); - supblk.hash_seed_2 = br.ReadUInt32(); - supblk.hash_seed_3 = br.ReadUInt32(); - supblk.hash_seed_4 = br.ReadUInt32(); - supblk.hash_version = br.ReadByte(); - supblk.jnl_backup_type = br.ReadByte(); - supblk.desc_grp_size = br.ReadUInt16(); - supblk.default_mnt_opts = br.ReadUInt32(); - supblk.first_meta_bg = br.ReadUInt32(); + 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 = br.ReadUInt32(); - br.BaseStream.Seek(68, SeekOrigin.Current); - supblk.blocks_hi = br.ReadUInt32(); - supblk.reserved_blocks_hi = br.ReadUInt32(); - supblk.free_blocks_hi = br.ReadUInt32(); - supblk.min_inode_size = br.ReadUInt16(); - supblk.rsv_inode_size = br.ReadUInt16(); - supblk.flags = br.ReadUInt32(); - supblk.raid_stride = br.ReadUInt16(); - supblk.mmp_interval = br.ReadUInt16(); - supblk.mmp_block = br.ReadUInt64(); - supblk.raid_stripe_width = br.ReadUInt32(); - supblk.flex_bg_grp_size = br.ReadByte(); - supblk.padding = br.ReadByte(); - supblk.padding2 = br.ReadUInt16(); - supblk.kbytes_written = br.ReadUInt64(); - supblk.snapshot_inum = br.ReadUInt32(); - supblk.snapshot_id = br.ReadUInt32(); - supblk.snapshot_blocks = br.ReadUInt64(); - supblk.snapshot_list = br.ReadUInt32(); - supblk.error_count = br.ReadUInt32(); - supblk.first_error_t = br.ReadUInt32(); - supblk.first_error_inode = br.ReadUInt32(); - supblk.first_error_block = br.ReadUInt64(); + 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]; - forstrings = br.ReadBytes(32); + Array.Copy (sb_sector, 0x1A0, forstrings, 0, 32); supblk.first_error_func = StringHandlers.CToString(forstrings); - supblk.first_error_line = br.ReadUInt32(); - supblk.last_error_t = br.ReadUInt32(); - supblk.last_error_inode = br.ReadUInt32(); - supblk.last_error_block = br.ReadUInt64(); + 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]; - forstrings = br.ReadBytes(32); + Array.Copy (sb_sector, 0x1C8, forstrings, 0, 32); supblk.last_error_func = StringHandlers.CToString(forstrings); - supblk.last_error_line = br.ReadUInt32(); forstrings = new byte[64]; - forstrings = br.ReadBytes(64); + Array.Copy (sb_sector, 0x1D8, forstrings, 0, 64); supblk.mount_options = StringHandlers.CToString(forstrings); if(supblk.magic == ext2OldFSMagic) @@ -558,102 +561,103 @@ namespace FileSystemIDandChk.Plugins public const UInt16 ext2FSMagic = 0xEF53; // Same for ext3 and ext4 public const UInt16 ext2OldFSMagic = 0xEF51; + // Size = 536 bytes public struct ext2FSSuperBlock { - public UInt32 inodes; // inodes on volume - public UInt32 blocks; // blocks on volume - public UInt32 reserved_blocks; // reserved blocks - public UInt32 free_blocks; // free blocks count - public UInt32 free_inodes; // free inodes count - public UInt32 first_block; // first data block - public UInt32 block_size; // block size - public Int32 frag_size; // fragment size - public UInt32 blocks_per_grp; // blocks per group - public UInt32 flags_per_grp; // fragments per group - public UInt32 inodes_per_grp; // inodes per group - public UInt32 mount_t; // last mount time - public UInt32 write_t; // last write time - public UInt16 mount_c; // mounts count - public Int16 max_mount_c; // max mounts - public UInt16 magic; // (little endian) - public UInt16 state; // filesystem state - public UInt16 err_behaviour; // behaviour on errors - public UInt16 minor_revision; // From 0.5b onward - public UInt32 check_t; // last check time - public UInt32 check_inv; // max time between checks + 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; // Creation OS - public UInt32 revision; // Revison level - public UInt16 default_uid; // Default UID for reserved blocks - public UInt16 default_gid; // Default GID for reserved blocks + 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; // First unreserved inode - public UInt16 inode_size; // inode size - public UInt16 block_group_no; // Block group number of THIS superblock - public UInt32 ftr_compat; // Compatible features set - public UInt32 ftr_incompat; // Incompatible features set + 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; // Read-only compatible features set + public UInt32 ftr_ro_compat; // 0x064, Read-only compatible features set // Found on Linux 2.1.132 - public Guid uuid; // 16 bytes, UUID - public string volume_name; // 16 bytes, volume name - public string last_mount_dir; // 64 bytes, where last mounted - public UInt32 algo_usage_bmp; // Usage bitmap algorithm, for compression - public byte prealloc_blks; // Block to try to preallocate - public byte prealloc_dir_blks; // Blocks to try to preallocate for directories - public UInt16 rsrvd_gdt_blocks; // Per-group desc for online growth + 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; // 16 bytes, UUID of journal superblock - public UInt32 journal_inode; // inode no. of journal file - public UInt32 journal_dev; // device no. of journal file - public UInt32 last_orphan; // Start of list of inodes to delete - public UInt32 hash_seed_1; // First byte of 128bit HTREE hash seed - public UInt32 hash_seed_2; // Second byte of 128bit HTREE hash seed - public UInt32 hash_seed_3; // Third byte of 128bit HTREE hash seed - public UInt32 hash_seed_4; // Fourth byte of 128bit HTREE hash seed - public byte hash_version; // Hash version - public byte jnl_backup_type; // Journal backup type - public UInt16 desc_grp_size; // Size of group descriptor - public UInt32 default_mnt_opts; // Default mount options - public UInt32 first_meta_bg; // First metablock block group + 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; // Filesystem creation time + 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; // High 32bits of blocks no. - public UInt32 reserved_blocks_hi; // High 32bits of reserved blocks no. - public UInt32 free_blocks_hi; // High 32bits of free blocks no. - public UInt16 min_inode_size; // inodes minimal size in bytes - public UInt16 rsv_inode_size; // Bytes reserved by new inodes - public UInt32 flags; // Flags - public UInt16 raid_stride; // RAID stride - public UInt16 mmp_interval; // Waiting seconds in MMP check - public UInt64 mmp_block; // Block for multi-mount protection - public UInt32 raid_stripe_width; // Blocks on all data disks (N*stride) - public byte flex_bg_grp_size; // FLEX_BG group size - public byte padding; - public UInt16 padding2; + 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; // Kibibytes written in volume lifetime - public UInt32 snapshot_inum; // Active snapshot inode number - public UInt32 snapshot_id; // Active snapshot sequential ID - public UInt64 snapshot_blocks; // Reserved blocks for active snapshot's future use - public UInt32 snapshot_list; // inode number of the on-disk start of the snapshot list + 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; // total registered filesystem errors - public UInt32 first_error_t; // time on first error - public UInt32 first_error_inode; // inode involved in first error - public UInt64 first_error_block; // block involved of first error - public string first_error_func; // 32 bytes, function where the error happened - public UInt32 first_error_line; // line number where error happened - public UInt32 last_error_t; // time of most recent error - public UInt32 last_error_inode; // inode involved in last error - public UInt32 last_error_line; // line number where error happened - public UInt64 last_error_block; // block involved of last error - public string last_error_func; // 32 bytes, function where the error happened - // End of optiona error-handling features - public string mount_options; // 64 bytes, last used mount options + 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 @@ -722,5 +726,4 @@ namespace FileSystemIDandChk.Plugins public const UInt32 EXT2_FLAGS_UNSIGNED_HASH = 0x00000002; // Unsigned dirhash in use public const UInt32 EXT2_FLAGS_TEST_FILESYS = 0x00000004; // Testing development code } -} - +} \ No newline at end of file diff --git a/FileSystemIDandChk/Plugins/extFS.cs b/FileSystemIDandChk/Plugins/extFS.cs index a6cb66eda..3718f7dcf 100644 --- a/FileSystemIDandChk/Plugins/extFS.cs +++ b/FileSystemIDandChk/Plugins/extFS.cs @@ -3,8 +3,6 @@ using System.IO; using System.Text; using FileSystemIDandChk; -// Information from Inside Macintosh - namespace FileSystemIDandChk.Plugins { class extFS : Plugin @@ -15,14 +13,11 @@ namespace FileSystemIDandChk.Plugins base.PluginUUID = new Guid("076CB3A2-08C2-4D69-BC8A-FCAA2E502BE2"); } - public override bool Identify(FileStream stream, long offset) + public override bool Identify(ImagePlugins.ImagePlugin imagePlugin, ulong partitionOffset) { - byte[] magic_b = new byte[2]; - ushort magic; + byte[] sb_sector = imagePlugin.ReadSector (2 + partitionOffset); // Superblock resides at 0x400 - stream.Seek(0x400 + 56 + offset, SeekOrigin.Begin); // Here should reside magic number - stream.Read(magic_b, 0, 2); - magic = BitConverter.ToUInt16(magic_b, 0); + UInt16 magic = BitConverter.ToUInt16(sb_sector, 0x038); // Here should reside magic number if(magic == extFSMagic) return true; @@ -30,25 +25,24 @@ namespace FileSystemIDandChk.Plugins return false; } - public override void GetInformation (FileStream stream, long offset, out string information) + public override void GetInformation (ImagePlugins.ImagePlugin imagePlugin, ulong partitionOffset, out string information) { information = ""; StringBuilder sb = new StringBuilder(); - BinaryReader br = new BinaryReader(stream); + byte[] sb_sector = imagePlugin.ReadSector (2 + partitionOffset); // Superblock resides at 0x400 extFSSuperBlock ext_sb = new extFSSuperBlock(); - br.BaseStream.Seek(0x400 + offset, SeekOrigin.Begin); - ext_sb.inodes = br.ReadUInt32(); - ext_sb.zones = br.ReadUInt32(); - ext_sb.firstfreeblk = br.ReadUInt32(); - ext_sb.freecountblk = br.ReadUInt32(); - ext_sb.firstfreeind = br.ReadUInt32(); - ext_sb.freecountind = br.ReadUInt32(); - ext_sb.firstdatazone = br.ReadUInt32(); - ext_sb.logzonesize = br.ReadUInt32(); - ext_sb.maxsize = br.ReadUInt32(); + 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); @@ -67,22 +61,21 @@ namespace FileSystemIDandChk.Plugins public struct extFSSuperBlock { - public UInt32 inodes; // inodes on volume - public UInt32 zones; // zones on volume - public UInt32 firstfreeblk; // first free block - public UInt32 freecountblk; // free blocks count - public UInt32 firstfreeind; // first free inode - public UInt32 freecountind; // free inodes count - public UInt32 firstdatazone; // first data zone - public UInt32 logzonesize; // log zone size - public UInt32 maxsize; // max zone size - public UInt32 reserved1; // reserved - public UInt32 reserved2; // reserved - public UInt32 reserved3; // reserved - public UInt32 reserved4; // reserved - public UInt32 reserved5; // reserved - public UInt16 magic; // 0x137D (little endian) + 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) } } -} - +} \ No newline at end of file