4.1. fat16 — FAT16 filesystem

File Allocation Table (FAT) is a computer file system architecture and a family of industry-standard file systems utilizing it. The FAT file system is a legacy file system which is simple and robust. It offers good performance even in light-weight implementations, but cannot deliver the same performance, reliability and scalability as some modern file systems. It is, however, supported for compatibility reasons by nearly all currently developed operating systems for personal computers and many mobile devices and embedded systems, and thus is a well-suited format for data exchange between computers and devices of almost any type and age from 1981 up to the present.

4.1.1. Example

Here is the pseudo-code for mounting a file system, performing file operations and unmounting the file system.

All function arguments are omitted in this example.

/* Mount the file system. This is normally done once when the
   application starts. */
fat16_init();
fat16_mount();

/* Perform file operations. */
fat16_file_open();
fat16_file_read();
fat16_file_close();

fat16_file_open();
fat16_file_write();
fat16_file_close();

/* Unmount the file system when it is no long needed. Normally when
   the application stops. */
fat16_unmount();

Source code: src/filesystems/fat16.h, src/filesystems/fat16.c

Test code: tst/filesystems/fat16/main.c

Test coverage: src/filesystems/fat16.c

Example code: examples/fat16/main.c


Defines

FAT16_SEEK_SET

The offset is relative to the start of the file.

FAT16_SEEK_CUR

The offset is relative to the current position indicator.

FAT16_SEEK_END

The offset is relative to the end of the file.

FAT16_EOF

End of file indicator.

O_READ

Open for reading.

O_RDONLY

Same as O_READ.

O_WRITE

Open for write.

O_WRONLY

Same as O_WRITE.

O_RDWR

Open for reading and writing.

O_APPEND

The file position indicator shall be set to the end of the file prior to each write.

O_SYNC

Synchronous writes.

O_CREAT

Create the file if non-existent.

O_EXCL

If O_CREAT and O_EXCL are set, file open shall fail if the file exists.

O_TRUNC

Truncate the file to zero length.

DIR_ATTR_READ_ONLY

File is read-only.

DIR_ATTR_HIDDEN

File should hidden in directory listings.

DIR_ATTR_SYSTEM

Entry is for a system file.

DIR_ATTR_VOLUME_ID

Directory entry contains the volume label.

DIR_ATTR_DIRECTORY

Entry is for a directory.

DIR_ATTR_ARCHIVE

Old DOS archive bit for backup support.

Typedefs

typedef ssize_t(* fat16_read_t)(void *arg_p, void *dst_p, uint32_t src_block)

Block read function callback.

typedef ssize_t(* fat16_write_t)(void *arg_p, uint32_t dst_block, const void *src_p)

Block write function callback.

typedef uint16_t fat_t

A FAT entry.

Functions

int fat16_init(struct fat16_t *self_p, fat16_read_t read, fat16_write_t write, void *arg_p, unsigned int partition)

Initialize a FAT16 volume.

Return
zero(0) or negative error code.
Parameters
  • self_p -

    FAT16 object to initialize.

  • read -

    Callback function used to read blocks of data.

  • write -

    Callback function used to write blocks of data.

  • arg_p -

    Argument passed as the first arguemtn to read() and write().

  • partition -

    Partition to be used. Legal values for a partition are 1-4 to use the corresponding partition on a device formatted with a MBR, Master Boot Record, or zero if the device is formatted as a super floppy with the FAT boot sector in block zero.

int fat16_mount(struct fat16_t *self_p)

Mount given FAT16 volume.

Return
zero(0) or negative error code.
Parameters
  • self_p -

    FAT16 object.

int fat16_unmount(struct fat16_t *self_p)

Unmount given FAT16 volume.

Return
zero(0) or negative error code.
Parameters
  • self_p -

    FAT16 object.

int fat16_format(struct fat16_t *self_p)

Create an empty FAT16 file system on the device.

Parameters
  • self_p -

    FAT16 object.

int fat16_print(struct fat16_t *self_p, void *chan_p)

Print volume information to given channel.

Return
zero(0) or negative error code.
Parameters
  • self_p -

    FAT16 object.

  • chan_p -

    Output channel.

int fat16_file_open(struct fat16_t *self_p, struct fat16_file_t *file_p, const char *path_p, int oflag)

Open a file by file path and mode flags.

