AFS0 disc format

With thanks to Alan Williams
EEA index

FileStore
Description
Hardware
Error codes
NVRAM
Disc format
Disc image
Accessing
Password file
E01 vs E01S
Rescuing
Emulator
SD card

Intro
MDFS
Others
Clocks
Bridges
Interfaces
Misc h/w
Testing
Misc info

Introduction

All sectors are uniquely numbered from the start of the disc. Sectors are 256 bytes long.
Under Level 3 the disc is partitioned, part of the disc is an ADFS area, the remaining part is set aside for network use.

 

Level 3

For reference, the Level 3 harddisc is laid out as shown below. It appears as if the disc is laid out as two "partitions", the first is an ADFS partition (on track zero) and the file server (NFS) partition (starting on track one).
This split-partitioning persists in the FileStore, and is - I believe - a hangover of the earlier (Level 3) having the harddisc connected via ADFS.
The ADFS partition is provided purely to supply important drive parameters in a format that ADFS understands.
  • Sector zero
    Bytes 246 - 248: Pointer to 1st sector of NFS partition
    (24 bit address)
  • Sector one
    Bytes 246 - 248: Pointer to copy of 1st sector of NFS partition
    (24 bit address)
Can anybody help fill out more information on this part of the disc format?

 

NFS Sector 1

The initial NFS sector is laid out as follows:
Byte(s) Meaning
 
 0 -  3 "AFS0", indicates a Fileserver disc
 
 4 - 19 16 characters - disc name
 
20 - 21 Number of cyclinders on the disc
(16 bit, LSB first)
 
22 - 24 Number of sectors on the disc
(24 bit, LSB first)
 
25 Number of physical discs in logical fileserver
(generally unused)
 
26 - 27 Number of sectors per cylinder
(16 bit, LSB first)
 
28 Number of sectors per bit map
 
29 Increment to drive number to start next drive
(generally unused)
 
30 Unused
 
31 - 33 SIN of root directory
(24 bit, LSB first)
 
