ELM Home Page

May 22, 2016
Update: May 5, 2017

exFAT Filesystem


This is a documentation about exFAT filesystem written based on the US. Pat. App. Pub. No. 2009/0164440 A1 and some researches in behavior of standard systems (real Windows). It is for a supplemental attached to FAT Filesystem. You need to understand the FAT filesystem prior to read this documentation. There is a possibility of some unintended or intended error in this documentation, so that you need to refer the primary sources of exFAT filesystem and make sure behavior of the real systems when write any exFAT driver or utility.

  1. Introduction
  2. exFAT Volume
  3. Boot Sector
  4. FAT and Allocation Bitmap
  5. Up-case Table
  6. Directory Entry
  7. Directory Operations
  8. Disk Partitioning

Introduction

The exFAT filesystem (Microsoft Extended FAT Filesystem) was developped as a succession of industry standard FAT filesystem widely used for removable media and built-in storages in embedded systems. For this reason, it is designed based on the FAT filesystem to be easily implemented to existng systems. This documentation describes mainly the differences between these filesystems. exFAT filesystem has some advantages of FAT filesystem as follows.

About Notations in this Document

Numbers with heading 0x are assumed to be hexadecimal numbers, and others are decimal numbers.

The prefix K, M, G and T of each unit is assumed to be 210, 220, 230 and 240 respectively.

The fragment of program codes contained in this document are written in C language, but it is not strict to the syntax.

32-bit value and 16-bit value are arbitrary mixed in the fragment of the program codes. The programmer needs be aware of the data loss due to the type conversion and how to avoid it. Also, every data type is assumed to be unsigned. Do not calculate in signed, or it may result unintended results.

exFAT Volume

The exFAT volume is composed of three areas. Each area is located on the volume in order of as follows: (exFAT Volume Map)

  1. Boot Area (volume configuration parameters)
  2. FAT Area (for only fragmented cluster chains)
  3. Data Area (file, directroy and some system structures)

Boot Sector

Volume configuration parameters are recoreded in the boot sector as FAT filesystem does. The exFAT boot sector is actually in 12 contiguous sectors block, and two set of boot sectors (main and backup) are set in the boot area where the top of the exFAT volume. Each boundaries, sizes and count of clusters are explicitly recorded in the boot sector and there is nothing unclear in volume recognization.

