home *** CD-ROM | disk | FTP | other *** search
/ Amiga Developer CD v1.2 / amidev_cd_12.iso / reference / amiga_mail_vol1 / dos / ffsandrom < prev    next >
Text File  |  1990-01-26  |  18KB  |  390 lines

  1. (c)  Copyright 1989 Commodore-Amiga, Inc.   All rights reserved.
  2. The information contained herein is subject to change without notice, and 
  3. is provided "as is" without warranty of any kind, either expressed or implied.  
  4. The entire risk as to the use of this information is assumed by the user.
  5.  
  6.  
  7.  
  8.  
  9.                   Low Level Differences Between FFS 
  10.                      and the ROM Filing System
  11.  
  12.                          by Steve Beats
  13.  
  14.  
  15. Most developers know by now that a Fast Filing System (FFS) for hard disks 
  16. has been added to V1.3 of the Amiga system software.  The following are 
  17. descriptions and 'C' structure definitions representing the current layout 
  18. of data on both the new FFS and the old ROM filing system disks.  
  19.  
  20. These structures are provided for those of you who wish to write disk salvage
  21. utilities and have a valid requirement for this information.  It is also quite
  22. useful to have this information handy if you've managed to trash a partition
  23. and only have DiskEd available to attempt fixing it.  Please note that these
  24. structures assume a fixed, 512 byte disk block.  This is a valid assumption 
  25. for filing systems up to V1.3.  However, this will NOT be the case under
  26. V1.4 Kickstart which will support full variable-sized disk blocks.
  27.  
  28. DiskDoctor-type utilities should run as many DOS checks as possible before
  29. assuming a disk has the layout described here.  Check the DOS type field on
  30. the boot block and run checksums on the root block after ensuring that the
  31. static fields are set to the expected values.  Hash table size will always
  32. be set to 72 for instance, this can be used as one of the consistency checks
  33. before proceeding to directly read from or write to the disk.
  34.  
  35. NEVER use this knowledge in an application program.  It is guaranteed to
  36. break under V1.4 Kickstart.  We are moving away from the single file system
  37. environment, especially since it's so easy to create and mount alternate
  38. filing systems on the Amiga.  Applications should stick strictly to the DOS
  39. library routines or the packet interface to a filing system.  Any other method
  40. of accessing files from the disk will not work.
  41.  
  42.  
  43.  
  44.  
  45.  
  46. The Boot Block
  47. --------------
  48.  
  49. The boot block is always on the first sector of a partition.  This is
  50. calculated as LowCyl * Surfaces * BlocksPerTrack.  The only field of any 
  51. use in the boot block is the first ULONG.  This should contain the string 
  52. "DOS" terminated by a 0 for the old filing system or a 1 for the fast filing 
  53. system.  Generally this should be the only field that needs checking to 
  54. determine file system type.  
  55.  
  56. However, if the first cylinder of a partition has gone bad, this field may 
  57. be invalid.  In this case, it is possible to use just the root block and the 
  58. data blocks to determine file system type.  Under V1.3 Workbench, DOSType
  59. can be determined from the environment vector for the given partition
  60. so this is a good alternative to snooping other parts of the disk.
  61.  
  62. On floppy drives, the boot block will also contain boot code which is
  63. responsible for initializing DOS when booting from a floppy.  Make sure this 
  64. data remains valid, or advise the user to run Install before using the 
  65. "doctored" disk again.  On hard disks, there is no code executed from the 
  66. boot block, it is the responsibility of an autobooting hard disk driver to do 
  67. the DOS intitialization.  In this case, it's OK to write back the boot block 
  68. with just the DOSx identifier initialized.
  69.  
  70.  
  71. Root Block
  72. ----------
  73.  
  74. This is the most important block as far as the filing system is concerned.
  75. It is called the root block because it is actually the "root" of the filing 
  76. system tree.  All other files and directories are accessed by keying them 
  77. off the root block.  Even if a file is stored many levels deep in the 
  78. directory structure, it is ultimately connected to the root through its
  79. parent directories.
  80.  
  81. If the root block of a disk goes bad, then the whole partition will have to 
  82. be scanned for "orphaned" files and directories.  The links to these 
  83. recovered files will have to be rebuilt in a new root block which can then 
  84. be written back to disk.  
  85.  
  86. The root is positioned such that the worst case seek to get to the root will 
  87. be no more than half the number of cylinders in the partition.  In other 
  88. words, the root is in the middle of the partition.  The disk block that the 
  89. root is stored on is calculated as follows:
  90.  
  91.     LowerKey = LowerCyl * Surfaces * BlocksPerTrack + Reserved
  92.     UpperKey = ((UpperCyl+1) * Surfaces * BlocksPerTrack) - 1
  93.     RootKey  = (UpperKey - LowerKey) / 2
  94.  
  95. Note that the UpperKey used here may not be the physical UpperKey used by 
  96. an FFS partition if PreAlloc is set to something other than 0.  Since the use 
  97. of PreAlloc was a new feature of FFS it was not included in the calculation 
  98. of the root block so as to maintain compatibility with the Format and DiskEd 
  99. commands.  If an FFS partition is being used, UpperKey should be modified as 
  100. UpperKey -= PreAlloc AFTER performing the root block calculation.  The values 
  101. of UpperKey and LowerKey will be useful for checking extension and hash 
  102. chains for validity.
  103.  
  104.    Note: all block numbers stored within the filing system are relative to
  105.    the beginning of the partition not including the Reserved blocks.  This
  106.    means that the physical disk block = LowerKey + Block# - Reserved.  Since
  107.    a block number of 0 is used to terminate lists, the zero block can never 
  108.    be made available to the filing system.  Hence the need for at least 1
  109.    "Reserved" block on all partitions.
  110.  
  111. Here is the 'C' structure definition of a 512 byte root block as used by
  112. both FFS and OLDFS partitions or floppies.  It is very similar to a 
  113. UserDirectoryBlock but some of the fields are different or used in a 
  114. different manner by the filing system.
  115.  
  116.  
  117.  
  118.  
  119.    struct RootBlock {
  120.     LONG    Type;        /* This is used to mark the type of this
  121.                    block and is set to TYPE_SHORT (2) */
  122.     ULONG    OwnKey;        /* Not used by root, must be set to 0 */
  123.     ULONG    SeqNum;        /* Not used by root, must be set to 0 */
  124.     ULONG    HTSize;        /* Size of the hash table in longwords,
  125.                    must be set to 72 */
  126.     ULONG    Nothing1;    /* reserved for future revs, must be 0 */
  127.     LONG    Checksum;    /* balance to 0 checksum.  When all longs
  128.                    in the block are added (ignoring carry)
  129.                    the sum should be 0 */
  130.     ULONG    HashTable[72];    /* hash table containing block numbers of
  131.                    files and directories in the root */
  132.     LONG    BitmapFlag;    /* flag to say whether the bitmap is valid
  133.                    or not.  -1=valid. 0=invalid.  If a
  134.                    partition is mounted (or uninhibited)
  135.                    with BitmapFlag = 0 then the validator
  136.                    will kick in to rebuild the bitmap */
  137.  
  138. /* the BitmapKeys and BitmapExtend fields shown here are valid for FFS only.
  139.    The ROM filing system has these two entries reversed and the slots in the
  140.    BitmapKeys array are used from BitmapKeys[24] to BitmapKeys[0] */
  141.  
  142.     ULONG    BitmapKeys[25];    /* An array of block numbers for the bitmap
  143.                    on this partition.  A block number of 0
  144.                    indicates the end of the list. */
  145.     ULONG    BitmapExtend;    /* If all of the BitmapKeys have been used
  146.                    then this will contain the block number
  147.                    of a disk block containing more Bitmap-
  148.                    Keys.  0 means no extender block present.
  149.                    OLDFS has a bug where it assumes that
  150.                    the root has protection bits and attempts
  151.                    to set them.  Since they coincide with this
  152.                    field, this is why there is a 53Meg limit
  153.                    on partition size under OLDFS */
  154.     ULONG    DirAltered[3];    /* A DOS DateStamp indicating the date when
  155.                    the root block was last modified or a
  156.                    file in the root block was modified */
  157.     char    Name[40];    /* Name of this volume as a BCPL string
  158.                    with number of bytes as the first
  159.                    character.  Only 30 chars used */
  160.     ULONG    DiskAltered[3];    /* A DOS DateStamp indicating the date when
  161.                    any file or section of the partition was
  162.                    modified.  (FFS has a bug which prevents
  163.                    it from updating this correctly, the
  164.                    DirAltered date gets changed instead) */
  165.     ULONG    DiskMade[3];    /* A DOS DateStamp indicating the date when
  166.                    this partition was first formatted and
  167.                    therefore created */
  168.     ULONG    Nothing2;    /* reserved for future revs, must be 0 */
  169.     ULONG    Nothing3;    /* reserved for future revs, must be 0 */
  170.     ULONG    Nothing4;    /* reserved for future revs, must be 0 */
  171.     LONG    SecondaryType;    /* Qualifier to Type.  Will be set to
  172.                    ST_ROOT (1) */
  173. };
  174.  
  175.  
  176. Bitmap Extension
  177. ----------------
  178.  
  179. Bitmap extensions, which are pointed to by the BitmapExtend entry in the root 
  180. block, are very simple in structure.  They consist of a list of 127 pointers 
  181. to bitmap blocks with the last entry being a pointer to another bitmap
  182. extender block.  There are no checksums on this data at all.  An entry of
  183. 0 terminates the list.
  184.  
  185.  
  186. Bitmap blocks
  187. -------------
  188.  
  189. Bitmap blocks are pointed to by the root blocks BitmapKeys array and also
  190. by any subsequent bitmap extender blocks if the disk is large enough.
  191.  
  192. Each bitmap block contains a longword sum-to-zero followed by 127 longs of 
  193. bitmap information (i.e., the 128 longwords in the bitmap block will sum up 
  194. to zero on a valid disk).  This means that each bitmap block can hold enough
  195. information for 127*32 disk blocks or just less than 2 Megabytes of disk
  196. space.  
  197.  
  198. The bits in the bitmap do not correspond exactly to the way that the blocks 
  199. are arranged on the disk.  This is an artifact caused by the method in which 
  200. the bitmap is accessed.  When determining or setting the state of a bitmap 
  201. entry, the filing system fetches the data a longword at a time and then uses 
  202. the block number modulo 32 to determine which bit in that longword is to be 
  203. examined.  
  204.  
  205. This means that bit 0 of longword 0 corresponds to block LowerKey while bit 0 
  206. of longword 1 corresponds to block LowerKey+32.  If you were to examine the 
  207. bitmap left to right one bit at a time, the bits would appear to be backwards
  208. on 32 bit boundaries.  However, if you access the bits logically using the 
  209. 68000 bit manipulation instructions, left to right ordering is preserved.
  210.  
  211. The bitmap only contains information about the blocks LowerKey through 
  212. UpperKey.  That is, Reserved and PreAlloc'ed blocks are not included in the 
  213. bitmap.  The bitmap blocks themselves are included and marked as used.
  214.  
  215. A bit set to 1 in the bitmap indicates that the corresponding block in the
  216. partition is free while a 0 bit indicates that the block is used.  While
  217. this may seem backwards, there is a valid reason for this.  When the filing 
  218. system is searching for a free block it is much easier to test a longword at
  219. a time for the non-zero condition.  This indicates that there is a free bit 
  220. somewhere in that block of 32 bits and a bit search can be started.  
  221.  
  222. If 0 were to indicate a free block, every single bit would have to be tested 
  223. individually to see if there were any free ones.  Testing all 32 bits at 
  224. once would not yield any useful information apart from the fact that all of 
  225. the blocks were free, a particularly rare occurence in a typical partition.
  226.  
  227.  
  228.  
  229.  
  230. User Directory Blocks
  231. ---------------------
  232.  
  233. The user directory blocks are distinct from the root block in that they are 
  234. creatable and deletable by the user or application program.  The root block, 
  235. while being a special case of a directory, cannot be created or deleted 
  236. using normal filing system calls.  Another major distinction is that the root 
  237. will NEVER have a parent directory while user directory blocks will ALWAYS 
  238. have one.
  239.  
  240.    struct UserDirectoryBlock {
  241.     LONG    Type;        /* This is used to mark the type of this
  242.                    block and is set to TYPE_SHORT (2) */
  243.     ULONG    OwnKey;        /* Set to directory's own block number */
  244.     ULONG    Spare1;        /* Not used, must be set to 0 */
  245.     ULONG    Spare2;        /* Not used, must be set to 0 */
  246.     ULONG    Spare3;        /* Not used, must be set to 0 */
  247.     LONG    Checksum;    /* balance to 0 checksum.  When all longs
  248.                    in the block are added (ignoring carry)
  249.                    the sum should be 0 */
  250.     ULONG    HashTable[72];    /* hash table containing block numbers of
  251.                    files and directories in this directory */
  252.     LONG    Spare4;        /* Not used, must be set to 0 */
  253.     LONG    Spare5;        /* Not used, must be set to 0 */
  254.     ULONG    Protection;    /* Protection bits for this directory */
  255.      LONG    Spare6;        /* Not used, must be set to 0 */
  256.     char    Comment[92];    /* Directory comment as a BCPL string, only
  257.                    80 characters can be used including the
  258.                    length byte at the beginning */
  259.     ULONG    Created[3];    /* DOS DateStamp struct indicating when
  260.                    this directory was created or modified */
  261.     char    DirName[36];    /* name of this directory as a BCPL string.
  262.                    only 30 characters are used */
  263.     LONG    Spare7[7];    /* Not used, must be set to 0 */
  264.     ULONG    HashChain;    /* block number of the next file on the
  265.                    hashchain if there's a hashing collision.
  266.                    0 means no next file or directory. */
  267.     ULONG    Parent;        /* Block number of the parent directory of
  268.                    this directory.  */
  269.     ULONG    Spare8;        /* Not used. must be set to 0 */
  270.     LONG    SecondaryType;    /* Qualifier to Type.  Will be set to
  271.                    ST_USERDIR (2) */
  272.  
  273.    };
  274.  
  275.  
  276. File Header Blocks
  277. ------------------
  278.  
  279. All files have an associated file header block that describes the file name 
  280. and creation date along with pointers to the required ancilliary data such 
  281. as extension blocks and protection information.  When a file is Locked the 
  282. returned FileLock has a field called fl_Key.  This field contains the block 
  283. number where this header can be found in the partition. (This field contains 
  284. an address in the case of the RAM disk).  
  285.  
  286. This is one of the few things that can be assumed about file locks, and will
  287. be supported in future revisions of the DOS filing system.  It's advisable
  288. for alternate filing systems to support this field too, though not strictly 
  289. nescessary or enforced by the operating system.
  290.  
  291.    struct FileHeaderBlock {
  292.     LONG    Type;        /* This is used to mark the type of this
  293.                    block and is set to TYPE_SHORT (2) */
  294.     ULONG    OwnKey;        /* Set to file headers own block number */
  295.     ULONG    HighSeq;    /* total blocks used in file (not updated
  296.                    by FFS, only the old filing system) */
  297.     ULONG    DataSize;    /* number of data blocks used for this file */
  298.     ULONG    FirstBlock;    /* block number of first block in the file */
  299.     LONG    Checksum;    /* balance to 0 checksum.  When all longs
  300.                    in the block are added (ignoring carry)
  301.                    the sum should be 0 */
  302.     ULONG    DataBlocks[72];    /* table of block numbers for the first 72
  303.                    blocks of data in this file.  Slots are
  304.                    used from DataBlocks[71] back to
  305.                    DataBlocks[0], then extension is used */
  306.     ULONG    Spare1;        /* Not used, must be set to 0 */
  307.     ULONG    Spare2;        /* not used, must be set to 0 */
  308.     ULONG    Protect;    /* protection bits mask */
  309.     ULONG    Date[3];    /* DOS DateStamp indicating creation date */
  310.     char    FileName[36];    /* Filename (only 30 characters used though) */
  311.     ULONG    Spare3[7];    /* not used, must be set to 0 */
  312.     ULONG    HashChain;    /* next entry with the same hash value */
  313.     ULONG    Parent;        /* block number of parent directory */
  314.     ULONG    Extension;    /* when all data block slots are used, this
  315.                    points to an extension block that has the
  316.                    same format as the file header block (but
  317.                    FileName and Date are not maintained and
  318.                    secondary type is ST_LIST (16)). A
  319.                    Block number of 0 terminates the list */
  320.     LONG    Second;        /* qualifier to type = ST_FILE (-3)
  321.    };
  322.  
  323.  
  324.  
  325. Data Blocks
  326. -----------
  327.  
  328. FFS puts nothing but data into data blocks so that it can make full use of 
  329. a DMA controller.  There is no need to strip any extra information before the 
  330. data can be DMA'ed directly to the caller's buffer.  The old filing system is 
  331. a little more paranoid and puts a lot of checksum information at the front
  332. of each data block.  The format of a data block under the old system is as 
  333. follows.
  334.  
  335.    struct FileDataBlock {
  336.     LONG    Type;        /* This is used to mark the type of this
  337.                    block and is set to TYPE_DATA (8). There
  338.                    is no secondary type on a data block */
  339.     ULONG    OwnKey;        /* Set to data blocks own block number */
  340.     ULONG    SeqNumber;    /* Sequence number of this block in the file */
  341.     ULONG    DataSize;    /* number of bytes of info used in this block */
  342.     ULONG    NextBlock;    /* block number of next block in the file */
  343.     LONG    Checksum;    /* balance to 0 checksum.  When all longs
  344.                    in the block are added (ignoring carry)
  345.                    the sum should be 0 */
  346.     char    Data[488];    /* the actual data */
  347.    }
  348.  
  349.  
  350. Hashing Algorithm
  351. -----------------
  352.  
  353. The hashing algorithm, which is used to determine where a file header goes in
  354. the hash table of a directory, is the same for both FFS and the ROM filing
  355. system.  The easiest way to describe it is with a small 'C' function.  Given
  356. a CPTR to a BCPL string, this routine will return the array index into the
  357. hash table.  This value is used to insert the file header with that name into
  358. the appropriate hash table entry in the owning directory.
  359.  
  360. Hash( name )
  361. unsigned char *name;
  362. {
  363. int val,i;
  364.  
  365.     val = (int)*name++;
  366.     for(i=0; i<val; i++) val = ((val*13) + (int)toupper( *name++ ))&0x7ff;
  367.     return(val % 72);
  368. }
  369.  
  370. One major difference between FFS and the old filing system is that hash 
  371. chains MUST be sorted for FFS.  When a hashing collision occurs, files
  372. are linked together using the HashChain entry in the FileHeaderBlock or
  373. UserDirectoryBlock.  The old filing system sticks the new header at the
  374. head of the list, while FFS merges the new header into the list in
  375. ascending block order.  
  376.  
  377. If FFS finds an unsorted hashchain, files will begin to dissappear when 
  378. ExNexting a directory.  This "missing" file can still be accessed by name, 
  379. so renaming it something else and back to its original name will resort the 
  380. hashchain.  This should only be a problem if your FFS partition was created 
  381. using early gamma versions of FFS and you didn't reformat when installing 
  382. the release version.
  383.  
  384. Most differences between the old filing system and the new Fast Filing System
  385. have been covered here.  Remember it is not appropriate to use this
  386. information in applications other than disk salvage utilities.  You should
  387. expect more changes to the file system under V1.4.  In particular, variable
  388. sized blocks will be supported in the next release.  Stick to system calls
  389. and the packet interface to insure future compatability.
  390.