[comp.sys.amiga] An in-depth tutorial on the current file system, etc.

kim@amdahl.uts.amdahl.com (Kim DeVaughn) (06/18/88)

[ "You really have to be brain-dead to microwave your cheese." ]

I happened upon the attached last night on a local BBS, and think it's
one of the best tutorials on the existing file system, etc. that I've
seen!  Not only does it pull together alot of information in one place,
but it also provides practical info on how to *use* a sector editor
utility (like Sectorama, etc.) effectively.

A real nice job and alot of thanks to the author, Dwayne Miller!

/kim



# This is a shell archive.  Remove anything before this line, then
# unpack it by saving it in a file and typing "sh file".  (Files
# unpacked will be owned by you and have default permissions.)
#
# This archive contains:
# disk.tutorial

echo x - disk.tutorial
cat > "disk.tutorial" << '//E*O*F disk.tutorial//'



            An Explanation of AmigaDOS Storage Device Structure

  In order for you to use a disk editor to its full disk-saving/disk-altering
potential, you must first understand the structure of an AmigaDOS device.
References will be made to a P.D. disk editor called 'Sectorama', though the
basic information and principals presented in this doc will be applicable to
all disk editors.  Note that to avoid confusion and to provide immediately
applicable info, the block formats presented in this doc are specifically for
512 byte blocks.  For larger blocks, the size of the Hash Table will vary and
all info after the hash table will be displaced ahead of the hash table so
the secondary-type word is at the end of the block.  All devices I know of to
this point use a 512 byte block.

  This document is basically written in two parts.  The first part is an
explanation of what each word in each type of block, how various types
of blocks are structured, and how all these blocks relate to one another on
an AmigaDOS storage device.  The second part is an explanation of how to do
things with a disk editor such as sectorama.



I) BLOCK BASICS
   ============

  Generally, each block on an AmigaDOS device contains a checksum, a header
key whose value is the disk address of the block, and a block type which tells
you what type of block this is so you know what format that particular block
uses.  Note that when I use the term, 'block', I am referring to a 512 byte
chunk of storage space on an AmigaDOS device.  For example, on a floppy or
hard drive, a block refers to a 512 byte sector.  In VDO: and RAM:, a block
refers to 512 contiguous bytes somewhere in memory.  Also note that the size
of each datum in a block is a 32 bit word.  For all blocks, the first
six words are as follows:

     +--------------------+
   0 |    Block Type      |
     +--------------------+
   1 |    Header Key      |
     +--------------------+
   2 |  Number or count   |
     +--------------------+
   3 | Table or Data size |
     +--------------------+
   4 | First or next data |
     +--------------------+
   5 |     Checksum       |
     +--------------------+
     :                    :

Block Type  - This identifies the general size and structure of this block.
              It currently has one of three values:

              T.SHORT = 00000002  This indicates the block is at the head of
                                  a list (i.e. a HEADER BLOCK).

              T.LIST  = 00000010  This indicates the block is a LIST BLOCK.
                                  A list block is a member of a linked list
                                  list blocks and contains a table of pointers
                                  to data blocks.

              T.DATA  = 00000008  This indicates the block is a DATA BLOCK.
                                  A data block is simply a block that contains
                                  data and will be described later in this
                                  doc.

Header Key  - This 32-bit word is the device's address for this block.  It
              is a pointer to this block.

Number or Count - If this not a data block, this is a total count of data
                  blocks (and, hence, the highest sequence number of any
                  data block) pointed-to by this block.

                - If this block is a data block, this number is the sequence
                  number of this data block.  That is, it tells us this data
                  block is the n'th member of a list of data blocks.

Table or Data Size - This is a count of how many 32-bit words there are in
                     the table or data starting at word # 6 in this block.


First or Next Data - This is a pointer to the data block following this block.
                     If this block is a header or a list block, then this
                     pointer will point to the first data block in a list
                     of data blocks.

Checksum - When this number and the values of all other words in this block
           are added up, the sum must be zero.  This is how bad blocks are
           detected by AmigaDOS.

For all types of blocks excepting data blocks, the last four words have the
following format:

     :                :
     +----------------+
  7C |   Hashchain    |
     +----------------+
  7D |    Parent      |
     +----------------+
  7E |   Extension    |
     +----------------+
  7F | Secondary Type |
     +----------------+

Hashchain - points to the next entry on this hash chain.

Parent - pointer to the parent directory.  The parent directory is the
         directory block which either points to this block or points to a
         linked list (i.e. hash chain) of which this block is a member.

Extension - pointer to the next extension block which essentially extends the
            table which starts at word # 6 of this block.