Boot Sector (sector 0)
Field nameOffsetSizeDescription
JumpBoot03 Jump instruction to the BootCode (x86 instruction). Must be 0xEB, 0x76, 0x90.
FileSystemName38 Filesystem name. Must be "EXFAT   ".
MustBeZero1153 This field must be filled with zeros and spans where the BPB of FAT filesystem. This is to prevent misrecognizing as FAT volume.
PartitionOffset648 Offset of this exFAT volume origin from top of the hosting physical drive in unit of sector. The value zero indicates this field has no meaning and should be ignored.
VolumeLength728 Size of this exFAT volume includes three areas (boot, FAT and data) in unit of sector. Unlike the FAT volume, this value must be exactly same as the size of its container (the partition in MBR format or the pysical drive in SFD format). Volume size must be equal or larger than 1 MB.
FatOffset804 Offset of FAT area origin from top of the volume in unit of sector.
FatLength844 Size of an FAT in unit of sector.
ClusterHeapOffset884 Offset of cluster heap (data area) origin from top of the volume in unit of sector.
ClusterCount924 Number of clusters on the volume. 0xFFFFFFF5 maximum.
FirstClusterOfRootDirectory964 First cluster number of the root directory.
VolumeSerialNumber1004 Volume serial number. This value is a random number typically generated from current time and date.
FileSystemRevision1042 Filesystem revision. Upper byte indicates the major number and lower byte inidicates the minor numer, e.g. 0x020B indicates the revision 2.11. This document describes about exFAT revision 1.0.
VolumeFlags1062 This field contains some flags to indicate status of this volume as described below:
bit0 (ActiveFat): 0 indicates the first FAT and allocation bitmap are used, 1 indicates the second FAT and allocation bitmap are used (TexFAT option)
bit1 (VolumeDirty): Set on mount, restored on unmount. If it is already set on mount, it means there is a possibility of some insanity in the volume. Cleard after a volume sanity check.
bit2 (MediaFailure): Set on unrecoverable disk error, cleared after a surface scan.
bit3-15: Reserved (0).
BytesPerSectorShift1081 Sector size in unit of byte expressed in log2. Valid value for this field is 9 to 12 (512 to 4096 bytes). It should be same as read/write block size of the storage device that hosts this volume.
SectorsPerClusterShift1091 Cluster size in unit of sector expressed in log2. Valid value for this field is 0 to 25-BytesPerSectorShift (one sector to 32 MB).
NumberOfFats1101 Number of FATs and allocation bitmaps. 1 indicates one FAT and one allocation bitmap are exist. 2 indicates two FATs and two allocation bitmaps are exitst. Always 1 for removable media, 2 for TexFAT volume option.
DriveSelect1111 Drive number used by disk BIOS (typically 0x80). This field is used in bootstrap program. Actually it depends on the OS.
PercentInUse1121 Volume usage in unit of percent. 0xFF means this field is not used and invalid.
Reserved1137 Reserved and should be filled with zero.
BootCode120390 Boot program. This is a system dependent field and filled with zeros when not used.
BootSignature5102 0xAA55. Boot signature used to validate that this is a boot sector.
512 If the sector size is larger than 512 bytes, rest field in the sector is undefined.
Extended Boot Sector (sector 1-8)
Field nameOffsetSizeDescription
ExtendedBootCode02BytesPerSectorShift-4 Extended boot code. This is system dependent field and filled with zero when not used.
ExtededBootSignature2BytesPerSectorShift-44 0xAA550000. Boot signature used to validate that this is an extended boot sector.

Sector 9 contains OEM parameter and sector 10 is reserved for future use. The content of these sectors is depends on the system and filled with zero when not used. Sector 11 is filled with 32-bit check sum values of from sector 0 to sector 10 inclusive. These 11 sectors are calculated in byte-by-byte as a simple byte array, however VolumeFlags and PercentInUse are excluded from the calculation.

/* Calculation of 32-bit check sum */
uint32_t sum32 (const void* p, uint32_t n)
{
    uint32_t sum = 0;
    const uint8_t *dp = (const uint8_t*)p;

    do {
        sum = ((sum & 1) ? 0x80000000 : 0) + (sum >> 1) + *dp++;
    } while (--n);

    return sum;
}
/* Calculation of 16-bit check sum */
uint16_t sum16 (const void* p, uint32_t n)
{
    uint16_t sum = 0;
    const uint8_t *dp = (const uint8_t*)p;

    do {
        sum = ((sum & 1) ? 0x8000 : 0) + (sum >> 1) + *dp++;
    } while (--n);

    return sum;
}

FAT and Allocation Bitmap

The exFAT FAT entry is 32-bit in size as FAT32 FAT entry except for all bits in each entries are used. exFAT has adopted allocation bitmap to manage the cluster allocation status, free or not. The first bit of the allocation bitmap (bit0 of the first byte) corresponds to the cluseter 2. The bit value 1 means the cluster is in-use and not free for new allocation. The bit value 0 means the cluster is free and the value of FAT entry has no meaning. This is a significant difference of exFAT filesystem from FAT filesystem which indicates free cluster by a zero in the FAT entry. Following table shows the status of a cluster and corresponding entries. In the special case, the value in the FAT entry can have no meaning even if the cluster is in-use. This is described in Directory Operations.

