FAT: Difference between revisions

144 bytes added ,  9 months ago
→‎FAT 12: more robust fat entry decode section for fat12
[unchecked revision][unchecked revision]
m (→‎BPB (BIOS Parameter Block): specify root directory entries)
(→‎FAT 12: more robust fat entry decode section for fat12)
Line 423:
FAT 12 uses 12 bits to address the clusters on the disk. Each 12 bit entry in the FAT points to the next cluster of a file on the disk. Given a valid cluster number, here is how you extract the value of the next cluster in the cluster chain:
<source lang="C">
unsigned char FAT_table[sector_size * 2]; // needs two in case we straddle a sector
unsigned int fat_offset = active_cluster + (active_cluster / 2);// multiply by 1.5
unsigned int fat_sector = first_fat_sector + (fat_offset / section_sizesector_size);
unsigned int ent_offset = fat_offset % section_sizesector_size;
 
//at this point you need to read two sectors from sectordisk starting at "fat_sector" on the disk into "FAT_table".
 
unsigned short table_value = *(unsigned short*)&FAT_table[ent_offset];
 
iftable_value = (active_cluster & 0x00011) ? table_value >> 4 : table_value & 0xfff;
table_value = table_value >> 4;
else
table_value = table_value & 0x0FFF;
 
//the variable "table_value" now has the information you need about the next cluster in the chain.
Line 441 ⟶ 438:
If "table_value" is greater than or equal to (>=) 0xFF8 then there are no more clusters in the chain. This means that the whole file has been read. If "table_value" equals (==) 0xFF7 then this cluster has been marked as "bad". "Bad" clusters are prone to errors and should be avoided. If "table_value" is not one of the above cases then it is the cluster number of the next cluster in the file.
 
The entries under index 0 and 1 are reserved. The zeroth entry is reserved because indexIndex 0 is used as value of other entries signifying that the given cluster is free., Zerothwith the corresponding first entry hasin tothe holdtable holding the value of the BPB_Media field from in theits low 8 bits, andwith the rest of the bits have to be set to zeroone. For example, if BPB_Media is 0xF8, then the zeroth entry should hold the value 0xFF8. The firstsecond entry is(index reserved1) foris theunused future andbut must to hold the value 0xFFF.
 
FAT12 uses an entry size that is not evenly divisible by 8 bits. This has some consequences.
Since FAT12 uses an entry size that is not evenly divisible by 8 bits, figuring out how to interpret the FAT can be slightly confusing. Consider two successive entries with values 0x123 and 0x456. The first byte of the first entry is the bottom two nibbles (0x23) and the highest nibble goes into the bottom nibble of the second byte (0x?1). Since the next entry is now starting mid-byte, only the lowest nibble can fit in the byte (0x6?) and the two highest nibbles go into the next byte (0x45). Therefore the 2 entries back-to-back look like this: 0x23 0x61 0x45.
 
First is storage in the table. Consider successive entries with values 0x123 and 0x456. In the bytes of the table, they'll be stored 0x23 0x61 0x45. Note that if you do little-endian 16-bit loads, you get 0x6123 at offset 0 and 0x4561 at offset 1, letting you recover the original two entry values with the shifts, masks, and offsets seen in the above code block.
This placement might be confusing, but if we consider a little-endian machine it will start make more sense. If you load the WORD value at offset zero, the resulting value will be 0x6123. Now the nibbles are in correct order, so to get the value of the first of the two entries you just have to AND the value with 0xfff. For the second entry, you have to first load WORD at offset 1, resulting in the value of 0x4561 and shifting it down by 4 bits (effectively removing the bottom nibble).
 
The second is that, as seen above with the offsets used being 0 and 1, those word bytes might not be 16-bit aligned. That usually just means the x86 takes a slower path to load the word if you do e.g. <tt>*(unsigned short *)bytes</tt>, but if you're use something like UBSan to avoid undefined behavior, those UB-catching routines can be triggered (usually resulting in a panic) if you don't load the two bytes separately and stick them together yourself.
 
The third consequence is that the word bytes might not be *sector* aligned. Which means if your code loads a single sector of the table, it needs a special case where it loads two if the entry straddles the sector-size boundary. Or you can just load two sectors every time as seen above.
 
==== FAT 16 ====
Anonymous user