Return
zero(0) or negative error code.
Parameters
  • self_p -

    FAT16 object.

  • file_p -

    File object to be initialized.

  • path_p -

    A valid 8.3 DOS name for a file path.

  • oflag -

    mode of file open (create, read, write, etc).

int fat16_file_close(struct fat16_file_t *file_p)

Close a file and force cached data and directory information to be written to the media.

Return
zero(0) or negative error code.
Parameters
  • file_p -

    File object.

ssize_t fat16_file_read(struct fat16_file_t *file_p, void *buf_p, size_t size)

Read data to given buffer with given size from the file.

Return
Number of bytes read or EOF(-1).
Parameters
  • file_p -

    File object.

  • buf_p -

    Buffer to read into.

  • size -

    number of bytes to read.

ssize_t fat16_file_write(struct fat16_file_t *file_p, const void *buf_p, size_t size)

Write data from buffer with given size to the file.

Return
Number of bytes written or EOF(-1).
Parameters
  • file_p -

    File object.

  • buf_p -

    Buffer to write.

  • size -

    number of bytes to write.

int fat16_file_seek(struct fat16_file_t *file_p, int pos, int whence)

Sets the file’s read/write position relative to mode.

Return
zero(0) or negative error code.
Parameters
  • file_p -

    File object.

  • pos -

    New position in bytes from given mode.

  • whence -

    Absolute, relative or from end.

ssize_t fat16_file_tell(struct fat16_file_t *file_p)

Return current position in the file.

Return
Current position or negative error code.
Parameters
  • file_p -

    File object.

int fat16_file_truncate(struct fat16_file_t *file_p, size_t size)

Truncate given file to a size of precisly size bytes.

If the file previously was larger than this size, the extra data is lost. If the file previously was shorter, it is extended, and the extended part reads as null bytes (‘\0’).

Return
zero(0) or negative error code.
Parameters
  • file_p -

    File object.

  • size -

    New size of the file in bytes.

ssize_t fat16_file_size(struct fat16_file_t *file_p)

Return number of bytes in the file.

Return
File size in bytes or negative error code.
Parameters
  • file_p -

    File object.

int fat16_file_sync(struct fat16_file_t *file_p)

Causes all modified data and directory fields to be written to the storage device.

Return
zero(0) or negative error code.
Parameters
  • file_p -

    File object.

int fat16_dir_open(struct fat16_t *self_p, struct fat16_dir_t *dir_p, const char *path_p, int oflag)

Open a directory by directory path and mode flags.

Return
zero(0) or negative error code.
Parameters
  • self_p -

    FAT16 object.

  • dir_p -

    Directory object to be initialized.

  • path_p -

    A valid 8.3 DOS name for a directory path.

  • oflag -

    mode of the directory to open (create, read, etc).

int fat16_dir_close(struct fat16_dir_t *dir_p)

Close given directory.

Return
zero(0) or negative error code.
Parameters
  • dir_p -

    Directory object.

int fat16_dir_read(struct fat16_dir_t *dir_p, struct fat16_dir_entry_t *entry_p)

Read the next file or directory within the opened directory.

Return
true(1) if an entry was read or false(0) if no entry could be read, otherwise negative error code.
Parameters
  • dir_p -

    Directory object.

  • entry_p -

    Read entry.

int fat16_stat(struct fat16_t *self_p, const char *path_p, struct fat16_stat_t *stat_p)

Gets file status by path.

Return
zero(0) or negative error code.
Parameters
  • self_p -

    The file system struct.

  • path_p -

    The path of the file to stat.

  • stat_p -

    The stat struct to populate.

Variables

struct dir_t PACKED
union fat16_time_t
#include <fat16.h>

FAT Time Format. A FAT directory entry time stamp is a 16-bit field that has a granularity of 2 seconds. Here is the format (bit 0 is the LSB of the 16-bit word, bit 15 is the MSB of the 16-bit word).

Bits 0-4: 2-second count, valid value range 0-29 inclusive (0-58 seconds). Bits 5-10: Minutes, valid value range 0-59 inclusive. Bits 11-15: Hours, valid value range 0-23 inclusive.

The valid time range is from Midnight 00:00:00 to 23:59:58.

Public Members

uint16_t as_uint16
uint16_t seconds
uint16_t minutes
uint16_t hours
struct fat16_time_t::@24 fat16_time_t::bits
union fat16_date_t
#include <fat16.h>

