170 lines
8.5 KiB
Plaintext
170 lines
8.5 KiB
Plaintext
By: Inbar Raz
|
|
--------------------------------------------------------------------
|
|
|
|
The FAT is a linked-list table that DOS uses to keep track of the physical
|
|
position of data on a disk and for locating free space for storing new files.
|
|
|
|
The word at offset 1aH in a directory entry is a cluster number of the first
|
|
cluster in an allocation chain. If you locate that cell in the FAT, it will
|
|
either indicate the end of the chain or the next cell, etc. Observe:
|
|
|
|
starting cluster number --|
|
|
Directory +-------------------+-+-------------------+---+---+-+-+-------+
|
|
Entry -- |M Y F I L E T X T|a| |tim|dat|08 | size |
|
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-|-+-+-+-+-+
|
|
+-------------------------+
|
|
00 01 02 03 04 05 06 07 |8 09 0a 0b 0c 0d 0e 0f
|
|
+--++--++--++--++--++--++--++--++-++--++--++--++--++--++--++--+
|
|
00 |ID||ff||03-04-05-ff||00||00||09-0a-0b-15||00||00||00||00|
|
|
+--++--++--++--++--++--++--++--++--++--++--++|-++--++--++--++--+
|
|
+-----------------------+
|
|
+--++--++--++--++--++-++--++--++--++--++--++--++--++--++--++--+
|
|
10 |00||00||00||00||00||16-17-19||f7||1a-1b-ff||00||00||00||00|
|
|
+--++--++--++--++--++--++--++|-++--++-++--++--++--++--++--++--+
|
|
+-------+
|
|
This diagram illustrates the main concepts of reading the FAT. In it:
|
|
þ The file MYFILE.TXT is 10 clusters long. The first byte is in cluster 08
|
|
and the last is in cluster 1bH. The chain is 8,9,0a,0b,15,16,17,19,1a,1b.
|
|
Each entry indicates the next entry in the chain, with a special code in
|
|
the last entry.
|
|
þ Cluster 18H is marked bad and is not part of any allocation chain.
|
|
þ Clusters 6,7, 0cH-14H, and 1cH-1fH are empty and available for allocation.
|
|
þ Another chain starts at cluster 2 and ends at cluster 5.
|
|
|
|
+-----------+
|
|
| FAT Facts | The FAT normally starts at logical sector 1 in the DOS partition
|
|
+-----------+ (eg, you can read it with INT 25H with DX=1). The only way to
|
|
be sure is to read the boot sector (DX=0), and examine offset 0eH. This
|
|
tells how many boot and reserved sectors come before the FAT. Use that
|
|
number (usually 1) in DX to read the FAT via INT 25H.
|
|
|
|
There may be more than one copy of the FAT. There are usually two complete
|
|
copies. If there are two or more, they will all be adjacent (the second FAT
|
|
directly follows the first).
|
|
|
|
You have the following services available to help you determine information
|
|
about the FAT:
|
|
|
|
þ Use INT 25H to read the Boot Sector and examine the data fields therein
|
|
þ Use DOS Fn 36H or 1cH to determine total disk sectors and clusters
|
|
þ Use DOS Fn 44H (if the device driver supports Generic IOCTL) DOS 3.2
|
|
þ Use DOS Fn 32H to get all kinds of useful information. UNDOCUMENTED
|
|
|
|
Note: The boot sector of non-booting disks (such as network block devices
|
|
and very old hard disks) may contain nothing but garbage.
|
|
|
|
+---------------+
|
|
| 12-bit/16-bit | The FAT can be laid out in 12-bit or 16-bit entries. 12-bit
|
|
+---------------+ entries are very efficient for media less than 384K--the
|
|
entire FAT can fit in a single 512-byte disk sector. For larger media, each
|
|
FAT entry must map to a larger and larger cluster size--to the point where a
|
|
20M hard disk would need to allocate in units of 16 sectors in order to use
|
|
the 12-bit format (in other words, a 1-byte file would take up a full 8K
|
|
cluster of a disk).
|
|
|
|
16-bit FAT entries were introduced with DOS 3.0 with the necessity of
|
|
efficient handling the AT's 20-Megabyte hard disk. However, floppy disks
|
|
and 10M hard disks continue to use the 12-bit layout. You can determine if
|
|
the FAT is laid out with 12-bit or 16-bit elements:
|
|
|
|
DOS 3.0 says: If a disk has more than 4086 (0ff6H) clusters, it uses 16 bits
|
|
(4096 is max value for a 12-bit number and >0ff6H is reserved)
|
|
DOS 3.2 says: If a disk has more than 20740 (5104H) SECTORS, it uses 16 bits
|
|
(in other words, any disk over 10 Megabytes uses a 16-bit FAT
|
|
and all others--including large RAM disks--use 12-bits).
|
|
|
|
Note: It's a common misconception that the 16-bit FAT allows DOS to work with
|
|
disks larger than 32 Megabytes. In fact, the limiting factor is that
|
|
INT 25H/26H (through which DOS performs its disk I/O) in unable to
|
|
access a SECTOR number higher than 65535. Normally, sectors are 512
|
|
bytes («-K), so that sets the 32M limit.
|
|
|
|
In DOS 4.0, INT 25H/26H supports a technique for accessing sector
|
|
numbers
|
|
higher than 65535, and thus supports trans-32M DOS partitions. This
|
|
has no effect on the layout of the FAT itself. Using 16-bit FAT
|
|
entries and 4-sector clusters, DOS now supports partitions up to 134M
|
|
(twice that for 8-sector clusters, etc.).
|
|
|
|
+-----------------+
|
|
| Reading the FAT | To read the value of any entry in a FAT (as when following
|
|
+-----------------+ a FAT chain), first read the entire FAT into memory and
|
|
obtain a starting cluster number from a directory. Then, for 12-bit entries:
|
|
==============
|
|
þ Multiply the cluster number by 3 =|
|
|
þ Divide the result by 2 =========+= (each entry is 1.5 (3/2) bytes long)
|
|
þ Read the WORD at the resulting address (as offset from the start of the FAT)
|
|
þ If the cluster was even, mask the value by 0fffH (keep the low 12 bits)
|
|
If the cluster number was odd, shift the value right by 4 bits (keep the
|
|
upper 12 bits)
|
|
þ The result is the entry for the next cluster in the chain (0fffH=the end).
|
|
|
|
Note: A 12-bit entry can cross over a sector boundary, so be careful with
|
|
1-sector FAT buffering schemes.
|
|
|
|
16-bit entries are simpler--each entry contains the 16-bit offset (from the
|
|
start of the FAT) of the next entry in the chain (0ffffH indicates the end).
|
|
|
|
+-------------+
|
|
| FAT Content | The first byte of the FAT is called the Media Descriptor or
|
|
+-------------+ FAT ID byte. The next 5 bytes (12-bit FATs) or 7 bytes
|
|
(16-bit FATs) are 0ffH. The rest of the FAT is composed of 12-bit or 16-bit
|
|
cells that each represent one disk cluster. These cells will contain one of
|
|
the following values:
|
|
|
|
þ (0)000H ................... an available cluster
|
|
þ (f)ff0H through (f)ff7H ... a reserved cluster
|
|
þ (f)ff7H ................... a bad cluster
|
|
þ (f)ff8H through (f)fffH ... the end of an allocation chain
|
|
þ (0)002H through (f)fefH ... the number of the next cluster in a chain
|
|
|
|
Note: the high nibble of the value is used only in 16-bit FATs; eg, a bad
|
|
cluster is marked with 0ff7H in 12-bit FATs, and fff7H with 16-bit FATs.
|
|
|
|
+------------------------------------------------+
|
|
| Converting a Cluster Number to a Sector Number | After you obtain a file's
|
|
+------------------------------------------------+ starting cluster number
|
|
from a directory entry you will want to locate to actual disk sector that
|
|
holds the file (or subdirectory) data.
|
|
|
|
A diskette (or a DOS partition of a hard disk) is laid out like so:
|
|
|
|
þ Boot and reserved sector(s)
|
|
þ FAT #1
|
|
þ FAT #2 (optional -- not used on RAM disks)
|
|
þ root directory
|
|
þ data area (all file data reside here, including files for directories)
|
|
|
|
Every section of this layout is variable and the sizes of each section must
|
|
be known in order to perform a correct cluster-to-sector conversion. The
|
|
following formulae represent the only documented method of determining a DOS
|
|
logical sector number from a cluster number:
|
|
|
|
RootDirSectors = sectorBytes / (rootDirEntries * 32)
|
|
FatSectors = fatCount * sectorsPerFat
|
|
DataStart = reservedSectors + fatSectors + rootDirSectors
|
|
|
|
INT 25h/26h Sector = DataStart + ((AnyClusterNumber-2) * sectorsPerCluster)
|
|
|
|
Where the variables:
|
|
|
|
sectorBytes sectorsPerFat fatCount
|
|
rootDirEntries reservedSectors sectorsPerCluster
|
|
|
|
are obtained from the Boot Sector or from a BPB (if you can get access). The
|
|
resulting sector number can be used in DX for INT 25H/26H DOS absolute disk
|
|
access.
|
|
|
|
If you are a daring sort of person, you can save trouble by using the
|
|
undocumented DOS Fn 32H (Get Disk Info) which provides a package of pre-
|
|
calculated data, including the sector number of the start of file data (it
|
|
gives you "DataStart", in the above equation).
|
|
|
|
Author's note: The best use I've found for all this information is in
|
|
directory scanning; ie, to bypass the DOS file-searching services and read
|
|
directory sectors directly. For a program that must obtain a list of all
|
|
files and directories, direct access of directory sectors will work roughly
|
|
twice as fast as DOS Fns 4eH and 4fH.
|
|
|
|
|