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 fat16_time_tas_uint16
uint16_t fat16_time_tseconds
uint16_t fat16_time_tminutes
uint16_t fat16_time_thours
struct fat16_time_t::@48 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 fat16_date_tas_uint16
uint16_t fat16_date_tday
uint16_t fat16_date_tmonth
uint16_t fat16_date_tyear
struct fat16_date_t::@49 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 part_tboot

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

uint8_t part_tbegin_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 part_tbegin_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 part_tbegin_cylinder_high

High bits cylinder for first block in partition.

uint8_t part_tbegin_cylinder_low

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

uint8_t part_ttype

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

uint8_t part_tend_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 part_tend_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 part_tend_cylinder_high

High bits of end cylinder

uint8_t part_tend_cylinder_low

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

uint32_t part_tfirst_sector

Logical block address of the first block in the partition.

uint32_t part_ttotal_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 bpb_tbytes_per_sector

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

uint8_t bpb_tsectors_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 bpb_treserved_sector_count

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

uint8_t bpb_tfat_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 bpb_troot_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 bpb_ttotal_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 bpb_tmedia_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 bpb_tsectors_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 bpb_tsectors_per_track

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

uint16_t bpb_thead_count

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

uint32_t bpb_thiddden_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 bpb_ttotal_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 fbs_tjmp_to_boot_code[3]

X86 jmp to boot program

char fbs_toem_name[8]

Informational only - don’t depend on it

struct bpb_t fbs_tbpb

BIOS Parameter Block

uint8_t fbs_tdrive_number

For int0x13 use value 0x80 for hard drive

uint8_t fbs_treserved1

Used by Windows NT - should be zero for FAT

uint8_t fbs_tboot_signature

0x29 if next three fields are valid

uint32_t fbs_tvolume_serial_number

Usually generated by combining date and time

char fbs_tvolume_label[11]

Should match volume label in root dir

char fbs_tfile_system_type[8]

Informational only - don’t depend on it

uint8_t fbs_tboot_code[448]

X86 boot code

uint16_t fbs_tboot_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 mbr_tcodeArea[440]

Code Area for master boot program.

uint32_t mbr_tdiskSignature

Optional WindowsNT disk signature. May contain more boot code.

uint16_t mbr_tusuallyZero

Usually zero but may be more boot code.

struct part_t mbr_tpart[4]

Partition tables.

uint16_t mbr_tmbr_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 dir_tname[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 dir_tattributes

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 dir_treserved1

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 dir_tcreation_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 dir_tcreation_time

Time file was created.

uint16_t dir_tcreation_date

Date file was created.

uint16_t dir_tlast_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 dir_tfirst_cluster_high

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

uint16_t dir_tlast_write_time

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

uint16_t dir_tlast_write_date

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

uint16_t dir_tfirst_cluster_low

Low word of this entry’s first cluster number.

uint32_t dir_tfile_size

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

union fat16_cache16_t

Public Members

uint8_t fat16_cache16_tdata[512]
fat_t fat16_cache16_tfat[256]
struct dir_t fat16_cache16_tdir[16]
struct mbr_t fat16_cache16_tmbr
struct fbs_t fat16_cache16_tfbs
struct fat16_cache_t

Public Members

uint32_t fat16_cache_tblock_number
uint8_t fat16_cache_tdirty
uint32_t fat16_cache_tmirror_block
union fat16_cache16_t fat16_cache_tbuffer
struct fat16_t

Public Members

fat16_read_t fat16_tread
fat16_write_t fat16_twrite
void *fat16_targ_p
unsigned int fat16_tpartition
uint8_t fat16_tfat_count
uint8_t fat16_tblocks_per_cluster
uint16_t fat16_troot_dir_entry_count
fat_t fat16_tblocks_per_fat
fat_t fat16_tcluster_count
uint32_t fat16_tvolume_start_block
uint32_t fat16_tfat_start_block
uint32_t fat16_troot_dir_start_block
uint32_t fat16_tdata_start_block
struct fat16_cache_t fat16_tcache
struct fat16_file_t

Public Members

struct fat16_t *fat16_file_tfat16_p
uint8_t fat16_file_tflags
int16_t fat16_file_tdir_entry_block
int16_t fat16_file_tdir_entry_index
fat_t fat16_file_tfirst_cluster
size_t fat16_file_tfile_size
fat_t fat16_file_tcur_cluster
size_t fat16_file_tcur_position
struct fat16_dir_t

Public Members

int16_t fat16_dir_troot_index
struct fat16_file_t fat16_dir_tfile
struct fat16_dir_entry_t

Public Members

char fat16_dir_entry_tname[256]
int fat16_dir_entry_tis_dir
size_t fat16_dir_entry_tsize
struct date_t fat16_dir_entry_tlatest_mod_date
struct fat16_stat_t

Public Members

size_t fat16_stat_tsize
int fat16_stat_tis_dir