Secondary Type - This exactly identifies what kind of block this is.  This
                 tells us exactly what function and structure this block has.
                 The possible codes in this word are:

                 ST.ROOT    = 00000001  This identifies the ROOT BLOCK, which
                                        is the device's 'root directory'.
                                        This block ultimately points to all
                                        the files and directories on the
                                        storage device.

                 ST.USERDIR = 00000002  This identifies a USER DIRECTORY BLOCK
                                        which points to all the files and
                                        directories which have been defined
                                        for this directory.

                 ST.FILE    = FFFFFFFD  This identifies either a FILE HEADER
                                        BLOCK, if the block type at word # 1
                                        is T.SHORT, or a FILE LIST BLOCK if
                                        the block type is T.LIST.
                                        A FILE HEADER BLOCK points to all the
                                        data blocks that make up the file.  If
                                        there are too many data blocks to be
                                        pointed to by this block, a list of
                                        FILE LIST BLOCKS is pointed-to by the
                                        extension pointer at word # 7E.  A
                                        FILE LIST BLOCK simply extends the
                                        table and points to the next FILE LIST
                                        BLOCK if more data block pointers are
                                        required.

Note that the above-mentioned word definitions are not applicable to some
block types and functions.  Where their function is non-applicable, their
value is usually set at zero.



II) THE ROOT BLOCK
    ==============

  The block that ultimately points to everything on the disk is called the