34 - 35 Date of initialisation (LSB = Day in month; MSB = Month + (16 * (Year - 1981))
This looks suspiciously like the old style Econet date - does the FileStore include support for the newer date format that will cope with dates after 1996?
 
36 - 37 First free cylinder
(16 bit, LSB first)
 
38 If non-zero, the disc is a floppy disc
All objects are referred to by SIN (System internal name). The SIN points to a map which gives the location of the object on store.

 

Free space map

On initialisation, the first sector, and the copy of the first sector, will always be sector 1 in a particular cylinder.
[reading this many years later, it does not make much sense - does anybody have the formatter in source form? I only have the compressed form which isn't so easy to read!]

The first sector in every NFS cylinder contains a bit-map of that cylinder's sectors. If, for example, a harddisc has 132 sectors per cylinder, the first sector of each cylinder has a bit map containing 132 bits.

There are 8 bits to a byte, and therefore the bit relating to sector 'n' of a cylinder is bit (n MOD 8) in byte (n DIV 8). If a sector is occupied, that bit is set to zero, otherwise the bit is set to one. I have highlighted this as it may appear backwards. One means emply.
Bit zero of byte zero of a map is always set to zero - even an empty cylinder has its first sector occupied, by the bit map.

Floppy discs operate slightly differently. It would be a waste to lose a sector per track on the bitmap, so they use a packed version of the map, for which I currently have no information.

 

Map sector

Byte(s) Meaning
 
0 - 5 "JesMap" indicates that this is a map sector.
 
6 Map chain sequence number.
A map can extend over several sectors, the last entry in a particular sector pointing to the next part of the map.
The sequence number is a copy of the last byte of the current MAP sector.
 
7 Unused
 
8 LSB of object length
 
9 Unused.
 
10 - xx A list of occupied sectors, each entry consisting of five bytes:
0 - 2 : lowest numbered sector in contiguous group, LSB first
3 - 4 : number of contiguous sectors in group LSB first
The object's length is determined by byte 8 plus the total number of sectors occupied.

 

Directory structure

Directories contain two linked lists. One list contains the objects in the directory, and is maintained in alphabetical order. The other contains a linked list of free entries in the directory.

The entries in the linked lists are measured relative to the start of the directory, so 50B would refer to an entry beginning at byte 0B in sector 05 of the directory. The last entry in either linked list is 00.

Byte(s) Meaning
 
0 - 1 Pointer to first entry in object linked list (LSB first)
 
2 Cycle number of directory
 
3 - 12 10 characters of directory name
 
13 - 14 Pointer to first entry in free entries linked list (LSB first)
 
15 - 16 Number of entries in the directory. This is specified as a 16 bit number (LSB first), though in reality a directory cannot be more than 255 entries long.
 
17 - xx Contents of directory, 26 bytes per entry:
0 - 1 Pointer to next entry in linked list
2 - 11 10 characters of object name
12 - 15 Load address (4 bytes)
16 - 19 Exec address (4 bytes)
  On RISC OS machines, the load and exec addresses are usually replaced by the filetype (3 bytes) and datestamp (5 bytes).
20 Attribute byte
b7 undefined (on some systems this may be interpreted as 'hidden')
b6 undefined (on some systems this may be interpreted as 'protected directory')
b5 If 1, is writeable by others
b4 If 1, is readable by others
b3 If 1, is locked
b2 undefined (on some systems this may be interpreted as 'execute')
b1 If 1, is writeable by owner
b0 If 1, is readable by owner
21 - 22 Date of most recent update to entry (as per date of initialisation)
23 - 25 SIN of object, LSB first
The last byte of the directory is a copy of the sequence number. This is used to check for broken directories.

 

Converting SINs to an actual disc address

It appears that in order to convert a SIN to an actual disc address, we need only shift it eight places to the left, i.e.:
disc_address% = object_sin% << 8

This will be because a sector is either used or not used. As each sector is 256 bytes long, a SIN can only point to an address that is &xxxxxx00.

 

Reading FileStore discs on a RISC OS machine

I tried to write a FileStore "AFS0" disc filing system (similar in concept to DOSFS), but it does not work correctly. It scans for disc information on the Service_IdentifyDisc call, reads the NFS sector to retrieve the disc size, shape, etc. Upon claiming the service call it causes the filer to report an address exception and maybe crash.
I present you the bare-bones source code if you wish to have a look and see what I have monumentally screwed up. Download fsfs.zip (14K). Written in C/assembler.
The module has been officially registered, so you should use the SWI chunk 0x561C0. The filing system number for FSFS should be 175, and the disc filetype for FSFS images should be 0xA94, called "FSFSdisc".

Alternatively, if you are only looking to pull some files off of a FileStore disc, my 'BudgieSoft' Econet Management Suite contains a program called !FSfloppy which is a three part process to create a directory containing a mirror of the files on the FileStore disc.
The three parts to the process are:

  • FetchDisc - to verify the disc format and then read the entire disc as a big file. Logically, this will require ~640Kb of disc space for the disc image.
  • BuildMap - will scan through the disc image (created by Fetchdisc) looking for files and directories. It does not follow recursively, it scans from end to end adding directories on one pass and examining them on the following pass. When no more directories are to be added, the process is complete.
    This isn't the most logical way to attack this problem, however it was the easiest to create and implement.
  • Resolver - will take the index file created by BuildMap and the image created by FetchDisc and pull out the files, creating directories if necessary. It can follow non-contiguous blocks (following the information provided by BuildMap).
Not the most ideal solution, but one that works provided your disc is not corrupt! Full source code is available, so you can tweak or look at how I did it for writing something better!

 

Finally...

The passwords file is stored as "$.Passwords". It must be an integral number of sectors long (i.e. byte 8 of its JesMap must be zero). Other than that, it does not have to reside in any special part of the disc.


Copyright © 2009 Rick Murray