REFACTOR: Final cleanup of DiscImageChef.Filesystems.

This commit is contained in:
2017-12-24 02:37:41 +00:00
parent ec73a6cdc3
commit 4115698ac8
94 changed files with 5196 additions and 5116 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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()
{

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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 &lt;256 allocation blocks
/// Directory entry for &lt;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 &gt;256 allocation blocks
/// Directory entry for &gt;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;
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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 &gt; 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 &lt;= 4 GiB, 3 if &gt; 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 &gt; 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 &lt;= 4 GiB, 3 if &gt; 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;
}
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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()
{

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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