mirror of
https://github.com/aaru-dps/Aaru.Server.git
synced 2025-12-16 19:24:27 +00:00
REFACTOR: Final cleanup of DiscImageChef.Filesystems.
This commit is contained in:
@@ -45,6 +45,8 @@ namespace DiscImageChef.Filesystems
|
||||
// This may be missing fields, or not, I don't know russian so any help is appreciated
|
||||
public class AODOS : Filesystem
|
||||
{
|
||||
readonly byte[] AODOSIdentifier = {0x20, 0x41, 0x4F, 0x2D, 0x44, 0x4F, 0x53, 0x20};
|
||||
|
||||
public AODOS()
|
||||
{
|
||||
Name = "Alexander Osipov DOS file system";
|
||||
@@ -66,41 +68,6 @@ namespace DiscImageChef.Filesystems
|
||||
CurrentEncoding = Encoding.GetEncoding("koi8-r");
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct AODOS_BootBlock
|
||||
{
|
||||
/// <summary>
|
||||
/// A NOP opcode
|
||||
/// </summary>
|
||||
public byte nop;
|
||||
/// <summary>
|
||||
/// A branch to real bootloader
|
||||
/// </summary>
|
||||
public ushort branch;
|
||||
/// <summary>
|
||||
/// Unused
|
||||
/// </summary>
|
||||
public byte unused;
|
||||
/// <summary>
|
||||
/// " AO-DOS "
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] public byte[] identifier;
|
||||
/// <summary>
|
||||
/// Volume label
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)] public byte[] volumeLabel;
|
||||
/// <summary>
|
||||
/// How many files are present in disk
|
||||
/// </summary>
|
||||
public ushort files;
|
||||
/// <summary>
|
||||
/// How many sectors are used
|
||||
/// </summary>
|
||||
public ushort usedSectors;
|
||||
}
|
||||
|
||||
readonly byte[] AODOSIdentifier = {0x20, 0x41, 0x4F, 0x2D, 0x44, 0x4F, 0x53, 0x20};
|
||||
|
||||
public override bool Identify(ImagePlugin imagePlugin, Partition partition)
|
||||
{
|
||||
// Does AO-DOS support hard disks?
|
||||
@@ -122,8 +89,7 @@ namespace DiscImageChef.Filesystems
|
||||
return bb.identifier.SequenceEqual(AODOSIdentifier);
|
||||
}
|
||||
|
||||
public override void GetInformation(ImagePlugin imagePlugin, Partition partition,
|
||||
out string information)
|
||||
public override void GetInformation(ImagePlugin imagePlugin, Partition partition, out string information)
|
||||
{
|
||||
byte[] sector = imagePlugin.ReadSector(0);
|
||||
AODOS_BootBlock bb = new AODOS_BootBlock();
|
||||
@@ -216,5 +182,38 @@ namespace DiscImageChef.Filesystems
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct AODOS_BootBlock
|
||||
{
|
||||
/// <summary>
|
||||
/// A NOP opcode
|
||||
/// </summary>
|
||||
public byte nop;
|
||||
/// <summary>
|
||||
/// A branch to real bootloader
|
||||
/// </summary>
|
||||
public ushort branch;
|
||||
/// <summary>
|
||||
/// Unused
|
||||
/// </summary>
|
||||
public byte unused;
|
||||
/// <summary>
|
||||
/// " AO-DOS "
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] public byte[] identifier;
|
||||
/// <summary>
|
||||
/// Volume label
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)] public byte[] volumeLabel;
|
||||
/// <summary>
|
||||
/// How many files are present in disk
|
||||
/// </summary>
|
||||
public ushort files;
|
||||
/// <summary>
|
||||
/// How many sectors are used
|
||||
/// </summary>
|
||||
public ushort usedSectors;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -66,18 +66,6 @@ namespace DiscImageChef.Filesystems
|
||||
CurrentEncoding = Encoding.UTF8;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct ApfsContainerSuperBlock
|
||||
{
|
||||
public ulong unknown1; // Varies between copies of the superblock
|
||||
public ulong unknown2;
|
||||
public ulong unknown3; // Varies by 1 between copies of the superblock
|
||||
public ulong unknown4;
|
||||
public uint magic;
|
||||
public uint blockSize;
|
||||
public ulong containerBlocks;
|
||||
}
|
||||
|
||||
public override bool Identify(ImagePlugin imagePlugin, Partition partition)
|
||||
{
|
||||
if(partition.Start >= partition.End) return false;
|
||||
@@ -97,8 +85,7 @@ namespace DiscImageChef.Filesystems
|
||||
return nxSb.magic == APFS_CONTAINER_MAGIC;
|
||||
}
|
||||
|
||||
public override void GetInformation(ImagePlugin imagePlugin, Partition partition,
|
||||
out string information)
|
||||
public override void GetInformation(ImagePlugin imagePlugin, Partition partition, out string information)
|
||||
{
|
||||
StringBuilder sbInformation = new StringBuilder();
|
||||
XmlFsType = new FileSystemType();
|
||||
@@ -196,5 +183,17 @@ namespace DiscImageChef.Filesystems
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct ApfsContainerSuperBlock
|
||||
{
|
||||
public ulong unknown1; // Varies between copies of the superblock
|
||||
public ulong unknown2;
|
||||
public ulong unknown3; // Varies by 1 between copies of the superblock
|
||||
public ulong unknown4;
|
||||
public uint magic;
|
||||
public uint blockSize;
|
||||
public ulong containerBlocks;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -44,30 +44,39 @@ namespace DiscImageChef.Filesystems
|
||||
public class AcornADFS : Filesystem
|
||||
{
|
||||
/// <summary>
|
||||
/// Location for boot block, in bytes
|
||||
/// Location for boot block, in bytes
|
||||
/// </summary>
|
||||
const ulong BOOT_BLOCK_LOCATION = 0xC00;
|
||||
/// <summary>
|
||||
/// Size of boot block, in bytes
|
||||
/// Size of boot block, in bytes
|
||||
/// </summary>
|
||||
const uint BOOT_BLOCK_SIZE = 0x200;
|
||||
/// <summary>
|
||||
/// Location of new directory, in bytes
|
||||
/// Location of new directory, in bytes
|
||||
/// </summary>
|
||||
const ulong NEW_DIRECTORY_LOCATION = 0x400;
|
||||
/// <summary>
|
||||
/// Location of old directory, in bytes
|
||||
/// Location of old directory, in bytes
|
||||
/// </summary>
|
||||
const ulong OLD_DIRECTORY_LOCATION = 0x200;
|
||||
/// <summary>
|
||||
/// Size of old directory
|
||||
/// Size of old directory
|
||||
/// </summary>
|
||||
const uint OLD_DIRECTORY_SIZE = 1280;
|
||||
/// <summary>
|
||||
/// Size of new directory
|
||||
/// Size of new directory
|
||||
/// </summary>
|
||||
const uint NEW_DIRECTORY_SIZE = 2048;
|
||||
|
||||
/// <summary>
|
||||
/// New directory format magic number, "Nick"
|
||||
/// </summary>
|
||||
const uint NEW_DIR_MAGIC = 0x6B63694E;
|
||||
/// <summary>
|
||||
/// Old directory format magic number, "Hugo"
|
||||
/// </summary>
|
||||
const uint OLD_DIR_MAGIC = 0x6F677548;
|
||||
|
||||
public AcornADFS()
|
||||
{
|
||||
Name = "Acorn Advanced Disc Filing System";
|
||||
@@ -89,175 +98,6 @@ namespace DiscImageChef.Filesystems
|
||||
CurrentEncoding = encoding ?? Encoding.GetEncoding("iso-8859-1");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Boot block, used in hard disks and ADFS-F and higher.
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct BootBlock
|
||||
{
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x1C0)] public byte[] spare;
|
||||
public DiscRecord discRecord;
|
||||
public byte flags;
|
||||
public ushort startCylinder;
|
||||
public byte checksum;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disc record, used in hard disks and ADFS-E and higher.
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct DiscRecord
|
||||
{
|
||||
public byte log2secsize;
|
||||
public byte spt;
|
||||
public byte heads;
|
||||
public byte density;
|
||||
public byte idlen;
|
||||
public byte log2bpmb;
|
||||
public byte skew;
|
||||
public byte bootoption;
|
||||
public byte lowsector;
|
||||
public byte nzones;
|
||||
public ushort zone_spare;
|
||||
public uint root;
|
||||
public uint disc_size;
|
||||
public ushort disc_id;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)] public byte[] disc_name;
|
||||
public uint disc_type;
|
||||
public uint disc_size_high;
|
||||
public byte flags;
|
||||
public byte nzones_high;
|
||||
public uint format_version;
|
||||
public uint root_size;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] public byte[] reserved;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Free block map, sector 0, used in ADFS-S, ADFS-L, ADFS-M and ADFS-D
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct OldMapSector0
|
||||
{
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 82 * 3)] public byte[] freeStart;
|
||||
public byte reserved;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)] public byte[] name;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] public byte[] size;
|
||||
public byte checksum;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Free block map, sector 1, used in ADFS-S, ADFS-L, ADFS-M and ADFS-D
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct OldMapSector1
|
||||
{
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 82 * 3)] public byte[] freeStart;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)] public byte[] name;
|
||||
public ushort discId;
|
||||
public byte boot;
|
||||
public byte freeEnd;
|
||||
public byte checksum;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Free block map, sector 0, used in ADFS-E
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct NewMap
|
||||
{
|
||||
public byte zoneChecksum;
|
||||
public ushort freeLink;
|
||||
public byte crossChecksum;
|
||||
public DiscRecord discRecord;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Directory header, common to "old" and "new" directories
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct DirectoryHeader
|
||||
{
|
||||
public byte masterSequence;
|
||||
public uint magic;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// New directory format magic number, "Nick"
|
||||
/// </summary>
|
||||
const uint NEW_DIR_MAGIC = 0x6B63694E;
|
||||
/// <summary>
|
||||
/// Old directory format magic number, "Hugo"
|
||||
/// </summary>
|
||||
const uint OLD_DIR_MAGIC = 0x6F677548;
|
||||
|
||||
/// <summary>
|
||||
/// Directory header, common to "old" and "new" directories
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct DirectoryEntry
|
||||
{
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)] public byte[] name;
|
||||
public uint load;
|
||||
public uint exec;
|
||||
public uint length;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] public byte[] address;
|
||||
public byte atts;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Directory tail, new format
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct NewDirectoryTail
|
||||
{
|
||||
public byte lastMark;
|
||||
public ushort reserved;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] public byte[] parent;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 19)] public byte[] title;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)] public byte[] name;
|
||||
public byte endMasSeq;
|
||||
public uint magic;
|
||||
public byte checkByte;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Directory tail, old format
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct OldDirectoryTail
|
||||
{
|
||||
public byte lastMark;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)] public byte[] name;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] public byte[] parent;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 19)] public byte[] title;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 14)] public byte[] reserved;
|
||||
public byte endMasSeq;
|
||||
public uint magic;
|
||||
public byte checkByte;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Directory, old format
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct OldDirectory
|
||||
{
|
||||
public DirectoryHeader header;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 47)] public DirectoryEntry[] entries;
|
||||
public OldDirectoryTail tail;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Directory, new format
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct NewDirectory
|
||||
{
|
||||
public DirectoryHeader header;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 77)] public DirectoryEntry[] entries;
|
||||
public NewDirectoryTail tail;
|
||||
}
|
||||
|
||||
// TODO: BBC Master hard disks are untested...
|
||||
public override bool Identify(ImagePlugin imagePlugin, Partition partition)
|
||||
{
|
||||
@@ -277,12 +117,14 @@ namespace DiscImageChef.Filesystems
|
||||
sector = imagePlugin.ReadSector(0);
|
||||
byte oldChk0 = AcornMapChecksum(sector, 255);
|
||||
ptr = GCHandle.Alloc(sector, GCHandleType.Pinned);
|
||||
OldMapSector0 oldMap0 = (OldMapSector0)Marshal.PtrToStructure(ptr.AddrOfPinnedObject(), typeof(OldMapSector0));
|
||||
OldMapSector0 oldMap0 =
|
||||
(OldMapSector0)Marshal.PtrToStructure(ptr.AddrOfPinnedObject(), typeof(OldMapSector0));
|
||||
|
||||
sector = imagePlugin.ReadSector(1);
|
||||
byte oldChk1 = AcornMapChecksum(sector, 255);
|
||||
ptr = GCHandle.Alloc(sector, GCHandleType.Pinned);
|
||||
OldMapSector1 oldMap1 = (OldMapSector1)Marshal.PtrToStructure(ptr.AddrOfPinnedObject(), typeof(OldMapSector1));
|
||||
OldMapSector1 oldMap1 =
|
||||
(OldMapSector1)Marshal.PtrToStructure(ptr.AddrOfPinnedObject(), typeof(OldMapSector1));
|
||||
|
||||
DicConsole.DebugWriteLine("ADFS Plugin", "oldMap0.checksum = {0}", oldMap0.checksum);
|
||||
DicConsole.DebugWriteLine("ADFS Plugin", "oldChk0 = {0}", oldChk0);
|
||||
@@ -317,7 +159,8 @@ namespace DiscImageChef.Filesystems
|
||||
sector = tmp;
|
||||
}
|
||||
ptr = GCHandle.Alloc(sector, GCHandleType.Pinned);
|
||||
OldDirectory oldRoot = (OldDirectory)Marshal.PtrToStructure(ptr.AddrOfPinnedObject(), typeof(OldDirectory));
|
||||
OldDirectory oldRoot =
|
||||
(OldDirectory)Marshal.PtrToStructure(ptr.AddrOfPinnedObject(), typeof(OldDirectory));
|
||||
byte dirChk = AcornDirectoryChecksum(sector, (int)OLD_DIRECTORY_SIZE - 1);
|
||||
|
||||
DicConsole.DebugWriteLine("ADFS Plugin", "oldRoot.header.magic at 0x200 = {0}",
|
||||
@@ -421,8 +264,7 @@ namespace DiscImageChef.Filesystems
|
||||
// TODO: Find root directory on volumes with DiscRecord
|
||||
// TODO: Support big directories (ADFS-G?)
|
||||
// TODO: Find the real freemap on volumes with DiscRecord, as DiscRecord's discid may be empty but this one isn't
|
||||
public override void GetInformation(ImagePlugin imagePlugin, Partition partition,
|
||||
out string information)
|
||||
public override void GetInformation(ImagePlugin imagePlugin, Partition partition, out string information)
|
||||
{
|
||||
StringBuilder sbInformation = new StringBuilder();
|
||||
XmlFsType = new FileSystemType();
|
||||
@@ -440,12 +282,14 @@ namespace DiscImageChef.Filesystems
|
||||
sector = imagePlugin.ReadSector(0);
|
||||
byte oldChk0 = AcornMapChecksum(sector, 255);
|
||||
ptr = GCHandle.Alloc(sector, GCHandleType.Pinned);
|
||||
OldMapSector0 oldMap0 = (OldMapSector0)Marshal.PtrToStructure(ptr.AddrOfPinnedObject(), typeof(OldMapSector0));
|
||||
OldMapSector0 oldMap0 =
|
||||
(OldMapSector0)Marshal.PtrToStructure(ptr.AddrOfPinnedObject(), typeof(OldMapSector0));
|
||||
|
||||
sector = imagePlugin.ReadSector(1);
|
||||
byte oldChk1 = AcornMapChecksum(sector, 255);
|
||||
ptr = GCHandle.Alloc(sector, GCHandleType.Pinned);
|
||||
OldMapSector1 oldMap1 = (OldMapSector1)Marshal.PtrToStructure(ptr.AddrOfPinnedObject(), typeof(OldMapSector1));
|
||||
OldMapSector1 oldMap1 =
|
||||
(OldMapSector1)Marshal.PtrToStructure(ptr.AddrOfPinnedObject(), typeof(OldMapSector1));
|
||||
|
||||
// According to documentation map1 MUST start on sector 1. On ADFS-D it starts at 0x100, not on sector 1 (0x400)
|
||||
if(oldMap0.checksum == oldChk0 && oldMap1.checksum != oldChk1 && sector.Length >= 512)
|
||||
@@ -492,9 +336,11 @@ namespace DiscImageChef.Filesystems
|
||||
sector = tmp;
|
||||
}
|
||||
ptr = GCHandle.Alloc(sector, GCHandleType.Pinned);
|
||||
OldDirectory oldRoot = (OldDirectory)Marshal.PtrToStructure(ptr.AddrOfPinnedObject(), typeof(OldDirectory));
|
||||
OldDirectory oldRoot =
|
||||
(OldDirectory)Marshal.PtrToStructure(ptr.AddrOfPinnedObject(), typeof(OldDirectory));
|
||||
|
||||
if(oldRoot.header.magic == OLD_DIR_MAGIC && oldRoot.tail.magic == OLD_DIR_MAGIC) namebytes = oldRoot.tail.name;
|
||||
if(oldRoot.header.magic == OLD_DIR_MAGIC && oldRoot.tail.magic == OLD_DIR_MAGIC)
|
||||
namebytes = oldRoot.tail.name;
|
||||
else
|
||||
{
|
||||
// RISC OS says the old directory can't be in the new location, hard disks created by RISC OS 3.10 do that...
|
||||
@@ -514,7 +360,8 @@ namespace DiscImageChef.Filesystems
|
||||
oldRoot = (OldDirectory)Marshal.PtrToStructure(ptr.AddrOfPinnedObject(),
|
||||
typeof(OldDirectory));
|
||||
|
||||
if(oldRoot.header.magic == OLD_DIR_MAGIC && oldRoot.tail.magic == OLD_DIR_MAGIC) namebytes = oldRoot.tail.name;
|
||||
if(oldRoot.header.magic == OLD_DIR_MAGIC && oldRoot.tail.magic == OLD_DIR_MAGIC)
|
||||
namebytes = oldRoot.tail.name;
|
||||
else
|
||||
{
|
||||
sector = imagePlugin.ReadSectors(sbSector, sectorsToRead);
|
||||
@@ -526,9 +373,11 @@ namespace DiscImageChef.Filesystems
|
||||
sector = tmp;
|
||||
}
|
||||
ptr = GCHandle.Alloc(sector, GCHandleType.Pinned);
|
||||
NewDirectory newRoot = (NewDirectory)Marshal.PtrToStructure(ptr.AddrOfPinnedObject(),
|
||||
typeof(NewDirectory));
|
||||
if(newRoot.header.magic == NEW_DIR_MAGIC && newRoot.tail.magic == NEW_DIR_MAGIC) namebytes = newRoot.tail.title;
|
||||
NewDirectory newRoot =
|
||||
(NewDirectory)Marshal.PtrToStructure(ptr.AddrOfPinnedObject(),
|
||||
typeof(NewDirectory));
|
||||
if(newRoot.header.magic == NEW_DIR_MAGIC && newRoot.tail.magic == NEW_DIR_MAGIC)
|
||||
namebytes = newRoot.tail.title;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -798,5 +647,165 @@ namespace DiscImageChef.Filesystems
|
||||
|
||||
return (byte)(((sum & 0xFF000000) >> 24) ^ ((sum & 0xFF0000) >> 16) ^ ((sum & 0xFF00) >> 8) ^ (sum & 0xFF));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Boot block, used in hard disks and ADFS-F and higher.
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct BootBlock
|
||||
{
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x1C0)] public byte[] spare;
|
||||
public DiscRecord discRecord;
|
||||
public byte flags;
|
||||
public ushort startCylinder;
|
||||
public byte checksum;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disc record, used in hard disks and ADFS-E and higher.
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct DiscRecord
|
||||
{
|
||||
public byte log2secsize;
|
||||
public byte spt;
|
||||
public byte heads;
|
||||
public byte density;
|
||||
public byte idlen;
|
||||
public byte log2bpmb;
|
||||
public byte skew;
|
||||
public byte bootoption;
|
||||
public byte lowsector;
|
||||
public byte nzones;
|
||||
public ushort zone_spare;
|
||||
public uint root;
|
||||
public uint disc_size;
|
||||
public ushort disc_id;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)] public byte[] disc_name;
|
||||
public uint disc_type;
|
||||
public uint disc_size_high;
|
||||
public byte flags;
|
||||
public byte nzones_high;
|
||||
public uint format_version;
|
||||
public uint root_size;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] public byte[] reserved;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Free block map, sector 0, used in ADFS-S, ADFS-L, ADFS-M and ADFS-D
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct OldMapSector0
|
||||
{
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 82 * 3)] public byte[] freeStart;
|
||||
public byte reserved;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)] public byte[] name;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] public byte[] size;
|
||||
public byte checksum;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Free block map, sector 1, used in ADFS-S, ADFS-L, ADFS-M and ADFS-D
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct OldMapSector1
|
||||
{
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 82 * 3)] public byte[] freeStart;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)] public byte[] name;
|
||||
public ushort discId;
|
||||
public byte boot;
|
||||
public byte freeEnd;
|
||||
public byte checksum;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Free block map, sector 0, used in ADFS-E
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct NewMap
|
||||
{
|
||||
public byte zoneChecksum;
|
||||
public ushort freeLink;
|
||||
public byte crossChecksum;
|
||||
public DiscRecord discRecord;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Directory header, common to "old" and "new" directories
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct DirectoryHeader
|
||||
{
|
||||
public byte masterSequence;
|
||||
public uint magic;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Directory header, common to "old" and "new" directories
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct DirectoryEntry
|
||||
{
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)] public byte[] name;
|
||||
public uint load;
|
||||
public uint exec;
|
||||
public uint length;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] public byte[] address;
|
||||
public byte atts;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Directory tail, new format
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct NewDirectoryTail
|
||||
{
|
||||
public byte lastMark;
|
||||
public ushort reserved;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] public byte[] parent;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 19)] public byte[] title;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)] public byte[] name;
|
||||
public byte endMasSeq;
|
||||
public uint magic;
|
||||
public byte checkByte;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Directory tail, old format
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct OldDirectoryTail
|
||||
{
|
||||
public byte lastMark;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)] public byte[] name;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] public byte[] parent;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 19)] public byte[] title;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 14)] public byte[] reserved;
|
||||
public byte endMasSeq;
|
||||
public uint magic;
|
||||
public byte checkByte;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Directory, old format
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct OldDirectory
|
||||
{
|
||||
public DirectoryHeader header;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 47)] public DirectoryEntry[] entries;
|
||||
public OldDirectoryTail tail;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Directory, new format
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct NewDirectory
|
||||
{
|
||||
public DirectoryHeader header;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 77)] public DirectoryEntry[] entries;
|
||||
public NewDirectoryTail tail;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -45,6 +45,12 @@ namespace DiscImageChef.Filesystems
|
||||
{
|
||||
public class AmigaDOSPlugin : Filesystem
|
||||
{
|
||||
const uint FFS_MASK = 0x444F5300;
|
||||
const uint MUFS_MASK = 0x6D754600;
|
||||
|
||||
const uint TYPE_HEADER = 2;
|
||||
const uint SUBTYPE_ROOT = 1;
|
||||
|
||||
public AmigaDOSPlugin()
|
||||
{
|
||||
Name = "Amiga DOS filesystem";
|
||||
@@ -66,150 +72,6 @@ namespace DiscImageChef.Filesystems
|
||||
CurrentEncoding = encoding ?? Encoding.GetEncoding("iso-8859-1");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Boot block, first 2 sectors
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct BootBlock
|
||||
{
|
||||
/// <summary>
|
||||
/// Offset 0x00, "DOSx" disk type
|
||||
/// </summary>
|
||||
public uint diskType;
|
||||
/// <summary>
|
||||
/// Offset 0x04, Checksum
|
||||
/// </summary>
|
||||
public uint checksum;
|
||||
/// <summary>
|
||||
/// Offset 0x08, Pointer to root block, mostly invalid
|
||||
/// </summary>
|
||||
public uint root_ptr;
|
||||
/// <summary>
|
||||
/// Offset 0x0C, Boot code, til completion. Size is intentionally incorrect to allow marshaling to work.
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)] public byte[] bootCode;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct RootBlock
|
||||
{
|
||||
/// <summary>
|
||||
/// Offset 0x00, block type, value = T_HEADER (2)
|
||||
/// </summary>
|
||||
public uint type;
|
||||
/// <summary>
|
||||
/// Offset 0x04, unused
|
||||
/// </summary>
|
||||
public uint headerKey;
|
||||
/// <summary>
|
||||
/// Offset 0x08, unused
|
||||
/// </summary>
|
||||
public uint highSeq;
|
||||
/// <summary>
|
||||
/// Offset 0x0C, longs used by hash table
|
||||
/// </summary>
|
||||
public uint hashTableSize;
|
||||
/// <summary>
|
||||
/// Offset 0x10, unused
|
||||
/// </summary>
|
||||
public uint firstData;
|
||||
/// <summary>
|
||||
/// Offset 0x14, Rootblock checksum
|
||||
/// </summary>
|
||||
public uint checksum;
|
||||
/// <summary>
|
||||
/// Offset 0x18, Hashtable, size = (block size / 4) - 56 or size = hashTableSize.
|
||||
/// Size intentionally bad to allow marshalling to work.
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)] public uint[] hashTable;
|
||||
/// <summary>
|
||||
/// Offset 0x18+hashTableSize*4+0, bitmap flag, 0xFFFFFFFF if valid
|
||||
/// </summary>
|
||||
public uint bitmapFlag;
|
||||
/// <summary>
|
||||
/// Offset 0x18+hashTableSize*4+4, bitmap pages, 25 entries
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 25)] public uint[] bitmapPages;
|
||||
/// <summary>
|
||||
/// Offset 0x18+hashTableSize*4+104, pointer to bitmap extension block
|
||||
/// </summary>
|
||||
public uint bitmapExtensionBlock;
|
||||
/// <summary>
|
||||
/// Offset 0x18+hashTableSize*4+108, last root alteration days since 1978/01/01
|
||||
/// </summary>
|
||||
public uint rDays;
|
||||
/// <summary>
|
||||
/// Offset 0x18+hashTableSize*4+112, last root alteration minutes past midnight
|
||||
/// </summary>
|
||||
public uint rMins;
|
||||
/// <summary>
|
||||
/// Offset 0x18+hashTableSize*4+116, last root alteration ticks (1/50 secs)
|
||||
/// </summary>
|
||||
public uint rTicks;
|
||||
/// <summary>
|
||||
/// Offset 0x18+hashTableSize*4+120, disk name, pascal string, 31 bytes
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 31)] public byte[] diskName;
|
||||
/// <summary>
|
||||
/// Offset 0x18+hashTableSize*4+151, unused
|
||||
/// </summary>
|
||||
public byte padding;
|
||||
/// <summary>
|
||||
/// Offset 0x18+hashTableSize*4+152, unused
|
||||
/// </summary>
|
||||
public uint reserved1;
|
||||
/// <summary>
|
||||
/// Offset 0x18+hashTableSize*4+156, unused
|
||||
/// </summary>
|
||||
public uint reserved2;
|
||||
/// <summary>
|
||||
/// Offset 0x18+hashTableSize*4+160, last disk alteration days since 1978/01/01
|
||||
/// </summary>
|
||||
public uint vDays;
|
||||
/// <summary>
|
||||
/// Offset 0x18+hashTableSize*4+164, last disk alteration minutes past midnight
|
||||
/// </summary>
|
||||
public uint vMins;
|
||||
/// <summary>
|
||||
/// Offset 0x18+hashTableSize*4+168, last disk alteration ticks (1/50 secs)
|
||||
/// </summary>
|
||||
public uint vTicks;
|
||||
/// <summary>
|
||||
/// Offset 0x18+hashTableSize*4+172, filesystem creation days since 1978/01/01
|
||||
/// </summary>
|
||||
public uint cDays;
|
||||
/// <summary>
|
||||
/// Offset 0x18+hashTableSize*4+176, filesystem creation minutes since 1978/01/01
|
||||
/// </summary>
|
||||
public uint cMins;
|
||||
/// <summary>
|
||||
/// Offset 0x18+hashTableSize*4+180, filesystem creation ticks since 1978/01/01
|
||||
/// </summary>
|
||||
public uint cTicks;
|
||||
/// <summary>
|
||||
/// Offset 0x18+hashTableSize*4+184, unused
|
||||
/// </summary>
|
||||
public uint nextHash;
|
||||
/// <summary>
|
||||
/// Offset 0x18+hashTableSize*4+188, unused
|
||||
/// </summary>
|
||||
public uint parentDir;
|
||||
/// <summary>
|
||||
/// Offset 0x18+hashTableSize*4+192, first directory cache block
|
||||
/// </summary>
|
||||
public uint extension;
|
||||
/// <summary>
|
||||
/// Offset 0x18+hashTableSize*4+196, block secondary type = ST_ROOT (1)
|
||||
/// </summary>
|
||||
public uint sec_type;
|
||||
}
|
||||
|
||||
const uint FFS_MASK = 0x444F5300;
|
||||
const uint MUFS_MASK = 0x6D754600;
|
||||
|
||||
const uint TYPE_HEADER = 2;
|
||||
const uint SUBTYPE_ROOT = 1;
|
||||
|
||||
public override bool Identify(ImagePlugin imagePlugin, Partition partition)
|
||||
{
|
||||
if(partition.Start >= partition.End) return false;
|
||||
@@ -263,7 +125,8 @@ namespace DiscImageChef.Filesystems
|
||||
RootBlock rblk = new RootBlock();
|
||||
|
||||
// So to handle even number of sectors
|
||||
foreach(ulong rootPtr in rootPtrs.Where(rootPtr => rootPtr < partition.End && rootPtr >= partition.Start)) {
|
||||
foreach(ulong rootPtr in rootPtrs.Where(rootPtr => rootPtr < partition.End && rootPtr >= partition.Start))
|
||||
{
|
||||
DicConsole.DebugWriteLine("AmigaDOS plugin", "Searching for Rootblock in sector {0}", rootPtr);
|
||||
|
||||
sector = imagePlugin.ReadSector(rootPtr);
|
||||
@@ -305,8 +168,7 @@ namespace DiscImageChef.Filesystems
|
||||
return false;
|
||||
}
|
||||
|
||||
public override void GetInformation(ImagePlugin imagePlugin, Partition partition,
|
||||
out string information)
|
||||
public override void GetInformation(ImagePlugin imagePlugin, Partition partition, out string information)
|
||||
{
|
||||
StringBuilder sbInformation = new StringBuilder();
|
||||
XmlFsType = new FileSystemType();
|
||||
@@ -345,7 +207,8 @@ namespace DiscImageChef.Filesystems
|
||||
uint blockSize = 0;
|
||||
|
||||
// So to handle even number of sectors
|
||||
foreach(ulong rootPtr in rootPtrs.Where(rootPtr => rootPtr < partition.End && rootPtr >= partition.Start)) {
|
||||
foreach(ulong rootPtr in rootPtrs.Where(rootPtr => rootPtr < partition.End && rootPtr >= partition.Start))
|
||||
{
|
||||
DicConsole.DebugWriteLine("AmigaDOS plugin", "Searching for Rootblock in sector {0}", rootPtr);
|
||||
|
||||
rootBlockSector = imagePlugin.ReadSector(rootPtr);
|
||||
@@ -453,8 +316,7 @@ namespace DiscImageChef.Filesystems
|
||||
if((bootBlk.diskType & 0xFF) == 4 || (bootBlk.diskType & 0xFF) == 5)
|
||||
sbInformation.AppendFormat("Directory cache starts at block {0}", rootBlk.extension).AppendLine();
|
||||
|
||||
long blocks = (long)((partition.End - partition.Start + 1) * imagePlugin.ImageInfo.SectorSize /
|
||||
blockSize);
|
||||
long blocks = (long)((partition.End - partition.Start + 1) * imagePlugin.ImageInfo.SectorSize / blockSize);
|
||||
|
||||
sbInformation.AppendFormat("Volume block size is {0} bytes", blockSize).AppendLine();
|
||||
sbInformation.AppendFormat("Volume has {0} blocks", blocks).AppendLine();
|
||||
@@ -581,5 +443,143 @@ namespace DiscImageChef.Filesystems
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Boot block, first 2 sectors
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct BootBlock
|
||||
{
|
||||
/// <summary>
|
||||
/// Offset 0x00, "DOSx" disk type
|
||||
/// </summary>
|
||||
public uint diskType;
|
||||
/// <summary>
|
||||
/// Offset 0x04, Checksum
|
||||
/// </summary>
|
||||
public uint checksum;
|
||||
/// <summary>
|
||||
/// Offset 0x08, Pointer to root block, mostly invalid
|
||||
/// </summary>
|
||||
public uint root_ptr;
|
||||
/// <summary>
|
||||
/// Offset 0x0C, Boot code, til completion. Size is intentionally incorrect to allow marshaling to work.
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)] public byte[] bootCode;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct RootBlock
|
||||
{
|
||||
/// <summary>
|
||||
/// Offset 0x00, block type, value = T_HEADER (2)
|
||||
/// </summary>
|
||||
public uint type;
|
||||
/// <summary>
|
||||
/// Offset 0x04, unused
|
||||
/// </summary>
|
||||
public uint headerKey;
|
||||
/// <summary>
|
||||
/// Offset 0x08, unused
|
||||
/// </summary>
|
||||
public uint highSeq;
|
||||
/// <summary>
|
||||
/// Offset 0x0C, longs used by hash table
|
||||
/// </summary>
|
||||
public uint hashTableSize;
|
||||
/// <summary>
|
||||
/// Offset 0x10, unused
|
||||
/// </summary>
|
||||
public uint firstData;
|
||||
/// <summary>
|
||||
/// Offset 0x14, Rootblock checksum
|
||||
/// </summary>
|
||||
public uint checksum;
|
||||
/// <summary>
|
||||
/// Offset 0x18, Hashtable, size = (block size / 4) - 56 or size = hashTableSize.
|
||||
/// Size intentionally bad to allow marshalling to work.
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)] public uint[] hashTable;
|
||||
/// <summary>
|
||||
/// Offset 0x18+hashTableSize*4+0, bitmap flag, 0xFFFFFFFF if valid
|
||||
/// </summary>
|
||||
public uint bitmapFlag;
|
||||
/// <summary>
|
||||
/// Offset 0x18+hashTableSize*4+4, bitmap pages, 25 entries
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 25)] public uint[] bitmapPages;
|
||||
/// <summary>
|
||||
/// Offset 0x18+hashTableSize*4+104, pointer to bitmap extension block
|
||||
/// </summary>
|
||||
public uint bitmapExtensionBlock;
|
||||
/// <summary>
|
||||
/// Offset 0x18+hashTableSize*4+108, last root alteration days since 1978/01/01
|
||||
/// </summary>
|
||||
public uint rDays;
|
||||
/// <summary>
|
||||
/// Offset 0x18+hashTableSize*4+112, last root alteration minutes past midnight
|
||||
/// </summary>
|
||||
public uint rMins;
|
||||
/// <summary>
|
||||
/// Offset 0x18+hashTableSize*4+116, last root alteration ticks (1/50 secs)
|
||||
/// </summary>
|
||||
public uint rTicks;
|
||||
/// <summary>
|
||||
/// Offset 0x18+hashTableSize*4+120, disk name, pascal string, 31 bytes
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 31)] public byte[] diskName;
|
||||
/// <summary>
|
||||
/// Offset 0x18+hashTableSize*4+151, unused
|
||||
/// </summary>
|
||||
public byte padding;
|
||||
/// <summary>
|
||||
/// Offset 0x18+hashTableSize*4+152, unused
|
||||
/// </summary>
|
||||
public uint reserved1;
|
||||
/// <summary>
|
||||
/// Offset 0x18+hashTableSize*4+156, unused
|
||||
/// </summary>
|
||||
public uint reserved2;
|
||||
/// <summary>
|
||||
/// Offset 0x18+hashTableSize*4+160, last disk alteration days since 1978/01/01
|
||||
/// </summary>
|
||||
public uint vDays;
|
||||
/// <summary>
|
||||
/// Offset 0x18+hashTableSize*4+164, last disk alteration minutes past midnight
|
||||
/// </summary>
|
||||
public uint vMins;
|
||||
/// <summary>
|
||||
/// Offset 0x18+hashTableSize*4+168, last disk alteration ticks (1/50 secs)
|
||||
/// </summary>
|
||||
public uint vTicks;
|
||||
/// <summary>
|
||||
/// Offset 0x18+hashTableSize*4+172, filesystem creation days since 1978/01/01
|
||||
/// </summary>
|
||||
public uint cDays;
|
||||
/// <summary>
|
||||
/// Offset 0x18+hashTableSize*4+176, filesystem creation minutes since 1978/01/01
|
||||
/// </summary>
|
||||
public uint cMins;
|
||||
/// <summary>
|
||||
/// Offset 0x18+hashTableSize*4+180, filesystem creation ticks since 1978/01/01
|
||||
/// </summary>
|
||||
public uint cTicks;
|
||||
/// <summary>
|
||||
/// Offset 0x18+hashTableSize*4+184, unused
|
||||
/// </summary>
|
||||
public uint nextHash;
|
||||
/// <summary>
|
||||
/// Offset 0x18+hashTableSize*4+188, unused
|
||||
/// </summary>
|
||||
public uint parentDir;
|
||||
/// <summary>
|
||||
/// Offset 0x18+hashTableSize*4+192, first directory cache block
|
||||
/// </summary>
|
||||
public uint extension;
|
||||
/// <summary>
|
||||
/// Offset 0x18+hashTableSize*4+196, block secondary type = ST_ROOT (1)
|
||||
/// </summary>
|
||||
public uint sec_type;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -41,39 +41,18 @@ namespace DiscImageChef.Filesystems.AppleDOS
|
||||
{
|
||||
public partial class AppleDOS : Filesystem
|
||||
{
|
||||
bool mounted;
|
||||
bool debug;
|
||||
readonly ImagePlugin device;
|
||||
|
||||
#region Caches
|
||||
/// <summary>Caches track/sector lists</summary>
|
||||
Dictionary<string, byte[]> extentCache;
|
||||
/// <summary>Caches files</summary>
|
||||
Dictionary<string, byte[]> fileCache;
|
||||
/// <summary>Caches catalog</summary>
|
||||
Dictionary<string, ushort> catalogCache;
|
||||
/// <summary>Caches file size</summary>
|
||||
Dictionary<string, int> fileSizeCache;
|
||||
/// <summary>Caches VTOC</summary>
|
||||
byte[] vtocBlocks;
|
||||
/// <summary>Caches catalog</summary>
|
||||
byte[] catalogBlocks;
|
||||
/// <summary>Caches boot code</summary>
|
||||
byte[] bootBlocks;
|
||||
/// <summary>Caches file type</summary>
|
||||
Dictionary<string, byte> fileTypeCache;
|
||||
/// <summary>Caches locked files</summary>
|
||||
List<string> lockedFiles;
|
||||
#endregion Caches
|
||||
|
||||
Vtoc vtoc;
|
||||
ulong start;
|
||||
bool debug;
|
||||
bool mounted;
|
||||
int sectorsPerTrack;
|
||||
ulong start;
|
||||
ulong totalFileEntries;
|
||||
bool track1UsedByFiles;
|
||||
bool track2UsedByFiles;
|
||||
int usedSectors;
|
||||
|
||||
Vtoc vtoc;
|
||||
|
||||
public AppleDOS()
|
||||
{
|
||||
Name = "Apple DOS File System";
|
||||
@@ -98,5 +77,26 @@ namespace DiscImageChef.Filesystems.AppleDOS
|
||||
// TODO: Until Apple ][ encoding is implemented
|
||||
CurrentEncoding = new LisaRoman();
|
||||
}
|
||||
|
||||
#region Caches
|
||||
/// <summary>Caches track/sector lists</summary>
|
||||
Dictionary<string, byte[]> extentCache;
|
||||
/// <summary>Caches files</summary>
|
||||
Dictionary<string, byte[]> fileCache;
|
||||
/// <summary>Caches catalog</summary>
|
||||
Dictionary<string, ushort> catalogCache;
|
||||
/// <summary>Caches file size</summary>
|
||||
Dictionary<string, int> fileSizeCache;
|
||||
/// <summary>Caches VTOC</summary>
|
||||
byte[] vtocBlocks;
|
||||
/// <summary>Caches catalog</summary>
|
||||
byte[] catalogBlocks;
|
||||
/// <summary>Caches boot code</summary>
|
||||
byte[] bootBlocks;
|
||||
/// <summary>Caches file type</summary>
|
||||
Dictionary<string, byte> fileTypeCache;
|
||||
/// <summary>Caches locked files</summary>
|
||||
List<string> lockedFiles;
|
||||
#endregion Caches
|
||||
}
|
||||
}
|
||||
@@ -41,7 +41,7 @@ namespace DiscImageChef.Filesystems.AppleDOS
|
||||
public partial class AppleDOS
|
||||
{
|
||||
/// <summary>
|
||||
/// Solves a symbolic link.
|
||||
/// Solves a symbolic link.
|
||||
/// </summary>
|
||||
/// <param name="path">Link path.</param>
|
||||
/// <param name="dest">Link destination.</param>
|
||||
@@ -51,7 +51,7 @@ namespace DiscImageChef.Filesystems.AppleDOS
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Lists contents from a directory.
|
||||
/// Lists contents from a directory.
|
||||
/// </summary>
|
||||
/// <param name="path">Directory path.</param>
|
||||
/// <param name="contents">Directory contents.</param>
|
||||
@@ -100,7 +100,8 @@ namespace DiscImageChef.Filesystems.AppleDOS
|
||||
CatalogSector catSector = (CatalogSector)Marshal.PtrToStructure(catPtr, typeof(CatalogSector));
|
||||
Marshal.FreeHGlobal(catPtr);
|
||||
|
||||
foreach(FileEntry entry in catSector.entries.Where(entry => entry.extentTrack > 0)) {
|
||||
foreach(FileEntry entry in catSector.entries.Where(entry => entry.extentTrack > 0))
|
||||
{
|
||||
track1UsedByFiles |= entry.extentTrack == 1;
|
||||
track2UsedByFiles |= entry.extentTrack == 2;
|
||||
|
||||
|
||||
@@ -58,7 +58,8 @@ namespace DiscImageChef.Filesystems.AppleDOS
|
||||
|
||||
if(debug && (string.Compare(path, "$", StringComparison.InvariantCulture) == 0 ||
|
||||
string.Compare(path, "$Boot", StringComparison.InvariantCulture) == 0 ||
|
||||
string.Compare(path, "$Vtoc", StringComparison.InvariantCulture) == 0)) attributes |= FileAttributes.System;
|
||||
string.Compare(path, "$Vtoc", StringComparison.InvariantCulture) == 0))
|
||||
attributes |= FileAttributes.System;
|
||||
|
||||
return Errno.NoError;
|
||||
}
|
||||
@@ -77,14 +78,9 @@ namespace DiscImageChef.Filesystems.AppleDOS
|
||||
if(debug && (string.Compare(path, "$", StringComparison.InvariantCulture) == 0 ||
|
||||
string.Compare(path, "$Boot", StringComparison.InvariantCulture) == 0 ||
|
||||
string.Compare(path, "$Vtoc", StringComparison.InvariantCulture) == 0))
|
||||
{
|
||||
if(string.Compare(path, "$", StringComparison.InvariantCulture) == 0)
|
||||
file = catalogBlocks;
|
||||
else if(string.Compare(path, "$Vtoc", StringComparison.InvariantCulture) == 0)
|
||||
file = vtocBlocks;
|
||||
else
|
||||
file = bootBlocks;
|
||||
}
|
||||
if(string.Compare(path, "$", StringComparison.InvariantCulture) == 0) file = catalogBlocks;
|
||||
else if(string.Compare(path, "$Vtoc", StringComparison.InvariantCulture) == 0) file = vtocBlocks;
|
||||
else file = bootBlocks;
|
||||
else
|
||||
{
|
||||
if(!fileCache.TryGetValue(filename, out file))
|
||||
@@ -224,7 +220,7 @@ namespace DiscImageChef.Filesystems.AppleDOS
|
||||
extentCache = new Dictionary<string, byte[]>();
|
||||
|
||||
foreach(Errno error in catalogCache.Keys.Select(CacheFile).Where(error => error != Errno.NoError))
|
||||
{ return error; }
|
||||
return error;
|
||||
|
||||
uint tracksOnBoot = 1;
|
||||
if(!track1UsedByFiles) tracksOnBoot++;
|
||||
|
||||
@@ -40,7 +40,7 @@ namespace DiscImageChef.Filesystems.AppleDOS
|
||||
public partial class AppleDOS
|
||||
{
|
||||
/// <summary>
|
||||
/// Mounts an Apple DOS filesystem
|
||||
/// Mounts an Apple DOS filesystem
|
||||
/// </summary>
|
||||
public override Errno Mount()
|
||||
{
|
||||
@@ -48,7 +48,7 @@ namespace DiscImageChef.Filesystems.AppleDOS
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Mounts an Apple DOS filesystem
|
||||
/// Mounts an Apple DOS filesystem
|
||||
/// </summary>
|
||||
public override Errno Mount(bool debug)
|
||||
{
|
||||
@@ -117,7 +117,7 @@ namespace DiscImageChef.Filesystems.AppleDOS
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Umounts this DOS filesystem
|
||||
/// Umounts this DOS filesystem
|
||||
/// </summary>
|
||||
public override Errno Unmount()
|
||||
{
|
||||
@@ -131,7 +131,7 @@ namespace DiscImageChef.Filesystems.AppleDOS
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets information about the mounted volume.
|
||||
/// Gets information about the mounted volume.
|
||||
/// </summary>
|
||||
/// <param name="stat">Information about the mounted volume.</param>
|
||||
public override Errno StatFs(ref FileSystemInfo stat)
|
||||
|
||||
@@ -38,7 +38,7 @@ namespace DiscImageChef.Filesystems.AppleDOS
|
||||
public partial class AppleDOS
|
||||
{
|
||||
/// <summary>
|
||||
/// Lists all extended attributes, alternate data streams and forks of the given file.
|
||||
/// Lists all extended attributes, alternate data streams and forks of the given file.
|
||||
/// </summary>
|
||||
/// <returns>Error number.</returns>
|
||||
/// <param name="path">Path.</param>
|
||||
@@ -71,7 +71,7 @@ namespace DiscImageChef.Filesystems.AppleDOS
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads an extended attribute, alternate data stream or fork from the given file.
|
||||
/// Reads an extended attribute, alternate data stream or fork from the given file.
|
||||
/// </summary>
|
||||
/// <returns>Error number.</returns>
|
||||
/// <param name="path">File path.</param>
|
||||
@@ -89,7 +89,8 @@ namespace DiscImageChef.Filesystems.AppleDOS
|
||||
|
||||
if(debug && (string.Compare(path, "$", StringComparison.InvariantCulture) == 0 ||
|
||||
string.Compare(path, "$Boot", StringComparison.InvariantCulture) == 0 ||
|
||||
string.Compare(path, "$Vtoc", StringComparison.InvariantCulture) == 0)) return Errno.NoSuchExtendedAttribute;
|
||||
string.Compare(path, "$Vtoc", StringComparison.InvariantCulture) == 0))
|
||||
return Errno.NoSuchExtendedAttribute;
|
||||
|
||||
if(!catalogCache.ContainsKey(filename)) return Errno.NoSuchFile;
|
||||
|
||||
|
||||
@@ -45,15 +45,15 @@ namespace DiscImageChef.Filesystems
|
||||
public class AppleHFS : Filesystem
|
||||
{
|
||||
/// <summary>
|
||||
/// "BD", HFS magic
|
||||
/// "BD", HFS magic
|
||||
/// </summary>
|
||||
const ushort HFS_MAGIC = 0x4244;
|
||||
/// <summary>
|
||||
/// "H+", HFS+ magic
|
||||
/// "H+", HFS+ magic
|
||||
/// </summary>
|
||||
const ushort HFSP_MAGIC = 0x482B;
|
||||
/// <summary>
|
||||
/// "LK", HFS bootblock magic
|
||||
/// "LK", HFS bootblock magic
|
||||
/// </summary>
|
||||
const ushort HFSBB_MAGIC = 0x4C4B;
|
||||
|
||||
@@ -96,8 +96,7 @@ namespace DiscImageChef.Filesystems
|
||||
if(drSigWord != HFS_MAGIC) continue;
|
||||
|
||||
drSigWord =
|
||||
BigEndianBitConverter
|
||||
.ToUInt16(mdbSector, offset + 0x7C); // Seek to embedded HFS+ signature
|
||||
BigEndianBitConverter.ToUInt16(mdbSector, offset + 0x7C); // Seek to embedded HFS+ signature
|
||||
|
||||
return drSigWord != HFSP_MAGIC;
|
||||
}
|
||||
@@ -117,8 +116,7 @@ namespace DiscImageChef.Filesystems
|
||||
return false;
|
||||
}
|
||||
|
||||
public override void GetInformation(ImagePlugin imagePlugin, Partition partition,
|
||||
out string information)
|
||||
public override void GetInformation(ImagePlugin imagePlugin, Partition partition, out string information)
|
||||
{
|
||||
information = "";
|
||||
|
||||
@@ -159,7 +157,8 @@ namespace DiscImageChef.Filesystems
|
||||
else return;
|
||||
}
|
||||
|
||||
HFS_MasterDirectoryBlock MDB = BigEndianMarshal.ByteArrayToStructureBigEndian<HFS_MasterDirectoryBlock>(mdbSector);
|
||||
HFS_MasterDirectoryBlock MDB =
|
||||
BigEndianMarshal.ByteArrayToStructureBigEndian<HFS_MasterDirectoryBlock>(mdbSector);
|
||||
HFS_BootBlock BB = BigEndianMarshal.ByteArrayToStructureBigEndian<HFS_BootBlock>(bbSector);
|
||||
|
||||
sb.AppendLine("Apple Hierarchical File System");
|
||||
@@ -275,7 +274,8 @@ namespace DiscImageChef.Filesystems
|
||||
XmlFsType.BackupDate = DateHandlers.MacToDateTime(MDB.drVolBkUp);
|
||||
XmlFsType.BackupDateSpecified = true;
|
||||
}
|
||||
XmlFsType.Bootable = BB.signature == HFSBB_MAGIC || MDB.drFndrInfo0 != 0 || MDB.drFndrInfo3 != 0 || MDB.drFndrInfo5 != 0;
|
||||
XmlFsType.Bootable = BB.signature == HFSBB_MAGIC || MDB.drFndrInfo0 != 0 || MDB.drFndrInfo3 != 0 ||
|
||||
MDB.drFndrInfo5 != 0;
|
||||
XmlFsType.Clusters = MDB.drNmAlBlks;
|
||||
XmlFsType.ClusterSize = (int)MDB.drAlBlkSiz;
|
||||
if(MDB.drCrDate > 0)
|
||||
@@ -312,8 +312,68 @@ namespace DiscImageChef.Filesystems
|
||||
return sector;
|
||||
}
|
||||
|
||||
public override Errno Mount()
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno Mount(bool debug)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno Unmount()
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno MapBlock(string path, long fileBlock, ref long deviceBlock)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno GetAttributes(string path, ref FileAttributes attributes)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno ListXAttr(string path, ref List<string> xattrs)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno GetXattr(string path, string xattr, ref byte[] buf)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno Read(string path, long offset, long size, ref byte[] buf)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno ReadDir(string path, ref List<string> contents)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno StatFs(ref FileSystemInfo stat)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno Stat(string path, ref FileEntryInfo stat)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno ReadLink(string path, ref string dest)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Master Directory Block, should be sector 2 in volume
|
||||
/// Master Directory Block, should be sector 2 in volume
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct HFS_MasterDirectoryBlock // Should be sector 2 in volume
|
||||
@@ -393,16 +453,20 @@ namespace DiscImageChef.Filesystems
|
||||
/// <summary>0x080, Size in blocks of volume common cache</summary>
|
||||
public ushort drCtlCSize;
|
||||
// End of variable variables :D
|
||||
/// <summary>0x082, Bytes in the extents B-Tree
|
||||
/// 3 HFS extents following, 32 bits each</summary>
|
||||
/// <summary>
|
||||
/// 0x082, Bytes in the extents B-Tree
|
||||
/// 3 HFS extents following, 32 bits each
|
||||
/// </summary>
|
||||
public uint drXTFlSize;
|
||||
/// <summary>0x092, Bytes in the catalog B-Tree
|
||||
/// 3 HFS extents following, 32 bits each</summary>
|
||||
/// <summary>
|
||||
/// 0x092, Bytes in the catalog B-Tree
|
||||
/// 3 HFS extents following, 32 bits each
|
||||
/// </summary>
|
||||
public uint drCTFlSize;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Should be sectors 0 and 1 in volume, followed by boot code
|
||||
/// Should be sectors 0 and 1 in volume, followed by boot code
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct HFS_BootBlock // Should be sectors 0 and 1 in volume
|
||||
@@ -446,65 +510,5 @@ namespace DiscImageChef.Filesystems
|
||||
/// <summary>Fraction of RAM for system heap</summary>
|
||||
public uint heap_fract;
|
||||
}
|
||||
|
||||
public override Errno Mount()
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno Mount(bool debug)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno Unmount()
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno MapBlock(string path, long fileBlock, ref long deviceBlock)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno GetAttributes(string path, ref FileAttributes attributes)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno ListXAttr(string path, ref List<string> xattrs)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno GetXattr(string path, string xattr, ref byte[] buf)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno Read(string path, long offset, long size, ref byte[] buf)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno ReadDir(string path, ref List<string> contents)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno StatFs(ref FileSystemInfo stat)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno Stat(string path, ref FileEntryInfo stat)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno ReadLink(string path, ref string dest)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -44,15 +44,15 @@ namespace DiscImageChef.Filesystems
|
||||
public class AppleHFSPlus : Filesystem
|
||||
{
|
||||
/// <summary>
|
||||
/// "BD", HFS magic
|
||||
/// "BD", HFS magic
|
||||
/// </summary>
|
||||
const ushort HFS_MAGIC = 0x4244;
|
||||
/// <summary>
|
||||
/// "H+", HFS+ magic
|
||||
/// "H+", HFS+ magic
|
||||
/// </summary>
|
||||
const ushort HFSP_MAGIC = 0x482B;
|
||||
/// <summary>
|
||||
/// "HX", HFSX magic
|
||||
/// "HX", HFSX magic
|
||||
/// </summary>
|
||||
const ushort HFSX_MAGIC = 0x4858;
|
||||
|
||||
@@ -88,8 +88,7 @@ namespace DiscImageChef.Filesystems
|
||||
uint sectorsToRead = 0x800 / imagePlugin.ImageInfo.SectorSize;
|
||||
if(0x800 % imagePlugin.ImageInfo.SectorSize > 0) sectorsToRead++;
|
||||
|
||||
byte[] vhSector = imagePlugin.ReadSectors(partition.Start,
|
||||
sectorsToRead);
|
||||
byte[] vhSector = imagePlugin.ReadSectors(partition.Start, sectorsToRead);
|
||||
|
||||
drSigWord = BigEndianBitConverter.ToUInt16(vhSector, 0x400); // Check for HFS Wrapper MDB
|
||||
|
||||
@@ -99,13 +98,11 @@ namespace DiscImageChef.Filesystems
|
||||
|
||||
if(drSigWord == HFSP_MAGIC) // "H+"
|
||||
{
|
||||
ushort xdrStABNt = BigEndianBitConverter
|
||||
.ToUInt16(vhSector, 0x47E);
|
||||
ushort xdrStABNt = BigEndianBitConverter.ToUInt16(vhSector, 0x47E);
|
||||
|
||||
uint drAlBlkSiz = BigEndianBitConverter.ToUInt32(vhSector, 0x414);
|
||||
|
||||
ushort drAlBlSt = BigEndianBitConverter
|
||||
.ToUInt16(vhSector, 0x41C);
|
||||
ushort drAlBlSt = BigEndianBitConverter.ToUInt16(vhSector, 0x41C);
|
||||
|
||||
hfspOffset = (ulong)((drAlBlSt * 512 + xdrStABNt * drAlBlkSiz) / imagePlugin.GetSectorSize());
|
||||
}
|
||||
@@ -119,8 +116,7 @@ namespace DiscImageChef.Filesystems
|
||||
return drSigWord == HFSP_MAGIC || drSigWord == HFSX_MAGIC;
|
||||
}
|
||||
|
||||
public override void GetInformation(ImagePlugin imagePlugin, Partition partition,
|
||||
out string information)
|
||||
public override void GetInformation(ImagePlugin imagePlugin, Partition partition, out string information)
|
||||
{
|
||||
information = "";
|
||||
|
||||
@@ -133,8 +129,7 @@ namespace DiscImageChef.Filesystems
|
||||
uint sectorsToRead = 0x800 / imagePlugin.ImageInfo.SectorSize;
|
||||
if(0x800 % imagePlugin.ImageInfo.SectorSize > 0) sectorsToRead++;
|
||||
|
||||
byte[] vhSector = imagePlugin.ReadSectors(partition.Start,
|
||||
sectorsToRead);
|
||||
byte[] vhSector = imagePlugin.ReadSectors(partition.Start, sectorsToRead);
|
||||
|
||||
drSigWord = BigEndianBitConverter.ToUInt16(vhSector, 0x400); // Check for HFS Wrapper MDB
|
||||
|
||||
@@ -144,13 +139,11 @@ namespace DiscImageChef.Filesystems
|
||||
|
||||
if(drSigWord == HFSP_MAGIC) // "H+"
|
||||
{
|
||||
ushort xdrStABNt = BigEndianBitConverter
|
||||
.ToUInt16(vhSector, 0x47E);
|
||||
ushort xdrStABNt = BigEndianBitConverter.ToUInt16(vhSector, 0x47E);
|
||||
|
||||
uint drAlBlkSiz = BigEndianBitConverter.ToUInt32(vhSector, 0x414);
|
||||
|
||||
ushort drAlBlSt = BigEndianBitConverter
|
||||
.ToUInt16(vhSector, 0x41C);
|
||||
ushort drAlBlSt = BigEndianBitConverter.ToUInt16(vhSector, 0x41C);
|
||||
|
||||
hfspOffset = (ulong)((drAlBlSt * 512 + xdrStABNt * drAlBlkSiz) / imagePlugin.GetSectorSize());
|
||||
wrapped = true;
|
||||
@@ -278,8 +271,68 @@ namespace DiscImageChef.Filesystems
|
||||
else return;
|
||||
}
|
||||
|
||||
public override Errno Mount()
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno Mount(bool debug)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno Unmount()
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno MapBlock(string path, long fileBlock, ref long deviceBlock)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno GetAttributes(string path, ref FileAttributes attributes)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno ListXAttr(string path, ref List<string> xattrs)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno GetXattr(string path, string xattr, ref byte[] buf)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno Read(string path, long offset, long size, ref byte[] buf)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno ReadDir(string path, ref List<string> contents)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno StatFs(ref FileSystemInfo stat)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno Stat(string path, ref FileEntryInfo stat)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno ReadLink(string path, ref string dest)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// HFS+ Volume Header, should be at offset 0x0400 bytes in volume with a size of 532 bytes
|
||||
/// HFS+ Volume Header, should be at offset 0x0400 bytes in volume with a size of 532 bytes
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct HFSPlusVolumeHeader
|
||||
@@ -290,12 +343,14 @@ namespace DiscImageChef.Filesystems
|
||||
public ushort version;
|
||||
/// <summary>0x004, Volume attributes</summary>
|
||||
public uint attributes;
|
||||
/// <summary>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</summary>
|
||||
/// <summary>
|
||||
/// 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
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] public byte[] lastMountedVersion;
|
||||
/// <summary>0x00C, Allocation block number containing the journal</summary>
|
||||
public uint journalInfoBlock;
|
||||
@@ -541,65 +596,5 @@ namespace DiscImageChef.Filesystems
|
||||
/// <summary>0x200</summary>
|
||||
public uint startupFile_extents_blockCount7;
|
||||
}
|
||||
|
||||
public override Errno Mount()
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno Mount(bool debug)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno Unmount()
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno MapBlock(string path, long fileBlock, ref long deviceBlock)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno GetAttributes(string path, ref FileAttributes attributes)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno ListXAttr(string path, ref List<string> xattrs)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno GetXattr(string path, string xattr, ref byte[] buf)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno Read(string path, long offset, long size, ref byte[] buf)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno ReadDir(string path, ref List<string> contents)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno StatFs(ref FileSystemInfo stat)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno Stat(string path, ref FileEntryInfo stat)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno ReadLink(string path, ref string dest)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -91,8 +91,8 @@ namespace DiscImageChef.Filesystems.AppleMFS
|
||||
entry.flMdDat = BigEndianBitConverter.ToUInt32(directoryBlocks, offset + 46);
|
||||
entry.flNam = new byte[directoryBlocks[offset + 50] + 1];
|
||||
Array.Copy(directoryBlocks, offset + 50, entry.flNam, 0, entry.flNam.Length);
|
||||
string lowerFilename = StringHandlers.PascalToString(entry.flNam, CurrentEncoding).ToLowerInvariant()
|
||||
.Replace('/', ':');
|
||||
string lowerFilename = StringHandlers
|
||||
.PascalToString(entry.flNam, CurrentEncoding).ToLowerInvariant().Replace('/', ':');
|
||||
|
||||
if(entry.flFlags.HasFlag(MFS_FileFlags.Used) && !idToFilename.ContainsKey(entry.flFlNum) &&
|
||||
!idToEntry.ContainsKey(entry.flFlNum) && !filenameToId.ContainsKey(lowerFilename) &&
|
||||
|
||||
@@ -169,8 +169,7 @@ namespace DiscImageChef.Filesystems.AppleMFS
|
||||
|
||||
if(string.Compare(path, "$", StringComparison.InvariantCulture) == 0)
|
||||
{
|
||||
stat.Blocks = directoryBlocks.Length / stat.BlockSize +
|
||||
directoryBlocks.Length % stat.BlockSize;
|
||||
stat.Blocks = directoryBlocks.Length / stat.BlockSize + directoryBlocks.Length % stat.BlockSize;
|
||||
stat.Length = directoryBlocks.Length;
|
||||
}
|
||||
else if(string.Compare(path, "$Bitmap", StringComparison.InvariantCulture) == 0)
|
||||
|
||||
@@ -56,8 +56,7 @@ namespace DiscImageChef.Filesystems.AppleMFS
|
||||
return drSigWord == MFS_MAGIC;
|
||||
}
|
||||
|
||||
public override void GetInformation(ImagePlugin imagePlugin, Partition partition,
|
||||
out string information)
|
||||
public override void GetInformation(ImagePlugin imagePlugin, Partition partition, out string information)
|
||||
{
|
||||
information = "";
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
#pragma warning disable 169
|
||||
|
||||
namespace DiscImageChef.Filesystems.AppleMFS
|
||||
@@ -42,7 +43,7 @@ namespace DiscImageChef.Filesystems.AppleMFS
|
||||
public partial class AppleMFS
|
||||
{
|
||||
/// <summary>
|
||||
/// Master Directory Block, should be at offset 0x0400 bytes in volume
|
||||
/// Master Directory Block, should be at offset 0x0400 bytes in volume
|
||||
/// </summary>
|
||||
struct MFS_MasterDirectoryBlock
|
||||
{
|
||||
@@ -79,7 +80,7 @@ namespace DiscImageChef.Filesystems.AppleMFS
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Should be at offset 0x0000 in volume, followed by boot code
|
||||
/// Should be at offset 0x0000 in volume, followed by boot code
|
||||
/// </summary>
|
||||
struct MFS_BootBlock
|
||||
{
|
||||
|
||||
@@ -74,8 +74,8 @@ namespace DiscImageChef.Filesystems.AppleMFS
|
||||
|
||||
if(!ArrayHelpers.ArrayIsNullOrEmpty(entry.flUsrWds)) xattrs.Add("com.apple.FinderInfo");
|
||||
|
||||
if(debug && device.ImageInfo.ReadableSectorTags.Contains(SectorTagType.AppleSectorTag) &&
|
||||
entry.flLgLen > 0) xattrs.Add("com.apple.macintosh.tags");
|
||||
if(debug && device.ImageInfo.ReadableSectorTags.Contains(SectorTagType.AppleSectorTag) && entry.flLgLen > 0)
|
||||
xattrs.Add("com.apple.macintosh.tags");
|
||||
|
||||
xattrs.Sort();
|
||||
|
||||
|
||||
@@ -93,8 +93,7 @@ namespace DiscImageChef.Filesystems
|
||||
return magic == AFS_MAGIC1;
|
||||
}
|
||||
|
||||
public override void GetInformation(ImagePlugin imagePlugin, Partition partition,
|
||||
out string information)
|
||||
public override void GetInformation(ImagePlugin imagePlugin, Partition partition, out string information)
|
||||
{
|
||||
information = "";
|
||||
|
||||
@@ -112,7 +111,8 @@ namespace DiscImageChef.Filesystems
|
||||
Array.Copy(tmp, offset, sbSector, 0, AFS_SUPERBLOCK_SIZE);
|
||||
|
||||
GCHandle handle = GCHandle.Alloc(sbSector, GCHandleType.Pinned);
|
||||
AtheosSuperBlock afsSb = (AtheosSuperBlock)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(AtheosSuperBlock));
|
||||
AtheosSuperBlock afsSb =
|
||||
(AtheosSuperBlock)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(AtheosSuperBlock));
|
||||
handle.Free();
|
||||
|
||||
sb.AppendLine("Atheos filesystem");
|
||||
@@ -121,8 +121,8 @@ namespace DiscImageChef.Filesystems
|
||||
|
||||
sb.AppendFormat("Volume name: {0}", StringHandlers.CToString(afsSb.name, CurrentEncoding)).AppendLine();
|
||||
sb.AppendFormat("{0} bytes per block", afsSb.block_size).AppendLine();
|
||||
sb.AppendFormat("{0} blocks in volume ({1} bytes)", afsSb.num_blocks,
|
||||
afsSb.num_blocks * afsSb.block_size).AppendLine();
|
||||
sb.AppendFormat("{0} blocks in volume ({1} bytes)", afsSb.num_blocks, afsSb.num_blocks * afsSb.block_size)
|
||||
.AppendLine();
|
||||
sb.AppendFormat("{0} used blocks ({1} bytes)", afsSb.used_blocks, afsSb.used_blocks * afsSb.block_size)
|
||||
.AppendLine();
|
||||
sb.AppendFormat("{0} bytes per i-node", afsSb.inode_size).AppendLine();
|
||||
@@ -163,8 +163,68 @@ namespace DiscImageChef.Filesystems
|
||||
};
|
||||
}
|
||||
|
||||
public override Errno Mount()
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno Mount(bool debug)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno Unmount()
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno MapBlock(string path, long fileBlock, ref long deviceBlock)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno GetAttributes(string path, ref FileAttributes attributes)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno ListXAttr(string path, ref List<string> xattrs)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno GetXattr(string path, string xattr, ref byte[] buf)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno Read(string path, long offset, long size, ref byte[] buf)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno ReadDir(string path, ref List<string> contents)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno StatFs(ref FileSystemInfo stat)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno Stat(string path, ref FileEntryInfo stat)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno ReadLink(string path, ref string dest)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Be superblock
|
||||
/// Be superblock
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct AtheosSuperBlock
|
||||
@@ -230,65 +290,5 @@ namespace DiscImageChef.Filesystems
|
||||
/// <summary>0x08C, Size of bootloader</summary>
|
||||
public int boot_size;
|
||||
}
|
||||
|
||||
public override Errno Mount()
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno Mount(bool debug)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno Unmount()
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno MapBlock(string path, long fileBlock, ref long deviceBlock)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno GetAttributes(string path, ref FileAttributes attributes)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno ListXAttr(string path, ref List<string> xattrs)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno GetXattr(string path, string xattr, ref byte[] buf)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno Read(string path, long offset, long size, ref byte[] buf)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno ReadDir(string path, ref List<string> contents)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno StatFs(ref FileSystemInfo stat)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno Stat(string path, ref FileEntryInfo stat)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno ReadLink(string path, ref string dest)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -106,8 +106,7 @@ namespace DiscImageChef.Filesystems
|
||||
return magic == BEFS_MAGIC1 || magicBe == BEFS_MAGIC1;
|
||||
}
|
||||
|
||||
public override void GetInformation(ImagePlugin imagePlugin, Partition partition,
|
||||
out string information)
|
||||
public override void GetInformation(ImagePlugin imagePlugin, Partition partition, out string information)
|
||||
{
|
||||
information = "";
|
||||
|
||||
@@ -171,13 +170,16 @@ namespace DiscImageChef.Filesystems
|
||||
1 << (int)besb.block_shift, besb.block_size).AppendLine();
|
||||
}
|
||||
|
||||
switch(besb.flags) {
|
||||
switch(besb.flags)
|
||||
{
|
||||
case BEFS_CLEAN:
|
||||
sb.AppendLine(besb.log_start == besb.log_end ? "Filesystem is clean" : "Filesystem is dirty");
|
||||
break;
|
||||
case BEFS_DIRTY: sb.AppendLine("Filesystem is dirty");
|
||||
case BEFS_DIRTY:
|
||||
sb.AppendLine("Filesystem is dirty");
|
||||
break;
|
||||
default: sb.AppendFormat("Unknown flags: {0:X8}", besb.flags).AppendLine();
|
||||
default:
|
||||
sb.AppendFormat("Unknown flags: {0:X8}", besb.flags).AppendLine();
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -219,64 +221,6 @@ namespace DiscImageChef.Filesystems
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Be superblock
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct BeSuperBlock
|
||||
{
|
||||
/// <summary>0x000, Volume name, 32 bytes</summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] public byte[] name;
|
||||
/// <summary>0x020, "BFS1", 0x42465331</summary>
|
||||
public uint magic1;
|
||||
/// <summary>0x024, "BIGE", 0x42494745</summary>
|
||||
public uint fs_byte_order;
|
||||
/// <summary>0x028, Bytes per block</summary>
|
||||
public uint block_size;
|
||||
/// <summary>0x02C, 1 << block_shift == block_size</summary>
|
||||
public uint block_shift;
|
||||
/// <summary>0x030, Blocks in volume</summary>
|
||||
public long num_blocks;
|
||||
/// <summary>0x038, Used blocks in volume</summary>
|
||||
public long used_blocks;
|
||||
/// <summary>0x040, Bytes per inode</summary>
|
||||
public int inode_size;
|
||||
/// <summary>0x044, 0xDD121031</summary>
|
||||
public uint magic2;
|
||||
/// <summary>0x048, Blocks per allocation group</summary>
|
||||
public int blocks_per_ag;
|
||||
/// <summary>0x04C, 1 << ag_shift == blocks_per_ag</summary>
|
||||
public int ag_shift;
|
||||
/// <summary>0x050, Allocation groups in volume</summary>
|
||||
public int num_ags;
|
||||
/// <summary>0x054, 0x434c454e if clean, 0x44495254 if dirty</summary>
|
||||
public uint flags;
|
||||
/// <summary>0x058, Allocation group of journal</summary>
|
||||
public int log_blocks_ag;
|
||||
/// <summary>0x05C, Start block of journal, inside ag</summary>
|
||||
public ushort log_blocks_start;
|
||||
/// <summary>0x05E, Length in blocks of journal, inside ag</summary>
|
||||
public ushort log_blocks_len;
|
||||
/// <summary>0x060, Start of journal</summary>
|
||||
public long log_start;
|
||||
/// <summary>0x068, End of journal</summary>
|
||||
public long log_end;
|
||||
/// <summary>0x070, 0x15B6830E</summary>
|
||||
public uint magic3;
|
||||
/// <summary>0x074, Allocation group where root folder's i-node resides</summary>
|
||||
public int root_dir_ag;
|
||||
/// <summary>0x078, Start in ag of root folder's i-node</summary>
|
||||
public ushort root_dir_start;
|
||||
/// <summary>0x07A, As this is part of inode_addr, this is 1</summary>
|
||||
public ushort root_dir_len;
|
||||
/// <summary>0x07C, Allocation group where indices' i-node resides</summary>
|
||||
public int indices_ag;
|
||||
/// <summary>0x080, Start in ag of indices' i-node</summary>
|
||||
public ushort indices_start;
|
||||
/// <summary>0x082, As this is part of inode_addr, this is 1</summary>
|
||||
public ushort indices_len;
|
||||
}
|
||||
|
||||
public override Errno Mount()
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
@@ -336,5 +280,63 @@ namespace DiscImageChef.Filesystems
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Be superblock
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct BeSuperBlock
|
||||
{
|
||||
/// <summary>0x000, Volume name, 32 bytes</summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] public byte[] name;
|
||||
/// <summary>0x020, "BFS1", 0x42465331</summary>
|
||||
public uint magic1;
|
||||
/// <summary>0x024, "BIGE", 0x42494745</summary>
|
||||
public uint fs_byte_order;
|
||||
/// <summary>0x028, Bytes per block</summary>
|
||||
public uint block_size;
|
||||
/// <summary>0x02C, 1 << block_shift == block_size</summary>
|
||||
public uint block_shift;
|
||||
/// <summary>0x030, Blocks in volume</summary>
|
||||
public long num_blocks;
|
||||
/// <summary>0x038, Used blocks in volume</summary>
|
||||
public long used_blocks;
|
||||
/// <summary>0x040, Bytes per inode</summary>
|
||||
public int inode_size;
|
||||
/// <summary>0x044, 0xDD121031</summary>
|
||||
public uint magic2;
|
||||
/// <summary>0x048, Blocks per allocation group</summary>
|
||||
public int blocks_per_ag;
|
||||
/// <summary>0x04C, 1 << ag_shift == blocks_per_ag</summary>
|
||||
public int ag_shift;
|
||||
/// <summary>0x050, Allocation groups in volume</summary>
|
||||
public int num_ags;
|
||||
/// <summary>0x054, 0x434c454e if clean, 0x44495254 if dirty</summary>
|
||||
public uint flags;
|
||||
/// <summary>0x058, Allocation group of journal</summary>
|
||||
public int log_blocks_ag;
|
||||
/// <summary>0x05C, Start block of journal, inside ag</summary>
|
||||
public ushort log_blocks_start;
|
||||
/// <summary>0x05E, Length in blocks of journal, inside ag</summary>
|
||||
public ushort log_blocks_len;
|
||||
/// <summary>0x060, Start of journal</summary>
|
||||
public long log_start;
|
||||
/// <summary>0x068, End of journal</summary>
|
||||
public long log_end;
|
||||
/// <summary>0x070, 0x15B6830E</summary>
|
||||
public uint magic3;
|
||||
/// <summary>0x074, Allocation group where root folder's i-node resides</summary>
|
||||
public int root_dir_ag;
|
||||
/// <summary>0x078, Start in ag of root folder's i-node</summary>
|
||||
public ushort root_dir_start;
|
||||
/// <summary>0x07A, As this is part of inode_addr, this is 1</summary>
|
||||
public ushort root_dir_len;
|
||||
/// <summary>0x07C, Allocation group where indices' i-node resides</summary>
|
||||
public int indices_ag;
|
||||
/// <summary>0x080, Start in ag of indices' i-node</summary>
|
||||
public ushort indices_start;
|
||||
/// <summary>0x082, As this is part of inode_addr, this is 1</summary>
|
||||
public ushort indices_len;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -44,7 +44,7 @@ namespace DiscImageChef.Filesystems
|
||||
public class BTRFS : Filesystem
|
||||
{
|
||||
/// <summary>
|
||||
/// BTRFS magic "_BHRfS_M"
|
||||
/// BTRFS magic "_BHRfS_M"
|
||||
/// </summary>
|
||||
const ulong btrfsMagic = 0x4D5F53665248425F;
|
||||
|
||||
@@ -69,62 +69,6 @@ namespace DiscImageChef.Filesystems
|
||||
CurrentEncoding = encoding ?? Encoding.GetEncoding("iso-8859-15");
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct SuperBlock
|
||||
{
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x20)] public byte[] checksum;
|
||||
public Guid uuid;
|
||||
public ulong pba;
|
||||
public ulong flags;
|
||||
public ulong magic;
|
||||
public ulong generation;
|
||||
public ulong root_lba;
|
||||
public ulong chunk_lba;
|
||||
public ulong log_lba;
|
||||
public ulong log_root_transid;
|
||||
public ulong total_bytes;
|
||||
public ulong bytes_used;
|
||||
public ulong root_dir_objectid;
|
||||
public ulong num_devices;
|
||||
public uint sectorsize;
|
||||
public uint nodesize;
|
||||
public uint leafsize;
|
||||
public uint stripesize;
|
||||
public uint n;
|
||||
public ulong chunk_root_generation;
|
||||
public ulong compat_flags;
|
||||
public ulong compat_ro_flags;
|
||||
public ulong incompat_flags;
|
||||
public ushort csum_type;
|
||||
public byte root_level;
|
||||
public byte chunk_root_level;
|
||||
public byte log_root_level;
|
||||
public DevItem dev_item;
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 0x100)] public string label;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x100)] public byte[] reserved;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x800)] public byte[] chunkpairs;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x4D5)] public byte[] unused;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct DevItem
|
||||
{
|
||||
public ulong id;
|
||||
public ulong bytes;
|
||||
public ulong used;
|
||||
public uint optimal_align;
|
||||
public uint optimal_width;
|
||||
public uint minimal_size;
|
||||
public ulong type;
|
||||
public ulong generation;
|
||||
public ulong start_offset;
|
||||
public uint dev_group;
|
||||
public byte seek_speed;
|
||||
public byte bandwitdh;
|
||||
public Guid device_uuid;
|
||||
public Guid uuid;
|
||||
}
|
||||
|
||||
public override bool Identify(ImagePlugin imagePlugin, Partition partition)
|
||||
{
|
||||
if(partition.Start >= partition.End) return false;
|
||||
@@ -153,8 +97,7 @@ namespace DiscImageChef.Filesystems
|
||||
return btrfsSb.magic == btrfsMagic;
|
||||
}
|
||||
|
||||
public override void GetInformation(ImagePlugin imagePlugin, Partition partition,
|
||||
out string information)
|
||||
public override void GetInformation(ImagePlugin imagePlugin, Partition partition, out string information)
|
||||
{
|
||||
StringBuilder sbInformation = new StringBuilder();
|
||||
XmlFsType = new FileSystemType();
|
||||
@@ -312,5 +255,61 @@ namespace DiscImageChef.Filesystems
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct SuperBlock
|
||||
{
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x20)] public byte[] checksum;
|
||||
public Guid uuid;
|
||||
public ulong pba;
|
||||
public ulong flags;
|
||||
public ulong magic;
|
||||
public ulong generation;
|
||||
public ulong root_lba;
|
||||
public ulong chunk_lba;
|
||||
public ulong log_lba;
|
||||
public ulong log_root_transid;
|
||||
public ulong total_bytes;
|
||||
public ulong bytes_used;
|
||||
public ulong root_dir_objectid;
|
||||
public ulong num_devices;
|
||||
public uint sectorsize;
|
||||
public uint nodesize;
|
||||
public uint leafsize;
|
||||
public uint stripesize;
|
||||
public uint n;
|
||||
public ulong chunk_root_generation;
|
||||
public ulong compat_flags;
|
||||
public ulong compat_ro_flags;
|
||||
public ulong incompat_flags;
|
||||
public ushort csum_type;
|
||||
public byte root_level;
|
||||
public byte chunk_root_level;
|
||||
public byte log_root_level;
|
||||
public DevItem dev_item;
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 0x100)] public string label;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x100)] public byte[] reserved;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x800)] public byte[] chunkpairs;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x4D5)] public byte[] unused;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct DevItem
|
||||
{
|
||||
public ulong id;
|
||||
public ulong bytes;
|
||||
public ulong used;
|
||||
public uint optimal_align;
|
||||
public uint optimal_width;
|
||||
public uint minimal_size;
|
||||
public ulong type;
|
||||
public ulong generation;
|
||||
public ulong start_offset;
|
||||
public uint dev_group;
|
||||
public byte seek_speed;
|
||||
public byte bandwitdh;
|
||||
public Guid device_uuid;
|
||||
public Guid uuid;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -65,124 +65,6 @@ namespace DiscImageChef.Filesystems
|
||||
CurrentEncoding = new PETSCII();
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct CommodoreBAM
|
||||
{
|
||||
/// <summary>
|
||||
/// Track where directory starts
|
||||
/// </summary>
|
||||
public byte directoryTrack;
|
||||
/// <summary>
|
||||
/// Sector where directory starts
|
||||
/// </summary>
|
||||
public byte directorySector;
|
||||
/// <summary>
|
||||
/// Disk DOS version, 0x41
|
||||
/// </summary>
|
||||
public byte dosVersion;
|
||||
/// <summary>
|
||||
/// Set to 0x80 if 1571, 0x00 if not
|
||||
/// </summary>
|
||||
public byte doubleSided;
|
||||
/// <summary>
|
||||
/// Block allocation map
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 140)] public byte[] bam;
|
||||
/// <summary>
|
||||
/// Disk name
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] public byte[] name;
|
||||
/// <summary>
|
||||
/// Filled with 0xA0
|
||||
/// </summary>
|
||||
public ushort fill1;
|
||||
/// <summary>
|
||||
/// Disk ID
|
||||
/// </summary>
|
||||
public ushort diskId;
|
||||
/// <summary>
|
||||
/// Filled with 0xA0
|
||||
/// </summary>
|
||||
public byte fill2;
|
||||
/// <summary>
|
||||
/// DOS type
|
||||
/// </summary>
|
||||
public ushort dosType;
|
||||
/// <summary>
|
||||
/// Filled with 0xA0
|
||||
/// </summary>
|
||||
public uint fill3;
|
||||
/// <summary>
|
||||
/// Unused
|
||||
/// </summary>
|
||||
public byte unused1;
|
||||
/// <summary>
|
||||
/// Block allocation map for Dolphin DOS extended tracks
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)] public byte[] dolphinBam;
|
||||
/// <summary>
|
||||
/// Block allocation map for Speed DOS extended tracks
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)] public byte[] speedBam;
|
||||
/// <summary>
|
||||
/// Unused
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 9)] public byte[] unused2;
|
||||
/// <summary>
|
||||
/// Free sector count for second side in 1571
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 9)] public byte[] freeCount;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct CommodoreHeader
|
||||
{
|
||||
/// <summary>
|
||||
/// Track where directory starts
|
||||
/// </summary>
|
||||
public byte directoryTrack;
|
||||
/// <summary>
|
||||
/// Sector where directory starts
|
||||
/// </summary>
|
||||
public byte directorySector;
|
||||
/// <summary>
|
||||
/// Disk DOS version, 0x44
|
||||
/// </summary>
|
||||
public byte diskDosVersion;
|
||||
/// <summary>
|
||||
/// Unusued
|
||||
/// </summary>
|
||||
public byte unused1;
|
||||
/// <summary>
|
||||
/// Disk name
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] public byte[] name;
|
||||
/// <summary>
|
||||
/// Filled with 0xA0
|
||||
/// </summary>
|
||||
public ushort fill1;
|
||||
/// <summary>
|
||||
/// Disk ID
|
||||
/// </summary>
|
||||
public ushort diskId;
|
||||
/// <summary>
|
||||
/// Filled with 0xA0
|
||||
/// </summary>
|
||||
public byte fill2;
|
||||
/// <summary>
|
||||
/// DOS version ('3')
|
||||
/// </summary>
|
||||
public byte dosVersion;
|
||||
/// <summary>
|
||||
/// Disk version ('D')
|
||||
/// </summary>
|
||||
public byte diskVersion;
|
||||
/// <summary>
|
||||
/// Filled with 0xA0
|
||||
/// </summary>
|
||||
public short fill3;
|
||||
}
|
||||
|
||||
public override bool Identify(ImagePlugin imagePlugin, Partition partition)
|
||||
{
|
||||
if(partition.Start > 0) return false;
|
||||
@@ -222,8 +104,7 @@ namespace DiscImageChef.Filesystems
|
||||
return false;
|
||||
}
|
||||
|
||||
public override void GetInformation(ImagePlugin imagePlugin, Partition partition,
|
||||
out string information)
|
||||
public override void GetInformation(ImagePlugin imagePlugin, Partition partition, out string information)
|
||||
{
|
||||
byte[] sector;
|
||||
|
||||
@@ -249,13 +130,13 @@ namespace DiscImageChef.Filesystems
|
||||
|
||||
sbInformation.AppendFormat("Directory starts at track {0} sector {1}", cbmHdr.directoryTrack,
|
||||
cbmHdr.directorySector).AppendLine();
|
||||
sbInformation.AppendFormat("Disk DOS Version: {0}",
|
||||
Encoding.ASCII.GetString(new[] {cbmHdr.diskDosVersion})).AppendLine();
|
||||
sbInformation
|
||||
.AppendFormat("Disk DOS Version: {0}", Encoding.ASCII.GetString(new[] {cbmHdr.diskDosVersion}))
|
||||
.AppendLine();
|
||||
sbInformation.AppendFormat("DOS Version: {0}", Encoding.ASCII.GetString(new[] {cbmHdr.dosVersion}))
|
||||
.AppendLine();
|
||||
sbInformation
|
||||
.AppendFormat("Disk Version: {0}", Encoding.ASCII.GetString(new[] {cbmHdr.diskVersion}))
|
||||
.AppendLine();
|
||||
sbInformation.AppendFormat("Disk Version: {0}", Encoding.ASCII.GetString(new[] {cbmHdr.diskVersion}))
|
||||
.AppendLine();
|
||||
sbInformation.AppendFormat("Disk ID: {0}", cbmHdr.diskId).AppendLine();
|
||||
sbInformation.AppendFormat("Disk name: {0}", StringHandlers.CToString(cbmHdr.name, CurrentEncoding))
|
||||
.AppendLine();
|
||||
@@ -349,5 +230,123 @@ namespace DiscImageChef.Filesystems
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct CommodoreBAM
|
||||
{
|
||||
/// <summary>
|
||||
/// Track where directory starts
|
||||
/// </summary>
|
||||
public byte directoryTrack;
|
||||
/// <summary>
|
||||
/// Sector where directory starts
|
||||
/// </summary>
|
||||
public byte directorySector;
|
||||
/// <summary>
|
||||
/// Disk DOS version, 0x41
|
||||
/// </summary>
|
||||
public byte dosVersion;
|
||||
/// <summary>
|
||||
/// Set to 0x80 if 1571, 0x00 if not
|
||||
/// </summary>
|
||||
public byte doubleSided;
|
||||
/// <summary>
|
||||
/// Block allocation map
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 140)] public byte[] bam;
|
||||
/// <summary>
|
||||
/// Disk name
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] public byte[] name;
|
||||
/// <summary>
|
||||
/// Filled with 0xA0
|
||||
/// </summary>
|
||||
public ushort fill1;
|
||||
/// <summary>
|
||||
/// Disk ID
|
||||
/// </summary>
|
||||
public ushort diskId;
|
||||
/// <summary>
|
||||
/// Filled with 0xA0
|
||||
/// </summary>
|
||||
public byte fill2;
|
||||
/// <summary>
|
||||
/// DOS type
|
||||
/// </summary>
|
||||
public ushort dosType;
|
||||
/// <summary>
|
||||
/// Filled with 0xA0
|
||||
/// </summary>
|
||||
public uint fill3;
|
||||
/// <summary>
|
||||
/// Unused
|
||||
/// </summary>
|
||||
public byte unused1;
|
||||
/// <summary>
|
||||
/// Block allocation map for Dolphin DOS extended tracks
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)] public byte[] dolphinBam;
|
||||
/// <summary>
|
||||
/// Block allocation map for Speed DOS extended tracks
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)] public byte[] speedBam;
|
||||
/// <summary>
|
||||
/// Unused
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 9)] public byte[] unused2;
|
||||
/// <summary>
|
||||
/// Free sector count for second side in 1571
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 9)] public byte[] freeCount;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct CommodoreHeader
|
||||
{
|
||||
/// <summary>
|
||||
/// Track where directory starts
|
||||
/// </summary>
|
||||
public byte directoryTrack;
|
||||
/// <summary>
|
||||
/// Sector where directory starts
|
||||
/// </summary>
|
||||
public byte directorySector;
|
||||
/// <summary>
|
||||
/// Disk DOS version, 0x44
|
||||
/// </summary>
|
||||
public byte diskDosVersion;
|
||||
/// <summary>
|
||||
/// Unusued
|
||||
/// </summary>
|
||||
public byte unused1;
|
||||
/// <summary>
|
||||
/// Disk name
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] public byte[] name;
|
||||
/// <summary>
|
||||
/// Filled with 0xA0
|
||||
/// </summary>
|
||||
public ushort fill1;
|
||||
/// <summary>
|
||||
/// Disk ID
|
||||
/// </summary>
|
||||
public ushort diskId;
|
||||
/// <summary>
|
||||
/// Filled with 0xA0
|
||||
/// </summary>
|
||||
public byte fill2;
|
||||
/// <summary>
|
||||
/// DOS version ('3')
|
||||
/// </summary>
|
||||
public byte dosVersion;
|
||||
/// <summary>
|
||||
/// Disk version ('D')
|
||||
/// </summary>
|
||||
public byte diskVersion;
|
||||
/// <summary>
|
||||
/// Filled with 0xA0
|
||||
/// </summary>
|
||||
public short fill3;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -40,75 +40,75 @@ namespace DiscImageChef.Filesystems.CPM
|
||||
{
|
||||
partial class CPM : Filesystem
|
||||
{
|
||||
bool mounted;
|
||||
readonly ImagePlugin device;
|
||||
Partition partition;
|
||||
|
||||
/// <summary>
|
||||
/// Stores all known CP/M disk definitions
|
||||
/// </summary>
|
||||
CpmDefinitions definitions;
|
||||
/// <summary>
|
||||
/// True if <see cref="Identify"/> thinks this is a CP/M filesystem
|
||||
/// True if <see cref="Identify" /> thinks this is a CP/M filesystem
|
||||
/// </summary>
|
||||
bool cpmFound;
|
||||
/// <summary>
|
||||
/// If <see cref="Identify"/> thinks this is a CP/M filesystem, this is the definition for it
|
||||
/// </summary>
|
||||
CpmDefinition workingDefinition;
|
||||
/// <summary>
|
||||
/// CP/M disc parameter block (on-memory)
|
||||
/// </summary>
|
||||
DiscParameterBlock dpb;
|
||||
/// <summary>
|
||||
/// Sector deinterleaving mask
|
||||
/// </summary>
|
||||
int[] sectorMask;
|
||||
/// <summary>
|
||||
/// The volume label, if the CP/M filesystem contains one
|
||||
/// </summary>
|
||||
string label;
|
||||
/// <summary>
|
||||
/// True if there are timestamps in Z80DOS or DOS+ format
|
||||
/// </summary>
|
||||
bool thirdPartyTimestamps;
|
||||
/// <summary>
|
||||
/// True if there are CP/M 3 timestamps
|
||||
/// </summary>
|
||||
bool standardTimestamps;
|
||||
/// <summary>
|
||||
/// Timestamp in volume label for creation
|
||||
/// </summary>
|
||||
byte[] labelCreationDate;
|
||||
/// <summary>
|
||||
/// Timestamp in volume label for update
|
||||
/// </summary>
|
||||
byte[] labelUpdateDate;
|
||||
|
||||
/// <summary>
|
||||
/// Cached <see cref="FileSystemInfo"/>
|
||||
/// Cached <see cref="FileSystemInfo" />
|
||||
/// </summary>
|
||||
FileSystemInfo cpmStat;
|
||||
/// <summary>
|
||||
/// Cached directory listing
|
||||
/// Cached file passwords, decoded
|
||||
/// </summary>
|
||||
Dictionary<string, byte[]> decodedPasswordCache;
|
||||
|
||||
/// <summary>
|
||||
/// Stores all known CP/M disk definitions
|
||||
/// </summary>
|
||||
CpmDefinitions definitions;
|
||||
/// <summary>
|
||||
/// Cached directory listing
|
||||
/// </summary>
|
||||
List<string> dirList;
|
||||
/// <summary>
|
||||
/// Cached file data
|
||||
/// CP/M disc parameter block (on-memory)
|
||||
/// </summary>
|
||||
DiscParameterBlock dpb;
|
||||
/// <summary>
|
||||
/// Cached file data
|
||||
/// </summary>
|
||||
Dictionary<string, byte[]> fileCache;
|
||||
/// <summary>
|
||||
/// Cached file <see cref="FileEntryInfo"/>
|
||||
/// The volume label, if the CP/M filesystem contains one
|
||||
/// </summary>
|
||||
Dictionary<string, FileEntryInfo> statCache;
|
||||
string label;
|
||||
/// <summary>
|
||||
/// Cached file passwords
|
||||
/// Timestamp in volume label for creation
|
||||
/// </summary>
|
||||
byte[] labelCreationDate;
|
||||
/// <summary>
|
||||
/// Timestamp in volume label for update
|
||||
/// </summary>
|
||||
byte[] labelUpdateDate;
|
||||
bool mounted;
|
||||
Partition partition;
|
||||
/// <summary>
|
||||
/// Cached file passwords
|
||||
/// </summary>
|
||||
Dictionary<string, byte[]> passwordCache;
|
||||
/// <summary>
|
||||
/// Cached file passwords, decoded
|
||||
/// Sector deinterleaving mask
|
||||
/// </summary>
|
||||
Dictionary<string, byte[]> decodedPasswordCache;
|
||||
int[] sectorMask;
|
||||
/// <summary>
|
||||
/// True if there are CP/M 3 timestamps
|
||||
/// </summary>
|
||||
bool standardTimestamps;
|
||||
/// <summary>
|
||||
/// Cached file <see cref="FileEntryInfo" />
|
||||
/// </summary>
|
||||
Dictionary<string, FileEntryInfo> statCache;
|
||||
/// <summary>
|
||||
/// True if there are timestamps in Z80DOS or DOS+ format
|
||||
/// </summary>
|
||||
bool thirdPartyTimestamps;
|
||||
/// <summary>
|
||||
/// If <see cref="Identify" /> thinks this is a CP/M filesystem, this is the definition for it
|
||||
/// </summary>
|
||||
CpmDefinition workingDefinition;
|
||||
|
||||
public CPM()
|
||||
{
|
||||
|
||||
@@ -35,48 +35,48 @@ namespace DiscImageChef.Filesystems.CPM
|
||||
partial class CPM
|
||||
{
|
||||
/// <summary>
|
||||
/// Enumerates the format identification byte used by CP/M-86
|
||||
/// Enumerates the format identification byte used by CP/M-86
|
||||
/// </summary>
|
||||
enum FormatByte : byte
|
||||
{
|
||||
/// <summary>
|
||||
/// 5.25" double-density single-side 8 sectors/track
|
||||
/// 5.25" double-density single-side 8 sectors/track
|
||||
/// </summary>
|
||||
k160 = 0,
|
||||
/// <summary>
|
||||
/// 5.25" double-density double-side 8 sectors/track
|
||||
/// 5.25" double-density double-side 8 sectors/track
|
||||
/// </summary>
|
||||
k320 = 1,
|
||||
/// <summary>
|
||||
/// 5.25" double-density double-side 9 sectors/track
|
||||
/// 5.25" double-density double-side 9 sectors/track
|
||||
/// </summary>
|
||||
k360 = 0x10,
|
||||
/// <summary>
|
||||
/// 5.25" double-density double-side 9 sectors/track
|
||||
/// 5.25" double-density double-side 9 sectors/track
|
||||
/// </summary>
|
||||
k360Alt = 0x40,
|
||||
/// <summary>
|
||||
/// 3.5" double-density double-side 9 sectors/track
|
||||
/// 3.5" double-density double-side 9 sectors/track
|
||||
/// </summary>
|
||||
k720 = 0x11,
|
||||
/// <summary>
|
||||
/// 3.5" double-density double-side 9 sectors/track using FEAT144
|
||||
/// 3.5" double-density double-side 9 sectors/track using FEAT144
|
||||
/// </summary>
|
||||
f720 = 0x48,
|
||||
/// <summary>
|
||||
/// 5.25" high-density double-side 15 sectors/track using FEAT144
|
||||
/// 5.25" high-density double-side 15 sectors/track using FEAT144
|
||||
/// </summary>
|
||||
f1200 = 0x0C,
|
||||
/// <summary>
|
||||
/// 3.5" high-density double-side 18 sectors/track using FEAT144
|
||||
/// 3.5" high-density double-side 18 sectors/track using FEAT144
|
||||
/// </summary>
|
||||
f1440 = 0x90,
|
||||
/// <summary>
|
||||
/// 5.25" double-density double-side 9 sectors/track
|
||||
/// 5.25" double-density double-side 9 sectors/track
|
||||
/// </summary>
|
||||
k360Alt2 = 0x26,
|
||||
/// <summary>
|
||||
/// 3.5" double-density double-side 9 sectors/track
|
||||
/// 3.5" double-density double-side 9 sectors/track
|
||||
/// </summary>
|
||||
k720Alt = 0x94
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ namespace DiscImageChef.Filesystems.CPM
|
||||
partial class CPM
|
||||
{
|
||||
/// <summary>
|
||||
/// Loads all the known CP/M disk definitions from an XML stored as an embedded resource.
|
||||
/// Loads all the known CP/M disk definitions from an XML stored as an embedded resource.
|
||||
/// </summary>
|
||||
/// <returns>The definitions.</returns>
|
||||
bool LoadDefinitions()
|
||||
@@ -50,7 +50,8 @@ namespace DiscImageChef.Filesystems.CPM
|
||||
{
|
||||
XmlReader defsReader =
|
||||
XmlReader.Create(Assembly.GetExecutingAssembly()
|
||||
.GetManifestResourceStream("DiscImageChef.Filesystems.CPM.cpmdefs.xml") ?? throw new InvalidOperationException());
|
||||
.GetManifestResourceStream("DiscImageChef.Filesystems.CPM.cpmdefs.xml") ??
|
||||
throw new InvalidOperationException());
|
||||
XmlSerializer defsSerializer = new XmlSerializer(typeof(CpmDefinitions));
|
||||
definitions = (CpmDefinitions)defsSerializer.Deserialize(defsReader);
|
||||
|
||||
@@ -78,131 +79,132 @@ namespace DiscImageChef.Filesystems.CPM
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// CP/M disk definitions
|
||||
/// CP/M disk definitions
|
||||
/// </summary>
|
||||
class CpmDefinitions
|
||||
{
|
||||
/// <summary>
|
||||
/// List of all CP/M disk definitions
|
||||
/// </summary>
|
||||
public List<CpmDefinition> definitions;
|
||||
/// <summary>
|
||||
/// Timestamp of creation of the CP/M disk definitions list
|
||||
/// Timestamp of creation of the CP/M disk definitions list
|
||||
/// </summary>
|
||||
public DateTime creation;
|
||||
/// <summary>
|
||||
/// List of all CP/M disk definitions
|
||||
/// </summary>
|
||||
public List<CpmDefinition> definitions;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// CP/M disk definition
|
||||
/// CP/M disk definition
|
||||
/// </summary>
|
||||
class CpmDefinition
|
||||
{
|
||||
/// <summary>
|
||||
/// Comment and description
|
||||
/// </summary>
|
||||
public string comment;
|
||||
/// <summary>
|
||||
/// Encoding, "FM", "MFM", "GCR"
|
||||
/// </summary>
|
||||
public string encoding;
|
||||
/// <summary>
|
||||
/// Controller bitrate
|
||||
/// </summary>
|
||||
public string bitrate;
|
||||
/// <summary>
|
||||
/// Total cylinders
|
||||
/// </summary>
|
||||
public int cylinders;
|
||||
/// <summary>
|
||||
/// Total sides
|
||||
/// </summary>
|
||||
public int sides;
|
||||
/// <summary>
|
||||
/// Physical sectors per side
|
||||
/// </summary>
|
||||
public int sectorsPerTrack;
|
||||
/// <summary>
|
||||
/// Physical bytes per sector
|
||||
/// </summary>
|
||||
public int bytesPerSector;
|
||||
/// <summary>
|
||||
/// Physical sector interleaving
|
||||
/// </summary>
|
||||
public int skew;
|
||||
/// <summary>
|
||||
/// Description of controller's side 0 (usually, upper side)
|
||||
/// </summary>
|
||||
public Side side1;
|
||||
/// <summary>
|
||||
/// Description of controller's side 1 (usually, lower side)
|
||||
/// </summary>
|
||||
public Side side2;
|
||||
/// <summary>
|
||||
/// Cylinder/side ordering. SIDES = change side after each track, CYLINDERS = change side after whole side, EAGLE and COLUMBIA unknown
|
||||
/// </summary>
|
||||
public string order;
|
||||
/// <summary>
|
||||
/// Disk definition label
|
||||
/// </summary>
|
||||
public string label;
|
||||
/// <summary>
|
||||
/// Left shifts needed to translate allocation block number to lba
|
||||
/// </summary>
|
||||
public int bsh;
|
||||
/// <summary>
|
||||
/// Block mask for <see cref="bsh"/>
|
||||
/// </summary>
|
||||
public int blm;
|
||||
/// <summary>
|
||||
/// Extent mask
|
||||
/// </summary>
|
||||
public int exm;
|
||||
/// <summary>
|
||||
/// Total number of 128 byte records on disk
|
||||
/// </summary>
|
||||
public int dsm;
|
||||
/// <summary>
|
||||
/// Total number of available directory entries
|
||||
/// </summary>
|
||||
public int drm;
|
||||
/// <summary>
|
||||
/// Maps the first 16 allocation blocks for reservation, high byte
|
||||
/// Maps the first 16 allocation blocks for reservation, high byte
|
||||
/// </summary>
|
||||
public int al0;
|
||||
/// <summary>
|
||||
/// Maps the first 16 allocation blocks for reservation, low byte
|
||||
/// Maps the first 16 allocation blocks for reservation, low byte
|
||||
/// </summary>
|
||||
public int al1;
|
||||
/// <summary>
|
||||
/// Tracks at the beginning of disk reserved for BIOS/BDOS
|
||||
/// Controller bitrate
|
||||
/// </summary>
|
||||
public int ofs;
|
||||
public string bitrate;
|
||||
/// <summary>
|
||||
/// Sectors at the beginning of disk reserved for BIOS/BDOS
|
||||
/// Block mask for <see cref="bsh" />
|
||||
/// </summary>
|
||||
public int sofs;
|
||||
public int blm;
|
||||
/// <summary>
|
||||
/// If true, all bytes written on disk are negated
|
||||
/// Left shifts needed to translate allocation block number to lba
|
||||
/// </summary>
|
||||
public int bsh;
|
||||
/// <summary>
|
||||
/// Physical bytes per sector
|
||||
/// </summary>
|
||||
public int bytesPerSector;
|
||||
/// <summary>
|
||||
/// Comment and description
|
||||
/// </summary>
|
||||
public string comment;
|
||||
/// <summary>
|
||||
/// If true, all bytes written on disk are negated
|
||||
/// </summary>
|
||||
public bool complement;
|
||||
/// <summary>
|
||||
/// Absolutely unknown?
|
||||
/// Total cylinders
|
||||
/// </summary>
|
||||
public int cylinders;
|
||||
/// <summary>
|
||||
/// Total number of available directory entries
|
||||
/// </summary>
|
||||
public int drm;
|
||||
/// <summary>
|
||||
/// Total number of 128 byte records on disk
|
||||
/// </summary>
|
||||
public int dsm;
|
||||
/// <summary>
|
||||
/// Encoding, "FM", "MFM", "GCR"
|
||||
/// </summary>
|
||||
public string encoding;
|
||||
/// <summary>
|
||||
/// Absolutely unknown?
|
||||
/// </summary>
|
||||
public bool evenOdd;
|
||||
/// <summary>
|
||||
/// Extent mask
|
||||
/// </summary>
|
||||
public int exm;
|
||||
/// <summary>
|
||||
/// Disk definition label
|
||||
/// </summary>
|
||||
public string label;
|
||||
/// <summary>
|
||||
/// Tracks at the beginning of disk reserved for BIOS/BDOS
|
||||
/// </summary>
|
||||
public int ofs;
|
||||
/// <summary>
|
||||
/// Cylinder/side ordering. SIDES = change side after each track, CYLINDERS = change side after whole side, EAGLE and
|
||||
/// COLUMBIA unknown
|
||||
/// </summary>
|
||||
public string order;
|
||||
/// <summary>
|
||||
/// Physical sectors per side
|
||||
/// </summary>
|
||||
public int sectorsPerTrack;
|
||||
/// <summary>
|
||||
/// Description of controller's side 0 (usually, upper side)
|
||||
/// </summary>
|
||||
public Side side1;
|
||||
/// <summary>
|
||||
/// Description of controller's side 1 (usually, lower side)
|
||||
/// </summary>
|
||||
public Side side2;
|
||||
/// <summary>
|
||||
/// Total sides
|
||||
/// </summary>
|
||||
public int sides;
|
||||
/// <summary>
|
||||
/// Physical sector interleaving
|
||||
/// </summary>
|
||||
public int skew;
|
||||
/// <summary>
|
||||
/// Sectors at the beginning of disk reserved for BIOS/BDOS
|
||||
/// </summary>
|
||||
public int sofs;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Side descriptions
|
||||
/// Side descriptions
|
||||
/// </summary>
|
||||
class Side
|
||||
{
|
||||
/// <summary>
|
||||
/// Side ID as found in each sector address mark
|
||||
/// </summary>
|
||||
public int sideId;
|
||||
/// <summary>
|
||||
/// Software interleaving mask, [1,3,0,2] means CP/M LBA 0 is physical sector 1, LBA 1 = 3, so on
|
||||
/// Software interleaving mask, [1,3,0,2] means CP/M LBA 0 is physical sector 1, LBA 1 = 3, so on
|
||||
/// </summary>
|
||||
public int[] sectorIds;
|
||||
/// <summary>
|
||||
/// Side ID as found in each sector address mark
|
||||
/// </summary>
|
||||
public int sideId;
|
||||
}
|
||||
}
|
||||
@@ -52,10 +52,10 @@ namespace DiscImageChef.Filesystems.CPM
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks that the given directory blocks follow the CP/M filesystem directory specification
|
||||
/// Corrupted directories will fail.
|
||||
/// FAT firectories will false positive if all files start with 0x05, and do not use full extentions, for example:
|
||||
/// "σAFILE.GZ" (using code page 437)
|
||||
/// Checks that the given directory blocks follow the CP/M filesystem directory specification
|
||||
/// Corrupted directories will fail.
|
||||
/// FAT firectories will false positive if all files start with 0x05, and do not use full extentions, for example:
|
||||
/// "σAFILE.GZ" (using code page 437)
|
||||
/// </summary>
|
||||
/// <returns>False if the directory does not follow the directory specification</returns>
|
||||
/// <param name="directory">Directory blocks.</param>
|
||||
@@ -76,17 +76,21 @@ namespace DiscImageChef.Filesystems.CPM
|
||||
|
||||
if((entry.statusUser & 0x7F) < 0x20)
|
||||
{
|
||||
for(int f = 0; f < 8; f++) if(entry.filename[f] < 0x20 && entry.filename[f] != 0x00) return false;
|
||||
for(int f = 0; f < 8; f++)
|
||||
if(entry.filename[f] < 0x20 && entry.filename[f] != 0x00) return false;
|
||||
|
||||
for(int e = 0; e < 3; e++) if(entry.extension[e] < 0x20 && entry.extension[e] != 0x00) return false;
|
||||
for(int e = 0; e < 3; e++)
|
||||
if(entry.extension[e] < 0x20 && entry.extension[e] != 0x00) return false;
|
||||
|
||||
if(!ArrayHelpers.ArrayIsNullOrWhiteSpace(entry.filename)) fileCount++;
|
||||
}
|
||||
else if(entry.statusUser == 0x20)
|
||||
{
|
||||
for(int f = 0; f < 8; f++) if(entry.filename[f] < 0x20 && entry.filename[f] != 0x00) return false;
|
||||
for(int f = 0; f < 8; f++)
|
||||
if(entry.filename[f] < 0x20 && entry.filename[f] != 0x00) return false;
|
||||
|
||||
for(int e = 0; e < 3; e++) if(entry.extension[e] < 0x20 && entry.extension[e] != 0x00) return false;
|
||||
for(int e = 0; e < 3; e++)
|
||||
if(entry.extension[e] < 0x20 && entry.extension[e] != 0x00) return false;
|
||||
|
||||
label = Encoding.ASCII.GetString(directory, off + 1, 11).Trim();
|
||||
labelCreationDate = new byte[4];
|
||||
|
||||
@@ -51,7 +51,8 @@ namespace DiscImageChef.Filesystems.CPM
|
||||
return Errno.NoError;
|
||||
}
|
||||
|
||||
if(!statCache.TryGetValue(pathElements[0].ToUpperInvariant(), out FileEntryInfo fInfo)) return Errno.NoSuchFile;
|
||||
if(!statCache.TryGetValue(pathElements[0].ToUpperInvariant(), out FileEntryInfo fInfo))
|
||||
return Errno.NoSuchFile;
|
||||
|
||||
attributes = fInfo.Attributes;
|
||||
return Errno.NoError;
|
||||
@@ -91,9 +92,7 @@ namespace DiscImageChef.Filesystems.CPM
|
||||
|
||||
public override Errno ReadLink(string path, ref string dest)
|
||||
{
|
||||
if(!mounted) return Errno.AccessDenied;
|
||||
|
||||
return Errno.NotSupported;
|
||||
return !mounted ? Errno.AccessDenied : Errno.NotSupported;
|
||||
}
|
||||
|
||||
public override Errno Stat(string path, ref FileEntryInfo stat)
|
||||
@@ -112,9 +111,9 @@ namespace DiscImageChef.Filesystems.CPM
|
||||
return Errno.NoError;
|
||||
}
|
||||
|
||||
if(statCache.TryGetValue(pathElements[0].ToUpperInvariant(), out stat)) return Errno.NoError;
|
||||
|
||||
return Errno.NoSuchFile;
|
||||
return statCache.TryGetValue(pathElements[0].ToUpperInvariant(), out stat)
|
||||
? Errno.NoError
|
||||
: Errno.NoSuchFile;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -264,12 +264,16 @@ namespace DiscImageChef.Filesystems.CPM
|
||||
|
||||
if(amsSb.format == 2)
|
||||
{
|
||||
switch(amsSb.sidedness & 0x02) {
|
||||
case 1: workingDefinition.order = "SIDES";
|
||||
switch(amsSb.sidedness & 0x02)
|
||||
{
|
||||
case 1:
|
||||
workingDefinition.order = "SIDES";
|
||||
break;
|
||||
case 2: workingDefinition.order = "CYLINDERS";
|
||||
case 2:
|
||||
workingDefinition.order = "CYLINDERS";
|
||||
break;
|
||||
default: workingDefinition.order = null;
|
||||
default:
|
||||
workingDefinition.order = null;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -373,7 +377,6 @@ namespace DiscImageChef.Filesystems.CPM
|
||||
for(int si = 0; si < hddSb.sectorsPerTrack; si++)
|
||||
workingDefinition.side1.sectorIds[si] = si + 1;
|
||||
for(int si = 0; si < hddSb.spt; si++) workingDefinition.side2.sectorIds[si] = si + 1;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -787,7 +790,13 @@ namespace DiscImageChef.Filesystems.CPM
|
||||
if(LoadDefinitions() && definitions?.definitions != null && definitions.definitions.Count > 0)
|
||||
{
|
||||
DicConsole.DebugWriteLine("CP/M Plugin", "Trying all known definitions.");
|
||||
foreach(CpmDefinition def in from def in definitions.definitions let sectors = (ulong)(def.cylinders * def.sides * def.sectorsPerTrack) where sectors == imagePlugin.GetSectors() && def.bytesPerSector == imagePlugin.GetSectorSize() select def) {
|
||||
foreach(CpmDefinition def in from def in definitions.definitions
|
||||
let sectors =
|
||||
(ulong)(def.cylinders * def.sides * def.sectorsPerTrack)
|
||||
where sectors == imagePlugin.GetSectors() &&
|
||||
def.bytesPerSector == imagePlugin.GetSectorSize()
|
||||
select def)
|
||||
{
|
||||
// Definition seems to describe current disk, at least, same number of volume sectors and bytes per sector
|
||||
DicConsole.DebugWriteLine("CP/M Plugin", "Trying definition \"{0}\"", def.comment);
|
||||
ulong offset;
|
||||
@@ -805,8 +814,7 @@ namespace DiscImageChef.Filesystems.CPM
|
||||
else
|
||||
{
|
||||
// Head changes after every track
|
||||
if(string.Compare(def.order, "SIDES",
|
||||
StringComparison.InvariantCultureIgnoreCase) == 0)
|
||||
if(string.Compare(def.order, "SIDES", StringComparison.InvariantCultureIgnoreCase) == 0)
|
||||
{
|
||||
sectorMask = new int[def.side1.sectorIds.Length + def.side2.sectorIds.Length];
|
||||
for(int m = 0; m < def.side1.sectorIds.Length; m++)
|
||||
@@ -838,8 +846,9 @@ namespace DiscImageChef.Filesystems.CPM
|
||||
continue;
|
||||
}
|
||||
// TODO: Implement EAGLE ordering
|
||||
else if(string.Compare(def.order, "EAGLE",
|
||||
StringComparison.InvariantCultureIgnoreCase) == 0)
|
||||
else if(
|
||||
string.Compare(def.order, "EAGLE", StringComparison.InvariantCultureIgnoreCase) == 0
|
||||
)
|
||||
{
|
||||
DicConsole.DebugWriteLine("CP/M Plugin",
|
||||
"Don't know how to handle EAGLE ordering, not proceeding with this definition.");
|
||||
@@ -873,14 +882,12 @@ namespace DiscImageChef.Filesystems.CPM
|
||||
|
||||
// Complement of the directory bytes if needed
|
||||
if(def.complement)
|
||||
for(int b = 0; b < directory.Length; b++)
|
||||
directory[b] = (byte)(~directory[b] & 0xFF);
|
||||
for(int b = 0; b < directory.Length; b++) directory[b] = (byte)(~directory[b] & 0xFF);
|
||||
|
||||
// Check the directory
|
||||
if(CheckDir(directory))
|
||||
{
|
||||
DicConsole.DebugWriteLine("CP/M Plugin",
|
||||
"Definition \"{0}\" has a correct directory",
|
||||
DicConsole.DebugWriteLine("CP/M Plugin", "Definition \"{0}\" has a correct directory",
|
||||
def.comment);
|
||||
|
||||
// Build a Disc Parameter Block
|
||||
|
||||
@@ -37,496 +37,499 @@ namespace DiscImageChef.Filesystems.CPM
|
||||
partial class CPM
|
||||
{
|
||||
/// <summary>
|
||||
/// Most of the times this structure is hard wired or generated by CP/M, not stored on disk
|
||||
/// Most of the times this structure is hard wired or generated by CP/M, not stored on disk
|
||||
/// </summary>
|
||||
class DiscParameterBlock
|
||||
{
|
||||
/// <summary>
|
||||
/// Sectors per track
|
||||
/// </summary>
|
||||
public ushort spt;
|
||||
/// <summary>
|
||||
/// Block shift
|
||||
/// </summary>
|
||||
public byte bsh;
|
||||
/// <summary>
|
||||
/// Block mask
|
||||
/// </summary>
|
||||
public byte blm;
|
||||
/// <summary>
|
||||
/// Extent mask
|
||||
/// </summary>
|
||||
public byte exm;
|
||||
/// <summary>
|
||||
/// Blocks on disk - 1
|
||||
/// </summary>
|
||||
public ushort dsm;
|
||||
/// <summary>
|
||||
/// Directory entries - 1
|
||||
/// </summary>
|
||||
public ushort drm;
|
||||
/// <summary>
|
||||
/// First byte of allocation bitmap
|
||||
/// First byte of allocation bitmap
|
||||
/// </summary>
|
||||
public byte al0;
|
||||
/// <summary>
|
||||
/// Second byte of allocation bitmap
|
||||
/// Second byte of allocation bitmap
|
||||
/// </summary>
|
||||
public byte al1;
|
||||
/// <summary>
|
||||
/// Checksum vector size
|
||||
/// Block mask
|
||||
/// </summary>
|
||||
public byte blm;
|
||||
/// <summary>
|
||||
/// Block shift
|
||||
/// </summary>
|
||||
public byte bsh;
|
||||
/// <summary>
|
||||
/// Checksum vector size
|
||||
/// </summary>
|
||||
public ushort cks;
|
||||
/// <summary>
|
||||
/// Reserved tracks
|
||||
/// Directory entries - 1
|
||||
/// </summary>
|
||||
public ushort drm;
|
||||
/// <summary>
|
||||
/// Blocks on disk - 1
|
||||
/// </summary>
|
||||
public ushort dsm;
|
||||
/// <summary>
|
||||
/// Extent mask
|
||||
/// </summary>
|
||||
public byte exm;
|
||||
/// <summary>
|
||||
/// Reserved tracks
|
||||
/// </summary>
|
||||
public ushort off;
|
||||
/// <summary>
|
||||
/// Physical sector shift
|
||||
/// Physical sector mask
|
||||
/// </summary>
|
||||
public byte phm;
|
||||
/// <summary>
|
||||
/// Physical sector shift
|
||||
/// </summary>
|
||||
public byte psh;
|
||||
/// <summary>
|
||||
/// Physical sector mask
|
||||
/// Sectors per track
|
||||
/// </summary>
|
||||
public byte phm;
|
||||
public ushort spt;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Amstrad superblock, for PCW
|
||||
/// Amstrad superblock, for PCW
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct AmstradSuperBlock
|
||||
{
|
||||
/// <summary>
|
||||
/// Format ID. 0 single-side, 3 double-side. 1 and 2 are for CPC but they don't use the superblock
|
||||
/// Format ID. 0 single-side, 3 double-side. 1 and 2 are for CPC but they don't use the superblock
|
||||
/// </summary>
|
||||
public byte format;
|
||||
/// <summary>
|
||||
/// Gives information about side ordering
|
||||
/// Gives information about side ordering
|
||||
/// </summary>
|
||||
public byte sidedness;
|
||||
/// <summary>
|
||||
/// Tracks per side, aka, cylinders
|
||||
/// Tracks per side, aka, cylinders
|
||||
/// </summary>
|
||||
public byte tps;
|
||||
/// <summary>
|
||||
/// Sectors per track
|
||||
/// Sectors per track
|
||||
/// </summary>
|
||||
public byte spt;
|
||||
/// <summary>
|
||||
/// Physical sector shift
|
||||
/// Physical sector shift
|
||||
/// </summary>
|
||||
public byte psh;
|
||||
/// <summary>
|
||||
/// Reserved tracks
|
||||
/// Reserved tracks
|
||||
/// </summary>
|
||||
public byte off;
|
||||
/// <summary>
|
||||
/// Block size shift
|
||||
/// Block size shift
|
||||
/// </summary>
|
||||
public byte bsh;
|
||||
/// <summary>
|
||||
/// How many blocks does the directory take
|
||||
/// How many blocks does the directory take
|
||||
/// </summary>
|
||||
public byte dirBlocks;
|
||||
/// <summary>
|
||||
/// GAP#3 length (intersector)
|
||||
/// GAP#3 length (intersector)
|
||||
/// </summary>
|
||||
public byte gapLen;
|
||||
/// <summary>
|
||||
/// GAP#4 length (end-of-track)
|
||||
/// GAP#4 length (end-of-track)
|
||||
/// </summary>
|
||||
public byte formatGap;
|
||||
/// <summary>
|
||||
/// Must be 0
|
||||
/// Must be 0
|
||||
/// </summary>
|
||||
public byte zero1;
|
||||
/// <summary>
|
||||
/// Must be 0
|
||||
/// Must be 0
|
||||
/// </summary>
|
||||
public byte zero2;
|
||||
/// <summary>
|
||||
/// Must be 0
|
||||
/// Must be 0
|
||||
/// </summary>
|
||||
public byte zero3;
|
||||
/// <summary>
|
||||
/// Must be 0
|
||||
/// Must be 0
|
||||
/// </summary>
|
||||
public byte zero4;
|
||||
/// <summary>
|
||||
/// Must be 0
|
||||
/// Must be 0
|
||||
/// </summary>
|
||||
public byte zero5;
|
||||
/// <summary>
|
||||
/// Indicates machine the boot code following the superblock is designed to boot
|
||||
/// Indicates machine the boot code following the superblock is designed to boot
|
||||
/// </summary>
|
||||
public byte fiddle;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Superblock found on CP/M-86 hard disk volumes
|
||||
/// Superblock found on CP/M-86 hard disk volumes
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct HardDiskSuperBlock
|
||||
{
|
||||
/// <summary>
|
||||
/// Value so the sum of all the superblock's sector bytes taken as 16-bit values gives 0
|
||||
/// Value so the sum of all the superblock's sector bytes taken as 16-bit values gives 0
|
||||
/// </summary>
|
||||
public ushort checksum;
|
||||
/// <summary>
|
||||
/// Copyright string
|
||||
/// Copyright string
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x1F)] public byte[] copyright;
|
||||
/// <summary>
|
||||
/// First cylinder of disk where this volume resides
|
||||
/// First cylinder of disk where this volume resides
|
||||
/// </summary>
|
||||
public ushort firstCylinder;
|
||||
/// <summary>
|
||||
/// How many cylinders does this volume span
|
||||
/// How many cylinders does this volume span
|
||||
/// </summary>
|
||||
public ushort cylinders;
|
||||
/// <summary>
|
||||
/// Heads on hard disk
|
||||
/// Heads on hard disk
|
||||
/// </summary>
|
||||
public byte heads;
|
||||
/// <summary>
|
||||
/// Sectors per track
|
||||
/// Sectors per track
|
||||
/// </summary>
|
||||
public byte sectorsPerTrack;
|
||||
/// <summary>
|
||||
/// Flags, only use by CCP/M where bit 0 equals verify on write
|
||||
/// Flags, only use by CCP/M where bit 0 equals verify on write
|
||||
/// </summary>
|
||||
public byte flags;
|
||||
/// <summary>
|
||||
/// Sector size / 128
|
||||
/// Sector size / 128
|
||||
/// </summary>
|
||||
public byte recordsPerSector;
|
||||
/// <summary>
|
||||
/// <see cref="DiscParameterBlock.spt"/>
|
||||
/// <see cref="DiscParameterBlock.spt" />
|
||||
/// </summary>
|
||||
public ushort spt;
|
||||
/// <summary>
|
||||
/// <see cref="DiscParameterBlock.bsh"/>
|
||||
/// <see cref="DiscParameterBlock.bsh" />
|
||||
/// </summary>
|
||||
public byte bsh;
|
||||
/// <summary>
|
||||
/// <see cref="DiscParameterBlock.blm"/>
|
||||
/// <see cref="DiscParameterBlock.blm" />
|
||||
/// </summary>
|
||||
public byte blm;
|
||||
/// <summary>
|
||||
/// <see cref="DiscParameterBlock.exm"/>
|
||||
/// <see cref="DiscParameterBlock.exm" />
|
||||
/// </summary>
|
||||
public byte exm;
|
||||
/// <summary>
|
||||
/// <see cref="DiscParameterBlock.dsm"/>
|
||||
/// <see cref="DiscParameterBlock.dsm" />
|
||||
/// </summary>
|
||||
public ushort dsm;
|
||||
/// <summary>
|
||||
/// <see cref="DiscParameterBlock.drm"/>
|
||||
/// <see cref="DiscParameterBlock.drm" />
|
||||
/// </summary>
|
||||
public ushort drm;
|
||||
/// <summary>
|
||||
/// <see cref="DiscParameterBlock.al0"/>
|
||||
/// <see cref="DiscParameterBlock.al0" />
|
||||
/// </summary>
|
||||
public ushort al0;
|
||||
/// <summary>
|
||||
/// <see cref="DiscParameterBlock.al1"/>
|
||||
/// <see cref="DiscParameterBlock.al1" />
|
||||
/// </summary>
|
||||
public ushort al1;
|
||||
/// <summary>
|
||||
/// <see cref="DiscParameterBlock.cks"/>
|
||||
/// <see cref="DiscParameterBlock.cks" />
|
||||
/// </summary>
|
||||
public ushort cks;
|
||||
/// <summary>
|
||||
/// <see cref="DiscParameterBlock.off"/>
|
||||
/// <see cref="DiscParameterBlock.off" />
|
||||
/// </summary>
|
||||
public ushort off;
|
||||
/// <summary>
|
||||
/// Must be zero
|
||||
/// Must be zero
|
||||
/// </summary>
|
||||
public ushort zero1;
|
||||
/// <summary>
|
||||
/// Must be zero
|
||||
/// Must be zero
|
||||
/// </summary>
|
||||
public ushort zero2;
|
||||
/// <summary>
|
||||
/// Must be zero
|
||||
/// Must be zero
|
||||
/// </summary>
|
||||
public ushort zero3;
|
||||
/// <summary>
|
||||
/// Must be zero
|
||||
/// Must be zero
|
||||
/// </summary>
|
||||
public ushort zero4;
|
||||
/// <summary>
|
||||
/// How many 128 bytes are in a block
|
||||
/// How many 128 bytes are in a block
|
||||
/// </summary>
|
||||
public ushort recordsPerBlock;
|
||||
/// <summary>
|
||||
/// Maximum number of bad blocks in the bad block list
|
||||
/// Maximum number of bad blocks in the bad block list
|
||||
/// </summary>
|
||||
public ushort badBlockWordsMax;
|
||||
/// <summary>
|
||||
/// Used number of bad blocks in the bad block list
|
||||
/// Used number of bad blocks in the bad block list
|
||||
/// </summary>
|
||||
public ushort badBlockWords;
|
||||
/// <summary>
|
||||
/// First block after the blocks reserved for bad block substitution
|
||||
/// First block after the blocks reserved for bad block substitution
|
||||
/// </summary>
|
||||
public ushort firstSub;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Volume label entry
|
||||
/// Volume label entry
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct LabelEntry
|
||||
{
|
||||
/// <summary>
|
||||
/// Must be 0x20
|
||||
/// Must be 0x20
|
||||
/// </summary>
|
||||
public byte signature;
|
||||
/// <summary>
|
||||
/// Label in ASCII
|
||||
/// Label in ASCII
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 11)] public byte[] label;
|
||||
/// <summary>
|
||||
/// Label flags. Bit 0 = label exists, bit 4 = creation timestamp, bit 5 = modification timestamp, bit 6 = access timestamp, bit 7 = password enabled
|
||||
/// Label flags. Bit 0 = label exists, bit 4 = creation timestamp, bit 5 = modification timestamp, bit 6 = access
|
||||
/// timestamp, bit 7 = password enabled
|
||||
/// </summary>
|
||||
public byte flags;
|
||||
/// <summary>
|
||||
/// Password decoder byte
|
||||
/// Password decoder byte
|
||||
/// </summary>
|
||||
public byte passwordDecoder;
|
||||
/// <summary>
|
||||
/// Must be 0
|
||||
/// Must be 0
|
||||
/// </summary>
|
||||
public ushort reserved;
|
||||
/// <summary>
|
||||
/// Password XOR'ed with <see cref="passwordDecoder"/>
|
||||
/// Password XOR'ed with <see cref="passwordDecoder" />
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] public byte[] password;
|
||||
/// <summary>
|
||||
/// Label creation time
|
||||
/// Label creation time
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] public byte[] ctime;
|
||||
/// <summary>
|
||||
/// Label modification time
|
||||
/// Label modification time
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] public byte[] mtime;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// CP/M 3 timestamp entry
|
||||
/// CP/M 3 timestamp entry
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct DateEntry
|
||||
{
|
||||
/// <summary>
|
||||
/// Must be 0x21
|
||||
/// Must be 0x21
|
||||
/// </summary>
|
||||
public byte signature;
|
||||
/// <summary>
|
||||
/// File 1 create/access timestamp
|
||||
/// File 1 create/access timestamp
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] public byte[] date1;
|
||||
/// <summary>
|
||||
/// File 1 modification timestamp
|
||||
/// File 1 modification timestamp
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] public byte[] date2;
|
||||
/// <summary>
|
||||
/// File 1 password mode
|
||||
/// File 1 password mode
|
||||
/// </summary>
|
||||
public byte mode1;
|
||||
public byte zero1;
|
||||
/// <summary>
|
||||
/// File 2 create/access timestamp
|
||||
/// File 2 create/access timestamp
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] public byte[] date3;
|
||||
/// <summary>
|
||||
/// File 2 modification timestamp
|
||||
/// File 2 modification timestamp
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] public byte[] date4;
|
||||
/// <summary>
|
||||
/// File 2 password mode
|
||||
/// File 2 password mode
|
||||
/// </summary>
|
||||
public byte mode2;
|
||||
public byte zero2;
|
||||
/// <summary>
|
||||
/// File 3 create/access timestamp
|
||||
/// File 3 create/access timestamp
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] public byte[] date5;
|
||||
/// <summary>
|
||||
/// File 3 modification timestamp
|
||||
/// File 3 modification timestamp
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] public byte[] date6;
|
||||
/// <summary>
|
||||
/// File 3 password mode
|
||||
/// File 3 password mode
|
||||
/// </summary>
|
||||
public byte mode3;
|
||||
public ushort zero3;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Password entry
|
||||
/// Password entry
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct PasswordEntry
|
||||
{
|
||||
/// <summary>
|
||||
/// 16 + user number
|
||||
/// 16 + user number
|
||||
/// </summary>
|
||||
public byte userNumber;
|
||||
/// <summary>
|
||||
/// Filename
|
||||
/// Filename
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] public byte[] filename;
|
||||
/// <summary>
|
||||
/// Extension
|
||||
/// Extension
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] public byte[] extension;
|
||||
/// <summary>
|
||||
/// Password mode. Bit 7 = required for read, bit 6 = required for write, bit 5 = required for delete
|
||||
/// Password mode. Bit 7 = required for read, bit 6 = required for write, bit 5 = required for delete
|
||||
/// </summary>
|
||||
public byte mode;
|
||||
/// <summary>
|
||||
/// Password decoder byte
|
||||
/// Password decoder byte
|
||||
/// </summary>
|
||||
public byte passwordDecoder;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] public byte[] reserved;
|
||||
/// <summary>
|
||||
/// Password XOR'ed with <see cref="passwordDecoder"/>
|
||||
/// Password XOR'ed with <see cref="passwordDecoder" />
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] public byte[] password;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] public byte[] reserved2;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Timestamp for Z80DOS or DOS+
|
||||
/// Timestamp for Z80DOS or DOS+
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct TrdPartyDateEntry
|
||||
{
|
||||
/// <summary>
|
||||
/// Must be 0x21
|
||||
/// Must be 0x21
|
||||
/// </summary>
|
||||
public byte signature;
|
||||
public byte zero;
|
||||
/// <summary>
|
||||
/// Creation year for file 1
|
||||
/// Creation year for file 1
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] public byte[] create1;
|
||||
/// <summary>
|
||||
/// Modification time for file 1
|
||||
/// Modification time for file 1
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] public byte[] modify1;
|
||||
/// <summary>
|
||||
/// Access time for file 1
|
||||
/// Access time for file 1
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] public byte[] access1;
|
||||
/// <summary>
|
||||
/// Creation year for file 2
|
||||
/// Creation year for file 2
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] public byte[] create2;
|
||||
/// <summary>
|
||||
/// Modification time for file 2
|
||||
/// Modification time for file 2
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] public byte[] modify2;
|
||||
/// <summary>
|
||||
/// Access time for file 2
|
||||
/// Access time for file 2
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] public byte[] access2;
|
||||
/// <summary>
|
||||
/// Creation year for file 3
|
||||
/// Creation year for file 3
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] public byte[] create3;
|
||||
/// <summary>
|
||||
/// Modification time for file 3
|
||||
/// Modification time for file 3
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] public byte[] modify3;
|
||||
/// <summary>
|
||||
/// Access time for file 3
|
||||
/// Access time for file 3
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] public byte[] access3;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Directory entry for <256 allocation blocks
|
||||
/// Directory entry for <256 allocation blocks
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct DirectoryEntry
|
||||
{
|
||||
/// <summary>
|
||||
/// User number. Bit 7 set in CP/M 1 means hidden
|
||||
/// User number. Bit 7 set in CP/M 1 means hidden
|
||||
/// </summary>
|
||||
public byte statusUser;
|
||||
/// <summary>
|
||||
/// Filename and bit 7 as flags
|
||||
/// Filename and bit 7 as flags
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] public byte[] filename;
|
||||
/// <summary>
|
||||
/// Extension and bit 7 as flags
|
||||
/// Extension and bit 7 as flags
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] public byte[] extension;
|
||||
/// <summary>
|
||||
/// Low byte of extent number
|
||||
/// Low byte of extent number
|
||||
/// </summary>
|
||||
public byte extentCounter;
|
||||
/// <summary>
|
||||
/// Last record bytes. In some implementations it means how many bytes are used in the last record, in others how many bytes are free.
|
||||
/// It always refer to 128 byte records even if blocks are way bigger, so it's mostly useless.
|
||||
/// Last record bytes. In some implementations it means how many bytes are used in the last record, in others how many
|
||||
/// bytes are free.
|
||||
/// It always refer to 128 byte records even if blocks are way bigger, so it's mostly useless.
|
||||
/// </summary>
|
||||
public byte lastRecordBytes;
|
||||
/// <summary>
|
||||
/// High byte of extent number
|
||||
/// High byte of extent number
|
||||
/// </summary>
|
||||
public byte extentCounterHigh;
|
||||
/// <summary>
|
||||
/// How many records are used in this entry. 0x80 if all are used.
|
||||
/// How many records are used in this entry. 0x80 if all are used.
|
||||
/// </summary>
|
||||
public byte records;
|
||||
/// <summary>
|
||||
/// Allocation blocks
|
||||
/// Allocation blocks
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] public byte[] allocations;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Directory entry for >256 allocation blocks
|
||||
/// Directory entry for >256 allocation blocks
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct DirectoryEntry16
|
||||
{
|
||||
/// <summary>
|
||||
/// User number. Bit 7 set in CP/M 1 means hidden
|
||||
/// User number. Bit 7 set in CP/M 1 means hidden
|
||||
/// </summary>
|
||||
public byte statusUser;
|
||||
/// <summary>
|
||||
/// Filename and bit 7 as flags
|
||||
/// Filename and bit 7 as flags
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] public byte[] filename;
|
||||
/// <summary>
|
||||
/// Extension and bit 7 as flags
|
||||
/// Extension and bit 7 as flags
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] public byte[] extension;
|
||||
/// <summary>
|
||||
/// Low byte of extent number
|
||||
/// Low byte of extent number
|
||||
/// </summary>
|
||||
public byte extentCounter;
|
||||
/// <summary>
|
||||
/// Last record bytes. In some implementations it means how many bytes are used in the last record, in others how many bytes are free.
|
||||
/// It always refer to 128 byte records even if blocks are way bigger, so it's mostly useless.
|
||||
/// Last record bytes. In some implementations it means how many bytes are used in the last record, in others how many
|
||||
/// bytes are free.
|
||||
/// It always refer to 128 byte records even if blocks are way bigger, so it's mostly useless.
|
||||
/// </summary>
|
||||
public byte lastRecordBytes;
|
||||
/// <summary>
|
||||
/// High byte of extent number
|
||||
/// High byte of extent number
|
||||
/// </summary>
|
||||
public byte extentCounterHigh;
|
||||
/// <summary>
|
||||
/// How many records are used in this entry. 0x80 if all are used.
|
||||
/// How many records are used in this entry. 0x80 if all are used.
|
||||
/// </summary>
|
||||
public byte records;
|
||||
/// <summary>
|
||||
/// Allocation blocks
|
||||
/// Allocation blocks
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] public ushort[] allocations;
|
||||
}
|
||||
|
||||
@@ -132,7 +132,8 @@ namespace DiscImageChef.Filesystems.CPM
|
||||
byte[] readSector =
|
||||
device.ReadSector((ulong)((int)partition.Start + p / sectorMask.Length * sectorMask.Length +
|
||||
sectorMask[p % sectorMask.Length]));
|
||||
if(workingDefinition.complement) for(int b = 0; b < readSector.Length; b++) readSector[b] = (byte)(~readSector[b] & 0xFF);
|
||||
if(workingDefinition.complement)
|
||||
for(int b = 0; b < readSector.Length; b++) readSector[b] = (byte)(~readSector[b] & 0xFF);
|
||||
|
||||
deinterleavedSectors.Add((ulong)p, readSector);
|
||||
}
|
||||
@@ -213,13 +214,14 @@ namespace DiscImageChef.Filesystems.CPM
|
||||
|
||||
// For each directory entry
|
||||
for(int dOff = 0; dOff < directory.Length; dOff += 32)
|
||||
// Describes a file (does not support PDOS entries with user >= 16, because they're identical to password entries
|
||||
// Describes a file (does not support PDOS entries with user >= 16, because they're identical to password entries
|
||||
if((directory[dOff] & 0x7F) < 0x10)
|
||||
if(allocationBlocks.Count > 256)
|
||||
{
|
||||
dirPtr = Marshal.AllocHGlobal(32);
|
||||
Marshal.Copy(directory, dOff, dirPtr, 32);
|
||||
DirectoryEntry16 entry = (DirectoryEntry16)Marshal.PtrToStructure(dirPtr, typeof(DirectoryEntry16));
|
||||
DirectoryEntry16 entry =
|
||||
(DirectoryEntry16)Marshal.PtrToStructure(dirPtr, typeof(DirectoryEntry16));
|
||||
Marshal.FreeHGlobal(dirPtr);
|
||||
|
||||
bool hidden = (entry.statusUser & 0x80) == 0x80;
|
||||
@@ -254,11 +256,11 @@ namespace DiscImageChef.Filesystems.CPM
|
||||
|
||||
// Do we have a stat for the file already?
|
||||
if(statCache.TryGetValue(filename, out FileEntryInfo fInfo)) statCache.Remove(filename);
|
||||
else
|
||||
{ fInfo = new FileEntryInfo {Attributes = new FileAttributes()}; }
|
||||
else fInfo = new FileEntryInfo {Attributes = new FileAttributes()};
|
||||
|
||||
// And any extent?
|
||||
if(fileExtents.TryGetValue(filename, out Dictionary<int, List<ushort>> extentBlocks)) fileExtents.Remove(filename);
|
||||
if(fileExtents.TryGetValue(filename, out Dictionary<int, List<ushort>> extentBlocks))
|
||||
fileExtents.Remove(filename);
|
||||
else extentBlocks = new Dictionary<int, List<ushort>>();
|
||||
|
||||
// Do we already have this extent? Should never happen
|
||||
@@ -275,7 +277,8 @@ namespace DiscImageChef.Filesystems.CPM
|
||||
// because that's where the directory resides.
|
||||
// There is also a field telling how many bytes are used in the last block, but its meaning is non-standard so
|
||||
// we must ignore it.
|
||||
foreach(ushort blk in entry.allocations.Where(blk => !blocks.Contains(blk) && blk != 0)) blocks.Add(blk);
|
||||
foreach(ushort blk in entry.allocations.Where(blk => !blocks.Contains(blk) && blk != 0))
|
||||
blocks.Add(blk);
|
||||
|
||||
// Save the file
|
||||
fInfo.UID = (ulong)user;
|
||||
@@ -341,11 +344,11 @@ namespace DiscImageChef.Filesystems.CPM
|
||||
|
||||
// Do we have a stat for the file already?
|
||||
if(statCache.TryGetValue(filename, out FileEntryInfo fInfo)) statCache.Remove(filename);
|
||||
else
|
||||
{ fInfo = new FileEntryInfo {Attributes = new FileAttributes()}; }
|
||||
else fInfo = new FileEntryInfo {Attributes = new FileAttributes()};
|
||||
|
||||
// And any extent?
|
||||
if(fileExtents.TryGetValue(filename, out Dictionary<int, List<ushort>> extentBlocks)) fileExtents.Remove(filename);
|
||||
if(fileExtents.TryGetValue(filename, out Dictionary<int, List<ushort>> extentBlocks))
|
||||
fileExtents.Remove(filename);
|
||||
else extentBlocks = new Dictionary<int, List<ushort>>();
|
||||
|
||||
// Do we already have this extent? Should never happen
|
||||
@@ -362,7 +365,8 @@ namespace DiscImageChef.Filesystems.CPM
|
||||
// because that's where the directory resides.
|
||||
// There is also a field telling how many bytes are used in the last block, but its meaning is non-standard so
|
||||
// we must ignore it.
|
||||
foreach(ushort blk in entry.allocations.Cast<ushort>().Where(blk => !blocks.Contains(blk) && blk != 0)) blocks.Add(blk);
|
||||
foreach(ushort blk in entry.allocations.Cast<ushort>()
|
||||
.Where(blk => !blocks.Contains(blk) && blk != 0)) blocks.Add(blk);
|
||||
|
||||
// Save the file
|
||||
fInfo.UID = (ulong)user;
|
||||
@@ -434,161 +438,164 @@ namespace DiscImageChef.Filesystems.CPM
|
||||
dirCnt++;
|
||||
}
|
||||
// Volume label and password entry. Volume password is ignored.
|
||||
else switch(directory[dOff] & 0x7F) {
|
||||
case 0x20:
|
||||
LabelEntry labelEntry;
|
||||
dirPtr = Marshal.AllocHGlobal(32);
|
||||
Marshal.Copy(directory, dOff, dirPtr, 32);
|
||||
labelEntry = (LabelEntry)Marshal.PtrToStructure(dirPtr, typeof(LabelEntry));
|
||||
Marshal.FreeHGlobal(dirPtr);
|
||||
else
|
||||
switch(directory[dOff] & 0x7F)
|
||||
{
|
||||
case 0x20:
|
||||
LabelEntry labelEntry;
|
||||
dirPtr = Marshal.AllocHGlobal(32);
|
||||
Marshal.Copy(directory, dOff, dirPtr, 32);
|
||||
labelEntry = (LabelEntry)Marshal.PtrToStructure(dirPtr, typeof(LabelEntry));
|
||||
Marshal.FreeHGlobal(dirPtr);
|
||||
|
||||
// The volume label defines if one of the fields in CP/M 3 timestamp is a creation or an access time
|
||||
atime |= (labelEntry.flags & 0x40) == 0x40;
|
||||
// The volume label defines if one of the fields in CP/M 3 timestamp is a creation or an access time
|
||||
atime |= (labelEntry.flags & 0x40) == 0x40;
|
||||
|
||||
label = Encoding.ASCII.GetString(directory, dOff + 1, 11).Trim();
|
||||
labelCreationDate = new byte[4];
|
||||
labelUpdateDate = new byte[4];
|
||||
Array.Copy(directory, dOff + 24, labelCreationDate, 0, 4);
|
||||
Array.Copy(directory, dOff + 28, labelUpdateDate, 0, 4);
|
||||
label = Encoding.ASCII.GetString(directory, dOff + 1, 11).Trim();
|
||||
labelCreationDate = new byte[4];
|
||||
labelUpdateDate = new byte[4];
|
||||
Array.Copy(directory, dOff + 24, labelCreationDate, 0, 4);
|
||||
Array.Copy(directory, dOff + 28, labelUpdateDate, 0, 4);
|
||||
|
||||
// Count entries 3 by 3 for timestamps
|
||||
switch(dirCnt % 3)
|
||||
{
|
||||
case 0:
|
||||
file1 = null;
|
||||
break;
|
||||
case 1:
|
||||
file2 = null;
|
||||
break;
|
||||
case 2:
|
||||
file3 = null;
|
||||
break;
|
||||
}
|
||||
|
||||
dirCnt++;
|
||||
break;
|
||||
case 0x21:
|
||||
if(directory[dOff + 10] == 0x00 && directory[dOff + 20] == 0x00 &&
|
||||
directory[dOff + 30] == 0x00 && directory[dOff + 31] == 0x00)
|
||||
{
|
||||
dirPtr = Marshal.AllocHGlobal(32);
|
||||
Marshal.Copy(directory, dOff, dirPtr, 32);
|
||||
DateEntry dateEntry = (DateEntry)Marshal.PtrToStructure(dirPtr, typeof(DateEntry));
|
||||
Marshal.FreeHGlobal(dirPtr);
|
||||
|
||||
FileEntryInfo fInfo;
|
||||
|
||||
// Entry contains timestamps for last 3 entries, whatever the kind they are.
|
||||
if(!string.IsNullOrEmpty(file1))
|
||||
{
|
||||
if(statCache.TryGetValue(file1, out fInfo)) statCache.Remove(file1);
|
||||
else fInfo = new FileEntryInfo();
|
||||
|
||||
if(atime) fInfo.AccessTime = DateHandlers.CpmToDateTime(dateEntry.date1);
|
||||
else fInfo.CreationTime = DateHandlers.CpmToDateTime(dateEntry.date1);
|
||||
|
||||
fInfo.LastWriteTime = DateHandlers.CpmToDateTime(dateEntry.date2);
|
||||
|
||||
statCache.Add(file1, fInfo);
|
||||
}
|
||||
|
||||
if(!string.IsNullOrEmpty(file2))
|
||||
{
|
||||
if(statCache.TryGetValue(file2, out fInfo)) statCache.Remove(file2);
|
||||
else fInfo = new FileEntryInfo();
|
||||
|
||||
if(atime) fInfo.AccessTime = DateHandlers.CpmToDateTime(dateEntry.date3);
|
||||
else fInfo.CreationTime = DateHandlers.CpmToDateTime(dateEntry.date3);
|
||||
|
||||
fInfo.LastWriteTime = DateHandlers.CpmToDateTime(dateEntry.date4);
|
||||
|
||||
statCache.Add(file2, fInfo);
|
||||
}
|
||||
|
||||
if(!string.IsNullOrEmpty(file3))
|
||||
{
|
||||
if(statCache.TryGetValue(file3, out fInfo)) statCache.Remove(file3);
|
||||
else fInfo = new FileEntryInfo();
|
||||
|
||||
if(atime) fInfo.AccessTime = DateHandlers.CpmToDateTime(dateEntry.date5);
|
||||
else fInfo.CreationTime = DateHandlers.CpmToDateTime(dateEntry.date5);
|
||||
|
||||
fInfo.LastWriteTime = DateHandlers.CpmToDateTime(dateEntry.date6);
|
||||
|
||||
statCache.Add(file3, fInfo);
|
||||
}
|
||||
|
||||
// Count entries 3 by 3 for timestamps
|
||||
switch(dirCnt % 3)
|
||||
{
|
||||
case 0:
|
||||
file1 = null;
|
||||
break;
|
||||
case 1:
|
||||
file2 = null;
|
||||
break;
|
||||
case 2:
|
||||
file3 = null;
|
||||
break;
|
||||
}
|
||||
|
||||
dirCnt++;
|
||||
break;
|
||||
case 0x21:
|
||||
if(directory[dOff + 10] == 0x00 && directory[dOff + 20] == 0x00 && directory[dOff + 30] == 0x00 &&
|
||||
directory[dOff + 31] == 0x00)
|
||||
{
|
||||
dirPtr = Marshal.AllocHGlobal(32);
|
||||
Marshal.Copy(directory, dOff, dirPtr, 32);
|
||||
DateEntry dateEntry = (DateEntry)Marshal.PtrToStructure(dirPtr, typeof(DateEntry));
|
||||
Marshal.FreeHGlobal(dirPtr);
|
||||
|
||||
FileEntryInfo fInfo;
|
||||
|
||||
// Entry contains timestamps for last 3 entries, whatever the kind they are.
|
||||
if(!string.IsNullOrEmpty(file1))
|
||||
{
|
||||
if(statCache.TryGetValue(file1, out fInfo)) statCache.Remove(file1);
|
||||
else fInfo = new FileEntryInfo();
|
||||
|
||||
if(atime) fInfo.AccessTime = DateHandlers.CpmToDateTime(dateEntry.date1);
|
||||
else fInfo.CreationTime = DateHandlers.CpmToDateTime(dateEntry.date1);
|
||||
|
||||
fInfo.LastWriteTime = DateHandlers.CpmToDateTime(dateEntry.date2);
|
||||
|
||||
statCache.Add(file1, fInfo);
|
||||
dirCnt = 0;
|
||||
}
|
||||
|
||||
if(!string.IsNullOrEmpty(file2))
|
||||
// However, if this byte is 0, timestamp is in Z80DOS or DOS+ format
|
||||
else if(directory[dOff + 1] == 0x00)
|
||||
{
|
||||
if(statCache.TryGetValue(file2, out fInfo)) statCache.Remove(file2);
|
||||
else fInfo = new FileEntryInfo();
|
||||
dirPtr = Marshal.AllocHGlobal(32);
|
||||
Marshal.Copy(directory, dOff, dirPtr, 32);
|
||||
TrdPartyDateEntry trdPartyDateEntry =
|
||||
(TrdPartyDateEntry)Marshal.PtrToStructure(dirPtr, typeof(TrdPartyDateEntry));
|
||||
Marshal.FreeHGlobal(dirPtr);
|
||||
|
||||
if(atime) fInfo.AccessTime = DateHandlers.CpmToDateTime(dateEntry.date3);
|
||||
else fInfo.CreationTime = DateHandlers.CpmToDateTime(dateEntry.date3);
|
||||
FileEntryInfo fInfo;
|
||||
|
||||
fInfo.LastWriteTime = DateHandlers.CpmToDateTime(dateEntry.date4);
|
||||
// Entry contains timestamps for last 3 entries, whatever the kind they are.
|
||||
if(!string.IsNullOrEmpty(file1))
|
||||
{
|
||||
if(statCache.TryGetValue(file1, out fInfo)) statCache.Remove(file1);
|
||||
else fInfo = new FileEntryInfo();
|
||||
|
||||
statCache.Add(file2, fInfo);
|
||||
byte[] ctime = new byte[4];
|
||||
ctime[0] = trdPartyDateEntry.create1[0];
|
||||
ctime[1] = trdPartyDateEntry.create1[1];
|
||||
|
||||
fInfo.AccessTime = DateHandlers.CpmToDateTime(trdPartyDateEntry.access1);
|
||||
fInfo.CreationTime = DateHandlers.CpmToDateTime(ctime);
|
||||
fInfo.LastWriteTime = DateHandlers.CpmToDateTime(trdPartyDateEntry.modify1);
|
||||
|
||||
statCache.Add(file1, fInfo);
|
||||
}
|
||||
|
||||
if(!string.IsNullOrEmpty(file2))
|
||||
{
|
||||
if(statCache.TryGetValue(file2, out fInfo)) statCache.Remove(file2);
|
||||
else fInfo = new FileEntryInfo();
|
||||
|
||||
byte[] ctime = new byte[4];
|
||||
ctime[0] = trdPartyDateEntry.create2[0];
|
||||
ctime[1] = trdPartyDateEntry.create2[1];
|
||||
|
||||
fInfo.AccessTime = DateHandlers.CpmToDateTime(trdPartyDateEntry.access2);
|
||||
fInfo.CreationTime = DateHandlers.CpmToDateTime(ctime);
|
||||
fInfo.LastWriteTime = DateHandlers.CpmToDateTime(trdPartyDateEntry.modify2);
|
||||
|
||||
statCache.Add(file2, fInfo);
|
||||
}
|
||||
|
||||
if(!string.IsNullOrEmpty(file3))
|
||||
{
|
||||
if(statCache.TryGetValue(file1, out fInfo)) statCache.Remove(file3);
|
||||
else fInfo = new FileEntryInfo();
|
||||
|
||||
byte[] ctime = new byte[4];
|
||||
ctime[0] = trdPartyDateEntry.create3[0];
|
||||
ctime[1] = trdPartyDateEntry.create3[1];
|
||||
|
||||
fInfo.AccessTime = DateHandlers.CpmToDateTime(trdPartyDateEntry.access3);
|
||||
fInfo.CreationTime = DateHandlers.CpmToDateTime(ctime);
|
||||
fInfo.LastWriteTime = DateHandlers.CpmToDateTime(trdPartyDateEntry.modify3);
|
||||
|
||||
statCache.Add(file3, fInfo);
|
||||
}
|
||||
|
||||
file1 = null;
|
||||
file2 = null;
|
||||
file3 = null;
|
||||
dirCnt = 0;
|
||||
}
|
||||
|
||||
if(!string.IsNullOrEmpty(file3))
|
||||
{
|
||||
if(statCache.TryGetValue(file3, out fInfo)) statCache.Remove(file3);
|
||||
else fInfo = new FileEntryInfo();
|
||||
|
||||
if(atime) fInfo.AccessTime = DateHandlers.CpmToDateTime(dateEntry.date5);
|
||||
else fInfo.CreationTime = DateHandlers.CpmToDateTime(dateEntry.date5);
|
||||
|
||||
fInfo.LastWriteTime = DateHandlers.CpmToDateTime(dateEntry.date6);
|
||||
|
||||
statCache.Add(file3, fInfo);
|
||||
}
|
||||
|
||||
file1 = null;
|
||||
file2 = null;
|
||||
file3 = null;
|
||||
dirCnt = 0;
|
||||
}
|
||||
// However, if this byte is 0, timestamp is in Z80DOS or DOS+ format
|
||||
else if(directory[dOff + 1] == 0x00)
|
||||
{
|
||||
dirPtr = Marshal.AllocHGlobal(32);
|
||||
Marshal.Copy(directory, dOff, dirPtr, 32);
|
||||
TrdPartyDateEntry trdPartyDateEntry = (TrdPartyDateEntry)Marshal.PtrToStructure(dirPtr, typeof(TrdPartyDateEntry));
|
||||
Marshal.FreeHGlobal(dirPtr);
|
||||
|
||||
FileEntryInfo fInfo;
|
||||
|
||||
// Entry contains timestamps for last 3 entries, whatever the kind they are.
|
||||
if(!string.IsNullOrEmpty(file1))
|
||||
{
|
||||
if(statCache.TryGetValue(file1, out fInfo)) statCache.Remove(file1);
|
||||
else fInfo = new FileEntryInfo();
|
||||
|
||||
byte[] ctime = new byte[4];
|
||||
ctime[0] = trdPartyDateEntry.create1[0];
|
||||
ctime[1] = trdPartyDateEntry.create1[1];
|
||||
|
||||
fInfo.AccessTime = DateHandlers.CpmToDateTime(trdPartyDateEntry.access1);
|
||||
fInfo.CreationTime = DateHandlers.CpmToDateTime(ctime);
|
||||
fInfo.LastWriteTime = DateHandlers.CpmToDateTime(trdPartyDateEntry.modify1);
|
||||
|
||||
statCache.Add(file1, fInfo);
|
||||
}
|
||||
|
||||
if(!string.IsNullOrEmpty(file2))
|
||||
{
|
||||
if(statCache.TryGetValue(file2, out fInfo)) statCache.Remove(file2);
|
||||
else fInfo = new FileEntryInfo();
|
||||
|
||||
byte[] ctime = new byte[4];
|
||||
ctime[0] = trdPartyDateEntry.create2[0];
|
||||
ctime[1] = trdPartyDateEntry.create2[1];
|
||||
|
||||
fInfo.AccessTime = DateHandlers.CpmToDateTime(trdPartyDateEntry.access2);
|
||||
fInfo.CreationTime = DateHandlers.CpmToDateTime(ctime);
|
||||
fInfo.LastWriteTime = DateHandlers.CpmToDateTime(trdPartyDateEntry.modify2);
|
||||
|
||||
statCache.Add(file2, fInfo);
|
||||
}
|
||||
|
||||
if(!string.IsNullOrEmpty(file3))
|
||||
{
|
||||
if(statCache.TryGetValue(file1, out fInfo)) statCache.Remove(file3);
|
||||
else fInfo = new FileEntryInfo();
|
||||
|
||||
byte[] ctime = new byte[4];
|
||||
ctime[0] = trdPartyDateEntry.create3[0];
|
||||
ctime[1] = trdPartyDateEntry.create3[1];
|
||||
|
||||
fInfo.AccessTime = DateHandlers.CpmToDateTime(trdPartyDateEntry.access3);
|
||||
fInfo.CreationTime = DateHandlers.CpmToDateTime(ctime);
|
||||
fInfo.LastWriteTime = DateHandlers.CpmToDateTime(trdPartyDateEntry.modify3);
|
||||
|
||||
statCache.Add(file3, fInfo);
|
||||
}
|
||||
|
||||
file1 = null;
|
||||
file2 = null;
|
||||
file3 = null;
|
||||
dirCnt = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Cache all files. As CP/M maximum volume size is 8 Mib
|
||||
// this should not be a problem
|
||||
@@ -675,7 +682,7 @@ namespace DiscImageChef.Filesystems.CPM
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets information about the mounted volume.
|
||||
/// Gets information about the mounted volume.
|
||||
/// </summary>
|
||||
/// <param name="stat">Information about the mounted volume.</param>
|
||||
public override Errno StatFs(ref FileSystemInfo stat)
|
||||
|
||||
@@ -38,7 +38,7 @@ namespace DiscImageChef.Filesystems.CPM
|
||||
partial class CPM
|
||||
{
|
||||
/// <summary>
|
||||
/// Reads an extended attribute, alternate data stream or fork from the given file.
|
||||
/// Reads an extended attribute, alternate data stream or fork from the given file.
|
||||
/// </summary>
|
||||
/// <returns>Error number.</returns>
|
||||
/// <param name="path">File path.</param>
|
||||
@@ -53,16 +53,19 @@ namespace DiscImageChef.Filesystems.CPM
|
||||
|
||||
if(!fileCache.ContainsKey(pathElements[0].ToUpperInvariant())) return Errno.NoSuchFile;
|
||||
|
||||
if(string.Compare(xattr, "com.caldera.cpm.password", StringComparison.InvariantCulture) == 0) if(!passwordCache.TryGetValue(pathElements[0].ToUpperInvariant(), out buf)) return Errno.NoError;
|
||||
if(string.Compare(xattr, "com.caldera.cpm.password", StringComparison.InvariantCulture) == 0)
|
||||
if(!passwordCache.TryGetValue(pathElements[0].ToUpperInvariant(), out buf)) return Errno.NoError;
|
||||
|
||||
if(string.Compare(xattr, "com.caldera.cpm.password.text", StringComparison.InvariantCulture) != 0)
|
||||
return Errno.NoSuchExtendedAttribute;
|
||||
|
||||
return !passwordCache.TryGetValue(pathElements[0].ToUpperInvariant(), out buf) ? Errno.NoError : Errno.NoSuchExtendedAttribute;
|
||||
return !passwordCache.TryGetValue(pathElements[0].ToUpperInvariant(), out buf)
|
||||
? Errno.NoError
|
||||
: Errno.NoSuchExtendedAttribute;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Lists all extended attributes, alternate data streams and forks of the given file.
|
||||
/// Lists all extended attributes, alternate data streams and forks of the given file.
|
||||
/// </summary>
|
||||
/// <returns>Error number.</returns>
|
||||
/// <param name="path">Path.</param>
|
||||
|
||||
@@ -42,6 +42,12 @@ namespace DiscImageChef.Filesystems
|
||||
{
|
||||
public class Cram : Filesystem
|
||||
{
|
||||
/// <summary>
|
||||
/// Identifier for Cram
|
||||
/// </summary>
|
||||
const uint CRAM_MAGIC = 0x28CD3D45;
|
||||
const uint CRAM_CIGAM = 0x453DCD28;
|
||||
|
||||
public Cram()
|
||||
{
|
||||
Name = "Cram filesystem";
|
||||
@@ -63,36 +69,6 @@ namespace DiscImageChef.Filesystems
|
||||
CurrentEncoding = encoding ?? Encoding.GetEncoding("iso-8859-15");
|
||||
}
|
||||
|
||||
enum CramCompression : ushort
|
||||
{
|
||||
Zlib = 1,
|
||||
Lzma = 2,
|
||||
Lzo = 3,
|
||||
Xz = 4,
|
||||
Lz4 = 5
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct CramSuperBlock
|
||||
{
|
||||
public uint magic;
|
||||
public uint size;
|
||||
public uint flags;
|
||||
public uint future;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] public byte[] signature;
|
||||
public uint crc;
|
||||
public uint edition;
|
||||
public uint blocks;
|
||||
public uint files;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] public byte[] name;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Identifier for Cram
|
||||
/// </summary>
|
||||
const uint CRAM_MAGIC = 0x28CD3D45;
|
||||
const uint CRAM_CIGAM = 0x453DCD28;
|
||||
|
||||
public override bool Identify(ImagePlugin imagePlugin, Partition partition)
|
||||
{
|
||||
if(partition.Start >= partition.End) return false;
|
||||
@@ -104,8 +80,7 @@ namespace DiscImageChef.Filesystems
|
||||
return magic == CRAM_MAGIC || magic == CRAM_CIGAM;
|
||||
}
|
||||
|
||||
public override void GetInformation(ImagePlugin imagePlugin, Partition partition,
|
||||
out string information)
|
||||
public override void GetInformation(ImagePlugin imagePlugin, Partition partition, out string information)
|
||||
{
|
||||
byte[] sector = imagePlugin.ReadSector(partition.Start);
|
||||
uint magic = BitConverter.ToUInt32(sector, 0x00);
|
||||
@@ -113,7 +88,8 @@ namespace DiscImageChef.Filesystems
|
||||
CramSuperBlock crSb = new CramSuperBlock();
|
||||
bool littleEndian = true;
|
||||
|
||||
switch(magic) {
|
||||
switch(magic)
|
||||
{
|
||||
case CRAM_MAGIC:
|
||||
IntPtr crSbPtr = Marshal.AllocHGlobal(Marshal.SizeOf(crSb));
|
||||
Marshal.Copy(sector, 0, crSbPtr, Marshal.SizeOf(crSb));
|
||||
@@ -210,5 +186,29 @@ namespace DiscImageChef.Filesystems
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
enum CramCompression : ushort
|
||||
{
|
||||
Zlib = 1,
|
||||
Lzma = 2,
|
||||
Lzo = 3,
|
||||
Xz = 4,
|
||||
Lz4 = 5
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct CramSuperBlock
|
||||
{
|
||||
public uint magic;
|
||||
public uint size;
|
||||
public uint flags;
|
||||
public uint future;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] public byte[] signature;
|
||||
public uint crc;
|
||||
public uint edition;
|
||||
public uint blocks;
|
||||
public uint files;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] public byte[] name;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -43,6 +43,8 @@ namespace DiscImageChef.Filesystems
|
||||
{
|
||||
public class ECMA67 : Filesystem
|
||||
{
|
||||
readonly byte[] ECMA67_Magic = {0x56, 0x4F, 0x4C};
|
||||
|
||||
public ECMA67()
|
||||
{
|
||||
Name = "ECMA-67";
|
||||
@@ -64,27 +66,6 @@ namespace DiscImageChef.Filesystems
|
||||
CurrentEncoding = encoding ?? Encoding.GetEncoding("iso-8859-1");
|
||||
}
|
||||
|
||||
readonly byte[] ECMA67_Magic = {0x56, 0x4F, 0x4C};
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct VolumeLabel
|
||||
{
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] public byte[] labelIdentifier;
|
||||
public byte labelNumber;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)] public byte[] volumeIdentifier;
|
||||
public byte volumeAccessibility;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 26)] public byte[] reserved1;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 14)] public byte[] owner;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)] public byte[] reserved2;
|
||||
public byte surface;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] public byte[] reserved3;
|
||||
public byte recordLength;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] public byte[] reserved4;
|
||||
public byte fileLabelAllocation;
|
||||
public byte labelStandardVersion;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 48)] public byte[] reserved5;
|
||||
}
|
||||
|
||||
public override bool Identify(ImagePlugin imagePlugin, Partition partition)
|
||||
{
|
||||
if(partition.Start > 0) return false;
|
||||
@@ -191,5 +172,24 @@ namespace DiscImageChef.Filesystems
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct VolumeLabel
|
||||
{
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] public byte[] labelIdentifier;
|
||||
public byte labelNumber;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)] public byte[] volumeIdentifier;
|
||||
public byte volumeAccessibility;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 26)] public byte[] reserved1;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 14)] public byte[] owner;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)] public byte[] reserved2;
|
||||
public byte surface;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] public byte[] reserved3;
|
||||
public byte recordLength;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] public byte[] reserved4;
|
||||
public byte fileLabelAllocation;
|
||||
public byte labelStandardVersion;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 48)] public byte[] reserved5;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -44,54 +44,6 @@ namespace DiscImageChef.Filesystems
|
||||
{
|
||||
public class EFS : Filesystem
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
||||
struct EFS_Superblock
|
||||
{
|
||||
/* 0: fs size incl. bb 0 (in bb) */
|
||||
public int sb_size;
|
||||
/* 4: first cg offset (in bb) */
|
||||
public int sb_firstcg;
|
||||
/* 8: cg size (in bb) */
|
||||
public int sb_cgfsize;
|
||||
/* 12: inodes/cg (in bb) */
|
||||
public short sb_cgisize;
|
||||
/* 14: geom: sectors/track */
|
||||
public short sb_sectors;
|
||||
/* 16: geom: heads/cylinder (unused) */
|
||||
public short sb_heads;
|
||||
/* 18: num of cg's in the filesystem */
|
||||
public short sb_ncg;
|
||||
/* 20: non-0 indicates fsck required */
|
||||
public short sb_dirty;
|
||||
/* 22: */
|
||||
public short sb_pad0;
|
||||
/* 24: superblock ctime */
|
||||
public int sb_time;
|
||||
/* 28: magic [0] */
|
||||
public uint sb_magic;
|
||||
/* 32: name of filesystem */
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)] public byte[] sb_fname;
|
||||
/* 38: name of filesystem pack */
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)] public byte[] sb_fpack;
|
||||
/* 44: bitmap size (in bytes) */
|
||||
public int sb_bmsize;
|
||||
/* 48: total free data blocks */
|
||||
public int sb_tfree;
|
||||
/* 52: total free inodes */
|
||||
public int sb_tinode;
|
||||
/* 56: bitmap offset (grown fs) */
|
||||
public int sb_bmblock;
|
||||
/* 62: repl. superblock offset */
|
||||
public int sb_replsb;
|
||||
/* 64: last allocated inode */
|
||||
public int sb_lastinode;
|
||||
/* 68: unused */
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)] public byte[] sb_spare;
|
||||
/* 88: checksum (all above) */
|
||||
public uint sb_checksum;
|
||||
}
|
||||
|
||||
const uint EFS_MAGIC = 0x00072959;
|
||||
const uint EFS_MAGIC_NEW = 0x0007295A;
|
||||
|
||||
@@ -163,8 +115,7 @@ namespace DiscImageChef.Filesystems
|
||||
return false;
|
||||
}
|
||||
|
||||
public override void GetInformation(ImagePlugin imagePlugin, Partition partition,
|
||||
out string information)
|
||||
public override void GetInformation(ImagePlugin imagePlugin, Partition partition, out string information)
|
||||
{
|
||||
information = "";
|
||||
if(imagePlugin.GetSectorSize() < 512) return;
|
||||
@@ -305,5 +256,53 @@ namespace DiscImageChef.Filesystems
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
||||
struct EFS_Superblock
|
||||
{
|
||||
/* 0: fs size incl. bb 0 (in bb) */
|
||||
public int sb_size;
|
||||
/* 4: first cg offset (in bb) */
|
||||
public int sb_firstcg;
|
||||
/* 8: cg size (in bb) */
|
||||
public int sb_cgfsize;
|
||||
/* 12: inodes/cg (in bb) */
|
||||
public short sb_cgisize;
|
||||
/* 14: geom: sectors/track */
|
||||
public short sb_sectors;
|
||||
/* 16: geom: heads/cylinder (unused) */
|
||||
public short sb_heads;
|
||||
/* 18: num of cg's in the filesystem */
|
||||
public short sb_ncg;
|
||||
/* 20: non-0 indicates fsck required */
|
||||
public short sb_dirty;
|
||||
/* 22: */
|
||||
public short sb_pad0;
|
||||
/* 24: superblock ctime */
|
||||
public int sb_time;
|
||||
/* 28: magic [0] */
|
||||
public uint sb_magic;
|
||||
/* 32: name of filesystem */
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)] public byte[] sb_fname;
|
||||
/* 38: name of filesystem pack */
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)] public byte[] sb_fpack;
|
||||
/* 44: bitmap size (in bytes) */
|
||||
public int sb_bmsize;
|
||||
/* 48: total free data blocks */
|
||||
public int sb_tfree;
|
||||
/* 52: total free inodes */
|
||||
public int sb_tinode;
|
||||
/* 56: bitmap offset (grown fs) */
|
||||
public int sb_bmblock;
|
||||
/* 62: repl. superblock offset */
|
||||
public int sb_replsb;
|
||||
/* 64: last allocated inode */
|
||||
public int sb_lastinode;
|
||||
/* 68: unused */
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)] public byte[] sb_spare;
|
||||
/* 88: checksum (all above) */
|
||||
public uint sb_checksum;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -43,57 +43,6 @@ namespace DiscImageChef.Filesystems
|
||||
{
|
||||
public class F2FS : Filesystem
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
||||
struct F2FS_Superblock
|
||||
{
|
||||
public uint magic;
|
||||
public ushort major_ver;
|
||||
public ushort minor_ver;
|
||||
public uint log_sectorsize;
|
||||
public uint log_sectors_per_block;
|
||||
public uint log_blocksize;
|
||||
public uint log_blocks_per_seg;
|
||||
public uint segs_per_sec;
|
||||
public uint secs_per_zone;
|
||||
public uint checksum_offset;
|
||||
public ulong block_count;
|
||||
public uint section_count;
|
||||
public uint segment_count;
|
||||
public uint segment_count_ckpt;
|
||||
public uint segment_count_sit;
|
||||
public uint segment_count_nat;
|
||||
public uint segment_count_ssa;
|
||||
public uint segment_count_main;
|
||||
public uint segment0_blkaddr;
|
||||
public uint cp_blkaddr;
|
||||
public uint sit_blkaddr;
|
||||
public uint nat_blkaddr;
|
||||
public uint ssa_blkaddr;
|
||||
public uint main_blkaddr;
|
||||
public uint root_ino;
|
||||
public uint node_ino;
|
||||
public uint meta_ino;
|
||||
public Guid uuid;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 1024)] public byte[] volume_name;
|
||||
public uint extension_count;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)] public byte[] extension_list1;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)] public byte[] extension_list2;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)] public byte[] extension_list3;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)] public byte[] extension_list4;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)] public byte[] extension_list5;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)] public byte[] extension_list6;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)] public byte[] extension_list7;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)] public byte[] extension_list8;
|
||||
public uint cp_payload;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)] public byte[] version;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)] public byte[] init_version;
|
||||
public uint feature;
|
||||
public byte encryption_level;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] public byte[] encrypt_pw_salt;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 871)] public byte[] reserved;
|
||||
}
|
||||
|
||||
const uint F2FS_MAGIC = 0xF2F52010;
|
||||
const uint F2FS_SUPER_OFFSET = 1024;
|
||||
const uint F2FS_MIN_SECTOR = 512;
|
||||
@@ -147,8 +96,7 @@ namespace DiscImageChef.Filesystems
|
||||
return f2fsSb.magic == F2FS_MAGIC;
|
||||
}
|
||||
|
||||
public override void GetInformation(ImagePlugin imagePlugin, Partition partition,
|
||||
out string information)
|
||||
public override void GetInformation(ImagePlugin imagePlugin, Partition partition, out string information)
|
||||
{
|
||||
information = "";
|
||||
if(imagePlugin.GetSectorSize() < F2FS_MIN_SECTOR || imagePlugin.GetSectorSize() > F2FS_MAX_SECTOR) return;
|
||||
@@ -266,5 +214,56 @@ namespace DiscImageChef.Filesystems
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
||||
struct F2FS_Superblock
|
||||
{
|
||||
public uint magic;
|
||||
public ushort major_ver;
|
||||
public ushort minor_ver;
|
||||
public uint log_sectorsize;
|
||||
public uint log_sectors_per_block;
|
||||
public uint log_blocksize;
|
||||
public uint log_blocks_per_seg;
|
||||
public uint segs_per_sec;
|
||||
public uint secs_per_zone;
|
||||
public uint checksum_offset;
|
||||
public ulong block_count;
|
||||
public uint section_count;
|
||||
public uint segment_count;
|
||||
public uint segment_count_ckpt;
|
||||
public uint segment_count_sit;
|
||||
public uint segment_count_nat;
|
||||
public uint segment_count_ssa;
|
||||
public uint segment_count_main;
|
||||
public uint segment0_blkaddr;
|
||||
public uint cp_blkaddr;
|
||||
public uint sit_blkaddr;
|
||||
public uint nat_blkaddr;
|
||||
public uint ssa_blkaddr;
|
||||
public uint main_blkaddr;
|
||||
public uint root_ino;
|
||||
public uint node_ino;
|
||||
public uint meta_ino;
|
||||
public Guid uuid;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 1024)] public byte[] volume_name;
|
||||
public uint extension_count;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)] public byte[] extension_list1;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)] public byte[] extension_list2;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)] public byte[] extension_list3;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)] public byte[] extension_list4;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)] public byte[] extension_list5;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)] public byte[] extension_list6;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)] public byte[] extension_list7;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)] public byte[] extension_list8;
|
||||
public uint cp_payload;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)] public byte[] version;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)] public byte[] init_version;
|
||||
public uint feature;
|
||||
public byte encryption_level;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] public byte[] encrypt_pw_salt;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 871)] public byte[] reserved;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -49,6 +49,10 @@ namespace DiscImageChef.Filesystems
|
||||
// X68K uses cdate/adate from direntry for extending filename
|
||||
public class FAT : Filesystem
|
||||
{
|
||||
const uint FSINFO_SIGNATURE1 = 0x41615252;
|
||||
const uint FSINFO_SIGNATURE2 = 0x61417272;
|
||||
const uint FSINFO_SIGNATURE3 = 0xAA550000;
|
||||
|
||||
public FAT()
|
||||
{
|
||||
Name = "Microsoft File Allocation Table";
|
||||
@@ -120,10 +124,9 @@ namespace DiscImageChef.Filesystems
|
||||
string msxString = Encoding.ASCII.GetString(msxId);
|
||||
string fat32String = Encoding.ASCII.GetString(fat32Id);
|
||||
bool atariOemCorrect = atariOem[0] >= 0x20 && atariOem[1] >= 0x20 && atariOem[2] >= 0x20 &&
|
||||
atariOem[3] >= 0x20 && atariOem[4] >= 0x20 && atariOem[5] >= 0x20;
|
||||
bool dosOemCorrect = dosOem[0] >= 0x20 && dosOem[1] >= 0x20 && dosOem[2] >= 0x20 &&
|
||||
dosOem[3] >= 0x20 && dosOem[4] >= 0x20 && dosOem[5] >= 0x20 &&
|
||||
dosOem[6] >= 0x20 && dosOem[7] >= 0x20;
|
||||
atariOem[3] >= 0x20 && atariOem[4] >= 0x20 && atariOem[5] >= 0x20;
|
||||
bool dosOemCorrect = dosOem[0] >= 0x20 && dosOem[1] >= 0x20 && dosOem[2] >= 0x20 && dosOem[3] >= 0x20 &&
|
||||
dosOem[4] >= 0x20 && dosOem[5] >= 0x20 && dosOem[6] >= 0x20 && dosOem[7] >= 0x20;
|
||||
string atariString = Encoding.ASCII.GetString(atariOem);
|
||||
string oemString = Encoding.ASCII.GetString(dosOem);
|
||||
|
||||
@@ -156,7 +159,7 @@ namespace DiscImageChef.Filesystems
|
||||
byte apricotMediaDescriptor = bpbSector[0x5A];
|
||||
ushort apricotFatSectors = BitConverter.ToUInt16(bpbSector, 0x5B);
|
||||
bool apricotCorrectSpc = apricotSpc == 1 || apricotSpc == 2 || apricotSpc == 4 || apricotSpc == 8 ||
|
||||
apricotSpc == 16 || apricotSpc == 32 || apricotSpc == 64;
|
||||
apricotSpc == 16 || apricotSpc == 32 || apricotSpc == 64;
|
||||
int bitsInApricotBps = CountBits.Count(apricotBps);
|
||||
byte apricotPartitions = bpbSector[0x0C];
|
||||
|
||||
@@ -178,7 +181,8 @@ namespace DiscImageChef.Filesystems
|
||||
hugeSectors /= 4;
|
||||
}
|
||||
|
||||
switch(oemString) {
|
||||
switch(oemString)
|
||||
{
|
||||
// exFAT
|
||||
case "EXFAT ": return false;
|
||||
// NTFS
|
||||
@@ -200,32 +204,38 @@ namespace DiscImageChef.Filesystems
|
||||
if(hpfsMagic1 == 0xF995E849 && hpfsMagic2 == 0xFA53E9C5) return false;
|
||||
}
|
||||
|
||||
switch(bitsInBps) {
|
||||
switch(bitsInBps)
|
||||
{
|
||||
// FAT32 for sure
|
||||
case 1 when correctSpc && numberOfFats <= 2 && sectors == 0 && fatSectors == 0 && fat32Signature == 0x29 && fat32String == "FAT32 ": return true;
|
||||
case 1 when correctSpc && numberOfFats <= 2 && sectors == 0 && fatSectors == 0 &&
|
||||
fat32Signature == 0x29 && fat32String == "FAT32 ": return true;
|
||||
// short FAT32
|
||||
case 1 when correctSpc && numberOfFats <= 2 && sectors == 0 && fatSectors == 0 && fat32Signature == 0x28:
|
||||
case 1 when correctSpc && numberOfFats <= 2 && sectors == 0 && fatSectors == 0 && fat32Signature == 0x28
|
||||
:
|
||||
return bigSectors == 0
|
||||
? hugeSectors <= partition.End - partition.Start + 1
|
||||
: bigSectors <= partition.End - partition.Start + 1;
|
||||
// MSX-DOS FAT12
|
||||
case 1 when correctSpc && numberOfFats <= 2 && rootEntries > 0 && sectors <= partition.End - partition.Start + 1 && fatSectors > 0 && msxString == "VOL_ID": return true;
|
||||
case 1 when correctSpc && numberOfFats <= 2 && rootEntries > 0 &&
|
||||
sectors <= partition.End - partition.Start + 1 && fatSectors > 0 &&
|
||||
msxString == "VOL_ID": return true;
|
||||
// EBPB
|
||||
case 1 when correctSpc && numberOfFats <= 2 && rootEntries > 0 && fatSectors > 0 && (bpbSignature == 0x28 || bpbSignature == 0x29):
|
||||
case 1 when correctSpc && numberOfFats <= 2 && rootEntries > 0 && fatSectors > 0 &&
|
||||
(bpbSignature == 0x28 || bpbSignature == 0x29):
|
||||
return sectors == 0
|
||||
? bigSectors <= partition.End - partition.Start + 1
|
||||
: sectors <= partition.End - partition.Start + 1;
|
||||
// BPB
|
||||
case 1 when correctSpc && reservedSecs < partition.End - partition.Start && numberOfFats <= 2 && rootEntries > 0 && fatSectors > 0:
|
||||
case 1 when correctSpc && reservedSecs < partition.End - partition.Start && numberOfFats <= 2 &&
|
||||
rootEntries > 0 && fatSectors > 0:
|
||||
return sectors == 0
|
||||
? bigSectors <= partition.End - partition.Start + 1
|
||||
: sectors <= partition.End - partition.Start + 1;
|
||||
}
|
||||
|
||||
// Apricot BPB
|
||||
if(bitsInApricotBps == 1 && apricotCorrectSpc &&
|
||||
apricotReservedSecs < partition.End - partition.Start && apricotFatsNo <= 2 &&
|
||||
apricotRootEntries > 0 && apricotFatSectors > 0 &&
|
||||
if(bitsInApricotBps == 1 && apricotCorrectSpc && apricotReservedSecs < partition.End - partition.Start &&
|
||||
apricotFatsNo <= 2 && apricotRootEntries > 0 && apricotFatSectors > 0 &&
|
||||
apricotSectors <= partition.End - partition.Start + 1 && apricotPartitions == 0) return true;
|
||||
|
||||
// All FAT12 without BPB can only be used on floppies, without partitions.
|
||||
@@ -243,8 +253,8 @@ namespace DiscImageChef.Filesystems
|
||||
bool equalFatIds = fat1Sector0[0] == fat2Sector0[0] && fat1Sector0[1] == fat2Sector0[1];
|
||||
// Volume is software interleaved 2:1
|
||||
MemoryStream rootMs = new MemoryStream();
|
||||
foreach(byte[] tmp in from ulong rootSector in new[] {0x17, 0x19, 0x1B, 0x1D, 0x1E, 0x20} select imagePlugin.ReadSector(rootSector))
|
||||
{ rootMs.Write(tmp, 0, tmp.Length); }
|
||||
foreach(byte[] tmp in from ulong rootSector in new[] {0x17, 0x19, 0x1B, 0x1D, 0x1E, 0x20}
|
||||
select imagePlugin.ReadSector(rootSector)) rootMs.Write(tmp, 0, tmp.Length);
|
||||
|
||||
byte[] rootDir = rootMs.ToArray();
|
||||
bool validRootDir = true;
|
||||
@@ -327,8 +337,7 @@ namespace DiscImageChef.Filesystems
|
||||
return fatId == fat2Sector[0];
|
||||
}
|
||||
|
||||
public override void GetInformation(ImagePlugin imagePlugin, Partition partition,
|
||||
out string information)
|
||||
public override void GetInformation(ImagePlugin imagePlugin, Partition partition, out string information)
|
||||
{
|
||||
information = "";
|
||||
|
||||
@@ -397,37 +406,37 @@ namespace DiscImageChef.Filesystems
|
||||
int bitsInBpsApricot = CountBits.Count(apricotBpb.mainBPB.bps);
|
||||
|
||||
bool correctSpcAtari = atariBpb.spc == 1 || atariBpb.spc == 2 || atariBpb.spc == 4 ||
|
||||
atariBpb.spc == 8 || atariBpb.spc == 16 || atariBpb.spc == 32 ||
|
||||
atariBpb.spc == 64;
|
||||
atariBpb.spc == 8 || atariBpb.spc == 16 || atariBpb.spc == 32 ||
|
||||
atariBpb.spc == 64;
|
||||
bool correctSpcMsx = msxBpb.spc == 1 || msxBpb.spc == 2 || msxBpb.spc == 4 || msxBpb.spc == 8 ||
|
||||
msxBpb.spc == 16 || msxBpb.spc == 32 || msxBpb.spc == 64;
|
||||
msxBpb.spc == 16 || msxBpb.spc == 32 || msxBpb.spc == 64;
|
||||
bool correctSpcDos20 = dos2Bpb.spc == 1 || dos2Bpb.spc == 2 || dos2Bpb.spc == 4 || dos2Bpb.spc == 8 ||
|
||||
dos2Bpb.spc == 16 || dos2Bpb.spc == 32 || dos2Bpb.spc == 64;
|
||||
dos2Bpb.spc == 16 || dos2Bpb.spc == 32 || dos2Bpb.spc == 64;
|
||||
bool correctSpcDos30 = dos30Bpb.spc == 1 || dos30Bpb.spc == 2 || dos30Bpb.spc == 4 ||
|
||||
dos30Bpb.spc == 8 || dos30Bpb.spc == 16 || dos30Bpb.spc == 32 ||
|
||||
dos30Bpb.spc == 64;
|
||||
dos30Bpb.spc == 8 || dos30Bpb.spc == 16 || dos30Bpb.spc == 32 ||
|
||||
dos30Bpb.spc == 64;
|
||||
bool correctSpcDos32 = dos32Bpb.spc == 1 || dos32Bpb.spc == 2 || dos32Bpb.spc == 4 ||
|
||||
dos32Bpb.spc == 8 || dos32Bpb.spc == 16 || dos32Bpb.spc == 32 ||
|
||||
dos32Bpb.spc == 64;
|
||||
dos32Bpb.spc == 8 || dos32Bpb.spc == 16 || dos32Bpb.spc == 32 ||
|
||||
dos32Bpb.spc == 64;
|
||||
bool correctSpcDos33 = dos33Bpb.spc == 1 || dos33Bpb.spc == 2 || dos33Bpb.spc == 4 ||
|
||||
dos33Bpb.spc == 8 || dos33Bpb.spc == 16 || dos33Bpb.spc == 32 ||
|
||||
dos33Bpb.spc == 64;
|
||||
dos33Bpb.spc == 8 || dos33Bpb.spc == 16 || dos33Bpb.spc == 32 ||
|
||||
dos33Bpb.spc == 64;
|
||||
bool correctSpcDos34 = shortEbpb.spc == 1 || shortEbpb.spc == 2 || shortEbpb.spc == 4 ||
|
||||
shortEbpb.spc == 8 || shortEbpb.spc == 16 || shortEbpb.spc == 32 ||
|
||||
shortEbpb.spc == 64;
|
||||
shortEbpb.spc == 8 || shortEbpb.spc == 16 || shortEbpb.spc == 32 ||
|
||||
shortEbpb.spc == 64;
|
||||
bool correctSpcDos40 = ebpb.spc == 1 || ebpb.spc == 2 || ebpb.spc == 4 || ebpb.spc == 8 ||
|
||||
ebpb.spc == 16 || ebpb.spc == 32 || ebpb.spc == 64;
|
||||
ebpb.spc == 16 || ebpb.spc == 32 || ebpb.spc == 64;
|
||||
bool correctSpcFat32Short = shortFat32Bpb.spc == 1 || shortFat32Bpb.spc == 2 ||
|
||||
shortFat32Bpb.spc == 4 || shortFat32Bpb.spc == 8 ||
|
||||
shortFat32Bpb.spc == 16 || shortFat32Bpb.spc == 32 ||
|
||||
shortFat32Bpb.spc == 64;
|
||||
shortFat32Bpb.spc == 4 || shortFat32Bpb.spc == 8 ||
|
||||
shortFat32Bpb.spc == 16 || shortFat32Bpb.spc == 32 ||
|
||||
shortFat32Bpb.spc == 64;
|
||||
bool correctSpcFat32 = fat32Bpb.spc == 1 || fat32Bpb.spc == 2 || fat32Bpb.spc == 4 ||
|
||||
fat32Bpb.spc == 8 || fat32Bpb.spc == 16 || fat32Bpb.spc == 32 ||
|
||||
fat32Bpb.spc == 64;
|
||||
fat32Bpb.spc == 8 || fat32Bpb.spc == 16 || fat32Bpb.spc == 32 ||
|
||||
fat32Bpb.spc == 64;
|
||||
bool correctSpcApricot = apricotBpb.mainBPB.spc == 1 || apricotBpb.mainBPB.spc == 2 ||
|
||||
apricotBpb.mainBPB.spc == 4 || apricotBpb.mainBPB.spc == 8 ||
|
||||
apricotBpb.mainBPB.spc == 16 || apricotBpb.mainBPB.spc == 32 ||
|
||||
apricotBpb.mainBPB.spc == 64;
|
||||
apricotBpb.mainBPB.spc == 4 || apricotBpb.mainBPB.spc == 8 ||
|
||||
apricotBpb.mainBPB.spc == 16 || apricotBpb.mainBPB.spc == 32 ||
|
||||
apricotBpb.mainBPB.spc == 64;
|
||||
|
||||
// This is to support FAT partitions on hybrid ISO/USB images
|
||||
if(imagePlugin.ImageInfo.XmlMediaType == XmlMediaType.OpticalDisc)
|
||||
@@ -452,9 +461,9 @@ namespace DiscImageChef.Filesystems
|
||||
}
|
||||
|
||||
andosOemCorrect = dos33Bpb.oem_name[0] < 0x20 && dos33Bpb.oem_name[1] >= 0x20 &&
|
||||
dos33Bpb.oem_name[2] >= 0x20 && dos33Bpb.oem_name[3] >= 0x20 &&
|
||||
dos33Bpb.oem_name[4] >= 0x20 && dos33Bpb.oem_name[5] >= 0x20 &&
|
||||
dos33Bpb.oem_name[6] >= 0x20 && dos33Bpb.oem_name[7] >= 0x20;
|
||||
dos33Bpb.oem_name[2] >= 0x20 && dos33Bpb.oem_name[3] >= 0x20 &&
|
||||
dos33Bpb.oem_name[4] >= 0x20 && dos33Bpb.oem_name[5] >= 0x20 &&
|
||||
dos33Bpb.oem_name[6] >= 0x20 && dos33Bpb.oem_name[7] >= 0x20;
|
||||
|
||||
if(bitsInBpsFat32 == 1 && correctSpcFat32 && fat32Bpb.fats_no <= 2 && fat32Bpb.sectors == 0 &&
|
||||
fat32Bpb.spfat == 0 && fat32Bpb.signature == 0x29 &&
|
||||
@@ -515,9 +524,8 @@ namespace DiscImageChef.Filesystems
|
||||
userShortExtendedBpb = true;
|
||||
}
|
||||
}
|
||||
else if(bitsInBpsDos33 == 1 && correctSpcDos33 &&
|
||||
dos33Bpb.rsectors < partition.End - partition.Start && dos33Bpb.fats_no <= 2 &&
|
||||
dos33Bpb.root_ent > 0 && dos33Bpb.spfat > 0)
|
||||
else if(bitsInBpsDos33 == 1 && correctSpcDos33 && dos33Bpb.rsectors < partition.End - partition.Start &&
|
||||
dos33Bpb.fats_no <= 2 && dos33Bpb.root_ent > 0 && dos33Bpb.spfat > 0)
|
||||
if(dos33Bpb.sectors == 0 && dos33Bpb.hsectors <= partition.Start && dos33Bpb.big_sectors > 0 &&
|
||||
dos33Bpb.big_sectors <= partition.End - partition.Start + 1)
|
||||
{
|
||||
@@ -603,8 +611,8 @@ namespace DiscImageChef.Filesystems
|
||||
bool equalFatIds = fat1Sector0[0] == fat2Sector0[0] && fat1Sector0[1] == fat2Sector0[1];
|
||||
// Volume is software interleaved 2:1
|
||||
MemoryStream rootMs = new MemoryStream();
|
||||
foreach(byte[] tmp in from ulong rootSector in new[] {0x17, 0x19, 0x1B, 0x1D, 0x1E, 0x20} select imagePlugin.ReadSector(rootSector))
|
||||
{ rootMs.Write(tmp, 0, tmp.Length); }
|
||||
foreach(byte[] tmp in from ulong rootSector in new[] {0x17, 0x19, 0x1B, 0x1D, 0x1E, 0x20}
|
||||
select imagePlugin.ReadSector(rootSector)) rootMs.Write(tmp, 0, tmp.Length);
|
||||
|
||||
byte[] rootDir = rootMs.ToArray();
|
||||
bool validRootDir = true;
|
||||
@@ -646,7 +654,8 @@ namespace DiscImageChef.Filesystems
|
||||
}
|
||||
|
||||
if(!useAtariBpb && !useMsxBpb && !useDos2Bpb && !useDos3Bpb && !useDos32Bpb && !useDos33Bpb &&
|
||||
!userShortExtendedBpb && !useExtendedBpb && !useShortFat32 && !useLongFat32 && !useApricotBpb && !useDecRainbowBpb)
|
||||
!userShortExtendedBpb && !useExtendedBpb && !useShortFat32 && !useLongFat32 && !useApricotBpb &&
|
||||
!useDecRainbowBpb)
|
||||
{
|
||||
isFat12 = true;
|
||||
byte[] fatSector = imagePlugin.ReadSector(1 + partition.Start);
|
||||
@@ -1281,8 +1290,8 @@ namespace DiscImageChef.Filesystems
|
||||
// Check that jumps to a correct boot code position and has boot signature set.
|
||||
// This will mean that the volume will boot, even if just to say "this is not bootable change disk"......
|
||||
if(XmlFsType.Bootable == false && fakeBpb.jump != null)
|
||||
XmlFsType.Bootable |= fakeBpb.jump[0] == 0xEB && fakeBpb.jump[1] > 0x58 &&
|
||||
fakeBpb.jump[1] < 0x80 && fakeBpb.boot_signature == 0xAA55;
|
||||
XmlFsType.Bootable |= fakeBpb.jump[0] == 0xEB && fakeBpb.jump[1] > 0x58 && fakeBpb.jump[1] < 0x80 &&
|
||||
fakeBpb.boot_signature == 0xAA55;
|
||||
|
||||
sectorsPerRealSector = fakeBpb.bps / imagePlugin.ImageInfo.SectorSize;
|
||||
// First root directory sector
|
||||
@@ -1302,8 +1311,8 @@ namespace DiscImageChef.Filesystems
|
||||
if(useDecRainbowBpb)
|
||||
{
|
||||
MemoryStream rootMs = new MemoryStream();
|
||||
foreach(byte[] tmp in from ulong rootSector in new[] {0x17, 0x19, 0x1B, 0x1D, 0x1E, 0x20} select imagePlugin.ReadSector(rootSector))
|
||||
{ rootMs.Write(tmp, 0, tmp.Length); }
|
||||
foreach(byte[] tmp in from ulong rootSector in new[] {0x17, 0x19, 0x1B, 0x1D, 0x1E, 0x20}
|
||||
select imagePlugin.ReadSector(rootSector)) rootMs.Write(tmp, 0, tmp.Length);
|
||||
|
||||
rootDirectory = rootMs.ToArray();
|
||||
}
|
||||
@@ -1334,7 +1343,8 @@ namespace DiscImageChef.Filesystems
|
||||
if(entry.ctime > 0 && entry.cdate > 0)
|
||||
{
|
||||
XmlFsType.CreationDate = DateHandlers.DosToDateTime(entry.cdate, entry.ctime);
|
||||
if(entry.ctime_ms > 0) XmlFsType.CreationDate = XmlFsType.CreationDate.AddMilliseconds(entry.ctime_ms * 10);
|
||||
if(entry.ctime_ms > 0)
|
||||
XmlFsType.CreationDate = XmlFsType.CreationDate.AddMilliseconds(entry.ctime_ms * 10);
|
||||
XmlFsType.CreationDateSpecified = true;
|
||||
sb.AppendFormat("Volume created on {0}", XmlFsType.CreationDate).AppendLine();
|
||||
}
|
||||
@@ -1365,8 +1375,68 @@ namespace DiscImageChef.Filesystems
|
||||
information = sb.ToString();
|
||||
}
|
||||
|
||||
public override Errno Mount()
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno Mount(bool debug)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno Unmount()
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno MapBlock(string path, long fileBlock, ref long deviceBlock)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno GetAttributes(string path, ref FileAttributes attributes)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno ListXAttr(string path, ref List<string> xattrs)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno GetXattr(string path, string xattr, ref byte[] buf)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno Read(string path, long offset, long size, ref byte[] buf)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno ReadDir(string path, ref List<string> contents)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno StatFs(ref FileSystemInfo stat)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno Stat(string path, ref FileEntryInfo stat)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno ReadLink(string path, ref string dest)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// BIOS Parameter Block as used by Atari ST GEMDOS on FAT12 volumes.
|
||||
/// BIOS Parameter Block as used by Atari ST GEMDOS on FAT12 volumes.
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct AtariParameterBlock
|
||||
@@ -1401,7 +1471,10 @@ namespace DiscImageChef.Filesystems
|
||||
public ushort hsectors;
|
||||
/// <summary>Word to be loaded in the cmdload system variable. Big-endian.</summary>
|
||||
public ushort execflag;
|
||||
/// <summary>Word indicating load mode. If zero, file named <see cref="fname"/> is located and loaded. It not, sectors specified in <see cref="ssect"/> and <see cref="sectcnt"/> are loaded. Big endian.</summary>
|
||||
/// <summary>
|
||||
/// Word indicating load mode. If zero, file named <see cref="fname" /> is located and loaded. It not, sectors
|
||||
/// specified in <see cref="ssect" /> and <see cref="sectcnt" /> are loaded. Big endian.
|
||||
/// </summary>
|
||||
public ushort ldmode;
|
||||
/// <summary>Starting sector of boot code.</summary>
|
||||
public ushort ssect;
|
||||
@@ -1426,7 +1499,7 @@ namespace DiscImageChef.Filesystems
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// BIOS Parameter Block as used by MSX-DOS 2.
|
||||
/// BIOS Parameter Block as used by MSX-DOS 2.
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct MsxParameterBlock
|
||||
@@ -1769,7 +1842,7 @@ namespace DiscImageChef.Filesystems
|
||||
public uint serial_no;
|
||||
/// <summary>Volume label, 11 bytes, space-padded</summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 11)] public byte[] reserved2;
|
||||
/// <summary>Sectors in volume if <see cref="big_sectors"/> equals 0</summary>
|
||||
/// <summary>Sectors in volume if <see cref="big_sectors" /> equals 0</summary>
|
||||
public ulong huge_sectors;
|
||||
/// <summary>Boot code.</summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 420)] public byte[] boot_code;
|
||||
@@ -2040,19 +2113,15 @@ namespace DiscImageChef.Filesystems
|
||||
public ushort startSector;
|
||||
}
|
||||
|
||||
const uint FSINFO_SIGNATURE1 = 0x41615252;
|
||||
const uint FSINFO_SIGNATURE2 = 0x61417272;
|
||||
const uint FSINFO_SIGNATURE3 = 0xAA550000;
|
||||
|
||||
/// <summary>FAT32 FS Information Sector</summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct FsInfoSector
|
||||
{
|
||||
/// <summary>Signature must be <see cref="FAT.FSINFO_SIGNATURE1"/></summary>
|
||||
/// <summary>Signature must be <see cref="FAT.FSINFO_SIGNATURE1" /></summary>
|
||||
public uint signature1;
|
||||
/// <summary>Reserved</summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 480)] public byte[] reserved1;
|
||||
/// <summary>Signature must be <see cref="FAT.FSINFO_SIGNATURE2"/></summary>
|
||||
/// <summary>Signature must be <see cref="FAT.FSINFO_SIGNATURE2" /></summary>
|
||||
public uint signature2;
|
||||
/// <summary>Free clusters</summary>
|
||||
public uint free_clusters;
|
||||
@@ -2060,7 +2129,7 @@ namespace DiscImageChef.Filesystems
|
||||
public uint last_cluster;
|
||||
/// <summary>Reserved</summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)] public byte[] reserved2;
|
||||
/// <summary>Signature must be <see cref="FAT.FSINFO_SIGNATURE3"/></summary>
|
||||
/// <summary>Signature must be <see cref="FAT.FSINFO_SIGNATURE3" /></summary>
|
||||
public uint signature3;
|
||||
}
|
||||
|
||||
@@ -2095,65 +2164,5 @@ namespace DiscImageChef.Filesystems
|
||||
public ushort start_cluster;
|
||||
public uint size;
|
||||
}
|
||||
|
||||
public override Errno Mount()
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno Mount(bool debug)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno Unmount()
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno MapBlock(string path, long fileBlock, ref long deviceBlock)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno GetAttributes(string path, ref FileAttributes attributes)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno ListXAttr(string path, ref List<string> xattrs)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno GetXattr(string path, string xattr, ref byte[] buf)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno Read(string path, long offset, long size, ref byte[] buf)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno ReadDir(string path, ref List<string> contents)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno StatFs(ref FileSystemInfo stat)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno Stat(string path, ref FileEntryInfo stat)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno ReadLink(string path, ref string dest)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -42,15 +42,6 @@ namespace DiscImageChef.Filesystems
|
||||
{
|
||||
public class FATX : Filesystem
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct FATX_Superblock
|
||||
{
|
||||
public uint magic;
|
||||
public uint id;
|
||||
public uint sectorsPerCluster;
|
||||
public uint rootDirectoryCluster;
|
||||
}
|
||||
|
||||
const uint FATX_MAGIC = 0x58544146;
|
||||
|
||||
public FATX()
|
||||
@@ -86,8 +77,7 @@ namespace DiscImageChef.Filesystems
|
||||
return fatxSb.magic == FATX_MAGIC;
|
||||
}
|
||||
|
||||
public override void GetInformation(ImagePlugin imagePlugin, Partition partition,
|
||||
out string information)
|
||||
public override void GetInformation(ImagePlugin imagePlugin, Partition partition, out string information)
|
||||
{
|
||||
information = "";
|
||||
if(imagePlugin.GetSectorSize() < 512) return;
|
||||
@@ -178,5 +168,14 @@ namespace DiscImageChef.Filesystems
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct FATX_Superblock
|
||||
{
|
||||
public uint magic;
|
||||
public uint id;
|
||||
public uint sectorsPerCluster;
|
||||
public uint rootDirectoryCluster;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -49,6 +49,38 @@ namespace DiscImageChef.Filesystems
|
||||
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
||||
public class FFSPlugin : Filesystem
|
||||
{
|
||||
const uint block_size = 8192;
|
||||
|
||||
// FreeBSD specifies starts at byte offsets 0, 8192, 65536 and 262144, but in other cases it's following sectors
|
||||
// Without bootcode
|
||||
const ulong sb_start_floppy = 0;
|
||||
// With bootcode
|
||||
const ulong sb_start_boot = 1;
|
||||
// Dunno, longer boot code
|
||||
const ulong sb_start_long_boot = 8;
|
||||
// Found on AT&T for MD-2D floppieslzio
|
||||
const ulong sb_start_att_dsdd = 14;
|
||||
// Found on hard disks (Atari UNIX e.g.)
|
||||
const ulong sb_start_piggy = 32;
|
||||
|
||||
// MAGICs
|
||||
// UFS magic
|
||||
const uint UFS_MAGIC = 0x00011954;
|
||||
// Big-endian UFS magic
|
||||
const uint UFS_CIGAM = 0x54190100;
|
||||
// BorderWare UFS
|
||||
const uint UFS_MAGIC_BW = 0x0F242697;
|
||||
// Big-endian BorderWare UFS
|
||||
const uint UFS_CIGAM_BW = 0x9726240F;
|
||||
// UFS2 magic
|
||||
const uint UFS2_MAGIC = 0x19540119;
|
||||
// Big-endian UFS2 magic
|
||||
const uint UFS2_CIGAM = 0x19015419;
|
||||
// Incomplete newfs
|
||||
const uint UFS_BAD_MAGIC = 0x19960408;
|
||||
// Big-endian incomplete newfs
|
||||
const uint UFS_BAD_CIGAM = 0x08049619;
|
||||
|
||||
public FFSPlugin()
|
||||
{
|
||||
Name = "BSD Fast File System (aka UNIX File System, UFS)";
|
||||
@@ -87,11 +119,15 @@ namespace DiscImageChef.Filesystems
|
||||
262144 / imagePlugin.GetSectorSize()
|
||||
};
|
||||
|
||||
return locations.Where(loc => partition.End > partition.Start + loc + sbSizeInSectors).Select(loc => imagePlugin.ReadSectors(partition.Start + loc, sbSizeInSectors)).Select(ufsSbSectors => BitConverter.ToUInt32(ufsSbSectors, 0x055C)).Any(magic => magic == UFS_MAGIC || magic == UFS_CIGAM || magic == UFS_MAGIC_BW || magic == UFS_CIGAM_BW || magic == UFS2_MAGIC || magic == UFS2_CIGAM || magic == UFS_BAD_MAGIC || magic == UFS_BAD_CIGAM);
|
||||
return locations.Where(loc => partition.End > partition.Start + loc + sbSizeInSectors)
|
||||
.Select(loc => imagePlugin.ReadSectors(partition.Start + loc, sbSizeInSectors))
|
||||
.Select(ufsSbSectors => BitConverter.ToUInt32(ufsSbSectors, 0x055C))
|
||||
.Any(magic => magic == UFS_MAGIC || magic == UFS_CIGAM || magic == UFS_MAGIC_BW ||
|
||||
magic == UFS_CIGAM_BW || magic == UFS2_MAGIC || magic == UFS2_CIGAM ||
|
||||
magic == UFS_BAD_MAGIC || magic == UFS_BAD_CIGAM);
|
||||
}
|
||||
|
||||
public override void GetInformation(ImagePlugin imagePlugin, Partition partition,
|
||||
out string information)
|
||||
public override void GetInformation(ImagePlugin imagePlugin, Partition partition, out string information)
|
||||
{
|
||||
information = "";
|
||||
StringBuilder sbInformation = new StringBuilder();
|
||||
@@ -119,7 +155,8 @@ namespace DiscImageChef.Filesystems
|
||||
262144 / imagePlugin.GetSectorSize()
|
||||
};
|
||||
|
||||
foreach(ulong loc in locations.Where(loc => partition.End > partition.Start + loc + sb_size_in_sectors)) {
|
||||
foreach(ulong loc in locations.Where(loc => partition.End > partition.Start + loc + sb_size_in_sectors))
|
||||
{
|
||||
ufs_sb_sectors = imagePlugin.ReadSectors(partition.Start + loc, sb_size_in_sectors);
|
||||
magic = BitConverter.ToUInt32(ufs_sb_sectors, 0x055C);
|
||||
|
||||
@@ -347,12 +384,16 @@ namespace DiscImageChef.Filesystems
|
||||
sbInformation.AppendFormat("NINDIR: 0x{0:X8}", ufs_sb.fs_nindir).AppendLine();
|
||||
sbInformation.AppendFormat("INOPB: 0x{0:X8}", ufs_sb.fs_inopb).AppendLine();
|
||||
sbInformation.AppendFormat("NSPF: 0x{0:X8}", ufs_sb.fs_old_nspf).AppendLine();
|
||||
switch(ufs_sb.fs_optim) {
|
||||
case 0: sbInformation.AppendLine("Filesystem will minimize allocation time");
|
||||
switch(ufs_sb.fs_optim)
|
||||
{
|
||||
case 0:
|
||||
sbInformation.AppendLine("Filesystem will minimize allocation time");
|
||||
break;
|
||||
case 1: sbInformation.AppendLine("Filesystem will minimize volume fragmentation");
|
||||
case 1:
|
||||
sbInformation.AppendLine("Filesystem will minimize volume fragmentation");
|
||||
break;
|
||||
default: sbInformation.AppendFormat("Unknown optimization value: 0x{0:X8}", ufs_sb.fs_optim).AppendLine();
|
||||
default:
|
||||
sbInformation.AppendFormat("Unknown optimization value: 0x{0:X8}", ufs_sb.fs_optim).AppendLine();
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -362,7 +403,8 @@ namespace DiscImageChef.Filesystems
|
||||
.AppendLine();
|
||||
sbInformation.AppendFormat("Hardware sector interleave: {0}", ufs_sb.fs_old_interleave).AppendLine();
|
||||
sbInformation.AppendFormat("Sector 0 skew: {0}/track", ufs_sb.fs_old_trackskew).AppendLine();
|
||||
if(!fs_type_43bsd && ufs_sb.fs_id_1 > 0 && ufs_sb.fs_id_2 > 0) sbInformation.AppendFormat("Volume ID: 0x{0:X8}{1:X8}", ufs_sb.fs_id_1, ufs_sb.fs_id_2).AppendLine();
|
||||
if(!fs_type_43bsd && ufs_sb.fs_id_1 > 0 && ufs_sb.fs_id_2 > 0)
|
||||
sbInformation.AppendFormat("Volume ID: 0x{0:X8}{1:X8}", ufs_sb.fs_id_1, ufs_sb.fs_id_2).AppendLine();
|
||||
else if(fs_type_43bsd && ufs_sb.fs_id_1 > 0 && ufs_sb.fs_id_2 > 0)
|
||||
{
|
||||
sbInformation.AppendFormat("{0} µsec for head switch", ufs_sb.fs_id_1).AppendLine();
|
||||
@@ -451,37 +493,65 @@ namespace DiscImageChef.Filesystems
|
||||
information = sbInformation.ToString();
|
||||
}
|
||||
|
||||
const uint block_size = 8192;
|
||||
public override Errno Mount()
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
// FreeBSD specifies starts at byte offsets 0, 8192, 65536 and 262144, but in other cases it's following sectors
|
||||
// Without bootcode
|
||||
const ulong sb_start_floppy = 0;
|
||||
// With bootcode
|
||||
const ulong sb_start_boot = 1;
|
||||
// Dunno, longer boot code
|
||||
const ulong sb_start_long_boot = 8;
|
||||
// Found on AT&T for MD-2D floppieslzio
|
||||
const ulong sb_start_att_dsdd = 14;
|
||||
// Found on hard disks (Atari UNIX e.g.)
|
||||
const ulong sb_start_piggy = 32;
|
||||
public override Errno Mount(bool debug)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
// MAGICs
|
||||
// UFS magic
|
||||
const uint UFS_MAGIC = 0x00011954;
|
||||
// Big-endian UFS magic
|
||||
const uint UFS_CIGAM = 0x54190100;
|
||||
// BorderWare UFS
|
||||
const uint UFS_MAGIC_BW = 0x0F242697;
|
||||
// Big-endian BorderWare UFS
|
||||
const uint UFS_CIGAM_BW = 0x9726240F;
|
||||
// UFS2 magic
|
||||
const uint UFS2_MAGIC = 0x19540119;
|
||||
// Big-endian UFS2 magic
|
||||
const uint UFS2_CIGAM = 0x19015419;
|
||||
// Incomplete newfs
|
||||
const uint UFS_BAD_MAGIC = 0x19960408;
|
||||
// Big-endian incomplete newfs
|
||||
const uint UFS_BAD_CIGAM = 0x08049619;
|
||||
public override Errno Unmount()
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno MapBlock(string path, long fileBlock, ref long deviceBlock)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno GetAttributes(string path, ref FileAttributes attributes)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno ListXAttr(string path, ref List<string> xattrs)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno GetXattr(string path, string xattr, ref byte[] buf)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno Read(string path, long offset, long size, ref byte[] buf)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno ReadDir(string path, ref List<string> contents)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno StatFs(ref FileSystemInfo stat)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno Stat(string path, ref FileEntryInfo stat)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno ReadLink(string path, ref string dest)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct csum
|
||||
@@ -518,8 +588,10 @@ namespace DiscImageChef.Filesystems
|
||||
{
|
||||
/// <summary>linked list of file systems</summary>
|
||||
public uint fs_link;
|
||||
/// <summary> used for incore super blocks
|
||||
/// on Sun: uint fs_rolled; // logging only: fs fully rolled</summary>
|
||||
/// <summary>
|
||||
/// used for incore super blocks
|
||||
/// on Sun: uint fs_rolled; // logging only: fs fully rolled
|
||||
/// </summary>
|
||||
public uint fs_rlink;
|
||||
/// <summary>addr of super-block in filesys</summary>
|
||||
public ufs_daddr_t fs_sblkno;
|
||||
@@ -586,21 +658,29 @@ namespace DiscImageChef.Filesystems
|
||||
/// <summary>value of NSPF</summary>
|
||||
public int fs_old_nspf;
|
||||
/* yet another configuration parameter */
|
||||
/// <summary>optimization preference, see below
|
||||
/// On SVR: int fs_state; // file system state</summary>
|
||||
/// <summary>
|
||||
/// optimization preference, see below
|
||||
/// On SVR: int fs_state; // file system state
|
||||
/// </summary>
|
||||
public int fs_optim;
|
||||
/// <summary># sectors/track including spares</summary>
|
||||
public int fs_old_npsect;
|
||||
/// <summary>hardware sector interleave</summary>
|
||||
public int fs_old_interleave;
|
||||
/// <summary>sector 0 skew, per track
|
||||
/// On A/UX: int fs_state; // file system state</summary>
|
||||
/// <summary>
|
||||
/// sector 0 skew, per track
|
||||
/// On A/UX: int fs_state; // file system state
|
||||
/// </summary>
|
||||
public int fs_old_trackskew;
|
||||
/// <summary>unique filesystem id
|
||||
/// On old: int fs_headswitch; // head switch time, usec</summary>
|
||||
/// <summary>
|
||||
/// unique filesystem id
|
||||
/// On old: int fs_headswitch; // head switch time, usec
|
||||
/// </summary>
|
||||
public int fs_id_1;
|
||||
/// <summary>unique filesystem id
|
||||
/// On old: int fs_trkseek; // track-to-track seek, usec</summary>
|
||||
/// <summary>
|
||||
/// unique filesystem id
|
||||
/// On old: int fs_trkseek; // track-to-track seek, usec
|
||||
/// </summary>
|
||||
public int fs_id_2;
|
||||
/* sizes determined by number of cylinder groups and their sizes */
|
||||
/// <summary>blk addr of cyl grp summary area</summary>
|
||||
@@ -730,65 +810,5 @@ namespace DiscImageChef.Filesystems
|
||||
/// <summary>list of blocks for each rotation</summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)] public byte[] fs_rotbl;
|
||||
}
|
||||
|
||||
public override Errno Mount()
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno Mount(bool debug)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno Unmount()
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno MapBlock(string path, long fileBlock, ref long deviceBlock)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno GetAttributes(string path, ref FileAttributes attributes)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno ListXAttr(string path, ref List<string> xattrs)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno GetXattr(string path, string xattr, ref byte[] buf)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno Read(string path, long offset, long size, ref byte[] buf)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno ReadDir(string path, ref List<string> contents)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno StatFs(ref FileSystemInfo stat)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno Stat(string path, ref FileEntryInfo stat)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno ReadLink(string path, ref string dest)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -40,22 +40,16 @@ using Schemas;
|
||||
namespace DiscImageChef.Filesystems
|
||||
{
|
||||
/// <summary>
|
||||
/// Abstract class to implement filesystem plugins.
|
||||
/// Abstract class to implement filesystem plugins.
|
||||
/// </summary>
|
||||
public abstract class Filesystem
|
||||
{
|
||||
protected Encoding CurrentEncoding;
|
||||
/// <summary>Plugin name.</summary>
|
||||
public string Name;
|
||||
/// <summary>Plugin UUID.</summary>
|
||||
public Guid PluginUuid;
|
||||
internal FileSystemType XmlFsType;
|
||||
protected Encoding CurrentEncoding;
|
||||
|
||||
/// <summary>
|
||||
/// Information about the filesystem as expected by CICM Metadata XML
|
||||
/// </summary>
|
||||
/// <value>Information about the filesystem as expected by CICM Metadata XML</value>
|
||||
public FileSystemType XmlFSType => XmlFsType;
|
||||
|
||||
protected Filesystem() { }
|
||||
|
||||
@@ -63,7 +57,7 @@ namespace DiscImageChef.Filesystems
|
||||
protected Filesystem(Encoding encoding) { }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a filesystem instance prepared for reading contents
|
||||
/// Initializes a filesystem instance prepared for reading contents
|
||||
/// </summary>
|
||||
/// <param name="imagePlugin">Image plugin.</param>
|
||||
/// <param name="partition">Partition.</param>
|
||||
@@ -71,7 +65,13 @@ namespace DiscImageChef.Filesystems
|
||||
protected Filesystem(ImagePlugin imagePlugin, Partition partition, Encoding encoding) { }
|
||||
|
||||
/// <summary>
|
||||
/// Identifies the filesystem in the specified LBA
|
||||
/// Information about the filesystem as expected by CICM Metadata XML
|
||||
/// </summary>
|
||||
/// <value>Information about the filesystem as expected by CICM Metadata XML</value>
|
||||
public FileSystemType XmlFSType => XmlFsType;
|
||||
|
||||
/// <summary>
|
||||
/// Identifies the filesystem in the specified LBA
|
||||
/// </summary>
|
||||
/// <param name="imagePlugin">Disk image.</param>
|
||||
/// <param name="partition">Partition.</param>
|
||||
@@ -79,31 +79,32 @@ namespace DiscImageChef.Filesystems
|
||||
public abstract bool Identify(ImagePlugin imagePlugin, Partition partition);
|
||||
|
||||
/// <summary>
|
||||
/// Gets information about the identified filesystem.
|
||||
/// Gets information about the identified filesystem.
|
||||
/// </summary>
|
||||
/// <param name="imagePlugin">Disk image.</param>
|
||||
/// <param name="partition">Partition.</param>
|
||||
/// <param name="information">Filesystem information.</param>
|
||||
public abstract void GetInformation(ImagePlugin imagePlugin, Partition partition,
|
||||
out string information);
|
||||
public abstract void GetInformation(ImagePlugin imagePlugin, Partition partition, out string information);
|
||||
|
||||
/// <summary>
|
||||
/// Initializates whatever internal structures the filesystem plugin needs to be able to read files and directories from the filesystem.
|
||||
/// Initializates whatever internal structures the filesystem plugin needs to be able to read files and directories
|
||||
/// from the filesystem.
|
||||
/// </summary>
|
||||
public abstract Errno Mount();
|
||||
|
||||
/// <summary>
|
||||
/// Initializates whatever internal structures the filesystem plugin needs to be able to read files and directories from the filesystem.
|
||||
/// Initializates whatever internal structures the filesystem plugin needs to be able to read files and directories
|
||||
/// from the filesystem.
|
||||
/// </summary>
|
||||
public abstract Errno Mount(bool debug);
|
||||
|
||||
/// <summary>
|
||||
/// Frees all internal structures created by <see cref="Mount()"/>
|
||||
/// Frees all internal structures created by <see cref="Mount()" />
|
||||
/// </summary>
|
||||
public abstract Errno Unmount();
|
||||
|
||||
/// <summary>
|
||||
/// Maps a filesystem block from a file to a block from the underlying device.
|
||||
/// Maps a filesystem block from a file to a block from the underlying device.
|
||||
/// </summary>
|
||||
/// <returns>Error number.</returns>
|
||||
/// <param name="path">File path.</param>
|
||||
@@ -112,7 +113,7 @@ namespace DiscImageChef.Filesystems
|
||||
public abstract Errno MapBlock(string path, long fileBlock, ref long deviceBlock);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the attributes of a file or directory
|
||||
/// Gets the attributes of a file or directory
|
||||
/// </summary>
|
||||
/// <returns>Error number.</returns>
|
||||
/// <param name="path">File path.</param>
|
||||
@@ -120,7 +121,7 @@ namespace DiscImageChef.Filesystems
|
||||
public abstract Errno GetAttributes(string path, ref FileAttributes attributes);
|
||||
|
||||
/// <summary>
|
||||
/// Lists all extended attributes, alternate data streams and forks of the given file.
|
||||
/// Lists all extended attributes, alternate data streams and forks of the given file.
|
||||
/// </summary>
|
||||
/// <returns>Error number.</returns>
|
||||
/// <param name="path">Path.</param>
|
||||
@@ -128,7 +129,7 @@ namespace DiscImageChef.Filesystems
|
||||
public abstract Errno ListXAttr(string path, ref List<string> xattrs);
|
||||
|
||||
/// <summary>
|
||||
/// Reads an extended attribute, alternate data stream or fork from the given file.
|
||||
/// Reads an extended attribute, alternate data stream or fork from the given file.
|
||||
/// </summary>
|
||||
/// <returns>Error number.</returns>
|
||||
/// <param name="path">File path.</param>
|
||||
@@ -137,7 +138,7 @@ namespace DiscImageChef.Filesystems
|
||||
public abstract Errno GetXattr(string path, string xattr, ref byte[] buf);
|
||||
|
||||
/// <summary>
|
||||
/// Reads data from a file (main/only data stream or data fork).
|
||||
/// Reads data from a file (main/only data stream or data fork).
|
||||
/// </summary>
|
||||
/// <param name="path">File path.</param>
|
||||
/// <param name="offset">Offset.</param>
|
||||
@@ -146,27 +147,27 @@ namespace DiscImageChef.Filesystems
|
||||
public abstract Errno Read(string path, long offset, long size, ref byte[] buf);
|
||||
|
||||
/// <summary>
|
||||
/// Lists contents from a directory.
|
||||
/// Lists contents from a directory.
|
||||
/// </summary>
|
||||
/// <param name="path">Directory path.</param>
|
||||
/// <param name="contents">Directory contents.</param>
|
||||
public abstract Errno ReadDir(string path, ref List<string> contents);
|
||||
|
||||
/// <summary>
|
||||
/// Gets information about the mounted volume.
|
||||
/// Gets information about the mounted volume.
|
||||
/// </summary>
|
||||
/// <param name="stat">Information about the mounted volume.</param>
|
||||
public abstract Errno StatFs(ref FileSystemInfo stat);
|
||||
|
||||
/// <summary>
|
||||
/// Gets information about a file or directory.
|
||||
/// Gets information about a file or directory.
|
||||
/// </summary>
|
||||
/// <param name="path">File path.</param>
|
||||
/// <param name="stat">File information.</param>
|
||||
public abstract Errno Stat(string path, ref FileEntryInfo stat);
|
||||
|
||||
/// <summary>
|
||||
/// Solves a symbolic link.
|
||||
/// Solves a symbolic link.
|
||||
/// </summary>
|
||||
/// <param name="path">Link path.</param>
|
||||
/// <param name="dest">Link destination.</param>
|
||||
|
||||
@@ -43,84 +43,6 @@ namespace DiscImageChef.Filesystems
|
||||
{
|
||||
public class Fossil : Filesystem
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct FossilHeader
|
||||
{
|
||||
/// <summary>
|
||||
/// Magic number
|
||||
/// </summary>
|
||||
public uint magic;
|
||||
/// <summary>
|
||||
/// Header version
|
||||
/// </summary>
|
||||
public ushort version;
|
||||
/// <summary>
|
||||
/// Block size
|
||||
/// </summary>
|
||||
public ushort blockSize;
|
||||
/// <summary>
|
||||
/// Block containing superblock
|
||||
/// </summary>
|
||||
public uint super;
|
||||
/// <summary>
|
||||
/// Block containing labels
|
||||
/// </summary>
|
||||
public uint label;
|
||||
/// <summary>
|
||||
/// Where do data blocks start
|
||||
/// </summary>
|
||||
public uint data;
|
||||
/// <summary>
|
||||
/// How many data blocks does it have
|
||||
/// </summary>
|
||||
public uint end;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct FossilSuperBlock
|
||||
{
|
||||
/// <summary>
|
||||
/// Magic number
|
||||
/// </summary>
|
||||
public uint magic;
|
||||
/// <summary>
|
||||
/// Header version
|
||||
/// </summary>
|
||||
public ushort version;
|
||||
/// <summary>
|
||||
/// file system low epoch
|
||||
/// </summary>
|
||||
public uint epochLow;
|
||||
/// <summary>
|
||||
/// file system high(active) epoch
|
||||
/// </summary>
|
||||
public uint epochHigh;
|
||||
/// <summary>
|
||||
/// next qid to allocate
|
||||
/// </summary>
|
||||
public ulong qid;
|
||||
/// <summary>
|
||||
/// data block number: root of active file system
|
||||
/// </summary>
|
||||
public int active;
|
||||
/// <summary>
|
||||
/// data block number: root of next file system to archive
|
||||
/// </summary>
|
||||
public int next;
|
||||
/// <summary>
|
||||
/// data block number: root of file system currently being archived
|
||||
/// </summary>
|
||||
public int current;
|
||||
/// <summary>
|
||||
/// Venti score of last successful archive
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)] public byte[] last;
|
||||
/// <summary>
|
||||
/// name of file system(just a comment)
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)] public byte[] name;
|
||||
}
|
||||
|
||||
const uint FOSSIL_HDR_MAGIC = 0x3776AE89;
|
||||
const uint FOSSIL_SB_MAGIC = 0x2340A3B1;
|
||||
// Fossil header starts at 128KiB
|
||||
@@ -166,8 +88,7 @@ namespace DiscImageChef.Filesystems
|
||||
return hdr.magic == FOSSIL_HDR_MAGIC;
|
||||
}
|
||||
|
||||
public override void GetInformation(ImagePlugin imagePlugin, Partition partition,
|
||||
out string information)
|
||||
public override void GetInformation(ImagePlugin imagePlugin, Partition partition, out string information)
|
||||
{
|
||||
information = "";
|
||||
if(imagePlugin.GetSectorSize() < 512) return;
|
||||
@@ -285,5 +206,83 @@ namespace DiscImageChef.Filesystems
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct FossilHeader
|
||||
{
|
||||
/// <summary>
|
||||
/// Magic number
|
||||
/// </summary>
|
||||
public uint magic;
|
||||
/// <summary>
|
||||
/// Header version
|
||||
/// </summary>
|
||||
public ushort version;
|
||||
/// <summary>
|
||||
/// Block size
|
||||
/// </summary>
|
||||
public ushort blockSize;
|
||||
/// <summary>
|
||||
/// Block containing superblock
|
||||
/// </summary>
|
||||
public uint super;
|
||||
/// <summary>
|
||||
/// Block containing labels
|
||||
/// </summary>
|
||||
public uint label;
|
||||
/// <summary>
|
||||
/// Where do data blocks start
|
||||
/// </summary>
|
||||
public uint data;
|
||||
/// <summary>
|
||||
/// How many data blocks does it have
|
||||
/// </summary>
|
||||
public uint end;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct FossilSuperBlock
|
||||
{
|
||||
/// <summary>
|
||||
/// Magic number
|
||||
/// </summary>
|
||||
public uint magic;
|
||||
/// <summary>
|
||||
/// Header version
|
||||
/// </summary>
|
||||
public ushort version;
|
||||
/// <summary>
|
||||
/// file system low epoch
|
||||
/// </summary>
|
||||
public uint epochLow;
|
||||
/// <summary>
|
||||
/// file system high(active) epoch
|
||||
/// </summary>
|
||||
public uint epochHigh;
|
||||
/// <summary>
|
||||
/// next qid to allocate
|
||||
/// </summary>
|
||||
public ulong qid;
|
||||
/// <summary>
|
||||
/// data block number: root of active file system
|
||||
/// </summary>
|
||||
public int active;
|
||||
/// <summary>
|
||||
/// data block number: root of next file system to archive
|
||||
/// </summary>
|
||||
public int next;
|
||||
/// <summary>
|
||||
/// data block number: root of file system currently being archived
|
||||
/// </summary>
|
||||
public int current;
|
||||
/// <summary>
|
||||
/// Venti score of last successful archive
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)] public byte[] last;
|
||||
/// <summary>
|
||||
/// name of file system(just a comment)
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)] public byte[] name;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -41,12 +41,11 @@ using Schemas;
|
||||
using hammer_crc_t = System.UInt32;
|
||||
using hammer_off_t = System.UInt64;
|
||||
using hammer_tid_t = System.UInt64;
|
||||
|
||||
#pragma warning disable 169
|
||||
|
||||
namespace DiscImageChef.Filesystems
|
||||
{
|
||||
[SuppressMessage("ReSharper", "BuiltInTypeReferenceStyle")]
|
||||
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
||||
public class HAMMER : Filesystem
|
||||
{
|
||||
const ulong HAMMER_FSBUF_VOLUME = 0xC8414D4DC5523031;
|
||||
@@ -92,8 +91,7 @@ namespace DiscImageChef.Filesystems
|
||||
return magic == HAMMER_FSBUF_VOLUME || magic == HAMMER_FSBUF_VOLUME_REV;
|
||||
}
|
||||
|
||||
public override void GetInformation(ImagePlugin imagePlugin, Partition partition,
|
||||
out string information)
|
||||
public override void GetInformation(ImagePlugin imagePlugin, Partition partition, out string information)
|
||||
{
|
||||
information = "";
|
||||
|
||||
@@ -115,7 +113,7 @@ namespace DiscImageChef.Filesystems
|
||||
{
|
||||
GCHandle handle = GCHandle.Alloc(sbSector, GCHandleType.Pinned);
|
||||
hammerSb = (HammerSuperBlock)Marshal.PtrToStructure(handle.AddrOfPinnedObject(),
|
||||
typeof(HammerSuperBlock));
|
||||
typeof(HammerSuperBlock));
|
||||
handle.Free();
|
||||
}
|
||||
else hammerSb = BigEndianMarshal.ByteArrayToStructureBigEndian<HammerSuperBlock>(sbSector);
|
||||
@@ -164,91 +162,6 @@ namespace DiscImageChef.Filesystems
|
||||
information = sb.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Be superblock
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct HammerSuperBlock
|
||||
{
|
||||
/// <summary><see cref="HAMMER_FSBUF_VOLUME"/> for a valid header</summary>
|
||||
public ulong vol_signature;
|
||||
|
||||
/* These are relative to block device offset, not zone offsets. */
|
||||
/// <summary>offset of boot area</summary>
|
||||
public long vol_bot_beg;
|
||||
/// <summary>offset of memory log</summary>
|
||||
public long vol_mem_beg;
|
||||
/// <summary>offset of the first buffer in volume</summary>
|
||||
public long vol_buf_beg;
|
||||
/// <summary>offset of volume EOF (on buffer boundary)</summary>
|
||||
public long vol_buf_end;
|
||||
public long vol_reserved01;
|
||||
|
||||
/// <summary>identify filesystem</summary>
|
||||
public Guid vol_fsid;
|
||||
/// <summary>identify filesystem type</summary>
|
||||
public Guid vol_fstype;
|
||||
/// <summary>filesystem label</summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)] public byte[] vol_label;
|
||||
|
||||
/// <summary>volume number within filesystem</summary>
|
||||
public int vol_no;
|
||||
/// <summary>number of volumes making up filesystem</summary>
|
||||
public int vol_count;
|
||||
|
||||
/// <summary>version control information</summary>
|
||||
public uint vol_version;
|
||||
/// <summary>header crc</summary>
|
||||
public hammer_crc_t vol_crc;
|
||||
/// <summary>volume flags</summary>
|
||||
public uint vol_flags;
|
||||
/// <summary>the root volume number (must be 0)</summary>
|
||||
public uint vol_rootvol;
|
||||
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] public uint[] vol_reserved;
|
||||
|
||||
/*
|
||||
* These fields are initialized and space is reserved in every
|
||||
* volume making up a HAMMER filesytem, but only the root volume
|
||||
* contains valid data. Note that vol0_stat_bigblocks does not
|
||||
* include big-blocks for freemap and undomap initially allocated
|
||||
* by newfs_hammer(8).
|
||||
*/
|
||||
/// <summary>total big-blocks when fs is empty</summary>
|
||||
public long vol0_stat_bigblocks;
|
||||
/// <summary>number of free big-blocks</summary>
|
||||
public long vol0_stat_freebigblocks;
|
||||
public long vol0_reserved01;
|
||||
/// <summary>for statfs only</summary>
|
||||
public long vol0_stat_inodes;
|
||||
public long vol0_reserved02;
|
||||
/// <summary>B-Tree root offset in zone-8</summary>
|
||||
public hammer_off_t vol0_btree_root;
|
||||
/// <summary>highest partially synchronized TID</summary>
|
||||
public hammer_tid_t vol0_next_tid;
|
||||
public hammer_off_t vol0_reserved03;
|
||||
|
||||
/// <summary>Blockmaps for zones. Not all zones use a blockmap. Note that the entire root blockmap is cached in the hammer_mount structure.</summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] public HammerBlockMap[] vol0_blockmap;
|
||||
|
||||
/// <summary>Array of zone-2 addresses for undo FIFO.</summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)] public hammer_off_t[] vol0_undo_array;
|
||||
}
|
||||
|
||||
struct HammerBlockMap
|
||||
{
|
||||
/// <summary>zone-2 offset only used by zone-4</summary>
|
||||
public hammer_off_t phys_offset;
|
||||
/// <summary>zone-X offset only used by zone-3</summary>
|
||||
public hammer_off_t first_offset;
|
||||
/// <summary>zone-X offset for allocation</summary>
|
||||
public hammer_off_t next_offset;
|
||||
/// <summary>zone-X offset only used by zone-3</summary>
|
||||
public hammer_off_t alloc_offset;
|
||||
public uint reserved01;
|
||||
public hammer_crc_t entry_crc;
|
||||
}
|
||||
|
||||
public override Errno Mount()
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
@@ -308,5 +221,96 @@ namespace DiscImageChef.Filesystems
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Hammer superblock
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
[SuppressMessage("ReSharper", "BuiltInTypeReferenceStyle")]
|
||||
struct HammerSuperBlock
|
||||
{
|
||||
/// <summary><see cref="HAMMER_FSBUF_VOLUME" /> for a valid header</summary>
|
||||
public ulong vol_signature;
|
||||
|
||||
/* These are relative to block device offset, not zone offsets. */
|
||||
/// <summary>offset of boot area</summary>
|
||||
public long vol_bot_beg;
|
||||
/// <summary>offset of memory log</summary>
|
||||
public long vol_mem_beg;
|
||||
/// <summary>offset of the first buffer in volume</summary>
|
||||
public long vol_buf_beg;
|
||||
/// <summary>offset of volume EOF (on buffer boundary)</summary>
|
||||
public long vol_buf_end;
|
||||
public long vol_reserved01;
|
||||
|
||||
/// <summary>identify filesystem</summary>
|
||||
public Guid vol_fsid;
|
||||
/// <summary>identify filesystem type</summary>
|
||||
public Guid vol_fstype;
|
||||
/// <summary>filesystem label</summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)] public byte[] vol_label;
|
||||
|
||||
/// <summary>volume number within filesystem</summary>
|
||||
public int vol_no;
|
||||
/// <summary>number of volumes making up filesystem</summary>
|
||||
public int vol_count;
|
||||
|
||||
/// <summary>version control information</summary>
|
||||
public uint vol_version;
|
||||
/// <summary>header crc</summary>
|
||||
public hammer_crc_t vol_crc;
|
||||
/// <summary>volume flags</summary>
|
||||
public uint vol_flags;
|
||||
/// <summary>the root volume number (must be 0)</summary>
|
||||
public uint vol_rootvol;
|
||||
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] public uint[] vol_reserved;
|
||||
|
||||
/*
|
||||
* These fields are initialized and space is reserved in every
|
||||
* volume making up a HAMMER filesytem, but only the root volume
|
||||
* contains valid data. Note that vol0_stat_bigblocks does not
|
||||
* include big-blocks for freemap and undomap initially allocated
|
||||
* by newfs_hammer(8).
|
||||
*/
|
||||
/// <summary>total big-blocks when fs is empty</summary>
|
||||
public long vol0_stat_bigblocks;
|
||||
/// <summary>number of free big-blocks</summary>
|
||||
public long vol0_stat_freebigblocks;
|
||||
public long vol0_reserved01;
|
||||
/// <summary>for statfs only</summary>
|
||||
public long vol0_stat_inodes;
|
||||
public long vol0_reserved02;
|
||||
/// <summary>B-Tree root offset in zone-8</summary>
|
||||
public hammer_off_t vol0_btree_root;
|
||||
/// <summary>highest partially synchronized TID</summary>
|
||||
public hammer_tid_t vol0_next_tid;
|
||||
public hammer_off_t vol0_reserved03;
|
||||
|
||||
/// <summary>
|
||||
/// Blockmaps for zones. Not all zones use a blockmap. Note that the entire root blockmap is cached in the
|
||||
/// hammer_mount structure.
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] public HammerBlockMap[] vol0_blockmap;
|
||||
|
||||
/// <summary>Array of zone-2 addresses for undo FIFO.</summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)] public hammer_off_t[] vol0_undo_array;
|
||||
}
|
||||
|
||||
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
||||
[SuppressMessage("ReSharper", "BuiltInTypeReferenceStyle")]
|
||||
struct HammerBlockMap
|
||||
{
|
||||
/// <summary>zone-2 offset only used by zone-4</summary>
|
||||
public hammer_off_t phys_offset;
|
||||
/// <summary>zone-X offset only used by zone-3</summary>
|
||||
public hammer_off_t first_offset;
|
||||
/// <summary>zone-X offset for allocation</summary>
|
||||
public hammer_off_t next_offset;
|
||||
/// <summary>zone-X offset only used by zone-3</summary>
|
||||
public hammer_off_t alloc_offset;
|
||||
public uint reserved01;
|
||||
public hammer_crc_t entry_crc;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -79,8 +79,7 @@ namespace DiscImageChef.Filesystems
|
||||
return magic1 == 0xF995E849 && magic2 == 0xFA53E9C5;
|
||||
}
|
||||
|
||||
public override void GetInformation(ImagePlugin imagePlugin, Partition partition,
|
||||
out string information)
|
||||
public override void GetInformation(ImagePlugin imagePlugin, Partition partition, out string information)
|
||||
{
|
||||
information = "";
|
||||
|
||||
@@ -95,7 +94,8 @@ namespace DiscImageChef.Filesystems
|
||||
|
||||
IntPtr bpbPtr = Marshal.AllocHGlobal(512);
|
||||
Marshal.Copy(hpfsBpbSector, 0, bpbPtr, 512);
|
||||
HPFS_BIOSParameterBlock hpfsBpb = (HPFS_BIOSParameterBlock)Marshal.PtrToStructure(bpbPtr, typeof(HPFS_BIOSParameterBlock));
|
||||
HPFS_BIOSParameterBlock hpfsBpb =
|
||||
(HPFS_BIOSParameterBlock)Marshal.PtrToStructure(bpbPtr, typeof(HPFS_BIOSParameterBlock));
|
||||
Marshal.FreeHGlobal(bpbPtr);
|
||||
|
||||
IntPtr sbPtr = Marshal.AllocHGlobal(512);
|
||||
@@ -214,148 +214,6 @@ namespace DiscImageChef.Filesystems
|
||||
information = sb.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// BIOS Parameter Block, at sector 0
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct HPFS_BIOSParameterBlock
|
||||
{
|
||||
/// <summary>0x000, Jump to boot code</summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] public byte[] jump;
|
||||
/// <summary>0x003, OEM Name, 8 bytes, space-padded</summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] public byte[] oem_name;
|
||||
/// <summary>0x00B, Bytes per sector</summary>
|
||||
public ushort bps;
|
||||
/// <summary>0x00D, Sectors per cluster</summary>
|
||||
public byte spc;
|
||||
/// <summary>0x00E, Reserved sectors between BPB and... does it have sense in HPFS?</summary>
|
||||
public ushort rsectors;
|
||||
/// <summary>0x010, Number of FATs... seriously?</summary>
|
||||
public byte fats_no;
|
||||
/// <summary>0x011, Number of entries on root directory... ok</summary>
|
||||
public ushort root_ent;
|
||||
/// <summary>0x013, Sectors in volume... doubt it</summary>
|
||||
public ushort sectors;
|
||||
/// <summary>0x015, Media descriptor</summary>
|
||||
public byte media;
|
||||
/// <summary>0x016, Sectors per FAT... again</summary>
|
||||
public ushort spfat;
|
||||
/// <summary>0x018, Sectors per track... you're kidding</summary>
|
||||
public ushort sptrk;
|
||||
/// <summary>0x01A, Heads... stop!</summary>
|
||||
public ushort heads;
|
||||
/// <summary>0x01C, Hidden sectors before BPB</summary>
|
||||
public uint hsectors;
|
||||
/// <summary>0x024, Sectors in volume if > 65535...</summary>
|
||||
public uint big_sectors;
|
||||
/// <summary>0x028, Drive number</summary>
|
||||
public byte drive_no;
|
||||
/// <summary>0x029, Volume flags?</summary>
|
||||
public byte nt_flags;
|
||||
/// <summary>0x02A, EPB signature, 0x29</summary>
|
||||
public byte signature;
|
||||
/// <summary>0x02B, Volume serial number</summary>
|
||||
public uint serial_no;
|
||||
/// <summary>0x02F, Volume label, 11 bytes, space-padded</summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 11)] public byte[] volume_label;
|
||||
/// <summary>0x03A, Filesystem type, 8 bytes, space-padded ("HPFS ")</summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] public byte[] fs_type;
|
||||
/// <summary>Boot code.</summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 448)] public byte[] boot_code;
|
||||
/// <summary>0x1FE, 0xAA55</summary>
|
||||
public ushort signature2;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// HPFS superblock at sector 16
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct HPFS_SuperBlock
|
||||
{
|
||||
/// <summary>0x000, 0xF995E849</summary>
|
||||
public uint magic1;
|
||||
/// <summary>0x004, 0xFA53E9C5</summary>
|
||||
public uint magic2;
|
||||
/// <summary>0x008, HPFS version</summary>
|
||||
public byte version;
|
||||
/// <summary>0x009, 2 if <= 4 GiB, 3 if > 4 GiB</summary>
|
||||
public byte func_version;
|
||||
/// <summary>0x00A, Alignment</summary>
|
||||
public ushort dummy;
|
||||
/// <summary>0x00C, LSN pointer to root fnode</summary>
|
||||
public uint root_fnode;
|
||||
/// <summary>0x010, Sectors on volume</summary>
|
||||
public uint sectors;
|
||||
/// <summary>0x014, Bad blocks on volume</summary>
|
||||
public uint badblocks;
|
||||
/// <summary>0x018, LSN pointer to volume bitmap</summary>
|
||||
public uint bitmap_lsn;
|
||||
/// <summary>0x01C, 0</summary>
|
||||
public uint zero1;
|
||||
/// <summary>0x020, LSN pointer to badblock directory</summary>
|
||||
public uint badblock_lsn;
|
||||
/// <summary>0x024, 0</summary>
|
||||
public uint zero2;
|
||||
/// <summary>0x028, Time of last CHKDSK</summary>
|
||||
public int last_chkdsk;
|
||||
/// <summary>0x02C, Time of last optimization</summary>
|
||||
public int last_optim;
|
||||
/// <summary>0x030, Sectors of dir band</summary>
|
||||
public uint dband_sectors;
|
||||
/// <summary>0x034, Start sector of dir band</summary>
|
||||
public uint dband_start;
|
||||
/// <summary>0x038, Last sector of dir band</summary>
|
||||
public uint dband_last;
|
||||
/// <summary>0x03C, LSN of free space bitmap</summary>
|
||||
public uint dband_bitmap;
|
||||
/// <summary>0x040, Can be used for volume name (32 bytes)</summary>
|
||||
public ulong zero3;
|
||||
/// <summary>0x048, ...</summary>
|
||||
public ulong zero4;
|
||||
/// <summary>0x04C, ...</summary>
|
||||
public ulong zero5;
|
||||
/// <summary>0x050, ...;</summary>
|
||||
public ulong zero6;
|
||||
/// <summary>0x058, LSN pointer to ACLs (only HPFS386)</summary>
|
||||
public uint acl_start;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// HPFS spareblock at sector 17
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct HPFS_SpareBlock
|
||||
{
|
||||
/// <summary>0x000, 0xF9911849</summary>
|
||||
public uint magic1;
|
||||
/// <summary>0x004, 0xFA5229C5</summary>
|
||||
public uint magic2;
|
||||
/// <summary>0x008, HPFS flags</summary>
|
||||
public byte flags1;
|
||||
/// <summary>0x009, HPFS386 flags</summary>
|
||||
public byte flags2;
|
||||
/// <summary>0x00A, Alignment</summary>
|
||||
public ushort dummy;
|
||||
/// <summary>0x00C, LSN of hotfix directory</summary>
|
||||
public uint hotfix_start;
|
||||
/// <summary>0x010, Used hotfixes</summary>
|
||||
public uint hotfix_used;
|
||||
/// <summary>0x014, Total hotfixes available</summary>
|
||||
public uint hotfix_entries;
|
||||
/// <summary>0x018, Unused spare dnodes</summary>
|
||||
public uint spare_dnodes_free;
|
||||
/// <summary>0x01C, Length of spare dnodes list</summary>
|
||||
public uint spare_dnodes;
|
||||
/// <summary>0x020, LSN of codepage directory</summary>
|
||||
public uint codepage_lsn;
|
||||
/// <summary>0x024, Number of codepages used</summary>
|
||||
public uint codepages;
|
||||
/// <summary>0x028, SuperBlock CRC32 (only HPFS386)</summary>
|
||||
public uint sb_crc32;
|
||||
/// <summary>0x02C, SpareBlock CRC32 (only HPFS386)</summary>
|
||||
public uint sp_crc32;
|
||||
}
|
||||
|
||||
public override Errno Mount()
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
@@ -415,5 +273,147 @@ namespace DiscImageChef.Filesystems
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// BIOS Parameter Block, at sector 0
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct HPFS_BIOSParameterBlock
|
||||
{
|
||||
/// <summary>0x000, Jump to boot code</summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] public byte[] jump;
|
||||
/// <summary>0x003, OEM Name, 8 bytes, space-padded</summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] public byte[] oem_name;
|
||||
/// <summary>0x00B, Bytes per sector</summary>
|
||||
public ushort bps;
|
||||
/// <summary>0x00D, Sectors per cluster</summary>
|
||||
public byte spc;
|
||||
/// <summary>0x00E, Reserved sectors between BPB and... does it have sense in HPFS?</summary>
|
||||
public ushort rsectors;
|
||||
/// <summary>0x010, Number of FATs... seriously?</summary>
|
||||
public byte fats_no;
|
||||
/// <summary>0x011, Number of entries on root directory... ok</summary>
|
||||
public ushort root_ent;
|
||||
/// <summary>0x013, Sectors in volume... doubt it</summary>
|
||||
public ushort sectors;
|
||||
/// <summary>0x015, Media descriptor</summary>
|
||||
public byte media;
|
||||
/// <summary>0x016, Sectors per FAT... again</summary>
|
||||
public ushort spfat;
|
||||
/// <summary>0x018, Sectors per track... you're kidding</summary>
|
||||
public ushort sptrk;
|
||||
/// <summary>0x01A, Heads... stop!</summary>
|
||||
public ushort heads;
|
||||
/// <summary>0x01C, Hidden sectors before BPB</summary>
|
||||
public uint hsectors;
|
||||
/// <summary>0x024, Sectors in volume if > 65535...</summary>
|
||||
public uint big_sectors;
|
||||
/// <summary>0x028, Drive number</summary>
|
||||
public byte drive_no;
|
||||
/// <summary>0x029, Volume flags?</summary>
|
||||
public byte nt_flags;
|
||||
/// <summary>0x02A, EPB signature, 0x29</summary>
|
||||
public byte signature;
|
||||
/// <summary>0x02B, Volume serial number</summary>
|
||||
public uint serial_no;
|
||||
/// <summary>0x02F, Volume label, 11 bytes, space-padded</summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 11)] public byte[] volume_label;
|
||||
/// <summary>0x03A, Filesystem type, 8 bytes, space-padded ("HPFS ")</summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] public byte[] fs_type;
|
||||
/// <summary>Boot code.</summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 448)] public byte[] boot_code;
|
||||
/// <summary>0x1FE, 0xAA55</summary>
|
||||
public ushort signature2;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// HPFS superblock at sector 16
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct HPFS_SuperBlock
|
||||
{
|
||||
/// <summary>0x000, 0xF995E849</summary>
|
||||
public uint magic1;
|
||||
/// <summary>0x004, 0xFA53E9C5</summary>
|
||||
public uint magic2;
|
||||
/// <summary>0x008, HPFS version</summary>
|
||||
public byte version;
|
||||
/// <summary>0x009, 2 if <= 4 GiB, 3 if > 4 GiB</summary>
|
||||
public byte func_version;
|
||||
/// <summary>0x00A, Alignment</summary>
|
||||
public ushort dummy;
|
||||
/// <summary>0x00C, LSN pointer to root fnode</summary>
|
||||
public uint root_fnode;
|
||||
/// <summary>0x010, Sectors on volume</summary>
|
||||
public uint sectors;
|
||||
/// <summary>0x014, Bad blocks on volume</summary>
|
||||
public uint badblocks;
|
||||
/// <summary>0x018, LSN pointer to volume bitmap</summary>
|
||||
public uint bitmap_lsn;
|
||||
/// <summary>0x01C, 0</summary>
|
||||
public uint zero1;
|
||||
/// <summary>0x020, LSN pointer to badblock directory</summary>
|
||||
public uint badblock_lsn;
|
||||
/// <summary>0x024, 0</summary>
|
||||
public uint zero2;
|
||||
/// <summary>0x028, Time of last CHKDSK</summary>
|
||||
public int last_chkdsk;
|
||||
/// <summary>0x02C, Time of last optimization</summary>
|
||||
public int last_optim;
|
||||
/// <summary>0x030, Sectors of dir band</summary>
|
||||
public uint dband_sectors;
|
||||
/// <summary>0x034, Start sector of dir band</summary>
|
||||
public uint dband_start;
|
||||
/// <summary>0x038, Last sector of dir band</summary>
|
||||
public uint dband_last;
|
||||
/// <summary>0x03C, LSN of free space bitmap</summary>
|
||||
public uint dband_bitmap;
|
||||
/// <summary>0x040, Can be used for volume name (32 bytes)</summary>
|
||||
public ulong zero3;
|
||||
/// <summary>0x048, ...</summary>
|
||||
public ulong zero4;
|
||||
/// <summary>0x04C, ...</summary>
|
||||
public ulong zero5;
|
||||
/// <summary>0x050, ...;</summary>
|
||||
public ulong zero6;
|
||||
/// <summary>0x058, LSN pointer to ACLs (only HPFS386)</summary>
|
||||
public uint acl_start;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// HPFS spareblock at sector 17
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct HPFS_SpareBlock
|
||||
{
|
||||
/// <summary>0x000, 0xF9911849</summary>
|
||||
public uint magic1;
|
||||
/// <summary>0x004, 0xFA5229C5</summary>
|
||||
public uint magic2;
|
||||
/// <summary>0x008, HPFS flags</summary>
|
||||
public byte flags1;
|
||||
/// <summary>0x009, HPFS386 flags</summary>
|
||||
public byte flags2;
|
||||
/// <summary>0x00A, Alignment</summary>
|
||||
public ushort dummy;
|
||||
/// <summary>0x00C, LSN of hotfix directory</summary>
|
||||
public uint hotfix_start;
|
||||
/// <summary>0x010, Used hotfixes</summary>
|
||||
public uint hotfix_used;
|
||||
/// <summary>0x014, Total hotfixes available</summary>
|
||||
public uint hotfix_entries;
|
||||
/// <summary>0x018, Unused spare dnodes</summary>
|
||||
public uint spare_dnodes_free;
|
||||
/// <summary>0x01C, Length of spare dnodes list</summary>
|
||||
public uint spare_dnodes;
|
||||
/// <summary>0x020, LSN of codepage directory</summary>
|
||||
public uint codepage_lsn;
|
||||
/// <summary>0x024, Number of codepages used</summary>
|
||||
public uint codepages;
|
||||
/// <summary>0x028, SuperBlock CRC32 (only HPFS386)</summary>
|
||||
public uint sb_crc32;
|
||||
/// <summary>0x02C, SpareBlock CRC32 (only HPFS386)</summary>
|
||||
public uint sp_crc32;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -77,8 +77,7 @@ namespace DiscImageChef.Filesystems.ISO9660
|
||||
CurrentEncoding.GetString(vdMagic) == CDI_MAGIC;
|
||||
}
|
||||
|
||||
public override void GetInformation(ImagePlugin imagePlugin, Partition partition,
|
||||
out string information)
|
||||
public override void GetInformation(ImagePlugin imagePlugin, Partition partition, out string information)
|
||||
{
|
||||
information = "";
|
||||
StringBuilder isoMetadata = new StringBuilder();
|
||||
@@ -179,8 +178,7 @@ namespace DiscImageChef.Filesystems.ISO9660
|
||||
}
|
||||
else if(cdi)
|
||||
fsvd =
|
||||
BigEndianMarshal
|
||||
.ByteArrayToStructureBigEndian<FileStructureVolumeDescriptor>(vdSector);
|
||||
BigEndianMarshal.ByteArrayToStructureBigEndian<FileStructureVolumeDescriptor>(vdSector);
|
||||
else
|
||||
{
|
||||
IntPtr ptr = Marshal.AllocHGlobal(2048);
|
||||
@@ -194,14 +192,16 @@ namespace DiscImageChef.Filesystems.ISO9660
|
||||
{
|
||||
IntPtr ptr = Marshal.AllocHGlobal(2048);
|
||||
Marshal.Copy(vdSector, 0, ptr, 2048);
|
||||
PrimaryVolumeDescriptor svd = (PrimaryVolumeDescriptor)Marshal.PtrToStructure(ptr, typeof(PrimaryVolumeDescriptor));
|
||||
PrimaryVolumeDescriptor svd =
|
||||
(PrimaryVolumeDescriptor)Marshal.PtrToStructure(ptr, typeof(PrimaryVolumeDescriptor));
|
||||
Marshal.FreeHGlobal(ptr);
|
||||
|
||||
// Check if this is Joliet
|
||||
if(svd.escape_sequences[0] == '%' && svd.escape_sequences[1] == '/')
|
||||
if(svd.escape_sequences[2] == '@' || svd.escape_sequences[2] == 'C' ||
|
||||
svd.escape_sequences[2] == 'E') jolietvd = svd;
|
||||
else DicConsole.WriteLine("ISO9660 plugin", "Found unknown supplementary volume descriptor");
|
||||
else
|
||||
DicConsole.WriteLine("ISO9660 plugin", "Found unknown supplementary volume descriptor");
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -302,7 +302,8 @@ namespace DiscImageChef.Filesystems.ISO9660
|
||||
|
||||
ushort nextSignature = BigEndianBitConverter.ToUInt16(sa, saOff);
|
||||
|
||||
switch(nextSignature) {
|
||||
switch(nextSignature)
|
||||
{
|
||||
// Easy, contains size field
|
||||
case APPLE_MAGIC:
|
||||
apple = true;
|
||||
@@ -344,7 +345,8 @@ namespace DiscImageChef.Filesystems.ISO9660
|
||||
{
|
||||
nextSignature = BigEndianBitConverter.ToUInt16(sa, saOff);
|
||||
|
||||
switch(nextSignature) {
|
||||
switch(nextSignature)
|
||||
{
|
||||
case APPLE_MAGIC:
|
||||
if(sa[saOff + 3] == 1 && sa[saOff + 2] == 7) apple = true;
|
||||
else apple |= sa[saOff + 3] != 1;
|
||||
@@ -352,8 +354,8 @@ namespace DiscImageChef.Filesystems.ISO9660
|
||||
case SUSP_CONTINUATION when saOff + sa[saOff + 2] <= saLen:
|
||||
byte[] ce = new byte[sa[saOff + 2]];
|
||||
Array.Copy(sa, saOff, ce, 0, ce.Length);
|
||||
ContinuationArea ca =
|
||||
BigEndianMarshal.ByteArrayToStructureBigEndian<ContinuationArea>(ce);
|
||||
ContinuationArea ca = BigEndianMarshal
|
||||
.ByteArrayToStructureBigEndian<ContinuationArea>(ce);
|
||||
contareas.Add(ca);
|
||||
break;
|
||||
case SUSP_REFERENCE when saOff + sa[saOff + 2] <= saLen:
|
||||
@@ -371,8 +373,8 @@ namespace DiscImageChef.Filesystems.ISO9660
|
||||
|
||||
ziso |= nextSignature == ZISO_MAGIC;
|
||||
amiga |= nextSignature == AMIGA_MAGIC;
|
||||
aaip |= nextSignature == AAIP_MAGIC ||
|
||||
nextSignature == AAIP_MAGIC_OLD && sa[saOff + 3] == 1 && sa[saOff + 2] >= 9;
|
||||
aaip |= nextSignature == AAIP_MAGIC || nextSignature == AAIP_MAGIC_OLD &&
|
||||
sa[saOff + 3] == 1 && sa[saOff + 2] >= 9;
|
||||
|
||||
saOff += sa[saOff + 2];
|
||||
|
||||
@@ -394,7 +396,7 @@ namespace DiscImageChef.Filesystems.ISO9660
|
||||
foreach(ContinuationArea ca in contareas)
|
||||
{
|
||||
uint caLen = (ca.ca_length_be + ca.offset_be) /
|
||||
(highSierra ? hsvd.Value.logical_block_size : pvd.Value.logical_block_size);
|
||||
(highSierra ? hsvd.Value.logical_block_size : pvd.Value.logical_block_size);
|
||||
if((ca.ca_length_be + ca.offset_be) %
|
||||
(highSierra ? hsvd.Value.logical_block_size : pvd.Value.logical_block_size) > 0) caLen++;
|
||||
|
||||
@@ -407,7 +409,8 @@ namespace DiscImageChef.Filesystems.ISO9660
|
||||
{
|
||||
ushort nextSignature = BigEndianBitConverter.ToUInt16(caData, caOff);
|
||||
|
||||
switch(nextSignature) {
|
||||
switch(nextSignature)
|
||||
{
|
||||
// Apple never said to include its extensions inside a continuation area, but just in case
|
||||
case APPLE_MAGIC:
|
||||
if(caData[caOff + 3] == 1 && caData[caOff + 2] == 7) apple = true;
|
||||
@@ -428,8 +431,8 @@ namespace DiscImageChef.Filesystems.ISO9660
|
||||
|
||||
ziso |= nextSignature == ZISO_MAGIC;
|
||||
amiga |= nextSignature == AMIGA_MAGIC;
|
||||
aaip |= nextSignature == AAIP_MAGIC ||
|
||||
nextSignature == AAIP_MAGIC_OLD && caData[caOff + 3] == 1 && caData[caOff + 2] >= 9;
|
||||
aaip |= nextSignature == AAIP_MAGIC || nextSignature == AAIP_MAGIC_OLD && caData[caOff + 3] == 1 &&
|
||||
caData[caOff + 2] >= 9;
|
||||
|
||||
caOff += caData[caOff + 2];
|
||||
}
|
||||
@@ -555,7 +558,8 @@ namespace DiscImageChef.Filesystems.ISO9660
|
||||
|
||||
IntPtr ptr = Marshal.AllocHGlobal(EL_TORITO_ENTRY_SIZE);
|
||||
Marshal.Copy(vdSector, toritoOff, ptr, EL_TORITO_ENTRY_SIZE);
|
||||
ElToritoValidationEntry valentry = (ElToritoValidationEntry)Marshal.PtrToStructure(ptr, typeof(ElToritoValidationEntry));
|
||||
ElToritoValidationEntry valentry =
|
||||
(ElToritoValidationEntry)Marshal.PtrToStructure(ptr, typeof(ElToritoValidationEntry));
|
||||
Marshal.FreeHGlobal(ptr);
|
||||
|
||||
if(valentry.signature != EL_TORITO_MAGIC) goto exit_torito;
|
||||
@@ -564,11 +568,13 @@ namespace DiscImageChef.Filesystems.ISO9660
|
||||
|
||||
ptr = Marshal.AllocHGlobal(EL_TORITO_ENTRY_SIZE);
|
||||
Marshal.Copy(vdSector, toritoOff, ptr, EL_TORITO_ENTRY_SIZE);
|
||||
ElToritoInitialEntry initialEntry = (ElToritoInitialEntry)Marshal.PtrToStructure(ptr, typeof(ElToritoInitialEntry));
|
||||
ElToritoInitialEntry initialEntry =
|
||||
(ElToritoInitialEntry)Marshal.PtrToStructure(ptr, typeof(ElToritoInitialEntry));
|
||||
Marshal.FreeHGlobal(ptr);
|
||||
initialEntry.boot_type = (ElToritoEmulation)((byte)initialEntry.boot_type & 0xF);
|
||||
|
||||
byte[] bootImage = imagePlugin.ReadSectors(initialEntry.load_rba + partition.Start, initialEntry.sector_count);
|
||||
byte[] bootImage =
|
||||
imagePlugin.ReadSectors(initialEntry.load_rba + partition.Start, initialEntry.sector_count);
|
||||
|
||||
isoMetadata.AppendLine("----------------------");
|
||||
isoMetadata.AppendLine("EL TORITO INFORMATION:");
|
||||
@@ -620,11 +626,12 @@ namespace DiscImageChef.Filesystems.ISO9660
|
||||
const int SECTION_COUNTER = 2;
|
||||
|
||||
while(toritoOff < vdSector.Length && (vdSector[toritoOff] == (byte)ElToritoIndicator.Header ||
|
||||
vdSector[toritoOff] == (byte)ElToritoIndicator.LastHeader))
|
||||
vdSector[toritoOff] == (byte)ElToritoIndicator.LastHeader))
|
||||
{
|
||||
ptr = Marshal.AllocHGlobal(EL_TORITO_ENTRY_SIZE);
|
||||
Marshal.Copy(vdSector, toritoOff, ptr, EL_TORITO_ENTRY_SIZE);
|
||||
ElToritoSectionHeaderEntry sectionHeader = (ElToritoSectionHeaderEntry)Marshal.PtrToStructure(ptr, typeof(ElToritoSectionHeaderEntry));
|
||||
ElToritoSectionHeaderEntry sectionHeader =
|
||||
(ElToritoSectionHeaderEntry)Marshal.PtrToStructure(ptr, typeof(ElToritoSectionHeaderEntry));
|
||||
Marshal.FreeHGlobal(ptr);
|
||||
toritoOff += EL_TORITO_ENTRY_SIZE;
|
||||
|
||||
@@ -637,16 +644,16 @@ namespace DiscImageChef.Filesystems.ISO9660
|
||||
{
|
||||
ptr = Marshal.AllocHGlobal(EL_TORITO_ENTRY_SIZE);
|
||||
Marshal.Copy(vdSector, toritoOff, ptr, EL_TORITO_ENTRY_SIZE);
|
||||
ElToritoSectionEntry sectionEntry = (ElToritoSectionEntry)Marshal.PtrToStructure(ptr, typeof(ElToritoSectionEntry));
|
||||
ElToritoSectionEntry sectionEntry =
|
||||
(ElToritoSectionEntry)Marshal.PtrToStructure(ptr, typeof(ElToritoSectionEntry));
|
||||
Marshal.FreeHGlobal(ptr);
|
||||
toritoOff += EL_TORITO_ENTRY_SIZE;
|
||||
|
||||
isoMetadata.AppendFormat("\tEntry {0}:", entryCounter);
|
||||
if(sectionEntry.bootable == ElToritoIndicator.Bootable)
|
||||
{
|
||||
bootImage =
|
||||
imagePlugin.ReadSectors(sectionEntry.load_rba + partition.Start,
|
||||
sectionEntry.sector_count);
|
||||
bootImage = imagePlugin.ReadSectors(sectionEntry.load_rba + partition.Start,
|
||||
sectionEntry.sector_count);
|
||||
isoMetadata.AppendFormat("\t\tBootable on {0}", sectionHeader.platform_id).AppendLine();
|
||||
isoMetadata.AppendFormat("\t\tBootable image starts at sector {0} and runs for {1} sectors",
|
||||
sectionEntry.load_rba, sectionEntry.sector_count).AppendLine();
|
||||
@@ -684,8 +691,8 @@ namespace DiscImageChef.Filesystems.ISO9660
|
||||
sectionEntry.selection_criteria_type).AppendLine();
|
||||
isoMetadata.AppendFormat("\t\tSystem type: 0x{0:X2}", sectionEntry.system_type)
|
||||
.AppendLine();
|
||||
isoMetadata.AppendFormat("\t\tBootable image's SHA1: {0}",
|
||||
sha1Ctx.Data(bootImage, out _)).AppendLine();
|
||||
isoMetadata.AppendFormat("\t\tBootable image's SHA1: {0}", sha1Ctx.Data(bootImage, out _))
|
||||
.AppendLine();
|
||||
}
|
||||
else isoMetadata.AppendLine("\t\tNot bootable");
|
||||
|
||||
@@ -700,7 +707,8 @@ namespace DiscImageChef.Filesystems.ISO9660
|
||||
{
|
||||
ptr = Marshal.AllocHGlobal(EL_TORITO_ENTRY_SIZE);
|
||||
Marshal.Copy(vdSector, toritoOff, ptr, EL_TORITO_ENTRY_SIZE);
|
||||
ElToritoSectionEntryExtension sectionExtension = (ElToritoSectionEntryExtension)
|
||||
ElToritoSectionEntryExtension sectionExtension =
|
||||
(ElToritoSectionEntryExtension)
|
||||
Marshal.PtrToStructure(ptr, typeof(ElToritoSectionEntryExtension));
|
||||
Marshal.FreeHGlobal(ptr);
|
||||
toritoOff += EL_TORITO_ENTRY_SIZE;
|
||||
|
||||
@@ -38,6 +38,49 @@ namespace DiscImageChef.Filesystems.ISO9660
|
||||
{
|
||||
public partial class ISO9660
|
||||
{
|
||||
static DecodedVolumeDescriptor DecodeVolumeDescriptor(FileStructureVolumeDescriptor pvd)
|
||||
{
|
||||
DecodedVolumeDescriptor decodedVD = new DecodedVolumeDescriptor
|
||||
{
|
||||
SystemIdentifier = Encoding.ASCII.GetString(pvd.system_id).TrimEnd().Trim('\0'),
|
||||
VolumeIdentifier = Encoding.ASCII.GetString(pvd.volume_id).TrimEnd().Trim('\0'),
|
||||
VolumeSetIdentifier = Encoding.ASCII.GetString(pvd.volume_set_id).TrimEnd().Trim('\0'),
|
||||
PublisherIdentifier = Encoding.ASCII.GetString(pvd.publisher_id).TrimEnd().Trim('\0'),
|
||||
DataPreparerIdentifier = Encoding.ASCII.GetString(pvd.preparer_id).TrimEnd().Trim('\0'),
|
||||
ApplicationIdentifier = Encoding.ASCII.GetString(pvd.application_data).TrimEnd().Trim('\0')
|
||||
};
|
||||
|
||||
if(pvd.creation_date[0] == '0' || pvd.creation_date[0] == 0x00) decodedVD.CreationTime = DateTime.MinValue;
|
||||
else decodedVD.CreationTime = DateHandlers.HighSierraToDateTime(pvd.creation_date);
|
||||
|
||||
if(pvd.modification_date[0] == '0' || pvd.modification_date[0] == 0x00)
|
||||
decodedVD.HasModificationTime = false;
|
||||
else
|
||||
{
|
||||
decodedVD.HasModificationTime = true;
|
||||
decodedVD.ModificationTime = DateHandlers.HighSierraToDateTime(pvd.modification_date);
|
||||
}
|
||||
|
||||
if(pvd.expiration_date[0] == '0' || pvd.expiration_date[0] == 0x00) decodedVD.HasExpirationTime = false;
|
||||
else
|
||||
{
|
||||
decodedVD.HasExpirationTime = true;
|
||||
decodedVD.ExpirationTime = DateHandlers.HighSierraToDateTime(pvd.expiration_date);
|
||||
}
|
||||
|
||||
if(pvd.effective_date[0] == '0' || pvd.effective_date[0] == 0x00) decodedVD.HasEffectiveTime = false;
|
||||
else
|
||||
{
|
||||
decodedVD.HasEffectiveTime = true;
|
||||
decodedVD.EffectiveTime = DateHandlers.HighSierraToDateTime(pvd.effective_date);
|
||||
}
|
||||
|
||||
decodedVD.Blocks = pvd.volume_space_size;
|
||||
decodedVD.BlockSize = pvd.logical_block_size;
|
||||
|
||||
return decodedVD;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct FileStructureVolumeDescriptor
|
||||
{
|
||||
@@ -115,48 +158,5 @@ namespace DiscImageChef.Filesystems.ISO9660
|
||||
public byte file_no;
|
||||
public byte reserved2;
|
||||
}
|
||||
|
||||
static DecodedVolumeDescriptor DecodeVolumeDescriptor(FileStructureVolumeDescriptor pvd)
|
||||
{
|
||||
DecodedVolumeDescriptor decodedVD = new DecodedVolumeDescriptor
|
||||
{
|
||||
SystemIdentifier = Encoding.ASCII.GetString(pvd.system_id).TrimEnd().Trim('\0'),
|
||||
VolumeIdentifier = Encoding.ASCII.GetString(pvd.volume_id).TrimEnd().Trim('\0'),
|
||||
VolumeSetIdentifier = Encoding.ASCII.GetString(pvd.volume_set_id).TrimEnd().Trim('\0'),
|
||||
PublisherIdentifier = Encoding.ASCII.GetString(pvd.publisher_id).TrimEnd().Trim('\0'),
|
||||
DataPreparerIdentifier = Encoding.ASCII.GetString(pvd.preparer_id).TrimEnd().Trim('\0'),
|
||||
ApplicationIdentifier = Encoding.ASCII.GetString(pvd.application_data).TrimEnd().Trim('\0')
|
||||
};
|
||||
|
||||
if(pvd.creation_date[0] == '0' || pvd.creation_date[0] == 0x00)
|
||||
decodedVD.CreationTime = DateTime.MinValue;
|
||||
else decodedVD.CreationTime = DateHandlers.HighSierraToDateTime(pvd.creation_date);
|
||||
|
||||
if(pvd.modification_date[0] == '0' || pvd.modification_date[0] == 0x00) decodedVD.HasModificationTime = false;
|
||||
else
|
||||
{
|
||||
decodedVD.HasModificationTime = true;
|
||||
decodedVD.ModificationTime = DateHandlers.HighSierraToDateTime(pvd.modification_date);
|
||||
}
|
||||
|
||||
if(pvd.expiration_date[0] == '0' || pvd.expiration_date[0] == 0x00) decodedVD.HasExpirationTime = false;
|
||||
else
|
||||
{
|
||||
decodedVD.HasExpirationTime = true;
|
||||
decodedVD.ExpirationTime = DateHandlers.HighSierraToDateTime(pvd.expiration_date);
|
||||
}
|
||||
|
||||
if(pvd.effective_date[0] == '0' || pvd.effective_date[0] == 0x00) decodedVD.HasEffectiveTime = false;
|
||||
else
|
||||
{
|
||||
decodedVD.HasEffectiveTime = true;
|
||||
decodedVD.EffectiveTime = DateHandlers.HighSierraToDateTime(pvd.effective_date);
|
||||
}
|
||||
|
||||
decodedVD.Blocks = pvd.volume_space_size;
|
||||
decodedVD.BlockSize = pvd.logical_block_size;
|
||||
|
||||
return decodedVD;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -38,6 +38,49 @@ namespace DiscImageChef.Filesystems.ISO9660
|
||||
{
|
||||
public partial class ISO9660
|
||||
{
|
||||
static DecodedVolumeDescriptor DecodeVolumeDescriptor(HighSierraPrimaryVolumeDescriptor pvd)
|
||||
{
|
||||
DecodedVolumeDescriptor decodedVD = new DecodedVolumeDescriptor
|
||||
{
|
||||
SystemIdentifier = Encoding.ASCII.GetString(pvd.system_id).TrimEnd().Trim('\0'),
|
||||
VolumeIdentifier = Encoding.ASCII.GetString(pvd.volume_id).TrimEnd().Trim('\0'),
|
||||
VolumeSetIdentifier = Encoding.ASCII.GetString(pvd.volume_set_id).TrimEnd().Trim('\0'),
|
||||
PublisherIdentifier = Encoding.ASCII.GetString(pvd.publisher_id).TrimEnd().Trim('\0'),
|
||||
DataPreparerIdentifier = Encoding.ASCII.GetString(pvd.preparer_id).TrimEnd().Trim('\0'),
|
||||
ApplicationIdentifier = Encoding.ASCII.GetString(pvd.application_data).TrimEnd().Trim('\0')
|
||||
};
|
||||
|
||||
if(pvd.creation_date[0] == '0' || pvd.creation_date[0] == 0x00) decodedVD.CreationTime = DateTime.MinValue;
|
||||
else decodedVD.CreationTime = DateHandlers.HighSierraToDateTime(pvd.creation_date);
|
||||
|
||||
if(pvd.modification_date[0] == '0' || pvd.modification_date[0] == 0x00)
|
||||
decodedVD.HasModificationTime = false;
|
||||
else
|
||||
{
|
||||
decodedVD.HasModificationTime = true;
|
||||
decodedVD.ModificationTime = DateHandlers.HighSierraToDateTime(pvd.modification_date);
|
||||
}
|
||||
|
||||
if(pvd.expiration_date[0] == '0' || pvd.expiration_date[0] == 0x00) decodedVD.HasExpirationTime = false;
|
||||
else
|
||||
{
|
||||
decodedVD.HasExpirationTime = true;
|
||||
decodedVD.ExpirationTime = DateHandlers.HighSierraToDateTime(pvd.expiration_date);
|
||||
}
|
||||
|
||||
if(pvd.effective_date[0] == '0' || pvd.effective_date[0] == 0x00) decodedVD.HasEffectiveTime = false;
|
||||
else
|
||||
{
|
||||
decodedVD.HasEffectiveTime = true;
|
||||
decodedVD.EffectiveTime = DateHandlers.HighSierraToDateTime(pvd.effective_date);
|
||||
}
|
||||
|
||||
decodedVD.Blocks = pvd.volume_space_size;
|
||||
decodedVD.BlockSize = pvd.logical_block_size;
|
||||
|
||||
return decodedVD;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct HighSierraPrimaryVolumeDescriptor
|
||||
{
|
||||
@@ -107,48 +150,5 @@ namespace DiscImageChef.Filesystems.ISO9660
|
||||
public byte name_len;
|
||||
// Followed by name[name_len] and then system area until length arrives
|
||||
}
|
||||
|
||||
static DecodedVolumeDescriptor DecodeVolumeDescriptor(HighSierraPrimaryVolumeDescriptor pvd)
|
||||
{
|
||||
DecodedVolumeDescriptor decodedVD = new DecodedVolumeDescriptor
|
||||
{
|
||||
SystemIdentifier = Encoding.ASCII.GetString(pvd.system_id).TrimEnd().Trim('\0'),
|
||||
VolumeIdentifier = Encoding.ASCII.GetString(pvd.volume_id).TrimEnd().Trim('\0'),
|
||||
VolumeSetIdentifier = Encoding.ASCII.GetString(pvd.volume_set_id).TrimEnd().Trim('\0'),
|
||||
PublisherIdentifier = Encoding.ASCII.GetString(pvd.publisher_id).TrimEnd().Trim('\0'),
|
||||
DataPreparerIdentifier = Encoding.ASCII.GetString(pvd.preparer_id).TrimEnd().Trim('\0'),
|
||||
ApplicationIdentifier = Encoding.ASCII.GetString(pvd.application_data).TrimEnd().Trim('\0')
|
||||
};
|
||||
|
||||
if(pvd.creation_date[0] == '0' || pvd.creation_date[0] == 0x00)
|
||||
decodedVD.CreationTime = DateTime.MinValue;
|
||||
else decodedVD.CreationTime = DateHandlers.HighSierraToDateTime(pvd.creation_date);
|
||||
|
||||
if(pvd.modification_date[0] == '0' || pvd.modification_date[0] == 0x00) decodedVD.HasModificationTime = false;
|
||||
else
|
||||
{
|
||||
decodedVD.HasModificationTime = true;
|
||||
decodedVD.ModificationTime = DateHandlers.HighSierraToDateTime(pvd.modification_date);
|
||||
}
|
||||
|
||||
if(pvd.expiration_date[0] == '0' || pvd.expiration_date[0] == 0x00) decodedVD.HasExpirationTime = false;
|
||||
else
|
||||
{
|
||||
decodedVD.HasExpirationTime = true;
|
||||
decodedVD.ExpirationTime = DateHandlers.HighSierraToDateTime(pvd.expiration_date);
|
||||
}
|
||||
|
||||
if(pvd.effective_date[0] == '0' || pvd.effective_date[0] == 0x00) decodedVD.HasEffectiveTime = false;
|
||||
else
|
||||
{
|
||||
decodedVD.HasEffectiveTime = true;
|
||||
decodedVD.EffectiveTime = DateHandlers.HighSierraToDateTime(pvd.effective_date);
|
||||
}
|
||||
|
||||
decodedVD.Blocks = pvd.volume_space_size;
|
||||
decodedVD.BlockSize = pvd.logical_block_size;
|
||||
|
||||
return decodedVD;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -38,6 +38,49 @@ namespace DiscImageChef.Filesystems.ISO9660
|
||||
{
|
||||
public partial class ISO9660
|
||||
{
|
||||
static DecodedVolumeDescriptor DecodeVolumeDescriptor(PrimaryVolumeDescriptor pvd)
|
||||
{
|
||||
DecodedVolumeDescriptor decodedVD = new DecodedVolumeDescriptor
|
||||
{
|
||||
SystemIdentifier = Encoding.ASCII.GetString(pvd.system_id).TrimEnd().Trim('\0'),
|
||||
VolumeIdentifier = Encoding.ASCII.GetString(pvd.volume_id).TrimEnd().Trim('\0'),
|
||||
VolumeSetIdentifier = Encoding.ASCII.GetString(pvd.volume_set_id).TrimEnd().Trim('\0'),
|
||||
PublisherIdentifier = Encoding.ASCII.GetString(pvd.publisher_id).TrimEnd().Trim('\0'),
|
||||
DataPreparerIdentifier = Encoding.ASCII.GetString(pvd.preparer_id).TrimEnd().Trim('\0'),
|
||||
ApplicationIdentifier = Encoding.ASCII.GetString(pvd.application_data).TrimEnd().Trim('\0')
|
||||
};
|
||||
|
||||
if(pvd.creation_date[0] == '0' || pvd.creation_date[0] == 0x00) decodedVD.CreationTime = DateTime.MinValue;
|
||||
else decodedVD.CreationTime = DateHandlers.Iso9660ToDateTime(pvd.creation_date);
|
||||
|
||||
if(pvd.modification_date[0] == '0' || pvd.modification_date[0] == 0x00)
|
||||
decodedVD.HasModificationTime = false;
|
||||
else
|
||||
{
|
||||
decodedVD.HasModificationTime = true;
|
||||
decodedVD.ModificationTime = DateHandlers.Iso9660ToDateTime(pvd.modification_date);
|
||||
}
|
||||
|
||||
if(pvd.expiration_date[0] == '0' || pvd.expiration_date[0] == 0x00) decodedVD.HasExpirationTime = false;
|
||||
else
|
||||
{
|
||||
decodedVD.HasExpirationTime = true;
|
||||
decodedVD.ExpirationTime = DateHandlers.Iso9660ToDateTime(pvd.expiration_date);
|
||||
}
|
||||
|
||||
if(pvd.effective_date[0] == '0' || pvd.effective_date[0] == 0x00) decodedVD.HasEffectiveTime = false;
|
||||
else
|
||||
{
|
||||
decodedVD.HasEffectiveTime = true;
|
||||
decodedVD.EffectiveTime = DateHandlers.Iso9660ToDateTime(pvd.effective_date);
|
||||
}
|
||||
|
||||
decodedVD.Blocks = pvd.volume_space_size;
|
||||
decodedVD.BlockSize = pvd.logical_block_size;
|
||||
|
||||
return decodedVD;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct PrimaryVolumeDescriptor
|
||||
{
|
||||
@@ -165,48 +208,5 @@ namespace DiscImageChef.Filesystems.ISO9660
|
||||
public ushort parent_dirno;
|
||||
// Followed by name[name_len]
|
||||
}
|
||||
|
||||
static DecodedVolumeDescriptor DecodeVolumeDescriptor(PrimaryVolumeDescriptor pvd)
|
||||
{
|
||||
DecodedVolumeDescriptor decodedVD = new DecodedVolumeDescriptor
|
||||
{
|
||||
SystemIdentifier = Encoding.ASCII.GetString(pvd.system_id).TrimEnd().Trim('\0'),
|
||||
VolumeIdentifier = Encoding.ASCII.GetString(pvd.volume_id).TrimEnd().Trim('\0'),
|
||||
VolumeSetIdentifier = Encoding.ASCII.GetString(pvd.volume_set_id).TrimEnd().Trim('\0'),
|
||||
PublisherIdentifier = Encoding.ASCII.GetString(pvd.publisher_id).TrimEnd().Trim('\0'),
|
||||
DataPreparerIdentifier = Encoding.ASCII.GetString(pvd.preparer_id).TrimEnd().Trim('\0'),
|
||||
ApplicationIdentifier = Encoding.ASCII.GetString(pvd.application_data).TrimEnd().Trim('\0')
|
||||
};
|
||||
|
||||
if(pvd.creation_date[0] == '0' || pvd.creation_date[0] == 0x00)
|
||||
decodedVD.CreationTime = DateTime.MinValue;
|
||||
else decodedVD.CreationTime = DateHandlers.Iso9660ToDateTime(pvd.creation_date);
|
||||
|
||||
if(pvd.modification_date[0] == '0' || pvd.modification_date[0] == 0x00) decodedVD.HasModificationTime = false;
|
||||
else
|
||||
{
|
||||
decodedVD.HasModificationTime = true;
|
||||
decodedVD.ModificationTime = DateHandlers.Iso9660ToDateTime(pvd.modification_date);
|
||||
}
|
||||
|
||||
if(pvd.expiration_date[0] == '0' || pvd.expiration_date[0] == 0x00) decodedVD.HasExpirationTime = false;
|
||||
else
|
||||
{
|
||||
decodedVD.HasExpirationTime = true;
|
||||
decodedVD.ExpirationTime = DateHandlers.Iso9660ToDateTime(pvd.expiration_date);
|
||||
}
|
||||
|
||||
if(pvd.effective_date[0] == '0' || pvd.effective_date[0] == 0x00) decodedVD.HasEffectiveTime = false;
|
||||
else
|
||||
{
|
||||
decodedVD.HasEffectiveTime = true;
|
||||
decodedVD.EffectiveTime = DateHandlers.Iso9660ToDateTime(pvd.effective_date);
|
||||
}
|
||||
|
||||
decodedVD.Blocks = pvd.volume_space_size;
|
||||
decodedVD.BlockSize = pvd.logical_block_size;
|
||||
|
||||
return decodedVD;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -57,21 +57,24 @@ namespace DiscImageChef.Filesystems.ISO9660
|
||||
decodedVD.CreationTime = DateTime.MinValue;
|
||||
else decodedVD.CreationTime = DateHandlers.Iso9660ToDateTime(jolietvd.creation_date);
|
||||
|
||||
if(jolietvd.modification_date[0] < 0x31 || jolietvd.modification_date[0] > 0x39) decodedVD.HasModificationTime = false;
|
||||
if(jolietvd.modification_date[0] < 0x31 || jolietvd.modification_date[0] > 0x39)
|
||||
decodedVD.HasModificationTime = false;
|
||||
else
|
||||
{
|
||||
decodedVD.HasModificationTime = true;
|
||||
decodedVD.ModificationTime = DateHandlers.Iso9660ToDateTime(jolietvd.modification_date);
|
||||
}
|
||||
|
||||
if(jolietvd.expiration_date[0] < 0x31 || jolietvd.expiration_date[0] > 0x39) decodedVD.HasExpirationTime = false;
|
||||
if(jolietvd.expiration_date[0] < 0x31 || jolietvd.expiration_date[0] > 0x39)
|
||||
decodedVD.HasExpirationTime = false;
|
||||
else
|
||||
{
|
||||
decodedVD.HasExpirationTime = true;
|
||||
decodedVD.ExpirationTime = DateHandlers.Iso9660ToDateTime(jolietvd.expiration_date);
|
||||
}
|
||||
|
||||
if(jolietvd.effective_date[0] < 0x31 || jolietvd.effective_date[0] > 0x39) decodedVD.HasEffectiveTime = false;
|
||||
if(jolietvd.effective_date[0] < 0x31 || jolietvd.effective_date[0] > 0x39)
|
||||
decodedVD.HasEffectiveTime = false;
|
||||
else
|
||||
{
|
||||
decodedVD.HasEffectiveTime = true;
|
||||
|
||||
@@ -42,95 +42,6 @@ namespace DiscImageChef.Filesystems
|
||||
{
|
||||
public class JFS : Filesystem
|
||||
{
|
||||
[Flags]
|
||||
enum JFS_Flags : uint
|
||||
{
|
||||
Unicode = 0x00000001,
|
||||
RemountRO = 0x00000002,
|
||||
Continue = 0x00000004,
|
||||
Panic = 0x00000008,
|
||||
UserQuota = 0x00000010,
|
||||
GroupQuota = 0x00000020,
|
||||
NoJournal = 0x00000040,
|
||||
Discard = 0x00000080,
|
||||
GroupCommit = 0x00000100,
|
||||
LazyCommit = 0x00000200,
|
||||
Temporary = 0x00000400,
|
||||
InlineLog = 0x00000800,
|
||||
InlineMoving = 0x00001000,
|
||||
BadSAIT = 0x00010000,
|
||||
Sparse = 0x00020000,
|
||||
DASDEnabled = 0x00040000,
|
||||
DASDPrime = 0x00080000,
|
||||
SwapBytes = 0x00100000,
|
||||
DirIndex = 0x00200000,
|
||||
Linux = 0x10000000,
|
||||
DFS = 0x20000000,
|
||||
OS2 = 0x40000000,
|
||||
AIX = 0x80000000
|
||||
}
|
||||
|
||||
[Flags]
|
||||
enum JFS_State : uint
|
||||
{
|
||||
Clean = 0,
|
||||
Mounted = 1,
|
||||
Dirty = 2,
|
||||
Logredo = 4,
|
||||
Extendfs = 8
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct JFS_Extent
|
||||
{
|
||||
/// <summary>
|
||||
/// Leftmost 24 bits are extent length, rest 8 bits are most significant for <see cref="addr2"/>
|
||||
/// </summary>
|
||||
public uint len_addr;
|
||||
public uint addr2;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct JFS_TimeStruct
|
||||
{
|
||||
public uint tv_sec;
|
||||
public uint tv_nsec;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct JFS_SuperBlock
|
||||
{
|
||||
public uint s_magic;
|
||||
public uint s_version;
|
||||
public ulong s_size;
|
||||
public uint s_bsize;
|
||||
public ushort s_l2bsize;
|
||||
public ushort s_l2bfactor;
|
||||
public uint s_pbsize;
|
||||
public ushort s_l1pbsize;
|
||||
public ushort pad;
|
||||
public uint s_agsize;
|
||||
public JFS_Flags s_flags;
|
||||
public JFS_State s_state;
|
||||
public uint s_compress;
|
||||
public JFS_Extent s_ait2;
|
||||
public JFS_Extent s_aim2;
|
||||
public uint s_logdev;
|
||||
public uint s_logserial;
|
||||
public JFS_Extent s_logpxd;
|
||||
public JFS_Extent s_fsckpxd;
|
||||
public JFS_TimeStruct s_time;
|
||||
public uint s_fsckloglen;
|
||||
public sbyte s_fscklog;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 11)] public byte[] s_fpack;
|
||||
public ulong s_xsize;
|
||||
public JFS_Extent s_xfsckpxd;
|
||||
public JFS_Extent s_xlogpxd;
|
||||
public Guid s_uuid;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] public byte[] s_label;
|
||||
public Guid s_loguuid;
|
||||
}
|
||||
|
||||
const uint JFS_BOOT_BLOCKS_SIZE = 0x8000;
|
||||
const uint JFS_MAGIC = 0x3153464A;
|
||||
|
||||
@@ -172,8 +83,7 @@ namespace DiscImageChef.Filesystems
|
||||
return jfsSb.s_magic == JFS_MAGIC;
|
||||
}
|
||||
|
||||
public override void GetInformation(ImagePlugin imagePlugin, Partition partition,
|
||||
out string information)
|
||||
public override void GetInformation(ImagePlugin imagePlugin, Partition partition, out string information)
|
||||
{
|
||||
information = "";
|
||||
StringBuilder sb = new StringBuilder();
|
||||
@@ -301,5 +211,94 @@ namespace DiscImageChef.Filesystems
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
[Flags]
|
||||
enum JFS_Flags : uint
|
||||
{
|
||||
Unicode = 0x00000001,
|
||||
RemountRO = 0x00000002,
|
||||
Continue = 0x00000004,
|
||||
Panic = 0x00000008,
|
||||
UserQuota = 0x00000010,
|
||||
GroupQuota = 0x00000020,
|
||||
NoJournal = 0x00000040,
|
||||
Discard = 0x00000080,
|
||||
GroupCommit = 0x00000100,
|
||||
LazyCommit = 0x00000200,
|
||||
Temporary = 0x00000400,
|
||||
InlineLog = 0x00000800,
|
||||
InlineMoving = 0x00001000,
|
||||
BadSAIT = 0x00010000,
|
||||
Sparse = 0x00020000,
|
||||
DASDEnabled = 0x00040000,
|
||||
DASDPrime = 0x00080000,
|
||||
SwapBytes = 0x00100000,
|
||||
DirIndex = 0x00200000,
|
||||
Linux = 0x10000000,
|
||||
DFS = 0x20000000,
|
||||
OS2 = 0x40000000,
|
||||
AIX = 0x80000000
|
||||
}
|
||||
|
||||
[Flags]
|
||||
enum JFS_State : uint
|
||||
{
|
||||
Clean = 0,
|
||||
Mounted = 1,
|
||||
Dirty = 2,
|
||||
Logredo = 4,
|
||||
Extendfs = 8
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct JFS_Extent
|
||||
{
|
||||
/// <summary>
|
||||
/// Leftmost 24 bits are extent length, rest 8 bits are most significant for <see cref="addr2" />
|
||||
/// </summary>
|
||||
public uint len_addr;
|
||||
public uint addr2;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct JFS_TimeStruct
|
||||
{
|
||||
public uint tv_sec;
|
||||
public uint tv_nsec;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct JFS_SuperBlock
|
||||
{
|
||||
public uint s_magic;
|
||||
public uint s_version;
|
||||
public ulong s_size;
|
||||
public uint s_bsize;
|
||||
public ushort s_l2bsize;
|
||||
public ushort s_l2bfactor;
|
||||
public uint s_pbsize;
|
||||
public ushort s_l1pbsize;
|
||||
public ushort pad;
|
||||
public uint s_agsize;
|
||||
public JFS_Flags s_flags;
|
||||
public JFS_State s_state;
|
||||
public uint s_compress;
|
||||
public JFS_Extent s_ait2;
|
||||
public JFS_Extent s_aim2;
|
||||
public uint s_logdev;
|
||||
public uint s_logserial;
|
||||
public JFS_Extent s_logpxd;
|
||||
public JFS_Extent s_fsckpxd;
|
||||
public JFS_TimeStruct s_time;
|
||||
public uint s_fsckloglen;
|
||||
public sbyte s_fscklog;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 11)] public byte[] s_fpack;
|
||||
public ulong s_xsize;
|
||||
public JFS_Extent s_xfsckpxd;
|
||||
public JFS_Extent s_xlogpxd;
|
||||
public Guid s_uuid;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] public byte[] s_label;
|
||||
public Guid s_loguuid;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -44,23 +44,6 @@ namespace DiscImageChef.Filesystems
|
||||
// Information from http://www.hp9845.net/9845/projects/hpdir/#lif_filesystem
|
||||
public class LIF : Filesystem
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct LIF_SystemBlock
|
||||
{
|
||||
public ushort magic;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)] public byte[] volumeLabel;
|
||||
public uint directoryStart;
|
||||
public ushort lifId;
|
||||
public ushort unused;
|
||||
public uint directorySize;
|
||||
public ushort lifVersion;
|
||||
public ushort unused2;
|
||||
public uint tracks;
|
||||
public uint heads;
|
||||
public uint sectors;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)] public byte[] creationDate;
|
||||
}
|
||||
|
||||
const uint LIF_MAGIC = 0x8000;
|
||||
|
||||
public LIF()
|
||||
@@ -95,8 +78,7 @@ namespace DiscImageChef.Filesystems
|
||||
return lifSb.magic == LIF_MAGIC;
|
||||
}
|
||||
|
||||
public override void GetInformation(ImagePlugin imagePlugin, Partition partition,
|
||||
out string information)
|
||||
public override void GetInformation(ImagePlugin imagePlugin, Partition partition, out string information)
|
||||
{
|
||||
information = "";
|
||||
|
||||
@@ -194,5 +176,22 @@ namespace DiscImageChef.Filesystems
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct LIF_SystemBlock
|
||||
{
|
||||
public ushort magic;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)] public byte[] volumeLabel;
|
||||
public uint directoryStart;
|
||||
public ushort lifId;
|
||||
public ushort unused;
|
||||
public uint directorySize;
|
||||
public ushort lifVersion;
|
||||
public ushort unused2;
|
||||
public uint tracks;
|
||||
public uint heads;
|
||||
public uint sectors;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)] public byte[] creationDate;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -35,48 +35,48 @@ namespace DiscImageChef.Filesystems.LisaFS
|
||||
public partial class LisaFS
|
||||
{
|
||||
/// <summary>
|
||||
/// Lisa FS v1, from Lisa OS 1.0 (Workshop or Office)
|
||||
/// Never seen on Sony floppies.
|
||||
/// Lisa FS v1, from Lisa OS 1.0 (Workshop or Office)
|
||||
/// Never seen on Sony floppies.
|
||||
/// </summary>
|
||||
const byte LISA_V1 = 0x0E;
|
||||
/// <summary>
|
||||
/// Lisa FS v2, from Lisa OS 2.0 (Workshop or Office)
|
||||
/// Contrary to what most information online says the only difference with V1
|
||||
/// is the Extents File size. Catalog format is the same
|
||||
/// Lisa FS v2, from Lisa OS 2.0 (Workshop or Office)
|
||||
/// Contrary to what most information online says the only difference with V1
|
||||
/// is the Extents File size. Catalog format is the same
|
||||
/// </summary>
|
||||
const byte LISA_V2 = 0x0F;
|
||||
/// <summary>
|
||||
/// Lisa FS v3, from Lisa OS 3.0 (Workshop or Office)
|
||||
/// Adds support for user catalogs (aka subdirectories),
|
||||
/// and changes the catalog format from extents to double-linked list.
|
||||
/// Uses '-' as path separator (so people that created Lisa/FILE.TEXT just
|
||||
/// created a file named like that :p)
|
||||
/// Lisa FS v3, from Lisa OS 3.0 (Workshop or Office)
|
||||
/// Adds support for user catalogs (aka subdirectories),
|
||||
/// and changes the catalog format from extents to double-linked list.
|
||||
/// Uses '-' as path separator (so people that created Lisa/FILE.TEXT just
|
||||
/// created a file named like that :p)
|
||||
/// </summary>
|
||||
const byte LISA_V3 = 0x11;
|
||||
/// <summary>Maximum string size in LisaFS</summary>
|
||||
const uint E_NAME = 32;
|
||||
/// <summary>
|
||||
/// Unused file ID
|
||||
/// Unused file ID
|
||||
/// </summary>
|
||||
const ushort FILEID_FREE = 0x0000;
|
||||
/// <summary>
|
||||
/// Used by the boot blocks
|
||||
/// Used by the boot blocks
|
||||
/// </summary>
|
||||
const ushort FILEID_BOOT = 0xAAAA;
|
||||
/// <summary>
|
||||
/// Used by the operating system loader blocks
|
||||
/// Used by the operating system loader blocks
|
||||
/// </summary>
|
||||
const ushort FILEID_LOADER = 0xBBBB;
|
||||
/// <summary>
|
||||
/// Used by the MDDF
|
||||
/// Used by the MDDF
|
||||
/// </summary>
|
||||
const ushort FILEID_MDDF = 0x0001;
|
||||
/// <summary>
|
||||
/// Used by the volume bitmap, sits between MDDF and S-Records file.
|
||||
/// Used by the volume bitmap, sits between MDDF and S-Records file.
|
||||
/// </summary>
|
||||
const ushort FILEID_BITMAP = 0x0002;
|
||||
/// <summary>
|
||||
/// S-Records file
|
||||
/// S-Records file
|
||||
/// </summary>
|
||||
const ushort FILEID_SRECORD = 0x0003;
|
||||
/// <summary>The root catalog</summary>
|
||||
@@ -84,7 +84,7 @@ namespace DiscImageChef.Filesystems.LisaFS
|
||||
const short FILEID_BOOT_SIGNED = -21846;
|
||||
const short FILEID_LOADER_SIGNED = -17477;
|
||||
/// <summary>
|
||||
/// A file that has been erased
|
||||
/// A file that has been erased
|
||||
/// </summary>
|
||||
const ushort FILEID_ERASED = 0x7FFF;
|
||||
const ushort FILEID_MAX = FILEID_ERASED;
|
||||
@@ -95,67 +95,67 @@ namespace DiscImageChef.Filesystems.LisaFS
|
||||
enum FileType : byte
|
||||
{
|
||||
/// <summary>
|
||||
/// Undefined file type
|
||||
/// Undefined file type
|
||||
/// </summary>
|
||||
Undefined = 0,
|
||||
/// <summary>
|
||||
/// MDDF
|
||||
/// MDDF
|
||||
/// </summary>
|
||||
MDDFile = 1,
|
||||
/// <summary>
|
||||
/// Root catalog
|
||||
/// Root catalog
|
||||
/// </summary>
|
||||
RootCat = 2,
|
||||
/// <summary>
|
||||
/// Bitmap
|
||||
/// Bitmap
|
||||
/// </summary>
|
||||
FreeList = 3,
|
||||
/// <summary>
|
||||
/// Unknown, maybe refers to the S-Records File?
|
||||
/// Unknown, maybe refers to the S-Records File?
|
||||
/// </summary>
|
||||
BadBlocks = 4,
|
||||
/// <summary>
|
||||
/// System data
|
||||
/// System data
|
||||
/// </summary>
|
||||
SysData = 5,
|
||||
/// <summary>
|
||||
/// Printer spool
|
||||
/// Printer spool
|
||||
/// </summary>
|
||||
Spool = 6,
|
||||
/// <summary>
|
||||
/// Executable. Yet application files don't use it
|
||||
/// Executable. Yet application files don't use it
|
||||
/// </summary>
|
||||
Exec = 7,
|
||||
/// <summary>
|
||||
/// User catalog
|
||||
/// User catalog
|
||||
/// </summary>
|
||||
UserCat = 8,
|
||||
/// <summary>
|
||||
/// Pipe. Not seen on disk.
|
||||
/// Pipe. Not seen on disk.
|
||||
/// </summary>
|
||||
Pipe = 9,
|
||||
/// <summary>
|
||||
/// Boot file?
|
||||
/// Boot file?
|
||||
/// </summary>
|
||||
BootFile = 10,
|
||||
/// <summary>
|
||||
/// Swap for data
|
||||
/// Swap for data
|
||||
/// </summary>
|
||||
SwapData = 11,
|
||||
/// <summary>
|
||||
/// Swap for code
|
||||
/// Swap for code
|
||||
/// </summary>
|
||||
SwapCode = 12,
|
||||
/// <summary>
|
||||
/// Unknown
|
||||
/// Unknown
|
||||
/// </summary>
|
||||
RamAP = 13,
|
||||
/// <summary>
|
||||
/// Any file
|
||||
/// Any file
|
||||
/// </summary>
|
||||
UserFile = 14,
|
||||
/// <summary>
|
||||
/// Erased?
|
||||
/// Erased?
|
||||
/// </summary>
|
||||
KilledObject = 15
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ namespace DiscImageChef.Filesystems.LisaFS
|
||||
public partial class LisaFS
|
||||
{
|
||||
/// <summary>
|
||||
/// Solves a symbolic link.
|
||||
/// Solves a symbolic link.
|
||||
/// </summary>
|
||||
/// <param name="path">Link path.</param>
|
||||
/// <param name="dest">Link destination.</param>
|
||||
@@ -52,7 +52,7 @@ namespace DiscImageChef.Filesystems.LisaFS
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Lists contents from a directory.
|
||||
/// Lists contents from a directory.
|
||||
/// </summary>
|
||||
/// <param name="path">Directory path.</param>
|
||||
/// <param name="contents">Directory contents.</param>
|
||||
@@ -90,13 +90,15 @@ namespace DiscImageChef.Filesystems.LisaFS
|
||||
{
|
||||
// Do same trick as Mac OS X, replace filesystem '/' with '-',
|
||||
// as '-' is the path separator in Lisa OS
|
||||
contents = (from entry in catalogCache where entry.parentID == dirId select StringHandlers.CToString(entry.filename, CurrentEncoding).Replace('/', '-')).ToList();
|
||||
contents = (from entry in catalogCache
|
||||
where entry.parentID == dirId
|
||||
select StringHandlers.CToString(entry.filename, CurrentEncoding).Replace('/', '-')).ToList();
|
||||
|
||||
return Errno.NoError;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads, interprets and caches the Catalog File
|
||||
/// Reads, interprets and caches the Catalog File
|
||||
/// </summary>
|
||||
Errno ReadCatalog()
|
||||
{
|
||||
@@ -215,7 +217,7 @@ namespace DiscImageChef.Filesystems.LisaFS
|
||||
|
||||
// Traverse all entries
|
||||
while(offset + 64 <= buf.Length)
|
||||
// Catalog block header
|
||||
// Catalog block header
|
||||
if(buf[offset + 0x24] == 0x08) offset += 78;
|
||||
// Maybe just garbage? Found in more than 1 disk
|
||||
else if(buf[offset + 0x24] == 0x7C) offset += 50;
|
||||
|
||||
@@ -46,7 +46,7 @@ namespace DiscImageChef.Filesystems.LisaFS
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Searches the disk for an extents file (or gets it from cache)
|
||||
/// Searches the disk for an extents file (or gets it from cache)
|
||||
/// </summary>
|
||||
/// <returns>Error.</returns>
|
||||
/// <param name="fileId">File identifier.</param>
|
||||
@@ -171,13 +171,11 @@ namespace DiscImageChef.Filesystems.LisaFS
|
||||
file.extents = new Extent[extentsCount];
|
||||
|
||||
for(int j = 0; j < extentsCount; j++)
|
||||
{
|
||||
file.extents[j] = new Extent
|
||||
{
|
||||
{
|
||||
start = BigEndianBitConverter.ToInt32(sector, extentsOffset + j * 6),
|
||||
length = BigEndianBitConverter.ToInt16(sector, extentsOffset + j * 6 + 4)
|
||||
};
|
||||
}
|
||||
|
||||
extentCache.Add(fileId, file);
|
||||
|
||||
@@ -185,77 +183,64 @@ namespace DiscImageChef.Filesystems.LisaFS
|
||||
|
||||
if(printedExtents.Contains(fileId)) return Errno.NoError;
|
||||
|
||||
DicConsole.DebugWriteLine("LisaFS plugin", "ExtentFile[{0}].filenameLen = {1}", fileId,
|
||||
file.filenameLen);
|
||||
DicConsole.DebugWriteLine("LisaFS plugin", "ExtentFile[{0}].filenameLen = {1}", fileId, file.filenameLen);
|
||||
DicConsole.DebugWriteLine("LisaFS plugin", "ExtentFile[{0}].filename = {1}", fileId,
|
||||
StringHandlers.CToString(file.filename, CurrentEncoding));
|
||||
DicConsole.DebugWriteLine("LisaFS plugin", "ExtentFile[{0}].unknown1 = 0x{1:X4}", fileId,
|
||||
file.unknown1);
|
||||
DicConsole.DebugWriteLine("LisaFS plugin", "ExtentFile[{0}].file_uid = 0x{1:X16}", fileId,
|
||||
file.file_uid);
|
||||
DicConsole.DebugWriteLine("LisaFS plugin", "ExtentFile[{0}].unknown2 = 0x{1:X2}", fileId,
|
||||
file.unknown2);
|
||||
DicConsole.DebugWriteLine("LisaFS plugin", "ExtentFile[{0}].unknown1 = 0x{1:X4}", fileId, file.unknown1);
|
||||
DicConsole.DebugWriteLine("LisaFS plugin", "ExtentFile[{0}].file_uid = 0x{1:X16}", fileId, file.file_uid);
|
||||
DicConsole.DebugWriteLine("LisaFS plugin", "ExtentFile[{0}].unknown2 = 0x{1:X2}", fileId, file.unknown2);
|
||||
DicConsole.DebugWriteLine("LisaFS plugin", "ExtentFile[{0}].etype = 0x{1:X2}", fileId, file.etype);
|
||||
DicConsole.DebugWriteLine("LisaFS plugin", "ExtentFile[{0}].ftype = {1}", fileId, file.ftype);
|
||||
DicConsole.DebugWriteLine("LisaFS plugin", "ExtentFile[{0}].unknown3 = 0x{1:X2}", fileId,
|
||||
file.unknown3);
|
||||
DicConsole.DebugWriteLine("LisaFS plugin", "ExtentFile[{0}].unknown3 = 0x{1:X2}", fileId, file.unknown3);
|
||||
DicConsole.DebugWriteLine("LisaFS plugin", "ExtentFile[{0}].dtc = {1}", fileId, file.dtc);
|
||||
DicConsole.DebugWriteLine("LisaFS plugin", "ExtentFile[{0}].dta = {1}", fileId, file.dta);
|
||||
DicConsole.DebugWriteLine("LisaFS plugin", "ExtentFile[{0}].dtm = {1}", fileId, file.dtm);
|
||||
DicConsole.DebugWriteLine("LisaFS plugin", "ExtentFile[{0}].dtb = {1}", fileId, file.dtb);
|
||||
DicConsole.DebugWriteLine("LisaFS plugin", "ExtentFile[{0}].dts = {1}", fileId, file.dts);
|
||||
DicConsole.DebugWriteLine("LisaFS plugin", "ExtentFile[{0}].serial = {1}", fileId, file.serial);
|
||||
DicConsole.DebugWriteLine("LisaFS plugin", "ExtentFile[{0}].unknown4 = 0x{1:X2}", fileId,
|
||||
file.unknown4);
|
||||
DicConsole.DebugWriteLine("LisaFS plugin", "ExtentFile[{0}].unknown4 = 0x{1:X2}", fileId, file.unknown4);
|
||||
DicConsole.DebugWriteLine("LisaFS plugin", "ExtentFile[{0}].locked = {1}", fileId, file.locked > 0);
|
||||
DicConsole.DebugWriteLine("LisaFS plugin", "ExtentFile[{0}].protect = {1}", fileId,
|
||||
file.protect > 0);
|
||||
DicConsole.DebugWriteLine("LisaFS plugin", "ExtentFile[{0}].protect = {1}", fileId, file.protect > 0);
|
||||
DicConsole.DebugWriteLine("LisaFS plugin", "ExtentFile[{0}].master = {1}", fileId, file.master > 0);
|
||||
DicConsole.DebugWriteLine("LisaFS plugin", "ExtentFile[{0}].scavenged = {1}", fileId,
|
||||
file.scavenged > 0);
|
||||
DicConsole.DebugWriteLine("LisaFS plugin", "ExtentFile[{0}].scavenged = {1}", fileId, file.scavenged > 0);
|
||||
DicConsole.DebugWriteLine("LisaFS plugin", "ExtentFile[{0}].closed = {1}", fileId, file.closed > 0);
|
||||
DicConsole.DebugWriteLine("LisaFS plugin", "ExtentFile[{0}].open = {1}", fileId, file.open > 0);
|
||||
DicConsole.DebugWriteLine("LisaFS plugin",
|
||||
"ExtentFile[{0}].unknown5 = 0x{1:X2}{2:X2}{3:X2}{4:X2}{5:X2}{6:X2}{7:X2}{8:X2}{9:X2}" +
|
||||
"{10:X2}{11:X2}", fileId, file.unknown5[0], file.unknown5[1],
|
||||
file.unknown5[2], file.unknown5[3], file.unknown5[4], file.unknown5[5],
|
||||
file.unknown5[6], file.unknown5[7], file.unknown5[8], file.unknown5[9],
|
||||
file.unknown5[10]);
|
||||
"{10:X2}{11:X2}", fileId, file.unknown5[0], file.unknown5[1], file.unknown5[2],
|
||||
file.unknown5[3], file.unknown5[4], file.unknown5[5], file.unknown5[6],
|
||||
file.unknown5[7], file.unknown5[8], file.unknown5[9], file.unknown5[10]);
|
||||
DicConsole.DebugWriteLine("LisaFS plugin", "ExtentFile[{0}].release = {1}", fileId, file.release);
|
||||
DicConsole.DebugWriteLine("LisaFS plugin", "ExtentFile[{0}].build = {1}", fileId, file.build);
|
||||
DicConsole.DebugWriteLine("LisaFS plugin", "ExtentFile[{0}].compatibility = {1}", fileId,
|
||||
file.compatibility);
|
||||
DicConsole.DebugWriteLine("LisaFS plugin", "ExtentFile[{0}].revision = {1}", fileId, file.revision);
|
||||
DicConsole.DebugWriteLine("LisaFS plugin", "ExtentFile[{0}].unknown6 = 0x{1:X4}", fileId,
|
||||
file.unknown6);
|
||||
DicConsole.DebugWriteLine("LisaFS plugin", "ExtentFile[{0}].unknown6 = 0x{1:X4}", fileId, file.unknown6);
|
||||
DicConsole.DebugWriteLine("LisaFS plugin", "ExtentFile[{0}].password_valid = {1}", fileId,
|
||||
file.password_valid > 0);
|
||||
DicConsole.DebugWriteLine("LisaFS plugin", "ExtentFile[{0}].password = {1}", fileId,
|
||||
CurrentEncoding.GetString(file.password));
|
||||
DicConsole.DebugWriteLine("LisaFS plugin", "ExtentFile[{0}].unknown7 = 0x{1:X2}{2:X2}{3:X2}",
|
||||
fileId, file.unknown7[0], file.unknown7[1], file.unknown7[2]);
|
||||
DicConsole.DebugWriteLine("LisaFS plugin", "ExtentFile[{0}].unknown7 = 0x{1:X2}{2:X2}{3:X2}", fileId,
|
||||
file.unknown7[0], file.unknown7[1], file.unknown7[2]);
|
||||
DicConsole.DebugWriteLine("LisaFS plugin", "ExtentFile[{0}].overhead = {1}", fileId, file.overhead);
|
||||
DicConsole.DebugWriteLine("LisaFS plugin",
|
||||
"ExtentFile[{0}].unknown8 = 0x{1:X2}{2:X2}{3:X2}{4:X2}{5:X2}{6:X2}{7:X2}{8:X2}{9:X2}" +
|
||||
"{10:X2}{11:X2}{12:X2}{13:X2}{14:X2}{15:X2}{16:X2}", fileId,
|
||||
file.unknown8[0], file.unknown8[1], file.unknown8[2], file.unknown8[3],
|
||||
file.unknown8[4], file.unknown8[5], file.unknown8[6], file.unknown8[7],
|
||||
file.unknown8[8], file.unknown8[9], file.unknown8[10], file.unknown8[11],
|
||||
file.unknown8[12], file.unknown8[13], file.unknown8[14],
|
||||
file.unknown8[15]);
|
||||
"{10:X2}{11:X2}{12:X2}{13:X2}{14:X2}{15:X2}{16:X2}", fileId, file.unknown8[0],
|
||||
file.unknown8[1], file.unknown8[2], file.unknown8[3], file.unknown8[4],
|
||||
file.unknown8[5], file.unknown8[6], file.unknown8[7], file.unknown8[8],
|
||||
file.unknown8[9], file.unknown8[10], file.unknown8[11], file.unknown8[12],
|
||||
file.unknown8[13], file.unknown8[14], file.unknown8[15]);
|
||||
DicConsole.DebugWriteLine("LisaFS plugin", "ExtentFile[{0}].length = {1}", fileId, file.length);
|
||||
DicConsole.DebugWriteLine("LisaFS plugin", "ExtentFile[{0}].unknown9 = 0x{1:X8}", fileId,
|
||||
file.unknown9);
|
||||
DicConsole.DebugWriteLine("LisaFS plugin", "ExtentFile[{0}].unknown9 = 0x{1:X8}", fileId, file.unknown9);
|
||||
for(int ext = 0; ext < file.extents.Length; ext++)
|
||||
{
|
||||
DicConsole.DebugWriteLine("LisaFS plugin", "ExtentFile[{0}].extents[{1}].start = {2}", fileId,
|
||||
ext, file.extents[ext].start);
|
||||
DicConsole.DebugWriteLine("LisaFS plugin", "ExtentFile[{0}].extents[{1}].length = {2}", fileId,
|
||||
ext, file.extents[ext].length);
|
||||
DicConsole.DebugWriteLine("LisaFS plugin", "ExtentFile[{0}].extents[{1}].start = {2}", fileId, ext,
|
||||
file.extents[ext].start);
|
||||
DicConsole.DebugWriteLine("LisaFS plugin", "ExtentFile[{0}].extents[{1}].length = {2}", fileId, ext,
|
||||
file.extents[ext].length);
|
||||
}
|
||||
|
||||
DicConsole.DebugWriteLine("LisaFS plugin", "ExtentFile[{0}].unknown10 = 0x{1:X4}", fileId,
|
||||
file.unknown10);
|
||||
DicConsole.DebugWriteLine("LisaFS plugin", "ExtentFile[{0}].unknown10 = 0x{1:X4}", fileId, file.unknown10);
|
||||
|
||||
printedExtents.Add(fileId);
|
||||
|
||||
@@ -263,7 +248,7 @@ namespace DiscImageChef.Filesystems.LisaFS
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads all the S-Records and caches it
|
||||
/// Reads all the S-Records and caches it
|
||||
/// </summary>
|
||||
Errno ReadSRecords()
|
||||
{
|
||||
@@ -276,15 +261,13 @@ namespace DiscImageChef.Filesystems.LisaFS
|
||||
srecords = new SRecord[sectors.Length / 14];
|
||||
|
||||
for(int s = 0; s < srecords.Length; s++)
|
||||
{
|
||||
srecords[s] = new SRecord
|
||||
{
|
||||
{
|
||||
extent_ptr = BigEndianBitConverter.ToUInt32(sectors, 0x00 + 14 * s),
|
||||
unknown = BigEndianBitConverter.ToUInt32(sectors, 0x04 + 14 * s),
|
||||
filesize = BigEndianBitConverter.ToUInt32(sectors, 0x08 + 14 * s),
|
||||
flags = BigEndianBitConverter.ToUInt16(sectors, 0x0C + 14 * s)
|
||||
};
|
||||
}
|
||||
|
||||
return Errno.NoError;
|
||||
}
|
||||
|
||||
@@ -161,7 +161,8 @@ namespace DiscImageChef.Filesystems.LisaFS
|
||||
buf = null;
|
||||
if(!mounted || !debug) return Errno.AccessDenied;
|
||||
|
||||
if(fileId > 4 || fileId <= 0) if(fileId != FILEID_BOOT_SIGNED && fileId != FILEID_LOADER_SIGNED) return Errno.InvalidArgument;
|
||||
if(fileId > 4 || fileId <= 0)
|
||||
if(fileId != FILEID_BOOT_SIGNED && fileId != FILEID_LOADER_SIGNED) return Errno.InvalidArgument;
|
||||
|
||||
if(systemFileCache.TryGetValue(fileId, out buf) && !tags) return Errno.NoError;
|
||||
|
||||
@@ -346,7 +347,8 @@ namespace DiscImageChef.Filesystems.LisaFS
|
||||
|
||||
if(!tags)
|
||||
{
|
||||
if(fileSizeCache.TryGetValue(fileId, out int realSize)) if(realSize > temp.Length) DicConsole.ErrorWriteLine("File {0} gets truncated.", fileId);
|
||||
if(fileSizeCache.TryGetValue(fileId, out int realSize))
|
||||
if(realSize > temp.Length) DicConsole.ErrorWriteLine("File {0} gets truncated.", fileId);
|
||||
buf = temp;
|
||||
|
||||
fileCache.Add(fileId, buf);
|
||||
|
||||
@@ -61,7 +61,8 @@ namespace DiscImageChef.Filesystems.LisaFS
|
||||
// LisaOS searches sectors until tag tells MDDF resides there, so we'll search 100 sectors
|
||||
for(int i = 0; i < 100; i++)
|
||||
{
|
||||
DecodeTag(imagePlugin.ReadSectorTag((ulong)i, SectorTagType.AppleSectorTag), out LisaTag.PriamTag searchTag);
|
||||
DecodeTag(imagePlugin.ReadSectorTag((ulong)i, SectorTagType.AppleSectorTag),
|
||||
out LisaTag.PriamTag searchTag);
|
||||
|
||||
DicConsole.DebugWriteLine("LisaFS plugin", "Sector {0}, file ID 0x{1:X4}", i, searchTag.FileId);
|
||||
|
||||
@@ -137,7 +138,8 @@ namespace DiscImageChef.Filesystems.LisaFS
|
||||
// LisaOS searches sectors until tag tells MDDF resides there, so we'll search 100 sectors
|
||||
for(int i = 0; i < 100; i++)
|
||||
{
|
||||
DecodeTag(imagePlugin.ReadSectorTag((ulong)i, SectorTagType.AppleSectorTag), out LisaTag.PriamTag searchTag);
|
||||
DecodeTag(imagePlugin.ReadSectorTag((ulong)i, SectorTagType.AppleSectorTag),
|
||||
out LisaTag.PriamTag searchTag);
|
||||
|
||||
DicConsole.DebugWriteLine("LisaFS plugin", "Sector {0}, file ID 0x{1:X4}", i, searchTag.FileId);
|
||||
|
||||
@@ -307,11 +309,10 @@ namespace DiscImageChef.Filesystems.LisaFS
|
||||
|
||||
sb.AppendFormat("Master copy ID: 0x{0:X8}", infoMddf.master_copy_id).AppendLine();
|
||||
|
||||
sb.AppendFormat("Volume is number {0} of {1}", infoMddf.volnum, infoMddf.vol_sequence)
|
||||
.AppendLine();
|
||||
sb.AppendFormat("Volume is number {0} of {1}", infoMddf.volnum, infoMddf.vol_sequence).AppendLine();
|
||||
|
||||
sb.AppendFormat("Serial number of Lisa computer that created this volume: {0}",
|
||||
infoMddf.machine_id).AppendLine();
|
||||
sb.AppendFormat("Serial number of Lisa computer that created this volume: {0}", infoMddf.machine_id)
|
||||
.AppendLine();
|
||||
sb.AppendFormat("Serial number of Lisa computer that can use this volume's software {0}",
|
||||
infoMddf.serialization).AppendLine();
|
||||
|
||||
@@ -341,8 +342,7 @@ namespace DiscImageChef.Filesystems.LisaFS
|
||||
infoMddf.srec_ptr + infoMddf.mddf_block + beforeMddf, infoMddf.srec_len)
|
||||
.AppendLine();
|
||||
|
||||
if(infoMddf.vol_left_mounted == 0) sb.AppendLine("Volume is clean");
|
||||
else sb.AppendLine("Volume is dirty");
|
||||
sb.AppendLine(infoMddf.vol_left_mounted == 0 ? "Volume is clean" : "Volume is dirty");
|
||||
|
||||
information = sb.ToString();
|
||||
|
||||
|
||||
@@ -43,31 +43,14 @@ namespace DiscImageChef.Filesystems.LisaFS
|
||||
// Variable names from Lisa API
|
||||
public partial class LisaFS : Filesystem
|
||||
{
|
||||
bool mounted;
|
||||
bool debug;
|
||||
readonly ImagePlugin device;
|
||||
bool debug;
|
||||
int devTagSize;
|
||||
|
||||
MDDF mddf;
|
||||
ulong volumePrefix;
|
||||
int devTagSize;
|
||||
bool mounted;
|
||||
SRecord[] srecords;
|
||||
|
||||
#region Caches
|
||||
/// <summary>Caches Extents Files</summary>
|
||||
Dictionary<short, ExtentFile> extentCache;
|
||||
/// <summary>Caches system files</summary>
|
||||
Dictionary<short, byte[]> systemFileCache;
|
||||
/// <summary>Caches user files files</summary>
|
||||
Dictionary<short, byte[]> fileCache;
|
||||
/// <summary>Caches catalogs</summary>
|
||||
List<CatalogEntry> catalogCache;
|
||||
/// <summary>Caches file size</summary>
|
||||
Dictionary<short, int> fileSizeCache;
|
||||
/// <summary>Lists Extents Files already printed in debug mode to not repeat them</summary>
|
||||
List<short> printedExtents;
|
||||
/// <summary>Caches the creation times for subdirectories as to not have to traverse the Catalog File on each stat</summary>
|
||||
Dictionary<short, DateTime> directoryDtcCache;
|
||||
#endregion Caches
|
||||
ulong volumePrefix;
|
||||
|
||||
public LisaFS()
|
||||
{
|
||||
@@ -90,5 +73,22 @@ namespace DiscImageChef.Filesystems.LisaFS
|
||||
PluginUuid = new Guid("7E6034D1-D823-4248-A54D-239742B28391");
|
||||
CurrentEncoding = new LisaRoman();
|
||||
}
|
||||
|
||||
#region Caches
|
||||
/// <summary>Caches Extents Files</summary>
|
||||
Dictionary<short, ExtentFile> extentCache;
|
||||
/// <summary>Caches system files</summary>
|
||||
Dictionary<short, byte[]> systemFileCache;
|
||||
/// <summary>Caches user files files</summary>
|
||||
Dictionary<short, byte[]> fileCache;
|
||||
/// <summary>Caches catalogs</summary>
|
||||
List<CatalogEntry> catalogCache;
|
||||
/// <summary>Caches file size</summary>
|
||||
Dictionary<short, int> fileSizeCache;
|
||||
/// <summary>Lists Extents Files already printed in debug mode to not repeat them</summary>
|
||||
List<short> printedExtents;
|
||||
/// <summary>Caches the creation times for subdirectories as to not have to traverse the Catalog File on each stat</summary>
|
||||
Dictionary<short, DateTime> directoryDtcCache;
|
||||
#endregion Caches
|
||||
}
|
||||
}
|
||||
@@ -37,11 +37,11 @@ namespace DiscImageChef.Filesystems.LisaFS
|
||||
public partial class LisaFS
|
||||
{
|
||||
/// <summary>
|
||||
/// The MDDF is the most import block on a Lisa FS volume.
|
||||
/// It describes the volume and its contents.
|
||||
/// On initialization the memory where it resides is not emptied
|
||||
/// so it tends to contain a lot of garbage. This has difficulted
|
||||
/// its reverse engineering.
|
||||
/// The MDDF is the most import block on a Lisa FS volume.
|
||||
/// It describes the volume and its contents.
|
||||
/// On initialization the memory where it resides is not emptied
|
||||
/// so it tends to contain a lot of garbage. This has difficulted
|
||||
/// its reverse engineering.
|
||||
/// </summary>
|
||||
struct MDDF
|
||||
{
|
||||
@@ -209,10 +209,10 @@ namespace DiscImageChef.Filesystems.LisaFS
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// An entry in the catalog from V3.
|
||||
/// The first entry is bigger than the rest, may be a header, I have not needed any of its values so I just ignored it.
|
||||
/// Each catalog is divided in 4-sector blocks, and if it needs more than a block there are previous and next block
|
||||
/// pointers, effectively making the V3 catalog a double-linked list. Garbage is not zeroed.
|
||||
/// An entry in the catalog from V3.
|
||||
/// The first entry is bigger than the rest, may be a header, I have not needed any of its values so I just ignored it.
|
||||
/// Each catalog is divided in 4-sector blocks, and if it needs more than a block there are previous and next block
|
||||
/// pointers, effectively making the V3 catalog a double-linked list. Garbage is not zeroed.
|
||||
/// </summary>
|
||||
struct CatalogEntry
|
||||
{
|
||||
@@ -225,11 +225,11 @@ namespace DiscImageChef.Filesystems.LisaFS
|
||||
/// <summary>0x23, null-termination</summary>
|
||||
public byte terminator;
|
||||
/// <summary>
|
||||
/// At 0x24
|
||||
/// 0x01 here for subdirectories, entries 48 bytes long
|
||||
/// 0x03 here for entries 64 bytes long
|
||||
/// 0x08 here for entries 78 bytes long
|
||||
/// This is incomplete, may fail, mostly works...
|
||||
/// At 0x24
|
||||
/// 0x01 here for subdirectories, entries 48 bytes long
|
||||
/// 0x03 here for entries 64 bytes long
|
||||
/// 0x08 here for entries 78 bytes long
|
||||
/// This is incomplete, may fail, mostly works...
|
||||
/// </summary>
|
||||
public byte fileType;
|
||||
/// <summary>0x25, lot of values found here, unknown</summary>
|
||||
@@ -249,7 +249,7 @@ namespace DiscImageChef.Filesystems.LisaFS
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// An extent indicating a start and a run of sectors.
|
||||
/// An extent indicating a start and a run of sectors.
|
||||
/// </summary>
|
||||
struct Extent
|
||||
{
|
||||
@@ -258,12 +258,12 @@ namespace DiscImageChef.Filesystems.LisaFS
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The Extents File. There is one Extents File per each file stored on disk.
|
||||
/// The file ID present on the sectors tags for the Extents File is the negated
|
||||
/// value of the file ID it represents. e.g. file = 5 (0x0005) extents = -5 (0xFFFB)
|
||||
/// It spans a single sector on V2 and V3 but 2 sectors on V1.
|
||||
/// It contains all information about a file, and is indexed in the S-Records file.
|
||||
/// It also contains the label. Garbage is zeroed.
|
||||
/// The Extents File. There is one Extents File per each file stored on disk.
|
||||
/// The file ID present on the sectors tags for the Extents File is the negated
|
||||
/// value of the file ID it represents. e.g. file = 5 (0x0005) extents = -5 (0xFFFB)
|
||||
/// It spans a single sector on V2 and V3 but 2 sectors on V1.
|
||||
/// It contains all information about a file, and is indexed in the S-Records file.
|
||||
/// It also contains the label. Garbage is zeroed.
|
||||
/// </summary>
|
||||
struct ExtentFile
|
||||
{
|
||||
@@ -335,29 +335,38 @@ namespace DiscImageChef.Filesystems.LisaFS
|
||||
public int length;
|
||||
/// <summary>0x84, 0x204 in v1, unknown</summary>
|
||||
public int unknown9;
|
||||
/// <summary>0x88, 0x208 in v1, extents, can contain up to 41 extents (85 in v1), dunno LisaOS maximum (never seen more than 3)</summary>
|
||||
/// <summary>
|
||||
/// 0x88, 0x208 in v1, extents, can contain up to 41 extents (85 in v1), dunno LisaOS maximum (never seen more
|
||||
/// than 3)
|
||||
/// </summary>
|
||||
public Extent[] extents;
|
||||
/// <summary>0x17E, unknown, empty, padding?</summary>
|
||||
public short unknown10;
|
||||
/// <summary>
|
||||
/// At 0x180, this is the label.
|
||||
/// While 1982 pre-release documentation says the label can be up to 448 bytes, v1 onward only have space for a 128 bytes one.
|
||||
/// Any application can write whatever they want in the label, however, Lisa Office uses it to store its own information, something
|
||||
/// that will effectively overwrite any information a user application wrote there.
|
||||
/// The information written here by Lisa Office is like the information Finder writes in the FinderInfo structures, plus
|
||||
/// the non-unique name that is shown on the GUI. For this reason I called it LisaInfo.
|
||||
/// I have not tried to reverse engineer it.
|
||||
/// At 0x180, this is the label.
|
||||
/// While 1982 pre-release documentation says the label can be up to 448 bytes, v1 onward only have space for a 128
|
||||
/// bytes one.
|
||||
/// Any application can write whatever they want in the label, however, Lisa Office uses it to store its own
|
||||
/// information, something
|
||||
/// that will effectively overwrite any information a user application wrote there.
|
||||
/// The information written here by Lisa Office is like the information Finder writes in the FinderInfo structures,
|
||||
/// plus
|
||||
/// the non-unique name that is shown on the GUI. For this reason I called it LisaInfo.
|
||||
/// I have not tried to reverse engineer it.
|
||||
/// </summary>
|
||||
public byte[] LisaInfo;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The S-Records File is a hashtable of S-Records, where the hash is the file ID they belong to.
|
||||
/// The S-Records File cannot be fragmented or grown, and it can easily become full before the 32766 file IDs are exhausted.
|
||||
/// Each S-Record entry contains a block pointer to the Extents File that correspond to that file ID as well as the real file size,
|
||||
/// the only important information about a file that's not inside the Extents File.
|
||||
/// It also contains a low value (less than 0x200) variable field of unknown meaning and another one that seems to be flags,
|
||||
/// with values like 0, 1, 3 and 5.
|
||||
/// The S-Records File is a hashtable of S-Records, where the hash is the file ID they belong to.
|
||||
/// The S-Records File cannot be fragmented or grown, and it can easily become full before the 32766 file IDs are
|
||||
/// exhausted.
|
||||
/// Each S-Record entry contains a block pointer to the Extents File that correspond to that file ID as well as the
|
||||
/// real file size,
|
||||
/// the only important information about a file that's not inside the Extents File.
|
||||
/// It also contains a low value (less than 0x200) variable field of unknown meaning and another one that seems to be
|
||||
/// flags,
|
||||
/// with values like 0, 1, 3 and 5.
|
||||
/// </summary>
|
||||
struct SRecord
|
||||
{
|
||||
@@ -372,13 +381,13 @@ namespace DiscImageChef.Filesystems.LisaFS
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The catalog entry for the V1 and V2 volume formats.
|
||||
/// It merely contains the file name, type and ID, plus a few (mostly empty) unknown fields.
|
||||
/// Contrary to V3, it has no header and instead of being a double-linked list it is fragmented using an Extents File.
|
||||
/// The Extents File position for the root catalog is then stored in the S-Records File.
|
||||
/// Its entries are not filed sequentially denoting some kind of in-memory structure while at the same time
|
||||
/// forcing LisaOS to read the whole catalog. That or I missed the pointers.
|
||||
/// Empty entries just contain a 0-len filename. Garbage is not zeroed.
|
||||
/// The catalog entry for the V1 and V2 volume formats.
|
||||
/// It merely contains the file name, type and ID, plus a few (mostly empty) unknown fields.
|
||||
/// Contrary to V3, it has no header and instead of being a double-linked list it is fragmented using an Extents File.
|
||||
/// The Extents File position for the root catalog is then stored in the S-Records File.
|
||||
/// Its entries are not filed sequentially denoting some kind of in-memory structure while at the same time
|
||||
/// forcing LisaOS to read the whole catalog. That or I missed the pointers.
|
||||
/// Empty entries just contain a 0-len filename. Garbage is not zeroed.
|
||||
/// </summary>
|
||||
struct CatalogEntryV2
|
||||
{
|
||||
|
||||
@@ -42,7 +42,7 @@ namespace DiscImageChef.Filesystems.LisaFS
|
||||
public partial class LisaFS
|
||||
{
|
||||
/// <summary>
|
||||
/// Mounts an Apple Lisa filesystem
|
||||
/// Mounts an Apple Lisa filesystem
|
||||
/// </summary>
|
||||
public override Errno Mount()
|
||||
{
|
||||
@@ -50,7 +50,7 @@ namespace DiscImageChef.Filesystems.LisaFS
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Mounts an Apple Lisa filesystem
|
||||
/// Mounts an Apple Lisa filesystem
|
||||
/// </summary>
|
||||
public override Errno Mount(bool debug)
|
||||
{
|
||||
@@ -319,7 +319,7 @@ namespace DiscImageChef.Filesystems.LisaFS
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Umounts this Lisa filesystem
|
||||
/// Umounts this Lisa filesystem
|
||||
/// </summary>
|
||||
public override Errno Unmount()
|
||||
{
|
||||
@@ -339,7 +339,7 @@ namespace DiscImageChef.Filesystems.LisaFS
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets information about the mounted volume.
|
||||
/// Gets information about the mounted volume.
|
||||
/// </summary>
|
||||
/// <param name="stat">Information about the mounted volume.</param>
|
||||
public override Errno StatFs(ref FileSystemInfo stat)
|
||||
|
||||
@@ -41,7 +41,7 @@ namespace DiscImageChef.Filesystems.LisaFS
|
||||
public partial class LisaFS
|
||||
{
|
||||
/// <summary>
|
||||
/// Lists all extended attributes, alternate data streams and forks of the given file.
|
||||
/// Lists all extended attributes, alternate data streams and forks of the given file.
|
||||
/// </summary>
|
||||
/// <returns>Error number.</returns>
|
||||
/// <param name="path">Path.</param>
|
||||
@@ -55,7 +55,7 @@ namespace DiscImageChef.Filesystems.LisaFS
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads an extended attribute, alternate data stream or fork from the given file.
|
||||
/// Reads an extended attribute, alternate data stream or fork from the given file.
|
||||
/// </summary>
|
||||
/// <returns>Error number.</returns>
|
||||
/// <param name="path">File path.</param>
|
||||
@@ -70,7 +70,7 @@ namespace DiscImageChef.Filesystems.LisaFS
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Lists special Apple Lisa filesystem features as extended attributes
|
||||
/// Lists special Apple Lisa filesystem features as extended attributes
|
||||
/// </summary>
|
||||
/// <returns>Error number.</returns>
|
||||
/// <param name="fileId">File identifier.</param>
|
||||
@@ -125,7 +125,7 @@ namespace DiscImageChef.Filesystems.LisaFS
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Lists special Apple Lisa filesystem features as extended attributes
|
||||
/// Lists special Apple Lisa filesystem features as extended attributes
|
||||
/// </summary>
|
||||
/// <returns>Error number.</returns>
|
||||
/// <param name="fileId">File identifier.</param>
|
||||
@@ -161,7 +161,8 @@ namespace DiscImageChef.Filesystems.LisaFS
|
||||
|
||||
if(error != Errno.NoError) return error;
|
||||
|
||||
switch(xattr) {
|
||||
switch(xattr)
|
||||
{
|
||||
case "com.apple.lisa.password" when file.password_valid > 0:
|
||||
buf = new byte[8];
|
||||
Array.Copy(file.password, 0, buf, 0, 8);
|
||||
@@ -184,7 +185,7 @@ namespace DiscImageChef.Filesystems.LisaFS
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Decodes a sector tag. Not tested with 24-byte tags.
|
||||
/// Decodes a sector tag. Not tested with 24-byte tags.
|
||||
/// </summary>
|
||||
/// <returns>Error number.</returns>
|
||||
/// <param name="tag">Sector tag.</param>
|
||||
|
||||
@@ -56,8 +56,6 @@ using time_t = System.Int32;
|
||||
|
||||
namespace DiscImageChef.Filesystems
|
||||
{
|
||||
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
||||
[SuppressMessage("ReSharper", "BuiltInTypeReferenceStyle")]
|
||||
public class Locus : Filesystem
|
||||
{
|
||||
const int NICINOD = 325;
|
||||
@@ -65,131 +63,6 @@ namespace DiscImageChef.Filesystems
|
||||
const int OLDNICINOD = 700;
|
||||
const int OLDNICFREE = 500;
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct Locus_Superblock
|
||||
{
|
||||
public uint s_magic; /* identifies this as a locus filesystem */
|
||||
/* defined as a constant below */
|
||||
public gfs_t s_gfs; /* global filesystem number */
|
||||
public daddr_t s_fsize; /* size in blocks of entire volume */
|
||||
/* several ints for replicated filsystems */
|
||||
public commitcnt_t s_lwm; /* all prior commits propagated */
|
||||
public commitcnt_t s_hwm; /* highest commit propagated */
|
||||
/* oldest committed version in the list.
|
||||
* llst mod NCMTLST is the offset of commit #llst in the list,
|
||||
* which wraps around from there.
|
||||
*/
|
||||
public commitcnt_t s_llst;
|
||||
public fstore_t s_fstore; /* filesystem storage bit mask; if the
|
||||
filsys is replicated and this is not a
|
||||
primary or backbone copy, this bit mask
|
||||
determines which files are stored */
|
||||
|
||||
public time_t s_time; /* last super block update */
|
||||
public daddr_t s_tfree; /* total free blocks*/
|
||||
|
||||
public ino_t s_isize; /* size in blocks of i-list */
|
||||
public short s_nfree; /* number of addresses in s_free */
|
||||
public LocusFlags s_flags; /* filsys flags, defined below */
|
||||
public ino_t s_tinode; /* total free inodes */
|
||||
public ino_t s_lasti; /* start place for circular search */
|
||||
public ino_t s_nbehind; /* est # free inodes before s_lasti */
|
||||
public pckno_t s_gfspack; /* global filesystem pack number */
|
||||
public short s_ninode; /* number of i-nodes in s_inode */
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] public short[] s_dinfo; /* interleave stuff */
|
||||
//#define s_m s_dinfo[0]
|
||||
//#define s_skip s_dinfo[0] /* AIX defines */
|
||||
//#define s_n s_dinfo[1]
|
||||
//#define s_cyl s_dinfo[1] /* AIX defines */
|
||||
public byte s_flock; /* lock during free list manipulation */
|
||||
public byte s_ilock; /* lock during i-list manipulation */
|
||||
public byte s_fmod; /* super block modified flag */
|
||||
public LocusVersion s_version; /* version of the data format in fs. */
|
||||
/* defined below. */
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] public byte[] s_fsmnt; /* name of this file system */
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
|
||||
public byte[] s_fpack; /* name of this physical volume */
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = NICINOD)] public ino_t[] s_inode; /* free i-node list */
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = NICFREE)]
|
||||
public daddr_t[] su_free; /* free block list for non-replicated filsys */
|
||||
public byte s_byteorder; /* byte order of integers */
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct Locus_OldSuperblock
|
||||
{
|
||||
public uint s_magic; /* identifies this as a locus filesystem */
|
||||
/* defined as a constant below */
|
||||
public gfs_t s_gfs; /* global filesystem number */
|
||||
public daddr_t s_fsize; /* size in blocks of entire volume */
|
||||
/* several ints for replicated filsystems */
|
||||
public commitcnt_t s_lwm; /* all prior commits propagated */
|
||||
public commitcnt_t s_hwm; /* highest commit propagated */
|
||||
/* oldest committed version in the list.
|
||||
* llst mod NCMTLST is the offset of commit #llst in the list,
|
||||
* which wraps around from there.
|
||||
*/
|
||||
public commitcnt_t s_llst;
|
||||
public fstore_t s_fstore; /* filesystem storage bit mask; if the
|
||||
filsys is replicated and this is not a
|
||||
primary or backbone copy, this bit mask
|
||||
determines which files are stored */
|
||||
|
||||
public time_t s_time; /* last super block update */
|
||||
public daddr_t s_tfree; /* total free blocks*/
|
||||
|
||||
public ino_t s_isize; /* size in blocks of i-list */
|
||||
public short s_nfree; /* number of addresses in s_free */
|
||||
public LocusFlags s_flags; /* filsys flags, defined below */
|
||||
public ino_t s_tinode; /* total free inodes */
|
||||
public ino_t s_lasti; /* start place for circular search */
|
||||
public ino_t s_nbehind; /* est # free inodes before s_lasti */
|
||||
public pckno_t s_gfspack; /* global filesystem pack number */
|
||||
public short s_ninode; /* number of i-nodes in s_inode */
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] public short[] s_dinfo; /* interleave stuff */
|
||||
//#define s_m s_dinfo[0]
|
||||
//#define s_skip s_dinfo[0] /* AIX defines */
|
||||
//#define s_n s_dinfo[1]
|
||||
//#define s_cyl s_dinfo[1] /* AIX defines */
|
||||
public byte s_flock; /* lock during free list manipulation */
|
||||
public byte s_ilock; /* lock during i-list manipulation */
|
||||
public byte s_fmod; /* super block modified flag */
|
||||
public LocusVersion s_version; /* version of the data format in fs. */
|
||||
/* defined below. */
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] public byte[] s_fsmnt; /* name of this file system */
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
|
||||
public byte[] s_fpack; /* name of this physical volume */
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = OLDNICINOD)] public ino_t[] s_inode; /* free i-node list */
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = OLDNICFREE)]
|
||||
public daddr_t[] su_free; /* free block list for non-replicated filsys */
|
||||
public byte s_byteorder; /* byte order of integers */
|
||||
}
|
||||
|
||||
[Flags]
|
||||
enum LocusFlags : ushort
|
||||
{
|
||||
SB_RDONLY = 0x1, /* no writes on filesystem */
|
||||
SB_CLEAN = 0x2, /* fs unmounted cleanly (or checks run) */
|
||||
SB_DIRTY = 0x4, /* fs mounted without CLEAN bit set */
|
||||
SB_RMV = 0x8, /* fs is a removable file system */
|
||||
SB_PRIMPACK = 0x10, /* This is the primary pack of the filesystem */
|
||||
SB_REPLTYPE = 0x20, /* This is a replicated type filesystem. */
|
||||
SB_USER = 0x40, /* This is a "user" replicated filesystem. */
|
||||
SB_BACKBONE = 0x80, /* backbone pack ; complete copy of primary pack but not modifiable */
|
||||
SB_NFS = 0x100, /* This is a NFS type filesystem */
|
||||
SB_BYHAND = 0x200, /* Inhibits automatic fscks on a mangled file system */
|
||||
SB_NOSUID = 0x400, /* Set-uid/Set-gid is disabled */
|
||||
SB_SYNCW = 0x800 /* Synchronous Write */
|
||||
}
|
||||
|
||||
[Flags]
|
||||
enum LocusVersion : byte
|
||||
{
|
||||
SB_SB4096 = 1, /* smallblock filesys with 4096 byte blocks */
|
||||
SB_B1024 = 2, /* 1024 byte block filesystem */
|
||||
NUMSCANDEV = 5 /* Used by scangfs(), refed in space.h */
|
||||
}
|
||||
|
||||
const uint Locus_Magic = 0xFFEEDDCD;
|
||||
const uint Locus_Cigam = 0xCDDDEEFF;
|
||||
const uint Locus_OldMagic = 0xFFEEDDCC;
|
||||
@@ -246,8 +119,7 @@ namespace DiscImageChef.Filesystems
|
||||
return false;
|
||||
}
|
||||
|
||||
public override void GetInformation(ImagePlugin imagePlugin, Partition partition,
|
||||
out string information)
|
||||
public override void GetInformation(ImagePlugin imagePlugin, Partition partition, out string information)
|
||||
{
|
||||
information = "";
|
||||
if(imagePlugin.GetSectorSize() < 512) return;
|
||||
@@ -417,5 +289,138 @@ namespace DiscImageChef.Filesystems
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
||||
[SuppressMessage("ReSharper", "BuiltInTypeReferenceStyle")]
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct Locus_Superblock
|
||||
{
|
||||
public uint s_magic; /* identifies this as a locus filesystem */
|
||||
/* defined as a constant below */
|
||||
public gfs_t s_gfs; /* global filesystem number */
|
||||
public daddr_t s_fsize; /* size in blocks of entire volume */
|
||||
/* several ints for replicated filsystems */
|
||||
public commitcnt_t s_lwm; /* all prior commits propagated */
|
||||
public commitcnt_t s_hwm; /* highest commit propagated */
|
||||
/* oldest committed version in the list.
|
||||
* llst mod NCMTLST is the offset of commit #llst in the list,
|
||||
* which wraps around from there.
|
||||
*/
|
||||
public commitcnt_t s_llst;
|
||||
public fstore_t s_fstore; /* filesystem storage bit mask; if the
|
||||
filsys is replicated and this is not a
|
||||
primary or backbone copy, this bit mask
|
||||
determines which files are stored */
|
||||
|
||||
public time_t s_time; /* last super block update */
|
||||
public daddr_t s_tfree; /* total free blocks*/
|
||||
|
||||
public ino_t s_isize; /* size in blocks of i-list */
|
||||
public short s_nfree; /* number of addresses in s_free */
|
||||
public LocusFlags s_flags; /* filsys flags, defined below */
|
||||
public ino_t s_tinode; /* total free inodes */
|
||||
public ino_t s_lasti; /* start place for circular search */
|
||||
public ino_t s_nbehind; /* est # free inodes before s_lasti */
|
||||
public pckno_t s_gfspack; /* global filesystem pack number */
|
||||
public short s_ninode; /* number of i-nodes in s_inode */
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] public short[] s_dinfo; /* interleave stuff */
|
||||
//#define s_m s_dinfo[0]
|
||||
//#define s_skip s_dinfo[0] /* AIX defines */
|
||||
//#define s_n s_dinfo[1]
|
||||
//#define s_cyl s_dinfo[1] /* AIX defines */
|
||||
public byte s_flock; /* lock during free list manipulation */
|
||||
public byte s_ilock; /* lock during i-list manipulation */
|
||||
public byte s_fmod; /* super block modified flag */
|
||||
public LocusVersion s_version; /* version of the data format in fs. */
|
||||
/* defined below. */
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] public byte[] s_fsmnt; /* name of this file system */
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
|
||||
public byte[] s_fpack; /* name of this physical volume */
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = NICINOD)] public ino_t[] s_inode; /* free i-node list */
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = NICFREE)]
|
||||
public daddr_t[] su_free; /* free block list for non-replicated filsys */
|
||||
public byte s_byteorder; /* byte order of integers */
|
||||
}
|
||||
|
||||
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
||||
[SuppressMessage("ReSharper", "BuiltInTypeReferenceStyle")]
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct Locus_OldSuperblock
|
||||
{
|
||||
public uint s_magic; /* identifies this as a locus filesystem */
|
||||
/* defined as a constant below */
|
||||
public gfs_t s_gfs; /* global filesystem number */
|
||||
public daddr_t s_fsize; /* size in blocks of entire volume */
|
||||
/* several ints for replicated filsystems */
|
||||
public commitcnt_t s_lwm; /* all prior commits propagated */
|
||||
public commitcnt_t s_hwm; /* highest commit propagated */
|
||||
/* oldest committed version in the list.
|
||||
* llst mod NCMTLST is the offset of commit #llst in the list,
|
||||
* which wraps around from there.
|
||||
*/
|
||||
public commitcnt_t s_llst;
|
||||
public fstore_t s_fstore; /* filesystem storage bit mask; if the
|
||||
filsys is replicated and this is not a
|
||||
primary or backbone copy, this bit mask
|
||||
determines which files are stored */
|
||||
|
||||
public time_t s_time; /* last super block update */
|
||||
public daddr_t s_tfree; /* total free blocks*/
|
||||
|
||||
public ino_t s_isize; /* size in blocks of i-list */
|
||||
public short s_nfree; /* number of addresses in s_free */
|
||||
public LocusFlags s_flags; /* filsys flags, defined below */
|
||||
public ino_t s_tinode; /* total free inodes */
|
||||
public ino_t s_lasti; /* start place for circular search */
|
||||
public ino_t s_nbehind; /* est # free inodes before s_lasti */
|
||||
public pckno_t s_gfspack; /* global filesystem pack number */
|
||||
public short s_ninode; /* number of i-nodes in s_inode */
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] public short[] s_dinfo; /* interleave stuff */
|
||||
//#define s_m s_dinfo[0]
|
||||
//#define s_skip s_dinfo[0] /* AIX defines */
|
||||
//#define s_n s_dinfo[1]
|
||||
//#define s_cyl s_dinfo[1] /* AIX defines */
|
||||
public byte s_flock; /* lock during free list manipulation */
|
||||
public byte s_ilock; /* lock during i-list manipulation */
|
||||
public byte s_fmod; /* super block modified flag */
|
||||
public LocusVersion s_version; /* version of the data format in fs. */
|
||||
/* defined below. */
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] public byte[] s_fsmnt; /* name of this file system */
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
|
||||
public byte[] s_fpack; /* name of this physical volume */
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = OLDNICINOD)] public ino_t[] s_inode; /* free i-node list */
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = OLDNICFREE)]
|
||||
public daddr_t[] su_free; /* free block list for non-replicated filsys */
|
||||
public byte s_byteorder; /* byte order of integers */
|
||||
}
|
||||
|
||||
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
||||
[SuppressMessage("ReSharper", "BuiltInTypeReferenceStyle")]
|
||||
[Flags]
|
||||
enum LocusFlags : ushort
|
||||
{
|
||||
SB_RDONLY = 0x1, /* no writes on filesystem */
|
||||
SB_CLEAN = 0x2, /* fs unmounted cleanly (or checks run) */
|
||||
SB_DIRTY = 0x4, /* fs mounted without CLEAN bit set */
|
||||
SB_RMV = 0x8, /* fs is a removable file system */
|
||||
SB_PRIMPACK = 0x10, /* This is the primary pack of the filesystem */
|
||||
SB_REPLTYPE = 0x20, /* This is a replicated type filesystem. */
|
||||
SB_USER = 0x40, /* This is a "user" replicated filesystem. */
|
||||
SB_BACKBONE = 0x80, /* backbone pack ; complete copy of primary pack but not modifiable */
|
||||
SB_NFS = 0x100, /* This is a NFS type filesystem */
|
||||
SB_BYHAND = 0x200, /* Inhibits automatic fscks on a mangled file system */
|
||||
SB_NOSUID = 0x400, /* Set-uid/Set-gid is disabled */
|
||||
SB_SYNCW = 0x800 /* Synchronous Write */
|
||||
}
|
||||
|
||||
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
||||
[SuppressMessage("ReSharper", "BuiltInTypeReferenceStyle")]
|
||||
[Flags]
|
||||
enum LocusVersion : byte
|
||||
{
|
||||
SB_SB4096 = 1, /* smallblock filesys with 4096 byte blocks */
|
||||
SB_B1024 = 2, /* 1024 byte block filesystem */
|
||||
NUMSCANDEV = 5 /* Used by scangfs(), refed in space.h */
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -77,14 +77,14 @@ namespace DiscImageChef.Filesystems
|
||||
byte[] bk0 = imagePlugin.ReadSector(0 + partition.Start);
|
||||
|
||||
GCHandle handle = GCHandle.Alloc(bk0, GCHandleType.Pinned);
|
||||
MicroDOSBlock0 block0 = (MicroDOSBlock0)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(MicroDOSBlock0));
|
||||
MicroDOSBlock0 block0 =
|
||||
(MicroDOSBlock0)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(MicroDOSBlock0));
|
||||
handle.Free();
|
||||
|
||||
return block0.label == MAGIC && block0.mklabel == MAGIC2;
|
||||
}
|
||||
|
||||
public override void GetInformation(ImagePlugin imagePlugin, Partition partition,
|
||||
out string information)
|
||||
public override void GetInformation(ImagePlugin imagePlugin, Partition partition, out string information)
|
||||
{
|
||||
information = "";
|
||||
|
||||
@@ -93,7 +93,8 @@ namespace DiscImageChef.Filesystems
|
||||
byte[] bk0 = imagePlugin.ReadSector(0 + partition.Start);
|
||||
|
||||
GCHandle handle = GCHandle.Alloc(bk0, GCHandleType.Pinned);
|
||||
MicroDOSBlock0 block0 = (MicroDOSBlock0)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(MicroDOSBlock0));
|
||||
MicroDOSBlock0 block0 =
|
||||
(MicroDOSBlock0)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(MicroDOSBlock0));
|
||||
handle.Free();
|
||||
|
||||
sb.AppendLine("MicroDOS filesystem");
|
||||
@@ -117,62 +118,6 @@ namespace DiscImageChef.Filesystems
|
||||
information = sb.ToString();
|
||||
}
|
||||
|
||||
// Followed by directory entries
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct MicroDOSBlock0
|
||||
{
|
||||
/// <summary>BK starts booting here</summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 24)] public byte[] bootCode;
|
||||
/// <summary>Number of files in directory</summary>
|
||||
public ushort files;
|
||||
/// <summary>Total number of blocks in files of the directory</summary>
|
||||
public ushort usedBlocks;
|
||||
/// <summary>Unknown</summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 228)] public byte[] unknown;
|
||||
/// <summary>Ownership label (label that shows it belongs to Micro DOS format)</summary>
|
||||
public ushort label;
|
||||
/// <summary>MK-DOS directory format label</summary>
|
||||
public ushort mklabel;
|
||||
/// <summary>Unknown</summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 50)] public byte[] unknown2;
|
||||
/// <summary>Disk size in blocks (absolute value for the system unlike NORD, NORTON etc.) that
|
||||
/// doesn't use two fixed values 40 or 80 tracks, but i.e. if you drive works with 76 tracks
|
||||
/// this field will contain an appropriate number of blocks</summary>
|
||||
public ushort blocks;
|
||||
/// <summary> Number of the first file's block. Value is changable</summary>
|
||||
public ushort firstUsedBlock;
|
||||
/// <summary>Unknown</summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)] public byte[] unknown3;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct DirectoryEntry
|
||||
{
|
||||
/// <summary>File status</summary>
|
||||
public byte status;
|
||||
/// <summary>Directory number (0 - root)</summary>
|
||||
public byte directory;
|
||||
/// <summary>File name 14. symbols in ASCII KOI8</summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)] public byte[] filename;
|
||||
/// <summary>Block number</summary>
|
||||
public ushort blockNo;
|
||||
/// <summary>Length in blocks</summary>
|
||||
public ushort blocks;
|
||||
/// <summary>Address</summary>
|
||||
public ushort address;
|
||||
/// <summary>Length</summary>
|
||||
public ushort length;
|
||||
}
|
||||
|
||||
enum FileStatus : byte
|
||||
{
|
||||
CommonFile = 0,
|
||||
Protected = 1,
|
||||
LogicalDisk = 2,
|
||||
BadFile = 0x80,
|
||||
Deleted = 0xFF
|
||||
}
|
||||
|
||||
public override Errno Mount()
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
@@ -232,5 +177,63 @@ namespace DiscImageChef.Filesystems
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
// Followed by directory entries
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct MicroDOSBlock0
|
||||
{
|
||||
/// <summary>BK starts booting here</summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 24)] public byte[] bootCode;
|
||||
/// <summary>Number of files in directory</summary>
|
||||
public ushort files;
|
||||
/// <summary>Total number of blocks in files of the directory</summary>
|
||||
public ushort usedBlocks;
|
||||
/// <summary>Unknown</summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 228)] public byte[] unknown;
|
||||
/// <summary>Ownership label (label that shows it belongs to Micro DOS format)</summary>
|
||||
public ushort label;
|
||||
/// <summary>MK-DOS directory format label</summary>
|
||||
public ushort mklabel;
|
||||
/// <summary>Unknown</summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 50)] public byte[] unknown2;
|
||||
/// <summary>
|
||||
/// Disk size in blocks (absolute value for the system unlike NORD, NORTON etc.) that
|
||||
/// doesn't use two fixed values 40 or 80 tracks, but i.e. if you drive works with 76 tracks
|
||||
/// this field will contain an appropriate number of blocks
|
||||
/// </summary>
|
||||
public ushort blocks;
|
||||
/// <summary> Number of the first file's block. Value is changable</summary>
|
||||
public ushort firstUsedBlock;
|
||||
/// <summary>Unknown</summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)] public byte[] unknown3;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct DirectoryEntry
|
||||
{
|
||||
/// <summary>File status</summary>
|
||||
public byte status;
|
||||
/// <summary>Directory number (0 - root)</summary>
|
||||
public byte directory;
|
||||
/// <summary>File name 14. symbols in ASCII KOI8</summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)] public byte[] filename;
|
||||
/// <summary>Block number</summary>
|
||||
public ushort blockNo;
|
||||
/// <summary>Length in blocks</summary>
|
||||
public ushort blocks;
|
||||
/// <summary>Address</summary>
|
||||
public ushort address;
|
||||
/// <summary>Length</summary>
|
||||
public ushort length;
|
||||
}
|
||||
|
||||
enum FileStatus : byte
|
||||
{
|
||||
CommonFile = 0,
|
||||
Protected = 1,
|
||||
LogicalDisk = 2,
|
||||
BadFile = 0x80,
|
||||
Deleted = 0xFF
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -124,8 +124,7 @@ namespace DiscImageChef.Filesystems
|
||||
return false;
|
||||
}
|
||||
|
||||
public override void GetInformation(ImagePlugin imagePlugin, Partition partition,
|
||||
out string information)
|
||||
public override void GetInformation(ImagePlugin imagePlugin, Partition partition, out string information)
|
||||
{
|
||||
information = "";
|
||||
|
||||
@@ -166,7 +165,8 @@ namespace DiscImageChef.Filesystems
|
||||
filenamesize = 60;
|
||||
littleEndian = magic != MINIX3_CIGAM || magic == MINIX2_CIGAM || magic == MINIX_CIGAM;
|
||||
|
||||
switch(magic) {
|
||||
switch(magic)
|
||||
{
|
||||
case MINIX3_MAGIC:
|
||||
case MINIX3_CIGAM:
|
||||
minixVersion = "Minix v3 filesystem";
|
||||
@@ -251,7 +251,7 @@ namespace DiscImageChef.Filesystems
|
||||
{
|
||||
GCHandle handle = GCHandle.Alloc(minixSbSector, GCHandleType.Pinned);
|
||||
mnxSb = (Minix3SuperBlock)Marshal.PtrToStructure(handle.AddrOfPinnedObject(),
|
||||
typeof(Minix3SuperBlock));
|
||||
typeof(Minix3SuperBlock));
|
||||
handle.Free();
|
||||
}
|
||||
else mnxSb = BigEndianMarshal.ByteArrayToStructureBigEndian<Minix3SuperBlock>(minixSbSector);
|
||||
@@ -288,7 +288,7 @@ namespace DiscImageChef.Filesystems
|
||||
{
|
||||
GCHandle handle = GCHandle.Alloc(minixSbSector, GCHandleType.Pinned);
|
||||
mnxSb = (MinixSuperBlock)Marshal.PtrToStructure(handle.AddrOfPinnedObject(),
|
||||
typeof(MinixSuperBlock));
|
||||
typeof(MinixSuperBlock));
|
||||
handle.Free();
|
||||
}
|
||||
else mnxSb = BigEndianMarshal.ByteArrayToStructureBigEndian<MinixSuperBlock>(minixSbSector);
|
||||
@@ -302,8 +302,8 @@ namespace DiscImageChef.Filesystems
|
||||
sb.AppendFormat("{0} zones on volume ({1} bytes)", mnxSb.s_nzones, mnxSb.s_nzones * 1024)
|
||||
.AppendLine();
|
||||
sb.AppendFormat("{0} inodes on volume", mnxSb.s_ninodes).AppendLine();
|
||||
sb.AppendFormat("{0} blocks on inode map ({1} bytes)", mnxSb.s_imap_blocks,
|
||||
mnxSb.s_imap_blocks * 1024).AppendLine();
|
||||
sb.AppendFormat("{0} blocks on inode map ({1} bytes)", mnxSb.s_imap_blocks, mnxSb.s_imap_blocks * 1024)
|
||||
.AppendLine();
|
||||
sb.AppendFormat("{0} blocks on zone map ({1} bytes)", mnxSb.s_zmap_blocks, mnxSb.s_zmap_blocks * 1024)
|
||||
.AppendLine();
|
||||
sb.AppendFormat("First data zone: {0}", mnxSb.s_firstdatazone).AppendLine();
|
||||
@@ -316,68 +316,6 @@ namespace DiscImageChef.Filesystems
|
||||
information = sb.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Superblock for Minix v1 and V2 filesystems
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct MinixSuperBlock
|
||||
{
|
||||
/// <summary>0x00, inodes on volume</summary>
|
||||
public ushort s_ninodes;
|
||||
/// <summary>0x02, zones on volume</summary>
|
||||
public ushort s_nzones;
|
||||
/// <summary>0x04, blocks on inode map</summary>
|
||||
public short s_imap_blocks;
|
||||
/// <summary>0x06, blocks on zone map</summary>
|
||||
public short s_zmap_blocks;
|
||||
/// <summary>0x08, first data zone</summary>
|
||||
public ushort s_firstdatazone;
|
||||
/// <summary>0x0A, log2 of blocks/zone</summary>
|
||||
public short s_log_zone_size;
|
||||
/// <summary>0x0C, max file size</summary>
|
||||
public uint s_max_size;
|
||||
/// <summary>0x10, magic</summary>
|
||||
public ushort s_magic;
|
||||
/// <summary>0x12, filesystem state</summary>
|
||||
public ushort s_state;
|
||||
/// <summary>0x14, number of zones</summary>
|
||||
public uint s_zones;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Superblock for Minix v3 filesystems
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct Minix3SuperBlock
|
||||
{
|
||||
/// <summary>0x00, inodes on volume</summary>
|
||||
public uint s_ninodes;
|
||||
/// <summary>0x02, old zones on volume</summary>
|
||||
public ushort s_nzones;
|
||||
/// <summary>0x06, blocks on inode map</summary>
|
||||
public ushort s_imap_blocks;
|
||||
/// <summary>0x08, blocks on zone map</summary>
|
||||
public ushort s_zmap_blocks;
|
||||
/// <summary>0x0A, first data zone</summary>
|
||||
public ushort s_firstdatazone;
|
||||
/// <summary>0x0C, log2 of blocks/zone</summary>
|
||||
public ushort s_log_zone_size;
|
||||
/// <summary>0x0E, padding</summary>
|
||||
public ushort s_pad1;
|
||||
/// <summary>0x10, max file size</summary>
|
||||
public uint s_max_size;
|
||||
/// <summary>0x14, number of zones</summary>
|
||||
public uint s_zones;
|
||||
/// <summary>0x18, magic</summary>
|
||||
public ushort s_magic;
|
||||
/// <summary>0x1A, padding</summary>
|
||||
public ushort s_pad2;
|
||||
/// <summary>0x1C, bytes in a block</summary>
|
||||
public ushort s_blocksize;
|
||||
/// <summary>0x1E, on-disk structures version</summary>
|
||||
public byte s_disk_version;
|
||||
}
|
||||
|
||||
public override Errno Mount()
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
@@ -437,5 +375,67 @@ namespace DiscImageChef.Filesystems
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Superblock for Minix v1 and V2 filesystems
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct MinixSuperBlock
|
||||
{
|
||||
/// <summary>0x00, inodes on volume</summary>
|
||||
public ushort s_ninodes;
|
||||
/// <summary>0x02, zones on volume</summary>
|
||||
public ushort s_nzones;
|
||||
/// <summary>0x04, blocks on inode map</summary>
|
||||
public short s_imap_blocks;
|
||||
/// <summary>0x06, blocks on zone map</summary>
|
||||
public short s_zmap_blocks;
|
||||
/// <summary>0x08, first data zone</summary>
|
||||
public ushort s_firstdatazone;
|
||||
/// <summary>0x0A, log2 of blocks/zone</summary>
|
||||
public short s_log_zone_size;
|
||||
/// <summary>0x0C, max file size</summary>
|
||||
public uint s_max_size;
|
||||
/// <summary>0x10, magic</summary>
|
||||
public ushort s_magic;
|
||||
/// <summary>0x12, filesystem state</summary>
|
||||
public ushort s_state;
|
||||
/// <summary>0x14, number of zones</summary>
|
||||
public uint s_zones;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Superblock for Minix v3 filesystems
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct Minix3SuperBlock
|
||||
{
|
||||
/// <summary>0x00, inodes on volume</summary>
|
||||
public uint s_ninodes;
|
||||
/// <summary>0x02, old zones on volume</summary>
|
||||
public ushort s_nzones;
|
||||
/// <summary>0x06, blocks on inode map</summary>
|
||||
public ushort s_imap_blocks;
|
||||
/// <summary>0x08, blocks on zone map</summary>
|
||||
public ushort s_zmap_blocks;
|
||||
/// <summary>0x0A, first data zone</summary>
|
||||
public ushort s_firstdatazone;
|
||||
/// <summary>0x0C, log2 of blocks/zone</summary>
|
||||
public ushort s_log_zone_size;
|
||||
/// <summary>0x0E, padding</summary>
|
||||
public ushort s_pad1;
|
||||
/// <summary>0x10, max file size</summary>
|
||||
public uint s_max_size;
|
||||
/// <summary>0x14, number of zones</summary>
|
||||
public uint s_zones;
|
||||
/// <summary>0x18, magic</summary>
|
||||
public ushort s_magic;
|
||||
/// <summary>0x1A, padding</summary>
|
||||
public ushort s_pad2;
|
||||
/// <summary>0x1C, bytes in a block</summary>
|
||||
public ushort s_blocksize;
|
||||
/// <summary>0x1E, on-disk structures version</summary>
|
||||
public byte s_disk_version;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -42,59 +42,6 @@ namespace DiscImageChef.Filesystems
|
||||
{
|
||||
public class NILFS2 : Filesystem
|
||||
{
|
||||
enum NILFS2_State : ushort
|
||||
{
|
||||
Valid = 0x0001,
|
||||
Error = 0x0002,
|
||||
Resize = 0x0004
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct NILFS2_Superblock
|
||||
{
|
||||
public uint rev_level;
|
||||
public ushort minor_rev_level;
|
||||
public ushort magic;
|
||||
public ushort bytes;
|
||||
public ushort flags;
|
||||
public uint crc_seed;
|
||||
public uint sum;
|
||||
public uint log_block_size;
|
||||
public ulong nsegments;
|
||||
public ulong dev_size;
|
||||
public ulong first_data_block;
|
||||
public uint blocks_per_segment;
|
||||
public uint r_segments_percentage;
|
||||
public ulong last_cno;
|
||||
public ulong last_pseg;
|
||||
public ulong last_seq;
|
||||
public ulong free_blocks_count;
|
||||
public ulong ctime;
|
||||
public ulong mtime;
|
||||
public ulong wtime;
|
||||
public ushort mnt_count;
|
||||
public ushort max_mnt_count;
|
||||
public NILFS2_State state;
|
||||
public ushort errors;
|
||||
public ulong lastcheck;
|
||||
public uint checkinterval;
|
||||
public uint creator_os;
|
||||
public ushort def_resuid;
|
||||
public ushort def_resgid;
|
||||
public uint first_ino;
|
||||
public ushort inode_size;
|
||||
public ushort dat_entry_size;
|
||||
public ushort checkpoint_size;
|
||||
public ushort segment_usage_size;
|
||||
public Guid uuid;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 80)] public byte[] volume_name;
|
||||
public uint c_interval;
|
||||
public uint c_block_max;
|
||||
public ulong feature_compat;
|
||||
public ulong feature_compat_ro;
|
||||
public ulong feature_incompat;
|
||||
}
|
||||
|
||||
const ushort NILFS2_MAGIC = 0x3434;
|
||||
const uint NILFS2_SUPER_OFFSET = 1024;
|
||||
|
||||
@@ -144,8 +91,7 @@ namespace DiscImageChef.Filesystems
|
||||
return nilfsSb.magic == NILFS2_MAGIC;
|
||||
}
|
||||
|
||||
public override void GetInformation(ImagePlugin imagePlugin, Partition partition,
|
||||
out string information)
|
||||
public override void GetInformation(ImagePlugin imagePlugin, Partition partition, out string information)
|
||||
{
|
||||
information = "";
|
||||
if(imagePlugin.GetSectorSize() < 512) return;
|
||||
@@ -264,5 +210,58 @@ namespace DiscImageChef.Filesystems
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
enum NILFS2_State : ushort
|
||||
{
|
||||
Valid = 0x0001,
|
||||
Error = 0x0002,
|
||||
Resize = 0x0004
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct NILFS2_Superblock
|
||||
{
|
||||
public uint rev_level;
|
||||
public ushort minor_rev_level;
|
||||
public ushort magic;
|
||||
public ushort bytes;
|
||||
public ushort flags;
|
||||
public uint crc_seed;
|
||||
public uint sum;
|
||||
public uint log_block_size;
|
||||
public ulong nsegments;
|
||||
public ulong dev_size;
|
||||
public ulong first_data_block;
|
||||
public uint blocks_per_segment;
|
||||
public uint r_segments_percentage;
|
||||
public ulong last_cno;
|
||||
public ulong last_pseg;
|
||||
public ulong last_seq;
|
||||
public ulong free_blocks_count;
|
||||
public ulong ctime;
|
||||
public ulong mtime;
|
||||
public ulong wtime;
|
||||
public ushort mnt_count;
|
||||
public ushort max_mnt_count;
|
||||
public NILFS2_State state;
|
||||
public ushort errors;
|
||||
public ulong lastcheck;
|
||||
public uint checkinterval;
|
||||
public uint creator_os;
|
||||
public ushort def_resuid;
|
||||
public ushort def_resgid;
|
||||
public uint first_ino;
|
||||
public ushort inode_size;
|
||||
public ushort dat_entry_size;
|
||||
public ushort checkpoint_size;
|
||||
public ushort segment_usage_size;
|
||||
public Guid uuid;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 80)] public byte[] volume_name;
|
||||
public uint c_interval;
|
||||
public uint c_block_max;
|
||||
public ulong feature_compat;
|
||||
public ulong feature_compat_ro;
|
||||
public ulong feature_incompat;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -93,8 +93,7 @@ namespace DiscImageChef.Filesystems
|
||||
return signature == 0xAA55;
|
||||
}
|
||||
|
||||
public override void GetInformation(ImagePlugin imagePlugin, Partition partition,
|
||||
out string information)
|
||||
public override void GetInformation(ImagePlugin imagePlugin, Partition partition, out string information)
|
||||
{
|
||||
information = "";
|
||||
|
||||
@@ -141,8 +140,7 @@ namespace DiscImageChef.Filesystems
|
||||
|
||||
XmlFsType = new FileSystemType();
|
||||
|
||||
if(ntfsBb.jump[0] == 0xEB && ntfsBb.jump[1] > 0x4E && ntfsBb.jump[1] < 0x80 &&
|
||||
ntfsBb.signature2 == 0xAA55)
|
||||
if(ntfsBb.jump[0] == 0xEB && ntfsBb.jump[1] > 0x4E && ntfsBb.jump[1] < 0x80 && ntfsBb.signature2 == 0xAA55)
|
||||
{
|
||||
XmlFsType.Bootable = true;
|
||||
Sha1Context sha1Ctx = new Sha1Context();
|
||||
@@ -160,8 +158,68 @@ namespace DiscImageChef.Filesystems
|
||||
information = sb.ToString();
|
||||
}
|
||||
|
||||
public override Errno Mount()
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno Mount(bool debug)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno Unmount()
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno MapBlock(string path, long fileBlock, ref long deviceBlock)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno GetAttributes(string path, ref FileAttributes attributes)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno ListXAttr(string path, ref List<string> xattrs)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno GetXattr(string path, string xattr, ref byte[] buf)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno Read(string path, long offset, long size, ref byte[] buf)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno ReadDir(string path, ref List<string> contents)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno StatFs(ref FileSystemInfo stat)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno Stat(string path, ref FileEntryInfo stat)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno ReadLink(string path, ref string dest)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// NTFS $BOOT
|
||||
/// NTFS $BOOT
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct NtfsBootBlock
|
||||
@@ -231,65 +289,5 @@ namespace DiscImageChef.Filesystems
|
||||
/// <summary>0x1FE, 0xAA55</summary>
|
||||
public ushort signature2;
|
||||
}
|
||||
|
||||
public override Errno Mount()
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno Mount(bool debug)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno Unmount()
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno MapBlock(string path, long fileBlock, ref long deviceBlock)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno GetAttributes(string path, ref FileAttributes attributes)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno ListXAttr(string path, ref List<string> xattrs)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno GetXattr(string path, string xattr, ref byte[] buf)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno Read(string path, long offset, long size, ref byte[] buf)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno ReadDir(string path, ref List<string> contents)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno StatFs(ref FileSystemInfo stat)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno Stat(string path, ref FileEntryInfo stat)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno ReadLink(string path, ref string dest)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -79,8 +79,7 @@ namespace DiscImageChef.Filesystems
|
||||
return magicGc == 0xC2339F3D || magicWii == 0x5D1C9EA3;
|
||||
}
|
||||
|
||||
public override void GetInformation(ImagePlugin imagePlugin, Partition partition,
|
||||
out string information)
|
||||
public override void GetInformation(ImagePlugin imagePlugin, Partition partition, out string information)
|
||||
{
|
||||
StringBuilder sbInformation = new StringBuilder();
|
||||
information = "";
|
||||
@@ -96,10 +95,8 @@ namespace DiscImageChef.Filesystems
|
||||
uint magicGc = BigEndianBitConverter.ToUInt32(header, 0x1C);
|
||||
uint magicWii = BigEndianBitConverter.ToUInt32(header, 0x18);
|
||||
|
||||
if(magicWii == 0x5D1C9EA3)
|
||||
wii = true;
|
||||
else if(magicGc != 0xC2339F3D)
|
||||
return;
|
||||
if(magicWii == 0x5D1C9EA3) wii = true;
|
||||
else if(magicGc != 0xC2339F3D) return;
|
||||
|
||||
fields.DiscType = Encoding.ASCII.GetString(header, 0, 1);
|
||||
fields.GameCode = Encoding.ASCII.GetString(header, 1, 2);
|
||||
@@ -314,46 +311,6 @@ namespace DiscImageChef.Filesystems
|
||||
XmlFsType.VolumeSerial = fields.DiscId;
|
||||
}
|
||||
|
||||
struct NintendoFields
|
||||
{
|
||||
public string DiscType;
|
||||
public string GameCode;
|
||||
public string RegionCode;
|
||||
public string PublisherCode;
|
||||
public string DiscId;
|
||||
public byte DiscNumber;
|
||||
public byte DiscVersion;
|
||||
public bool Streaming;
|
||||
public byte StreamBufferSize;
|
||||
public string Title;
|
||||
public uint DebugOff;
|
||||
public uint DebugAddr;
|
||||
public uint DolOff;
|
||||
public uint FstOff;
|
||||
public uint FstSize;
|
||||
public uint FstMax;
|
||||
public NintendoPartition[] FirstPartitions;
|
||||
public NintendoPartition[] SecondPartitions;
|
||||
public NintendoPartition[] ThirdPartitions;
|
||||
public NintendoPartition[] FourthPartitions;
|
||||
public byte Region;
|
||||
public byte JapanAge;
|
||||
public byte UsaAge;
|
||||
public byte GermanAge;
|
||||
public byte PegiAge;
|
||||
public byte FinlandAge;
|
||||
public byte PortugalAge;
|
||||
public byte UkAge;
|
||||
public byte AustraliaAge;
|
||||
public byte KoreaAge;
|
||||
}
|
||||
|
||||
struct NintendoPartition
|
||||
{
|
||||
public uint Offset;
|
||||
public uint Type;
|
||||
}
|
||||
|
||||
static string DiscTypeToString(string discType)
|
||||
{
|
||||
switch(discType)
|
||||
@@ -510,5 +467,45 @@ namespace DiscImageChef.Filesystems
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
struct NintendoFields
|
||||
{
|
||||
public string DiscType;
|
||||
public string GameCode;
|
||||
public string RegionCode;
|
||||
public string PublisherCode;
|
||||
public string DiscId;
|
||||
public byte DiscNumber;
|
||||
public byte DiscVersion;
|
||||
public bool Streaming;
|
||||
public byte StreamBufferSize;
|
||||
public string Title;
|
||||
public uint DebugOff;
|
||||
public uint DebugAddr;
|
||||
public uint DolOff;
|
||||
public uint FstOff;
|
||||
public uint FstSize;
|
||||
public uint FstMax;
|
||||
public NintendoPartition[] FirstPartitions;
|
||||
public NintendoPartition[] SecondPartitions;
|
||||
public NintendoPartition[] ThirdPartitions;
|
||||
public NintendoPartition[] FourthPartitions;
|
||||
public byte Region;
|
||||
public byte JapanAge;
|
||||
public byte UsaAge;
|
||||
public byte GermanAge;
|
||||
public byte PegiAge;
|
||||
public byte FinlandAge;
|
||||
public byte PortugalAge;
|
||||
public byte UkAge;
|
||||
public byte AustraliaAge;
|
||||
public byte KoreaAge;
|
||||
}
|
||||
|
||||
struct NintendoPartition
|
||||
{
|
||||
public uint Offset;
|
||||
public uint Type;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -104,8 +104,7 @@ namespace DiscImageChef.Filesystems
|
||||
return magic == "DECFILE11A " || magic == "DECFILE11B ";
|
||||
}
|
||||
|
||||
public override void GetInformation(ImagePlugin imagePlugin, Partition partition,
|
||||
out string information)
|
||||
public override void GetInformation(ImagePlugin imagePlugin, Partition partition, out string information)
|
||||
{
|
||||
information = "";
|
||||
|
||||
@@ -114,7 +113,8 @@ namespace DiscImageChef.Filesystems
|
||||
byte[] hbSector = imagePlugin.ReadSector(1 + partition.Start);
|
||||
|
||||
GCHandle handle = GCHandle.Alloc(hbSector, GCHandleType.Pinned);
|
||||
OdsHomeBlock homeblock = (OdsHomeBlock)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(OdsHomeBlock));
|
||||
OdsHomeBlock homeblock =
|
||||
(OdsHomeBlock)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(OdsHomeBlock));
|
||||
handle.Free();
|
||||
|
||||
// Optical disc
|
||||
@@ -241,6 +241,66 @@ namespace DiscImageChef.Filesystems
|
||||
information = sb.ToString();
|
||||
}
|
||||
|
||||
public override Errno Mount()
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno Mount(bool debug)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno Unmount()
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno MapBlock(string path, long fileBlock, ref long deviceBlock)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno GetAttributes(string path, ref FileAttributes attributes)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno ListXAttr(string path, ref List<string> xattrs)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno GetXattr(string path, string xattr, ref byte[] buf)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno Read(string path, long offset, long size, ref byte[] buf)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno ReadDir(string path, ref List<string> contents)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno StatFs(ref FileSystemInfo stat)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno Stat(string path, ref FileEntryInfo stat)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno ReadLink(string path, ref string dest)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct OdsHomeBlock
|
||||
{
|
||||
@@ -337,65 +397,5 @@ namespace DiscImageChef.Filesystems
|
||||
/// <summary>0x1FE, Checksum of preceding 255 words (16 bit units)</summary>
|
||||
public ushort checksum2;
|
||||
}
|
||||
|
||||
public override Errno Mount()
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno Mount(bool debug)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno Unmount()
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno MapBlock(string path, long fileBlock, ref long deviceBlock)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno GetAttributes(string path, ref FileAttributes attributes)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno ListXAttr(string path, ref List<string> xattrs)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno GetXattr(string path, string xattr, ref byte[] buf)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno Read(string path, long offset, long size, ref byte[] buf)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno ReadDir(string path, ref List<string> contents)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno StatFs(ref FileSystemInfo stat)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno Stat(string path, ref FileEntryInfo stat)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno ReadLink(string path, ref string dest)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -82,8 +82,7 @@ namespace DiscImageChef.Filesystems
|
||||
return Encoding.ASCII.GetString(syncBytes) == "ZZZZZ";
|
||||
}
|
||||
|
||||
public override void GetInformation(ImagePlugin imagePlugin, Partition partition,
|
||||
out string information)
|
||||
public override void GetInformation(ImagePlugin imagePlugin, Partition partition, out string information)
|
||||
{
|
||||
information = "";
|
||||
StringBuilder superBlockMetadata = new StringBuilder();
|
||||
@@ -143,37 +142,6 @@ namespace DiscImageChef.Filesystems
|
||||
};
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct OperaSuperBlock
|
||||
{
|
||||
/// <summary>0x000, Record type, must be 1</summary>
|
||||
public byte record_type;
|
||||
/// <summary>0x001, 5 bytes, "ZZZZZ"</summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)] public byte[] sync_bytes;
|
||||
/// <summary>0x006, Record version, must be 1</summary>
|
||||
public byte record_version;
|
||||
/// <summary>0x007, Volume flags</summary>
|
||||
public byte volume_flags;
|
||||
/// <summary>0x008, 32 bytes, volume comment</summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] public byte[] volume_comment;
|
||||
/// <summary>0x028, 32 bytes, volume label</summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] public byte[] volume_label;
|
||||
/// <summary>0x048, Volume ID</summary>
|
||||
public int volume_id;
|
||||
/// <summary>0x04C, Block size in bytes</summary>
|
||||
public int block_size;
|
||||
/// <summary>0x050, Blocks in volume</summary>
|
||||
public int block_count;
|
||||
/// <summary>0x054, Root directory ID</summary>
|
||||
public int root_dirid;
|
||||
/// <summary>0x058, Root directory blocks</summary>
|
||||
public int rootdir_blocks;
|
||||
/// <summary>0x05C, Root directory block size</summary>
|
||||
public int rootdir_bsize;
|
||||
/// <summary>0x060, Last root directory copy</summary>
|
||||
public int last_root_copy;
|
||||
}
|
||||
|
||||
public override Errno Mount()
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
@@ -233,5 +201,36 @@ namespace DiscImageChef.Filesystems
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct OperaSuperBlock
|
||||
{
|
||||
/// <summary>0x000, Record type, must be 1</summary>
|
||||
public byte record_type;
|
||||
/// <summary>0x001, 5 bytes, "ZZZZZ"</summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)] public byte[] sync_bytes;
|
||||
/// <summary>0x006, Record version, must be 1</summary>
|
||||
public byte record_version;
|
||||
/// <summary>0x007, Volume flags</summary>
|
||||
public byte volume_flags;
|
||||
/// <summary>0x008, 32 bytes, volume comment</summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] public byte[] volume_comment;
|
||||
/// <summary>0x028, 32 bytes, volume label</summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] public byte[] volume_label;
|
||||
/// <summary>0x048, Volume ID</summary>
|
||||
public int volume_id;
|
||||
/// <summary>0x04C, Block size in bytes</summary>
|
||||
public int block_size;
|
||||
/// <summary>0x050, Blocks in volume</summary>
|
||||
public int block_count;
|
||||
/// <summary>0x054, Root directory ID</summary>
|
||||
public int root_dirid;
|
||||
/// <summary>0x058, Root directory blocks</summary>
|
||||
public int rootdir_blocks;
|
||||
/// <summary>0x05C, Root directory block size</summary>
|
||||
public int rootdir_bsize;
|
||||
/// <summary>0x060, Last root directory copy</summary>
|
||||
public int last_root_copy;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -74,8 +74,7 @@ namespace DiscImageChef.Filesystems
|
||||
return Encoding.ASCII.GetString(systemDescriptor) == "PC Engine CD-ROM SYSTEM";
|
||||
}
|
||||
|
||||
public override void GetInformation(ImagePlugin imagePlugin, Partition partition,
|
||||
out string information)
|
||||
public override void GetInformation(ImagePlugin imagePlugin, Partition partition, out string information)
|
||||
{
|
||||
information = "";
|
||||
XmlFsType = new FileSystemType
|
||||
|
||||
@@ -42,6 +42,27 @@ namespace DiscImageChef.Filesystems
|
||||
{
|
||||
public class PFS : Filesystem
|
||||
{
|
||||
/// <summary>
|
||||
/// Identifier for AFS (PFS v1)
|
||||
/// </summary>
|
||||
const uint AFS_DISK = 0x41465301;
|
||||
/// <summary>
|
||||
/// Identifier for PFS v2
|
||||
/// </summary>
|
||||
const uint PFS2_DISK = 0x50465302;
|
||||
/// <summary>
|
||||
/// Identifier for PFS v3
|
||||
/// </summary>
|
||||
const uint PFS_DISK = 0x50465301;
|
||||
/// <summary>
|
||||
/// Identifier for multi-user AFS
|
||||
/// </summary>
|
||||
const uint MUAF_DISK = 0x6D754146;
|
||||
/// <summary>
|
||||
/// Identifier for multi-user PFS
|
||||
/// </summary>
|
||||
const uint MUPFS_DISK = 0x6D755046;
|
||||
|
||||
public PFS()
|
||||
{
|
||||
Name = "Professional File System";
|
||||
@@ -63,128 +84,6 @@ namespace DiscImageChef.Filesystems
|
||||
CurrentEncoding = encoding ?? Encoding.GetEncoding("iso-8859-1");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Boot block, first 2 sectors
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct BootBlock
|
||||
{
|
||||
/// <summary>
|
||||
/// "PFS\1" disk type
|
||||
/// </summary>
|
||||
public uint diskType;
|
||||
/// <summary>
|
||||
/// Boot code, til completion
|
||||
/// </summary>
|
||||
public byte[] bootCode;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct RootBlock
|
||||
{
|
||||
/// <summary>
|
||||
/// Disk type
|
||||
/// </summary>
|
||||
public uint diskType;
|
||||
/// <summary>
|
||||
/// Options
|
||||
/// </summary>
|
||||
public uint options;
|
||||
/// <summary>
|
||||
/// Current datestamp
|
||||
/// </summary>
|
||||
public uint datestamp;
|
||||
/// <summary>
|
||||
/// Volume creation day
|
||||
/// </summary>
|
||||
public ushort creationday;
|
||||
/// <summary>
|
||||
/// Volume creation minute
|
||||
/// </summary>
|
||||
public ushort creationminute;
|
||||
/// <summary>
|
||||
/// Volume creation tick
|
||||
/// </summary>
|
||||
public ushort creationtick;
|
||||
/// <summary>
|
||||
/// AmigaDOS protection bits
|
||||
/// </summary>
|
||||
public ushort protection;
|
||||
/// <summary>
|
||||
/// Volume label (Pascal string)
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] public byte[] diskname;
|
||||
/// <summary>
|
||||
/// Last reserved block
|
||||
/// </summary>
|
||||
public uint lastreserved;
|
||||
/// <summary>
|
||||
/// First reserved block
|
||||
/// </summary>
|
||||
public uint firstreserved;
|
||||
/// <summary>
|
||||
/// Free reserved blocks
|
||||
/// </summary>
|
||||
public uint reservedfree;
|
||||
/// <summary>
|
||||
/// Size of reserved blocks in bytes
|
||||
/// </summary>
|
||||
public ushort reservedblocksize;
|
||||
/// <summary>
|
||||
/// Blocks in rootblock, including bitmap
|
||||
/// </summary>
|
||||
public ushort rootblockclusters;
|
||||
/// <summary>
|
||||
/// Free blocks
|
||||
/// </summary>
|
||||
public uint blocksfree;
|
||||
/// <summary>
|
||||
/// Blocks that must be always free
|
||||
/// </summary>
|
||||
public uint alwaysfree;
|
||||
/// <summary>
|
||||
/// Current bitmapfield number for allocation
|
||||
/// </summary>
|
||||
public uint rovingPointer;
|
||||
/// <summary>
|
||||
/// Pointer to deldir
|
||||
/// </summary>
|
||||
public uint delDirPtr;
|
||||
/// <summary>
|
||||
/// Disk size in sectors
|
||||
/// </summary>
|
||||
public uint diskSize;
|
||||
/// <summary>
|
||||
/// Rootblock extension
|
||||
/// </summary>
|
||||
public uint extension;
|
||||
/// <summary>
|
||||
/// Unused
|
||||
/// </summary>
|
||||
public uint unused;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Identifier for AFS (PFS v1)
|
||||
/// </summary>
|
||||
const uint AFS_DISK = 0x41465301;
|
||||
/// <summary>
|
||||
/// Identifier for PFS v2
|
||||
/// </summary>
|
||||
const uint PFS2_DISK = 0x50465302;
|
||||
/// <summary>
|
||||
/// Identifier for PFS v3
|
||||
/// </summary>
|
||||
const uint PFS_DISK = 0x50465301;
|
||||
/// <summary>
|
||||
/// Identifier for multi-user AFS
|
||||
/// </summary>
|
||||
const uint MUAF_DISK = 0x6D754146;
|
||||
/// <summary>
|
||||
/// Identifier for multi-user PFS
|
||||
/// </summary>
|
||||
const uint MUPFS_DISK = 0x6D755046;
|
||||
|
||||
public override bool Identify(ImagePlugin imagePlugin, Partition partition)
|
||||
{
|
||||
if(partition.Length < 3) return false;
|
||||
@@ -199,8 +98,7 @@ namespace DiscImageChef.Filesystems
|
||||
magic == MUPFS_DISK;
|
||||
}
|
||||
|
||||
public override void GetInformation(ImagePlugin imagePlugin, Partition partition,
|
||||
out string information)
|
||||
public override void GetInformation(ImagePlugin imagePlugin, Partition partition, out string information)
|
||||
{
|
||||
byte[] rootBlockSector = imagePlugin.ReadSector(2 + partition.Start);
|
||||
RootBlock rootBlock = BigEndianMarshal.ByteArrayToStructureBigEndian<RootBlock>(rootBlockSector);
|
||||
@@ -314,5 +212,106 @@ namespace DiscImageChef.Filesystems
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Boot block, first 2 sectors
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct BootBlock
|
||||
{
|
||||
/// <summary>
|
||||
/// "PFS\1" disk type
|
||||
/// </summary>
|
||||
public uint diskType;
|
||||
/// <summary>
|
||||
/// Boot code, til completion
|
||||
/// </summary>
|
||||
public byte[] bootCode;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct RootBlock
|
||||
{
|
||||
/// <summary>
|
||||
/// Disk type
|
||||
/// </summary>
|
||||
public uint diskType;
|
||||
/// <summary>
|
||||
/// Options
|
||||
/// </summary>
|
||||
public uint options;
|
||||
/// <summary>
|
||||
/// Current datestamp
|
||||
/// </summary>
|
||||
public uint datestamp;
|
||||
/// <summary>
|
||||
/// Volume creation day
|
||||
/// </summary>
|
||||
public ushort creationday;
|
||||
/// <summary>
|
||||
/// Volume creation minute
|
||||
/// </summary>
|
||||
public ushort creationminute;
|
||||
/// <summary>
|
||||
/// Volume creation tick
|
||||
/// </summary>
|
||||
public ushort creationtick;
|
||||
/// <summary>
|
||||
/// AmigaDOS protection bits
|
||||
/// </summary>
|
||||
public ushort protection;
|
||||
/// <summary>
|
||||
/// Volume label (Pascal string)
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] public byte[] diskname;
|
||||
/// <summary>
|
||||
/// Last reserved block
|
||||
/// </summary>
|
||||
public uint lastreserved;
|
||||
/// <summary>
|
||||
/// First reserved block
|
||||
/// </summary>
|
||||
public uint firstreserved;
|
||||
/// <summary>
|
||||
/// Free reserved blocks
|
||||
/// </summary>
|
||||
public uint reservedfree;
|
||||
/// <summary>
|
||||
/// Size of reserved blocks in bytes
|
||||
/// </summary>
|
||||
public ushort reservedblocksize;
|
||||
/// <summary>
|
||||
/// Blocks in rootblock, including bitmap
|
||||
/// </summary>
|
||||
public ushort rootblockclusters;
|
||||
/// <summary>
|
||||
/// Free blocks
|
||||
/// </summary>
|
||||
public uint blocksfree;
|
||||
/// <summary>
|
||||
/// Blocks that must be always free
|
||||
/// </summary>
|
||||
public uint alwaysfree;
|
||||
/// <summary>
|
||||
/// Current bitmapfield number for allocation
|
||||
/// </summary>
|
||||
public uint rovingPointer;
|
||||
/// <summary>
|
||||
/// Pointer to deldir
|
||||
/// </summary>
|
||||
public uint delDirPtr;
|
||||
/// <summary>
|
||||
/// Disk size in sectors
|
||||
/// </summary>
|
||||
public uint diskSize;
|
||||
/// <summary>
|
||||
/// Rootblock extension
|
||||
/// </summary>
|
||||
public uint extension;
|
||||
/// <summary>
|
||||
/// Unused
|
||||
/// </summary>
|
||||
public uint unused;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -48,15 +48,15 @@ namespace DiscImageChef.Filesystems
|
||||
{
|
||||
const byte EMPTY_STORAGE_TYPE = 0x00;
|
||||
/// <summary>
|
||||
/// A file that occupies one block or less
|
||||
/// A file that occupies one block or less
|
||||
/// </summary>
|
||||
const byte SEEDLING_FILE_TYPE = 0x01;
|
||||
/// <summary>
|
||||
/// A file that occupies between 2 and 256 blocks
|
||||
/// A file that occupies between 2 and 256 blocks
|
||||
/// </summary>
|
||||
const byte SAPLING_FILE_TYPE = 0x02;
|
||||
/// <summary>
|
||||
/// A file that occupies between 257 and 32768 blocks
|
||||
/// A file that occupies between 257 and 32768 blocks
|
||||
/// </summary>
|
||||
const byte TREE_FILE_TYPE = 0x03;
|
||||
const byte PASCAL_AREA_TYPE = 0x04;
|
||||
@@ -120,9 +120,21 @@ namespace DiscImageChef.Filesystems
|
||||
{
|
||||
byte[] tmp = imagePlugin.ReadSectors(partition.Start, 2);
|
||||
|
||||
foreach(int offset in new[] {0, 0x200, 0x400, 0x600, 0x800, 0xA00}.Where(offset => BitConverter.ToUInt16(tmp, offset) == 0 &&
|
||||
(byte)((tmp[offset + 0x04] & STORAGE_TYPE_MASK) >> 4) == ROOT_DIRECTORY_TYPE &&
|
||||
tmp[offset + 0x23] == ENTRY_LENGTH && tmp[offset + 0x24] == ENTRIES_PER_BLOCK)) {
|
||||
foreach(int offset in new[] {0, 0x200, 0x400, 0x600, 0x800, 0xA00}.Where(offset =>
|
||||
BitConverter
|
||||
.ToUInt16(tmp,
|
||||
offset) ==
|
||||
0 &&
|
||||
(byte)
|
||||
((tmp[offset + 0x04] &
|
||||
STORAGE_TYPE_MASK) >>
|
||||
4) ==
|
||||
ROOT_DIRECTORY_TYPE &&
|
||||
tmp[offset + 0x23] ==
|
||||
ENTRY_LENGTH &&
|
||||
tmp[offset + 0x24] ==
|
||||
ENTRIES_PER_BLOCK))
|
||||
{
|
||||
Array.Copy(tmp, offset, rootDirectoryKeyBlock, 0, 0x200);
|
||||
APMFromHDDOnCD = true;
|
||||
break;
|
||||
@@ -157,8 +169,7 @@ namespace DiscImageChef.Filesystems
|
||||
return totalBlocks <= partition.End - partition.Start + 1;
|
||||
}
|
||||
|
||||
public override void GetInformation(ImagePlugin imagePlugin, Partition partition,
|
||||
out string information)
|
||||
public override void GetInformation(ImagePlugin imagePlugin, Partition partition, out string information)
|
||||
{
|
||||
StringBuilder sbInformation = new StringBuilder();
|
||||
|
||||
@@ -172,9 +183,21 @@ namespace DiscImageChef.Filesystems
|
||||
{
|
||||
byte[] tmp = imagePlugin.ReadSectors(partition.Start, 2);
|
||||
|
||||
foreach(int offset in new[] {0, 0x200, 0x400, 0x600, 0x800, 0xA00}.Where(offset => BitConverter.ToUInt16(tmp, offset) == 0 &&
|
||||
(byte)((tmp[offset + 0x04] & STORAGE_TYPE_MASK) >> 4) == ROOT_DIRECTORY_TYPE &&
|
||||
tmp[offset + 0x23] == ENTRY_LENGTH && tmp[offset + 0x24] == ENTRIES_PER_BLOCK)) {
|
||||
foreach(int offset in new[] {0, 0x200, 0x400, 0x600, 0x800, 0xA00}.Where(offset =>
|
||||
BitConverter
|
||||
.ToUInt16(tmp,
|
||||
offset) ==
|
||||
0 &&
|
||||
(byte)
|
||||
((tmp[offset + 0x04] &
|
||||
STORAGE_TYPE_MASK) >>
|
||||
4) ==
|
||||
ROOT_DIRECTORY_TYPE &&
|
||||
tmp[offset + 0x23] ==
|
||||
ENTRY_LENGTH &&
|
||||
tmp[offset + 0x24] ==
|
||||
ENTRIES_PER_BLOCK))
|
||||
{
|
||||
Array.Copy(tmp, offset, rootDirectoryKeyBlockBytes, 0, 0x200);
|
||||
APMFromHDDOnCD = true;
|
||||
break;
|
||||
@@ -235,8 +258,7 @@ namespace DiscImageChef.Filesystems
|
||||
sbInformation.AppendLine("ProDOS uses 512 bytes/sector while devices uses 2048 bytes/sector.")
|
||||
.AppendLine();
|
||||
|
||||
if(rootDirectoryKeyBlock.header.version != VERSION1 ||
|
||||
rootDirectoryKeyBlock.header.min_version != VERSION1)
|
||||
if(rootDirectoryKeyBlock.header.version != VERSION1 || rootDirectoryKeyBlock.header.min_version != VERSION1)
|
||||
{
|
||||
sbInformation.AppendLine("Warning! Detected unknown ProDOS version ProDOS filesystem.");
|
||||
sbInformation.AppendLine("All of the following information may be incorrect");
|
||||
@@ -363,80 +385,80 @@ namespace DiscImageChef.Filesystems
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// ProDOS directory entry, decoded structure
|
||||
/// ProDOS directory entry, decoded structure
|
||||
/// </summary>
|
||||
struct ProDOSEntry
|
||||
{
|
||||
/// <summary>
|
||||
/// Type of file pointed by this entry
|
||||
/// Offset 0x00, mask 0xF0
|
||||
/// Type of file pointed by this entry
|
||||
/// Offset 0x00, mask 0xF0
|
||||
/// </summary>
|
||||
public byte storage_type;
|
||||
/// <summary>
|
||||
/// Length of name_length pascal string
|
||||
/// Offset 0x00, mask 0x0F
|
||||
/// Length of name_length pascal string
|
||||
/// Offset 0x00, mask 0x0F
|
||||
/// </summary>
|
||||
public byte name_length;
|
||||
/// <summary>
|
||||
/// Pascal string of file name
|
||||
/// Offset 0x01, 15 bytes
|
||||
/// Pascal string of file name
|
||||
/// Offset 0x01, 15 bytes
|
||||
/// </summary>
|
||||
public string file_name;
|
||||
/// <summary>
|
||||
/// Descriptor of internal structure of the file
|
||||
/// Offset 0x10, 1 byte
|
||||
/// Descriptor of internal structure of the file
|
||||
/// Offset 0x10, 1 byte
|
||||
/// </summary>
|
||||
public byte file_type;
|
||||
/// <summary>
|
||||
/// Block address of master index block for tree files.
|
||||
/// Block address of index block for sapling files.
|
||||
/// Block address of block for seedling files.
|
||||
/// Offset 0x11, 2 bytes
|
||||
/// Block address of master index block for tree files.
|
||||
/// Block address of index block for sapling files.
|
||||
/// Block address of block for seedling files.
|
||||
/// Offset 0x11, 2 bytes
|
||||
/// </summary>
|
||||
public ushort key_pointer;
|
||||
/// <summary>
|
||||
/// Blocks used by file or directory, including index blocks.
|
||||
/// Offset 0x13, 2 bytes
|
||||
/// Blocks used by file or directory, including index blocks.
|
||||
/// Offset 0x13, 2 bytes
|
||||
/// </summary>
|
||||
public ushort blocks_used;
|
||||
/// <summary>
|
||||
/// Size of file in bytes
|
||||
/// Offset 0x15, 3 bytes
|
||||
/// Size of file in bytes
|
||||
/// Offset 0x15, 3 bytes
|
||||
/// </summary>
|
||||
public uint EOF;
|
||||
/// <summary>
|
||||
/// File creation datetime
|
||||
/// Offset 0x18, 4 bytes
|
||||
/// File creation datetime
|
||||
/// Offset 0x18, 4 bytes
|
||||
/// </summary>
|
||||
public DateTime creation_time;
|
||||
/// <summary>
|
||||
/// Version of ProDOS that created this file
|
||||
/// Offset 0x1C, 1 byte
|
||||
/// Version of ProDOS that created this file
|
||||
/// Offset 0x1C, 1 byte
|
||||
/// </summary>
|
||||
public byte version;
|
||||
/// <summary>
|
||||
/// Minimum version of ProDOS needed to access this file
|
||||
/// Offset 0x1D, 1 byte
|
||||
/// Minimum version of ProDOS needed to access this file
|
||||
/// Offset 0x1D, 1 byte
|
||||
/// </summary>
|
||||
public byte min_version;
|
||||
/// <summary>
|
||||
/// File permissions
|
||||
/// Offset 0x1E, 1 byte
|
||||
/// File permissions
|
||||
/// Offset 0x1E, 1 byte
|
||||
/// </summary>
|
||||
public byte access;
|
||||
/// <summary>
|
||||
/// General purpose field to store additional information about file format
|
||||
/// Offset 0x1F, 2 bytes
|
||||
/// General purpose field to store additional information about file format
|
||||
/// Offset 0x1F, 2 bytes
|
||||
/// </summary>
|
||||
public ushort aux_type;
|
||||
/// <summary>
|
||||
/// File last modification date time
|
||||
/// Offset 0x21, 4 bytes
|
||||
/// File last modification date time
|
||||
/// Offset 0x21, 4 bytes
|
||||
/// </summary>
|
||||
public DateTime last_mod;
|
||||
/// <summary>
|
||||
/// Block address pointer to key block of the directory containing this entry
|
||||
/// Offset 0x25, 2 bytes
|
||||
/// Block address pointer to key block of the directory containing this entry
|
||||
/// Offset 0x25, 2 bytes
|
||||
/// </summary>
|
||||
public ushort header_pointer;
|
||||
}
|
||||
@@ -444,71 +466,71 @@ namespace DiscImageChef.Filesystems
|
||||
struct ProDOSRootDirectoryHeader
|
||||
{
|
||||
/// <summary>
|
||||
/// Constant 0x0F
|
||||
/// Offset 0x04, mask 0xF0
|
||||
/// Constant 0x0F
|
||||
/// Offset 0x04, mask 0xF0
|
||||
/// </summary>
|
||||
public byte storage_type;
|
||||
/// <summary>
|
||||
/// Length of volume_name pascal string
|
||||
/// Offset 0x04, mask 0x0F
|
||||
/// Length of volume_name pascal string
|
||||
/// Offset 0x04, mask 0x0F
|
||||
/// </summary>
|
||||
public byte name_length;
|
||||
/// <summary>
|
||||
/// The name of the volume.
|
||||
/// Offset 0x05, 15 bytes
|
||||
/// The name of the volume.
|
||||
/// Offset 0x05, 15 bytes
|
||||
/// </summary>
|
||||
public string volume_name;
|
||||
/// <summary>
|
||||
/// Reserved for future expansion
|
||||
/// Offset 0x14, 8 bytes
|
||||
/// Reserved for future expansion
|
||||
/// Offset 0x14, 8 bytes
|
||||
/// </summary>
|
||||
public ulong reserved;
|
||||
/// <summary>
|
||||
/// Creation time of the volume
|
||||
/// Offset 0x1C, 4 bytes
|
||||
/// Creation time of the volume
|
||||
/// Offset 0x1C, 4 bytes
|
||||
/// </summary>
|
||||
public DateTime creation_time;
|
||||
/// <summary>
|
||||
/// Version number of the volume format
|
||||
/// Offset 0x20, 1 byte
|
||||
/// Version number of the volume format
|
||||
/// Offset 0x20, 1 byte
|
||||
/// </summary>
|
||||
public byte version;
|
||||
/// <summary>
|
||||
/// Reserved for future use
|
||||
/// Offset 0x21, 1 byte
|
||||
/// Reserved for future use
|
||||
/// Offset 0x21, 1 byte
|
||||
/// </summary>
|
||||
public byte min_version;
|
||||
/// <summary>
|
||||
/// Permissions for the volume
|
||||
/// Offset 0x22, 1 byte
|
||||
/// Permissions for the volume
|
||||
/// Offset 0x22, 1 byte
|
||||
/// </summary>
|
||||
public byte access;
|
||||
/// <summary>
|
||||
/// Length of an entry in this directory
|
||||
/// Const 0x27
|
||||
/// Offset 0x23, 1 byte
|
||||
/// Length of an entry in this directory
|
||||
/// Const 0x27
|
||||
/// Offset 0x23, 1 byte
|
||||
/// </summary>
|
||||
public byte entry_length;
|
||||
/// <summary>
|
||||
/// Number of entries per block
|
||||
/// Const 0x0D
|
||||
/// Offset 0x24, 1 byte
|
||||
/// Number of entries per block
|
||||
/// Const 0x0D
|
||||
/// Offset 0x24, 1 byte
|
||||
/// </summary>
|
||||
public byte entries_per_block;
|
||||
/// <summary>
|
||||
/// Number of active files in this directory
|
||||
/// Offset 0x25, 2 bytes
|
||||
/// Number of active files in this directory
|
||||
/// Offset 0x25, 2 bytes
|
||||
/// </summary>
|
||||
public ushort file_count;
|
||||
/// <summary>
|
||||
/// Block address of the first block of the volume's bitmap,
|
||||
/// one for every 4096 blocks or fraction
|
||||
/// Offset 0x27, 2 bytes
|
||||
/// Block address of the first block of the volume's bitmap,
|
||||
/// one for every 4096 blocks or fraction
|
||||
/// Offset 0x27, 2 bytes
|
||||
/// </summary>
|
||||
public ushort bit_map_pointer;
|
||||
/// <summary>
|
||||
/// Total number of blocks in the volume
|
||||
/// Offset 0x29, 2 bytes
|
||||
/// Total number of blocks in the volume
|
||||
/// Offset 0x29, 2 bytes
|
||||
/// </summary>
|
||||
public ushort total_blocks;
|
||||
}
|
||||
@@ -516,76 +538,76 @@ namespace DiscImageChef.Filesystems
|
||||
struct ProDOSDirectoryHeader
|
||||
{
|
||||
/// <summary>
|
||||
/// Constant 0x0E
|
||||
/// Offset 0x04, mask 0xF0
|
||||
/// Constant 0x0E
|
||||
/// Offset 0x04, mask 0xF0
|
||||
/// </summary>
|
||||
public byte storage_type;
|
||||
/// <summary>
|
||||
/// Length of volume_name pascal string
|
||||
/// Offset 0x04, mask 0x0F
|
||||
/// Length of volume_name pascal string
|
||||
/// Offset 0x04, mask 0x0F
|
||||
/// </summary>
|
||||
public byte name_length;
|
||||
/// <summary>
|
||||
/// The name of the directory.
|
||||
/// Offset 0x05, 15 bytes
|
||||
/// The name of the directory.
|
||||
/// Offset 0x05, 15 bytes
|
||||
/// </summary>
|
||||
public string directory_name;
|
||||
/// <summary>
|
||||
/// Reserved for future expansion
|
||||
/// Offset 0x14, 8 bytes
|
||||
/// Reserved for future expansion
|
||||
/// Offset 0x14, 8 bytes
|
||||
/// </summary>
|
||||
public ulong reserved;
|
||||
/// <summary>
|
||||
/// Creation time of the volume
|
||||
/// Offset 0x1C, 4 bytes
|
||||
/// Creation time of the volume
|
||||
/// Offset 0x1C, 4 bytes
|
||||
/// </summary>
|
||||
public DateTime creation_time;
|
||||
/// <summary>
|
||||
/// Version number of the volume format
|
||||
/// Offset 0x20, 1 byte
|
||||
/// Version number of the volume format
|
||||
/// Offset 0x20, 1 byte
|
||||
/// </summary>
|
||||
public byte version;
|
||||
/// <summary>
|
||||
/// Reserved for future use
|
||||
/// Offset 0x21, 1 byte
|
||||
/// Reserved for future use
|
||||
/// Offset 0x21, 1 byte
|
||||
/// </summary>
|
||||
public byte min_version;
|
||||
/// <summary>
|
||||
/// Permissions for the volume
|
||||
/// Offset 0x22, 1 byte
|
||||
/// Permissions for the volume
|
||||
/// Offset 0x22, 1 byte
|
||||
/// </summary>
|
||||
public byte access;
|
||||
/// <summary>
|
||||
/// Length of an entry in this directory
|
||||
/// Const 0x27
|
||||
/// Offset 0x23, 1 byte
|
||||
/// Length of an entry in this directory
|
||||
/// Const 0x27
|
||||
/// Offset 0x23, 1 byte
|
||||
/// </summary>
|
||||
public byte entry_length;
|
||||
/// <summary>
|
||||
/// Number of entries per block
|
||||
/// Const 0x0D
|
||||
/// Offset 0x24, 1 byte
|
||||
/// Number of entries per block
|
||||
/// Const 0x0D
|
||||
/// Offset 0x24, 1 byte
|
||||
/// </summary>
|
||||
public byte entries_per_block;
|
||||
/// <summary>
|
||||
/// Number of active files in this directory
|
||||
/// Offset 0x25, 2 bytes
|
||||
/// Number of active files in this directory
|
||||
/// Offset 0x25, 2 bytes
|
||||
/// </summary>
|
||||
public ushort file_count;
|
||||
/// <summary>
|
||||
/// Block address of parent directory block that contains this entry
|
||||
/// Offset 0x27, 2 bytes
|
||||
/// Block address of parent directory block that contains this entry
|
||||
/// Offset 0x27, 2 bytes
|
||||
/// </summary>
|
||||
public ushort parent_pointer;
|
||||
/// <summary>
|
||||
/// Entry number within the block indicated in parent_pointer
|
||||
/// Offset 0x29, 1 byte
|
||||
/// Entry number within the block indicated in parent_pointer
|
||||
/// Offset 0x29, 1 byte
|
||||
/// </summary>
|
||||
public byte parent_entry_number;
|
||||
/// <summary>
|
||||
/// Length of the entry that holds this directory, in the parent entry
|
||||
/// Const 0x27
|
||||
/// Offset 0x2A, 1 byte
|
||||
/// Length of the entry that holds this directory, in the parent entry
|
||||
/// Const 0x27
|
||||
/// Offset 0x2A, 1 byte
|
||||
/// </summary>
|
||||
public byte parent_entry_length;
|
||||
}
|
||||
@@ -593,23 +615,23 @@ namespace DiscImageChef.Filesystems
|
||||
struct ProDOSDirectoryKeyBlock
|
||||
{
|
||||
/// <summary>
|
||||
/// Always 0
|
||||
/// Offset 0x00, 2 bytes
|
||||
/// Always 0
|
||||
/// Offset 0x00, 2 bytes
|
||||
/// </summary>
|
||||
public ushort zero;
|
||||
/// <summary>
|
||||
/// Pointer to next directory block, 0 if last
|
||||
/// Offset 0x02, 2 bytes
|
||||
/// Pointer to next directory block, 0 if last
|
||||
/// Offset 0x02, 2 bytes
|
||||
/// </summary>
|
||||
public ushort next_pointer;
|
||||
/// <summary>
|
||||
/// Directory header
|
||||
/// Offset 0x04, 39 bytes
|
||||
/// Directory header
|
||||
/// Offset 0x04, 39 bytes
|
||||
/// </summary>
|
||||
public ProDOSDirectoryHeader header;
|
||||
/// <summary>
|
||||
/// Directory entries
|
||||
/// Offset 0x2F, 39 bytes each, 12 entries
|
||||
/// Directory entries
|
||||
/// Offset 0x2F, 39 bytes each, 12 entries
|
||||
/// </summary>
|
||||
public ProDOSEntry[] entries;
|
||||
}
|
||||
@@ -617,23 +639,23 @@ namespace DiscImageChef.Filesystems
|
||||
struct ProDOSRootDirectoryKeyBlock
|
||||
{
|
||||
/// <summary>
|
||||
/// Always 0
|
||||
/// Offset 0x00, 2 bytes
|
||||
/// Always 0
|
||||
/// Offset 0x00, 2 bytes
|
||||
/// </summary>
|
||||
public ushort zero;
|
||||
/// <summary>
|
||||
/// Pointer to next directory block, 0 if last
|
||||
/// Offset 0x02, 2 bytes
|
||||
/// Pointer to next directory block, 0 if last
|
||||
/// Offset 0x02, 2 bytes
|
||||
/// </summary>
|
||||
public ushort next_pointer;
|
||||
/// <summary>
|
||||
/// Directory header
|
||||
/// Offset 0x04, 39 bytes
|
||||
/// Directory header
|
||||
/// Offset 0x04, 39 bytes
|
||||
/// </summary>
|
||||
public ProDOSRootDirectoryHeader header;
|
||||
/// <summary>
|
||||
/// Directory entries
|
||||
/// Offset 0x2F, 39 bytes each, 12 entries
|
||||
/// Directory entries
|
||||
/// Offset 0x2F, 39 bytes each, 12 entries
|
||||
/// </summary>
|
||||
public ProDOSEntry[] entries;
|
||||
}
|
||||
@@ -641,18 +663,18 @@ namespace DiscImageChef.Filesystems
|
||||
struct ProDOSDirectoryBlock
|
||||
{
|
||||
/// <summary>
|
||||
/// Pointer to previous directory block
|
||||
/// Offset 0x00, 2 bytes
|
||||
/// Pointer to previous directory block
|
||||
/// Offset 0x00, 2 bytes
|
||||
/// </summary>
|
||||
public ushort zero;
|
||||
/// <summary>
|
||||
/// Pointer to next directory block, 0 if last
|
||||
/// Offset 0x02, 2 bytes
|
||||
/// Pointer to next directory block, 0 if last
|
||||
/// Offset 0x02, 2 bytes
|
||||
/// </summary>
|
||||
public ushort next_pointer;
|
||||
/// <summary>
|
||||
/// Directory entries
|
||||
/// Offset 0x2F, 39 bytes each, 13 entries
|
||||
/// Directory entries
|
||||
/// Offset 0x2F, 39 bytes each, 13 entries
|
||||
/// </summary>
|
||||
public ProDOSEntry[] entries;
|
||||
}
|
||||
@@ -660,7 +682,7 @@ namespace DiscImageChef.Filesystems
|
||||
struct ProDOSIndexBlock
|
||||
{
|
||||
/// <summary>
|
||||
/// Up to 256 pointers to blocks, 0 to indicate the block is sparsed (non-allocated)
|
||||
/// Up to 256 pointers to blocks, 0 to indicate the block is sparsed (non-allocated)
|
||||
/// </summary>
|
||||
public ushort[] block_pointer;
|
||||
}
|
||||
@@ -668,7 +690,7 @@ namespace DiscImageChef.Filesystems
|
||||
struct ProDOSMasterIndexBlock
|
||||
{
|
||||
/// <summary>
|
||||
/// Up to 128 pointers to index blocks
|
||||
/// Up to 128 pointers to index blocks
|
||||
/// </summary>
|
||||
public ushort[] index_block_pointer;
|
||||
}
|
||||
|
||||
@@ -43,65 +43,6 @@ namespace DiscImageChef.Filesystems
|
||||
{
|
||||
public class QNX4 : Filesystem
|
||||
{
|
||||
struct QNX4_Extent
|
||||
{
|
||||
public uint block;
|
||||
public uint length;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct QNX4_Inode
|
||||
{
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] public byte[] di_fname;
|
||||
public uint di_size;
|
||||
public QNX4_Extent di_first_xtnt;
|
||||
public uint di_xblk;
|
||||
public uint di_ftime;
|
||||
public uint di_mtime;
|
||||
public uint di_atime;
|
||||
public uint di_ctime;
|
||||
public ushort di_num_xtnts;
|
||||
public ushort di_mode;
|
||||
public ushort di_uid;
|
||||
public ushort di_gid;
|
||||
public ushort di_nlink;
|
||||
public uint di_zero;
|
||||
public byte di_type;
|
||||
public byte di_status;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct QNX4_LinkInfo
|
||||
{
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 48)] public byte[] dl_fname;
|
||||
public uint dl_inode_blk;
|
||||
public byte dl_inode_ndx;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)] public byte[] dl_spare;
|
||||
public byte dl_status;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct QNX4_ExtentBlock
|
||||
{
|
||||
public uint next_xblk;
|
||||
public uint prev_xblk;
|
||||
public byte num_xtnts;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] public byte[] spare;
|
||||
public uint num_blocks;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 60)] public QNX4_Extent[] xtnts;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] public byte[] signature;
|
||||
public QNX4_Extent first_xtnt;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct QNX4_Superblock
|
||||
{
|
||||
public QNX4_Inode rootDir;
|
||||
public QNX4_Inode inode;
|
||||
public QNX4_Inode boot;
|
||||
public QNX4_Inode altBoot;
|
||||
}
|
||||
|
||||
readonly byte[] QNX4_RootDir_Fname =
|
||||
{0x2F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
|
||||
@@ -159,8 +100,7 @@ namespace DiscImageChef.Filesystems
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void GetInformation(ImagePlugin imagePlugin, Partition partition,
|
||||
out string information)
|
||||
public override void GetInformation(ImagePlugin imagePlugin, Partition partition, out string information)
|
||||
{
|
||||
information = "";
|
||||
byte[] sector = imagePlugin.ReadSector(partition.Start + 1);
|
||||
@@ -321,5 +261,64 @@ namespace DiscImageChef.Filesystems
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
struct QNX4_Extent
|
||||
{
|
||||
public uint block;
|
||||
public uint length;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct QNX4_Inode
|
||||
{
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] public byte[] di_fname;
|
||||
public uint di_size;
|
||||
public QNX4_Extent di_first_xtnt;
|
||||
public uint di_xblk;
|
||||
public uint di_ftime;
|
||||
public uint di_mtime;
|
||||
public uint di_atime;
|
||||
public uint di_ctime;
|
||||
public ushort di_num_xtnts;
|
||||
public ushort di_mode;
|
||||
public ushort di_uid;
|
||||
public ushort di_gid;
|
||||
public ushort di_nlink;
|
||||
public uint di_zero;
|
||||
public byte di_type;
|
||||
public byte di_status;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct QNX4_LinkInfo
|
||||
{
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 48)] public byte[] dl_fname;
|
||||
public uint dl_inode_blk;
|
||||
public byte dl_inode_ndx;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)] public byte[] dl_spare;
|
||||
public byte dl_status;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct QNX4_ExtentBlock
|
||||
{
|
||||
public uint next_xblk;
|
||||
public uint prev_xblk;
|
||||
public byte num_xtnts;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] public byte[] spare;
|
||||
public uint num_blocks;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 60)] public QNX4_Extent[] xtnts;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] public byte[] signature;
|
||||
public QNX4_Extent first_xtnt;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct QNX4_Superblock
|
||||
{
|
||||
public QNX4_Inode rootDir;
|
||||
public QNX4_Inode inode;
|
||||
public QNX4_Inode boot;
|
||||
public QNX4_Inode altBoot;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -42,60 +42,6 @@ namespace DiscImageChef.Filesystems
|
||||
{
|
||||
public class QNX6 : Filesystem
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct QNX6_RootNode
|
||||
{
|
||||
public ulong size;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] public uint[] pointers;
|
||||
public byte levels;
|
||||
public byte mode;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)] public byte[] spare;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct QNX6_SuperBlock
|
||||
{
|
||||
public uint magic;
|
||||
public uint checksum;
|
||||
public ulong serial;
|
||||
public uint ctime;
|
||||
public uint atime;
|
||||
public uint flags;
|
||||
public ushort version1;
|
||||
public ushort version2;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] public byte[] volumeid;
|
||||
public uint blockSize;
|
||||
public uint numInodes;
|
||||
public uint freeInodes;
|
||||
public uint numBlocks;
|
||||
public uint freeBlocks;
|
||||
public uint allocationGroup;
|
||||
public QNX6_RootNode inode;
|
||||
public QNX6_RootNode bitmap;
|
||||
public QNX6_RootNode longfile;
|
||||
public QNX6_RootNode unknown;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct QNX6_AudiSuperBlock
|
||||
{
|
||||
public uint magic;
|
||||
public uint checksum;
|
||||
public ulong serial;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)] public byte[] spare1;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)] public byte[] id;
|
||||
public uint blockSize;
|
||||
public uint numInodes;
|
||||
public uint freeInodes;
|
||||
public uint numBlocks;
|
||||
public uint freeBlocks;
|
||||
public uint spare2;
|
||||
public QNX6_RootNode inode;
|
||||
public QNX6_RootNode bitmap;
|
||||
public QNX6_RootNode longfile;
|
||||
public QNX6_RootNode unknown;
|
||||
}
|
||||
|
||||
const uint QNX6_SUPER_BLOCK_SIZE = 0x1000;
|
||||
const uint QNX6_BOOT_BLOCKS_SIZE = 0x2000;
|
||||
const uint QNX6_MAGIC = 0x68191122;
|
||||
@@ -147,8 +93,7 @@ namespace DiscImageChef.Filesystems
|
||||
return qnxSb.magic == QNX6_MAGIC || audiSb.magic == QNX6_MAGIC;
|
||||
}
|
||||
|
||||
public override void GetInformation(ImagePlugin imagePlugin, Partition partition,
|
||||
out string information)
|
||||
public override void GetInformation(ImagePlugin imagePlugin, Partition partition, out string information)
|
||||
{
|
||||
information = "";
|
||||
StringBuilder sb = new StringBuilder();
|
||||
@@ -297,5 +242,59 @@ namespace DiscImageChef.Filesystems
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct QNX6_RootNode
|
||||
{
|
||||
public ulong size;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] public uint[] pointers;
|
||||
public byte levels;
|
||||
public byte mode;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)] public byte[] spare;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct QNX6_SuperBlock
|
||||
{
|
||||
public uint magic;
|
||||
public uint checksum;
|
||||
public ulong serial;
|
||||
public uint ctime;
|
||||
public uint atime;
|
||||
public uint flags;
|
||||
public ushort version1;
|
||||
public ushort version2;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] public byte[] volumeid;
|
||||
public uint blockSize;
|
||||
public uint numInodes;
|
||||
public uint freeInodes;
|
||||
public uint numBlocks;
|
||||
public uint freeBlocks;
|
||||
public uint allocationGroup;
|
||||
public QNX6_RootNode inode;
|
||||
public QNX6_RootNode bitmap;
|
||||
public QNX6_RootNode longfile;
|
||||
public QNX6_RootNode unknown;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct QNX6_AudiSuperBlock
|
||||
{
|
||||
public uint magic;
|
||||
public uint checksum;
|
||||
public ulong serial;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)] public byte[] spare1;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)] public byte[] id;
|
||||
public uint blockSize;
|
||||
public uint numInodes;
|
||||
public uint freeInodes;
|
||||
public uint numBlocks;
|
||||
public uint freeBlocks;
|
||||
public uint spare2;
|
||||
public QNX6_RootNode inode;
|
||||
public QNX6_RootNode bitmap;
|
||||
public QNX6_RootNode longfile;
|
||||
public QNX6_RootNode unknown;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -43,111 +43,6 @@ namespace DiscImageChef.Filesystems
|
||||
{
|
||||
public class RBF : Filesystem
|
||||
{
|
||||
/// <summary>
|
||||
/// Identification sector. Wherever the sector this resides on, becomes LSN 0.
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct RBF_IdSector
|
||||
{
|
||||
/// <summary>Sectors on disk</summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] public byte[] dd_tot;
|
||||
/// <summary>Tracks</summary>
|
||||
public byte dd_tks;
|
||||
/// <summary>Bytes in allocation map</summary>
|
||||
public ushort dd_map;
|
||||
/// <summary>Sectors per cluster</summary>
|
||||
public ushort dd_bit;
|
||||
/// <summary>LSN of root directory</summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] public byte[] dd_dir;
|
||||
/// <summary>Owner ID</summary>
|
||||
public ushort dd_own;
|
||||
/// <summary>Attributes</summary>
|
||||
public byte dd_att;
|
||||
/// <summary>Disk ID</summary>
|
||||
public ushort dd_dsk;
|
||||
/// <summary>Format byte</summary>
|
||||
public byte dd_fmt;
|
||||
/// <summary>Sectors per track</summary>
|
||||
public ushort dd_spt;
|
||||
/// <summary>Reserved</summary>
|
||||
public ushort dd_res;
|
||||
/// <summary>LSN of boot file</summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] public byte[] dd_bt;
|
||||
/// <summary>Size of boot file</summary>
|
||||
public ushort dd_bsz;
|
||||
/// <summary>Creation date</summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)] public byte[] dd_dat;
|
||||
/// <summary>Volume name</summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] public byte[] dd_nam;
|
||||
/// <summary>Path options</summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] public byte[] dd_opt;
|
||||
/// <summary>Reserved</summary>
|
||||
public byte reserved;
|
||||
/// <summary>Magic number</summary>
|
||||
public uint dd_sync;
|
||||
/// <summary>LSN of allocation map</summary>
|
||||
public uint dd_maplsn;
|
||||
/// <summary>Size of an LSN</summary>
|
||||
public ushort dd_lsnsize;
|
||||
/// <summary>Version ID</summary>
|
||||
public ushort dd_versid;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Identification sector. Wherever the sector this resides on, becomes LSN 0.
|
||||
/// Introduced on OS-9000, this can be big or little endian.
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct RBF_NewIdSector
|
||||
{
|
||||
/// <summary>Magic number</summary>
|
||||
public uint rid_sync;
|
||||
/// <summary>Disk ID</summary>
|
||||
public uint rid_diskid;
|
||||
/// <summary>Sectors on disk</summary>
|
||||
public uint rid_totblocks;
|
||||
/// <summary>Cylinders</summary>
|
||||
public ushort rid_cylinders;
|
||||
/// <summary>Sectors in cylinder 0</summary>
|
||||
public ushort rid_cyl0size;
|
||||
/// <summary>Sectors per cylinder</summary>
|
||||
public ushort rid_cylsize;
|
||||
/// <summary>Heads</summary>
|
||||
public ushort rid_heads;
|
||||
/// <summary>Bytes per sector</summary>
|
||||
public ushort rid_blocksize;
|
||||
/// <summary>Disk format</summary>
|
||||
public ushort rid_format;
|
||||
/// <summary>Flags</summary>
|
||||
public ushort rid_flags;
|
||||
/// <summary>Padding</summary>
|
||||
public ushort rid_unused1;
|
||||
/// <summary>Sector of allocation bitmap</summary>
|
||||
public uint rid_bitmap;
|
||||
/// <summary>Sector of debugger FD</summary>
|
||||
public uint rid_firstboot;
|
||||
/// <summary>Sector of bootfile FD</summary>
|
||||
public uint rid_bootfile;
|
||||
/// <summary>Sector of root directory FD</summary>
|
||||
public uint rid_rootdir;
|
||||
/// <summary>Group owner of media</summary>
|
||||
public ushort rid_group;
|
||||
/// <summary>Owner of media</summary>
|
||||
public ushort rid_owner;
|
||||
/// <summary>Creation time</summary>
|
||||
public uint rid_ctime;
|
||||
/// <summary>Last write time for this structure</summary>
|
||||
public uint rid_mtime;
|
||||
/// <summary>Volume name</summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] public byte[] rid_name;
|
||||
/// <summary>Endian flag</summary>
|
||||
public byte rid_endflag;
|
||||
/// <summary>Padding</summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] public byte[] rid_unused2;
|
||||
/// <summary>Parity</summary>
|
||||
public uint rid_parity;
|
||||
}
|
||||
|
||||
/// <summary>Magic number for OS-9. Same for OS-9000?</summary>
|
||||
const uint RBF_SYNC = 0x4372757A;
|
||||
const uint RBF_CNYS = 0x7A757243;
|
||||
@@ -206,8 +101,7 @@ namespace DiscImageChef.Filesystems
|
||||
return false;
|
||||
}
|
||||
|
||||
public override void GetInformation(ImagePlugin imagePlugin, Partition partition,
|
||||
out string information)
|
||||
public override void GetInformation(ImagePlugin imagePlugin, Partition partition, out string information)
|
||||
{
|
||||
information = "";
|
||||
if(imagePlugin.GetSectorSize() < 256) return;
|
||||
@@ -403,5 +297,110 @@ namespace DiscImageChef.Filesystems
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Identification sector. Wherever the sector this resides on, becomes LSN 0.
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct RBF_IdSector
|
||||
{
|
||||
/// <summary>Sectors on disk</summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] public byte[] dd_tot;
|
||||
/// <summary>Tracks</summary>
|
||||
public byte dd_tks;
|
||||
/// <summary>Bytes in allocation map</summary>
|
||||
public ushort dd_map;
|
||||
/// <summary>Sectors per cluster</summary>
|
||||
public ushort dd_bit;
|
||||
/// <summary>LSN of root directory</summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] public byte[] dd_dir;
|
||||
/// <summary>Owner ID</summary>
|
||||
public ushort dd_own;
|
||||
/// <summary>Attributes</summary>
|
||||
public byte dd_att;
|
||||
/// <summary>Disk ID</summary>
|
||||
public ushort dd_dsk;
|
||||
/// <summary>Format byte</summary>
|
||||
public byte dd_fmt;
|
||||
/// <summary>Sectors per track</summary>
|
||||
public ushort dd_spt;
|
||||
/// <summary>Reserved</summary>
|
||||
public ushort dd_res;
|
||||
/// <summary>LSN of boot file</summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] public byte[] dd_bt;
|
||||
/// <summary>Size of boot file</summary>
|
||||
public ushort dd_bsz;
|
||||
/// <summary>Creation date</summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)] public byte[] dd_dat;
|
||||
/// <summary>Volume name</summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] public byte[] dd_nam;
|
||||
/// <summary>Path options</summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] public byte[] dd_opt;
|
||||
/// <summary>Reserved</summary>
|
||||
public byte reserved;
|
||||
/// <summary>Magic number</summary>
|
||||
public uint dd_sync;
|
||||
/// <summary>LSN of allocation map</summary>
|
||||
public uint dd_maplsn;
|
||||
/// <summary>Size of an LSN</summary>
|
||||
public ushort dd_lsnsize;
|
||||
/// <summary>Version ID</summary>
|
||||
public ushort dd_versid;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Identification sector. Wherever the sector this resides on, becomes LSN 0.
|
||||
/// Introduced on OS-9000, this can be big or little endian.
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct RBF_NewIdSector
|
||||
{
|
||||
/// <summary>Magic number</summary>
|
||||
public uint rid_sync;
|
||||
/// <summary>Disk ID</summary>
|
||||
public uint rid_diskid;
|
||||
/// <summary>Sectors on disk</summary>
|
||||
public uint rid_totblocks;
|
||||
/// <summary>Cylinders</summary>
|
||||
public ushort rid_cylinders;
|
||||
/// <summary>Sectors in cylinder 0</summary>
|
||||
public ushort rid_cyl0size;
|
||||
/// <summary>Sectors per cylinder</summary>
|
||||
public ushort rid_cylsize;
|
||||
/// <summary>Heads</summary>
|
||||
public ushort rid_heads;
|
||||
/// <summary>Bytes per sector</summary>
|
||||
public ushort rid_blocksize;
|
||||
/// <summary>Disk format</summary>
|
||||
public ushort rid_format;
|
||||
/// <summary>Flags</summary>
|
||||
public ushort rid_flags;
|
||||
/// <summary>Padding</summary>
|
||||
public ushort rid_unused1;
|
||||
/// <summary>Sector of allocation bitmap</summary>
|
||||
public uint rid_bitmap;
|
||||
/// <summary>Sector of debugger FD</summary>
|
||||
public uint rid_firstboot;
|
||||
/// <summary>Sector of bootfile FD</summary>
|
||||
public uint rid_bootfile;
|
||||
/// <summary>Sector of root directory FD</summary>
|
||||
public uint rid_rootdir;
|
||||
/// <summary>Group owner of media</summary>
|
||||
public ushort rid_group;
|
||||
/// <summary>Owner of media</summary>
|
||||
public ushort rid_owner;
|
||||
/// <summary>Creation time</summary>
|
||||
public uint rid_ctime;
|
||||
/// <summary>Last write time for this structure</summary>
|
||||
public uint rid_mtime;
|
||||
/// <summary>Volume name</summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] public byte[] rid_name;
|
||||
/// <summary>Endian flag</summary>
|
||||
public byte rid_endflag;
|
||||
/// <summary>Padding</summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] public byte[] rid_unused2;
|
||||
/// <summary>Parity</summary>
|
||||
public uint rid_parity;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -80,8 +80,7 @@ namespace DiscImageChef.Filesystems
|
||||
return magic == "DECRT11A ";
|
||||
}
|
||||
|
||||
public override void GetInformation(ImagePlugin imagePlugin, Partition partition,
|
||||
out string information)
|
||||
public override void GetInformation(ImagePlugin imagePlugin, Partition partition, out string information)
|
||||
{
|
||||
information = "";
|
||||
|
||||
@@ -90,7 +89,8 @@ namespace DiscImageChef.Filesystems
|
||||
byte[] hbSector = imagePlugin.ReadSector(1 + partition.Start);
|
||||
|
||||
GCHandle handle = GCHandle.Alloc(hbSector, GCHandleType.Pinned);
|
||||
RT11HomeBlock homeblock = (RT11HomeBlock)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(RT11HomeBlock));
|
||||
RT11HomeBlock homeblock =
|
||||
(RT11HomeBlock)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(RT11HomeBlock));
|
||||
handle.Free();
|
||||
|
||||
/* TODO: Is this correct?
|
||||
@@ -130,42 +130,6 @@ namespace DiscImageChef.Filesystems
|
||||
information = sb.ToString();
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct RT11HomeBlock
|
||||
{
|
||||
/// <summary>Bad block replacement table</summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 130)] public byte[] badBlockTable;
|
||||
/// <summary>Unused</summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] public byte[] unused;
|
||||
/// <summary>INITIALIZE/RESTORE data area</summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 38)] public byte[] initArea;
|
||||
/// <summary>BUP information area</summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 18)] public byte[] bupInformation;
|
||||
/// <summary>Empty</summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 260)] public byte[] empty;
|
||||
/// <summary>Reserved</summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] public byte[] reserved1;
|
||||
/// <summary>Reserved</summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] public byte[] reserved2;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 14)] public byte[] empty2;
|
||||
/// <summary>Cluster size</summary>
|
||||
public ushort cluster;
|
||||
/// <summary>Block of the first directory segment</summary>
|
||||
public ushort rootBlock;
|
||||
/// <summary>"V3A" in Radix-50</summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] public byte[] systemVersion;
|
||||
/// <summary>Name of the volume, 12 bytes</summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)] public byte[] volname;
|
||||
/// <summary>Name of the volume owner, 12 bytes</summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)] public byte[] ownername;
|
||||
/// <summary>RT11 defines it as "DECRT11A ", 12 bytes</summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)] public byte[] format;
|
||||
/// <summary>Unused</summary>
|
||||
public ushort unused2;
|
||||
/// <summary>Checksum of preceding 255 words (16 bit units)</summary>
|
||||
public ushort checksum;
|
||||
}
|
||||
|
||||
public override Errno Mount()
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
@@ -225,5 +189,41 @@ namespace DiscImageChef.Filesystems
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct RT11HomeBlock
|
||||
{
|
||||
/// <summary>Bad block replacement table</summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 130)] public byte[] badBlockTable;
|
||||
/// <summary>Unused</summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] public byte[] unused;
|
||||
/// <summary>INITIALIZE/RESTORE data area</summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 38)] public byte[] initArea;
|
||||
/// <summary>BUP information area</summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 18)] public byte[] bupInformation;
|
||||
/// <summary>Empty</summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 260)] public byte[] empty;
|
||||
/// <summary>Reserved</summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] public byte[] reserved1;
|
||||
/// <summary>Reserved</summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] public byte[] reserved2;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 14)] public byte[] empty2;
|
||||
/// <summary>Cluster size</summary>
|
||||
public ushort cluster;
|
||||
/// <summary>Block of the first directory segment</summary>
|
||||
public ushort rootBlock;
|
||||
/// <summary>"V3A" in Radix-50</summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] public byte[] systemVersion;
|
||||
/// <summary>Name of the volume, 12 bytes</summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)] public byte[] volname;
|
||||
/// <summary>Name of the volume owner, 12 bytes</summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)] public byte[] ownername;
|
||||
/// <summary>RT11 defines it as "DECRT11A ", 12 bytes</summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)] public byte[] format;
|
||||
/// <summary>Unused</summary>
|
||||
public ushort unused2;
|
||||
/// <summary>Checksum of preceding 255 words (16 bit units)</summary>
|
||||
public ushort checksum;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -43,52 +43,11 @@ namespace DiscImageChef.Filesystems
|
||||
{
|
||||
public class Reiser : Filesystem
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct ReiserJournalParams
|
||||
{
|
||||
public uint journal_1stblock;
|
||||
public uint journal_dev;
|
||||
public uint journal_size;
|
||||
public uint journal_trans_max;
|
||||
public uint journal_magic;
|
||||
public uint journal_max_batch;
|
||||
public uint journal_max_commit_age;
|
||||
public uint journal_max_trans_age;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct Reiser_Superblock
|
||||
{
|
||||
public uint block_count;
|
||||
public uint free_blocks;
|
||||
public uint root_block;
|
||||
public ReiserJournalParams journal;
|
||||
public ushort blocksize;
|
||||
public ushort oid_maxsize;
|
||||
public ushort oid_cursize;
|
||||
public ushort umount_state;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)] public byte[] magic;
|
||||
public ushort fs_state;
|
||||
public uint hash_function_code;
|
||||
public ushort tree_height;
|
||||
public ushort bmap_nr;
|
||||
public ushort version;
|
||||
public ushort reserved_for_journal;
|
||||
public uint inode_generation;
|
||||
public uint flags;
|
||||
public Guid uuid;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] public byte[] label;
|
||||
public ushort mnt_count;
|
||||
public ushort max_mnt_count;
|
||||
public uint last_check;
|
||||
public uint check_interval;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 76)] public byte[] unused;
|
||||
}
|
||||
const uint REISER_SUPER_OFFSET = 0x10000;
|
||||
|
||||
readonly byte[] Reiser35_Magic = {0x52, 0x65, 0x49, 0x73, 0x45, 0x72, 0x46, 0x73, 0x00, 0x00};
|
||||
readonly byte[] Reiser36_Magic = {0x52, 0x65, 0x49, 0x73, 0x45, 0x72, 0x32, 0x46, 0x73, 0x00};
|
||||
readonly byte[] ReiserJr_Magic = {0x52, 0x65, 0x49, 0x73, 0x45, 0x72, 0x33, 0x46, 0x73, 0x00};
|
||||
const uint REISER_SUPER_OFFSET = 0x10000;
|
||||
|
||||
public Reiser()
|
||||
{
|
||||
@@ -137,8 +96,7 @@ namespace DiscImageChef.Filesystems
|
||||
ReiserJr_Magic.SequenceEqual(reiserSb.magic);
|
||||
}
|
||||
|
||||
public override void GetInformation(ImagePlugin imagePlugin, Partition partition,
|
||||
out string information)
|
||||
public override void GetInformation(ImagePlugin imagePlugin, Partition partition, out string information)
|
||||
{
|
||||
information = "";
|
||||
if(imagePlugin.GetSectorSize() < 512) return;
|
||||
@@ -256,5 +214,47 @@ namespace DiscImageChef.Filesystems
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct ReiserJournalParams
|
||||
{
|
||||
public uint journal_1stblock;
|
||||
public uint journal_dev;
|
||||
public uint journal_size;
|
||||
public uint journal_trans_max;
|
||||
public uint journal_magic;
|
||||
public uint journal_max_batch;
|
||||
public uint journal_max_commit_age;
|
||||
public uint journal_max_trans_age;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct Reiser_Superblock
|
||||
{
|
||||
public uint block_count;
|
||||
public uint free_blocks;
|
||||
public uint root_block;
|
||||
public ReiserJournalParams journal;
|
||||
public ushort blocksize;
|
||||
public ushort oid_maxsize;
|
||||
public ushort oid_cursize;
|
||||
public ushort umount_state;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)] public byte[] magic;
|
||||
public ushort fs_state;
|
||||
public uint hash_function_code;
|
||||
public ushort tree_height;
|
||||
public ushort bmap_nr;
|
||||
public ushort version;
|
||||
public ushort reserved_for_journal;
|
||||
public uint inode_generation;
|
||||
public uint flags;
|
||||
public Guid uuid;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] public byte[] label;
|
||||
public ushort mnt_count;
|
||||
public ushort max_mnt_count;
|
||||
public uint last_check;
|
||||
public uint check_interval;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 76)] public byte[] unused;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -43,19 +43,10 @@ namespace DiscImageChef.Filesystems
|
||||
{
|
||||
public class Reiser4 : Filesystem
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct Reiser4_Superblock
|
||||
{
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] public byte[] magic;
|
||||
public ushort diskformat;
|
||||
public ushort blocksize;
|
||||
public Guid uuid;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] public byte[] label;
|
||||
}
|
||||
const uint REISER4_SUPER_OFFSET = 0x10000;
|
||||
|
||||
readonly byte[] Reiser4_Magic =
|
||||
{0x52, 0x65, 0x49, 0x73, 0x45, 0x72, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
const uint REISER4_SUPER_OFFSET = 0x10000;
|
||||
|
||||
public Reiser4()
|
||||
{
|
||||
@@ -103,8 +94,7 @@ namespace DiscImageChef.Filesystems
|
||||
return Reiser4_Magic.SequenceEqual(reiserSb.magic);
|
||||
}
|
||||
|
||||
public override void GetInformation(ImagePlugin imagePlugin, Partition partition,
|
||||
out string information)
|
||||
public override void GetInformation(ImagePlugin imagePlugin, Partition partition, out string information)
|
||||
{
|
||||
information = "";
|
||||
if(imagePlugin.GetSectorSize() < 512) return;
|
||||
@@ -206,5 +196,15 @@ namespace DiscImageChef.Filesystems
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct Reiser4_Superblock
|
||||
{
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] public byte[] magic;
|
||||
public ushort diskformat;
|
||||
public ushort blocksize;
|
||||
public Guid uuid;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] public byte[] label;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -42,6 +42,11 @@ namespace DiscImageChef.Filesystems
|
||||
{
|
||||
public class SFS : Filesystem
|
||||
{
|
||||
/// <summary>Identifier for SFS v1</summary>
|
||||
const uint SFS_MAGIC = 0x53465300;
|
||||
/// <summary>Identifier for SFS v2</summary>
|
||||
const uint SFS2_MAGIC = 0x53465302;
|
||||
|
||||
public SFS()
|
||||
{
|
||||
Name = "SmartFileSystem";
|
||||
@@ -63,45 +68,6 @@ namespace DiscImageChef.Filesystems
|
||||
CurrentEncoding = encoding ?? Encoding.GetEncoding("iso-8859-1");
|
||||
}
|
||||
|
||||
[Flags]
|
||||
enum SFSFlags : byte
|
||||
{
|
||||
RecyledFolder = 64,
|
||||
CaseSensitive = 128
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct RootBlock
|
||||
{
|
||||
public uint blockId;
|
||||
public uint blockChecksum;
|
||||
public uint blockSelfPointer;
|
||||
public ushort version;
|
||||
public ushort sequence;
|
||||
public uint datecreated;
|
||||
public SFSFlags bits;
|
||||
public byte padding1;
|
||||
public ushort padding2;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] public uint[] reserved1;
|
||||
public ulong firstbyte;
|
||||
public ulong lastbyte;
|
||||
public uint totalblocks;
|
||||
public uint blocksize;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] public uint[] reserved2;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] public uint[] reserved3;
|
||||
public uint bitmapbase;
|
||||
public uint adminspacecontainer;
|
||||
public uint rootobjectcontainer;
|
||||
public uint extentbnoderoot;
|
||||
public uint objectnoderoot;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] public uint[] reserved4;
|
||||
}
|
||||
|
||||
/// <summary>Identifier for SFS v1</summary>
|
||||
const uint SFS_MAGIC = 0x53465300;
|
||||
/// <summary>Identifier for SFS v2</summary>
|
||||
const uint SFS2_MAGIC = 0x53465302;
|
||||
|
||||
public override bool Identify(ImagePlugin imagePlugin, Partition partition)
|
||||
{
|
||||
if(partition.Start >= partition.End) return false;
|
||||
@@ -115,8 +81,7 @@ namespace DiscImageChef.Filesystems
|
||||
return magic == SFS_MAGIC || magic == SFS2_MAGIC;
|
||||
}
|
||||
|
||||
public override void GetInformation(ImagePlugin imagePlugin, Partition partition,
|
||||
out string information)
|
||||
public override void GetInformation(ImagePlugin imagePlugin, Partition partition, out string information)
|
||||
{
|
||||
byte[] rootBlockSector = imagePlugin.ReadSector(partition.Start);
|
||||
RootBlock rootBlock = BigEndianMarshal.ByteArrayToStructureBigEndian<RootBlock>(rootBlockSector);
|
||||
@@ -217,5 +182,39 @@ namespace DiscImageChef.Filesystems
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
[Flags]
|
||||
enum SFSFlags : byte
|
||||
{
|
||||
RecyledFolder = 64,
|
||||
CaseSensitive = 128
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct RootBlock
|
||||
{
|
||||
public uint blockId;
|
||||
public uint blockChecksum;
|
||||
public uint blockSelfPointer;
|
||||
public ushort version;
|
||||
public ushort sequence;
|
||||
public uint datecreated;
|
||||
public SFSFlags bits;
|
||||
public byte padding1;
|
||||
public ushort padding2;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] public uint[] reserved1;
|
||||
public ulong firstbyte;
|
||||
public ulong lastbyte;
|
||||
public uint totalblocks;
|
||||
public uint blocksize;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] public uint[] reserved2;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] public uint[] reserved3;
|
||||
public uint bitmapbase;
|
||||
public uint adminspacecontainer;
|
||||
public uint rootobjectcontainer;
|
||||
public uint extentbnoderoot;
|
||||
public uint objectnoderoot;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] public uint[] reserved4;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -81,15 +81,13 @@ namespace DiscImageChef.Filesystems
|
||||
return signature == 0x29 && fsType == "SOL_FS ";
|
||||
}
|
||||
|
||||
public override void GetInformation(ImagePlugin imagePlugin, Partition partition,
|
||||
out string information)
|
||||
public override void GetInformation(ImagePlugin imagePlugin, Partition partition, out string information)
|
||||
{
|
||||
information = "";
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
byte[] bpbSector = imagePlugin.ReadSector(0 + partition.Start);
|
||||
|
||||
|
||||
SolarOSParameterBlock bpb = new SolarOSParameterBlock
|
||||
{
|
||||
bps = BitConverter.ToUInt16(bpbSector, 0x0B),
|
||||
@@ -174,42 +172,6 @@ namespace DiscImageChef.Filesystems
|
||||
information = sb.ToString();
|
||||
}
|
||||
|
||||
struct SolarOSParameterBlock
|
||||
{
|
||||
/// <summary>0x00, x86 jump (3 bytes), jumps to 0x60</summary>
|
||||
public byte[] x86_jump;
|
||||
/// <summary>0x03, 8 bytes, "SOLAR_OS"</summary>
|
||||
public string OEMName;
|
||||
/// <summary>0x0B, Bytes per sector</summary>
|
||||
public ushort bps;
|
||||
/// <summary>0x0D, unknown, 0x01</summary>
|
||||
public byte unk1;
|
||||
/// <summary>0x0E, unknown, 0x0201</summary>
|
||||
public ushort unk2;
|
||||
/// <summary>0x10, Number of entries on root directory ? (no root directory found)</summary>
|
||||
public ushort root_ent;
|
||||
/// <summary>0x12, Sectors in volume</summary>
|
||||
public ushort sectors;
|
||||
/// <summary>0x14, Media descriptor</summary>
|
||||
public byte media;
|
||||
/// <summary>0x15, Sectors per FAT ? (no FAT found)</summary>
|
||||
public ushort spfat;
|
||||
/// <summary>0x17, Sectors per track</summary>
|
||||
public ushort sptrk;
|
||||
/// <summary>0x19, Heads</summary>
|
||||
public ushort heads;
|
||||
/// <summary>0x1B, unknown, 10 bytes, zero-filled</summary>
|
||||
public byte[] unk3;
|
||||
/// <summary>0x25, 0x29</summary>
|
||||
public byte signature;
|
||||
/// <summary>0x26, unknown, zero-filled</summary>
|
||||
public uint unk4;
|
||||
/// <summary>0x2A, 11 bytes, volume name, space-padded</summary>
|
||||
public string vol_name;
|
||||
/// <summary>0x35, 8 bytes, "SOL_FS "</summary>
|
||||
public string fs_type;
|
||||
}
|
||||
|
||||
public override Errno Mount()
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
@@ -269,5 +231,41 @@ namespace DiscImageChef.Filesystems
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
struct SolarOSParameterBlock
|
||||
{
|
||||
/// <summary>0x00, x86 jump (3 bytes), jumps to 0x60</summary>
|
||||
public byte[] x86_jump;
|
||||
/// <summary>0x03, 8 bytes, "SOLAR_OS"</summary>
|
||||
public string OEMName;
|
||||
/// <summary>0x0B, Bytes per sector</summary>
|
||||
public ushort bps;
|
||||
/// <summary>0x0D, unknown, 0x01</summary>
|
||||
public byte unk1;
|
||||
/// <summary>0x0E, unknown, 0x0201</summary>
|
||||
public ushort unk2;
|
||||
/// <summary>0x10, Number of entries on root directory ? (no root directory found)</summary>
|
||||
public ushort root_ent;
|
||||
/// <summary>0x12, Sectors in volume</summary>
|
||||
public ushort sectors;
|
||||
/// <summary>0x14, Media descriptor</summary>
|
||||
public byte media;
|
||||
/// <summary>0x15, Sectors per FAT ? (no FAT found)</summary>
|
||||
public ushort spfat;
|
||||
/// <summary>0x17, Sectors per track</summary>
|
||||
public ushort sptrk;
|
||||
/// <summary>0x19, Heads</summary>
|
||||
public ushort heads;
|
||||
/// <summary>0x1B, unknown, 10 bytes, zero-filled</summary>
|
||||
public byte[] unk3;
|
||||
/// <summary>0x25, 0x29</summary>
|
||||
public byte signature;
|
||||
/// <summary>0x26, unknown, zero-filled</summary>
|
||||
public uint unk4;
|
||||
/// <summary>0x2A, 11 bytes, volume name, space-padded</summary>
|
||||
public string vol_name;
|
||||
/// <summary>0x35, 8 bytes, "SOL_FS "</summary>
|
||||
public string fs_type;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -42,6 +42,12 @@ namespace DiscImageChef.Filesystems
|
||||
{
|
||||
public class Squash : Filesystem
|
||||
{
|
||||
/// <summary>
|
||||
/// Identifier for Squash
|
||||
/// </summary>
|
||||
const uint SQUASH_MAGIC = 0x73717368;
|
||||
const uint SQUASH_CIGAM = 0x68737173;
|
||||
|
||||
public Squash()
|
||||
{
|
||||
Name = "Squash filesystem";
|
||||
@@ -63,46 +69,6 @@ namespace DiscImageChef.Filesystems
|
||||
CurrentEncoding = encoding ?? Encoding.UTF8;
|
||||
}
|
||||
|
||||
enum SquashCompression : ushort
|
||||
{
|
||||
Zlib = 1,
|
||||
Lzma = 2,
|
||||
Lzo = 3,
|
||||
Xz = 4,
|
||||
Lz4 = 5,
|
||||
Zstd = 6
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct SquashSuperBlock
|
||||
{
|
||||
public uint magic;
|
||||
public uint inodes;
|
||||
public uint mkfs_time;
|
||||
public uint block_size;
|
||||
public uint fragments;
|
||||
public ushort compression;
|
||||
public ushort block_log;
|
||||
public ushort flags;
|
||||
public ushort no_ids;
|
||||
public ushort s_major;
|
||||
public ushort s_minor;
|
||||
public ulong root_inode;
|
||||
public ulong bytes_used;
|
||||
public ulong id_table_start;
|
||||
public ulong xattr_id_table_start;
|
||||
public ulong inode_table_start;
|
||||
public ulong directory_table_start;
|
||||
public ulong fragment_table_start;
|
||||
public ulong lookup_table_start;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Identifier for Squash
|
||||
/// </summary>
|
||||
const uint SQUASH_MAGIC = 0x73717368;
|
||||
const uint SQUASH_CIGAM = 0x68737173;
|
||||
|
||||
public override bool Identify(ImagePlugin imagePlugin, Partition partition)
|
||||
{
|
||||
if(partition.Start >= partition.End) return false;
|
||||
@@ -114,8 +80,7 @@ namespace DiscImageChef.Filesystems
|
||||
return magic == SQUASH_MAGIC || magic == SQUASH_CIGAM;
|
||||
}
|
||||
|
||||
public override void GetInformation(ImagePlugin imagePlugin, Partition partition,
|
||||
out string information)
|
||||
public override void GetInformation(ImagePlugin imagePlugin, Partition partition, out string information)
|
||||
{
|
||||
byte[] sector = imagePlugin.ReadSector(partition.Start);
|
||||
uint magic = BitConverter.ToUInt32(sector, 0x00);
|
||||
@@ -123,7 +88,8 @@ namespace DiscImageChef.Filesystems
|
||||
SquashSuperBlock sqSb = new SquashSuperBlock();
|
||||
bool littleEndian = true;
|
||||
|
||||
switch(magic) {
|
||||
switch(magic)
|
||||
{
|
||||
case SQUASH_MAGIC:
|
||||
IntPtr sqSbPtr = Marshal.AllocHGlobal(Marshal.SizeOf(sqSb));
|
||||
Marshal.Copy(sector, 0, sqSbPtr, Marshal.SizeOf(sqSb));
|
||||
@@ -248,5 +214,39 @@ namespace DiscImageChef.Filesystems
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
enum SquashCompression : ushort
|
||||
{
|
||||
Zlib = 1,
|
||||
Lzma = 2,
|
||||
Lzo = 3,
|
||||
Xz = 4,
|
||||
Lz4 = 5,
|
||||
Zstd = 6
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct SquashSuperBlock
|
||||
{
|
||||
public uint magic;
|
||||
public uint inodes;
|
||||
public uint mkfs_time;
|
||||
public uint block_size;
|
||||
public uint fragments;
|
||||
public ushort compression;
|
||||
public ushort block_log;
|
||||
public ushort flags;
|
||||
public ushort no_ids;
|
||||
public ushort s_major;
|
||||
public ushort s_minor;
|
||||
public ulong root_inode;
|
||||
public ulong bytes_used;
|
||||
public ulong id_table_start;
|
||||
public ulong xattr_id_table_start;
|
||||
public ulong inode_table_start;
|
||||
public ulong directory_table_start;
|
||||
public ulong fragment_table_start;
|
||||
public ulong lookup_table_start;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -37,7 +37,7 @@ using System.Runtime.InteropServices;
|
||||
namespace DiscImageChef.Filesystems
|
||||
{
|
||||
/// <summary>
|
||||
/// File attributes.
|
||||
/// File attributes.
|
||||
/// </summary>
|
||||
[Flags]
|
||||
public enum FileAttributes : ulong
|
||||
@@ -143,12 +143,31 @@ namespace DiscImageChef.Filesystems
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Information about a file entry
|
||||
/// Information about a file entry
|
||||
/// </summary>
|
||||
public class FileEntryInfo
|
||||
{
|
||||
/// <summary>File attributes</summary>
|
||||
public FileAttributes Attributes;
|
||||
/// <summary>File length in blocks</summary>
|
||||
public long Blocks;
|
||||
/// <summary>File block size in bytes</summary>
|
||||
public long BlockSize;
|
||||
/// <summary>If file points to a device, device number</summary>
|
||||
public ulong DeviceNo;
|
||||
/// <summary>POSIX group ID</summary>
|
||||
public ulong GID;
|
||||
|
||||
/// <summary>inode number for this file</summary>
|
||||
public ulong Inode;
|
||||
/// <summary>File length in bytes</summary>
|
||||
public long Length;
|
||||
/// <summary>Number of hard links pointing to this file</summary>
|
||||
public ulong Links;
|
||||
/// <summary>POSIX permissions/mode for this file</summary>
|
||||
public uint Mode;
|
||||
/// <summary>POSIX owner ID</summary>
|
||||
public ulong UID;
|
||||
|
||||
/// <summary>File creation date in UTC</summary>
|
||||
public DateTime CreationTimeUtc { get; set; }
|
||||
@@ -164,77 +183,59 @@ namespace DiscImageChef.Filesystems
|
||||
/// <summary>File creation date</summary>
|
||||
public DateTime CreationTime
|
||||
{
|
||||
get { return CreationTimeUtc.ToLocalTime(); }
|
||||
set { CreationTimeUtc = value.ToUniversalTime(); }
|
||||
get => CreationTimeUtc.ToLocalTime();
|
||||
set => CreationTimeUtc = value.ToUniversalTime();
|
||||
}
|
||||
/// <summary>File last access date</summary>
|
||||
public DateTime AccessTime
|
||||
{
|
||||
get { return AccessTimeUtc.ToLocalTime(); }
|
||||
set { AccessTimeUtc = value.ToUniversalTime(); }
|
||||
get => AccessTimeUtc.ToLocalTime();
|
||||
set => AccessTimeUtc = value.ToUniversalTime();
|
||||
}
|
||||
/// <summary>File attributes change date</summary>
|
||||
public DateTime StatusChangeTime
|
||||
{
|
||||
get { return StatusChangeTimeUtc.ToLocalTime(); }
|
||||
set { StatusChangeTimeUtc = value.ToUniversalTime(); }
|
||||
get => StatusChangeTimeUtc.ToLocalTime();
|
||||
set => StatusChangeTimeUtc = value.ToUniversalTime();
|
||||
}
|
||||
/// <summary>File last backup date</summary>
|
||||
public DateTime BackupTime
|
||||
{
|
||||
get { return BackupTimeUtc.ToLocalTime(); }
|
||||
set { BackupTimeUtc = value.ToUniversalTime(); }
|
||||
get => BackupTimeUtc.ToLocalTime();
|
||||
set => BackupTimeUtc = value.ToUniversalTime();
|
||||
}
|
||||
/// <summary>File last modification date</summary>
|
||||
public DateTime LastWriteTime
|
||||
{
|
||||
get { return LastWriteTimeUtc.ToLocalTime(); }
|
||||
set { LastWriteTimeUtc = value.ToUniversalTime(); }
|
||||
get => LastWriteTimeUtc.ToLocalTime();
|
||||
set => LastWriteTimeUtc = value.ToUniversalTime();
|
||||
}
|
||||
|
||||
/// <summary>inode number for this file</summary>
|
||||
public ulong Inode;
|
||||
/// <summary>POSIX permissions/mode for this file</summary>
|
||||
public uint Mode;
|
||||
/// <summary>Number of hard links pointing to this file</summary>
|
||||
public ulong Links;
|
||||
/// <summary>POSIX owner ID</summary>
|
||||
public ulong UID;
|
||||
/// <summary>POSIX group ID</summary>
|
||||
public ulong GID;
|
||||
/// <summary>If file points to a device, device number</summary>
|
||||
public ulong DeviceNo;
|
||||
/// <summary>File length in bytes</summary>
|
||||
public long Length;
|
||||
/// <summary>File block size in bytes</summary>
|
||||
public long BlockSize;
|
||||
/// <summary>File length in blocks</summary>
|
||||
public long Blocks;
|
||||
}
|
||||
|
||||
public class FileSystemInfo
|
||||
{
|
||||
/// <summary>Blocks for this filesystem</summary>
|
||||
public long Blocks;
|
||||
/// <summary>Maximum length of filenames on this filesystem</summary>
|
||||
public ushort FilenameLength;
|
||||
/// <summary>Files on this filesystem</summary>
|
||||
public ulong Files;
|
||||
/// <summary>Blocks free on this filesystem</summary>
|
||||
public long FreeBlocks;
|
||||
/// <summary>Free inodes on this filesystem</summary>
|
||||
public ulong FreeFiles;
|
||||
/// <summary>Filesystem ID</summary>
|
||||
public FileSystemId Id;
|
||||
/// <summary>ID of plugin for this file</summary>
|
||||
public Guid PluginId;
|
||||
|
||||
/// <summary>Filesystem type</summary>
|
||||
public string Type;
|
||||
|
||||
public FileSystemInfo()
|
||||
{
|
||||
Id = new FileSystemId();
|
||||
}
|
||||
|
||||
/// <summary>Filesystem type</summary>
|
||||
public string Type;
|
||||
/// <summary>ID of plugin for this file</summary>
|
||||
public Guid PluginId;
|
||||
/// <summary>Blocks for this filesystem</summary>
|
||||
public long Blocks;
|
||||
/// <summary>Blocks free on this filesystem</summary>
|
||||
public long FreeBlocks;
|
||||
/// <summary>Files on this filesystem</summary>
|
||||
public ulong Files;
|
||||
/// <summary>Free inodes on this filesystem</summary>
|
||||
public ulong FreeFiles;
|
||||
/// <summary>Maximum length of filenames on this filesystem</summary>
|
||||
public ushort FilenameLength;
|
||||
/// <summary>Filesystem ID</summary>
|
||||
public FileSystemId Id;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Explicit)]
|
||||
@@ -250,7 +251,7 @@ namespace DiscImageChef.Filesystems
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Errors
|
||||
/// Errors
|
||||
/// </summary>
|
||||
public enum Errno
|
||||
{
|
||||
|
||||
@@ -110,7 +110,10 @@ namespace DiscImageChef.Filesystems
|
||||
spc
|
||||
};
|
||||
|
||||
foreach(byte[] sb_sector in locations.TakeWhile(i => i + sb_size_in_sectors < (int)imagePlugin.ImageInfo.Sectors).Select(i => imagePlugin.ReadSectors((ulong)i + partition.Start, sb_size_in_sectors))) {
|
||||
foreach(byte[] sb_sector in locations
|
||||
.TakeWhile(i => i + sb_size_in_sectors < (int)imagePlugin.ImageInfo.Sectors)
|
||||
.Select(i => imagePlugin.ReadSectors((ulong)i + partition.Start, sb_size_in_sectors)))
|
||||
{
|
||||
uint magic = BitConverter.ToUInt32(sb_sector, 0x3F8);
|
||||
|
||||
if(magic == XENIX_MAGIC || magic == XENIX_CIGAM || magic == SYSV_MAGIC || magic == SYSV_CIGAM)
|
||||
@@ -156,15 +159,13 @@ namespace DiscImageChef.Filesystems
|
||||
if(s_fsize >= V7_MAXSIZE || s_nfree >= V7_NICFREE || s_ninode >= V7_NICINOD) continue;
|
||||
|
||||
if(s_fsize * 1024 == (partition.End - partition.Start) * imagePlugin.GetSectorSize() ||
|
||||
s_fsize * 512 == (partition.End - partition.Start) * imagePlugin.GetSectorSize())
|
||||
return true;
|
||||
s_fsize * 512 == (partition.End - partition.Start) * imagePlugin.GetSectorSize()) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public override void GetInformation(ImagePlugin imagePlugin, Partition partition,
|
||||
out string information)
|
||||
public override void GetInformation(ImagePlugin imagePlugin, Partition partition, out string information)
|
||||
{
|
||||
information = "";
|
||||
|
||||
@@ -680,6 +681,66 @@ namespace DiscImageChef.Filesystems
|
||||
BigEndianBitConverter.IsLittleEndian = false; // Return to default (bigendian)
|
||||
}
|
||||
|
||||
public override Errno Mount()
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno Mount(bool debug)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno Unmount()
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno MapBlock(string path, long fileBlock, ref long deviceBlock)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno GetAttributes(string path, ref FileAttributes attributes)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno ListXAttr(string path, ref List<string> xattrs)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno GetXattr(string path, string xattr, ref byte[] buf)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno Read(string path, long offset, long size, ref byte[] buf)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno ReadDir(string path, ref List<string> contents)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno StatFs(ref FileSystemInfo stat)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno Stat(string path, ref FileEntryInfo stat)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno ReadLink(string path, ref string dest)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
// Old XENIX use different offsets
|
||||
struct XenixSuperBlock
|
||||
{
|
||||
@@ -926,65 +987,5 @@ namespace DiscImageChef.Filesystems
|
||||
/// <summary>0x1F4, zero-filled</summary>
|
||||
public uint s_unique;
|
||||
}
|
||||
|
||||
public override Errno Mount()
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno Mount(bool debug)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno Unmount()
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno MapBlock(string path, long fileBlock, ref long deviceBlock)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno GetAttributes(string path, ref FileAttributes attributes)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno ListXAttr(string path, ref List<string> xattrs)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno GetXattr(string path, string xattr, ref byte[] buf)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno Read(string path, long offset, long size, ref byte[] buf)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno ReadDir(string path, ref List<string> contents)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno StatFs(ref FileSystemInfo stat)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno Stat(string path, ref FileEntryInfo stat)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno ReadLink(string path, ref string dest)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -159,8 +159,14 @@ namespace DiscImageChef.Filesystems.UCSDPascal
|
||||
{
|
||||
entry = new PascalFileEntry();
|
||||
|
||||
foreach(PascalFileEntry ent in fileEntries.Where(ent => string.Compare(path, StringHandlers.PascalToString(ent.filename, CurrentEncoding),
|
||||
StringComparison.InvariantCultureIgnoreCase) == 0)) {
|
||||
foreach(PascalFileEntry ent in fileEntries.Where(ent =>
|
||||
string.Compare(path,
|
||||
StringHandlers
|
||||
.PascalToString(ent.filename,
|
||||
CurrentEncoding),
|
||||
StringComparison
|
||||
.InvariantCultureIgnoreCase) == 0))
|
||||
{
|
||||
entry = ent;
|
||||
return Errno.NoError;
|
||||
}
|
||||
|
||||
@@ -80,13 +80,10 @@ namespace DiscImageChef.Filesystems.UCSDPascal
|
||||
if(volEntry.blocks < 0 || (ulong)volEntry.blocks != imagePlugin.GetSectors()) return false;
|
||||
|
||||
// There can be not less than zero files
|
||||
if(volEntry.files < 0) return false;
|
||||
|
||||
return true;
|
||||
return volEntry.files >= 0;
|
||||
}
|
||||
|
||||
public override void GetInformation(ImagePlugin imagePlugin, Partition partition,
|
||||
out string information)
|
||||
public override void GetInformation(ImagePlugin imagePlugin, Partition partition, out string information)
|
||||
{
|
||||
StringBuilder sbInformation = new StringBuilder();
|
||||
information = "";
|
||||
|
||||
@@ -53,7 +53,7 @@ namespace DiscImageChef.Filesystems.UCSDPascal
|
||||
public short dummy;
|
||||
/// <summary>0x14, last booted</summary>
|
||||
public short lastBoot;
|
||||
/// <summary>0x16, tail to make record same size as <see cref="PascalFileEntry"/></summary>
|
||||
/// <summary>0x16, tail to make record same size as <see cref="PascalFileEntry" /></summary>
|
||||
public int tail;
|
||||
}
|
||||
|
||||
|
||||
@@ -121,13 +121,15 @@ namespace DiscImageChef.Filesystems.UCSDPascal
|
||||
|
||||
public override Errno StatFs(ref FileSystemInfo stat)
|
||||
{
|
||||
stat = new FileSystemInfo();
|
||||
stat.Blocks = mountedVolEntry.blocks;
|
||||
stat.FilenameLength = 16;
|
||||
stat.Files = (ulong)mountedVolEntry.files;
|
||||
stat.FreeBlocks = 0;
|
||||
stat.PluginId = PluginUuid;
|
||||
stat.Type = "UCSD Pascal";
|
||||
stat = new FileSystemInfo
|
||||
{
|
||||
Blocks = mountedVolEntry.blocks,
|
||||
FilenameLength = 16,
|
||||
Files = (ulong)mountedVolEntry.files,
|
||||
FreeBlocks = 0,
|
||||
PluginId = PluginUuid,
|
||||
Type = "UCSD Pascal"
|
||||
};
|
||||
|
||||
stat.FreeBlocks = mountedVolEntry.blocks - (mountedVolEntry.lastBlock - mountedVolEntry.firstBlock);
|
||||
foreach(PascalFileEntry entry in fileEntries) stat.FreeBlocks -= entry.lastBlock - entry.firstBlock;
|
||||
|
||||
@@ -42,14 +42,14 @@ namespace DiscImageChef.Filesystems.UCSDPascal
|
||||
// Information from Call-A.P.P.L.E. Pascal Disk Directory Structure
|
||||
public partial class PascalPlugin : Filesystem
|
||||
{
|
||||
bool mounted;
|
||||
bool debug;
|
||||
readonly ImagePlugin device;
|
||||
|
||||
PascalVolumeEntry mountedVolEntry;
|
||||
List<PascalFileEntry> fileEntries;
|
||||
byte[] bootBlocks;
|
||||
byte[] catalogBlocks;
|
||||
bool debug;
|
||||
List<PascalFileEntry> fileEntries;
|
||||
bool mounted;
|
||||
|
||||
PascalVolumeEntry mountedVolEntry;
|
||||
|
||||
public PascalPlugin()
|
||||
{
|
||||
|
||||
@@ -45,6 +45,12 @@ namespace DiscImageChef.Filesystems
|
||||
// TODO: Detect bootable
|
||||
public class UDF : Filesystem
|
||||
{
|
||||
readonly byte[] UDF_Magic =
|
||||
{
|
||||
0x2A, 0x4F, 0x53, 0x54, 0x41, 0x20, 0x55, 0x44, 0x46, 0x20, 0x43, 0x6F, 0x6D, 0x70, 0x6C, 0x69, 0x61, 0x6E,
|
||||
0x74, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
public UDF()
|
||||
{
|
||||
Name = "Universal Disk Format";
|
||||
@@ -68,11 +74,304 @@ namespace DiscImageChef.Filesystems
|
||||
CurrentEncoding = Encoding.UTF8;
|
||||
}
|
||||
|
||||
readonly byte[] UDF_Magic =
|
||||
public override bool Identify(ImagePlugin imagePlugin, Partition partition)
|
||||
{
|
||||
0x2A, 0x4F, 0x53, 0x54, 0x41, 0x20, 0x55, 0x44, 0x46, 0x20, 0x43, 0x6F, 0x6D, 0x70, 0x6C, 0x69, 0x61, 0x6E,
|
||||
0x74, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
// UDF needs at least that
|
||||
if(partition.End - partition.Start < 256) return false;
|
||||
|
||||
// UDF needs at least that
|
||||
if(imagePlugin.ImageInfo.SectorSize < 512) return false;
|
||||
|
||||
byte[] sector;
|
||||
AnchorVolumeDescriptorPointer anchor = new AnchorVolumeDescriptorPointer();
|
||||
// All positions where anchor may reside
|
||||
ulong[] positions = {256, 512, partition.End - 256, partition.End};
|
||||
bool anchorFound = false;
|
||||
|
||||
foreach(ulong position in positions.Where(position => position + partition.Start < partition.End))
|
||||
{
|
||||
sector = imagePlugin.ReadSector(position);
|
||||
anchor = new AnchorVolumeDescriptorPointer();
|
||||
IntPtr anchorPtr = Marshal.AllocHGlobal(Marshal.SizeOf(anchor));
|
||||
Marshal.Copy(sector, 0, anchorPtr, Marshal.SizeOf(anchor));
|
||||
anchor =
|
||||
(AnchorVolumeDescriptorPointer)Marshal.PtrToStructure(anchorPtr,
|
||||
typeof(AnchorVolumeDescriptorPointer));
|
||||
Marshal.FreeHGlobal(anchorPtr);
|
||||
|
||||
DicConsole.DebugWriteLine("UDF Plugin", "anchor.tag.tagIdentifier = {0}", anchor.tag.tagIdentifier);
|
||||
DicConsole.DebugWriteLine("UDF Plugin", "anchor.tag.descriptorVersion = {0}",
|
||||
anchor.tag.descriptorVersion);
|
||||
DicConsole.DebugWriteLine("UDF Plugin", "anchor.tag.tagChecksum = 0x{0:X2}", anchor.tag.tagChecksum);
|
||||
DicConsole.DebugWriteLine("UDF Plugin", "anchor.tag.reserved = {0}", anchor.tag.reserved);
|
||||
DicConsole.DebugWriteLine("UDF Plugin", "anchor.tag.tagSerialNumber = {0}", anchor.tag.tagSerialNumber);
|
||||
DicConsole.DebugWriteLine("UDF Plugin", "anchor.tag.descriptorCrc = 0x{0:X4}",
|
||||
anchor.tag.descriptorCrc);
|
||||
DicConsole.DebugWriteLine("UDF Plugin", "anchor.tag.descriptorCrcLength = {0}",
|
||||
anchor.tag.descriptorCrcLength);
|
||||
DicConsole.DebugWriteLine("UDF Plugin", "anchor.tag.tagLocation = {0}", anchor.tag.tagLocation);
|
||||
DicConsole.DebugWriteLine("UDF Plugin", "anchor.mainVolumeDescriptorSequenceExtent.length = {0}",
|
||||
anchor.mainVolumeDescriptorSequenceExtent.length);
|
||||
DicConsole.DebugWriteLine("UDF Plugin", "anchor.mainVolumeDescriptorSequenceExtent.location = {0}",
|
||||
anchor.mainVolumeDescriptorSequenceExtent.location);
|
||||
DicConsole.DebugWriteLine("UDF Plugin", "anchor.reserveVolumeDescriptorSequenceExtent.length = {0}",
|
||||
anchor.reserveVolumeDescriptorSequenceExtent.length);
|
||||
DicConsole.DebugWriteLine("UDF Plugin", "anchor.reserveVolumeDescriptorSequenceExtent.location = {0}",
|
||||
anchor.reserveVolumeDescriptorSequenceExtent.location);
|
||||
|
||||
if(anchor.tag.tagIdentifier != TagIdentifier.AnchorVolumeDescriptorPointer ||
|
||||
anchor.tag.tagLocation != position ||
|
||||
anchor.mainVolumeDescriptorSequenceExtent.location + partition.Start >= partition.End) continue;
|
||||
|
||||
anchorFound = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if(!anchorFound) return false;
|
||||
|
||||
ulong count = 0;
|
||||
|
||||
while(count < 256)
|
||||
{
|
||||
sector = imagePlugin.ReadSector(partition.Start + anchor.mainVolumeDescriptorSequenceExtent.location +
|
||||
count);
|
||||
TagIdentifier tagId = (TagIdentifier)BitConverter.ToUInt16(sector, 0);
|
||||
uint location = BitConverter.ToUInt32(sector, 0x0C);
|
||||
|
||||
if(location == partition.Start + anchor.mainVolumeDescriptorSequenceExtent.location + count)
|
||||
{
|
||||
if(tagId == TagIdentifier.TerminatingDescriptor) break;
|
||||
|
||||
if(tagId == TagIdentifier.LogicalVolumeDescriptor)
|
||||
{
|
||||
LogicalVolumeDescriptor lvd = new LogicalVolumeDescriptor();
|
||||
IntPtr lvdPtr = Marshal.AllocHGlobal(Marshal.SizeOf(lvd));
|
||||
Marshal.Copy(sector, 0, lvdPtr, Marshal.SizeOf(lvd));
|
||||
lvd = (LogicalVolumeDescriptor)Marshal.PtrToStructure(lvdPtr, typeof(LogicalVolumeDescriptor));
|
||||
Marshal.FreeHGlobal(lvdPtr);
|
||||
|
||||
return UDF_Magic.SequenceEqual(lvd.domainIdentifier.identifier);
|
||||
}
|
||||
}
|
||||
else break;
|
||||
|
||||
count++;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public override void GetInformation(ImagePlugin imagePlugin, Partition partition, out string information)
|
||||
{
|
||||
byte[] sector;
|
||||
|
||||
StringBuilder sbInformation = new StringBuilder();
|
||||
|
||||
sbInformation.AppendLine("Universal Disk Format");
|
||||
|
||||
AnchorVolumeDescriptorPointer anchor = new AnchorVolumeDescriptorPointer();
|
||||
// All positions where anchor may reside
|
||||
ulong[] positions = {256, 512, partition.End - 256, partition.End};
|
||||
|
||||
foreach(ulong position in positions)
|
||||
{
|
||||
sector = imagePlugin.ReadSector(position);
|
||||
anchor = new AnchorVolumeDescriptorPointer();
|
||||
IntPtr anchorPtr = Marshal.AllocHGlobal(Marshal.SizeOf(anchor));
|
||||
Marshal.Copy(sector, 0, anchorPtr, Marshal.SizeOf(anchor));
|
||||
anchor =
|
||||
(AnchorVolumeDescriptorPointer)Marshal.PtrToStructure(anchorPtr,
|
||||
typeof(AnchorVolumeDescriptorPointer));
|
||||
Marshal.FreeHGlobal(anchorPtr);
|
||||
|
||||
if(anchor.tag.tagIdentifier == TagIdentifier.AnchorVolumeDescriptorPointer &&
|
||||
anchor.tag.tagLocation == position &&
|
||||
anchor.mainVolumeDescriptorSequenceExtent.location + partition.Start < partition.End) break;
|
||||
}
|
||||
|
||||
ulong count = 0;
|
||||
|
||||
PrimaryVolumeDescriptor pvd = new PrimaryVolumeDescriptor();
|
||||
LogicalVolumeDescriptor lvd = new LogicalVolumeDescriptor();
|
||||
LogicalVolumeIntegrityDescriptor lvid = new LogicalVolumeIntegrityDescriptor();
|
||||
LogicalVolumeIntegrityDescriptorImplementationUse lvidiu =
|
||||
new LogicalVolumeIntegrityDescriptorImplementationUse();
|
||||
|
||||
while(count < 256)
|
||||
{
|
||||
sector = imagePlugin.ReadSector(partition.Start + anchor.mainVolumeDescriptorSequenceExtent.location +
|
||||
count);
|
||||
TagIdentifier tagId = (TagIdentifier)BitConverter.ToUInt16(sector, 0);
|
||||
uint location = BitConverter.ToUInt32(sector, 0x0C);
|
||||
|
||||
if(location == partition.Start + anchor.mainVolumeDescriptorSequenceExtent.location + count)
|
||||
{
|
||||
if(tagId == TagIdentifier.TerminatingDescriptor) break;
|
||||
|
||||
switch(tagId)
|
||||
{
|
||||
case TagIdentifier.LogicalVolumeDescriptor:
|
||||
IntPtr lvdPtr = Marshal.AllocHGlobal(Marshal.SizeOf(lvd));
|
||||
Marshal.Copy(sector, 0, lvdPtr, Marshal.SizeOf(lvd));
|
||||
lvd = (LogicalVolumeDescriptor)
|
||||
Marshal.PtrToStructure(lvdPtr, typeof(LogicalVolumeDescriptor));
|
||||
Marshal.FreeHGlobal(lvdPtr);
|
||||
break;
|
||||
case TagIdentifier.PrimaryVolumeDescriptor:
|
||||
IntPtr pvdPtr = Marshal.AllocHGlobal(Marshal.SizeOf(pvd));
|
||||
Marshal.Copy(sector, 0, pvdPtr, Marshal.SizeOf(pvd));
|
||||
pvd = (PrimaryVolumeDescriptor)
|
||||
Marshal.PtrToStructure(pvdPtr, typeof(PrimaryVolumeDescriptor));
|
||||
Marshal.FreeHGlobal(pvdPtr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else break;
|
||||
|
||||
count++;
|
||||
}
|
||||
|
||||
sector = imagePlugin.ReadSector(lvd.integritySequenceExtent.location);
|
||||
IntPtr lvidPtr = Marshal.AllocHGlobal(Marshal.SizeOf(lvid));
|
||||
Marshal.Copy(sector, 0, lvidPtr, Marshal.SizeOf(lvid));
|
||||
lvid =
|
||||
(LogicalVolumeIntegrityDescriptor)
|
||||
Marshal.PtrToStructure(lvidPtr, typeof(LogicalVolumeIntegrityDescriptor));
|
||||
Marshal.FreeHGlobal(lvidPtr);
|
||||
|
||||
if(lvid.tag.tagIdentifier == TagIdentifier.LogicalVolumeIntegrityDescriptor &&
|
||||
lvid.tag.tagLocation == lvd.integritySequenceExtent.location)
|
||||
{
|
||||
IntPtr lvidiuPtr = Marshal.AllocHGlobal(Marshal.SizeOf(lvidiu));
|
||||
Marshal.Copy(sector, (int)(lvid.numberOfPartitions * 8 + 80), lvidiuPtr, Marshal.SizeOf(lvidiu));
|
||||
lvidiu =
|
||||
(LogicalVolumeIntegrityDescriptorImplementationUse)Marshal.PtrToStructure(lvidiuPtr,
|
||||
typeof(
|
||||
LogicalVolumeIntegrityDescriptorImplementationUse
|
||||
));
|
||||
Marshal.FreeHGlobal(lvidiuPtr);
|
||||
}
|
||||
else lvid = new LogicalVolumeIntegrityDescriptor();
|
||||
|
||||
sbInformation.AppendFormat("Volume is number {0} of {1}", pvd.volumeSequenceNumber,
|
||||
pvd.maximumVolumeSequenceNumber).AppendLine();
|
||||
sbInformation.AppendFormat("Volume set identifier: {0}",
|
||||
StringHandlers.DecompressUnicode(pvd.volumeSetIdentifier)).AppendLine();
|
||||
sbInformation
|
||||
.AppendFormat("Volume name: {0}", StringHandlers.DecompressUnicode(lvd.logicalVolumeIdentifier))
|
||||
.AppendLine();
|
||||
sbInformation.AppendFormat("Volume uses {0} bytes per block", lvd.logicalBlockSize).AppendLine();
|
||||
sbInformation.AppendFormat("Volume was las written in {0}", EcmaToDateTime(lvid.recordingDateTime))
|
||||
.AppendLine();
|
||||
sbInformation.AppendFormat("Volume contains {0} partitions", lvid.numberOfPartitions).AppendLine();
|
||||
sbInformation
|
||||
.AppendFormat("Volume contains {0} files and {1} directories", lvidiu.files, lvidiu.directories)
|
||||
.AppendLine();
|
||||
sbInformation.AppendFormat("Volume conforms to {0}",
|
||||
CurrentEncoding.GetString(lvd.domainIdentifier.identifier).TrimEnd('\u0000'))
|
||||
.AppendLine();
|
||||
sbInformation.AppendFormat("Volume was last written by: {0}",
|
||||
CurrentEncoding
|
||||
.GetString(pvd.implementationIdentifier.identifier).TrimEnd('\u0000'))
|
||||
.AppendLine();
|
||||
sbInformation.AppendFormat("Volume requires UDF version {0}.{1:X2} to be read",
|
||||
Convert.ToInt32($"{(lvidiu.minimumReadUDF & 0xFF00) >> 8}", 10),
|
||||
Convert.ToInt32($"{lvidiu.minimumReadUDF & 0xFF}", 10)).AppendLine();
|
||||
sbInformation.AppendFormat("Volume requires UDF version {0}.{1:X2} to be written to",
|
||||
Convert.ToInt32($"{(lvidiu.minimumWriteUDF & 0xFF00) >> 8}", 10),
|
||||
Convert.ToInt32($"{lvidiu.minimumWriteUDF & 0xFF}", 10)).AppendLine();
|
||||
sbInformation.AppendFormat("Volume cannot be written by any UDF version higher than {0}.{1:X2}",
|
||||
Convert.ToInt32($"{(lvidiu.maximumWriteUDF & 0xFF00) >> 8}", 10),
|
||||
Convert.ToInt32($"{lvidiu.maximumWriteUDF & 0xFF}", 10)).AppendLine();
|
||||
|
||||
XmlFsType = new FileSystemType
|
||||
{
|
||||
Type =
|
||||
$"UDF v{Convert.ToInt32($"{(lvidiu.maximumWriteUDF & 0xFF00) >> 8}", 10)}.{Convert.ToInt32($"{lvidiu.maximumWriteUDF & 0xFF}", 10):X2}",
|
||||
ApplicationIdentifier =
|
||||
CurrentEncoding.GetString(pvd.implementationIdentifier.identifier).TrimEnd('\u0000'),
|
||||
ClusterSize = (int)lvd.logicalBlockSize,
|
||||
ModificationDate = EcmaToDateTime(lvid.recordingDateTime),
|
||||
ModificationDateSpecified = true,
|
||||
Files = lvidiu.files,
|
||||
FilesSpecified = true,
|
||||
VolumeName = StringHandlers.DecompressUnicode(lvd.logicalVolumeIdentifier),
|
||||
VolumeSetIdentifier = StringHandlers.DecompressUnicode(pvd.volumeSetIdentifier),
|
||||
SystemIdentifier = CurrentEncoding.GetString(pvd.implementationIdentifier.identifier).TrimEnd('\u0000')
|
||||
};
|
||||
XmlFsType.Clusters = (long)((partition.End - partition.Start + 1) * imagePlugin.ImageInfo.SectorSize /
|
||||
(ulong)XmlFsType.ClusterSize);
|
||||
|
||||
information = sbInformation.ToString();
|
||||
}
|
||||
|
||||
static DateTime EcmaToDateTime(Timestamp timestamp)
|
||||
{
|
||||
return DateHandlers.EcmaToDateTime(timestamp.typeAndZone, timestamp.year, timestamp.month, timestamp.day,
|
||||
timestamp.hour, timestamp.minute, timestamp.second,
|
||||
timestamp.centiseconds, timestamp.hundredsMicroseconds,
|
||||
timestamp.microseconds);
|
||||
}
|
||||
|
||||
public override Errno Mount()
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno Mount(bool debug)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno Unmount()
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno MapBlock(string path, long fileBlock, ref long deviceBlock)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno GetAttributes(string path, ref FileAttributes attributes)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno ListXAttr(string path, ref List<string> xattrs)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno GetXattr(string path, string xattr, ref byte[] buf)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno Read(string path, long offset, long size, ref byte[] buf)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno ReadDir(string path, ref List<string> contents)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno StatFs(ref FileSystemInfo stat)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno Stat(string path, ref FileEntryInfo stat)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno ReadLink(string path, ref string dest)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
[Flags]
|
||||
enum EntityFlags : byte
|
||||
@@ -85,15 +384,15 @@ namespace DiscImageChef.Filesystems
|
||||
struct EntityIdentifier
|
||||
{
|
||||
/// <summary>
|
||||
/// Entity flags
|
||||
/// Entity flags
|
||||
/// </summary>
|
||||
public EntityFlags flags;
|
||||
/// <summary>
|
||||
/// Structure identifier
|
||||
/// Structure identifier
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 23)] public byte[] identifier;
|
||||
/// <summary>
|
||||
/// Structure data
|
||||
/// Structure data
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] public byte[] identifierSuffix;
|
||||
}
|
||||
@@ -231,307 +530,5 @@ namespace DiscImageChef.Filesystems
|
||||
public ushort minimumWriteUDF;
|
||||
public ushort maximumWriteUDF;
|
||||
}
|
||||
|
||||
public override bool Identify(ImagePlugin imagePlugin, Partition partition)
|
||||
{
|
||||
// UDF needs at least that
|
||||
if(partition.End - partition.Start < 256) return false;
|
||||
|
||||
// UDF needs at least that
|
||||
if(imagePlugin.ImageInfo.SectorSize < 512) return false;
|
||||
|
||||
byte[] sector;
|
||||
AnchorVolumeDescriptorPointer anchor = new AnchorVolumeDescriptorPointer();
|
||||
// All positions where anchor may reside
|
||||
ulong[] positions = {256, 512, partition.End - 256, partition.End};
|
||||
bool anchorFound = false;
|
||||
|
||||
foreach(ulong position in positions.Where(position => position + partition.Start < partition.End)) {
|
||||
sector = imagePlugin.ReadSector(position);
|
||||
anchor = new AnchorVolumeDescriptorPointer();
|
||||
IntPtr anchorPtr = Marshal.AllocHGlobal(Marshal.SizeOf(anchor));
|
||||
Marshal.Copy(sector, 0, anchorPtr, Marshal.SizeOf(anchor));
|
||||
anchor =
|
||||
(AnchorVolumeDescriptorPointer)Marshal.PtrToStructure(anchorPtr,
|
||||
typeof(AnchorVolumeDescriptorPointer));
|
||||
Marshal.FreeHGlobal(anchorPtr);
|
||||
|
||||
DicConsole.DebugWriteLine("UDF Plugin", "anchor.tag.tagIdentifier = {0}", anchor.tag.tagIdentifier);
|
||||
DicConsole.DebugWriteLine("UDF Plugin", "anchor.tag.descriptorVersion = {0}",
|
||||
anchor.tag.descriptorVersion);
|
||||
DicConsole.DebugWriteLine("UDF Plugin", "anchor.tag.tagChecksum = 0x{0:X2}", anchor.tag.tagChecksum);
|
||||
DicConsole.DebugWriteLine("UDF Plugin", "anchor.tag.reserved = {0}", anchor.tag.reserved);
|
||||
DicConsole.DebugWriteLine("UDF Plugin", "anchor.tag.tagSerialNumber = {0}", anchor.tag.tagSerialNumber);
|
||||
DicConsole.DebugWriteLine("UDF Plugin", "anchor.tag.descriptorCrc = 0x{0:X4}",
|
||||
anchor.tag.descriptorCrc);
|
||||
DicConsole.DebugWriteLine("UDF Plugin", "anchor.tag.descriptorCrcLength = {0}",
|
||||
anchor.tag.descriptorCrcLength);
|
||||
DicConsole.DebugWriteLine("UDF Plugin", "anchor.tag.tagLocation = {0}", anchor.tag.tagLocation);
|
||||
DicConsole.DebugWriteLine("UDF Plugin", "anchor.mainVolumeDescriptorSequenceExtent.length = {0}",
|
||||
anchor.mainVolumeDescriptorSequenceExtent.length);
|
||||
DicConsole.DebugWriteLine("UDF Plugin", "anchor.mainVolumeDescriptorSequenceExtent.location = {0}",
|
||||
anchor.mainVolumeDescriptorSequenceExtent.location);
|
||||
DicConsole.DebugWriteLine("UDF Plugin", "anchor.reserveVolumeDescriptorSequenceExtent.length = {0}",
|
||||
anchor.reserveVolumeDescriptorSequenceExtent.length);
|
||||
DicConsole.DebugWriteLine("UDF Plugin", "anchor.reserveVolumeDescriptorSequenceExtent.location = {0}",
|
||||
anchor.reserveVolumeDescriptorSequenceExtent.location);
|
||||
|
||||
if(anchor.tag.tagIdentifier != TagIdentifier.AnchorVolumeDescriptorPointer ||
|
||||
anchor.tag.tagLocation != position ||
|
||||
anchor.mainVolumeDescriptorSequenceExtent.location + partition.Start >= partition.End) continue;
|
||||
|
||||
anchorFound = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if(!anchorFound) return false;
|
||||
|
||||
ulong count = 0;
|
||||
|
||||
while(count < 256)
|
||||
{
|
||||
sector = imagePlugin.ReadSector(partition.Start + anchor.mainVolumeDescriptorSequenceExtent.location +
|
||||
count);
|
||||
TagIdentifier tagId = (TagIdentifier)BitConverter.ToUInt16(sector, 0);
|
||||
uint location = BitConverter.ToUInt32(sector, 0x0C);
|
||||
|
||||
if(location == partition.Start + anchor.mainVolumeDescriptorSequenceExtent.location + count)
|
||||
{
|
||||
if(tagId == TagIdentifier.TerminatingDescriptor) break;
|
||||
|
||||
if(tagId == TagIdentifier.LogicalVolumeDescriptor)
|
||||
{
|
||||
LogicalVolumeDescriptor lvd = new LogicalVolumeDescriptor();
|
||||
IntPtr lvdPtr = Marshal.AllocHGlobal(Marshal.SizeOf(lvd));
|
||||
Marshal.Copy(sector, 0, lvdPtr, Marshal.SizeOf(lvd));
|
||||
lvd = (LogicalVolumeDescriptor)Marshal.PtrToStructure(lvdPtr, typeof(LogicalVolumeDescriptor));
|
||||
Marshal.FreeHGlobal(lvdPtr);
|
||||
|
||||
return UDF_Magic.SequenceEqual(lvd.domainIdentifier.identifier);
|
||||
}
|
||||
}
|
||||
else break;
|
||||
|
||||
count++;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public override void GetInformation(ImagePlugin imagePlugin, Partition partition,
|
||||
out string information)
|
||||
{
|
||||
byte[] sector;
|
||||
|
||||
StringBuilder sbInformation = new StringBuilder();
|
||||
|
||||
sbInformation.AppendLine("Universal Disk Format");
|
||||
|
||||
AnchorVolumeDescriptorPointer anchor = new AnchorVolumeDescriptorPointer();
|
||||
// All positions where anchor may reside
|
||||
ulong[] positions = {256, 512, partition.End - 256, partition.End};
|
||||
|
||||
foreach(ulong position in positions)
|
||||
{
|
||||
sector = imagePlugin.ReadSector(position);
|
||||
anchor = new AnchorVolumeDescriptorPointer();
|
||||
IntPtr anchorPtr = Marshal.AllocHGlobal(Marshal.SizeOf(anchor));
|
||||
Marshal.Copy(sector, 0, anchorPtr, Marshal.SizeOf(anchor));
|
||||
anchor =
|
||||
(AnchorVolumeDescriptorPointer)Marshal.PtrToStructure(anchorPtr,
|
||||
typeof(AnchorVolumeDescriptorPointer));
|
||||
Marshal.FreeHGlobal(anchorPtr);
|
||||
|
||||
if(anchor.tag.tagIdentifier == TagIdentifier.AnchorVolumeDescriptorPointer &&
|
||||
anchor.tag.tagLocation == position &&
|
||||
anchor.mainVolumeDescriptorSequenceExtent.location + partition.Start < partition.End) break;
|
||||
}
|
||||
|
||||
ulong count = 0;
|
||||
|
||||
PrimaryVolumeDescriptor pvd = new PrimaryVolumeDescriptor();
|
||||
LogicalVolumeDescriptor lvd = new LogicalVolumeDescriptor();
|
||||
LogicalVolumeIntegrityDescriptor lvid = new LogicalVolumeIntegrityDescriptor();
|
||||
LogicalVolumeIntegrityDescriptorImplementationUse lvidiu =
|
||||
new LogicalVolumeIntegrityDescriptorImplementationUse();
|
||||
|
||||
while(count < 256)
|
||||
{
|
||||
sector = imagePlugin.ReadSector(partition.Start + anchor.mainVolumeDescriptorSequenceExtent.location +
|
||||
count);
|
||||
TagIdentifier tagId = (TagIdentifier)BitConverter.ToUInt16(sector, 0);
|
||||
uint location = BitConverter.ToUInt32(sector, 0x0C);
|
||||
|
||||
if(location == partition.Start + anchor.mainVolumeDescriptorSequenceExtent.location + count)
|
||||
{
|
||||
if(tagId == TagIdentifier.TerminatingDescriptor) break;
|
||||
|
||||
switch(tagId) {
|
||||
case TagIdentifier.LogicalVolumeDescriptor:
|
||||
IntPtr lvdPtr = Marshal.AllocHGlobal(Marshal.SizeOf(lvd));
|
||||
Marshal.Copy(sector, 0, lvdPtr, Marshal.SizeOf(lvd));
|
||||
lvd = (LogicalVolumeDescriptor)Marshal.PtrToStructure(lvdPtr, typeof(LogicalVolumeDescriptor));
|
||||
Marshal.FreeHGlobal(lvdPtr);
|
||||
break;
|
||||
case TagIdentifier.PrimaryVolumeDescriptor:
|
||||
IntPtr pvdPtr = Marshal.AllocHGlobal(Marshal.SizeOf(pvd));
|
||||
Marshal.Copy(sector, 0, pvdPtr, Marshal.SizeOf(pvd));
|
||||
pvd = (PrimaryVolumeDescriptor)Marshal.PtrToStructure(pvdPtr, typeof(PrimaryVolumeDescriptor));
|
||||
Marshal.FreeHGlobal(pvdPtr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else break;
|
||||
|
||||
count++;
|
||||
}
|
||||
|
||||
sector = imagePlugin.ReadSector(lvd.integritySequenceExtent.location);
|
||||
IntPtr lvidPtr = Marshal.AllocHGlobal(Marshal.SizeOf(lvid));
|
||||
Marshal.Copy(sector, 0, lvidPtr, Marshal.SizeOf(lvid));
|
||||
lvid =
|
||||
(LogicalVolumeIntegrityDescriptor)
|
||||
Marshal.PtrToStructure(lvidPtr, typeof(LogicalVolumeIntegrityDescriptor));
|
||||
Marshal.FreeHGlobal(lvidPtr);
|
||||
|
||||
if(lvid.tag.tagIdentifier == TagIdentifier.LogicalVolumeIntegrityDescriptor &&
|
||||
lvid.tag.tagLocation == lvd.integritySequenceExtent.location)
|
||||
{
|
||||
IntPtr lvidiuPtr = Marshal.AllocHGlobal(Marshal.SizeOf(lvidiu));
|
||||
Marshal.Copy(sector, (int)(lvid.numberOfPartitions * 8 + 80), lvidiuPtr, Marshal.SizeOf(lvidiu));
|
||||
lvidiu =
|
||||
(LogicalVolumeIntegrityDescriptorImplementationUse)Marshal.PtrToStructure(lvidiuPtr,
|
||||
typeof(
|
||||
LogicalVolumeIntegrityDescriptorImplementationUse
|
||||
));
|
||||
Marshal.FreeHGlobal(lvidiuPtr);
|
||||
}
|
||||
else lvid = new LogicalVolumeIntegrityDescriptor();
|
||||
|
||||
sbInformation.AppendFormat("Volume is number {0} of {1}", pvd.volumeSequenceNumber,
|
||||
pvd.maximumVolumeSequenceNumber).AppendLine();
|
||||
sbInformation.AppendFormat("Volume set identifier: {0}",
|
||||
StringHandlers.DecompressUnicode(pvd.volumeSetIdentifier)).AppendLine();
|
||||
sbInformation
|
||||
.AppendFormat("Volume name: {0}", StringHandlers.DecompressUnicode(lvd.logicalVolumeIdentifier))
|
||||
.AppendLine();
|
||||
sbInformation.AppendFormat("Volume uses {0} bytes per block", lvd.logicalBlockSize).AppendLine();
|
||||
sbInformation.AppendFormat("Volume was las written in {0}", EcmaToDateTime(lvid.recordingDateTime))
|
||||
.AppendLine();
|
||||
sbInformation.AppendFormat("Volume contains {0} partitions", lvid.numberOfPartitions).AppendLine();
|
||||
sbInformation
|
||||
.AppendFormat("Volume contains {0} files and {1} directories", lvidiu.files, lvidiu.directories)
|
||||
.AppendLine();
|
||||
sbInformation.AppendFormat("Volume conforms to {0}",
|
||||
CurrentEncoding
|
||||
.GetString(lvd.domainIdentifier.identifier).TrimEnd('\u0000'))
|
||||
.AppendLine();
|
||||
sbInformation.AppendFormat("Volume was last written by: {0}",
|
||||
CurrentEncoding
|
||||
.GetString(pvd.implementationIdentifier.identifier)
|
||||
.TrimEnd('\u0000')).AppendLine();
|
||||
sbInformation.AppendFormat("Volume requires UDF version {0}.{1:X2} to be read",
|
||||
Convert.ToInt32($"{(lvidiu.minimumReadUDF & 0xFF00) >> 8}", 10),
|
||||
Convert.ToInt32($"{lvidiu.minimumReadUDF & 0xFF}", 10))
|
||||
.AppendLine();
|
||||
sbInformation.AppendFormat("Volume requires UDF version {0}.{1:X2} to be written to",
|
||||
Convert.ToInt32($"{(lvidiu.minimumWriteUDF & 0xFF00) >> 8}",
|
||||
10),
|
||||
Convert.ToInt32($"{lvidiu.minimumWriteUDF & 0xFF}", 10))
|
||||
.AppendLine();
|
||||
sbInformation.AppendFormat("Volume cannot be written by any UDF version higher than {0}.{1:X2}",
|
||||
Convert.ToInt32($"{(lvidiu.maximumWriteUDF & 0xFF00) >> 8}",
|
||||
10),
|
||||
Convert.ToInt32($"{lvidiu.maximumWriteUDF & 0xFF}", 10))
|
||||
.AppendLine();
|
||||
|
||||
XmlFsType = new FileSystemType
|
||||
{
|
||||
Type =
|
||||
$"UDF v{Convert.ToInt32($"{(lvidiu.maximumWriteUDF & 0xFF00) >> 8}", 10)}.{Convert.ToInt32($"{lvidiu.maximumWriteUDF & 0xFF}", 10):X2}",
|
||||
ApplicationIdentifier =
|
||||
CurrentEncoding.GetString(pvd.implementationIdentifier.identifier).TrimEnd('\u0000'),
|
||||
ClusterSize = (int)lvd.logicalBlockSize,
|
||||
ModificationDate = EcmaToDateTime(lvid.recordingDateTime),
|
||||
ModificationDateSpecified = true,
|
||||
Files = lvidiu.files,
|
||||
FilesSpecified = true,
|
||||
VolumeName = StringHandlers.DecompressUnicode(lvd.logicalVolumeIdentifier),
|
||||
VolumeSetIdentifier = StringHandlers.DecompressUnicode(pvd.volumeSetIdentifier),
|
||||
SystemIdentifier = CurrentEncoding.GetString(pvd.implementationIdentifier.identifier).TrimEnd('\u0000')
|
||||
};
|
||||
XmlFsType.Clusters = (long)((partition.End - partition.Start + 1) * imagePlugin.ImageInfo.SectorSize /
|
||||
(ulong)XmlFsType.ClusterSize);
|
||||
|
||||
information = sbInformation.ToString();
|
||||
}
|
||||
|
||||
static DateTime EcmaToDateTime(Timestamp timestamp)
|
||||
{
|
||||
return DateHandlers.EcmaToDateTime(timestamp.typeAndZone, timestamp.year, timestamp.month, timestamp.day,
|
||||
timestamp.hour, timestamp.minute, timestamp.second,
|
||||
timestamp.centiseconds, timestamp.hundredsMicroseconds,
|
||||
timestamp.microseconds);
|
||||
}
|
||||
|
||||
public override Errno Mount()
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno Mount(bool debug)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno Unmount()
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno MapBlock(string path, long fileBlock, ref long deviceBlock)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno GetAttributes(string path, ref FileAttributes attributes)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno ListXAttr(string path, ref List<string> xattrs)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno GetXattr(string path, string xattr, ref byte[] buf)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno Read(string path, long offset, long size, ref byte[] buf)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno ReadDir(string path, ref List<string> contents)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno StatFs(ref FileSystemInfo stat)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno Stat(string path, ref FileEntryInfo stat)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno ReadLink(string path, ref string dest)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -49,91 +49,11 @@ using time_t = System.Int64;
|
||||
|
||||
namespace DiscImageChef.Filesystems
|
||||
{
|
||||
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
||||
[SuppressMessage("ReSharper", "BuiltInTypeReferenceStyle")]
|
||||
public class UNICOS : Filesystem
|
||||
{
|
||||
const int NC1MAXPART = 64;
|
||||
const int NC1MAXIREG = 4;
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct nc1ireg_sb
|
||||
{
|
||||
public ushort i_unused; /* reserved */
|
||||
public ushort i_nblk; /* number of blocks */
|
||||
public uint i_sblk; /* start block number */
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct nc1fdev_sb
|
||||
{
|
||||
public long fd_name; /* Physical device name */
|
||||
public uint fd_sblk; /* Start block number */
|
||||
public uint fd_nblk; /* Number of blocks */
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = NC1MAXIREG)]
|
||||
public nc1ireg_sb[] fd_ireg; /* Inode regions */
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct UNICOS_Superblock
|
||||
{
|
||||
public ulong s_magic; /* magic number to indicate file system type */
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] public byte[] s_fname; /* file system name */
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] public byte[] s_fpack; /* file system pack name */
|
||||
public dev_t s_dev; /* major/minor device, for verification */
|
||||
|
||||
public daddr_t s_fsize; /* size in blocks of entire volume */
|
||||
public long s_isize; /* Number of total inodes */
|
||||
public long s_bigfile; /* number of bytes at which a file is big */
|
||||
public long s_bigunit; /* minimum number of blocks allocated for big files */
|
||||
public ulong s_secure; /* security: secure FS label */
|
||||
public long s_maxlvl; /* security: maximum security level */
|
||||
public long s_minlvl; /* security: minimum security level */
|
||||
public long s_valcmp; /* security: valid security compartments */
|
||||
public time_t s_time; /* last super block update */
|
||||
public blkno_t s_dboff; /* Dynamic block number */
|
||||
public ino_t s_root; /* root inode */
|
||||
public long s_error; /* Type of file system error detected */
|
||||
public blkno_t s_mapoff; /* Start map block number */
|
||||
public long s_mapblks; /* Last map block number */
|
||||
public long s_nscpys; /* Number of copies of s.b per partition */
|
||||
public long s_npart; /* Number of partitions */
|
||||
public long s_ifract; /* Ratio of inodes to blocks */
|
||||
public extent_t s_sfs; /* SFS only blocks */
|
||||
public long s_flag; /* Flag word */
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = NC1MAXPART)]
|
||||
public nc1fdev_sb[] s_part; /* Partition descriptors */
|
||||
public long s_iounit; /* Physical block size */
|
||||
public long s_numiresblks; /* number of inode reservation blocks */
|
||||
/* per region (currently 1) */
|
||||
/* 0 = 1*(AU) words, n = (n+1)*(AU) words */
|
||||
public long s_priparts; /* bitmap of primary partitions */
|
||||
public long s_priblock; /* block size of primary partition(s) */
|
||||
/* 0 = 1*512 words, n = (n+1)*512 words */
|
||||
public long s_prinblks; /* number of 512 wds blocks in primary */
|
||||
public long s_secparts; /* bitmap of secondary partitions */
|
||||
public long s_secblock; /* block size of secondary partition(s) */
|
||||
/* 0 = 1*512 words, n = (n+1)*512 words */
|
||||
public long s_secnblks; /* number of 512 wds blocks in secondary */
|
||||
public long s_sbdbparts; /* bitmap of partitions with file system data */
|
||||
/* including super blocks, dynamic block */
|
||||
/* and free block bitmaps (only primary */
|
||||
/* partitions may contain these) */
|
||||
public long s_rootdparts; /* bitmap of partitions with root directory */
|
||||
/* (only primary partitions) */
|
||||
public long s_nudparts; /* bitmap of no-user-data partitions */
|
||||
/* (only primary partitions) */
|
||||
public long s_nsema; /* SFS: # fs semaphores to allocate */
|
||||
public long s_priactive; /* bitmap of primary partitions which contain */
|
||||
/* active (up to date) dynamic blocks and */
|
||||
/* free block bitmaps. All bits set indicate */
|
||||
/* that all primary partitions are active, */
|
||||
/* and no kernel manipulation of active flag */
|
||||
/* is allowed. */
|
||||
public long s_sfs_arbiterid; /* SFS Arbiter ID */
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 91)] public long[] s_fill; /* reserved */
|
||||
}
|
||||
|
||||
const ulong UNICOS_Magic = 0x6e6331667331636e;
|
||||
const ulong UNICOS_Secure = 0xcd076d1771d670cd;
|
||||
|
||||
@@ -178,8 +98,7 @@ namespace DiscImageChef.Filesystems
|
||||
return unicosSb.s_magic == UNICOS_Magic;
|
||||
}
|
||||
|
||||
public override void GetInformation(ImagePlugin imagePlugin, Partition partition,
|
||||
out string information)
|
||||
public override void GetInformation(ImagePlugin imagePlugin, Partition partition, out string information)
|
||||
{
|
||||
information = "";
|
||||
if(imagePlugin.GetSectorSize() < 512) return;
|
||||
@@ -285,5 +204,87 @@ namespace DiscImageChef.Filesystems
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
||||
struct nc1ireg_sb
|
||||
{
|
||||
public ushort i_unused; /* reserved */
|
||||
public ushort i_nblk; /* number of blocks */
|
||||
public uint i_sblk; /* start block number */
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
||||
struct nc1fdev_sb
|
||||
{
|
||||
public long fd_name; /* Physical device name */
|
||||
public uint fd_sblk; /* Start block number */
|
||||
public uint fd_nblk; /* Number of blocks */
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = NC1MAXIREG)]
|
||||
public nc1ireg_sb[] fd_ireg; /* Inode regions */
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
||||
[SuppressMessage("ReSharper", "BuiltInTypeReferenceStyle")]
|
||||
struct UNICOS_Superblock
|
||||
{
|
||||
public ulong s_magic; /* magic number to indicate file system type */
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] public byte[] s_fname; /* file system name */
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] public byte[] s_fpack; /* file system pack name */
|
||||
public dev_t s_dev; /* major/minor device, for verification */
|
||||
|
||||
public daddr_t s_fsize; /* size in blocks of entire volume */
|
||||
public long s_isize; /* Number of total inodes */
|
||||
public long s_bigfile; /* number of bytes at which a file is big */
|
||||
public long s_bigunit; /* minimum number of blocks allocated for big files */
|
||||
public ulong s_secure; /* security: secure FS label */
|
||||
public long s_maxlvl; /* security: maximum security level */
|
||||
public long s_minlvl; /* security: minimum security level */
|
||||
public long s_valcmp; /* security: valid security compartments */
|
||||
public time_t s_time; /* last super block update */
|
||||
public blkno_t s_dboff; /* Dynamic block number */
|
||||
public ino_t s_root; /* root inode */
|
||||
public long s_error; /* Type of file system error detected */
|
||||
public blkno_t s_mapoff; /* Start map block number */
|
||||
public long s_mapblks; /* Last map block number */
|
||||
public long s_nscpys; /* Number of copies of s.b per partition */
|
||||
public long s_npart; /* Number of partitions */
|
||||
public long s_ifract; /* Ratio of inodes to blocks */
|
||||
public extent_t s_sfs; /* SFS only blocks */
|
||||
public long s_flag; /* Flag word */
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = NC1MAXPART)]
|
||||
public nc1fdev_sb[] s_part; /* Partition descriptors */
|
||||
public long s_iounit; /* Physical block size */
|
||||
public long s_numiresblks; /* number of inode reservation blocks */
|
||||
/* per region (currently 1) */
|
||||
/* 0 = 1*(AU) words, n = (n+1)*(AU) words */
|
||||
public long s_priparts; /* bitmap of primary partitions */
|
||||
public long s_priblock; /* block size of primary partition(s) */
|
||||
/* 0 = 1*512 words, n = (n+1)*512 words */
|
||||
public long s_prinblks; /* number of 512 wds blocks in primary */
|
||||
public long s_secparts; /* bitmap of secondary partitions */
|
||||
public long s_secblock; /* block size of secondary partition(s) */
|
||||
/* 0 = 1*512 words, n = (n+1)*512 words */
|
||||
public long s_secnblks; /* number of 512 wds blocks in secondary */
|
||||
public long s_sbdbparts; /* bitmap of partitions with file system data */
|
||||
/* including super blocks, dynamic block */
|
||||
/* and free block bitmaps (only primary */
|
||||
/* partitions may contain these) */
|
||||
public long s_rootdparts; /* bitmap of partitions with root directory */
|
||||
/* (only primary partitions) */
|
||||
public long s_nudparts; /* bitmap of no-user-data partitions */
|
||||
/* (only primary partitions) */
|
||||
public long s_nsema; /* SFS: # fs semaphores to allocate */
|
||||
public long s_priactive; /* bitmap of primary partitions which contain */
|
||||
/* active (up to date) dynamic blocks and */
|
||||
/* free block bitmaps. All bits set indicate */
|
||||
/* that all primary partitions are active, */
|
||||
/* and no kernel manipulation of active flag */
|
||||
/* is allowed. */
|
||||
public long s_sfs_arbiterid; /* SFS Arbiter ID */
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 91)] public long[] s_fill; /* reserved */
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -77,8 +77,7 @@ namespace DiscImageChef.Filesystems
|
||||
return magic == BFS_MAGIC;
|
||||
}
|
||||
|
||||
public override void GetInformation(ImagePlugin imagePlugin, Partition partition,
|
||||
out string information)
|
||||
public override void GetInformation(ImagePlugin imagePlugin, Partition partition, out string information)
|
||||
{
|
||||
information = "";
|
||||
|
||||
@@ -127,28 +126,6 @@ namespace DiscImageChef.Filesystems
|
||||
information = sb.ToString();
|
||||
}
|
||||
|
||||
struct BFSSuperBlock
|
||||
{
|
||||
/// <summary>0x00, 0x1BADFACE</summary>
|
||||
public uint s_magic;
|
||||
/// <summary>0x04, start in bytes of volume</summary>
|
||||
public uint s_start;
|
||||
/// <summary>0x08, end in bytes of volume</summary>
|
||||
public uint s_end;
|
||||
/// <summary>0x0C, unknown :p</summary>
|
||||
public uint s_from;
|
||||
/// <summary>0x10, unknown :p</summary>
|
||||
public uint s_to;
|
||||
/// <summary>0x14, unknown :p</summary>
|
||||
public int s_bfrom;
|
||||
/// <summary>0x18, unknown :p</summary>
|
||||
public int s_bto;
|
||||
/// <summary>0x1C, 6 bytes, filesystem name</summary>
|
||||
public string s_fsname;
|
||||
/// <summary>0x22, 6 bytes, volume name</summary>
|
||||
public string s_volume;
|
||||
}
|
||||
|
||||
public override Errno Mount()
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
@@ -208,5 +185,27 @@ namespace DiscImageChef.Filesystems
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
struct BFSSuperBlock
|
||||
{
|
||||
/// <summary>0x00, 0x1BADFACE</summary>
|
||||
public uint s_magic;
|
||||
/// <summary>0x04, start in bytes of volume</summary>
|
||||
public uint s_start;
|
||||
/// <summary>0x08, end in bytes of volume</summary>
|
||||
public uint s_end;
|
||||
/// <summary>0x0C, unknown :p</summary>
|
||||
public uint s_from;
|
||||
/// <summary>0x10, unknown :p</summary>
|
||||
public uint s_to;
|
||||
/// <summary>0x14, unknown :p</summary>
|
||||
public int s_bfrom;
|
||||
/// <summary>0x18, unknown :p</summary>
|
||||
public int s_bto;
|
||||
/// <summary>0x1C, 6 bytes, filesystem name</summary>
|
||||
public string s_fsname;
|
||||
/// <summary>0x22, 6 bytes, volume name</summary>
|
||||
public string s_volume;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -42,6 +42,12 @@ namespace DiscImageChef.Filesystems
|
||||
{
|
||||
public class VMfs : Filesystem
|
||||
{
|
||||
/// <summary>
|
||||
/// Identifier for VMfs
|
||||
/// </summary>
|
||||
const uint VMFS_MAGIC = 0xC001D00D;
|
||||
const uint VMFS_BASE = 0x00100000;
|
||||
|
||||
public VMfs()
|
||||
{
|
||||
Name = "VMware filesystem";
|
||||
@@ -63,36 +69,6 @@ namespace DiscImageChef.Filesystems
|
||||
CurrentEncoding = encoding ?? Encoding.UTF8;
|
||||
}
|
||||
|
||||
[Flags]
|
||||
enum VMfsFlags : byte
|
||||
{
|
||||
RecyledFolder = 64,
|
||||
CaseSensitive = 128
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct VolumeInfo
|
||||
{
|
||||
public uint magic;
|
||||
public uint version;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)] public byte[] unknown1;
|
||||
public byte lun;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] public byte[] unknown2;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 28)] public byte[] name;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 49)] public byte[] unknown3;
|
||||
public uint size;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 31)] public byte[] unknown4;
|
||||
public Guid uuid;
|
||||
public ulong ctime;
|
||||
public ulong mtime;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Identifier for VMfs
|
||||
/// </summary>
|
||||
const uint VMFS_MAGIC = 0xC001D00D;
|
||||
const uint VMFS_BASE = 0x00100000;
|
||||
|
||||
public override bool Identify(ImagePlugin imagePlugin, Partition partition)
|
||||
{
|
||||
if(partition.Start >= partition.End) return false;
|
||||
@@ -108,8 +84,7 @@ namespace DiscImageChef.Filesystems
|
||||
return magic == VMFS_MAGIC;
|
||||
}
|
||||
|
||||
public override void GetInformation(ImagePlugin imagePlugin, Partition partition,
|
||||
out string information)
|
||||
public override void GetInformation(ImagePlugin imagePlugin, Partition partition, out string information)
|
||||
{
|
||||
ulong vmfsSuperOff = VMFS_BASE / imagePlugin.ImageInfo.SectorSize;
|
||||
byte[] sector = imagePlugin.ReadSector(partition.Start + vmfsSuperOff);
|
||||
@@ -214,5 +189,29 @@ namespace DiscImageChef.Filesystems
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
[Flags]
|
||||
enum VMfsFlags : byte
|
||||
{
|
||||
RecyledFolder = 64,
|
||||
CaseSensitive = 128
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct VolumeInfo
|
||||
{
|
||||
public uint magic;
|
||||
public uint version;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)] public byte[] unknown1;
|
||||
public byte lun;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] public byte[] unknown2;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 28)] public byte[] name;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 49)] public byte[] unknown3;
|
||||
public uint size;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 31)] public byte[] unknown4;
|
||||
public Guid uuid;
|
||||
public ulong ctime;
|
||||
public ulong mtime;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -42,6 +42,12 @@ namespace DiscImageChef.Filesystems
|
||||
{
|
||||
public class VxFS : Filesystem
|
||||
{
|
||||
/// <summary>
|
||||
/// Identifier for VxFS
|
||||
/// </summary>
|
||||
const uint VXFS_MAGIC = 0xA501FCF5;
|
||||
const uint VXFS_BASE = 0x400;
|
||||
|
||||
public VxFS()
|
||||
{
|
||||
Name = "Veritas filesystem";
|
||||
@@ -63,6 +69,125 @@ namespace DiscImageChef.Filesystems
|
||||
CurrentEncoding = encoding ?? Encoding.UTF8;
|
||||
}
|
||||
|
||||
public override bool Identify(ImagePlugin imagePlugin, Partition partition)
|
||||
{
|
||||
ulong vmfsSuperOff = VXFS_BASE / imagePlugin.ImageInfo.SectorSize;
|
||||
|
||||
if(partition.Start + vmfsSuperOff >= partition.End) return false;
|
||||
|
||||
byte[] sector = imagePlugin.ReadSector(partition.Start + vmfsSuperOff);
|
||||
|
||||
uint magic = BitConverter.ToUInt32(sector, 0x00);
|
||||
|
||||
return magic == VXFS_MAGIC;
|
||||
}
|
||||
|
||||
public override void GetInformation(ImagePlugin imagePlugin, Partition partition, out string information)
|
||||
{
|
||||
ulong vmfsSuperOff = VXFS_BASE / imagePlugin.ImageInfo.SectorSize;
|
||||
byte[] sector = imagePlugin.ReadSector(partition.Start + vmfsSuperOff);
|
||||
|
||||
VxSuperBlock vxSb = new VxSuperBlock();
|
||||
IntPtr vxSbPtr = Marshal.AllocHGlobal(Marshal.SizeOf(vxSb));
|
||||
Marshal.Copy(sector, 0, vxSbPtr, Marshal.SizeOf(vxSb));
|
||||
vxSb = (VxSuperBlock)Marshal.PtrToStructure(vxSbPtr, typeof(VxSuperBlock));
|
||||
Marshal.FreeHGlobal(vxSbPtr);
|
||||
|
||||
StringBuilder sbInformation = new StringBuilder();
|
||||
|
||||
sbInformation.AppendLine("Veritas file system");
|
||||
|
||||
sbInformation.AppendFormat("Volume version {0}", vxSb.vs_version).AppendLine();
|
||||
sbInformation.AppendFormat("Volume name {0}", StringHandlers.CToString(vxSb.vs_fname, CurrentEncoding))
|
||||
.AppendLine();
|
||||
sbInformation.AppendFormat("Volume has {0} blocks of {1} bytes each", vxSb.vs_bsize, vxSb.vs_size)
|
||||
.AppendLine();
|
||||
sbInformation.AppendFormat("Volume has {0} inodes per block", vxSb.vs_inopb).AppendLine();
|
||||
sbInformation.AppendFormat("Volume has {0} free inodes", vxSb.vs_ifree).AppendLine();
|
||||
sbInformation.AppendFormat("Volume has {0} free blocks", vxSb.vs_free).AppendLine();
|
||||
sbInformation.AppendFormat("Volume created on {0}",
|
||||
DateHandlers.UnixUnsignedToDateTime(vxSb.vs_ctime, vxSb.vs_cutime)).AppendLine();
|
||||
sbInformation.AppendFormat("Volume last modified on {0}",
|
||||
DateHandlers.UnixUnsignedToDateTime(vxSb.vs_wtime, vxSb.vs_wutime)).AppendLine();
|
||||
if(vxSb.vs_clean != 0) sbInformation.AppendLine("Volume is dirty");
|
||||
|
||||
information = sbInformation.ToString();
|
||||
|
||||
XmlFsType = new FileSystemType
|
||||
{
|
||||
Type = "Veritas file system",
|
||||
CreationDate = DateHandlers.UnixUnsignedToDateTime(vxSb.vs_ctime, vxSb.vs_cutime),
|
||||
CreationDateSpecified = true,
|
||||
ModificationDate = DateHandlers.UnixUnsignedToDateTime(vxSb.vs_wtime, vxSb.vs_wutime),
|
||||
ModificationDateSpecified = true,
|
||||
Clusters = vxSb.vs_size,
|
||||
ClusterSize = vxSb.vs_bsize,
|
||||
Dirty = vxSb.vs_clean != 0,
|
||||
FreeClusters = vxSb.vs_free,
|
||||
FreeClustersSpecified = true
|
||||
};
|
||||
}
|
||||
|
||||
public override Errno Mount()
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno Mount(bool debug)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno Unmount()
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno MapBlock(string path, long fileBlock, ref long deviceBlock)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno GetAttributes(string path, ref FileAttributes attributes)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno ListXAttr(string path, ref List<string> xattrs)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno GetXattr(string path, string xattr, ref byte[] buf)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno Read(string path, long offset, long size, ref byte[] buf)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno ReadDir(string path, ref List<string> contents)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno StatFs(ref FileSystemInfo stat)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno Stat(string path, ref FileEntryInfo stat)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno ReadLink(string path, ref string dest)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct VxSuperBlock
|
||||
{
|
||||
@@ -205,131 +330,5 @@ namespace DiscImageChef.Filesystems
|
||||
/// <summary>checksum of V2 RO</summary>
|
||||
public int vs_checksum2;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Identifier for VxFS
|
||||
/// </summary>
|
||||
const uint VXFS_MAGIC = 0xA501FCF5;
|
||||
const uint VXFS_Base = 0x400;
|
||||
|
||||
public override bool Identify(ImagePlugin imagePlugin, Partition partition)
|
||||
{
|
||||
ulong vmfsSuperOff = VXFS_Base / imagePlugin.ImageInfo.SectorSize;
|
||||
|
||||
if(partition.Start + vmfsSuperOff >= partition.End) return false;
|
||||
|
||||
byte[] sector = imagePlugin.ReadSector(partition.Start + vmfsSuperOff);
|
||||
|
||||
uint magic = BitConverter.ToUInt32(sector, 0x00);
|
||||
|
||||
return magic == VXFS_MAGIC;
|
||||
}
|
||||
|
||||
public override void GetInformation(ImagePlugin imagePlugin, Partition partition,
|
||||
out string information)
|
||||
{
|
||||
ulong vmfsSuperOff = VXFS_Base / imagePlugin.ImageInfo.SectorSize;
|
||||
byte[] sector = imagePlugin.ReadSector(partition.Start + vmfsSuperOff);
|
||||
|
||||
VxSuperBlock vxSb = new VxSuperBlock();
|
||||
IntPtr vxSbPtr = Marshal.AllocHGlobal(Marshal.SizeOf(vxSb));
|
||||
Marshal.Copy(sector, 0, vxSbPtr, Marshal.SizeOf(vxSb));
|
||||
vxSb = (VxSuperBlock)Marshal.PtrToStructure(vxSbPtr, typeof(VxSuperBlock));
|
||||
Marshal.FreeHGlobal(vxSbPtr);
|
||||
|
||||
StringBuilder sbInformation = new StringBuilder();
|
||||
|
||||
sbInformation.AppendLine("Veritas file system");
|
||||
|
||||
sbInformation.AppendFormat("Volume version {0}", vxSb.vs_version).AppendLine();
|
||||
sbInformation.AppendFormat("Volume name {0}", StringHandlers.CToString(vxSb.vs_fname, CurrentEncoding))
|
||||
.AppendLine();
|
||||
sbInformation.AppendFormat("Volume has {0} blocks of {1} bytes each", vxSb.vs_bsize, vxSb.vs_size)
|
||||
.AppendLine();
|
||||
sbInformation.AppendFormat("Volume has {0} inodes per block", vxSb.vs_inopb).AppendLine();
|
||||
sbInformation.AppendFormat("Volume has {0} free inodes", vxSb.vs_ifree).AppendLine();
|
||||
sbInformation.AppendFormat("Volume has {0} free blocks", vxSb.vs_free).AppendLine();
|
||||
sbInformation.AppendFormat("Volume created on {0}",
|
||||
DateHandlers.UnixUnsignedToDateTime(vxSb.vs_ctime, vxSb.vs_cutime)).AppendLine();
|
||||
sbInformation.AppendFormat("Volume last modified on {0}",
|
||||
DateHandlers.UnixUnsignedToDateTime(vxSb.vs_wtime, vxSb.vs_wutime)).AppendLine();
|
||||
if(vxSb.vs_clean != 0) sbInformation.AppendLine("Volume is dirty");
|
||||
|
||||
information = sbInformation.ToString();
|
||||
|
||||
XmlFsType = new FileSystemType
|
||||
{
|
||||
Type = "Veritas file system",
|
||||
CreationDate = DateHandlers.UnixUnsignedToDateTime(vxSb.vs_ctime, vxSb.vs_cutime),
|
||||
CreationDateSpecified = true,
|
||||
ModificationDate = DateHandlers.UnixUnsignedToDateTime(vxSb.vs_wtime, vxSb.vs_wutime),
|
||||
ModificationDateSpecified = true,
|
||||
Clusters = vxSb.vs_size,
|
||||
ClusterSize = vxSb.vs_bsize,
|
||||
Dirty = vxSb.vs_clean != 0,
|
||||
FreeClusters = vxSb.vs_free,
|
||||
FreeClustersSpecified = true
|
||||
};
|
||||
}
|
||||
|
||||
public override Errno Mount()
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno Mount(bool debug)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno Unmount()
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno MapBlock(string path, long fileBlock, ref long deviceBlock)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno GetAttributes(string path, ref FileAttributes attributes)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno ListXAttr(string path, ref List<string> xattrs)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno GetXattr(string path, string xattr, ref byte[] buf)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno Read(string path, long offset, long size, ref byte[] buf)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno ReadDir(string path, ref List<string> contents)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno StatFs(ref FileSystemInfo stat)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno Stat(string path, ref FileEntryInfo stat)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno ReadLink(string path, ref string dest)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -43,67 +43,6 @@ namespace DiscImageChef.Filesystems
|
||||
{
|
||||
public class XFS : Filesystem
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct XFS_Superblock
|
||||
{
|
||||
public uint magicnum;
|
||||
public uint blocksize;
|
||||
public ulong dblocks;
|
||||
public ulong rblocks;
|
||||
public ulong rextents;
|
||||
public Guid uuid;
|
||||
public ulong logstat;
|
||||
public ulong rootino;
|
||||
public ulong rbmino;
|
||||
public ulong rsumino;
|
||||
public uint rextsize;
|
||||
public uint agblocks;
|
||||
public uint agcount;
|
||||
public uint rbmblocks;
|
||||
public uint logblocks;
|
||||
public ushort version;
|
||||
public ushort sectsize;
|
||||
public ushort inodesize;
|
||||
public ushort inopblock;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)] public byte[] fname;
|
||||
public byte blocklog;
|
||||
public byte sectlog;
|
||||
public byte inodelog;
|
||||
public byte inopblog;
|
||||
public byte agblklog;
|
||||
public byte rextslog;
|
||||
public byte inprogress;
|
||||
public byte imax_pct;
|
||||
public ulong icount;
|
||||
public ulong ifree;
|
||||
public ulong fdblocks;
|
||||
public ulong frextents;
|
||||
public ulong uquotino;
|
||||
public ulong gquotino;
|
||||
public ushort qflags;
|
||||
public byte flags;
|
||||
public byte shared_vn;
|
||||
public ulong inoalignmt;
|
||||
public ulong unit;
|
||||
public ulong width;
|
||||
public byte dirblklog;
|
||||
public byte logsectlog;
|
||||
public ushort logsectsize;
|
||||
public uint logsunit;
|
||||
public uint features2;
|
||||
public uint bad_features2;
|
||||
public uint features_compat;
|
||||
public uint features_ro_compat;
|
||||
public uint features_incompat;
|
||||
public uint features_log_incompat;
|
||||
// This field is little-endian while rest of superblock is big-endian
|
||||
public uint crc;
|
||||
public uint spino_align;
|
||||
public ulong pquotino;
|
||||
public ulong lsn;
|
||||
public Guid meta_uuid;
|
||||
}
|
||||
|
||||
const uint XFS_MAGIC = 0x58465342;
|
||||
|
||||
public XFS()
|
||||
@@ -178,8 +117,7 @@ namespace DiscImageChef.Filesystems
|
||||
return false;
|
||||
}
|
||||
|
||||
public override void GetInformation(ImagePlugin imagePlugin, Partition partition,
|
||||
out string information)
|
||||
public override void GetInformation(ImagePlugin imagePlugin, Partition partition, out string information)
|
||||
{
|
||||
information = "";
|
||||
if(imagePlugin.GetSectorSize() < 512) return;
|
||||
@@ -319,5 +257,66 @@ namespace DiscImageChef.Filesystems
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct XFS_Superblock
|
||||
{
|
||||
public uint magicnum;
|
||||
public uint blocksize;
|
||||
public ulong dblocks;
|
||||
public ulong rblocks;
|
||||
public ulong rextents;
|
||||
public Guid uuid;
|
||||
public ulong logstat;
|
||||
public ulong rootino;
|
||||
public ulong rbmino;
|
||||
public ulong rsumino;
|
||||
public uint rextsize;
|
||||
public uint agblocks;
|
||||
public uint agcount;
|
||||
public uint rbmblocks;
|
||||
public uint logblocks;
|
||||
public ushort version;
|
||||
public ushort sectsize;
|
||||
public ushort inodesize;
|
||||
public ushort inopblock;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)] public byte[] fname;
|
||||
public byte blocklog;
|
||||
public byte sectlog;
|
||||
public byte inodelog;
|
||||
public byte inopblog;
|
||||
public byte agblklog;
|
||||
public byte rextslog;
|
||||
public byte inprogress;
|
||||
public byte imax_pct;
|
||||
public ulong icount;
|
||||
public ulong ifree;
|
||||
public ulong fdblocks;
|
||||
public ulong frextents;
|
||||
public ulong uquotino;
|
||||
public ulong gquotino;
|
||||
public ushort qflags;
|
||||
public byte flags;
|
||||
public byte shared_vn;
|
||||
public ulong inoalignmt;
|
||||
public ulong unit;
|
||||
public ulong width;
|
||||
public byte dirblklog;
|
||||
public byte logsectlog;
|
||||
public ushort logsectsize;
|
||||
public uint logsunit;
|
||||
public uint features2;
|
||||
public uint bad_features2;
|
||||
public uint features_compat;
|
||||
public uint features_ro_compat;
|
||||
public uint features_incompat;
|
||||
public uint features_log_incompat;
|
||||
// This field is little-endian while rest of superblock is big-endian
|
||||
public uint crc;
|
||||
public uint spino_align;
|
||||
public ulong pquotino;
|
||||
public ulong lsn;
|
||||
public Guid meta_uuid;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -66,164 +66,14 @@ namespace DiscImageChef.Filesystems
|
||||
const ulong ZEC_MAGIC = 0x0210DA7AB10C7A11;
|
||||
const ulong ZEC_CIGAM = 0x117A0CB17ADA1002;
|
||||
|
||||
struct ZIO_Checksum
|
||||
{
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] public ulong[] word;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// There is an empty ZIO at sector 16 or sector 31, with magic and checksum, to detect it is really ZFS I suppose.
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct ZIO_Empty
|
||||
{
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 472)] public byte[] empty;
|
||||
public ulong magic;
|
||||
public ZIO_Checksum checksum;
|
||||
}
|
||||
|
||||
// These parameters define how the nvlist is stored
|
||||
const byte NVS_LITTLE_ENDIAN = 1;
|
||||
const byte NVS_BIG_ENDIAN = 0;
|
||||
const byte NVS_NATIVE = 0;
|
||||
const byte NVS_XDR = 1;
|
||||
|
||||
/// <summary>
|
||||
/// This structure indicates which encoding method and endianness is used to encode the nvlist
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct NVS_Method
|
||||
{
|
||||
public byte encoding;
|
||||
public byte endian;
|
||||
public byte reserved1;
|
||||
public byte reserved2;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This structure gives information about the encoded nvlist
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct NVS_XDR_Header
|
||||
{
|
||||
public NVS_Method encodingAndEndian;
|
||||
public uint version;
|
||||
public uint flags;
|
||||
}
|
||||
|
||||
enum NVS_DataTypes : uint
|
||||
{
|
||||
DATA_TYPE_UNKNOWN = 0,
|
||||
DATA_TYPE_BOOLEAN,
|
||||
DATA_TYPE_BYTE,
|
||||
DATA_TYPE_INT16,
|
||||
DATA_TYPE_UINT16,
|
||||
DATA_TYPE_INT32,
|
||||
DATA_TYPE_UINT32,
|
||||
DATA_TYPE_INT64,
|
||||
DATA_TYPE_UINT64,
|
||||
DATA_TYPE_STRING,
|
||||
DATA_TYPE_BYTE_ARRAY,
|
||||
DATA_TYPE_INT16_ARRAY,
|
||||
DATA_TYPE_UINT16_ARRAY,
|
||||
DATA_TYPE_INT32_ARRAY,
|
||||
DATA_TYPE_UINT32_ARRAY,
|
||||
DATA_TYPE_INT64_ARRAY,
|
||||
DATA_TYPE_UINT64_ARRAY,
|
||||
DATA_TYPE_STRING_ARRAY,
|
||||
DATA_TYPE_HRTIME,
|
||||
DATA_TYPE_NVLIST,
|
||||
DATA_TYPE_NVLIST_ARRAY,
|
||||
DATA_TYPE_BOOLEAN_VALUE,
|
||||
DATA_TYPE_INT8,
|
||||
DATA_TYPE_UINT8,
|
||||
DATA_TYPE_BOOLEAN_ARRAY,
|
||||
DATA_TYPE_INT8_ARRAY,
|
||||
DATA_TYPE_UINT8_ARRAY,
|
||||
DATA_TYPE_DOUBLE
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This represent an encoded nvpair (an item of an nvlist)
|
||||
/// </summary>
|
||||
struct NVS_Item
|
||||
{
|
||||
/// <summary>
|
||||
/// Size in bytes when encoded in XDR
|
||||
/// </summary>
|
||||
public uint encodedSize;
|
||||
/// <summary>
|
||||
/// Size in bytes when decoded
|
||||
/// </summary>
|
||||
public uint decodedSize;
|
||||
/// <summary>
|
||||
/// On disk, it is null-padded for alignment to 4 bytes and prepended by a 4 byte length indicator
|
||||
/// </summary>
|
||||
public string name;
|
||||
/// <summary>
|
||||
/// Data type
|
||||
/// </summary>
|
||||
public NVS_DataTypes dataType;
|
||||
/// <summary>
|
||||
/// How many elements are here
|
||||
/// </summary>
|
||||
public uint elements;
|
||||
/// <summary>
|
||||
/// On disk size is relative to <see cref="dataType"/> and <see cref="elements"/> always aligned to 4 bytes
|
||||
/// </summary>
|
||||
public object value;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct DVA
|
||||
{
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] public ulong[] word;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct SPA_BlockPointer
|
||||
{
|
||||
/// <summary>
|
||||
/// Data virtual address
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] public DVA[] dataVirtualAddress;
|
||||
/// <summary>
|
||||
/// Block properties
|
||||
/// </summary>
|
||||
public ulong properties;
|
||||
/// <summary>
|
||||
/// Reserved for future expansion
|
||||
/// </summary>
|
||||
public ulong[] padding;
|
||||
/// <summary>
|
||||
/// TXG when block was allocated
|
||||
/// </summary>
|
||||
public ulong birthTxg;
|
||||
/// <summary>
|
||||
/// Transaction group at birth
|
||||
/// </summary>
|
||||
public ulong birth;
|
||||
/// <summary>
|
||||
/// Fill count
|
||||
/// </summary>
|
||||
public ulong fill;
|
||||
public ZIO_Checksum checksum;
|
||||
}
|
||||
|
||||
const ulong UBERBLOCK_MAGIC = 0x00BAB10C;
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct ZFS_Uberblock
|
||||
{
|
||||
public ulong magic;
|
||||
public ulong spaVersion;
|
||||
public ulong lastTxg;
|
||||
public ulong guidSum;
|
||||
public ulong timestamp;
|
||||
public SPA_BlockPointer mosPtr;
|
||||
public ulong softwareVersion;
|
||||
}
|
||||
|
||||
const uint ZFS_MAGIC = 0x58465342;
|
||||
|
||||
public ZFS()
|
||||
@@ -270,8 +120,7 @@ namespace DiscImageChef.Filesystems
|
||||
return magic == ZEC_MAGIC || magic == ZEC_CIGAM;
|
||||
}
|
||||
|
||||
public override void GetInformation(ImagePlugin imagePlugin, Partition partition,
|
||||
out string information)
|
||||
public override void GetInformation(ImagePlugin imagePlugin, Partition partition, out string information)
|
||||
{
|
||||
information = "";
|
||||
if(imagePlugin.GetSectorSize() < 512) return;
|
||||
@@ -309,8 +158,7 @@ namespace DiscImageChef.Filesystems
|
||||
|
||||
XmlFsType = new FileSystemType {Type = "ZFS filesystem"};
|
||||
if(decodedNvList.TryGetValue("name", out NVS_Item tmpObj)) XmlFsType.VolumeName = (string)tmpObj.value;
|
||||
if(decodedNvList.TryGetValue("guid", out tmpObj))
|
||||
XmlFsType.VolumeSerial = $"{(ulong)tmpObj.value}";
|
||||
if(decodedNvList.TryGetValue("guid", out tmpObj)) XmlFsType.VolumeSerial = $"{(ulong)tmpObj.value}";
|
||||
if(decodedNvList.TryGetValue("pool_guid", out tmpObj))
|
||||
XmlFsType.VolumeSetIdentifier = $"{(ulong)tmpObj.value}";
|
||||
}
|
||||
@@ -639,7 +487,8 @@ namespace DiscImageChef.Filesystems
|
||||
|
||||
byte[] subListBytes = new byte[item.encodedSize - (offset - currOff)];
|
||||
Array.Copy(nvlist, offset, subListBytes, 0, subListBytes.Length);
|
||||
if(DecodeNvList(subListBytes, out Dictionary<string, NVS_Item> subList, true, littleEndian)) item.value = subList;
|
||||
if(DecodeNvList(subListBytes, out Dictionary<string, NVS_Item> subList, true, littleEndian))
|
||||
item.value = subList;
|
||||
else goto default;
|
||||
offset = (int)(currOff + item.encodedSize);
|
||||
break;
|
||||
@@ -849,5 +698,155 @@ namespace DiscImageChef.Filesystems
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
struct ZIO_Checksum
|
||||
{
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] public ulong[] word;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// There is an empty ZIO at sector 16 or sector 31, with magic and checksum, to detect it is really ZFS I suppose.
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct ZIO_Empty
|
||||
{
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 472)] public byte[] empty;
|
||||
public ulong magic;
|
||||
public ZIO_Checksum checksum;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This structure indicates which encoding method and endianness is used to encode the nvlist
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct NVS_Method
|
||||
{
|
||||
public byte encoding;
|
||||
public byte endian;
|
||||
public byte reserved1;
|
||||
public byte reserved2;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This structure gives information about the encoded nvlist
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct NVS_XDR_Header
|
||||
{
|
||||
public NVS_Method encodingAndEndian;
|
||||
public uint version;
|
||||
public uint flags;
|
||||
}
|
||||
|
||||
enum NVS_DataTypes : uint
|
||||
{
|
||||
DATA_TYPE_UNKNOWN = 0,
|
||||
DATA_TYPE_BOOLEAN,
|
||||
DATA_TYPE_BYTE,
|
||||
DATA_TYPE_INT16,
|
||||
DATA_TYPE_UINT16,
|
||||
DATA_TYPE_INT32,
|
||||
DATA_TYPE_UINT32,
|
||||
DATA_TYPE_INT64,
|
||||
DATA_TYPE_UINT64,
|
||||
DATA_TYPE_STRING,
|
||||
DATA_TYPE_BYTE_ARRAY,
|
||||
DATA_TYPE_INT16_ARRAY,
|
||||
DATA_TYPE_UINT16_ARRAY,
|
||||
DATA_TYPE_INT32_ARRAY,
|
||||
DATA_TYPE_UINT32_ARRAY,
|
||||
DATA_TYPE_INT64_ARRAY,
|
||||
DATA_TYPE_UINT64_ARRAY,
|
||||
DATA_TYPE_STRING_ARRAY,
|
||||
DATA_TYPE_HRTIME,
|
||||
DATA_TYPE_NVLIST,
|
||||
DATA_TYPE_NVLIST_ARRAY,
|
||||
DATA_TYPE_BOOLEAN_VALUE,
|
||||
DATA_TYPE_INT8,
|
||||
DATA_TYPE_UINT8,
|
||||
DATA_TYPE_BOOLEAN_ARRAY,
|
||||
DATA_TYPE_INT8_ARRAY,
|
||||
DATA_TYPE_UINT8_ARRAY,
|
||||
DATA_TYPE_DOUBLE
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This represent an encoded nvpair (an item of an nvlist)
|
||||
/// </summary>
|
||||
struct NVS_Item
|
||||
{
|
||||
/// <summary>
|
||||
/// Size in bytes when encoded in XDR
|
||||
/// </summary>
|
||||
public uint encodedSize;
|
||||
/// <summary>
|
||||
/// Size in bytes when decoded
|
||||
/// </summary>
|
||||
public uint decodedSize;
|
||||
/// <summary>
|
||||
/// On disk, it is null-padded for alignment to 4 bytes and prepended by a 4 byte length indicator
|
||||
/// </summary>
|
||||
public string name;
|
||||
/// <summary>
|
||||
/// Data type
|
||||
/// </summary>
|
||||
public NVS_DataTypes dataType;
|
||||
/// <summary>
|
||||
/// How many elements are here
|
||||
/// </summary>
|
||||
public uint elements;
|
||||
/// <summary>
|
||||
/// On disk size is relative to <see cref="dataType" /> and <see cref="elements" /> always aligned to 4 bytes
|
||||
/// </summary>
|
||||
public object value;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct DVA
|
||||
{
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] public ulong[] word;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct SPA_BlockPointer
|
||||
{
|
||||
/// <summary>
|
||||
/// Data virtual address
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] public DVA[] dataVirtualAddress;
|
||||
/// <summary>
|
||||
/// Block properties
|
||||
/// </summary>
|
||||
public ulong properties;
|
||||
/// <summary>
|
||||
/// Reserved for future expansion
|
||||
/// </summary>
|
||||
public ulong[] padding;
|
||||
/// <summary>
|
||||
/// TXG when block was allocated
|
||||
/// </summary>
|
||||
public ulong birthTxg;
|
||||
/// <summary>
|
||||
/// Transaction group at birth
|
||||
/// </summary>
|
||||
public ulong birth;
|
||||
/// <summary>
|
||||
/// Fill count
|
||||
/// </summary>
|
||||
public ulong fill;
|
||||
public ZIO_Checksum checksum;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct ZFS_Uberblock
|
||||
{
|
||||
public ulong magic;
|
||||
public ulong spaVersion;
|
||||
public ulong lastTxg;
|
||||
public ulong guidSum;
|
||||
public ulong timestamp;
|
||||
public SPA_BlockPointer mosPtr;
|
||||
public ulong softwareVersion;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -66,150 +66,39 @@ namespace DiscImageChef.Filesystems
|
||||
const int TP_BSIZE = 1024;
|
||||
|
||||
/// <summary>
|
||||
/// Dump tape header
|
||||
/// Dump tape header
|
||||
/// </summary>
|
||||
const short TS_TAPE = 1;
|
||||
/// <summary>
|
||||
/// Beginning of file record
|
||||
/// Beginning of file record
|
||||
/// </summary>
|
||||
const short TS_INODE = 2;
|
||||
/// <summary>
|
||||
/// Map of inodes on tape
|
||||
/// Map of inodes on tape
|
||||
/// </summary>
|
||||
const short TS_BITS = 3;
|
||||
/// <summary>
|
||||
/// Continuation of file record
|
||||
/// Continuation of file record
|
||||
/// </summary>
|
||||
const short TS_ADDR = 4;
|
||||
/// <summary>
|
||||
/// Map of inodes deleted since last dump
|
||||
/// Map of inodes deleted since last dump
|
||||
/// </summary>
|
||||
const short TS_END = 5;
|
||||
/// <summary>
|
||||
/// Inode bitmap
|
||||
/// Inode bitmap
|
||||
/// </summary>
|
||||
const short TS_CLRI = 6;
|
||||
const short TS_ACL = 7;
|
||||
const short TS_PCL = 8;
|
||||
|
||||
// Old 16-bit format record
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct spcl16
|
||||
{
|
||||
/// <summary>Record type</summary>
|
||||
public short c_type;
|
||||
/// <summary>Dump date</summary>
|
||||
public int c_date;
|
||||
/// <summary>Previous dump date</summary>
|
||||
public int c_ddate;
|
||||
/// <summary>Dump volume number</summary>
|
||||
public short c_volume;
|
||||
/// <summary>Logical block of this record</summary>
|
||||
public int c_tapea;
|
||||
/// <summary>Inode number</summary>
|
||||
public ushort c_inumber;
|
||||
/// <summary>Magic number</summary>
|
||||
public ushort c_magic;
|
||||
/// <summary>Record checksum</summary>
|
||||
public int c_checksum;
|
||||
// Unneeded for now
|
||||
/*
|
||||
struct dinode c_dinode;
|
||||
int c_count;
|
||||
char c_addr[BSIZE];
|
||||
*/
|
||||
}
|
||||
|
||||
// 32-bit AIX format record
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct spcl_aix
|
||||
{
|
||||
/// <summary>Record type</summary>
|
||||
public int c_type;
|
||||
/// <summary>Dump date</summary>
|
||||
public int c_date;
|
||||
/// <summary>Previous dump date</summary>
|
||||
public int c_ddate;
|
||||
/// <summary>Dump volume number</summary>
|
||||
public int c_volume;
|
||||
/// <summary>Logical block of this record</summary>
|
||||
public int c_tapea;
|
||||
public uint c_inumber;
|
||||
public uint c_magic;
|
||||
public int c_checksum;
|
||||
// Unneeded for now
|
||||
/*
|
||||
public bsd_dinode bsd_c_dinode;
|
||||
public int c_count;
|
||||
public char c_addr[TP_NINDIR];
|
||||
public int xix_flag;
|
||||
public dinode xix_dinode;
|
||||
*/
|
||||
}
|
||||
|
||||
const int TP_NINDIR = TP_BSIZE / 2;
|
||||
const int LBLSIZE = 16;
|
||||
const int NAMELEN = 64;
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct s_spcl
|
||||
{
|
||||
public int c_type; /* record type (see below) */
|
||||
public int c_date; /* date of this dump */
|
||||
public int c_ddate; /* date of previous dump */
|
||||
public int c_volume; /* dump volume number */
|
||||
public int c_tapea; /* logical block of this record */
|
||||
public uint c_inumber; /* number of inode */
|
||||
public int c_magic; /* magic number (see above) */
|
||||
public int c_checksum; /* record checksum */
|
||||
public dinode c_dinode; /* ownership and mode of inode */
|
||||
public int c_count; /* number of valid c_addr entries */
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = TP_NINDIR)]
|
||||
public byte[] c_addr; /* 1 => data; 0 => hole in inode */
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = LBLSIZE)] public byte[] c_label; /* dump label */
|
||||
public int c_level; /* level of this dump */
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = NAMELEN)]
|
||||
public byte[] c_filesys; /* name of dumpped file system */
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = NAMELEN)] public byte[] c_dev; /* name of dumpped device */
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = NAMELEN)] public byte[] c_host; /* name of dumpped host */
|
||||
public int c_flags; /* additional information */
|
||||
public int c_firstrec; /* first record on volume */
|
||||
public long c_ndate; /* date of this dump */
|
||||
public long c_nddate; /* date of previous dump */
|
||||
public long c_ntapea; /* logical block of this record */
|
||||
public long c_nfirstrec; /* first record on volume */
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] public int[] c_spare; /* reserved for future uses */
|
||||
}
|
||||
|
||||
const int NDADDR = 12;
|
||||
const int NIADDR = 3;
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct dinode
|
||||
{
|
||||
public ushort di_mode; /* 0: IFMT, permissions; see below. */
|
||||
public short di_nlink; /* 2: File link count. */
|
||||
public int inumber; /* 4: Lfs: inode number. */
|
||||
public ulong di_size; /* 8: File byte count. */
|
||||
public int di_atime; /* 16: Last access time. */
|
||||
public int di_atimensec; /* 20: Last access time. */
|
||||
public int di_mtime; /* 24: Last modified time. */
|
||||
public int di_mtimensec; /* 28: Last modified time. */
|
||||
public int di_ctime; /* 32: Last inode change time. */
|
||||
public int di_ctimensec; /* 36: Last inode change time. */
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = NDADDR)]
|
||||
public ufs_daddr_t[] di_db; /* 40: Direct disk blocks. */
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = NIADDR)]
|
||||
public ufs_daddr_t[] di_ib; /* 88: Indirect disk blocks. */
|
||||
public uint di_flags; /* 100: Status flags (chflags). */
|
||||
public uint di_blocks; /* 104: Blocks actually held. */
|
||||
public int di_gen; /* 108: Generation number. */
|
||||
public uint di_uid; /* 112: File owner. */
|
||||
public uint di_gid; /* 116: File group. */
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
|
||||
public int[] di_spare; /* 120: Reserved; currently unused */
|
||||
}
|
||||
|
||||
public dump()
|
||||
{
|
||||
Name = "dump(8) Plugin";
|
||||
@@ -272,8 +161,7 @@ namespace DiscImageChef.Filesystems
|
||||
newHdr.c_magic == NFS_CIGAM || newHdr.c_magic == UFS2_MAGIC || newHdr.c_magic == UFS2_CIGAM;
|
||||
}
|
||||
|
||||
public override void GetInformation(ImagePlugin imagePlugin, Partition partition,
|
||||
out string information)
|
||||
public override void GetInformation(ImagePlugin imagePlugin, Partition partition, out string information)
|
||||
{
|
||||
information = "";
|
||||
if(imagePlugin.GetSectorSize() < 512) return;
|
||||
@@ -482,5 +370,116 @@ namespace DiscImageChef.Filesystems
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
// Old 16-bit format record
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct spcl16
|
||||
{
|
||||
/// <summary>Record type</summary>
|
||||
public short c_type;
|
||||
/// <summary>Dump date</summary>
|
||||
public int c_date;
|
||||
/// <summary>Previous dump date</summary>
|
||||
public int c_ddate;
|
||||
/// <summary>Dump volume number</summary>
|
||||
public short c_volume;
|
||||
/// <summary>Logical block of this record</summary>
|
||||
public int c_tapea;
|
||||
/// <summary>Inode number</summary>
|
||||
public ushort c_inumber;
|
||||
/// <summary>Magic number</summary>
|
||||
public ushort c_magic;
|
||||
/// <summary>Record checksum</summary>
|
||||
public int c_checksum;
|
||||
// Unneeded for now
|
||||
/*
|
||||
struct dinode c_dinode;
|
||||
int c_count;
|
||||
char c_addr[BSIZE];
|
||||
*/
|
||||
}
|
||||
|
||||
// 32-bit AIX format record
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct spcl_aix
|
||||
{
|
||||
/// <summary>Record type</summary>
|
||||
public int c_type;
|
||||
/// <summary>Dump date</summary>
|
||||
public int c_date;
|
||||
/// <summary>Previous dump date</summary>
|
||||
public int c_ddate;
|
||||
/// <summary>Dump volume number</summary>
|
||||
public int c_volume;
|
||||
/// <summary>Logical block of this record</summary>
|
||||
public int c_tapea;
|
||||
public uint c_inumber;
|
||||
public uint c_magic;
|
||||
public int c_checksum;
|
||||
// Unneeded for now
|
||||
/*
|
||||
public bsd_dinode bsd_c_dinode;
|
||||
public int c_count;
|
||||
public char c_addr[TP_NINDIR];
|
||||
public int xix_flag;
|
||||
public dinode xix_dinode;
|
||||
*/
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct s_spcl
|
||||
{
|
||||
public int c_type; /* record type (see below) */
|
||||
public int c_date; /* date of this dump */
|
||||
public int c_ddate; /* date of previous dump */
|
||||
public int c_volume; /* dump volume number */
|
||||
public int c_tapea; /* logical block of this record */
|
||||
public uint c_inumber; /* number of inode */
|
||||
public int c_magic; /* magic number (see above) */
|
||||
public int c_checksum; /* record checksum */
|
||||
public dinode c_dinode; /* ownership and mode of inode */
|
||||
public int c_count; /* number of valid c_addr entries */
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = TP_NINDIR)]
|
||||
public byte[] c_addr; /* 1 => data; 0 => hole in inode */
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = LBLSIZE)] public byte[] c_label; /* dump label */
|
||||
public int c_level; /* level of this dump */
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = NAMELEN)]
|
||||
public byte[] c_filesys; /* name of dumpped file system */
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = NAMELEN)] public byte[] c_dev; /* name of dumpped device */
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = NAMELEN)] public byte[] c_host; /* name of dumpped host */
|
||||
public int c_flags; /* additional information */
|
||||
public int c_firstrec; /* first record on volume */
|
||||
public long c_ndate; /* date of this dump */
|
||||
public long c_nddate; /* date of previous dump */
|
||||
public long c_ntapea; /* logical block of this record */
|
||||
public long c_nfirstrec; /* first record on volume */
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] public int[] c_spare; /* reserved for future uses */
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct dinode
|
||||
{
|
||||
public ushort di_mode; /* 0: IFMT, permissions; see below. */
|
||||
public short di_nlink; /* 2: File link count. */
|
||||
public int inumber; /* 4: Lfs: inode number. */
|
||||
public ulong di_size; /* 8: File byte count. */
|
||||
public int di_atime; /* 16: Last access time. */
|
||||
public int di_atimensec; /* 20: Last access time. */
|
||||
public int di_mtime; /* 24: Last modified time. */
|
||||
public int di_mtimensec; /* 28: Last modified time. */
|
||||
public int di_ctime; /* 32: Last inode change time. */
|
||||
public int di_ctimensec; /* 36: Last inode change time. */
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = NDADDR)]
|
||||
public ufs_daddr_t[] di_db; /* 40: Direct disk blocks. */
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = NIADDR)]
|
||||
public ufs_daddr_t[] di_ib; /* 88: Indirect disk blocks. */
|
||||
public uint di_flags; /* 100: Status flags (chflags). */
|
||||
public uint di_blocks; /* 104: Blocks actually held. */
|
||||
public int di_gen; /* 108: Generation number. */
|
||||
public uint di_uid; /* 112: File owner. */
|
||||
public uint di_gid; /* 116: File group. */
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
|
||||
public int[] di_spare; /* 120: Reserved; currently unused */
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -44,6 +44,10 @@ namespace DiscImageChef.Filesystems
|
||||
// Information from https://www.sans.org/reading-room/whitepapers/forensics/reverse-engineering-microsoft-exfat-file-system-33274
|
||||
public class exFAT : Filesystem
|
||||
{
|
||||
readonly Guid OEM_FLASH_PARAMETER_GUID = new Guid("0A0C7E46-3399-4021-90C8-FA6D389C4BA2");
|
||||
|
||||
readonly byte[] Signature = {0x45, 0x58, 0x46, 0x41, 0x54, 0x20, 0x20, 0x20};
|
||||
|
||||
public exFAT()
|
||||
{
|
||||
Name = "Microsoft Extended File Allocation Table";
|
||||
@@ -96,7 +100,8 @@ namespace DiscImageChef.Filesystems
|
||||
byte[] parametersSector = imagePlugin.ReadSector(9 + partition.Start);
|
||||
IntPtr parametersPtr = Marshal.AllocHGlobal(512);
|
||||
Marshal.Copy(parametersSector, 0, parametersPtr, 512);
|
||||
OemParameterTable parametersTable = (OemParameterTable)Marshal.PtrToStructure(parametersPtr, typeof(OemParameterTable));
|
||||
OemParameterTable parametersTable =
|
||||
(OemParameterTable)Marshal.PtrToStructure(parametersPtr, typeof(OemParameterTable));
|
||||
Marshal.FreeHGlobal(parametersPtr);
|
||||
|
||||
byte[] chkSector = imagePlugin.ReadSector(11 + partition.Start);
|
||||
@@ -155,8 +160,65 @@ namespace DiscImageChef.Filesystems
|
||||
information = sb.ToString();
|
||||
}
|
||||
|
||||
readonly byte[] Signature = {0x45, 0x58, 0x46, 0x41, 0x54, 0x20, 0x20, 0x20};
|
||||
readonly Guid OEM_FLASH_PARAMETER_GUID = new Guid("0A0C7E46-3399-4021-90C8-FA6D389C4BA2");
|
||||
public override Errno GetAttributes(string path, ref FileAttributes attributes)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override Errno GetXattr(string path, string xattr, ref byte[] buf)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override Errno ListXAttr(string path, ref List<string> xattrs)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override Errno MapBlock(string path, long fileBlock, ref long deviceBlock)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override Errno Mount()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override Errno Mount(bool debug)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override Errno Read(string path, long offset, long size, ref byte[] buf)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override Errno ReadDir(string path, ref List<string> contents)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override Errno ReadLink(string path, ref string dest)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override Errno Stat(string path, ref FileEntryInfo stat)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override Errno StatFs(ref FileSystemInfo stat)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override Errno Unmount()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
[Flags]
|
||||
enum VolumeFlags : ushort
|
||||
@@ -219,65 +281,5 @@ namespace DiscImageChef.Filesystems
|
||||
{
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)] public uint[] checksum;
|
||||
}
|
||||
|
||||
public override Errno GetAttributes(string path, ref FileAttributes attributes)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override Errno GetXattr(string path, string xattr, ref byte[] buf)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override Errno ListXAttr(string path, ref List<string> xattrs)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override Errno MapBlock(string path, long fileBlock, ref long deviceBlock)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override Errno Mount()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override Errno Mount(bool debug)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override Errno Read(string path, long offset, long size, ref byte[] buf)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override Errno ReadDir(string path, ref List<string> contents)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override Errno ReadLink(string path, ref string dest)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override Errno Stat(string path, ref FileEntryInfo stat)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override Errno StatFs(ref FileSystemInfo stat)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override Errno Unmount()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -46,6 +46,122 @@ namespace DiscImageChef.Filesystems
|
||||
{
|
||||
const int SB_POS = 0x400;
|
||||
|
||||
/// <summary>
|
||||
/// Same magic for ext2, ext3 and ext4
|
||||
/// </summary>
|
||||
const ushort EXT2_MAGIC = 0xEF53;
|
||||
|
||||
const ushort EXT2_MAGIC_OLD = 0xEF51;
|
||||
|
||||
// ext? filesystem states
|
||||
/// <summary>Cleanly-unmounted volume</summary>
|
||||
const ushort EXT2_VALID_FS = 0x0001;
|
||||
/// <summary>Dirty volume</summary>
|
||||
const ushort EXT2_ERROR_FS = 0x0002;
|
||||
/// <summary>Recovering orphan files</summary>
|
||||
const ushort EXT3_ORPHAN_FS = 0x0004;
|
||||
|
||||
// ext? default mount flags
|
||||
/// <summary>Enable debugging messages</summary>
|
||||
const uint EXT2_DEFM_DEBUG = 0x000001;
|
||||
/// <summary>Emulates BSD behaviour on new file creation</summary>
|
||||
const uint EXT2_DEFM_BSDGROUPS = 0x000002;
|
||||
/// <summary>Enable user xattrs</summary>
|
||||
const uint EXT2_DEFM_XATTR_USER = 0x000004;
|
||||
/// <summary>Enable POSIX ACLs</summary>
|
||||
const uint EXT2_DEFM_ACL = 0x000008;
|
||||
/// <summary>Use 16bit UIDs</summary>
|
||||
const uint EXT2_DEFM_UID16 = 0x000010;
|
||||
/// <summary>Journal data mode</summary>
|
||||
const uint EXT3_DEFM_JMODE_DATA = 0x000040;
|
||||
/// <summary>Journal ordered mode</summary>
|
||||
const uint EXT3_DEFM_JMODE_ORDERED = 0x000080;
|
||||
/// <summary>Journal writeback mode</summary>
|
||||
const uint EXT3_DEFM_JMODE_WBACK = 0x000100;
|
||||
|
||||
// Behaviour on errors
|
||||
/// <summary>Continue execution</summary>
|
||||
const ushort EXT2_ERRORS_CONTINUE = 1;
|
||||
/// <summary>Remount fs read-only</summary>
|
||||
const ushort EXT2_ERRORS_RO = 2;
|
||||
/// <summary>Panic</summary>
|
||||
const ushort EXT2_ERRORS_PANIC = 3;
|
||||
|
||||
// OS codes
|
||||
const uint EXT2_OS_LINUX = 0;
|
||||
const uint EXT2_OS_HURD = 1;
|
||||
const uint EXT2_OS_MASIX = 2;
|
||||
const uint EXT2_OS_FREEBSD = 3;
|
||||
const uint EXT2_OS_LITES = 4;
|
||||
|
||||
// Revision levels
|
||||
/// <summary>The good old (original) format</summary>
|
||||
const uint EXT2_GOOD_OLD_REV = 0;
|
||||
/// <summary>V2 format w/ dynamic inode sizes</summary>
|
||||
const uint EXT2_DYNAMIC_REV = 1;
|
||||
|
||||
// Compatible features
|
||||
/// <summary>Pre-allocate directories</summary>
|
||||
const uint EXT2_FEATURE_COMPAT_DIR_PREALLOC = 0x00000001;
|
||||
/// <summary>imagic inodes ?</summary>
|
||||
const uint EXT2_FEATURE_COMPAT_IMAGIC_INODES = 0x00000002;
|
||||
/// <summary>Has journal (it's ext3)</summary>
|
||||
const uint EXT3_FEATURE_COMPAT_HAS_JOURNAL = 0x00000004;
|
||||
/// <summary>EA blocks</summary>
|
||||
const uint EXT2_FEATURE_COMPAT_EXT_ATTR = 0x00000008;
|
||||
/// <summary>Online filesystem resize reservations</summary>
|
||||
const uint EXT2_FEATURE_COMPAT_RESIZE_INO = 0x00000010;
|
||||
/// <summary>Can use hashed indexes on directories</summary>
|
||||
const uint EXT2_FEATURE_COMPAT_DIR_INDEX = 0x00000020;
|
||||
|
||||
// Read-only compatible features
|
||||
/// <summary>Reduced number of superblocks</summary>
|
||||
const uint EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER = 0x00000001;
|
||||
/// <summary>Can have files bigger than 2GiB</summary>
|
||||
const uint EXT2_FEATURE_RO_COMPAT_LARGE_FILE = 0x00000002;
|
||||
/// <summary>Use B-Tree for directories</summary>
|
||||
const uint EXT2_FEATURE_RO_COMPAT_BTREE_DIR = 0x00000004;
|
||||
/// <summary>Can have files bigger than 2TiB *ext4*</summary>
|
||||
const uint EXT4_FEATURE_RO_COMPAT_HUGE_FILE = 0x00000008;
|
||||
/// <summary>Group descriptor checksums and sparse inode table *ext4*</summary>
|
||||
const uint EXT4_FEATURE_RO_COMPAT_GDT_CSUM = 0x00000010;
|
||||
/// <summary>More than 32000 directory entries *ext4*</summary>
|
||||
const uint EXT4_FEATURE_RO_COMPAT_DIR_NLINK = 0x00000020;
|
||||
/// <summary>Nanosecond timestamps and creation time *ext4*</summary>
|
||||
const uint EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE = 0x00000040;
|
||||
|
||||
// Incompatible features
|
||||
/// <summary>Uses compression</summary>
|
||||
const uint EXT2_FEATURE_INCOMPAT_COMPRESSION = 0x00000001;
|
||||
/// <summary>Filetype in directory entries</summary>
|
||||
const uint EXT2_FEATURE_INCOMPAT_FILETYPE = 0x00000002;
|
||||
/// <summary>Journal needs recovery *ext3*</summary>
|
||||
const uint EXT3_FEATURE_INCOMPAT_RECOVER = 0x00000004;
|
||||
/// <summary>Has journal on another device *ext3*</summary>
|
||||
const uint EXT3_FEATURE_INCOMPAT_JOURNAL_DEV = 0x00000008;
|
||||
/// <summary>Reduced block group backups</summary>
|
||||
const uint EXT2_FEATURE_INCOMPAT_META_BG = 0x00000010;
|
||||
/// <summary>Volume use extents *ext4*</summary>
|
||||
const uint EXT4_FEATURE_INCOMPAT_EXTENTS = 0x00000040;
|
||||
/// <summary>Supports volumes bigger than 2^32 blocks *ext4*</summary>
|
||||
const uint EXT4_FEATURE_INCOMPAT_64BIT = 0x00000080;
|
||||
/// <summary>Multi-mount protection *ext4*</summary>
|
||||
const uint EXT4_FEATURE_INCOMPAT_MMP = 0x00000100;
|
||||
/// <summary>Flexible block group metadata location *ext4*</summary>
|
||||
const uint EXT4_FEATURE_INCOMPAT_FLEX_BG = 0x00000200;
|
||||
/// <summary>EA in inode *ext4*</summary>
|
||||
const uint EXT4_FEATURE_INCOMPAT_EA_INODE = 0x00000400;
|
||||
/// <summary>Data can reside in directory entry *ext4*</summary>
|
||||
const uint EXT4_FEATURE_INCOMPAT_DIRDATA = 0x00001000;
|
||||
|
||||
// Miscellaneous filesystem flags
|
||||
/// <summary>Signed dirhash in use</summary>
|
||||
const uint EXT2_FLAGS_SIGNED_HASH = 0x00000001;
|
||||
/// <summary>Unsigned dirhash in use</summary>
|
||||
const uint EXT2_FLAGS_UNSIGNED_HASH = 0x00000002;
|
||||
/// <summary>Testing development code</summary>
|
||||
const uint EXT2_FLAGS_TEST_FILESYS = 0x00000004;
|
||||
|
||||
public ext2FS()
|
||||
{
|
||||
Name = "Linux extended Filesystem 2, 3 and 4";
|
||||
@@ -87,8 +203,7 @@ namespace DiscImageChef.Filesystems
|
||||
return magic == EXT2_MAGIC || magic == EXT2_MAGIC_OLD;
|
||||
}
|
||||
|
||||
public override void GetInformation(ImagePlugin imagePlugin, Partition partition,
|
||||
out string information)
|
||||
public override void GetInformation(ImagePlugin imagePlugin, Partition partition, out string information)
|
||||
{
|
||||
information = "";
|
||||
|
||||
@@ -115,7 +230,8 @@ namespace DiscImageChef.Filesystems
|
||||
|
||||
XmlFsType = new FileSystemType();
|
||||
|
||||
switch(supblk.magic) {
|
||||
switch(supblk.magic)
|
||||
{
|
||||
case EXT2_MAGIC_OLD:
|
||||
sb.AppendLine("ext2 (old) filesystem");
|
||||
XmlFsType.Type = "ext2";
|
||||
@@ -123,12 +239,14 @@ namespace DiscImageChef.Filesystems
|
||||
case EXT2_MAGIC:
|
||||
ext3 |= (supblk.ftr_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL) == EXT3_FEATURE_COMPAT_HAS_JOURNAL ||
|
||||
(supblk.ftr_incompat & EXT3_FEATURE_INCOMPAT_RECOVER) == EXT3_FEATURE_INCOMPAT_RECOVER ||
|
||||
(supblk.ftr_incompat & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) == EXT3_FEATURE_INCOMPAT_JOURNAL_DEV;
|
||||
(supblk.ftr_incompat & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) ==
|
||||
EXT3_FEATURE_INCOMPAT_JOURNAL_DEV;
|
||||
|
||||
if((supblk.ftr_ro_compat & EXT4_FEATURE_RO_COMPAT_HUGE_FILE) == EXT4_FEATURE_RO_COMPAT_HUGE_FILE ||
|
||||
(supblk.ftr_ro_compat & EXT4_FEATURE_RO_COMPAT_GDT_CSUM) == EXT4_FEATURE_RO_COMPAT_GDT_CSUM ||
|
||||
(supblk.ftr_ro_compat & EXT4_FEATURE_RO_COMPAT_DIR_NLINK) == EXT4_FEATURE_RO_COMPAT_DIR_NLINK ||
|
||||
(supblk.ftr_ro_compat & EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE) == EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE ||
|
||||
(supblk.ftr_ro_compat & EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE) ==
|
||||
EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE ||
|
||||
(supblk.ftr_incompat & EXT4_FEATURE_INCOMPAT_64BIT) == EXT4_FEATURE_INCOMPAT_64BIT ||
|
||||
(supblk.ftr_incompat & EXT4_FEATURE_INCOMPAT_MMP) == EXT4_FEATURE_INCOMPAT_MMP ||
|
||||
(supblk.ftr_incompat & EXT4_FEATURE_INCOMPAT_FLEX_BG) == EXT4_FEATURE_INCOMPAT_FLEX_BG ||
|
||||
@@ -525,15 +643,68 @@ namespace DiscImageChef.Filesystems
|
||||
information = sb.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Same magic for ext2, ext3 and ext4
|
||||
/// </summary>
|
||||
const ushort EXT2_MAGIC = 0xEF53;
|
||||
public override Errno Mount()
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
const ushort EXT2_MAGIC_OLD = 0xEF51;
|
||||
public override Errno Mount(bool debug)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno Unmount()
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno MapBlock(string path, long fileBlock, ref long deviceBlock)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno GetAttributes(string path, ref FileAttributes attributes)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno ListXAttr(string path, ref List<string> xattrs)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno GetXattr(string path, string xattr, ref byte[] buf)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno Read(string path, long offset, long size, ref byte[] buf)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno ReadDir(string path, ref List<string> contents)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno StatFs(ref FileSystemInfo stat)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno Stat(string path, ref FileEntryInfo stat)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno ReadLink(string path, ref string dest)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// ext2/3/4 superblock
|
||||
/// ext2/3/4 superblock
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
||||
@@ -752,174 +923,5 @@ namespace DiscImageChef.Filesystems
|
||||
/// <summary>crc32c(superblock)</summary>
|
||||
public uint checksum;
|
||||
}
|
||||
|
||||
// ext? filesystem states
|
||||
/// <summary>Cleanly-unmounted volume</summary>
|
||||
const ushort EXT2_VALID_FS = 0x0001;
|
||||
/// <summary>Dirty volume</summary>
|
||||
const ushort EXT2_ERROR_FS = 0x0002;
|
||||
/// <summary>Recovering orphan files</summary>
|
||||
const ushort EXT3_ORPHAN_FS = 0x0004;
|
||||
|
||||
// ext? default mount flags
|
||||
/// <summary>Enable debugging messages</summary>
|
||||
const uint EXT2_DEFM_DEBUG = 0x000001;
|
||||
/// <summary>Emulates BSD behaviour on new file creation</summary>
|
||||
const uint EXT2_DEFM_BSDGROUPS = 0x000002;
|
||||
/// <summary>Enable user xattrs</summary>
|
||||
const uint EXT2_DEFM_XATTR_USER = 0x000004;
|
||||
/// <summary>Enable POSIX ACLs</summary>
|
||||
const uint EXT2_DEFM_ACL = 0x000008;
|
||||
/// <summary>Use 16bit UIDs</summary>
|
||||
const uint EXT2_DEFM_UID16 = 0x000010;
|
||||
/// <summary>Journal data mode</summary>
|
||||
const uint EXT3_DEFM_JMODE_DATA = 0x000040;
|
||||
/// <summary>Journal ordered mode</summary>
|
||||
const uint EXT3_DEFM_JMODE_ORDERED = 0x000080;
|
||||
/// <summary>Journal writeback mode</summary>
|
||||
const uint EXT3_DEFM_JMODE_WBACK = 0x000100;
|
||||
|
||||
// Behaviour on errors
|
||||
/// <summary>Continue execution</summary>
|
||||
const ushort EXT2_ERRORS_CONTINUE = 1;
|
||||
/// <summary>Remount fs read-only</summary>
|
||||
const ushort EXT2_ERRORS_RO = 2;
|
||||
/// <summary>Panic</summary>
|
||||
const ushort EXT2_ERRORS_PANIC = 3;
|
||||
|
||||
// OS codes
|
||||
const uint EXT2_OS_LINUX = 0;
|
||||
const uint EXT2_OS_HURD = 1;
|
||||
const uint EXT2_OS_MASIX = 2;
|
||||
const uint EXT2_OS_FREEBSD = 3;
|
||||
const uint EXT2_OS_LITES = 4;
|
||||
|
||||
// Revision levels
|
||||
/// <summary>The good old (original) format</summary>
|
||||
const uint EXT2_GOOD_OLD_REV = 0;
|
||||
/// <summary>V2 format w/ dynamic inode sizes</summary>
|
||||
const uint EXT2_DYNAMIC_REV = 1;
|
||||
|
||||
// Compatible features
|
||||
/// <summary>Pre-allocate directories</summary>
|
||||
const uint EXT2_FEATURE_COMPAT_DIR_PREALLOC = 0x00000001;
|
||||
/// <summary>imagic inodes ?</summary>
|
||||
const uint EXT2_FEATURE_COMPAT_IMAGIC_INODES = 0x00000002;
|
||||
/// <summary>Has journal (it's ext3)</summary>
|
||||
const uint EXT3_FEATURE_COMPAT_HAS_JOURNAL = 0x00000004;
|
||||
/// <summary>EA blocks</summary>
|
||||
const uint EXT2_FEATURE_COMPAT_EXT_ATTR = 0x00000008;
|
||||
/// <summary>Online filesystem resize reservations</summary>
|
||||
const uint EXT2_FEATURE_COMPAT_RESIZE_INO = 0x00000010;
|
||||
/// <summary>Can use hashed indexes on directories</summary>
|
||||
const uint EXT2_FEATURE_COMPAT_DIR_INDEX = 0x00000020;
|
||||
|
||||
// Read-only compatible features
|
||||
/// <summary>Reduced number of superblocks</summary>
|
||||
const uint EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER = 0x00000001;
|
||||
/// <summary>Can have files bigger than 2GiB</summary>
|
||||
const uint EXT2_FEATURE_RO_COMPAT_LARGE_FILE = 0x00000002;
|
||||
/// <summary>Use B-Tree for directories</summary>
|
||||
const uint EXT2_FEATURE_RO_COMPAT_BTREE_DIR = 0x00000004;
|
||||
/// <summary>Can have files bigger than 2TiB *ext4*</summary>
|
||||
const uint EXT4_FEATURE_RO_COMPAT_HUGE_FILE = 0x00000008;
|
||||
/// <summary>Group descriptor checksums and sparse inode table *ext4*</summary>
|
||||
const uint EXT4_FEATURE_RO_COMPAT_GDT_CSUM = 0x00000010;
|
||||
/// <summary>More than 32000 directory entries *ext4*</summary>
|
||||
const uint EXT4_FEATURE_RO_COMPAT_DIR_NLINK = 0x00000020;
|
||||
/// <summary>Nanosecond timestamps and creation time *ext4*</summary>
|
||||
const uint EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE = 0x00000040;
|
||||
|
||||
// Incompatible features
|
||||
/// <summary>Uses compression</summary>
|
||||
const uint EXT2_FEATURE_INCOMPAT_COMPRESSION = 0x00000001;
|
||||
/// <summary>Filetype in directory entries</summary>
|
||||
const uint EXT2_FEATURE_INCOMPAT_FILETYPE = 0x00000002;
|
||||
/// <summary>Journal needs recovery *ext3*</summary>
|
||||
const uint EXT3_FEATURE_INCOMPAT_RECOVER = 0x00000004;
|
||||
/// <summary>Has journal on another device *ext3*</summary>
|
||||
const uint EXT3_FEATURE_INCOMPAT_JOURNAL_DEV = 0x00000008;
|
||||
/// <summary>Reduced block group backups</summary>
|
||||
const uint EXT2_FEATURE_INCOMPAT_META_BG = 0x00000010;
|
||||
/// <summary>Volume use extents *ext4*</summary>
|
||||
const uint EXT4_FEATURE_INCOMPAT_EXTENTS = 0x00000040;
|
||||
/// <summary>Supports volumes bigger than 2^32 blocks *ext4*</summary>
|
||||
const uint EXT4_FEATURE_INCOMPAT_64BIT = 0x00000080;
|
||||
/// <summary>Multi-mount protection *ext4*</summary>
|
||||
const uint EXT4_FEATURE_INCOMPAT_MMP = 0x00000100;
|
||||
/// <summary>Flexible block group metadata location *ext4*</summary>
|
||||
const uint EXT4_FEATURE_INCOMPAT_FLEX_BG = 0x00000200;
|
||||
/// <summary>EA in inode *ext4*</summary>
|
||||
const uint EXT4_FEATURE_INCOMPAT_EA_INODE = 0x00000400;
|
||||
/// <summary>Data can reside in directory entry *ext4*</summary>
|
||||
const uint EXT4_FEATURE_INCOMPAT_DIRDATA = 0x00001000;
|
||||
|
||||
// Miscellaneous filesystem flags
|
||||
/// <summary>Signed dirhash in use</summary>
|
||||
const uint EXT2_FLAGS_SIGNED_HASH = 0x00000001;
|
||||
/// <summary>Unsigned dirhash in use</summary>
|
||||
const uint EXT2_FLAGS_UNSIGNED_HASH = 0x00000002;
|
||||
/// <summary>Testing development code</summary>
|
||||
const uint EXT2_FLAGS_TEST_FILESYS = 0x00000004;
|
||||
|
||||
public override Errno Mount()
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno Mount(bool debug)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno Unmount()
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno MapBlock(string path, long fileBlock, ref long deviceBlock)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno GetAttributes(string path, ref FileAttributes attributes)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno ListXAttr(string path, ref List<string> xattrs)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno GetXattr(string path, string xattr, ref byte[] buf)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno Read(string path, long offset, long size, ref byte[] buf)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno ReadDir(string path, ref List<string> contents)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno StatFs(ref FileSystemInfo stat)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno Stat(string path, ref FileEntryInfo stat)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
public override Errno ReadLink(string path, ref string dest)
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -45,6 +45,11 @@ namespace DiscImageChef.Filesystems
|
||||
{
|
||||
const int SB_POS = 0x400;
|
||||
|
||||
/// <summary>
|
||||
/// ext superblock magic
|
||||
/// </summary>
|
||||
const ushort EXT_MAGIC = 0x137D;
|
||||
|
||||
public extFS()
|
||||
{
|
||||
Name = "Linux extended Filesystem";
|
||||
@@ -84,8 +89,7 @@ namespace DiscImageChef.Filesystems
|
||||
return magic == EXT_MAGIC;
|
||||
}
|
||||
|
||||
public override void GetInformation(ImagePlugin imagePlugin, Partition partition,
|
||||
out string information)
|
||||
public override void GetInformation(ImagePlugin imagePlugin, Partition partition, out string information)
|
||||
{
|
||||
information = "";
|
||||
|
||||
@@ -115,7 +119,6 @@ namespace DiscImageChef.Filesystems
|
||||
maxsize = BitConverter.ToUInt32(sbSector, 0x020)
|
||||
};
|
||||
|
||||
|
||||
sb.AppendLine("ext filesystem");
|
||||
sb.AppendFormat("{0} zones on volume", extSb.zones);
|
||||
sb.AppendFormat("{0} free blocks ({1} bytes)", extSb.freecountblk, extSb.freecountblk * 1024);
|
||||
@@ -139,49 +142,6 @@ namespace DiscImageChef.Filesystems
|
||||
information = sb.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// ext superblock magic
|
||||
/// </summary>
|
||||
const ushort EXT_MAGIC = 0x137D;
|
||||
|
||||
/// <summary>
|
||||
/// ext superblock
|
||||
/// </summary>
|
||||
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
||||
struct extFSSuperBlock
|
||||
{
|
||||
/// <summary>0x000, inodes on volume</summary>
|
||||
public uint inodes;
|
||||
/// <summary>0x004, zones on volume</summary>
|
||||
public uint zones;
|
||||
/// <summary>0x008, first free block</summary>
|
||||
public uint firstfreeblk;
|
||||
/// <summary>0x00C, free blocks count</summary>
|
||||
public uint freecountblk;
|
||||
/// <summary>0x010, first free inode</summary>
|
||||
public uint firstfreeind;
|
||||
/// <summary>0x014, free inodes count</summary>
|
||||
public uint freecountind;
|
||||
/// <summary>0x018, first data zone</summary>
|
||||
public uint firstdatazone;
|
||||
/// <summary>0x01C, log zone size</summary>
|
||||
public uint logzonesize;
|
||||
/// <summary>0x020, max zone size</summary>
|
||||
public uint maxsize;
|
||||
/// <summary>0x024, reserved</summary>
|
||||
public uint reserved1;
|
||||
/// <summary>0x028, reserved</summary>
|
||||
public uint reserved2;
|
||||
/// <summary>0x02C, reserved</summary>
|
||||
public uint reserved3;
|
||||
/// <summary>0x030, reserved</summary>
|
||||
public uint reserved4;
|
||||
/// <summary>0x034, reserved</summary>
|
||||
public uint reserved5;
|
||||
/// <summary>0x038, 0x137D (little endian)</summary>
|
||||
public ushort magic;
|
||||
}
|
||||
|
||||
public override Errno Mount()
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
@@ -241,5 +201,43 @@ namespace DiscImageChef.Filesystems
|
||||
{
|
||||
return Errno.NotImplemented;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// ext superblock
|
||||
/// </summary>
|
||||
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
||||
struct extFSSuperBlock
|
||||
{
|
||||
/// <summary>0x000, inodes on volume</summary>
|
||||
public uint inodes;
|
||||
/// <summary>0x004, zones on volume</summary>
|
||||
public uint zones;
|
||||
/// <summary>0x008, first free block</summary>
|
||||
public uint firstfreeblk;
|
||||
/// <summary>0x00C, free blocks count</summary>
|
||||
public uint freecountblk;
|
||||
/// <summary>0x010, first free inode</summary>
|
||||
public uint firstfreeind;
|
||||
/// <summary>0x014, free inodes count</summary>
|
||||
public uint freecountind;
|
||||
/// <summary>0x018, first data zone</summary>
|
||||
public uint firstdatazone;
|
||||
/// <summary>0x01C, log zone size</summary>
|
||||
public uint logzonesize;
|
||||
/// <summary>0x020, max zone size</summary>
|
||||
public uint maxsize;
|
||||
/// <summary>0x024, reserved</summary>
|
||||
public uint reserved1;
|
||||
/// <summary>0x028, reserved</summary>
|
||||
public uint reserved2;
|
||||
/// <summary>0x02C, reserved</summary>
|
||||
public uint reserved3;
|
||||
/// <summary>0x030, reserved</summary>
|
||||
public uint reserved4;
|
||||
/// <summary>0x034, reserved</summary>
|
||||
public uint reserved5;
|
||||
/// <summary>0x038, 0x137D (little endian)</summary>
|
||||
public ushort magic;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user