'Root Block'.  This block usually resides in the exact center of a storage
device to minimize the distance a read/write head of a floppy or hard disk
must move when travelling from an outer cylinder to the Root Block.  The
format of the Root Block is as follows:

        symbolic    usual
         value      value
     +----------------------+
   0 |  T.SHORT  = 00000002 |  Indicates this is a 512 byte header block
     +----------------------+
   1 |        0  = 00000000 |  Header Key (Always zero in a root block)
     +----------------------+
   2 |        0  = 00000000 |  Highest sequence number in chain (0 for root)
     +----------------------+
   3 |  HT SIZE  = 00000048 |  Hashtable size (=blocksize-56 = 512/4-56 words)
     +----------------------+
   4 |        0  = 00000000 |
     +----------------------+
   5 | CHECKSUM  =    ?     |  Checksum for this block
 ----+----------------------+
{  6 |                      |
{    |      Hash Table      |
{ to :                      :
{    :                      :
{ 4D |                      |
 ----+----------------------+
  4E |   BMFLAG  = FFFFFFFF |  True (all F's) if device or disk bitmap valid
 ----+----------------------+
{ 4F |                      |
{    |     Bitmap Pages     |
{ to :                      :
{    :                      :
{ 68 |                      |
 ----+----------------------+
  69 |     DAYS  =    ?     |  Volume last altered date and time.
     +----------------------+  Date is in packed format.
  6A |     MINS  =    ?     |  Time is rated in minutes and ticks.
     +----------------------+  One tick is 1/60th of a second.
  6B |    TICKS  =    ?     |
 ----+----------------------+
{ 6C |                      |  Volume name as a BCPL string of 30 characters
{    |      Disk Name       |  or less, though the amount of space to store
{ to :                      :  this string always remains the same size.
{    :                      :
{ 78 |                      |
 ----+----------------------+
  79 |CREATEDAYS =    ?     |  Date and time when this volume was created.
     +----------------------+  Format here, as well as all date/time data
  7A |CREATEMINS =    ?     |  presented in other types of blocks are in the
     +----------------------+  format shown for the above volume last altered
  7B |CREATETICKS=    ?     |  date and time.
     +----------------------+
  7C |        0  = 00000000 |  Next entry on this hash chain (0 for root)
     +----------------------+
  7D |        0  = 00000000 |  Parent directory (always 0 for root)
     +----------------------+
  7E |        0  = 00000000 |  Extension  (always 0 for root)
     +----------------------+
  7F |  ST.ROOT  = 00000001 |  Secondary type indicates this is a Root Block
     +----------------------+

-> What the heck is a HASH TABLE?

  A HASH TABLE is a table of pointers to files and to lists of files.  To
locate a particular file in the table, the name of the file is used to
calculate where in the table it is to be located.  This location may not be
unique to the name of this file.  In this case, the pointer will point to a
linked list of file headers which must be traversed until the file header for
the file we're searching for is found.  This linked list is referred to as a
HASH CHAIN.

  The actual searching-out of files will be discussed in more practical terms
in the practical portion of this document.

-> What things are pointed-to by pointers in a HASH TABLE?

  Each non-zero pointers in the hash table points to either a FILE HEADER
BLOCK or a USER DIRECTORY BLOCK which, in turn, may have a hash chain pointer
which will point to the next file header block or user directory block in
the hash chain.

-> What are bitmap pages?

  The words in the list of bitmap pages point to 512 byte blocks which
simply map-out which blocks on the device are used, and which are free for
usage.  I don't yet understand how the bitmaps are set-up or maintained,
but as soon as I find out, I'll slip the info into this document.

-> What is a BCPL string?

  This is a string of bytes where the first byte indicates the number of
characters in the string (say, 'n' characters), the next 'n' characters
contain the ASCII values for the string, and the rest of the string is
ignored.  For example, on my Workbench disk, a hex dump of the string looks
like this:

09576F72 6B62656E 63686F72 6B62656E .Workbenchorkben
63680000 00000000 00000000 00000000 ch..............
00000000 00000000                   ........

Where the 09 at the beginning specifies that only the next nine characters
are valid characters of the string and the rest are ignored.

Note that for the root block, zeros are always in the Header Key, Sequence
Number, Hash cain, Parent, and Extension fields.  This is because a ROOT BLOCK
is always at a specific spot on the device (for a disk, it is exactly
cenetered between the outer- and inner-most cylinders), it never require hash
table extensions, it is not pointed-to by a hash table and is not part of a
hash list, and it does not have a parent directory.



III) USER DIRECTORY BLOCKS
     =====================

  A user directory block is created when a new directory is made in a storage
device.  It contains its own name and protection status, its parent directory,
as well as a hash table pointing to files and user directories that have been
placed into this directory.  The hash table functions exactly the same way as
that in the ROOT BLOCK.  The format of a USER DIRECTORY BLOCK is as follows:

        symbolic    usual
         value      value
     +----------------------+
   0 |  T.SHORT  = 00000002 |  Indicates this is a 512 byte header block
     +----------------------+
   1 |  OWN KEY  =    ?     |  Header Key (pointer to this very block)
     +----------------------+
   2 |        0  = 00000000 |  Highest sequence number in chain (always zero)
     +----------------------+
   3 |        0  = 00000000 |
     +----------------------+
   4 |        0  = 00000000 |
     +----------------------+
   5 | CHECKSUM  =    ?     |  Checksum for this block
 ----+----------------------+
{  6 |                      |
{    |      Hash Table      |
{ to :                      :
{    :                      :
{ 4D |                      |
 ----+----------------------+
  4E |    SPARE  = 00000000 |
  4F |    SPARE  = 00000000 |
     +----------------------+
  50 |  PROTECT  =    ?     |  Protection bits (Read/Write/Execute/Delete)
     +----------------------+
  51 |        0  = 00000000 |  Unused (always zero)
 ----+----------------------+
{ 52 |                      |
{    |       COMMENT        |  Stored as a BCPL string
{ to :                      :  (up to 90 characters)
{    :                      :
{ 68 |                      |
 ----+----------------------+
  69 |     DAYS  =    ?     |  Directory creation date and time.
     +----------------------+
  6A |     MINS  =    ?     |
     +----------------------+
  6B |    TICKS  =    ?     |
 ----+----------------------+
{ 6C |                      |
{    |    Directory Name    |  Directory name as a BCPL
{ to :                      :  (up to 30 characters)
{    :                      :
{ 7B |                      |
 ----+----------------------+
  7C |HASHCHAIN  =    ?     |  Next entry with same hash value
     +----------------------+
  7D |   PARENT  =    ?     |  Back pointer to parent directory
     +----------------------+
  7E |        0  = 00000000 |  Extension  (always 0 for root)
     +----------------------+
  7F |  ST.ROOT  = 00000002 |  Secondary type indicates this is a Root Block
     +----------------------+



IV) FILE HEADER BLOCK
    =================

  This block is the first block of any given file.  It contains file
information such as the name, size, protection status, creation date, and a
pointer to the parent directory block of the file.  It also contains a table
of pointers to all the data blocks that make up the file.  If there are more
data blocks than there are pointers in the table of data block pointers (at
words # 6 to 4D), an extension pointer is provided to a FILE LIST BLOCK which
contains a similar table of data block pointers.  If the file list block
still doesn't provide enough pointers, it will provide yet another extension
pointer to another FILE LIST BLOCK.  This list of FILE LIST BLOCKS extends
until enough pointers are provided to point to all the data blocks of the
file.

        symbolic    usual
         value      value
     +----------------------+
   0 |  T.SHORT  = 00000002 |  Indicates this is a 512 byte header block
     +----------------------+
   1 |  OWN KEY  =    ?     |  Header Key (pointer to this very block)
     +----------------------+
   2 |HIGHEST SEQ=    ?     |  Number of data blocks pointed-to by this block
     +----------------------+
   3 |DATA SIZE  =    ?     |
     +----------------------+
   4 |FIRST DATA =    ?     |  Pointer to the first data block of the file
     +----------------------+
   5 | CHECKSUM  =    ?     |  Checksum for this block
 ----+----------------------+
{  6 |          :           |
{    :          :           :  List of pointers to data blocks
{ to :          :           :  (i.e. Data block keys)
{    |     DATA BLOCK 3     |
{    |     DATA BLOCK 2     |
{ 4D |     DATA BLOCK 1     |
 ----+----------------------+
  4E |    SPARE  = 00000000 |
  4F |    SPARE  = 00000000 |
     +----------------------+
  50 |  PROTECT  =    ?     |  Protection bits (Read/Write/Execute/Delete)
     +----------------------+
  51 | BYTESIZE  =    ?     |  Total size of file in bytes
 ----+----------------------+
{ 52 |                      |
{    |       COMMENT        |  Stored as a BCPL string
{ to :                      :  (up to 90 characters)
{    :                      :
{ 68 |                      |
 ----+----------------------+
  69 |     DAYS  =    ?     |  File creation date and time.
     +----------------------+
  6A |     MINS  =    ?     |
     +----------------------+
  6B |    TICKS  =    ?     |
 ----+----------------------+
{ 6C |                      |
{    |      File Name       |  File  name as a BCPL string
{ to :                      :  (up to 30 characters)
{    :                      :
{ 7B |                      |
 ----+----------------------+
  7C |HASHCHAIN  =    ?     |  Next entry with same hash value
     +----------------------+
  7D |   PARENT  =    ?     |  Back pointer to parent directory
     +----------------------+
  7E |EXTENSION  =    ?     |  Pointer to a FILE LIST BLOCK (if required)
     +----------------------+
  7F |  ST.ROOT  = FFFFFFFD |  Secondary type indicates this is a Root Block
     +----------------------+



V) FILE LIST BLOCK
   ===============

  This type of block is used to extend the table of data block keys
(pointers) of a FILE HEADER BLOCK when the table in the FILE HEADER BLOCK
hasn't enough pointers to point to all the file's data blocks.  If a FILE
LIST BLOCK doesn't have enough pointers to point to the rest of the file's
data blocks, the EXTENSION pointer of the block will point to yet another
FILE LIST BLOCK.  The extension list continues until enough pointers are
provided for all the data blocks in the file.

        symbolic    usual
         value      value
     +----------------------+
   0 |  T.LIST   = 00000010 |  Indicates this is a file list block
     +----------------------+
   1 |  OWN KEY  =    ?     |  Header Key (pointer to this very block)
     +----------------------+
   2 |BLOCK COUNT=    ?     |  Number of data blocks pointed-to by this block
     +----------------------+
   3 |DATA SIZE  = 00000000 |
     +----------------------+
   4 |FIRST DATA =    ?     |  Pointer to the first data block of the file
     +----------------------+
   5 | CHECKSUM  =    ?     |  Checksum for this block
 ----+----------------------+
{  6 |          :           |
{    :          :           :  Extended list of pointers to data blocks
{ to :          :           :  (i.e. Data block keys)
{    |     DATA BLOCK 3     |
{    |     DATA BLOCK 2     |
{ 4D |     DATA BLOCK 1     |
 ----+----------------------+
{ 4E |                      |
{    |        unused        |  unused (all zeros)
{ to :                      :
{    :                      :
{ 7B |                      |
 ----+----------------------+
  7C |        0  = 00000000 |  Next in hash list (always zero for list block)
     +----------------------+
  7D |   PARENT  =    ?     |  Points to the file header block of this file
     +----------------------+
  7E |EXTENSION  =    ?     |  Points to the next FILE LIST BLOCK (if required)
     +----------------------+
  7F |  ST.ROOT  = FFFFFFFD |  Secondary type indicates this is a Root Block
     +----------------------+



VI)  DATA BLOCK
     ==========

  A data block contains data from a file and is pointed-to by preceding
data blocks and by a pointer in a table in either a FILE HEADER BLOCK or a
FILE LIST BLOCK.  Thus, the data block can be accessed directly from a header
or list block of a file, or sequentially by following the linked list of data
blocks.  Each data block also points to the FILE HEADER BLOCK which describes
the file which contains this data block.  A sequence number is also present
in a data block, and indicates that this data block is the n'th data block
in the list of the file's data blocks.

        symbolic    usual
         value      value
     +----------------------+
   0 |  T.DATA   = 00000008 |  Indicates this is a data block
     +----------------------+
   1 |  HEADER   =    ?     |  Header key pointing to the file header block.
     +----------------------+
   2 |  SEQ NUM  =    ?     |  Sequence number
     +----------------------+
   3 | DATA SIZE = 00000000 |  Number of words of data in this block
     +----------------------+
   4 | NEXT DATA =    ?     |  Pointer to the next data block
     +----------------------+
   5 | CHECKSUM  =    ?     |  Checksum for this block
 ----+----------------------+
{  6 |                      |
{    |         DATA         |
{ to :                      :
{    :                      :
{ 7F |                      |
     +----------------------+



VII)  HOW DO THE BLOCKS FIT TOGETHER?
      ===============================

  The ROOT BLOCK is located at a fixed location, exactly between the highest
and lowest addresses available on a storage device.  The ROOT BLOCK contains
a table of pointers (the hash table) to linked lists (hash chains) of USER
DIRECTORY BLOCKS and FILE HEADER BLOCKS which describe user directories and
files accessible from the root directory.

  A USER DIRECTORY BLOCK contains the name and protection status of a user
directory, as well as a hash table containing pointers to hash chains of
USER DIRECTORY BLOCKS and FILE HEADER BLOCKS which describe user directories
and files accessible from that user directory.  Since the USER DIRECTORY
itself is a member of a hash chain, it also contains pointers to its parent
directory block and to the next USER DIRECTORY BLOCK or FILE HEADER BLOCK in
the header chain.

  A FILE HEADER BLOCK contains information describing the file it represents,
as well as a table of pointers to DATA BLOCKS that make up the file.  If
there aren't enough pointers in this table to point to all the file's DATA
BLOCKS, an EXTENSION pointer points to a list of FILE LIST BLOCKS which
extend the table.  Since the FILE HEADER BLOCK is a member of a hash chain,
it contains pointers to its parent directory and to the next USER DIRECTORY
BLOCK or FILE HEADER BLOCK in the header chain.

  A FILE LIST BLOCK contains a table of pointers to DATA BLOCKS and extends
the table of the FILE HEADER BLOCK or FILE LIST BLOCK which points to this
FILE LIST BLOCK.  If there aren't enough pointers in this table to point to
the remainder of the file's DATA BLOCKS, an EXTENSION pointer in the FILE
LIST BLOCK points to the next FILE LIST BLOCK to extend its data block table.

  A DATA BLOCK's main content is data.  It is part of a linked list of DATA
BLOCKS and includes a pointer to the next DATA BLOCK in the list.  It also
includes a sequence number indicating that this DATA BLOCK is the n'th DATA
BLOCK in the list.  Each DATA BLOCK is pointed-to both by the preceding DATA
BLOCK in the list, and by a pointer in a data block table in either a FILE
HEADER BLOCK or a FILE LIST BLOCK.  Each DATA BLOCK also contains a pointer
to the FILE HEADER BLOCK which describes the file which the DATA BLOCK is a
member of.

  Confused?  Don't worry, practical stuff is coming up next...



VIII) UNDERSTANDING YOUR DISK EDITOR
      ==============================

  Before we begin playing with a disk editor, I recommend that you create a
backup of a densely populated disk, like your workbench, so that if a wrong
key is pressed while looking through the backup, you haven't done damage to
your one and only copy.

a) A Look at Sectorama
   ===================
     For those of you lucky enough to have a copy of sectorama handy, fire it
   up and I can explain what all those obscure thingies on the right side and
   of the top line of the screen mean and where, from the block you are
   looking at, the information was taken.

     The lower right hand portion of the display identifies the storage
   device currently being examined by this sectorama display.  It gives us
   the device name (as a volume name), the device unit number, and the
   filename of the device driver that communicates with the device.

     The display section immediately above this info contains hardware-
   dependant information.  The middle column shows us the the sector, track
   cylinder, surface, and block numbers of the block currently being
   displayed.  This information is all given in decimal values.  All these
   statistics are all determined by a set of info used by the device
   driver.  For a floppy, for example, it these tell us on which cylinder the
   read/write head is currently positioned over, which sector on which
   surface (top or bottom) is being read by the read/write head, and the
   hardware-specific track and block numbers for that sector.  The rightmost
   column are device statistics.  These tell us how many of each category
   there are on this device.

     Note that by pointing at any of the figures in the center column of this
   section, you can change the current values.  By changing sector, surface,
   or block number, you can examine any sector of the device immediately.

     The section immediately above the hardware information contains
   information about (and from) the block currently being displayed:

     Date       -refers to the creation date which is taken from word # 69.

     Time       -is calculated from words # 6A (to get hours and minutes) and
                 # 6B (to get seconds).

     Highest Seq # -is taken from word # 2 and refers to the number of
                         words used in the table starting at word # 6.

     Data Size  -refers to the size of the table at word # 6.

     Protect    -refers to the protection status of a user directory block or
                 a file header block and is taken from the value at word # 50

     File Bytes -refers to the size of a file in kilobytes.  This value is
                 1/1000'th the value of word # 51.

     The section at the upper right corner of the display is a list of
   keyboard commands with current values beside them.  All except the
   checksum are pointers to other blocks in the device.  The checksum is the
   current block's checksum value taken from word # 5.  This value must be
   recalculated every time you make an alteration to a block.  The pointers
   shown beside each command are as follows:

     R-Go Root     -points to the root directory of this disk.  This pointer
                    is a constant value which has been calculate for this
                    storage device.

     P-Go Parent   -points to a FILE HEADER BLOCK's or USER DIRECTORY BLOCK's
                    parent directory block.  This pointer is taken from
                    word # 7D.

     C-Go Hash Chain -points to the next FILE HEADER BLOCK or USER
                      DIRECTORY BLOCK in this blocks hash chain.  This
                      pointer is taken from word # 7C.

     X-Go Extension -points to the next FILE LIST BLOCK in an extension
                     chain.  This pointer is taken from word # 7E.

     H-Go Header    -for DATA BLOCKS, this points to the FILE HEADER BLOCK
                     to which this DATA BLOCK belongs.
                    -for other blocks, this points to the block currently
                     being examined.
                    -in both cases, this pointer is taken from word # 1.

     For all the above commands, if you type the letter to initiate the
   command, sectorama will jump to the block corresponding to the pointer
   displayed beside the command.

     At the top of the display are three more information displays.  On the
   left is the block number of the block currently being displayed.  Next to
   that is the Type of the block being displayed.  The block type is
   determined by word # 0, which contains the block type, and word # 7F,
   which contains the secondary type.

     Next to the block type is the Name of the block.  This name may be a
   volume name or a directory name or a file name, depending on if this block
   is a ROOT BLOCK, a USER DIRECTORY BLOCK, or a FILE HEADER BLOCK,
   respectively.


b) Sectorama commands
   ==================
     All the sectorama commands are adequately described in the documentation
   file that accompanies it.


c) A Practical Session
   ===================
   i) Touring a floppy, a summary
      ---------------------------
         I suggest that as you progress through this little step-by-step
      blathering that each time you come across a new type of block, you
      compare the data being displayed by sectorama to the block
      descriptions shown above so that you become more familiar about where
      things are located in each type of block.

         The steps for performing the operations summarized below with
      Sectorama are described in detail, with a running commentary, in
      section ii) Touring a floppy with Sectorama.  For following these
      steps with any other disk editor, I suggest that you quickly read
      through the Sectorama tour to familiarize yourself with what is
      being attempted, then attempt the summarized steps below to familiarize
      yourself with your disk editor and AmigaDOS.

         Steps 1 thru 8 will guide you from a disk's ROOT BLOCK, into a file
      and through all the data blocks in that file.  A quick summary of
      these steps is as follows:

         Steps 9 thru 14 show you how to alter a block and write it to disk.

     _A step-by-step of the tour, in summary is as follows:

    / 1. Run the disk editor.
    |
    | 1a.  (Load the root block.  This is done automatically by Sectorama.)
    |
    | 2. Locate the 'c' directory by using the hash function.
Part< 3. Load the USER DIRECTORY BLOCK for the c directory.
 1a | 4. Locate the 'dir' command file by using the hash function.
    | 5. Load the FILE HEADER BLOCK for the 'dir' file.
    | 6. Load the first DATA BLOCK of the 'dir' file.
    | 7. Load and examine each consecutive DATA BLOCK of the 'dir' file until
    |      the last DATA BLOCK in the file has been loaded and examined.
    \_8. Load the FILE HEADER BLOCK pointed-to by the final DATA BLOCK.
     _
    / 9.  Locate and select the first word in the comment filed of the FILE
    |       HEADER BLOCK for the 'dir' file.
    | 10. Edit the ASCII values of the comment field.
Part< 11. Edit the hexadecimal value of the first byte of the first word of
 1b |       the comment field to insert the string length of the comment
    |       created in step 10.
    | 12. Re-calculate the checksum for this block.
    | 13. Write the altered block to disk.
    \_14. Quit the disk editor.



  ii) Touring a floppy with Sectorama...
      ----------------------------------


      1.   O.K., get your disk editor up and running (if it isn't already)
         and begin examining a back-up copy of your workbench disk.  For
         sectorama, the CLI command line for this if the disk was in df0:
         would look like:

         1> run sec df0:

         What you will see on your display (in neato-keen hi-res) is data
      of the ROOT BLOCK of df0:.  On top of the display is 'Type=ROOT DIR'
      which indicates that the block currently being displayed is a
      ROOT BLOCK.

      2.  Now that we are at the ROOT BLOCK, lets find the c directory.  The
      first step for this is to find out what value we get when we use the
      hash function on the string 'c'.  To do this you must envoke the hash
      function by picking 'COMPUTE HASH VALUE' under the SEARCH menu, then
      typing the file or directory name, in this case the letter c followed
      by a <RETURN>.  This highlights the block address of the hash chain
      which contains the c directory.

      3.  Now that you've found the possible whereabouts of the c directory
      jump to it by hitting the j key.  If (more likely than not) on top of
      the display is 'Name=c' then the display is currently displaying the
      contents of the c directory and the top of the display has
      'Type=DIRECTORY' indicating that what is being displayed is a USER
      DIRECTORY BLOCK, which is essentially the c directory of df0:.

      4.  Now that we're at the c directory, let's look at a file containing
      loadable/executable code for a well-known function... say, the file
      called 'dir'.  Envoke the hash function as before using the string
      dir.  The block address of the hash chain that contains the dir file
      will be highlighted.

      5.  Press the j key to jump to the beginning of the hash chain which
      will have (again, more likely than not) 'Type=FILE   Name=dir'
      displayed above the table of block data.  The Type=FILE indicates that
      this is the header block for the file indicated by Name=dir.  This is a
      fairly short file, so that all the block addresses for the DATA BLOCKS
      for this file are included in this block and that no extension blocks
      are required for this file, which is why the block address beside
      'X-Go Extension=' is 00000000.

        Also notice that the block address beside 'D-Go Next Data' is the
      same as the last entry in the data table of this block (at word # 4D
      according to my version of dir).  This is because data blocks are
      arranged in this table starting at the end of the table and working
      towards the beginning.

      6.  Let's take a look at the first DATA BLOCK, then, by hitting the
      d key to 'Go Next Data'.  What will be displayed is the first DATA
      BLOCK of the dir file.  On top of the display will be 'Type=DATA BLOCK'
      confirming that fact.  Note that word # 04, which has the same value as
      is displayed beside D-Go Next Data =, points to the next DATA BLOCK for
      this file.

      7.  Let's traverse the entire list of DATA BLOCKS to see what the last
      one in the list looks like.  You can do this by hitting the D key
      about 16 times or so.  While you do this, note that the value beside
      H-Go Header =  stays constant for each data block while all the other
      values remain constant.  The value beside H-Go Header =  points to
      the FILE HEADER BLOCK which owns the DATA BLOCK.  If this ever changes
      as you are traversing a list of DATA BLOCKS, you KNOW there is a
      problem with the file.  Also note that as you jump from block to block,
      the HISTORY list at the bottom of the display keeps track of your last
      eight jumps.  This is a valuable feature when you overshoot a problem
      area and need to know where you've been in previous jumps.  Also note
      that for each successive DATA BLOCK that you display, the sequence
      number displayed in the middle of the right part of the screen is
      incremented by one.  This helps you figure out exactly where you are in
      the file you are looking through.  If ever this sequence number jumps
      up or down by more that one, you know the DATA BLOCK is out of its
      proper sequence.

      8.  Once you've reach the end of the DATA BLOCK list, you will find that
      hitting the D key will now only cause the display to flash, indicating
      that this is indeed the end of the DATA BLOCK list for this file.  Lets
      jump back to the FILE HEADER BLOCK for the 'dir' file by hitting the
      h key (for H-Go Header).


      9.  Now that we've jumped around the disk doing some block reading,
      let's get more adventurous.  Let's modify a block on the disk.  By
      comparing the FILE HEADER BLOCK description above, we note that the
      comment field in this block begins at word # 52 and ends at word # 68.
      Move your pointer to word # 52 and click your left mouse button to
      highlight it.

      10. Next, press the A key to enter ASCII edit mode (the command list on
      the right of the display describes it as Edir ASCII).  Now type a space
      and then some sort of short comment, being careful not to type past
      word #68.  For example, I typed the comment ' dir, oh dir' beginning
      in word #52.  Note that the delete key and backspace key do not work
      normally in this mode, and actually produce their own special ascii
      values.  To re-type something, you must either move your pointer to the
      desired location and click, or use your cursor keys to move the
      highlighter to the desired character, then type your correction.
      To exit this edit mode, simply hit <RETURN>.

      11. To make our comment a proper BCPL string, we must put a character
      count at word # 52.  Count how many characters there are in your string
      and convert this number to hexadecimal.  Next, enter the hexadecimal
      edit mode by hitting the e key (for Edit), type your two-digit
      hexadecimal value and hit return.  For example, in my 'dir, oh dir'
      comment there are eleven characters.  Eleven converts to 0B in
      hexadecimal, so I edit word #52, type 0B, and hit return.

      12. Since we've altered the contents of this block, the checksum for
      this block is no longer valid.  We must hit the k key to calculate a
      new checksum.  When you have done this, you will note that the value
      beside K-Checksum = and at word # 05 have changed to the newly
      calculated checksum.

      13.  Note that any changes you have made so far haven't been written to
      disk at all.  Nothing is ever written to disk until you actually write
      it by hitting the u key to 'Update block'.  To incorporate your new
      file comment for the file called 'dir', hit the u key.

      14.  Then quit Sectorama, and list df0:c/dir to see the
      change that you've just made.  Note that you may have to list the whole
      c directory to see the change since AmigaDOS keeps track of which
      sectors of which device it currently has in buffers, and will avoid
      fetching your modified sector if it is currently in df0:'s buffer.


        What we've just done is to examine a disk, seek-out a specific file,
      look through the file's data, then modify the FILE HEADER BLOCK of
      that file.  What we haven't seen yet are two important data
      structures which we will look for now.  Specifically, these structures
      are the hash chain, and the file list.

      1. to 3.  Same as steps 1. to 3. above. (Locate & load the c directory)

      4. Now calculate the hash value for Echo using the Calculate Hash Value
      function.  Write the highlighted number down.

      5. Calculate the hash value for Quit using the same hash function used
      in step 4.

      6. Calculate the hash value for Why using the hash function.  You will
      find that the value you have written down for the value calculated for
      Why, Quit, and Echo are all identical, implying that if you jump to
      this number, you will have access to all three files.
         What this really means is that the FILE HEADER BLOCKS of these three
      files are members of the same hash chain.

      7. Jump to the first file in the hash chain by hitting the j key.  I
      cannot say exactly which FILE HEADER BLOCK you will be shown, since
      that depends on in what order the files in the chain were created on
      this disk.  Note that the value beside P-Go Parent =  is that of the
      USER DIRECTORY BLOCK of the directory containing this file, namely the
      c directory.

      8.  Note that the block address beside C-Go Hash Chain =  is non-zero.
      At least, if the files Echo, Quit, and Why are in the c directory on
      this disk, the value will be non-zero.  Otherwise, this demonstration
      will not be successful.  To display the header of the next file or
      directory in this hash chain, hit the c key (indicated by C-Go Hash
      Chain).

      9.  Note that the value beside P-Go Parent hasn't changed.  This is
      because all members of a hash chain always belong to the same
      directory.  To traverse the hash chain and find the last FILE HEADER
      BLOCK or USER DIRECTORY BLOCK in the chain, keep hitting the c key
      until the value beside C-Go Hash Chain becomes zero.  When this
      happens, further presses of the c key will merely cause the display
      to flash, indicating you are at the end of the hash chain.

      10. Jump back to the ROOT BLOCK by hitting the r key.


        To find what an extension file looks like, we must look for a large
      file... one where the amount of data is large enough that more pointers
      are available in a FILE HEADER BLOCK's DATA BLOCK pointer table.  A
      DATA BLOCK pointer table usually has 72 available entries.  Since each
      BLOCK is 512 bytes long, we need a file that is over 72 x 512 = 36864
      bytes long.  The Preferences file is about twice that length, so let's
      take a look at it.

      11. Calculate the hash value for Preferences using the hash function.

      12. Jump to the FILE HEADER BLOCK for the Preferences file by hitting
      the j key.  You will note that all the entries in the DATA BLOCK
      pointer table in this FILE HEADER BLOCK are used-up.  You will find
      the rest of the pointers required to point to the rest of the DATA
      BLOCKS for this file in the file list.  The block number of the first
      FILE LIST BLOCK in the file list is shown beside X-Go Extension.

      13. Hit the x key to jump to the first FILE LIST BLOCK.  Note that the
      block number displayed beside P-Go Parent is the same as the block
      number of the FILE HEADER BLOCK to which this FILE LIST BLOCK belongs.
      Also note that the value beside X-Go Extension is now zero.  If the
      required even more DATA BLOCKS, that is, if the file was longer than
      about 73kbytes, the value beside X-Go Extension would point to the next
      FILE LIST BLOCK in the file list.

        So, that pretty well wraps-up the tour.  We've seen all the data
      structures used by AmigaDOS and have had a chance to modify a block.
      There are a number of implications of AmigaDOS structure that this
      document hasn't covered, but these things will become apparent as you
      are given the opportunity to apply the disk editor.

        I hope the information forwarded by this document will help you solve
      or at least understand problems that may occur from time to time when
      storing things on AmigaDOS compatible devices.

A Trouble-shooting Example
--------------------------
        This information was recently invaluable to me as I discovered a
      problem with my hard drive recently that could have blossomed into a
      fairly major disaster.  A file was written on top of another file.

        I kept getting a read/write error when I tried to copy the
      over-written file to another device.  So, I examined the hard drive
      with Sectorama.  I used the hash function to locate which hash chain
      the file was stored under, traversed the hash chain until I found the
      file header block of the file in question.  I then traversed the list
      of data blocks for the file by hitting the d key repeatedly.  The
      list seemed to be intact since I was able to follow the list to its
      last block.

        I then hit the h key to display the file header block again.  It
      was the file header block of an entirely different file!  So, I jump
      back to the root, jumped to the file I was originally investigating,
      and again traversed the data block list while watching the value
      beside H-Go Header for any changes.  About half-way through the file
      the value changed.  I noted the block number of that data block,
      hit the h key to jump to the wrong file header block again, and noted
      that the block number of the erroneous data block was listed.  I went
      back to the root block and back to the original file header block and
      found that the same erroneous data block was listed here, too.

        I checked all the files on the hard disk, and found that only one
      file was unreadable.  Thus, that file had been overwritten.  This
      implied that somehow the bitmap of the disk was erroneous since the
      data block used by the file was claimed by another file.  I had to
      backup-up new files, format the hard drive to prevent further calamity,
      and copy back all the files.  That cured the whole problem.

        I had a directory problem a while ago that I now know how to fix
      recover from with a disk editor.  The directory of a device wrapped
      around so that when I executed a list command, I got an endless
      repetition of the same files, while other files on the disk would
      never be listed.  When I listed the ignored files by naming them
      directly, they would show up.  If I executed a dir command, the
      storage device was searched and searched and searched until the
      computer crashed.  I believe that is due to dir's method of collecting
      all files in a directory for sorting until the end of the directory
      is reached, which, in this case, it never did.

        Solving this is a matter of copying all files possible to another
      device.  This means individually copying all the files since wildcards
      cause a directory search which, in this case, would never end.  The
      files you cannot see can be searched-out with Sectorama using wildcards
      since Sectorama provides full-disk searches without consulting a
      directory.  After finding and copying all your files to another device,
      I'd recommend formatting the device to remove anything that might cause
      a relapse of the problem.


      If you have any corrections, comments, or suggestions about the above
document, please send them to me or tell me about them.  You can reach me at:

     //
   \X/ Tesseract BBS
       (306)757-5699
       (24 hours, 8N1, 300 or 1200 baud)

address:  Dwayne Miller
          770 Robinson Street
          Regina, Saskatchewan, Canada  (Yup, way up there!)
          S4T 2M1

  voice: (306)525-1652

P.S. Sectorama was written by David Joiner of MicroIllusions and is commonly
     available, often named 'sec.arc' or 'sector.arc' or 'sectoram.arc' etc.

//E*O*F disk.tutorial//

echo Possible errors detected by \'wc\' [hopefully none]:
temp=/tmp/shar$$
trap "rm -f $temp; exit" 0 1 2 3 15
cat > $temp <<\!!!
 973  7291  46762  disk.tutorial
!!!
wc  disk.tutorial | sed 's=[^ ]*/==' | diff -bw $temp -
exit 0

-- 
UUCP:  kim@amdahl.amdahl.com
  or:  {sun,decwrl,hplabs,pyramid,ihnp4,uunet,oliveb,cbosgd,ames}!amdahl!kim
DDD:   408-746-8462
USPS:  Amdahl Corp.  M/S 249,  1250 E. Arques Av,  Sunnyvale, CA 94086
CIS:   76535,25