FAT date representation support Date Format. A FAT directory entry date stamp is a 16-bit field that is basically a date relative to the MS-DOS epoch of 01/01/1980. Here is the format (bit 0 is the LSB of the 16-bit word, bit 15 is the MSB of the 16-bit word):

Bits 0-4: Day of month, valid value range 1-31 inclusive. Bits 5-8: Month of year, 1 = January, valid value range 1-12 inclusive. Bits 9-15: Count of years from 1980, valid value range 0-127 inclusive (1980-2107).

Public Members

uint16_t as_uint16
uint16_t day
uint16_t month
uint16_t year
struct fat16_date_t::@25 fat16_date_t::bits
struct part_t
#include <fat16.h>

MBR partition table entry. A partition table entry for a MBR formatted storage device. The MBR partition table has four entries.

Public Members

uint8_t boot

Boot Indicator. Indicates whether the volume is the active partition. Legal values include: 0x00. Do not use for booting. 0x80 Active partition.

uint8_t begin_head

Head part of Cylinder-head-sector address of the first block in the partition. Legal values are 0-255. Only used in old PC BIOS.

unsigned begin_sector

Sector part of Cylinder-head-sector address of the first block in the partition. Legal values are 1-63. Only used in old PC BIOS.

unsigned begin_cylinder_high

High bits cylinder for first block in partition.

uint8_t begin_cylinder_low

Combine beginCylinderLow with beginCylinderHigh. Legal values are 0-1023. Only used in old PC BIOS.

uint8_t type

Partition type. See defines that begin with PART_TYPE_ for some Microsoft partition types.

uint8_t end_head

head part of cylinder-head-sector address of the last sector in the partition. Legal values are 0-255. Only used in old PC BIOS.

unsigned end_sector

Sector part of cylinder-head-sector address of the last sector in the partition. Legal values are 1-63. Only used in old PC BIOS.

unsigned end_cylinder_high

High bits of end cylinder

uint8_t end_cylinder_low

Combine endCylinderLow with endCylinderHigh. Legal values are 0-1023. Only used in old PC BIOS.

uint32_t first_sector

Logical block address of the first block in the partition.

uint32_t total_sectors

Length of the partition, in blocks.

struct bpb_t
#include <fat16.h>

BIOS parameter block; The BIOS parameter block describes the physical layout of a FAT volume.

Public Members

uint16_t bytes_per_sector

Count of bytes per sector. This value may take on only the following values: 512, 1024, 2048 or 4096

uint8_t sectors_per_cluster

Number of sectors per allocation unit. This value must be a power of 2 that is greater than 0. The legal values are 1, 2, 4, 8, 16, 32, 64, and 128.

uint16_t reserved_sector_count

Number of sectors before the first FAT. This value must not be zero.

uint8_t fat_count

The count of FAT data structures on the volume. This field should always contain the value 2 for any FAT volume of any type.

uint16_t root_dir_entry_count

For FAT12 and FAT16 volumes, this field contains the count of 32-byte directory entries in the root directory. For FAT32 volumes, this field must be set to 0. For FAT12 and FAT16 volumes, this value should always specify a count that when multiplied by 32 results in a multiple of bytesPerSector. FAT16 volumes should use the value 512.

uint16_t total_sectors_small

This field is the old 16-bit total count of sectors on the volume. This count includes the count of all sectors in all four regions of the volume. This field can be 0; if it is 0, then totalSectors32 must be non-zero. For FAT32 volumes, this field must be 0. For FAT12 and FAT16 volumes, this field contains the sector count, and totalSectors32 is 0 if the total sector count fits (is less than 0x10000).

uint8_t media_type

This dates back to the old MS-DOS 1.x media determination and is no longer usually used for anything. 0xf8 is the standard value for fixed (non-removable) media. For removable media, 0xf0 is frequently used. Legal values are 0xf0 or 0xf8-0xff.

uint16_t sectors_per_fat

Count of sectors occupied by one FAT on FAT12/FAT16 volumes. On FAT32 volumes this field must be 0, and sectorsPerFat32 contains the FAT size count.

uint16_t sectors_per_track

Sectors per track for interrupt 0x13. Not used otherwise.

uint16_t head_count

Number of heads for interrupt 0x13. Not used otherwise.

