From: Laurent.Clevy@meteo.frNewsgroups: comp.sys.amiga.programmer, comp.sys.amiga.misc, comp.os.linux.miscSubject: Amiga floppy disks format (AmigaDos file system - floppies)Followup-To: posterSummary: This document describes the AmigaDos File System for floppy disks only.        Physical/Logical formats, OFS/FFS, Directory caching, Links, Checksums.Archive-name: amiga/amiga_floppy_formatLast-modified: 28. May 1997Version: 0.9Copyright: (c) 1997 Laurent ClevyMaintainer: Laurent Clevy <Laurent.Clevy@meteo.fr>                     FAQ : The Amiga floppy disks format                               Laurent Clevy                           Laurent.Clevy@meteo.fr                         25 avenue Aristide Briand                              28000 Chartres                                  FranceDisclaimer and copyright------------------------This document is Copyright (C) 1997 by Laurent Clevy, but may befreely distributed, provided the author name and addressesare included and no money is charged for this document.This document is provided "as is". No warranties are made as to its correctness.Amiga, AmigaDos are registred trademarks of Gateway 2000.Introduction------------This document purpose is to describe the Amiga floppy disk format. I don'tfound any document which explains this format in details. Because I wishthis machine to be supported a long time, including via emulators, I decidedto write this file, and supply C routines as examples.Corrections (including about my english) are very welcome. Unfortunately,I have no permanent e-mail address currently, the only way to touch me is by postmail.Index-----1. How bytes are physically read/written on disk ?        1.1 What is MFM ?        1.2 What is the physical track format ?        1.3 What is the physical sector format ?        1.4 How to decode MFM data ?2. What is the Amiga floppy disk geometry ?3. How is logically organised a Amiga floppy disk ?        3.1 What is a Bootblock ?        3.2 What is a Rootblock ?                3.2.1 How to find the first sector of a entry ?                3.2.2 How to list directory entries ?                3.2.3 How to compute the checksum ?        3.3 How is managed the free/used blocks list ?                3.3.1 How to compute bitmap checksum ?                3.3.2 What is the 'bm_ext' field in Rootblock ?        3.4 How are stored files on a disk ?        3.5 How are stored directories ?        3.6 How are implemented links with AmigaDos ?                3.6.1 Hard links                3.6.2 Soft links        3.7 How is the block associated to directory caching ?4. What is a blank disk ?        4.1 a Minimal blank disk        4.2 A 'Bootable' disk        4.3 A Directory cache mode disk5. References6. C Routines7. Other Amiga file systems8. To doConventions-----------* In this document, hexadecimal values are written like in C : for example 0x0cis the decimal value 12.As the Amiga is a 680x0 based computer, integers that require more thanone byte are stored on disk in 'Motorola order' : the most significant bytecomes first, then the less significant bytes in descending order ofsignificance (MSB LSB for two-byte integers, B3 B2 B1 B0 for four-byteintegers). A byte is 8 bits long. The left bit of a byte is the 7th, the right bitis the 0th.A 'word' is a 2 bytes (16 bits) integer, a 'long' a 4 bytes (32 bits) integer.Values are unsigned unless otherwise noted.* A block pointer is the number of this block on the disk. Disk starts with the #0 block.* Hashing is a method to access tables : given a number or a string,a hash function gives a index into a table.* Chained lists are cells oriented data structures. Each cell contains a pointerto the next or previous cell or both, the last pointer is null.C example :struct lcell {        char name[10];                /* contains next cell adress, or NULL if this cell is the last */        struct lcell* next_cell;        };* Names of blocks begin with a capital (Rootblock).Name of fields are noted between quotes ('field_name').* All formats are described as tables, one rows per field.Here is an example with then well known beginning of GIF format :offset  type    length  name            comments----------------------------------------------------------0       char    3       signature       'GIF'3       char    3       version         '87a' or '89a'6       short   1       screen width8       short   1       screen height1. How bytes are physically read/written on disk ?=================================================Most of PC-like floppy disk controllers (FDC) are not able to read Amiga disks,because Amiga physical floppy disk operations are made by a specificchip called "Paula".However, I'm supplying this information because it's hard to find out.If you only want to understand the UAE .adf format, you don't need to read thispart.For classical floppy disk operations, Paula is set with the followingparameters :- MFM encoding- Precompensation time : 0 nanosec- Controller clock rate : 2 microseconds per bit cell- Sync value = 0x4489The controller is able to put the read/write heads on a cylinder, and is able to readwith the lower or upper side head. A track of 0x1900 words is usually read.1.1 What is MFM ?-----------------Because bits can't be written with magnetic fields directly on disk, anencoding scheme is required. Amiga floppy disks are MFM (Modified FrequenceModulation) encoded.The MFM encoding scheme is :        user's data bit         MFM coded bits        ---------------         --------------        1                       01        0                       10 if following a 0 data bit        0                       00 if following a 1 data bitUser data longs are splitted in two parts, a part with even bits part first,followed by a part with odd bits.1.2 What is the physical track format ?---------------------------------------Double density (DD) disks have 11 sectors per track, High density (DD) diskshave 22.So a track consists of 11/22 MFM encoded sectors, plus inter-track-gap.Note that sectors are not written from 0 to 10/21, you must use the 'info'field to recreate orderly track in memory. Each track begins with the firstsector, and ends the end of the last sector (11th with DD disks, 22th with HDs).Each sector starts with 2 synchronization words. The synchro value is 0x4489.1.3 What is the physical sector format ?----------------------------------------Here it comes :0/0x0   word    2       MFM value 0xAAAA AAAA        SYNCHRONIZATION4/0x4   word    1       MFM value 0x44896/0x6   word    1       MFM value 0x4489        HEADER8/0x8   long    1       info (even bits)12/0xc  long    1       info (odd bits)                        decoded long is : 0xff TT SS SG                                TT = track number ( 3 means cyl 1, head 1)                                SS = sector number ( 0 -> 10/21 )                                        sectors are not orderly !!!                                SG = number of sector before gap (including                                        current one)                        Example for cylinder 0, head 1 of a DD disk :                                0xff010009                                0xff010108                                0xff010207                                0xff010306                                0xff010405                                0xff010504                                0xff010603                                0xff010702                                0xff010801                                        <-- inter-sector-gap here !                                0xff01090b (0xb means -1 ?)                                0xff010a0a (0xa means -2 ?)16/0x10 long    4       sector label (even)32/0x20 long    4       sector label (odd)                        decoded value seems to be always 0        END OF HEADER48/0x30 long    1       header checksum (even)52/0x34 long    1       header checksum (odd)                        (computed on mfm longs,                        longs between offsets 8 and 44                         == 2*(1+4) longs)56/0x38 long    1       data checksum (even)60/0x3c long    1       data checksum (odd)                        (from 64 to 1088 == 2*512 longs)        DATA64/0x40 long    512     coded data (even)576/240 long    512     coded data (odd)1088/440        END OF DATA1.4 How to decode MFM data ?----------------------------the algorithm :#define MASK 0x55555555 /* 01010101 ... 01010101 */unsigned long *p1;      /* MFM coded data buffer (size == 2*data_size) */unsigned long *q;       /* decoded data buffer (size == data_size) */unsigned long a,b;unsigned long chksum;int data_size;          /* size in long, 1 for info, 4 for sector label */chksum=0L;do <data_size> times {        a = *p1;                /* even bits */        b = *(p1+data_size);    /* odd bits */        chksum^=a;              /* eor */        chksum^=b;        *q = ( b & MASK ) | ( ( a & MASK ) << 1 );      /* MFM decoding */        p1++;        q++;        }chksum&=MASK;2. What is the Amiga floppy disk geometry ?===========================================Here follows the disk geometries for DD and HD.                bytes/sector    sector/cyl      sides/cyl       cyl/disk------------------------------------------------------------------------DD disks        512             11              2               80HD disks        512             22              2               80The relations between sectors, sides and cylinders are for a DD disk :Block   sector  side    track-----------------------------0       0       0       01       1       0       02       2       0       0...10      10      0       011      0       1       0...21      10      1       022      0       0       1..1759    10      1       79A DD disk has 11*2*80=1760 (0 to 1759) blocks, a HD disk has 22*2*80=3520 blocks.Of course the file system uses some of them, even for a blank disk.As the next part deals with, at least 4 blocks are used, for 3 logicalstructures : bootblock (2), rootblock (1) and bitmap block (1).The length of .ADF files for a DD disk is then 512*11*2*80 = 901120 bytes.3. How is logically organised a Amiga floppy disk ?===================================================The logical low level object of a Amiga disk is the 'sector' (or 'block') : 512consecutive bytes.Disk information is distribued in the Bootblocks, the Rootblock and Bitmapblock(s).FFS has block structures to provide directory list caching and (hard) links :Directory cache blocks and Link blocks.Directory tree is stored with a Directory block for each node.Directory entries (files, directories and links) are stored with a table, andare accessed with hashing and chained lists.Files are stored with a File header block and Data blocks. File extensionblocks are also used for files stored with more than 72 Data blocks.3.1 What is a Bootblock ?-------------------------The first object of an Amiga floppy is the Boot block. If the checksum and theDiskType are correct, the system will execute the bootblock code, at boottime, of course :-).A valid bootblock is written by the AmigaDos command 'install'.* BootBlock (1024 bytes) sectors 0 and 1-------------------------------------------------------------------------------offset  size    number  name            meaning-------------------------------------------------------------------------------0/0     char    4       DiskType        'D''O''S' + flags (0->5)                                        flags =         set     clr                                                0       FFS     OFS                                                1       INT     NOINT                                                2       DIRC    NODIRC4/4     long    1       Chksum          special checksum8/8     long    1       Rootblock       ==880   DD and HD12/0x0c char    1012    Bootblock code  (see 4.2 'Bootable disk' for more information)-------------------------------------------------------------------------------The DiskType flag informs of the disk format.OFS = Old/Original File System, the first one. (AmigaDos 1.2)FFS = Fast File System (AmigaDos 2.04)INT = International characters Mode (AmigaDos 3.0).DIRC = stands for Directory Cache Mode (AmigaDos 3.0). This mode speeds up        directory listing, but take some disk space.There are few differences between the two file systems.- OFS Datablock stores 488 bytes, FFS stores 512 bytes,- FFS supports directories caching, links and international mode,- the FFS is faster than OFS.The bootblock checksum algorithm follows :* in 68000 assembler :        lea     bootbuffer,a0        move.l  a0,a1        clr.l   4(a1)                   ;clear the checksum        move.w  #256-1,d1               ;1024/4 times        moveq   #0,d0lpchk:  add.l   (a0)+,d0                ;accumulation        bcc.s   jump                    ;if carry set, add 1 to checksum        add.l   #1,d0jump:   dbf     d1,lpchk                ;next long word        not.l   d0        move.l  d0,4(a1)                ;new checksum* in C :#include<limits.h>#define Short(p) ((p)[0]<<8 | (p)[1])#define Long(p) (Short(p)<<16 | Short(p+2))unsigned long newsum,d;unsigned char buf[1024];                /* contains bootblock */int i;memset(buf+4,0,4);      /* clear old checksum */newsum=0L;for(i=0; i<256; i++) {        d=Long(buf+i*4);        if ( (ULONG_MAX-newsum) < d )   /* overflow */                newsum++;        newsum+=d;        }newsum=~newsum;3.2 What is a Rootblock ?-------------------------The Rootblock is at the middle of the media : block number 880 for DD disks,block 1760 for HDs.The Rootblock contains information about disk : its name, its formatting date,etc ...It also contains information to access the files/directories/links located at the root(Unix /) directory.* Rootblock (512 bytes) sector 880 for a DD disk, 1760 for a HD disk------------------------------------------------------------------------------0/0     long    1       type            block primary type = T_HEADER (value 2)4/4     long    1       header_key      unused in rootblock (value 0)        long    1       high_seq        unused (value 0)12/c    long    1       ht_size         Hash table size in long (value 0x48)16/10   long    1       first_data      unused (value 0)20/14   long    1       chksum          sum to check block integrity24/18   long    72      ht[]            hash table (entry block number)312/138 long    1       bm_flag         bitmap flag, -1 means VALID316/13c long    25      bm_pages[]      bitmap blocks pointers (first at 0)416/1a0 long    1       bm_ext          first bitmap extension block (Hard disks only)        ...432/1b0 char    1       name_len;       disk name length433/1b1 char    30      diskname[]      disk name        ...472/1d8 long    1       days            last access date : days since 1 jan 1978476/1dc long    1       mins            minutes past midnight480/1e0 long    1       ticks           ticks (1/50 sec) past last minute484/1e4 long    1       c_days          creation date488/1e8 long    1       c_mins492/1ec long    1       c_ticks        long    1       next_hash       unused (value = 0)        long    1       parent_dir      unused (value = 0)504/1f8 long    1       extension       FFS: first directory cache block, 0 otherwise508/1fc long    1       sec_type        block secondary type = ST_ROOT (value 1)-------------------------------------------------------------------------------3.2.1 How to find the first sector of a directory entry ?---------------------------------------------------------Given the name of a file/directory/link you compute itshash value with this algorithm :* The hash function :#include<ctype.h>int HashName(char *name){int hash;int i,l;l=hash=strlen(name);for(i=0; i<l; i++) {        hash=hash*13;        hash=hash + toupper(name[i]);        hash=hash & 0x7ff;        }hash=hash % 72;hash=hash + 6;return(hash);}The hash value is used to access HashTable ('ht' field in Rootblock/Directory block).But several names can result a unique HashValue. The first block pointersof them are stored in a chained list which start at HashTable[HashValue-6].Here follows the method to find the requested block :1. HashValue = HashName( name )2. sector = Hashtable[ HashValue-6 ]3. if (sector == 0)                printf "File/Dir not found"                stop        else                Loading the sector4. while ( sector name != name )        sector = Next_hash sector        if (sector == 0)                printf "File/Dir not found"        else                Loading the sectorThe Next_hash field is found in File header, Directory and Link blocks.Filenames can contain lowercase and uppercase, but the Hash functiontells us that 'fIlE1' and 'FiLe1' are a same file.3.2.2 How to list directory entries ?-------------------------------------The HashTable contains the entries block number.To obtain the list of a directory entries (files, directories or links) thealgorithm is :long entry;int i;for(i=0; i<ht_size; i++) {        entry = HashTable[i]        while ( entry !=0 ) {                printf "entry name"                entry = Next_hash                }        }3.2.3 How to compute the checksum ?-----------------------------------#define Short(p) ((p)[0]<<8 | (p)[1])#define Long(p) (Short(p)<<16 | Short(p+2))unsigned long newsum;unsigned char buf[512];         /* contains rootblock */int i;memset(buf+20,0,4);             /* clear old checksum */newsum=0L;for(i=0; i<128; i++)        newsum+=Long(buf+i*4);newsum=-newsum;This checksum algorithm works for most blocks type except noted.The AmigaDos command 'relabel' rename the disk.The 'format' command is used for ... formatting.The bitmap table ('bm_pages[]') stores one or several pointers to Bitmap blocks.The first is at index 0.3.3 How is managed the free and used blocks list?-------------------------------------------------Bitmap blocks stores if a sector is free or allocated. Onebit is used per sector. If the bit is set, the sector isfree, a cleared bit means a allocated sector.Boot blocks allocation (2 for a floppy disk) is not stored in bitmap.Bitmap is stored in longs, the first sector of a long is the bit 0.* Bitmap block (512 bytes), often rootblock+1-------------------------------------------------------------------------------0/0     long    1       checksum        special algorithm4/4     long    127     map-------------------------------------------------------------------------------Here follows for a DD disk the relationship between bitmap and sector number :block #         long #  bit #-------------------------------2               0       03               0       14               0       2...33              0       3134              1       035              1       1...880             27      2881             27      3...1759            54      281760            54      29This map is 1758 bits long (1760-2) and is stored on 54 full long and the first 30th bitsof the 55th long.3.3.1 How to compute bitmap checksum ?--------------------------------------#define Short(p) ((p)[0]<<8 | (p)[1])#define Long(p) (Short(p)<<16 | Short(p+2))unsigned long newsum;unsigned char buf[512];         /* contains block */int i;newsum=0L;for(i=1; i<128; i++)                    /* ignores old checksum */        newsum=newsum-Long(buf+i*4);3.3.2 What is the 'bm_ext' field in Rootblock ?-----------------------------------------------If 25 bitmap blocks (which pointers are stored on Rootblock) are not enough (for Hard Disks),extra needed bitmap blocks pointers are stored in bitmap extension blocks.* Bitmap extension block (512 bytes) (Hard disk only)-------------------------------------------------------------------------------0/0     long    127     bitmap block pointers508/1fc long    1       next (0 for last)-------------------------------------------------------------------------------The Bitmap extension chained list start at Rootblock with the 'bm_ext'.3.4 How are stored files on a disk ?------------------------------------The first block of a file is the File header block, which contains information aboutthe file (size, last access date, ...) and pointers to the first 72th Data blocks.Data blocks store file data.If more than 72 Data blocks are needed to store a file, the other Data block pointers arestored in File extension blocks.File extension blocks are organised in a chained list, which starts in File header block ('extension').* File header block (512 bytes) -------------------------------------------------------------------------------0/0     long    1       type            block primary type T_HEADER (==2)4       long    1       header_key      self pointer8       long    1       high_seq        number of data block ptr stored here12/c    long    1       data_size       unused (==0)16/10   long    1       first_data      first data block ptr20/14   long    1       chksum          same algorithm as rootblock24/18   long    72      data_blocks[]   data blk ptr (first at [high_seq-1])        ...             320/140 long    1       protect         protection flags (bit set)                                        0       delete forbidden (D)                                        1       modification forbidden (E)                                        2       write/update forbidden (W)                                        3       read forbidden (R)                                        4       file is an archive (A)                                        5       pure, can be made resident (P)                                        6       file is a script (S)                                        7       hidden file with DIR (H)324/144 long    1       byte_size       file size328/148 char    1       comm_len        file comment length329/149 char    22      comment[]       comment        ...             420/1a4 long    1       days            last access date (days since 1 jan 1978)424/1a8 long    1       mins            last access time428/1ac long    1       ticks432/1b0 char    1       name_len        filename length433/1b1 char    30      filename[]      filename        ...             468/1d4 long    1       real_entry      FFS : unused (== 0)472/1d8 long    1       next_link       FFS : links chained list (first = newest)        ...             496/1f0 long    1       hash_chain      next entry ptr with same hash500/1f4 long    1       parent          parent directory504/1f8 long    1       extension       pointer to 1st file extension block508/1fc long    1       sec_type        secondary type : ST_FILE (== -3)-------------------------------------------------------------------------------Here we are discovering the first method to read a file : Data block pointerstables. The first table is in File header block, the others in File extension blocks.For an empty file, a Header file block is written, with 'byte_size' equal to 0,and no Data block pointers in 'data_blocks[]'.* File extension block (512 bytes) (first pointer in File header)-------------------------------------------------------------------------------0/0     long    1       type            primary type : T_LIST (== 16)4/4     long    1       header_key      self pointer8/8     long    1       high_seq        number of data blk ptr stored12/c    long    1       data_size       unused (== 0)16/10   long    1       first_data      unused (== 0)20/14   long    1       chksum          rootblock algorithm24/18   long    72      data_blocks[]   data blk ptr (first at [high_seq-1])        long    45      unused        long    1       info            unused (== 0)        long    1       hash_chain;     unused (== 0)500/1f4 long    1       parent          ptr to parent directory504/1f8 long    1       extension       next file header extension block, 0 for last508/1fc long    1       sec_type        secondary type : ST_FILE (== -3)        -------------------------------------------------------------------------------* Data blocks (512 bytes) (first pointer in File header 'first_data' and 'data_blocks[71]')OFS-------------------------------------------------------------------------------0/0     long    1       type            primary type : T_DATA (== 8)4/4     long    1       header_key      pointer to file header block8/8     long    1       seq_num         file data block number (first is #1) 12/c    long    1       data_size       data size (<= 488)16/10   long    1       next_data       next data block ptr (0 for last)20/14   long    1       chksum          rootblock algorithm24/18   UCHAR   488     data[]          file data-------------------------------------------------------------------------------In OFS, there is a second way to read a file : using the Data block chained list.The list starts in File header ('first_data') and goes on with 'next_data' in each Datablock.FFS-------------------------------------------------------------------------------0/0     UCHAR   512     data[]          file data-------------------------------------------------------------------------------In FFS, the only way to read or recover a file is to use File extension blocks.If a File extension block is unreadable, there is no way to find thecorresponding Data blocks.The OFS is more robust than FFS, but slower and can store less data on disk.As you see, disk salvaging is easier with OFS.When a file is deleted, only its File header block number is cleared from the Directoryblock (or from the same-hash-value list). File header block, Data blocks andFile extension blocks are not cleared ! The undelete operation is easy .3.5 How are stored directories ?--------------------------------Directory blocks are very similar to Rootblock, except they don't needinformation about bitmap and disk, but have comments.* Directory block (512 bytes)-------------------------------------------------------------------------------0/0     long    1       type            primary type : T_HEADER (== 2)4/4     long    1       header_key      self pointer8/8     long    1       high_seq        unused (== 0)12/c    long    1       ht_size         unused (== 0)        long    1       unused20/14   long    1       chksum          normal algorithm24/18   long    72      ht[]            HashTable (file/dir/link block number)        long    2       unused320/140 long    1       protect         protect flag (like file header)        long    1       unused328/148 char    1       comm_len        comment length329/149 char    22      comment[]       comment        char    69      unused420/1a4 long    1       days            last access date424/1a8 long    1       mins            last access time428/1ac long    1       ticks432/1b0 char    1       name_len        name length433/1b1 char    30      dirname[]       directory name        char    5       unused468/1d4 long    1       real_entry      unused (== 0)472/1d8 long    1       next_link       FFS : links chained list        long    4       unused496/1f0 long    1       next_hash       next entry with same hash value500/1f4 long    1       parent          parent directory504/1f8 long    1       extension       FFS : first directory cache block508/1fc long    1       sec_type        secondary type : ST_UDIR (== 2)-------------------------------------------------------------------------------You can obtain directory listing exactly like with the root directory.3.6 How are implemented links with AmigaDos ?----------------------------------------------Only FFS handles links and directory caching.Soft links are not supported by AmigaDos 3.0. Linked files are seen asdirectories...However, some shells (like Csh 5.37) supports them, so I'm supplying thestructure.3.6.1 Hard links----------------* Hard link (512 bytes)-------------------------------------------------------------------------------0/0     long    1       type            T_HEADER = 24/4     long    1       self pointer        long    3       unused (== 0)20/14   long    1       checksum        ...             unused420/1a4 long    1       days            date424/1a8 long    1       mins            time428/1ac long    1       ticks432/1b0 char    1       name len433/1b1 char    30      name[]          link name (dir or file name)        ...             unused468/1d4 long    1       real_entry      pointer to real entry472/1d8 long    1       next_link       (links chained list )        ...             unused500/1f4 long    1       parent          parent directory        ...             unused  508/1fc long    1       sec_type        FILE = -4, DIR = 4-------------------------------------------------------------------------------A 'real' entry is a file or directory entry, opposed to link entries.A hard link can only be created on the same disk as the real entry disk.Several links can be made on the same real entry. This is stored with achained list.'real entry' always contains the real entry block pointer.'next_link' stores the links chaimed list.Adding are made at head :>ls  ------rw-d     1912  15-May-96 22:28:08  realChained list state :block# real     next    name----------------------------484     0       0       real>ln real link1>ls  ------rw-d     1912  15-May-96 22:28:08  real  -H----rw-d     1912  15-May-96 22:28:10  link1 -> Empty:realblock# real     next    name----------------------------484     0       104     real104     484     0       link1>ln link1 link2>ls  ------rw-d     1912  15-May-96 22:28:08  real  -H----rw-d     1912  15-May-96 22:28:10  link1 -> Empty:real  -H----rw-d     1912  15-May-96 22:28:12  link2 -> Empty:realblock# real     next    name----------------------------484     0       107     real104     484     0       link1107     484     104     link2The links are stored 'newest first', due to the adding at head.real -> newest link -> ... -> oldest link -> 0-> means "point to"3.6.2 Soft links----------------* Soft link (512 bytes)-------------------------------------------------------------------------------0/0     long    1       type            T_HEADER (== 2)4/4     long    1       self pointer        ...             unused20/14   long    1       checksum24/18   char    30      real entry name (doesn't need to exist !)        ...             unused420/1a4 long    1       days            creation date (access is real's)424/1a8 long    1       mins428/1ac long    1       ticks        ...             unused500/1f4 long    1       parent          parent directory        ...             unused508/1fc long    1       sec_type        ST_LSOFT (== 3)-------------------------------------------------------------------------------3.7 How is the block associated to directory caching ?------------------------------------------------------To speed up directory listing, Directory cache blocks have been created.Directory cache blocks are also organised in chained lists.The list starts at the directory block (root or normal directory) with 'extension'.* Directory cache block (512 bytes)-------------------------------------------------------------------------------0/0     long    1       type            DIRCACHE == 33 (0x21)4/4     long    1       header_key      self pointer8/8     long    1       parent          parent directory12/c    long    1       records_nb      directory entry records in this block16/10   long    1       next_dirc       dir cache chained list20/14   long    1       chksum          normal checksum24/18   UCHAR   488     records[]       entries list-------------------------------------------------------------------------------The directory entries are stored this way :* Directory cache block entry record (26 <= size (in bytes) <= 77)-------------------------------------------------------------------------------0       long    1       header          entry block pointer4       long    1       size            file size (0 for a directory)8       long    1       protect         protection flags12      long    1       unused          ( == 0 )16      short   1       days            date18      short   1       mins            time20      short   1       ticks22      char    1       type            secondary type23      char    1       name_len        >=1, <=30?       char    ?       name            name?       char    1       comm_len        >=0, <=22?       char    ?       comment         comment?       (char)  0       optional padding byte (680x0 longs must be word aligned)-------------------------------------------------------------------------------4. What is a blank disk ?=========================A minimal blank disk has a Bootblock, a Rootblock and a Bitmap block.4.1 a Minimal blank disk------------------------* The Bootblock (0 and 1)0       char    4       ID              'D''O''S' + flags (0 -> 5)4       long    1023    full of zeros* The Rootblock (880)0       long    1       type            212/c    long    1       ht_size         0x4820/14   long    1       checksum        computed312/138 long    1       bm_flag         -1 (valid bitmap)316/13c long    1       bm_pages[0]     bitmap sector #432/1b0 char    1       disk_name size  ?433/1b1 char    ?       disk_name       ?472/1d8 long    1       last access date476/1dc long    1       last access time480/1e0 long    1       last access time484/1e4 long    1       creation date488/1e8 long    1       creation time492/1ec long    1       creation time504/1f8 long    1       FFS : first dir cache sector  or 0508/1fc long    1       sub_type        1No specified fields are null.* The Bitmap block (here 881) for a DD disk0       long    1       checksum4       long    27      free sectors    0xffffffff112/70  long    1       root+bitmap     0xffff3fff116/74  long    27      free sectors    0xffffffff120/78  long    72      unused          !=04.2 A 'Bootable' disk---------------------* The Bootblock becomes :0       long    1       ID              'D''O''S' + flags4       long    1       checksum        computed8       long    1       rootblock ?     88012/c    byte    81      bootcode        AmigaDos 3.0 version        values                  disassembled        --------------+---------------------        43FA003E                lea     exp(pc),a1      ;Lib name        7025                    moveq   #37,d0          ;Lib version        4EAEFDD8                jsr     -552(a6)        ;OpenLibrary()        4A80                    tst.l   d0              ;error == 0        670C                    beq.b   else        2240                    move.l  d0,a1           ;lib pointer        08E90006 0022           bset    #6,34(a1)       ; ?        4EAEFE62                jsr     -414(a6)        ;CloseLibrary()        43FA0018        else:   lea     dos(PC),a1      ;name        4EAEFFA0                jsr     -96(a6)         ;FindResident()        4A80                    tst.l   d0        670A                    beq.b   else2           ;not found        2040                    move.l  d0,a0        20680016                move.l  22(a0),a0       ;DosInit sub        7000                    moveq   #0,d0        4E75                    rts        70FF            else2:  moveq   #-1,d0        4E75                    rts        646F732E 6C696272 617279                        dos:    "dos.library"        00                                              ;padding byte        65787061 6E73696F 6E2E6C69 62726172 79                        exp:    "expansion.library"93/5d   byte    931     full of zeros4.3 A Directory cache mode disk-------------------------------* A directory cache block (882)0       long    1       type            0x214       long    1       self pointer    8828       long    1       cached dir      880 (root)12/c    long    1       entries number  016/10   long    1       next dir cache  0 (last)20/14   long    1       checksum        computed24      long    122     full of zeros5. References=============* ASM Sources:        Scoopex and Crionics disassembled demo hardloaders        'the floppy disk book' copier source file, DATA BECKER books, 1988* On-Line material :        - Very good 'ded.doc' file including Hard Disk information :                <ftp://ftp.funet.fi/pub/amiga/utilities/disk/Ded-1.11.lha>        - A clean track-loader which don't use AmigaDOS :                <ftp://ftp.wustl.edu/pub/aminet/dev/asm/t-loader.lha>        - A remplacement for 'trackdisk.device' :                <ftp://ftp.wustl.edu/pub/aminet/disk/misc/hackdisk202.lha>        - 'amigadisk_hardware.doc'  (by Dave Edwards, Mark Meany, ... of ACC)                <http://home.sol.no/svjohan/assem/refs/diskHW.lha>* Books :        Rom Kernel Reference Manual : Hardware, pages 235-244, Addison Wesley        La Bible de l'Amiga, Dittrich/Gelfand/Schemmel, Data Becker, 1988.        The AmigaDos reference manual must contains a lot of information about Amigafile systems, but i don't own it (Addison Wesley).6. C Routines================Unix system routines yet implemented :cd, pwd, getdent, ls, ls -l, ls -r, open, close, read, stat.newfs, mount, umount.Links and directory cache are supported.Soon available on good FTP servers.7. Other Amiga FileSystems========================An Amiga filesystem for Linux 0.99pl2 by Ray Burr (read only, hard disk support) :        <ftp://tsx-11.mit.edu/pub/linux/patches/amigaffs.tar.Z>An enhanced version for Linux 1.2.13 by Hans-Joachim "JBHR" Widmaier (RDSK, links and        international mode supported):        <ftp://ftp.ibp.fr/pub/linux/sunsite/system/filesystems/jb-affs-1.0.tar.gz>A .ADF manipulation package for DOS/Windows, "ADF-suite" (GUI, no sources included):        <http://www.geocities.com/SiliconValley/Lakes/7094/index.html>8. To do========- Hard disk support- Disk salvaging- Undelete files- ADF monitor/editor-------------------------------------------------------------------------------'FAQ : THE AMIGA FLOPPY DISK FORMAT' ends here !