# The structure of the `fatsoa.fs` partition The FAT file system is made up of three regions: the reserved region, the FAT region and the cluster region. In this document we will make a brief description of each one, with examples that will help you to better understand this file system and also help you to complete the laboratory practice. ## The reserved region Right before the first FAT, there are some reserved sectors. It contains some metadata related to the file system itself, it is the first sector and it is also known as the `volume_id`. This region is pointed by the corresponding partition entry, of the partition table in the MBR (Master Boot Record) This region is described by the following declaration: ```c= struct BS_Structure bs_data; ``` ``` Data member Offset Value ---------------------------------------------- uint16_t bytesPerSector 0x0B uint8_t sectorPerCluster 0x0D uint16_t reservedSectorCount 0x0E uint8_t numberofFATs 0x10 uint8_t FATsize_F32 0x24 uint32_t rootCluster 0x2C uint8_t fileSystemType[8] 0x52 uint32_t bootEndSignature 0x1FE ``` :::spoiler What are the contents of the `struct BS_Structure` ``` Data member Offset Value ---------------------------------------------- uint16_t bytesPerSector 0x0B 0x200 (512) uint8_t sectorPerCluster 0x0D 0x08 uint16_t reservedSectorCount 0x0E 0x0020 (32) uint8_t numberofFATs 0x10 0x02 uint8_t FATsize_F32 0x24 0x000000C8 (200) uint32_t rootCluster 0x2C 0x00000002 uint8_t fileSystemType[8] 0x52 0x4641543332202020 'FAT32___' uint32_t bootEndSignature 0x1FE 0xAA55 ``` ::: :::spoiler Where does the first FAT begins? ``` fat_begin_offset = bs_data.reservedSectorCount * bs_data.bytesPerSector fat_begin_offset = 32 sectors * 512 B/sector = 0x4000 ``` ::: :::spoiler Where does the second FAT begins? ``` (bs_data.reservedSectorCount + bs_data.FATsize_F32)* * bs_data.bytesPerSector = (32 + 200) * 512 = 0x1D000 ``` ::: :::spoiler In which cluster is the root directory ``` uint32_t rootCluster 0x2C 0x00000002 ``` ::: :::spoiler Where does the root cluster begin (offset)? ``` lba = bs_data.reservedSectorCount + + bs_datanumberofFATs * bs_data.FATsize_F32 = = 32 + 200 * 2 = 432 offset = lba * bs_data.bytesPerSector = 432 * 512 = 0x36000 ``` ::: :::spoiler Give an expression to find the offset of an arbitrary cluster The function `Cluster2Offset` provides this functionality, that it, getting the LBA and the offset from a cluster number. ``` lba = (cluster-2) * bs_data.sectorPerCluster + + bs_data.reservedSectorCount + + bs_data.numberofFATs * bs_data.FATsize_F32 offset = lba * bs_data.bytesPerSector ``` ::: ## The cluster region The clusters are meant to hold three different types of information: - Directories - Long file names (longer than 8 bytes) - The contents of the files themselves ### Directories A directory has 16 entries, each of 32 bytes, so they fit in a complete 512 bytes sector. ```c= struct DIR_Structure directory_info[16]; ``` In each entry there is, among other things (like the name of the file), the first cluster of the corresponding file. For example, in the first directory entry we can find the next information: `directory_info[0]`, offset = 0x36000 ```shell $ cat fatsoa.fs| hexdump -C -n 100 -s 0x36000 00036000 53 4f 41 2d 46 53 20 20 20 20 20 08 00 00 96 80 |SOA-FS .....| ``` ``` uint8_t DIR_name[11] # 0 | 53 4f 41 2d 46 53 20 20 'SOA-FS' uint8_t DIR_attrib # 0B | 08 (ATTR_VOLUME_ID) uint16_t firstClusterHI # 14 | 0x0000 uint16_t firstClusterLO # 1A | 0x0000 uint32_t fileSize # 1C | 0x0000 0x0000 ``` It is important to take into account the first byte of the name, `directory_info[i].DIR_name[0]`, since it indicates special statuses, such as `DELETED` or `EMPTY`. ```c #define EMPTY 0x00 #define DELETED 0xe5 ``` When `EMPTY` o `DELETED` the corresponding entry can be reused. The attribute `directory_info[i].DIR_attrib` can have the following values: ```c #define ATTR_READ_ONLY 0x01 #define ATTR_HIDDEN 0x02 #define ATTR_SYSTEM 0x04 #define ATTR_VOLUME_ID 0x08 #define ATTR_DIRECTORY 0x10 #define ATTR_ARCHIVE 0x20 #define ATTR_LONG_NAME 0x0F ``` This a full hexadecimal dump of the root file system: ``` 00036000 53 4f 41 2d 46 53 20 20 20 20 20 08 00 00 96 80 |SOA-FS .....| 00036010 6a 51 6a 51 00 00 96 80 6a 51 00 00 00 00 00 00 |jQjQ....jQ......| 00036020 41 6c 00 65 00 65 00 6d 00 65 00 0f 00 06 2e 00 |Al.e.e.m.e......| 00036030 74 00 78 00 74 00 00 00 ff ff 00 00 ff ff ff ff |t.x.t...........| 00036040 4c 45 45 4d 45 20 20 20 54 58 54 20 00 5a 89 75 |LEEME TXT .Z.u| 00036050 6a 51 6a 51 00 00 89 75 6a 51 04 00 32 00 00 00 |jQjQ...ujQ..2...| 00036060 55 44 34 20 20 20 20 20 20 20 20 10 00 c4 92 76 |UD4 ....v| 00036070 6a 51 6a 51 00 00 92 76 6a 51 03 00 00 00 00 00 |jQjQ...vjQ......| 00036080 e5 6f 00 64 00 73 00 2e 00 70 00 0f 00 8c 64 00 |.o.d.s...p....d.| 00036090 66 00 00 00 ff ff ff ff ff ff 00 00 ff ff ff ff |f...............| 000360a0 e5 44 53 20 20 20 20 20 50 44 46 20 00 1c 99 82 |.DS PDF ....| 000360b0 6a 51 6a 51 00 00 99 82 6a 51 07 00 36 6c 09 00 |jQjQ....jQ..6l..| ``` For example, the attribute for the `LEEME.TXT` file is `0x20`, so this a file, and its first cluster is `cluster_lo=0x0004` and `cluster_hi=0x0000`, total `0x00000004'. ## The FAT region This is the region in which the FAT is allocated. The FAT has the following characteristics: - Each FAT entry is 32 bits (That is from where FAT-32 got his name) - Each entry number represents the same cluster number, and the value stored in that position is the number of the next cluster of the file. - The first two entries are reserved, and the third, that corresponds to cluster 2, is the entry for the root directory, as it was determined in the reserved area (`bs_data.rootCluster = 2`). - If there are no more clusters in the file, a value greater than 0x0FFFFFF8 is set. From the reserved (`bs_data`) area we can obtain the beginning of the FAT: `fat_begin_offset = 0x4000`. With this information we can make a dump: ``` 00004000 f8 ff ff 0f ff ff ff 0f f8 ff ff 0f ff ff ff 0f |................| 00004010 ff ff ff 0f 06 00 00 00 ff ff ff 0f f7 ff ff 0f |................| 00004020 f7 ff ff 0f f7 ff ff 0f f7 ff ff 0f f7 ff ff 0f |................| ``` For the cluster 2, we can read in the FAT the value `0xF8FFFF0F` which means that the root directory occupies only one cluster, and therefore there are no more clusters for this entry. But, in the case of the file that starts with the cluster 5 (`/UD4/FAT32.H`), the FAT shows that, starting with cluster 5, the next is cluster 6. Now, if we go to the sixth entry in the FAT we find that the value is `0xFFFFFF0F`. This indicates that something is wrong with this cluster. Finally, if we want to find the contents of a file, say of `/UD4/FAT32.H`, since we know from the FAT that its clusters are 5 and 6, we can calculate the offset of the first one with `LBA2Offset(5) = 0x39000` and then read the data: ``` 00039000 2f 2f 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a |//**************| 00039010 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a |****************| * 00039030 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 0d 0a 2f 2f 20 41 |**********..// A| 00039040 75 74 6f 72 3a 20 53 4f 41 0d 0a 2f 2f 2a 2a 2a |utor: SOA..//***| 00039050 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a |****************| * 00039080 2a 2a 2a 2a 2a 0d 0a 0d 0a 0d 0a 23 69 66 6e 64 |*****......#ifnd| 00039090 65 66 20 5f 46 41 54 33 32 5f 48 5f 0d 0a 23 64 |ef _FAT32_H_..#d| 000390a0 65 66 69 6e 65 20 5f 46 41 54 33 32 5f 48 5f 0d |efine _FAT32_H_.| 000390b0 0a 0d 0a 23 69 6e 63 6c 75 64 65 20 3c 73 74 64 |...#include <std| 000390c0 69 6e 74 2e 68 3e 0d 0a |int.h>..| 000390c8 ```