bitmapFATCluster status
0(Don't care)Free
10 - 1(Reserved)
12 - ClusterCount+1In-use (value is link to next)
1ClusterCount+2 - 0xFFFFFFF6(Reserved)
10xFFFFFFF7Bad cluster
10xFFFFFFF8 - 0xFFFFFFFE(Reserved)
10xFFFFFFFFIn-use (end of chain)

The allocation bitmap is recored in the data area and its allocation information (start cluster and size) is recorded as a special directory entry (described in Directory Entry) on the root directory. The sizeof allocation bitmap becomes (ClusterCount + 7) / 8 bytes.

Up-case Table

In the exFAT filesystem, file names are handled as LFN extension of FAT filesystem does. Case information is preserved on recording, and matched in case insensitive. exFAT volume has up-case table on the volume for up-case conversion while it is done with on-system conversion table at the FAT filesystem. Perhaps, this is for new character definitions in the future. However what occures on the compatibility between the changes and existing systems is not clear. The up-case table needs to support ASCII alhpabetic character at least, and non-ASCII characters are optional. According to a research into the exFAT volume formatted by Windows, it seems to be same as FAT filesystem on the Windows does, but it is not that kept unchanged in the future.

The up-case table seems to support only BMP where corresponds to U+0000 - U+FFFF. It is recorded on the volume in compressed form. The following function is to extract the compressed table and create a case conversion table.

void load_upcase (
    uint16_t dst[],  /* Output table for U+0000 - U+FFFF */
    uint16_t src[],  /* Compressed table to input */
    uint16_t n_src   /* Size of compressed table [items] */
)
{
    uint16_t c, si, di;

    /* Fill output table with default values */
    c = 0; do dst[c] = c; while (++c);

    si = di = 0;
    do {
        c = src[si++];        /* Get an up-case character */
        if (c == 0xFFFF && si < n_src) {
            di += src[si++];  /* When U+FFFF appeared, skip the codes indicated by next item */
        } else {
            dst[di++] = c;    /* Store the up-case character */
        }
    } while (si < n_src);
}

Up-case table is recorded in the data area and its allocation information (start cluster and size) is recorded in a special directory entry (this is described below) on the root directory.

Directory Entry

Entry Type

Root directory is recorded in the data area. The first cluster number is stored in FirstClusterOfRootDirectory. The size of directory entry is 32 bytes. These are saeme as FAT filesystem does. Maximum length of a directory is 256 MB (8 M enrtries) while 2 MB at FAT filesystem. The first byte of each entry indicates the type of the entry. It is divided into four bit fields as shown below

Bit field in EntryType byte
FieldMeaning
InUse(bit7)0 = Free entry, 1 = Entry is in-use.
TypeCategory(bit6)0 = Primary entry, 1 = Secondary entry attached to primary entry.
TypeImportance(bit5)0 = Critcal entry, 1 = Benign entry.
TypeCode(bit4-0)0-31: Type code.

Therefore the EntryType byte provides the information about the entry, but in fact the inportant thing is its value to identify the entry type. Following table shows the defined value and entry type. Last four entry types in the table are optional for generic use or not defined for exFAT 1.00, so that they are not described in this documentation.

Entry type and
EntryTypeDescription
0x81Allocation bitmap
0x82Up-case table
0x83Volume label
0x85File and directory (file attribute and timestamp)
0xC0Stream extension (file allocation information)
0xC1File name (name of the file)
0xC2Windows CE access control list
0xA0Volume GUID
0xA1TexFAT Padding
0xA2Windows CE access control table

EntryType is the only common field for every type of entries and other fields are defined for each entry types individually. To delete an entry, clear InUse bit of EntryType instead of storeing 0xE5 what FAT filessytem does. If EntryType is zero, all following enrties in the directory are guaranteed zero.

Allocation Bitmap Entry

Contains allocation information of allocation bitmap. This entry is recorded in the root directory independently.

Field nameOfsSizeFunction
EntryType010x81 (Allocaation bitmap entry).
BitMapFlags11Bit0: 0 = 1st bitmap, 1 = 2nd bitmap.
Bit7-1: Reserved (0).
Reserved218Reserved (0).
FirstCluster204First cluster number of this allocation bitmap.
DataLength248Size of bitmap in unit of byte.

Up-case Table Entry

Contains allocation information of up-case table. This entry is recorded in the root directory independently.

Field nameOfsSizeFunction
EntryType010x82 (Up-case table entry).
Reserved113Reserved (0).
TableChecksum4432-bit checksum of the up-case table.
Reserved2812Reserved (0).
FirstCluster204First cluster number of the up-case table.
DataLength248Size of the table in unit of byte.

Volume Label Entry

Contains volume label of this volume. This entry is recorded in the root directory independently. If the size field is zero or this entry is not exist, the volume has no volume label. Any character allowed for file name includes dot can be used for the volume label.

Field nameOfsSizeFunction
EntryType010x83 (Volume label entry).
CharacterCount11Size of volume label in unit of character 0 to 11 inclusive.
VolumeLabel222Volume label string in UTF-16LE. Unlike FAT filesystem, case information is preserved and trailing spaces are valid as a part of the label.
Reserved248Reserved (0).

File and Directory Entry

This is one of the entry types which composes an entry set. It indicates start of an entry set and contains file attribute and timestamp. The entry set is a block of consecutive directory entries to record meta data of a file or sub-directory. It is set on the direcotry in order of this entry (1 entry), stream extension entry (1 entry), and name extensiton entries (1-17 entries), so that an entry set spans from 3 to 19 entries.

Field nameOfsSizeFunction
EntryType010x85 (File and directory entry).
SecondaryCount11Number of following entries. The size of this entry set is SecondaryCount+1 entries.
SetCheckSum22A 16-bit checksum to validate this entry set. The checksum of an entry set is calculated in byte-by-byte as a simple byte array excluding only this field.
FileAttribute42File attribute in combination of following flags. The meaning of these flags are same as FAT filesystem.
bit0: Read-Only.
bit1: Hidden.
bit2: System.
bit3: Reserved (0).
bit4: Directory.
bit5: Archive.
bit6-15: Reserved (0).
Reserved162Reserved (0).
CreateTimestamp84Timestamp of the file created. Upper 16 bits contains the local date and lower 16 bits contains the local time. Each fields in the date and time are same as FAT filesystem.
LastModifiedTimestamp124Timestamp of the file modified.
LastAccessedTimestamp164Timestamp of the file accessed.
Create10msIncrement201Sub-second information of CreateTimestamp in unit of 10 ms (from 0 to 199).
LastModified10msIncrement211Sub second information of LastModifiedTimestamp.
CreateTZOffset221Time zone offset of CreateTimestamp in unit of quarter hour with ORed by 0x80. For example, +9 * 4 | 0x80 = 0xA4 for JST(+9:00), -7 * 4 | 0x80 = 0xE0 for PST(-7:00). The timestamp in UTC can be got by this field. Set 0x00 when time zone is not used.
LastModifiedTZOffset231Timezone offset of LastModifiedTimestamp.
LastAccessedTZOffset241Timezone offset of LastAccessedTimestamp.
Reserved2257Reserved (0).

Stream Extension Enrty

This is one of the entry types which composes an entry set. It contains the file allocation information.

Field nameOfsSizeFunction
EntryType010xC0 (Stream extension entry).
GeneralSecondaryFlags11 These flags indicate status of the file allocation.
bit0(AllocationPossible): 0 = Cluster allocation is not possible and FirstCluster and DataLength field are undefined, 1 = Cluster allocation is possible and FirstCluster and DataLength field are valid as defined.
bit1(NoFatChain): 0 = Cluster chain on the FAT is valid, 1 = Cluster chain is contiguous and not recorded on the FAT.
bit2-15: Reserved (0).
If AllocationPossible flag is 0 (actually always 1), ValidDataLength, FirstCluster, DataLength are invalid. When cluster chain is contiguous, NoFatChain can be set and any recording on the FAT is not needed.
Reserved121Reserved (0).
NameLength31Length of the file name in UTF-16 encoding unit. Valid value for this field is 1 to 255.
NameHash4216-bit checksum of the up-case converted file name. The value is calculated in byte-by-byte as a UTF-16LE string. This enables to skip comparison at most unmatched file when look for a file in the directory.
Reserved262Reserved (0).
ValidDataLength88Valid data length of the file in unit of byte. It indicates how long the data actually written. Valid value for this field is 0 to DataLength. Any data located beyond this offset is undefined and zeros should be returned if read it. This is the feature to implement fallocate() efficiently. As for the sub-directories, the value must be equal to DataLength.
Reserved3164Reserved (0).
FirstCluster204First cluster number of the cluster chain. When DataLength is zero, also this value must be zero and the file does not have cluster chain.
DataLength248Actual length of the file in unit of byte. Size of sub-directory is always multiple of cluster size.

File Name Entry

This is one of the entry types which composes an entry set. It contains the file name string. Any character except for control characters (U+0000 to U+001F, U+007F) and " * / : < > ? \ | is allowable for file name as LFN extensiton of FAT filesystem. exFAT filesystem does not support alternative file name (SFN) what FAT filesystem supports.

Field nameOfsSizeFunction
EntryType010xC1 (File name enrty).
GeneralSecondaryFlags11Always 0.
FileName230Contains file name string in UTF-16LE. If the name length is less than 15 characters, rest of space in this field is filled with zero. If the name length exceeds 15 characters, multiple file entries ((NameLength + 14) / 15) are used and set in the entry block in ascending order.

This is an example of exFAT root directory after formatting and a file creation. You will able to see how the entries are stored on the directory.

Directory Operations

Creating a File

To create a file, find a block of free entries in the directory and create the entry set of the file. The entry set has Archive attrribute and set DataLength field to zero as initial value. AllocationPossible bit is always 1 and NoFatChain bit is initially cleared.

When any data is written to the file and a new cluster is allocated, the cluster number is set to FirstCluster and set NoFatChain bit. Thereafter no data is written to the FAT entries as long as the cluter chain is contiguous. When the cluster chain gets fragmented on a cluster allocation, create valid cluster chain on the FAT and clear NoFatChain bit. This is applied to only file and sub-directory. Any other data (root directory, allocation bitmap and up-case table) always have valid cluster chain on the FAT.

Creating a Sub-directory

To create a sub-directory, find a block of free entries in the directory and create the entry set of the sub-directory. The entry set has Directory attrribute. A cluster is initially allocated to the directory and each entry is filled with zero. NoFatChain bit is as described above. When the sub-directory gets full, the cluster chain is stretched a cluster a time and the cluster is initialized to zero. The maximum length of a direcotry is 256 MB (8 M entries).

There are significant difference from FAT sub-directory. DataLength field has a valid value. Dot entries (".", "..") on the FAT sub-directory are not exist on the exFAT sub-directory. It may be logically generated and appeared in the directory listing.

Deleting a File

To remove a file, clear InUse bit in each entries of the file entry set. If the file has a cluster chain, also the chain needs to be removed from the FAT. In this case the FAT entries do not need to be changed because the clusters get free by clearing the allocation bitmap.

Deleting a Sub-directorty

It is same as deleting a file. All nodes below the directory needs to be scanned and all files and directories in the directory need to be deleted prior to delete the directory, or those objects' clusters get lost clusters.

Disk Partitioning

Same as the description of FAT filesystem. The value of system type in the partition table for exFAT volume is 0x07, which is same as NTFS. However MBR format does not support the storage device larger than 2 TB, because the allocation information in the partition table is recorded in 32-bit LBA. To use such storage device, it needs to be in SFD format or GPT format.