Acorn 8-Bit ADFS Filesystem Structure ===================================== mdfs.net/Docs/Comp/Disk/Format/ADFS Acorn 8-bit ADFS is often refered to as ADFS-S, ADFS-M and ADFS-L, but these refer to the size of formatted floppy disks. The filesystem is identical, and is the same regardless of the media the data is on. Acorn ADFS uses 256-byte or 1024-byte logical disk sectors. Logical sectors are counted with 24-bit numbers starting from &000000 at the start of the filesystem, so the largest possible ADFS disk system is 4G. Acorn ADFS uses 32-bit file lengths, so the largest possible file is 4G-1. However, the 8-bit ADFS API uses the top three bits of the sector address to specify the drive, leaving 21 bits to specify the logical sector, so in practice the largest possible filesystem is 512M. Small ADFS floppy disks are formatted to: ADFS-S: 1 side, 40 tracks, 16 sectors, 256 bytes = 160K old map, old dir ADFS-M: 1 side, 80 tracks, 16 sectors, 256 bytes = 320K old map, old dir ADFS-L: 2 sides, 80 tracks, 16 sectors, 256 bytes = 640K old map, old dir Tracks are sequential, that is logical_sector=sector+track*16+side*1280. Logical sector zero is zero bytes from the start of the physical disk (ie, sector &000000). Large ADFS floppy disks are formatted to: ADFS-D: 80 tracks, 2 sides, 5 sectors, 1024 bytes = 800K old map, new dir ADFS-E: 80 tracks, 2 sides, 5 sectors, 1024 bytes = 800K new map, new dir ADFS-F: 80 tracks, 2 sides, 10 sectors, 1024 bytes = 1600K new map, new dir ADFS-G: 80 tracks, 2 sides, 20 sectors, 1024 bytes = 3200K new map, new dir Tracks are interleaved, so track 0, side 0 is followed by track 0, side 1, etc., that is logical_sector=sector+track*2+side*2*n where n is the number of sectors per track. Hard drives use 256-byte logical sectors regardless of the physical sector size. Logical sector zero is 0 bytes from the start of the physical disk. New map ADFS hard disks have a boot block in logical sectors 12 and 13. The type of ADFS filesystem can be determined by looking for the "Hugo"/ "Nick" identifier that marks the start of the root directory 512 bytes into the filesystem and 1024 bytes in. This will be logical sector 2 with 256-byte sectors and logical sector 1 with 1024-byte sectors, and also tells you the directory size and whether floppies have sequential or interleaved tracks. "Hugo"/"Nick" at Sector Size Tracks Directory size 512 bytes in 256 bytes Sequential &500 bytes 1024 bytes in 1024 bytes Interleaved &800 bytes Unless otherwise mentioned, the rest of this document refers to logical sectors of 256 bytes, so logical sector 4 on a 1024-byte disk is physical sector 1 on track 0, and physical sector 4 on a 256-byte disk. There is also a later ADFS directory structure that uses a variable-length name heap. This is not covered in this document. Sector 0,1 - Free Space Map --------------------------- The first two sectors contain the free space map and disk identifier. Sector 0 contains the start sectors of the free space blocks, sector 1 contains the length of each free space block. 000-002 Start sector of first free space 003-005 Start sector of second free space 006-008 Start sector of third free space ... 0F6-0F8 Sector of Level 3 fileserver partition 'sec1', or zero 0F9-0FB Zero, or half RISC OS disk name at 0F7-0FB, interleaved with the even characters at 1F6-1FA 0FC-0FE Total number of sectors on disk 0FF Checksum of sector 0 100-102 Length of first free space 103-105 Length of second free space 106-108 Length of third free space ... 1F6-1F8 Sector of Level 3 fileserver partition 'sec2', or zero 1F9-1FA Zero, or half RISC OS disk name at 1F6-1FA, interleaved with the odd characters at 0F7-0FB 1FB-1FC Disk identifier 1FD Boot option, set with *OPT 4 1FE Pointer to end of free space list ie, 3*(number of free space blocks) 1FF Checksum of sector 1 The checksums are calculated by starting with 255, then adding with carry the 255 bytes of data, adding the bytes counting downwards from byte 254 to byte 0. The following BASIC code will do this. DEFFNadfs_sum(mem%):LOCAL sum%:sum%=255 FOR A%=254 TO 0 STEP -1 IF sum%>255:sum%=(sum%+1)AND255 sum%=sum%+mem%?A%:NEXT:=sum%AND255 Note that a lot of documentation (including earlier versions of this document) gets this wrong, often starting from 0 instead of 255, and adding upwards instead of downwards. The Disk Identifier is set to a random 16-bit number on initialisation. A 'Bad map' error is generated if the checksums are wrong, or if bits 29-31 of any start sector are nonzero, or if bits 29-31 of any length are nonzero. Sector 2-3 ---------- On a large-sector disk, the first five bytes of sector 2 must all be zeros to indicate it is a large-sector disk and that the root directory starts at sector 4 (1024-byte logical sector 1), and a floppy disk has interleaved tracks. Otherwise, the root directory starts at sector 2 with 256-byte sectors, and a floppy disk has sequential tracks. Root directory -------------- On large-sector ADFS disks the root directory starts at logical sector 4 (1024-byte logical sector 1), and directories are 8 sectors long (2 x 1024-byte sectors), and tracks on floppy disks are interleaved. On small-sector ADFS disks the root directory starts at sector 2, and directories are 5 sectors long, and tracks on floppy disks are ordered sequentially. The disk type is found by looking for the 'Hugo' or 'Nick' string at the start of sector 2, followed by looking at the start of sector 4 (1024-byte logical sector 1). Root Directory - sectors 2-6 or sectors 4-11 -------------------------------------------- The sectors following the Free Space Map contain the '$' root directory. The parent of the root directory is again the root directory. Directories ----------- Directories occupy five logical sectors (&500 bytes) on small-sector disks and have up to 47 entries, and eight logical sectors (&800 bytes) on large-sector disks and have up to 77 entries. Directories have the following layout. 000 Directory Header 005 First directory entry 01F Second directory entry 039 Third directory entry ... 4B1 47th directory entry 7xx 77th directory entry 4CB Small directory Footer 7D7 Large directory footer Directory Header ---------------- 0 1 2 3 4 +--+--+--+--+--+ +--+--+--+--+--+ |Sq| H u g o| or |Sq| N i c k| +--+--+--+--+--+ +--+--+--+--+--+ 000 Directory Master Sequence Number in BCD 001-004 Directory identifier RISC OS ADFS recognises "Hugo" and "Nick" 8-bit ADFS only recognises "Hugo" Directory Entries ----------------- 0 1 2 3 4 5 6 7 8 9 A B C D E F 10 11 12 13 14 15 16 17 18 19 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | Object name and attributes | Load Addr | Exec Addr | Length | Sector |Sq| +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 000-009 Object name and access bits Access bits are encoded in b7 of bytes 000-009 on small-sector disks 000: 'R' - object readable 001: 'W' - object writable 002: 'L' - object locked 003: 'D' - object is a directory 004: 'E' - object execute-only 005: 'r' - object publicly readable 006: 'w' - object publicly writable 007: 'e' - object publicly execute-only 008: 'P' - object private 009: - unused Files are created with 'WR' access, directories are created with 'DLR' on 8-bit systems and 'DR' on 32-bit systems. ADFS ignores the bits stored in bytes 5 to 8, but some ADFSs will store and retrieve them to allow them to be preserved when transfering files to and from other filing systems. 00A-00D Load address 00E-011 Execution address 012-015 Length 016-018 Start sector/allocation number 019 Sequence number on small-sector disks Access byte on large-sector disks as %00wrDLWR Directory Footer - small directories ------------------------------------ 4CB 4CD 4CF 4D1 4D3 4D5 4D7 4D9 4DB 4DD 4DF 4E1 4E3 4E5 4E7 4E9 4EB 4CC 4CE 4D0 4D2 4D4 4D6 4D8 4DA 4DC 4DE 4E0 4E2 4E4 4E6 4E8 4EA +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ |00| Directory name | Parent | Directory title | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 4ED 4EF 4F1 4F3 4F5 4F7 4F9 4FB 4FD 4FF 4EC 4EE 4F0 4F2 4F4 4F6 4F8 4FA 4FC 4FE +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | Reserved, set to &00 |Sq| H u g o|Ch| +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ Directory Footer - large directories ------------------------------------ 7D7 7D9 4DB 4DD 4DF 7E1 7E3 7E5 7E7 7E9 7EB 7ED 7EF 7D8 7DA 7DC 7DE 7E0 7E2 7E4 7E6 7E8 7EA 7EC 7EE +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ |00|00 00| Parent | Directory title | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 7F1 7F3 7F5 7F7 7F9 7FB 7FD 7FF 7F0 7F2 7F4 7F6 7F8 7FA 7FC 7FE +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+ | Directory name |Sq| H u g o|Ch| or |Sq| N i c k|Ch| +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+ SmallDir LargeDir 4CB 7D7 &00 - marks end of directory 4CC-4D5 7F0-7F9 Directory name 4D6-4D8 7DA-7DC Start sector of parent directory 4D9-4EB 4DD-7EF Directory title - initially set to same as directory name. 4EC-4F9 7D8-7D9 Reserved (set to zero) 4FA 7FA Directory Master Sequence Number in BCD 4FB-4FE 7FB-7FE Directory identifier - "Hugo" (or "Nick" in LargeDirs) 4FF 7FF &00 - This is used by 32-bit ADFS as a directory checksum, if it is zero it is ignored. 8-bit ADFS always ignores it, and writes it as a zero. A directory is reported as 'Broken' if the Master Sequence Number and "Hugo"/"Nick" strings do not match - bytes &000-&004 are compared with bytes &4FA-&4FE/&7FA-&7FE. Strings in directories are terminated with &0D or &00 if shorter than ten characters, they are not space padded as with most other filesystems. The objects in a directory are always stored in case-insensitive sorted order. If objects are not sorted, then mis-sorted entries will not be found by filing system operations. The final directory entry is followed by a &00 byte, in a full directory this &00 byte is the byte at &4CB/&7D7. Solidisk ADFS implements directory passwords using the reserved space at &4EC-&4F9. Object sector start ------------------- With 'old map' ADFS an object's start sector is the logical sector that the object starts on in the filesystem. This will be a single contiguous block of data. With 'new map' ADFS (ADFS-E and later) an object's start sector is an allocation number that indexes into the allocation map to locate the object within the filesystem. This may be scattered into fragments. Identifying a disk ------------------ (Initial notes) With a physical floppy, read the sector sizes. 256-byte sectors indicates the disk uses 256-byte sectors, 1024-byte sectors indicates 1024-byte sectors. Untested if 256-byte ADFS within 1024-byte sectors is recognised. With a disk image or hard drive: Read the sector 512 bytes from the start of the filesystem. This will be logical sector 2 for 256-byte sector disks and the middle of logical sector 0 for 1024-byte sector disks. If there is a "Hugo"/"Nick" directory marker then the disk uses 256-byte logical sectors, &500-byte directories, and object start sector numbers and free space map, and this is the start of the root directory. If there is no "Hugo"/"Nick" marker, read from 1024 bytes into the filesystem. This will be logical sector 1 for 1024-byte sector disks. If there is a directory marker here, the disk uses 1024-byte sectors, &800-byte directories and this is the start of the root directory. If there is no Hugo/Nick marker here, fail to recognise the disk. For a more vigourous test, check the end of the root directory has a matching Hugo/Nick marker. With 1024-byte sectors, further tests are needed to decide what map is used. History ------- 11-Feb-2018 Added note on new map start sector. Corrected new dir access byte. Described physical floppy formats as a table. Initial notes on identifying a disk or image. 10-Feb-2016 Initial version.