This would be useful if we want to do recovery on corrupted memory cards.
Master Boot Record and Partition Table
MBR is always the first sector of the disk, located at cylinder 0 head 0 sector 1. The structure (total 512 bytes) is:
Offset | Size | Description |
---|---|---|
0x0 | 446 | Executable code to boot |
0x1BE | 16 | 1st Partition entry |
0x1CE | 16 | 2nd Partition entry |
0x1DE | 16 | 2nd Partition entry |
0x1EE | 16 | 2nd Partition entry |
0x1FE | 2 | Signature: 0x55 0xAA |
The partition table is, therefore, part of the MBR. The 16-byte record in the partition table has the following structure:
Offset | Size | Description |
---|---|---|
0x0 | 1 | State of partition (0x00=Inactive, 0x80=Active) |
0x1 | 3 | Beginning of partition: head, cylinder, sector numbers |
0x4 | 1 | Partition type, e.g. FAT32=0x0B |
0x5 | 3 | End of partition: head, cylinder, sector numbers |
0x8 | 4 | Number of sectors between the MBR and first sector in partition |
0xC | 4 | Number of sectors in the partition |
The beginning and the end of partition is encoded as follows:
Bits
23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
| Head number | Cylinder num, bits 7-0| |Sector number |
^
Cylinder num, bits 9-8--+
In this interpretation, the sector number if limited to 6 bits (max 63) and the cylinder is 10 bits (max 1024), but the cylinder number is having the two high bits in the third byte the the eight low bits in the second byte. In other words, the maximum size of disk that supported by this structure is 255 head, 1023 cylinder, 63 sector, total to 8414461440 bytes or 8.4 GB. Larger disks needs LBA mode interpretation. In that case, the recorded in offset 0x8 tells where the LBA begins.
When there are “extended partitions”, the first sector of each partition is MBR-like which the partition table behaves as a linked list: The MBR marks the 2nd partition as extended, with the size included all “logical drives”. The first sector of the 2nd partition marks the region for the first logical partition as its 1st partition and the 2nd partition is the remaining spaces. Until the last logical partition, where only the 1st partition entry is filled and there would be no 2nd partition entry.
FAT32 Boot record
The first sector of every FAT32 partition is a FAT32 boot record. Its structure is as follows:
Offset | Size | Description |
---|---|---|
0x0 | 3 | Jump instruction to boot code, usually 0xEB 0x58 0x90 |
0x3 | 8 | OEM name |
0xB | 2 | Bytes per sector |
0xD | 1 | Sector per cluster, in powers of 2 |
0xE | 2 | Number of reserved sectors |
0x10 | 1 | Number of copies of FAT |
0x11 | 2 | was max root directory entries, n/a for FAT32 |
0x13 | 2 | was number of sectors in partition, n/a for FAT32 |
0x15 | 1 | Media descriptor, hard disk = 0xF8 |
0x16 | 2 | was sectors per FAT, must be zero for FAT32 |
0x18 | 2 | Sectors per track |
0x1A | 2 | Number of heads |
0x1C | 4 | Number of hidden sectors in partition |
0x20 | 4 | Number of sectors in partition |
0x24 | 4 | Number of sectors per FAT |
0x28 | 2 | Flags |
0x2A | 2 | Version of FAT32 drive, high/low byte = major/minor |
0x2C | 4 | Cluster number of the start of the root directory |
0x30 | 2 | Sector number of the filesystem information sector, offset from the start of the partition |
0x32 | 2 | Sector number of the backup boot sector, offset from the start of the partition |
0x34 | 12 | Reserved |
0x40 | 1 | Logical drive number of partition |
0x41 | 1 | Unused |
0x42 | 1 | Signature 0x29 |
0x43 | 4 | Serial number of partition |
0x47 | 11 | Volume name of partition |
0x52 | 8 | Name of FAT, usually “FAT32” |
0x5A | 420 | Boot code |
0x1FE | 2 | Signature 0x55 0xAA |
The OEM name tells what system did the partition formatted. Examples include “MSWIN4.1” or “mkdosfs”.
In FAT32, the number of reserved sectors (offset 0xE) is usually 32. While this is usually 1 in FAT16. The total number of sectors (offset 0x13) is zero indicates that the value should be reference by offset 0x20. This is usually the case in FAT32.
The flag (offset 0x28) is in the following structure:
- 1st Byte: must be 0x00
- 2nd Byte: MSB set = FAT mirroring is disabled
- 2nd Byte: lower 7 bits = The active FAT copy
Usually the filesystem information sector (mentioned by offset 0x30) is at the second sector of the partition. It is served as the extended boot record in FAT32. Its structure is:
Offset | Size | Description |
---|---|---|
0x0 | 4 | Signature 0x52 0x52 0x61 0x41, i.e. “RRaA” |
0x4 | 480 | All null bytes, reserved |
0x1E4 | 4 | Signature 0x72 0x72 0x41 0x61, i.e. “rrAa” |
0x1E8 | 4 | Number of free clusters, 0xFFFFFFFF if unknown |
0x1EC | 4 | Most recently allocated cluster number |
0x1F0 | 14 | Reserved, all null |
0x1FE | 2 | Signature 0x55 0xAA |
Therefore, the structure of a FAT32 partition is as follows:
If the number of reserved sectors (0xE) is \(R\), number of FATs (0x10) is \(N\) and the number of sectors per FAT (0x24 or 0x16) is \(S\), then, counting from the beginning of the partition, sector 0 is the boot record, sector \(R\) is the first FAT, sector \(R+NS\) is the beginning of data area, and this is the location of the root directory.
File Allocation Tables in FAT32
The data area must start on a cluster boundary. The FAT is a sequence of numbers, each in 32-bit for FAT32 and 16-bit for FAT16. The \(k\)-th number (\(k\ge 0\)) is corresponding to the \(k\)-th cluster in the data area, which tells which is the next cluster of the data block. The first data cluster is cluster number 2. Thus in FAT, the value of:
- 0x0FFFFFF8 to 0x0FFFFFFF marks the end of a cluster chain
- 0x0FFFFFF7 marks a bad cluster
- 0x0FFFFFF0 to 0x0FFFFFF6, and also 0x00000001 are reserved value, shall not be used in FAT
- 0x00000000 marks an unused cluster
- Other value (highest 4 bit must be zero) indicates the position of next cluster of a file
And because of first data cluster is cluster 2, the first 2 FAT entries are always 0x0FFFFFFF and never allocated to user data.
Directory table
Files are organized in a directory. A directory is one or more cluster with a number of 32-byte entries. In FAT32 that supports long file name, a 8.3 filename entry has the following format:
Offset | Length | Description |
---|---|---|
0x0 | 8 | File name |
0x8 | 3 | Extension |
0xB | 1 | Attribute |
0xC | 1 | Null byte |
0xD | 1 | Creation time, 10 ms portion in 2 sec, value of 0 to 199 |
0xE | 2 | Creation time |
0x10 | 2 | Creation date |
0x12 | 2 | Last accessed date |
0x14 | 2 | High bits of cluster number |
0x16 | 2 | Time |
0x18 | 2 | Date |
0x1A | 2 | Lower bits of cluster number |
0x1C | 4 | File size |
The attribute is in the following format:
7 6 5 4 3 2 1 0
| | | | | | | |
| | | | | | | +- Volume label, not actually a file
| | | | | | +--- Directory, not actually a file
| | | | | +----- Hidden file
| | | | +------- System file
| | | +--------- Read-only file
| | +----------- Archive
+-+------------- zero bits
The 16-bit time field is encoded as follows:
- Bit 15-11: Hour (0 to 23)
- Bit 10-5: Minutes (0 to 59)
- Bit 4-0: Seconds divided by 2 (0 to 29)
And the 16-bit date field is encoded as follows:
- Bit 15-9: Year, 1980+n, (n from 0 to 127)
- Bit 8-5: Month (1 to 12)
- Bit 4-0: Day (1 to 31)
The long file name entry is stored right above the 8.3 entry. Each LFN entry is for 13 unicode characters and longer file names are stored “backward”, i.e. tail parts of the LFN is above the head parts and they are all above the 8.3 entry.
A LFN entry has the following format:
Offset | Size | Description |
---|---|---|
0x0 | 1 | Order of LFN entry, >= 1 |
0x1 | 10 | Unicode character 1-5 |
0xB | 1 | Attribute |
0xC | 1 | Null byte |
0xD | 1 | Checksum of the 8.3 filename |
0xE | 12 | Unicode character 6-11 |
0x1A | 2 | Null bytes |
0x1C | 4 | Unicode character 12-13 |
The checksum is computed using the 8.3 filename, total of 11 bytes. The C code is as follows:
unsigned char compute_checksum(unsigned char filename[11]) {
unsigned char cksum = filename[0];
int i;
for (i=1; i<=11; i++) {
cksum = ((cksum >> 1)|((cksum & 0x01)<<7)) + filename[i];
};
return cksum;
};
When the first byte of a 32-byte record in the directory is byte 0x00, it marks the end of the directory record. When it is byte 0xE5, however, means this record can be skipped (i.e. deleted).