uint32_t hiddden_sectors

Count of hidden sectors preceding the partition that contains this FAT volume. This field is generally only relevant for media visible on interrupt 0x13.

uint32_t total_sectors_large

This field is the new 32-bit total count of sectors on the volume. This count includes the count of all sectors in all four regions of the volume. This field can be 0; if it is 0, then totalSectors16 must be non-zero.

struct fbs_t
#include <fat16.h>

Boot sector for a FAT16 or FAT32 volume.

Public Members

uint8_t jmp_to_boot_code[3]

X86 jmp to boot program

char oem_name[8]

Informational only - don’t depend on it

struct bpb_t bpb

BIOS Parameter Block

uint8_t drive_number

For int0x13 use value 0x80 for hard drive

uint8_t reserved1

Used by Windows NT - should be zero for FAT

uint8_t boot_signature

0x29 if next three fields are valid

uint32_t volume_serial_number

Usually generated by combining date and time

char volume_label[11]

Should match volume label in root dir

char file_system_type[8]

Informational only - don’t depend on it

uint8_t boot_code[448]

X86 boot code

uint16_t boot_sector_sig

Must be 0x55AA

struct mbr_t
#include <fat16.h>

Master Boot Record. The first block of a storage device that is formatted with a MBR.

Public Members

uint8_t codeArea[440]

Code Area for master boot program.

uint32_t diskSignature

Optional WindowsNT disk signature. May contain more boot code.

uint16_t usuallyZero

Usually zero but may be more boot code.

struct part_t part[4]

Partition tables.

uint16_t mbr_sig

First MBR signature byte. Must be 0x55

struct dir_t
#include <fat16.h>

FAT short directory entry. Short means short 8.3 name, not the entry size.

Public Members

uint8_t name[11]

Short 8.3 name. The first eight bytes contain the file name with blank fill. The last three bytes contain the file extension with blank fill.

uint8_t attributes

Entry attributes. The upper two bits of the attribute byte are reserved and should always be set to 0 when a file is created and never modified or looked at after that. See defines that begin with DIR_ATT_.

uint8_t reserved1

Reserved for use by Windows NT. Set value to 0 when a file is created and never modify or look at it after that.

uint8_t creation_time_tenths

The granularity of the seconds part of creationTime is 2 seconds so this field is a count of tenths of a second and its valid value range is 0-199 inclusive. (WHG note - seems to be hundredths)

uint16_t creation_time

Time file was created.

uint16_t creation_date

Date file was created.

uint16_t last_access_date

Last access date. Note that there is no last access time, only a date. This is the date of last read or write. In the case of a write, this should be set to the same date as lastWriteDate.

uint16_t first_cluster_high

High word of this entry’s first cluster number (always 0 for a FAT12 or FAT16 volume).

uint16_t last_write_time

Time of last write. File creation is considered a write.

uint16_t last_write_date

Date of last write. File creation is considered a write.

uint16_t first_cluster_low

Low word of this entry’s first cluster number.

uint32_t file_size

32-bit unsigned holding this file’s size in bytes.

union fat16_cache16_t

Public Members

uint8_t data[512]
fat_t fat[256]
struct dir_t dir[16]
struct mbr_t mbr
struct fbs_t fbs
struct fat16_cache_t

Public Members

uint32_t block_number
uint8_t dirty
uint32_t mirror_block
union fat16_cache16_t buffer
struct fat16_t

Public Members

fat16_read_t read
fat16_write_t write
void *arg_p
unsigned int partition
uint8_t fat_count
uint8_t blocks_per_cluster
uint16_t root_dir_entry_count
fat_t blocks_per_fat
fat_t cluster_count
uint32_t volume_start_block
uint32_t fat_start_block
uint32_t root_dir_start_block
uint32_t data_start_block
struct fat16_cache_t cache
struct fat16_file_t

Public Members

struct fat16_t *fat16_p
uint8_t flags
int16_t dir_entry_block
int16_t dir_entry_index
fat_t first_cluster
size_t file_size
fat_t cur_cluster
size_t cur_position
struct fat16_dir_t

Public Members

int16_t root_index
struct fat16_file_t file
struct fat16_dir_entry_t

Public Members

char name[256]
int is_dir
size_t size
struct date_t latest_mod_date
struct fat16_stat_t

Public Members

size_t size
int is_dir