// /*************************************************************************** // The Disc Image Chef // ---------------------------------------------------------------------------- // // Filename : Structs.cs // Author(s) : Natalia Portillo // // Component : Apple Lisa filesystem plugin. // // --[ Description ] ---------------------------------------------------------- // // Apple Lisa filesystem structures. // // --[ License ] -------------------------------------------------------------- // // This library is free software; you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as // published by the Free Software Foundation; either version 2.1 of the // License, or (at your option) any later version. // // This library is distributed in the hope that it will be useful, but // WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License along with this library; if not, see . // // ---------------------------------------------------------------------------- // Copyright © 2011-2016 Natalia Portillo // ****************************************************************************/ using System; namespace DiscImageChef.Filesystems.LisaFS { partial class LisaFS : Filesystem { /// /// 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. /// struct MDDF { /// 0x00, Filesystem version public ushort fsversion; /// 0x02, Volume ID public ulong volid; /// 0x0A, Volume sequence number public ushort volnum; /// 0x0C, Pascal string, 32+1 bytes, volume name public string volname; /// 0x2D, unknown, possible padding public byte unknown1; /// 0x2E, Pascal string, 32+1 bytes, password public string password; /// 0x4F, unknown, possible padding public byte unknown2; /// 0x50, Lisa serial number that init'ed this disk public uint machine_id; /// 0x54, ID of the master copy ? no idea really public uint master_copy_id; /// 0x58, Date of volume creation public DateTime dtvc; /// 0x5C, Date... public DateTime dtcc; /// 0x60, Date of volume backup public DateTime dtvb; /// 0x64, Date of volume scavenging public DateTime dtvs; /// 0x68, unknown public uint unknown3; /// 0x6C, block the MDDF is residing on public uint mddf_block; /// 0x70, volsize-1 public uint volsize_minus_one; /// 0x74, volsize-1-mddf_block public uint volsize_minus_mddf_minus_one; /// 0x78, Volume size in blocks public uint vol_size; /// 0x7C, Blocks size of underlying drive (data+tags) public ushort blocksize; /// 0x7E, Data only block size public ushort datasize; /// 0x80, unknown public ushort unknown4; /// 0x82, unknown public uint unknown5; /// 0x86, unknown public uint unknown6; /// 0x8A, Size in sectors of filesystem clusters public ushort clustersize; /// 0x8C, Filesystem size in blocks public uint fs_size; /// 0x90, unknown public uint unknown7; /// 0x94, Pointer to S-Records public uint srec_ptr; /// 0x98, unknown public ushort unknown9; /// 0x9A, S-Records length public ushort srec_len; /// 0x9C, unknown public uint unknown10; /// 0xA0, unknown public uint unknown11; /// 0xA4, unknown public uint unknown12; /// 0xA8, unknown public uint unknown13; /// 0xAC, unknown public uint unknown14; /// 0xB0, Files in volume public ushort filecount; /// 0xB2, unknown public uint unknown15; /// 0xB6, unknown public uint unknown16; /// 0xBA, Free blocks public uint freecount; /// 0xBE, unknown public ushort unknown17; /// 0xC0, unknown public uint unknown18; /// 0xC4, no idea public ulong overmount_stamp; /// 0xCC, serialization, lisa serial number authorized to use blocked software on this volume public uint serialization; /// 0xD0, unknown public uint unknown19; /// 0xD4, unknown, possible timestamp public uint unknown_timestamp; /// 0xD8, unknown public uint unknown20; /// 0xDC, unknown public uint unknown21; /// 0xE0, unknown public uint unknown22; /// 0xE4, unknown public uint unknown23; /// 0xE8, unknown public uint unknown24; /// 0xEC, unknown public uint unknown25; /// 0xF0, unknown public uint unknown26; /// 0xF4, unknown public uint unknown27; /// 0xF8, unknown public uint unknown28; /// 0xFC, unknown public uint unknown29; /// 0x100, unknown public uint unknown30; /// 0x104, unknown public uint unknown31; /// 0x108, unknown public uint unknown32; /// 0x10C, unknown public uint unknown33; /// 0x110, unknown public uint unknown34; /// 0x114, unknown public uint unknown35; /// 0x118, ID of volume where this volume was backed up public ulong backup_volid; /// 0x120, Size of LisaInfo label public ushort label_size; /// 0x122, not clear public ushort fs_overhead; /// 0x124, Return code of Scavenger public ushort result_scavenge; /// 0x126, No idea public ushort boot_code; /// 0x128, No idea public ushort boot_environ; /// 0x12A, unknown public uint unknown36; /// 0x12E, unknown public uint unknown37; /// 0x132, unknown public uint unknown38; /// 0x136, Total volumes in sequence public ushort vol_sequence; /// 0x138, Volume is dirty? public byte vol_left_mounted; /// Is password present? (On-disk position unknown) public byte passwd_present; /// Opened files (memory-only?) (On-disk position unknown) public uint opencount; /// No idea (On-disk position unknown) public uint copy_thread; // Flags are boolean, but Pascal seems to use them as full unsigned 8 bit values /// No idea (On-disk position unknown) public byte privileged; /// Read-only volume (On-disk position unknown) public byte write_protected; /// Master disk (On-disk position unknown) public byte master; /// Copy disk (On-disk position unknown) public byte copy; /// No idea (On-disk position unknown) public byte copy_flag; /// No idea (On-disk position unknown) public byte scavenge_flag; } /// /// The sector tag. Before the sector is encoded to GCR the tag is attached to the data. /// Its size and format varies depending on device. /// Lisa OS relies on tags for scavenging a floppy, but ignores most of them for normal usage, /// except on hard disks where the checksum byte is absolutely enforced (a sector with an invalid /// one gives an OS error). /// struct Tag { /// 0x00 version public ushort version; /// 0x02 unknown public ushort unknown; /// 0x04 File ID. Negative numbers are extents for the file with same absolute value number public short fileID; /// Only in 20 bytes tag at 0x06, mask 0x8000 if valid tag public ushort usedBytes; /// Only in 20 bytes tag at 0x08, 3 bytes public uint absoluteBlock; /// Only in 20 bytes tag at 0x0B, checksum byte public byte checksum; /// 0x06 in 12 bytes tag, 0x0C in 20 bytes tag, relative block public ushort relBlock; /// /// Next block for this file. /// In 12 bytes tag at 0x08, 2 bytes, 0x8000 bit seems always set, 0x07FF means this is last block. /// In 20 bytes tag at 0x0E, 3 bytes, 0xFFFFFF means this is last block. /// public uint nextBlock; /// /// Previous block for this file. /// In 12 bytes tag at 0x0A, 2 bytes, 0x07FF means this is first block. /// In 20 bytes tag at 0x11, 3 bytes, 0xFFFFFF means this is first block. /// public uint prevBlock; /// On-memory value for easy first block search. public bool isFirst; /// On-memory value for easy last block search. public bool isLast; } /// /// 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. /// struct CatalogEntry { /// 0x00, seems to be 0x24 when the entry is valid public byte marker; /// 0x01, parent directory ID for this file, 0 for root directory public ushort parentID; /// 0x03, filename, 32-bytes, null-padded public byte[] filename; /// 0x23, null-termination public byte terminator; /// /// 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... /// public byte fileType; /// 0x25, lot of values found here, unknown public byte unknown; /// 0x26, file ID, must be positive and bigger than 4 public short fileID; /// 0x28, creation date public uint dtc; /// 0x2C, last modification date public uint dtm; /// 0x30, file length in bytes public int length; /// 0x34, file length in bytes, including wasted block space public int wasted; /// 0x38, unknown public byte[] tail; } /// /// An extent indicating a start and a run of sectors. /// struct Extent { public int start; public short length; } /// /// 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. /// struct ExtentFile { /// 0x00, filename length public byte filenameLen; /// 0x01, filename public byte[] filename; /// 0x20, unknown public ushort unknown1; /// 0x22, 8 bytes public ulong file_uid; /// 0x2A, unknown public byte unknown2; /// 0x2B, entry type? gets modified public byte etype; /// 0x2C, file type public FileType ftype; /// 0x2D, unknown public byte unknown3; /// 0x2E, creation time public uint dtc; /// 0x32, last access time public uint dta; /// 0x36, modification time public uint dtm; /// 0x3A, backup time public uint dtb; /// 0x3E, scavenge time public uint dts; /// 0x42, machine serial number public uint serial; /// 0x46, unknown public byte unknown4; /// 0x47, locked file public byte locked; /// 0x48, protected file public byte protect; /// 0x49, master file public byte master; /// 0x4A, scavenged file public byte scavenged; /// 0x4B, file closed by os public byte closed; /// 0x4C, file left open public byte open; /// 0x4D, 11 bytes, unknown public byte[] unknown5; /// 0x58, Release number public ushort release; /// 0x5A, Build number public ushort build; /// 0x5C, Compatibility level public ushort compatibility; /// 0x5E, Revision level public ushort revision; /// 0x60, unknown public ushort unknown6; /// 0x62, 0x08 set if password is valid public byte password_valid; /// 0x63, 8 bytes, scrambled password public byte[] password; /// 0x6B, 3 bytes, unknown public byte[] unknown7; /// 0x6E, filesystem overhead public ushort overhead; /// 0x70, 16 bytes, unknown public byte[] unknown8; /// 0x80, 0x200 in v1, file length in blocks public int length; /// 0x84, 0x204 in v1, unknown public int unknown9; /// 0x88, 0x208 in v1, extents, can contain up to 41 extents (85 in v1), dunno LisaOS maximum (never seen more than 3) public Extent[] extents; /// 0x17E, unknown, empty, padding? public short unknown10; /// /// 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. /// public byte[] LisaInfo; } /// /// 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. /// struct SRecord { /// 0x00, block where ExtentsFile for this entry resides public uint extent_ptr; /// 0x04, unknown public uint unknown; /// 0x08, filesize in bytes public uint filesize; /// 0x0C, some kind of flags, meaning unknown public ushort flags; } /// /// 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. /// struct CatalogEntryV2 { /// 0x00, filename, 32-bytes, null-padded public byte filenameLen; /// 0x01, filename, 31-bytes public byte[] filename; /// 0x21, unknown public byte unknown1; /// 0x22, unknown public byte fileType; /// 0x23, unknown public byte unknown2; /// 0x24, unknown public short fileID; /// 0x26, 16 bytes, unknown public byte[] unknown3; } } }