Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Introduction

Keramics provides read-only access to a collection of data formats.

This document is intended as a working document of specifications of data formats used by the Keramics project. These specifications are based on available documentation and analysis of data samples.

Note that these might differ from authorative format specifications and are works in progress.

Storage media image formats

A storage media image format is used to store data from storage media devices such as a hard disk, a floppy or optical disk like CD-ROM or DVD.

Formats

Expert Witness Compression Format (EWF)

EWF is short for Expert Witness Compression Format. It is a file type used to store storage media images for digital forensic purposes. It is currently widely used in the field of computer forensics in proprietary tooling like EnCase en FTK.

The “ASR Data - E01 Compression Format” is the earliest known specification of the format was provided by ASR Data for the SMART application.

The EWF format was superseded by the Expert Witness Compression Format version 2 in EnCase 7 (EWF2-Ex01 and EWF2-Lx01). EnCase 7 also uses a different version of EWF-L01 then its predecessors.

Overview

The Expert Witness Compression Format (EWF) is used to store:

  • storage media images, such as hard disks, USB sticks, optical disks
  • individual volumes or partitions
  • “physical” RAM and process memory

EWF can store data compressed or uncompressed, in a single image in one or more segment files. Each segment file consist of a standard header, followed by multiple sections. A single section cannot span multiple files. Sections are arranged back-to-back.

Terminology

In this document when referred to the EWF format it refers to the original specification by ASR Data. The newer formats like that of EnCase are deducted from the original specification and will be referred to as the EWF-E01, because of the default file extension. Whereas the Logical File Evidence (LVF) format introduced in EnCase 5, which is also stored in the EWF format will be referred to as EWF-L01. The SMART format is viewed separately to allow for discussion if the implementation differs from the specification by ASR Data and will be referred to as the EWF-S01, because of the default file extension.

All offsets are relative to the beginning of an individual section, unless otherwise noted. EnCase allows a maximum size of a segment file to be 2000 MiB. This has to do with the size of the offset of the chunk of media data. This is a 32 bit value where the most significant bit (MSB) is used as a compression flag. Therefore the maximum offset size (31 bit) can address about 2048 MiB. In EnCase 6.7 an addition was made to the table value to provide for a base offset to allow for segment files greater than 2048 MiB.

A chunk is defined as the sector size (per default 512 bytes) multiplied by the block size, the number of sectors per chunk (block) (per default 64 sectors). The data within the EWF format is stored in little-endian. The terms block and chunk are used intermittently.

Segment file

EWF stores data in one or more segment files (or segments). Each segment file consists of:

  • A file header.
  • One or more sections.

File header

Each segment file starts with a file header.

EWF defines that the file header consists of 2 parts, namely:

  • a signature part
  • fields part

EWF, EWF-E01 and SMART (EWF-S01)

The file header, used by both the EWF-E01 and SMART (EWF-S01) formats, is 13 bytes in size and consists of:

OffsetSizeValueDescription
08"EVF\x09\x0d\x0a\xff\x00"Signature
810x01Start of fields
92Segment number, which must be 1 or higher
1120x0000End of fields

The segment number contains a number which refers to the number of the segment file, starting with 1 for the first file.

Note this means there could only be a maximum of 65535 (0xffff) files, if it is an unsigned value.

EWF-L01

The file header, used by the EWF-L01 format, is 13 bytes in size and consists of:

OffsetSizeValueDescription
08"LVF\x09\x0d\x0a\xff\x00"Signature
810x01Start of fields
92Segment number, which must be 1 or higher
1120x0000End of fields

The segment number contains a number which refers to the number of the segment file, starting with 1 for the first file.

Note this means there could only be a maximum of 65535 (0xffff) files, if it is an unsigned value.

Segment file extensions

The SMART (EWF-S01) and the EWF-E01 formats use a different naming convention for the segment files.

SMART (EWF-S01)

The SMART (EWF-S01) extension naming has two distinct parts.

  • The first segment file has the extension ‘.s01’.
    • The next segment file has the extension ’.s02.
    • This will continue up to ‘.s99’.
  • After which the next segment file has the extension ‘.saa’.
    • The next segment file has the extension ‘.sab’.
    • This will continue up to ‘.saz’.
    • The next segment file has the extension ‘.sba’.
    • This will continue up to ‘.szz’.
    • The next segment file has the extension ‘.faa’.
    • This will continue up to ‘.zzz’.
    • Not confirmed but other sources report it will even continue to the use the extensions ‘.{aa’.

Keramics supports extensions up to .zzz

EWF-E01

The EWF-E01 extension naming has two distinct parts.

  • The first segment file has the extension ‘.E01’.
    • The next segment file has the extension ’.E02.
    • This will continue up to ‘.E99’.
  • After which the next segment file has the extension ‘.EAA’.
    • The next segment file has the extension ‘.EAB’.
    • This will continue up to ‘.EAZ’.
    • The next segment file has the extension ‘.EBA’.
    • This will continue up to ‘.EZZ’.
    • The next segment file has the extension ‘.FAA’.
    • This will continue up to ‘.ZZZ’.
    • Not confirmed but other sources report it will even continue to the use the extensions ‘.[AA’.

Keramics supports extensions up to .ZZZ

EWF-L01

The EWF-L01 extension naming has two distinct parts.

  • The first segment file has the extension ‘.L01’.
    • The next segment file has the extension ’.L02.
    • This will continue up to ‘.L99’.
  • After which the next segment file has the extension ‘.LAA’.
    • The next segment file has the extension ‘.LAB’.
    • This will continue up to ‘.LAZ’.
    • The next segment file has the extension ‘.LBA’.
    • This will continue up to ‘.LZZ’.
    • The next segment file has the extension ‘.MAA’.
    • This will continue up to ‘.ZZZ’.
    • Not confirmed but other sources report it will even continue to the use the extensions ‘.[AA’.

Keramics supports extensions up to .ZZZ

Segment file set identifier GUID

Segment file sets do not have a strict unique identifier. However the volume section contains a GUID that can be used for this purpose. Where:

  • linen 5 to 6 use a time and MAC address based version (1) of the GUID
  • EnCase 5 to 7 and linen 6 to 7 use a random based version (4) of the GUID

Note that in linen 6 the switch from a version 1 to 4 GUID was somewhere made between version 6.01 and 6.19.

See RFC4122 for more information about the different GUID versions.

The sections

The remainder of the segment file consists of sections. Every section starts with the same data this will be referred to as the section header.

Section header

The section header consist of 76 bytes, it contains information about a specific section.

OffsetSizeValueDescription
016Section type, a string containing the section type definition, such as "header" or "volume"
168Next section offset, where the offset is relative from the start of the segment file
248Section size
32400x00Unknown (Padding)
724Checksum, which contains an Adler-32 of all the previous data within the section header

Some sections contain additional data, refer to paragraph section types for more information.

Note Expert Witness 1.35 (for Windows) does not set the section size.

Note that in EnCase 2 DOS version the padding itself does not contains 0-byte values but data, probably the memory is not filled with 0-byte values.

Section types

There are multiple section types. “ASR Data - E01 Compression Format” defines the following:

  • Header section
  • Volume section
  • Table section
  • Next and Done section

The following sections type were found analyzing more recent EnCase files (EWF-E01):

  • Header2 section
  • Disk section
  • Sectors section
  • Table2 section
  • Data section
  • Error2 section
  • Session section
  • Hash section
  • Digest section

The following sections type were found analyzing more recent EnCase files (EWF-L01):

  • Ltree section
  • Ltypes section

Header2 section

The header2 section is identified in the section data type field as “header2”. Some aspects of this section are:

  • Found in EWF-E01 in EnCase 4 to 7, and EWF-L01 in EnCase 5 to 7
  • Found at the start of the first segment file. Not found in subsequent segment files.
  • The same header2 section is found twice directly after one and other.

The additional data this section contains is the following:

OffsetSizeValueDescription
76 (0x4c)...Information about the acquired media

The information about the acquired media consists of zlib compressed data. It contains text in UTF16 format specifying information about the acquired media. The text multiple lines separated by an end of line character(s).

The first 2 bytes of the UTF16 string are the byte order mark (BOM):

  • 0xff 0xfe for UTF-16 litte-endian
  • 0xfe 0xff for UTF-16 big-endian

In the next paragraphs the various variants of the header2 section are described.

EnCase 4 (EWF-E01)

In EnCase 4 (EWF-E01) the header2 information consist of 5 lines, and contains the equivalent information as the header section.

Line numberValueDescription
11The number of categories provided
2mainThe name/type of the category provided
3Identifiers for the values in the 4th line
4The data for the different identifiers in the 3rd line
5(an empty line)

The end of line character(s) is a newline (0x0a).

Note this end of line character differs from the one used in the header section.

The 3rd and the 4th line consist of the following tab (0x09) separated values.

Identifier numberCharacter in 3rd lineValue in 4th line
1aUnique description
2cCase number
3nEvidence number
4eExaminer name
5tNotes
6avVersion, which contains the EnCase version used to acquire the media
7ovPlatform, which contains the platform/operating system used to acquire the media
8mAcquisition date and time
9uSystem date and time
10pPassword hash

Also see header2 values

Note the hashing algorithm is the same as for the header section.

EnCase 5 to 7 (EWF-E01)

In EnCase 5 to 7 (EWF-E01) the header2 information consist of 17 lines, and contains:

Line numberValueDescription
13The number of categories provided
2mainThe name/type of the category provided
3Identifier for the values in the category
4The data for the different identifiers in the category
5(an empty line)
6srceThe name/type of the category provided, also see sources category
7
8Identifier for the values in the category
9The data for the different identifiers in the category
10
11(an empty line)
12subThe name/type of the category provided, also see subjects category
13
14Identifier for the values in the category
15The data for the different identifiers in the category
16
17(an empty line)

The end of line character(s) is a newline (0x0a).

Main category

The 3rd and the 4th line consist of the following tab (0x09) separated values.

Note the actual values in this category are dependent on the version of EnCase.

Identifier numberCharacter in 3rd lineValue in 4th line
1aUnique description
2cCase number
3nEvidence number
4eExaminer name
5tNotes
6mdThe model of the media, such as hard disk model (introduced in EnCase 6)
7snThe serial number of media (introduced in EnCase 6)
8lThe device label (introduced in EnCase 6.19)
9avVersion, which contains the EnCase version used to acquire the media. EnCase limits this value to 12 characters
10ovPlatform, which contains the platform/operating system used to acquire the media
11mAcquisition date and time
12uSystem date and time
13pPassword hash
14pidProcess identifier, which contains the identifier of the process memory acquired (introduced in EnCase 6.12/Winen 6.11)
15dcUnknown
16extExtents, which contains the extents of the process memory acquired (introduced in EnCase 6.12/Winen 6.11)

Also see header2 values

Note that both the acquiry and system date and time are empty in a file created by winen.

Note that the date values in the header section (not the header2 section) are set to: “Thu Jan 1 00:00:00 1970”. Where the time is dependent on the time zone and daylight savings.

Note that in a Logicube Dossier generated header2 section an additional emtpy value in the 4th line was observed. The number of values in the 3rd and 4th can differ.

Sources category

Line 6 the srce category contains information about acquisition sources.

TODO: describe what a source is in the context of EnCase.

Line 7 consists of 2 values, namely the values are “0 1”.

The 8th line consist of the following tab (0x09) separated values.

Note that the actual values in this category are dependent on the version of EnCase.

Identifier numberCharacter in 8rd lineMeaning
1p
2n
3idIdentifier, which contains an integer identifying the source
4evEvidence number, which contains a string
5tbTotal bytes, which contains an integer
6loLogical offset, which contains an integer which is -1 when value is not set
7poPhysical offset, which contains an integer which is -1 when value is not set
8ahMD5 hash, which contains a string with the MD5 hash of the source
9shSHA1 hash, contains a string with the SHA1 hash of the source (introduced in EnCase 6.19)
10guDevice GUID, which contains a string with a GUID or "0" if not set
11pguPrimary device GUID, which contains a string with a GUID or "0" if not set (introduced in EnCase 7)
12aqAcquisition date and time, which contains an integer with a POSIX timestamp

Line 9 consists of 2 values, namely the values are “0 0”.

Line 10 contains the values defined by line 8.

Note the default values of some of these values has changed around EnCase 6.12.

If the “ha” value contains “00000000000000000000000000000000” this means the MD5 hash is not set. The same applies for the “sha” value when it contains “0000000000000000000000000000000000000000” the SHA1 has is not set.

Subjects category

Line 12 the sub category contains information about subjects.

TODO: describe what a subject is in the context of EnCase.

Line 13 consists of 2 values, namely the values are “0 1”.

The 14th line consist of the following tab (0x09) separated values.

Identifier numberCharacter in 14rd lineMeaning
1p
2n
3idIdentifier, which contains an integer identifying the subject
4nuUnknown (Number)
5coUnknown (Comment)
6guUnknown (GUID)

Line 15 consists of 2 values, namely the values are “0 0”.

Line 16 contains the values defined by line 14.

Note that the default values of some of these values has changed around EnCase 6.12.

EnCase 5 to 7 (EWF-L01)

The EnCase 5 to 7 (EWF-E01) header2 section specification also applies to the EnCase 5 to 7 (EWF-L01) format. However:

  • both the acquired and system date and time are not set

Header2 values

IdentifierDescriptionNotes
aUnique descriptionFree form string. Note that EnCase might not respond when this value is large e.g. >= 1 MiB
avVersionFree form string. EnCase limits this string to 12 - 1 characters
cCase numberFree form string. EnCase limits this string to 3000 - 1 characters
dcUnknown
eExaminer nameFree form string. EnCase limits this string to 3000 - 1 characters
extExtentsExtents header value
lDevice labelFree form string
mAcquisition date and timeString containing POSIX 32-bit epoch timestamp, e.g. "1142163845" which represents the date: March 12 2006, 11:44:05
mdModelFree form string. EnCase limits this string to 3000 - 1 characters
nEvidence numberFree form string. EnCase limits this string to 3000 - 1 characters
ovPlatformFree form string. EnCase limits this string to 24 - 1 characters
pidProcess identifierString containing the process identifier (pid) number
pPassword hashString containing the password hash. If no password is set it should be simply the character '0'
snSerial NumberFree form string. EnCase limits this string to 3000 - 1 characters
tNotesFree form string. EnCase limits this string to 3000 - 1 characters
uSystem date and timeString containing POSIX 32-bit epoch timestamp, e.g. "1142163845" which represents the date: March 12 2006, 11:44:05

Note the restrictions were tested with EnCase 7.02.01, older versions could have a restriction of 40 characters instead of 3000 characters.

Extents header value

An extents header value consist of:

number of entries
entries that consist of: S <1> <2> <3>

Header section

The header section is identified in the section data type field as “header”. Some aspects of this section are:

  • Defined in “ASR Data - E01 Compression Format”
  • Found in EWF-E01 in EnCase 1 to 7 or linen 5 to 7 or FTK Imager, EWF-L01 in EnCase 5 to 7, and SMART (EWF-S01)
  • Found at the start of the first segment file or in EnCase 4 to 7 after the header2 section in the first segment file. Typically not found in subsequent segment files with the exception of Logicube Dossier generated EWF-E01 files.

The additional data this section contains is the following:

OffsetSizeValueDescription
76 (0x4c)...Information about the acquired media

The information about the acquired media consists of zlib compressed data. It contains text in ASCII format specifying information about the acquired media. The text multiple lines separated by an end of line character(s).

In the next paragraphs the various variants of the header section are described. In all cases the information consists of at least 4 lines:

Line numberValueDescription
11The number of categories provided
2mainThe name/type of the category provided
3Identifiers for the values in the 4th line
4The data for the different identifiers in the 3rd line

An additional 5th line is found in FTK Imager, EnCase 1 to 7 (EWF-E01).

Line numberValueDescription
5(an empty line)

EWF format

Some aspects of this section are:

  • “ASR Data - E01 Compression Format” specifies the end of line character(s) is a newline (0x0a).

According to “ASR Data - E01 Compression Format” the 3rd and the 4th line consist of the following tab (0x09) separated values:

Identifier numberCharacter in 3rd lineValue in 4th line
1cCase number
2nEvidence number
3aUnique description
4eExaminer name
5tNotes
6mAcquisition date and time
7uSystem date and time
8pPassword hash
9rCompression level

Also see header values

“ASR Data - E01 Compression Format” states that the Expert Witness Compression uses ‘f’, fastest compression.

EnCase 1 (EWF-E01)

Some aspects of this section are:

  • The header section is defined only once.
  • It is the first section of the first segment file. It is not found in subsequent segment files.
  • The header data itself is compressed using zlib.
  • The end of line character(s) is a carriage return (0x0d) followed by a newline (0x0a).

The 3rd and the 4th line consist of the following tab (0x09) separated values“

Identifier numberCharacter in 3rd lineValue in 4th line
1cCase number
2nEvidence number
3aUnique description
4eExaminer name
5tNotes
6mAcquisition date and time
7uSystem date and time
8pPassword hash
9rCompression level

Also see header values

SMART (EWF-S01)

Some aspects of this section are:

  • The header section is defined once.
  • It is the first section of the first segment file. It is not found in subsequent segment files.
  • The header data is always processed by zlib, however the same compression level is used as for the chunks. This could mean compression level 0 which is no compression.

The SMART format uses the FTK Imager (EWF-E01) specification for this section. Note that this could be something FTK Imager specific.

EnCase 2 and 3 (EWF-E01)

Some aspects of this section are:

  • The same header section defined twice.
  • It is the first and second section of the first segment file. It is not found in subsequent segment files.
  • The header data itself is compressed using zlib.
  • The end of line character(s) is a carriage return (0x0d) followed by a newline (0x0a).

The 3rd and the 4th line consist of the following tab (0x09) separated values:

Identifier numberCharacter in 3rd lineValue in 4th line
1cCase number
2nEvidence number
3aUnique description
4eExaminer name
5tNotes
6avVersion, which contains the EnCase version used to acquire the media
7ovPlatform, which contains the platform/operating system used to acquire the media
8mAcquisition date and time
9uSystem date and time
10pPassword hash
11rCompression level

Also see header values

EnCase 4 to 7 (EWF-E01)

Some aspects of this section are:

  • The header is defined only once.
  • It resides after the header2 sections of the first segment file. It is not found in subsequent segment files.
  • The header data itself is compressed using zlib.
  • The end of line character(s) is a carriage return (0x0d) followed by a newline (0x0a).

The 3rd and the 4th line consist of the following tab (0x09) separated values:

Identifier numberCharacter in 3rd lineValue in 4th line
1cCase number
2nEvidence number
3aUnique description
4eExaminer name
5tNotes
6avVersion, which contains the EnCase version used to acquire the media
7ovPlatform, which contains the platform/operating system used to acquire the media
8mAcquisition date and time
9uSystem date and time
10pPassword hash

Also see header values

linen 5 to 7 (EWF-E01)

Some aspects of this section are:

  • The same header section defined twice.
  • It is the first and second section of the first segment file. It is not found in subsequent segment files.
  • The header data itself is compressed using zlib.
  • The end of line character(s) is a newline (0x0a).

The header information consist of 18 lines

The remainder of the string contains the following information:

Line numberValueDescription
13The number of categories provided
2mainThe name/type of the category provided
3Identifier for the values in the 4th line
4The data for the different identifiers in the 3rd line
5(an empty line)
6srceThe name/type of the section provided, also see Sources category
7
8Identifier for the values in the section
9
10
11(an empty line)
12subThe name/type of the section provided, also see Subjects category
13
14Identifier for the values in the section
15
16
17(an empty line)

The end of line character(s) is a newline (0x0a).

Main category - linen 5

The 3rd and the 4th line consist of the following tab (0x09) separated values.

Note the actual values in this category are dependent on the version of linen.

Identifier numberCharacter in 3rd lineValue in 4th line
1aUnique description
2cCase number
3nEvidence number
4eExaminer name
5tNotes
6avVersion, which contains the linen version used to acquire the media
7ovPlatform, which contains the platform/operating system used to acquire the media
8mAcquisition date and time
9uSystem date and time
10pPassword hash

Also see header values

Main category - linen 6 to 7

The 3rd and the 4th line consist of the following tab (0x09) separated values.

Note the actual values in this category are dependent on the version of linen.

Identifier numberCharacter in 3rd lineValue in 4th line
1aUnique description
2cCase number
3nEvidence number
4eExaminer name
5tNotes
6mdThe model of the media, such as hard disk model (Introduced in linen 6)
7snThe serial number of media (Introduced in linen 6)
8lThe device label (Introduced in linen 6.19)
9avVersion, which contains the linen version used to acquire the media
10ovPlatform, which contains the platform/operating system used to acquire the media
11mAcquisition date and time
12uSystem date and time
13pPassword hash
14pidProcess identifier, which contains the identifier of the process memory acquired (Introduced in linen 6.19 or earlier)
15dcUnknown (Introduced in linen 6)
16extExtents, which contains the extents of the process memory acquired (Introduced in linen 6.19 or earlier)

Note as of linen 6.19 the acquire date and time is in UTC and the system date and time is in local time. Where as before both values were in local time.

Also see header values

Sources category

Line 6 the srce category contains information about acquisition sources

TODO: describe what a source is in the context of EnCase.

Line 7 consists of 2 values, namely the values are “0 1”.

The 8th line consist of the following tab (0x09) separated values.

Identifier numberCharacter in 8rd lineMeaning
1p
2n
3idIdentifier, which contains an integer identifying the source
4evEvidence number, which contains a string
5tbTotal bytes, which contains an integer
6loLogical offset, which contains an integer which is -1 when value is not set
7poPhysical offset, which contains an integer which is -1 when value is not set
8ahUnknown (MD5?), which contains a string
9shUnknown (SHA1?), which contains a string (Introduced in linen 6.19 or earlier)
10guDevice GUID, which contains a string with a GUID or "0" if not set
11aqAcquisition date and time, which contains an integer with a POSIX timestamp

Line 9 consists of 2 values, namely the values are “0 0”.

Line 10 contains the values defined by line 8.

Note the default values of some of these values has changed around linen 6.19 or earlier.

Subjects category

Line 12 the sub category contains information about subjects.

TODO: describe what a subject is in the context of EnCase.

Line 13 consists of 2 values, namely the values are “0 1”.

The 14th line consist of the following tab (0x09) separated values.

Identifier numberCharacter in 14rd lineMeaning
1p
2n
3idIdentifier, which contains an integer identifying the subject
4nuUnknown (Number)
5coUnknown (Comment)
6guUnknown (GUID)

Line 15 consists of 2 values, namely the values are “0 0”.

Line 16 contains the values defined by line 14.

Note the default values of some of these values has changed around linen 6.19 or earlier.

FTK Imager (EWF-E01)

Some aspects of this section are:

  • In FTK Imager (EWF-E01) the same header section defined twice.
  • It is the first and second section of the first segment file. It is not found in subsequent segment files.
  • The header data itself is compressed using zlib. Note that the compression level can be none and therefore the header looks uncompressed.
  • In FTK Imager the end of line character(s) is a newline (0x0a).

The 3rd and the 4th line consist of the following tab (0x09) separated values:

Identifier numberCharacter in 3rd lineValue in 4th line
1cCase number
2nEvidence number
3aUnique description
4eExaminer name
5tNotes
6avVersion, which contains the FTK Imager version used to acquire the media
7ovPlatform, which contains the platform/operating system used to acquire the media
8mAcquisition date and time
9uSystem date and time
10pPassword hash
11rCompression level

Also see header values

EnCase 5 to 7 (EWF-L01)

The EnCase 4 to 7 (EWF-E01) header section specification is also used for the EnCase 5 to 7 (EWF-L01) format, with the following aspects:

  • In EnCase 5 both the acquired and system date and time are set to 0.
  • In EnCase 6 and 7 both the acquired and system date and time are set to Jan 1, 1970 00:00:00 (the time is dependent on the local timezone and daylight savings)

Header values

IdentifierDescriptionNotes
aUnique descriptionFree form string. Note that EnCase might not respond when this value is large e.g. >= 1 MiB
avVersionFree form string. EnCase limits this string to 12 - 1 characters
cCase numberFree form string. EnCase limits this string to 3000 - 1 characters
dcUnknown
eExaminer nameFree form string. EnCase limits this string to 3000 - 1 characters
extExtentsExtents header value
lDevice labelFree form string
mAcquisition date and timeContains a date and time header value
mdModelFree form string. EnCase limits this string to 3000 - 1 characters
nEvidence numberFree form string. EnCase limits this string to 3000 - 1 characters
ovPlatformFree form string. EnCase limits this string to 24 -1 characters
pidProcess identifierString containing the process identifier (pid) number
pPassword hashString containing the password hash. If no password is set it should be simply the character '0'
rCompression levelCompression header value
snSerial NumberFree form string. EnCase limits this string to 3000 - 1 characters
tNotesFree form string. EnCase limits this string to 3000 - 1 characters
uSystemdate and timeContains a date and time header value

Note the restrictions were tested with EnCase 7.02.01, older versions could have a restriction of 40 characters instead of 3000 characters.

Date and time header value

In EnCase a date and time contains a string of individual values separated by a space, e.g. “2002 3 4 10 19 59”, which represents March 4, 2002 10:19:59.

In linen a date and time contains a string with a POSIX 32-bit epoch timestamp, e.g. “1142163845” which represents the date: March 12 2006, 11:44:05

Extents header value

An extents header value consist of:

number of entries
entries that consist of: S <1> <2> <3>
Compression header value

A compression header value consist of a single character that represent the compression level.

Character valueMeaning
bBest compression is used
fFastest compression is used
nNo compression is used
Notes

There should not be a tab, carriage return and newline characters within the text in the 4th line. Or is there a method to escape these characters?

“ASR Data - E01 Compression Format” states that these characters should not be used in the free form text. Need to confirm this, the specification only speaks of a newline character.

Currently the password has no a additional value than allow an application check it. The data itself is not protected using the password. The password hashing algorithm is unknown. Need to find out. And does the algorithm differ per EnCase version? probably not. The algorithm does not differ in EnCase 1 to 7. FTK Imager does not bother with a password.

Volume section

The volume section is identified in the section data type field as “volume”. Some aspects of this section are:

  • Defined in “ASR Data - E01 Compression Format”
  • Found in EWF-E01 in EnCase 1 to 7 or linen 5 to 7 or FTK Imager, EWF-L01 in EnCase 5 to 7, and SMART (EWF-S01)
  • Found after the header section of the first segment file. Not found in subsequent segment files.

In the next paragraphs the various versions of the volume section are described.

EWF specification

The specification according to “ASR Data - E01 Compression Format”.

The volume section data is 94 bytes in size and consists of:

OffsetSizeValueDescription
040x01Unknown (Reserved)
44The number of chunks within the all segment files
84The number of sectors per chunk, which contains 64 per default
124The number of bytes per sectors, which contains 512 per default
164The sectors count, the number of sectors within all segment files
20200x00Unknown (Reserved)
40450x00Unknown (Padding)
855Signature, which contains the EWF file header signature
904Checksum, which contains an Adler-32 of all the previous data within the volume section data

The number of chunks is a 32-bit value this means it maximum of addressable chunks would be: 4294967295 (= 2^32 - 1). For a chunk size of 32768 x 4294967295, which is about 127 TiB. The maximum segment file amount is 2^16 - 1 = 65535. This allows for an equal number of storage if a segment file is filled to its maximum number of chunks.

However Keramics is restricted at 14295 segment files, due to the extension naming schema of the segment files.

SMART (EWF-S01)

The SMART format uses the EWF specification for this section.

In SMART the signature (reverse) value is the string “SMART” (0x53 0x4d 0x41 0x52 0x54) instead of the file header signature.

FTK Imager, EnCase 1 to 7 and linen 5 to 7 (EWF-E01)

The specification for FTK Imager, EnCase 1 to 7 and linen 5 to 7.

The volume section data is 1052 bytes in size and consists of:

OffsetSizeValueDescription
01Media type
130x00Unknown (empty values)
44The number of chunks within the all segment files
84The number of sectors per chunk (or block size), which contains 64 per default. EnCase 5 is the first version which allows this value to be different than 64
124The number of bytes per sector
168The sectors count, which contains the number of sectors within all segment files. This value probably has been changed in EnCase 6 from a 32-bit value to a 64-bit value to support media >2TiB
244The number of cylinders of the C:H:S value, which most of the time this value is empty (0x00)
284The number of heads of the C:H:S value, which most of the time this value is empty (0x00)
324The number of sectors of the C:H:S value, which most of the time this value is empty (0x00)
361Media flags
3730x00Unknown (empty values)
404PALM volume start sector
4440x00Unknown (empty values)
484SMART logs start sector, which contains an offset relative from the end of media, e.g. a value of 10 would refer to sector = number of sectors - 10
521Compression level (Introduced in EnCase 5)
5330x00Unknown (empty values, these values seem to be part of the compression level)
564The sector error granularity, which contains the error block size (Introduced in EnCase 5)
6040x00Unknown (empty values)
6416Segment file set identifier, which contains a GUID/UUID generated on the acquiry system probably used to uniquely identify a set of segment files (Introduced in EnCase 5)
809630x00Unknown (empty values)
104350x00Unknown (Signature)
10484Checksum, which contains an Adler-32 of all the previous data within the volume section data

TODO: a value that could be in the volume is the RAID stripe size

Note that EnCase requires for media that contains no partition table that the is physical media flag is not set and vice versa. Other tools like FTK check the actual storage media data.

EnCase 5 to 7 (EWF-L01)

The EWF-L01 format uses the EnCase 5 (EWF-E01) volume section specification. However:

  • the volume type contains 0x0e
  • the number of chunks is 0
  • the number of bytes per sectors is some kind of block size value (4096), perhaps the source file system block size
  • the sectors count, represents some other value because (sector_size x sector_amount != total_size). The total size is in the ltree section.

Media type

ValueIdentifierDescription
0x00A removable storage media device
0x01A fixed storage media device
0x03An optical disc (CD/DVD/BD)
0x0eLogical Evidence (LEF or L01)
0x10Physical Memory (RAM) or process memory

Note that FTK imager versions, before version 2.9, set the storage media to fixed (0x01). The exact version of FTK imager where this behavior changed is unknown.

Media flags

ValueIdentifierDescription
0x01Is an image file. In FTK Imager, EnCase 1 to 7 this bit is always set, when not set EnCase seems to see the image file as a device
0x02Is physical device or device type, where 0 represents a non physical device (logical) and 1 represents a physical device
0x04Fastbloc write blocker used
0x08Tableau write blocker used. This was added in EnCase 6.13

Note that if both the the Fastbloc and Tableau write blocker media flags are set EnCase only shows the Fastbloc.

Compression level

ValueIdentifierDescription
0x00no compression
0x01good compression
0x02best compression

Note that EnCase 7 no longer provides the fast and best compression options.

Disk section

The disk section is identified in the section data type field as “disk”. Some aspects of this section are:

  • Not defined in “ASR Data - E01 Compression Format”.
  • Not found in SMART (EWF-S01).

With a disk section in an FTK Imager 2.3 (EWF-E01) image it was confirmed that the disk section is the same as the volume section.

Note that the disk section was found only in FTK Imager 2.3 when acquiring a physical disk not a floppy. This requires additional research, it is currently assumed that the disk section some old method to differentiate between a partition (volume) image or a physical disk image.

Data section

The data section is identified in the section data type field as “data”. Some aspects of this section are:

  • Not defined in “ASR Data - E01 Compression Format”.
  • Found in EWF-E01 in EnCase 1 to 7 or linen 5 to 7 or FTK Imager, and EWF-L01 in EnCase 5 to 7. Not found in SMART (EWF-S01).
  • For multiple segment files it does not reside in the first segment file. For a single segment file it does.
  • Found after the last table2 section in a single segment file or for multiple segment files at the start of the segment files, except for the first.
  • The data section has data it should should contain the same information as the volume section.

The data section is a copy of the volume section.

FTK Imager, EnCase 1 to 7 and linen 5 to 7 (EWF-E01)

Note that in Logicube products (Talon (firmware predating April 2013) and Forensic dossier (before version 3.3.3RC16)) the checksum is not calculated and set to 0.

Sectors section

The sectors section is identified in the section data type field as “sectors”. Some aspects of this section are:

  • Not defined in “ASR Data - E01 Compression Format”.
  • Found in EWF-E01 in EnCase 2 to 7, or linen 5 to 7 or FTK Imager, EWF-L01 in EnCase 5 to 7. Not found in EnCase 1 (EWF-E01) or SMART (EWF-S01).
  • The first sectors section can be found after the volume section in the first segment file or at the after the data section in subsequent segment files. Successive sector data sections are found after the sector table2 section.

The sectors section contains the actual chunks of media data.

  • The sectors section can contain multiple chunks.
  • The default size of a chunk is 32768 bytes of data (64 standard sectors, with a size of 512 bytes per sector). It is possible in EnCase 5 and 6 and linen 5 and 6 to change the number of sectors per block to 64, 128, 256, 1024, 2048, 4096, 8192, 16384 or 32768. In EnCase 7 and linen 7 this has been reduced to 64, 128, 256, 1024.

Data chunk

The first chunk is often located directly after the section header, although the format does not require this.

When the data is compressed and the compressed data (with checksum) is larger than the uncompressed data (without the checksum) the data chunk is stored uncompressed. The default size of a chunk is 32768 bytes of data (64 standard sectors).

An uncompressed data chunk is of variable size and consists of:

OffsetSizeValueDescription
0...Uncompressed chunk data
...4Checksum, which contains an Adler-32 of the chunk data

The compressed data chunk consist of zlib compressed data. The checksum of the compressed data chunk is part the zlib compressed data format.

Optical disc images

For a MODE-1 CD-ROM optical disc image EnCase only seems to support 2048 bytes per sector (the data).

The raw sector size of a MODE-1 CD-ROM is 2352 bytes in size and consists of:

OffsetSizeValueDescription
016Synchronization bytes
162048Data
20544Error detection
205880x00Unknown (Empty values)
2066276Error correction

TODO: add information about Mode-2 and Mode-XA

Table section

The table section is identified in the section data type field as “table”. Some aspects of this section are:

  • Defined in “ASR Data - E01 Compression Format”.
  • Found in EWF-E01 in EnCase 1 to 7 or linen 5 to 7 or FTK Imager, EWF-L01 in EnCase 5 to 7, and SMART (EWF-S01)

Note that the offsets within the section header are 8 bytes (64 bits) of size while the offsets in the table entry array are 4 bytes (32 bits) in size.

In the next paragraphs the various versions of the table section are described.

EWF specification

Some aspects of the table section according to the EWF specification are:

  • The first table section resides after the volume section in the first segment file or after the file header in subsequent segment files.
  • It can be found in every segment file.

The table section consists of:

  • the table header
  • an array of table entries
  • the data chunks
Table header

The table header is 24 bytes in size and consists of:

OffsetSizeValueDescription
04The number of entries
4160x00Unknown (Padding)
204Checksum, which contains an Adler-32 of all the previous data within the table header data

According to “ASR Data - E01 Compression Format”:

  • the number of entries, contains 0x01
  • the table can hold 16375 entries if more entries are required an additional table section should be created.
Table entry

The table entry is 4 bytes in size and consists of:

OffsetSizeValueDescription
04Chunk data offset

The most significant bit (MSB) in the chunk data offset indicates if the chunk is compressed (1) or uncompressed (0).

A chunk data offset points to the start of the chunk of media data, which resides in the same table section within the segment file. The offset contains a value relative to the start of the file.

Data chunk

The first chunk is often located directly after the last table entry, although the format does not require this.

A data chunk is always compressed even when no compression is required. This approach provides a checksum for each chunk. The default size of a chunk is 32768 bytes of data (64 standard sectors). The resulting size of the “compressed” chunk can therefore be larger than the default chunk size.

Note that this was deducted from the behavior of FTK Imager for SMART (EWF-S01).

The compressed data chunk consist of zlib compressed data. The checksum of the compressed data chunk is part the zlib compressed data format.

SMART (EWF-S01)

The table section in the SMART (EWF-S01) format is equivalent to that of the EWF specification.

EnCase 1 (EWF-E01)

Some aspects of this section are:

  • The table section resides after the volume section in the first segment file or after the file header in subsequent segment files.
  • It can be found in every segment file.

The table section consists of:

  • the table header
  • an array of table entries
  • the table footer
  • the data chunks
Table header

The table header is 24 bytes in size and consists of:

OffsetSizeValueDescription
04The number of entries
4160x00Unknown (Padding)
204Checksum, which contains an Adler-32 of all the previous data within the table header data

The table can hold 16375 entries if more entries are required an additional table section should be created.

Table entry

The table entry is 4 bytes in size and consists of:

OffsetSizeValueDescription
04Chunk data offset

The most significant bit (MSB) in the chunk data offset indicates if the chunk is compressed (1) or uncompressed (0).

A chunk data offset points to the start of the chunk of media data, which resides in the same table section within the segment file. The offset contains a value relative to the start of the file.

The table footer is 4 bytes in size and consists of:

OffsetSizeValueDescription
04Checksum, which contains an Adler-32 of the offset array
Data chunk

The first chunk is often located directly after the table footer, although the format does not require this.

When the data is compressed and the compressed data (with checksum) is larger than the uncompressed data (without the checksum) the data chunk is stored uncompressed. The default size of a chunk is 32768 bytes of data (64 standard sectors).

An uncompressed data chunk is of variable size and consists of:

OffsetSizeValueDescription
0...Uncompressed chunk data
...4Checksum, which contains an Adler-32 of the chunk data

The compressed data chunk consist of zlib compressed data. The checksum of the compressed data chunk is part the zlib compressed data format.

FTK Imager and EnCase 2 to 5 and linen 5 (EWF-E01)

Some aspects of this section are:

  • The table section resides after the sectors section.
  • It can be found in every segment file.
  • The data chunks are no longer stored in this section but in the sectors section instead.
  • The table2 section contains a mirror copy of the table section. In EWF-E01 it is always present.

The table section consists of:

  • the table header
  • an array of table entries
  • the table footer
Table header

The sector table header is 24 bytes in size and consists of:

OffsetSizeValueDescription
04The number of entries
4160x00Unknown (Padding)
204Checksum, which contains an Adler-32 of all the previous data within the table header data

The table section can hold 16375 entries. A new table section should be created to hold more entries. Both FTK Imager and EnCase 5 can handle more than 16375, FTK 1 cannot. To contain more than 16375 chunks new sectors, table and table2 sections need to be created after the table2 section.

Table entry

The table entry is 4 bytes in size and consists of:

OffsetSizeValueDescription
04Chunk data offset

The most significant bit (MSB) in the chunk data offset indicates if the chunk is compressed (1) or uncompressed (0).

A chunk data offset points to the start of the chunk of media data, which resides in the preceding sectors section within the segment file. The offset contains a value relative to the start of the file.

The table footer is 4 bytes in size and consists of:

OffsetSizeValueDescription
04Checksum, which contains an Adler-32 of the offset array

EnCase 6 to 7 and linen 6 to 7 (EWF-E01)

Some aspects of this section are:

  • Every segment file contains its own table section.
  • It resides after the sectors section.
  • The data chunks are no longer stored in this section but in the sectors section instead.
  • The table2 section contains a mirror copy of the table section. In EWF-E01 it is always present.

The table section consists of:

  • the table header
  • an array of table entries
  • the table footer
Table header

The sector table header is 24 bytes in size and consists of:

OffsetSizeValueDescription
04The number of entries
440x00Unknown (Padding)
88The table base offset
1640x00Unknown (Padding)
204Checksum, which contains an Adler-32 of all the previous data within the table header data

As of EnCase 6 the number of entries is no longer restricted to 16375 entries. The new limit seems to be 65534.

Table entry

The table entry is 4 bytes in size and consists of:

OffsetSizeValueDescription
04Chunk data offset

The most significant bit (MSB) in the chunk data offset indicates if the chunk is compressed (1) or uncompressed (0).

A chunk data offset points to the start of the chunk of media data, which resides in the preceding sectors section within the segment file. The offset contains a value relative to the table base offset.

In EnCase 6.7.1 the sectors section can be larger than 2048Mb. The table entries offsets are 31 bit values in EnCase6 the offset in a table entry value will actually use the full 32 bit if the 2048Mb has been exceeded. This behavior is no longer present in EnCase 6.8 so it is assumed to be a bug. Keramics currently assumes that the if the 31 bit value overflows the following chunks are uncompressed. This allows EnCase 6.7.1 faulty EWF files to be converted.

The table footer is 4 bytes in size and consists of:

OffsetSizeValueDescription
04Checksum, which contains an Adler-32 of the offset array

EnCase 6 to 7 (EWF-L01)

The EWF-L01 format uses the EnCase 6 to 7 (EWF-E01) table section specification.

Table2 section

The table2 section is identified in the section data type field as “table2”. Some aspects of this section are:

  • Not defined in “ASR Data - E01 Compression Format”.
  • Found in EWF-E01 in EnCase 2 to 7, or linen 5 to 7 or FTK Imager, EWF-L01 in EnCase 5 to 7. Not found in EnCase 1 (EWF-E01) or SMART (EWF-S01).
  • Uses the same format as the table section.
  • Resides directly after the table section.

FTK Imager and EnCase 2 to 7 and linen 5 to 7 (EWF-E01)

The table2 section contains a mirror copy of the table section. Probably intended for recovery purposes.

EnCase 5 to 7 (EWF-L01)

The EWF-L01 format uses the EWF-E01 table2 section specification.

Next section

The next section is identified in the section data type field as “next”. Some aspects of this section are:

  • Defined in “ASR Data - E01 Compression Format”.
  • Found in EWF-E01 in EnCase 1 to 7 or linen 5 to 7 or FTK Imager, EWF-L01 in EnCase 5 to 7, and SMART (EWF-S01)
  • The last section within a segment other than the last segment file.
  • The offset to the next section in the section header of the next section point to itself (the start of the next section).
  • It should be the last section in a segment file, other than the last segment file.

SMART (EWF-S01)

It resides after the table or table2 section.

FTK Imager, EnCase and linen (EWF-E01)

It resides after the data section in a single segment file or for multiple segment files after the table2 section.

In the EnCase (EWF-E01) format the size in the section header is 0 instead of 76 (the size of the section header).

Note that FTK imager versions before 2.9 sets the section size to 76. At the moment it is unknown in which version this behavior was changed.

Ltypes section

The ltypes section is identifier in the section data type field as “ltypes”. Some aspects of this section are:

  • Found in EWF-L01 in of EnCase 7
  • Found in the last segment file after table2 section before tree section.

The additional ltypes section data is 6 bytes in size and consists of:

OffsetSizeValueDescription
02Unknown
22Unknown
42Unknown

Ltree section

The ltree section is identifier in the section data type field as “ltree”. Some aspects of this section are:

  • Found in EWF-L01 in of EnCase 5 to 7
  • Found in the last segment file after ltypes section and before data section.

The ltree section consists of:

  • ltree header
  • ltree data

Ltree header

The ltree header is 48 bytes in size and consists of:

OffsetSizeValueDescription
016Integrity hash, which contains the MD5 of the ltree data
168Data size
244Checksum, which contains an Adler-32 of all the data within the ltree header where the checksum value itself is zeroed out
2820Unknown (empty values)

Ltree data

The ltree data string consists of an UTF-16 little-endian encoded string without byte order mark. The ltree data is not strict UTF-16 since it allows for unpaired surrogates, such as “U+d800” and “U+dc00”.

Other observed characteristics where the names in the ltree deviate from the original source:

  • [U+0001-U+0008] were converted to U+00ba
  • [U+0009, U+000a] were stripped
  • [U+000b, U+000c] were converted to U+0020
  • U+000d was converted to U+0002
  • U+00ba remained the same

Note that this behavior could be related to EnCase as well and might not be specific for EWF-L01.

The ltree data string contains the following information:

Line numberValueDescription
15The number of categories provided
2recInformation about unknown, also see Records category
...(an empty line)
...permInformation about file permissions, also see Permissions category
...(an empty line)
...srceInformation about acquisition sources, also see sources category
...(an empty line)
...subInformation about unknown, also see subjects category
...(an empty line)
...entryInformation about file entries, also see File entries category
...(an empty line)

The end of line character(s) is a newline (0x0a).

Records category

The rec category contains information about records.

The 1st line of the category contains the string “rec”.

The 2nd line of the category contains tab (0x09) separated type indicators.

Identifier numberType indicatorDescription
1tbTotal bytes, which contains an integer with size of the logical file data (media data)
2clUnknown (Clusters?)
3nUnknown (introduced in EnCase 6.19)
4fpUnknown (introduced in EnCase 7)
5pgUnknown (introduced in EnCase 7)
6lgUnknown (introduced in EnCase 7)
7igUnknown (introduced in EnCase 7)

The 3rd line of the category consist of the tab (0x09) separated values.

Permissions category

The perm category contains information about file permissions.

The 1st line of the category contains the string “perm”.

The 2nd line consists of the following 2 values:

Value numberValueDescription
1The number of permission groups in the category
21Unknown

The 3rd line of the category contains tab (0x09) separated type indicators. For more information see the sections below.

The remaining lines in the category consist of:

  • category root entry
    • zero or more permissions group entries
      • zero or more permission entries

Each entry consist of 2 lines:

Line numberValueDescription
1Number of entries
2Tab (0x09) separated values that correspond to the type indicators

The 1st line of the category root entry consists of the following 2 values:

Value numberValueDescription
10Unknown
2The number of permission groups in the category

The 1st line of the permission group entry consists of the following 2 values:

Value numberValueDescription
10Unknown
2The number of permissions in the group

The 1st line of the permission entry consists of the following 2 values:

Value numberValueDescription
10Unknown
20Unknown
Permission type indicators
Identifier numberType indicatorDescription
1pIs parent, where 1 represents if the entry is a category root or permissions group and 0 represents if the entry is a permission
2nName, which contains a string
3sSecurity identifier, which contains a string with either a Windows NT security identifier (SID) or a POSIX user (uid) or group identifier (gid) in the format " number:" such as " 99:"
4prProperty type, also see permission types
5ntaAccess mask
6ntiUnknown (Windows NT access control entry (ACE) flags?, which contains an integer with a Windows NT access control entry (ACE) flags)
7ntsUnknown (Permission?) (Removed in EnCase 6)
Permission types
ValueIdentifierDescription
(empty)Owner or category root
1Group
2Allow
 
6Other
 
10Unknown (permissions group?)
Access mask

Access mask seen in combination with property types 0, 1 and 6

ValueIdentifierDescription
(empty)Owner or category root
0x00000001[Lst Fldr/Rd Data]List folder / Read data
0x00000002[Crt Fl/W Data]Create file / Write data
 
0x00000020[Trav Fldr/X Fl]Traverse folder / Execute file

Access mask seen in combination with property type 2

[0x001200a9] [R&X] [R] [Sync]
[0x001301bf] [M] [R&X] [R] [W] [Sync]
[0x001f01ff] [FC] [M] [R&X] [R] [W] [Sync]
ValueIdentifierDescription
(empty)Owner or category root
0x00000001
0x00000002
0x00000004
0x00000008
0x00000010
0x00000020
0x00000040
0x00000080
0x00000100
 
0x00010000
0x00020000
0x00040000
0x00080000
0x00100000

Sources category

The srce category contains information about acquisition sources of the file entries.

TODO: describe what an acquisition source is in the context of EnCase.

The 1st line of the category contains the string “srce”.

The 2nd line consists of 2 values.

Value indexValueDescription
1The number of sources in the category
21Unknown

The 3rd line of the category contains tab (0x09) separated type indicators. For more information see the sections below.

The remaining lines in the category consist of:

  • category root
    • zero or more source entries

Each entry consist of 2 lines:

Line numberValueDescription
1Number of entries
2Tab (0x09) separated values that correspond to the type indicators

The 1st line of the category root entry consists of the following 2 values:

Value numberValueDescription
10Unknown
2The number of sources in the category

The 1st line of the source entry consists of the following 2 values:

Value numberValueDescription
10Unknown
20Unknown
Source type indicators
Identifier numberType indicatorDescription
1p
2n
3idIdentifier, which contains an integer identifying the source
4evEvidence number, which contains a string
5doDomain, which contains a string (introduced in EnCase 7.9)
6locLocation, which contains a string (introduced in EnCase 7.9)
7seSerial number, which contains a string (introduced in EnCase 7.9)
8mfrManufacturer, which contains a string (introduced in EnCase 7.9)
9moModel, which contains a string (introduced in EnCase 7.9)
10tbTotal bytes, which contains an integer
11loLogical offset, which contains an integer which is -1 when value is not set
12poPhysical offset, which contains an integer which is -1 when value is not set
13ahMD5 hash, which contains a string with the MD5 hash of the source
14shSHA1 hash, which contains a string with the SHA1 hash of the source (introduced in EnCase 6.19)
15guDevice GUID, which contains a string with a GUID or "0" if not set
16pguPrimary device GUID, which contains a string with a GUID or "0" if not set (introduced in EnCase 7)
17aqAcquisition date and time, which contains an integer with a POSIX timestamp
18ipIP address, which contains a string (introduced in EnCase 7.9)
19siUnknown (Static IP address?), Contains 1 if static, empty otherwise (introduced in EnCase 7.9)
20maMAC address, which contains a string without separator characters (introduced in EnCase 7.9)
21dtDrive type, which contains a single character (introduced in EnCase 7.9)

The acquisition date and time is in the form of: “1142163845”, which is a POSIX epoch timestamp and represents the date: March 12 2006, 11:44:05.

If the “ha” value contains “00000000000000000000000000000000” this means the MD5 hash is not set. The same applies for the “sha” value when it contains “0000000000000000000000000000000000000000” the SHA1 has is not set.

If the “ma” value contains “000000000000” this means the MAC address is not set.

Drive type
Character valueMeaning
fFixed drive

Subjects category

The sub category contains information about TODO

TODO: describe what a subject is in the context of EnCase.

The 1st line of the category contains the string “sub”.

The 2nd line consists of 2 values.

Value indexValueDescription
1The number of subjects in the category
21Unknown

The 3rd line of the category contains tab (0x09) separated type indicators. For more information see the sections below.

The remaining lines in the category consist of:

  • category root
    • zero or more subject entries

Each entry consist of 2 lines:

Line numberValueDescription
1Number of entries
2Tab (0x09) separated values that correspond to the type indicators

The 1st line of the category root entry consists of the following 2 values:

Value numberValueDescription
10Unknown
2The number of subject in the category

The 1st line of the subject entry consists of the following 2 values:

Value numberValueDescription
10Unknown
20Unknown
Subject type indicators
Identifier numberType indicatorDescription
1p
2n
3idIdentifier, which contains an integer identifying the subject
4nuUnknown (Number)
5coUnknown (Comment)
6guUnknown (GUID)

File entries category

The entry category contains information about the file entries.

The 1st line of the category contains the string “entry”.

The 2nd line consists of 2 values.

Value indexValueDescription
1The number of file entries in the category or 1 if unknown
21Unknown

The 3rd line of the category contains tab (0x09) separated type indicators. For more information see the sections below.

The remaining lines in the category consist of:

  • category root
    • zero or more file entries
      • zero or more sub file entries

Each entry consist of 2 lines:

Line numberValueDescription
1Number of entries
2Tab (0x09) separated values that correspond to the type indicators

The 1st line of the category root entry consists of the following 2 values:

Value numberValueDescription
10 if not set or 26 if Unknown
2The number of file entries in the category

The 1st line of the file entry consists of the following 2 values:

Value numberValueDescription
1Number of file entries in the parent file entry or 0 if not set
2The number of sub file entries in the file entry
EnCase 5 and 6 (EWF-L01) file entry type indicators
Identifier numberCharacter in 29th lineMeaning
1pIs parent, where 1 => if the entry is a directory and (empty) => if the entry is a file
2nName
3idIdentifier, contains an integer identifying the file entry
4oprFile entry flags
5srcSource identifier, which contains an integer that corresponds to an identifier in the Sources category
6subSubject identifier, which contains an integer that corresponds to an identifier in the Subjects category
7cidUnknown (record type)
8jqUnknown
9crCreation date and time
10acAccess date and time, for which currently is assumed the precision is date only
11wr(File) modification (last written) date and time
12mo(File system) entry modification date and time
13dlDeletion date and time
14aqAcquisition date and time, which contains an integer with a POSIX timestamp
15haMD5 hash, which contains a string with the MD5 hash of the file data
16lsFile size in bytes. If the file size is 0 the data size should be 1
17duDuplicate data offset, relative from the start of the media data
18loLogical offset, which contains an integer which is -1 when value is not set
19poPhysical offset, which contains an integer which is -1 when value is not set (or does this value contain the segment file in which the start of the data is stored, -1 for a single segment file?)
20midGUID, which contains a string with a GUID (introduced in EnCase 6.19)
21cfiUnknown (introduced in EnCase 6.14)
22beBinary extents
23pmPermissions group index, which contains an integer that corresponds to an identifier in the Permissions category or -1 if not set. The value is 0 by default
24lptUnknown (introduced in EnCase 6.19)

The creation, access and last written date and time are in the form of: “1142163845”, which is a POSIX epoch timestamp and represents the date: March 12 2006, 11:44:05.

The “ha” value (Hash) consist of a MD5 hash string when file entries are hashed. If the “ha” value contains “00000000000000000000000000000000” this means the MD5 hash is not set.

Ltree file entries

The ltree entries of files and directories consist of entries starting with: 0 followed by the number of sub file entries.

The entries of files and directories:

Line numberValueDescription
1(empty)The root directory
2The target drive/mount point
3The actual single file entries
EnCase 7 (EWF-L01) file entry type indicators
Identifier numberCharacter in 29th lineMeaning
1midGUID, which contains a string with a GUID
2lsFile size, in bytes. If the file size is 0 the data size should be 1
3beBinary extents
4idIdentifier, which contains an integer identifying the file entry
5crCreation date and time
6acAccess date and time
7wr(File) modification (last written) date and time
8mo(File system) entry modification date and time
9dlDeletion date and time
10sigUnknown (Introduced in EnCase 7)
11haMD5 hash, which contains a string with the MD5 hash of the file data
12shaSHA1 hash, which contains a string with the SHA1 hash of the file data. (Introduced in EnCase 7)
13entUnknown, seen "B" (Introduced in EnCase 7.9)
14snhShort name (or DOS 8.3 name) (Introduced in EnCase 7.9)
15pIs parent, where "1" represents that the entry is a directory and "" (an empty string) that the entry is a file
16nName
17duDuplicate data offset, relative from the start of the media data
18loLogical offset, which contains an integer which is -1 when value is not set
19poPhysical offset, which contains an integer which is -1 when value is not set (or does this value contain the segment file in which the start of the data is stored, -1 for a single segment file?)
20pmPermissions group index, which contains an integer that corresponds to an identifier in the Permissions category or -1 if not set. The value is 0 by default
21oesUnknown (Original extents?) (Introduced in EnCase 7)
22oprFile entry flags
23srcSource identifier, which contains an integer that corresponds to an identifier in the Sources category
24subSubject identifier, which contains an integer that corresponds to an identifier in the Subjects category
25cidUnknown (record type?)
26jqUnknown
27altUnknown (Introduced in EnCase 7)
28epUnknown (Introduced in EnCase 7)
29aqAcquisition date and time, which contains an integer with a POSIX timestamp
30cfiUnknown
31sgUnknown (Introduced in EnCase 7)
32eaExtended attributes (Introduced in EnCase 7.9)
33lptUnknown

If the “ha” value contains “00000000000000000000000000000000” this means the MD5 hash is not set. The same applies for the “sha” value when it contains “0000000000000000000000000000000000000000” the SHA1 has is not set.

File entry name

A file entry name (“n” value):

  • can contain path segment separator characters like “\” and “/”
  • uses the “MIDDLE DOT” Unicode character (U+00b7) as a (NTFS) alternative data stream (ADS) name seperator

Note that a regular “MIDDLE DOT” Unicode character will be encoded in the same way so no real way to reliably tell the difference.

An empty name has been observed to be represented as “NoName”.

Short name

The short name (“snh”) value contains 2 values:

Value numberValueDescription
1The number of characters in the short name including the end-of-string character
2The short name string, without an end-of-string character

For example: “13 FILE10~1.TXT”

Original extents

TODO: add some text

1 30a555b 30a6000 12011ae00 9008d7 3f 43 1 12011ae00 30a6000 120113 30a6 9008d7 18530
Ltree file entries

The ltree entries of files and directories consist of entries starting with: 26 followed by the number of sub file entries.

The entries of files and directories:

Line numberValueDescription
1LogicalEntriesThe root directory
2The target drive/mount point
3The actual single file entries
File entry flags
ValueIdentifierDescription
0x00000001Unknown (Is read-only?)
0x00000002HiddenIs hidden
0x00000004SystemIs system
0x00000008ArchiveIs archive
0x00000010Sym LinkIs symbolic link, junction or reparse point
0x00000080DeletedIs deleted
0x00001000Hard LinkedIs hard link
0x00002000StreamIs stream
0x00100000InternalIs internal (used in combination with 0x00000006?)
0x00200000Unallocated ClustersUnknown
0x00400000Unknown
0x01000000Unknown
0x02000000FolderIs folder
0x04000000Data is sparse

If 0x00002000 or 0x02000000 are not set the file entry is of type “File”.

If the sparse data flag is set:

  • the data size should be 1 and data should consist of a single byte value.
  • the data size should be equal to the file size and data should be the same.

If the duplicate data offset value is not set the single byte value in the data should be used to reconstruct the file data. E.g. if the file size is 4096 and the data contains the byte value 0x00 the resulting file should consists of 4096 0-byte values.

If the duplicate data offset value is set the single byte in the data is ignored and the duplicate data offset refers to the location where the data stored.

Binary extents value

The binary extents value contains 3 values separated by a space:

Unknown Offset Size

Where:

  • unknown always is 1, could this be the number of extents?
  • extent data offset, relative from the start of the media data
  • extent data size

The offset and size are specified in hexadecimal values.

Note that the binary extents value contains only 1 value for the first single file entry.

Extended attributes value

The extended attributes value contains base-16 encoded data, which consists of:

  • Extended attributes header (stored as an extended attribute)
  • One or more extended attributes
Extended attributes header

The extended attributes header is 37 bytes in size and consists of:

OffsetSizeValueDescription
040Unknown (0 => root, 1 => otherwise)
411Unknown (0 => is leaf node, 1 => is branch node?)
5411Number of characters in name string including the end-of-string character
941Number of characters in value string including the end-of-string character
1322"Attributes\0"Name string, which contains an UTF-16 little-endian encoded string including end-of-string character
352"\0"Value string, which contains an UTF-16 little-endian encoded string including end-of-string character
Extended attribute

An extended attributes is of variable size and consists of:

OffsetSizeValueDescription
04Unknown (0 => root, 1 => otherwise)
41Unknown (0 => is leaf node, 1 => is branch node?)
54Number of characters in name string including the end-of-string character
94Number of characters in value string including the end-of-string character
13...Name string, which contains an UTF-16 little-endian encoded string including end-of-string character
......Value string, which contains an UTF-16 little-endian encoded string including end-of-string character

TODO: complete section

Note that branch nodes are presuably used to group attributes, however these are not used consistently and are not shown by EnCase 7.

Map section

Some aspects of this section are:

  • Found in EWF-L01 in of EnCase 7 (First seen in EnCase 7.4.1.10)
  • Found in the last segment file after data section before done section.

The map consists of:

  • map string
  • map entries array

Map string

The map string consists of an UTF-16 little-endian encoded string without the UTF-16 endian byte order mark.

The map string contains the following information:

Line numberValueDescription
11The number of categories provided
2rProbably the type of information provided
3cIdentifier for the values in the 4th line
4The data for the different identifiers in the 3rd line
5(an empty line)
Map string values
Identifier numberCharacter in 29th lineMeaning
1CNumber of map entries (count)

The number of map entries should match the number of file entries in the ltree.

Map entry

A map entry is 24 bytes in size and consists of:

OffsetSizeValueDescription
04Unknown
44Unknown (empty values or part of previous value)
816Unknown

Session section

The session section is identifier in the section data type field as “session”. Some aspects of this section are:

  • Not defined in “ASR Data - E01 Compression Format”.
  • It is not found in SMART (EWF-S01) and FTK Imager (EWF-E01).
  • It is found in EnCase 5 and 6 (EWF-E01) files.
  • It is only added to the last segment file for images of optical disc (CD/DVD/BD) media.
  • It is found after the data section and before the error2 section.

The session section data consists of:

  • The session header
  • The session entries array
  • The session footer

Session header

The session header is 36 byte in size and consists of:

OffsetSizeValueDescription
04Number of sessions
428Unknown (empty values)
324Checksum, which contains an Adler-32 of all the previous data within the additional session section data

Session entry

A session entry is 32 byte in size and consists of:

OffsetSizeValueDescription
04Flags
44Start sector
824Unknown (empty values)

EnCase stores audio tracks as 0 byte data with a sector size of 2048.

Note that for a CD the first session sector is stored as 16, although the actual session starts at sector 0. Could this value be overloaded to indicate the size of the reserved space between the start of the session and the ISO 9660 volume descriptor.

Session flags

ValueIdentifierDescription
0x00000001If set the track is an audio track otherwise the track is a data track

The session footer is 4 byte in size and consists of:

OffsetSizeValueDescription
04Checksum, which contains an Adler-32 of all the data within the session entries array

Error2 section

The error2 section is identifier in the section data type field as “error2”. Some aspects of this section are:

  • Not defined in “ASR Data - E01 Compression Format”.
  • It is not found in SMART (EWF-S01).
  • It is found in, EnCase 3 to 7 and linen 5 to 7 (EWF-E01) files.
  • It is only added to the last segment file when errors were encountered while reading the input.

TODO: check FTK Imager, EnCase 1 and 2 for presence of the error2 section.

It contains the sectors that have read errors. The sector where a read error occurred are filled with zero’s during acquiry by EnCase.

The error2 section data consists of:

  • The error2 header
  • The error2 entries array
  • The error2 footer

Error2 header

The error2 header is 520 byte in size and consists of:

OffsetSizeValueDescription
04Number of entries
4512Unknown (empty values)
5164Checksum, which contains an Adler-32 of all the previous data within the error2 header data

Error2 entry

An error2 entry is 8 byte in size and consists of:

OffsetSizeValueDescription
04Start sector
44The number of sectors

The error2 footer is 4 byte in size and consists of:

OffsetSizeValueDescription
04Checksum, which contains an Adler-32 of all the data within the error2 entries array

Digest section

The digest section is identified in the section data type field as “digest”. Some aspects of this section are:

  • It is found in EnCase 6 to 7 files, as of EnCase 6.12 and linen 6.12 (EWF-E01).

The digest section contains a MD5 and/or SHA1 hash of the data within the chunks.

The digest section data is 80 byte in size and consists of:

OffsetSizeValueDescription
016MD5 hash of the media data
1620SHA1 hash of the media data
36400x00Unknown (Padding)
764Checksum, which contains an Adler-32 of all the previous data within the digest section data

Hash section

The hash section is identified in the section data type field as “hash”. Some aspects of this section are:

  • Defined in “ASR Data - E01 Compression Format”.
  • It is found in SMART (EWF-S01) and FTK Imager, EnCase 1 to 7 and linen 5 to 7 (EWF-E01) files.
  • It is not found in EnCase 5 (EWF-L01).
  • The hash section is optional, it does not need to be present. If it does it resides in the last segment file before the done section.

The hash section contains a MD5 hash of the data within the chunks.

The hash section data is 36 byte in size and consists of:

OffsetSizeValueDescription
016MD5 hash of the media data
1616Unknown
324Checksum, which contains an Adler-32 of all the previous data within the additional hash section data

Notes

Observations regarding the unknown value:

  • is zero in SMART
  • is zero in EnCase 3 and below
  • in EnCase 4 the first 4 bytes are 0, the next 8 bytes seem random, the last 4 bytes seem fixed
  • in EnCase 5 and 6 the first 8 bytes seem random, the last 8 bytes equal the file header signature
  • in linen 5 the first and last set of 4 bytes seem the same, the second set of 4 bytes seem to be random, the third set of 4 bytes seem to contain a piece of the file header signature
  • in linen 6 the first and third set of 4 bytes seem random, the second and last set of 4 bytes seem to be the same
  • EnCase5 seems to contain a GUID of the acquired device?

Test with EnCase 4 show that:

  • The value does not equal the checksum of the media data
  • Does not differentiate for the same media acquired within the same program session, using different formats, but differ for different media and different program sessions

Done section

The done section is identified in the section data type field as “done”. Some aspects of this section are:

  • Defined in “ASR Data - E01 Compression Format”.
  • It is found in SMART (EWF-S01), FTK Imager, EnCase 1 to 7 and linen 5 to 7 (EWF-E01) and EnCase 5 (EWF-L01) files.
  • The done section is the last section within the last segment file.
  • The offset to the next section in the section header of the done section point to itself (the start of the done section).
  • It should be the last section in the last segment file.

SMART (EWF-S01)

It resides after the table or table2 section.

FTK Imager, EnCase and linen (EWF-E01)

It resides after the data section in a single segment file or for multiple segment files after the table2 section.

In the EnCase (EWF-E01) format the size in the section header is 0 instead of 76 (the size of the section header).

Note that FTK imager versions before 2.9 sets the section size to 76. At the moment it is unknown in which version this behavior was changed.

Incomplete section

The incomplete section is identified in the section data type field as “incomplete”.

This section is seen rarely. It was seen in an EnCase 6.13 (EWF-E01) file as the last last section within the last segment file. The incomplete section was preceded by a hash and digest section, although later in the set of EWF files another hash and digest section were defined.

It is currently assumed that the incomplete section indicates an incomplete image created using remote imaging. The incomplete section contains data but currently there is no indication what purpose the data has.

EWF-X

EWF-X (extended) is an experimental format to enhance the EWF format. EWF-X is based on the EWF-E01 format. EWF-X does not limit the table entries to 16375. EWF-X is not the same as version 2 of EWF.

TODO: add note about the table entry limit.

Sections

Additional sections provided in the EWF-X format are:

  • xheader
  • xhash

Xheader

The xheader section contains zlib compressed data containing XML data containing the header values.

<?xml version="1.0" encoding="UTF-8"?>
<xheader>
    <case_number>1</case_number>
    <description>Description</description>
    <examiner_name>John D.</examiner_name>
    <evidence_number>1.1</evidence_number>
    <notes>Just a floppy in my system</notes>
    <acquiry_operating_system>Linux</acquiry_operating_system>
    <acquiry_date>Sat Jan 20 18:32:08 2007 CET</acquiry_date>
    <acquiry_software>ewfacquire</acquiry_software>
    <acquiry_software_version>20070120</acquiry_software_version>
</xheader>

Xhash

The xhash section contains zlib compressed data containing XML data containing the hash values.

<?xml version="1.0" encoding="UTF-8"?>
<xhash>
    <md5>ae1ce8f5ac079d3ee93f97fe3792bda3</md5>
    <sha1>31a58f090460b92220d724b28eeb2838a1df6184</sha1>
</xhash>

GUID

EWF-X uses a random based version of the GUID

Format edge cases and corruption scenarios

This chapter contains several corruption scenarios that have been encountered “in the wild”.

Corrupt uncompressed chunk

TODO: add description

Corrupt compressed chunk

TODO: add description

DEFLATE uncompressed block data with copy of uncompressed data size of 0

Seen in combination with some firmware versions of Tableau TD3 forensic imager.

In this corruption scenarion the copy of uncompressed data size value of the DEFLATE uncompressed block data is set to 0 instead of the 1s complement of the uncompressed data size.

Keramics currently does not handle this corruption scenario.

Corrupt section header

TODO: add description

reading section header from file IO pool entry: 1 at offset: 415912423
type                      : table2
next offset               : 415978027
size                      : 65604
checksum                  : 0xf35f03e0
number of offsets         : 16375
base offset               : 0x00000000
checksum                  : 0x180d0137

reading section header from file IO pool entry: 1 at offset: 415978027
type                      : sectors
next offset               : 415978027
size                      : 0
checksum                  : 0x1ad00464

Corrupt table section

TODO: add description

Scenarios:

  • with and with out table 2
  • corruption in number of entries
  • corruption in entry data

Corrupted segment file header

TODO: add description

Partial segment file

TODO: add description

Missing segment file(s)

TODO: add description

Dual image: section size versus offset

The section headers define both the next section offset and the size of the section. If an implementation reads only one of the two to determine the next section, a dual EWF image can be crafted that consists of two separate images including hashes.

Keramics will mark such an image as corrupted.

Table entries offset overflow

In EnCase 6.7.1 the sectors section can be larger than 2048 MiB. The table entries offsets are 31 bit values in EnCase6 the offset in a table entry value will actually use the full 32 bit if the 2048 MiB has been exceeded. This behavior is no longer present in EnCase 6.8 so it is assumed to be a bug.

Keramics currently assumes that the if the 31 bit value overflows the following chunks are uncompressed. This allows EnCase 6.7.1 faulty EWF files to be converted by Keramics.

Multiple incomplete segment file set identifiers

Although rare it can occur that a set of EWF image files changes its segment file set identifier. This was seen in an image created by EnCase 6.13, presumably using remote imaging. The image contained 3 different segment file set identifiers. The first changes after an incomplete section. The second one changed without any clear indication. The corresponding data section also changed in some extent e.g. compression method and media flags, the is physical flag being dropped. The change was consistent across multiple segment files. It is unlikely that deliberate manipulation is involved. EnCase considers the image as invalid.

Although with some tweaking of the individual segment file sets could be read. In this case the data read from the segment file sets was heavily corrupted. For now Keramics does not support reading multiple segment files sets from a single image, but this might change in the future.

AD encryption

As of version 2.8 FTK Imager supports “AD encryption”. Although the output file uses the EWF extensions the file actually is a AES-256 encrypted container. The EWF can be encrypted using a passphrase or a certificate.

TODO: link to format definition

References

Expert Witness Compression Format version 2 (EWF2)

TODO: add description

Mac OS Encrypted Encoding

Mac OS uses encrypted encoding (CEncryptedEncoding) to encrypt various formats, such as:

Overview

There are 2 known versions of Encrypted Encoding.

Encrypted Encoding version 1

A version 1 encrypted container consist of:

Format version 1 supports the following key protectors:

  • Passphrase

Encrypted Encoding version 2

A version 2 encrypted container consist of:

  • Encrypted container header at the start of the file
  • Key protectors
  • Unknown (empty values), probably reserved for the key protectors
  • Encrypted data, typically at offset 122368

Version 2 supports the following key protectors:

  • Passphrase
  • Public key
  • Unknown (keybag)

Characteristics

CharacteristicsDescription
Byte orderbig-endian
Date and time valuesN/A
Character stringsN/A

Encrypted container

The encrypted container footer is 1276 bytes in size and consists of:

OffsetSizeValueDescription
016Container identifier (UUID), used in Mac OS keychain as account identifier
164Block size, in number of bytes
204Key protector encryption method
244Key protector padding type
284Key protector encryption mode
324Key protector key size, in number of bits
364Key protector initialization vector size
404Key derivation method
444Unknown
484Key derivation number of iterations
524Key derivation salt size, in number of bytes
5632Key derivation salt
884Block initialization vector size
924Block encryption mode
964Block encryption method
1004Block key size, in number of bits
10432Unknown (Wrapped block (or master) data encryption key (DEK) initialization vector?)
1364Wrapped block (or master) data encryption key (DEK) size
140256Wrapped block (or master) data encryption key (DEK)
3964HMAC method
4004HMAC key size, in number of bits
40432Unknown (Wrapped block HMAC initialization vector?)
4364Wrapped block HMAC key size
440256Wrapped block HMAC key
6964Integrity encryption method
7004Integrity key size, in number of bits
70432Unknown (Wrapped integrity key initialization vector?)
7364Wrapped integrity key size
740256Wrapped integrity key
9964Unknown (data size)
1000256Unknown (data)
12564Data fork offset, where the offset is relative from the start of the container
12604Data fork size, in number of bytes
126441Encrypted Encoding format version
12688"cdsaencr"Signature

Note that “cdsaencr” presumably is short for Common Data Security Architecture (CDSA) encryption. Common Security Services Manager (CSSM) is part of CDSA.

Key data can be obtained from the wrapped key data using the following approach (presumably based on RFC 3537):

  • Use the specified key derivation method, e.g. PDBKDF2, with salt and number of iterations to determine the key encryption key (KEK) based on a passphrase.
  • Pad the initialization vector [0x4a, 0xdd, 0xa2, 0x2c, 0x79, 0xe8, 0x21, 0x05] with 0-byte values if necessesary, e.g. if initialization vector is 8 bytes but the encryption method (AES) requires an initialization vector of 16 bytes.
  • Decrypt the wrapped key data using the encryption method and mode, e.g. DES3-CBC, with the number of bits of the KEK (defined by encryption key size) and the initialization vector if applicable.
  • Remove the padding, specified by the padding type.
  • Reverse the resulting intermediate key data.

The intermediate key data is of variable size and consists of:

OffsetSizeValueDescription
08Initialization vector
8...Wrapped key data
  • Pad the initialization vector of the intermediate key data with 0-byte values if necessesary.
  • Decrypt the wrapped key data (of the intermediate key data) using the encryption method and mode, e.g. DES3-CBC, with the number of bits of the KEK (defined by encryption key size) and the initialization vector (of the intermediate key data) if applicable.
  • Remove the padding, specified by the padding type.

The decypted key data is of variable size and consists of:

OffsetSizeValueDescription
040Signature
4...Key data

Encrypted container header

The encrypted container header is of variable size and consists of:

OffsetSizeValueDescription
08"encrcdsa"Signature
842Encrypted Encrypted Encoding format version
124Block initialization vector size, in number of bytes
164Block encryption mode
204Block encryption method
244Block key size, in number of bits
284HMAC method
324HMAC key size, in number of bits
3616Container identifier (UUID), used in Mac OS keychain as account identifier
524Block size, in number of bytes
568Data fork size, in number of bytes
648Data fork offset, where the offset is relative from the start of the container
724Number of key protector descriptors
76...Array of key protector descriptors

Key protector descriptor

The key protector descriptor is 20 bytes in size and consists of:

OffsetSizeValueDescription
04Unlock type
48Data offset, where the offset is relative from the start of the container
128Data size

Unlock types

ValueIdentifierDescription
1CSSM_APPLE_UNLOCK_TYPE_KEY_DIRECTMaster key wrapped by passphrase, stored as passphrase wrapped key
2CSSM_APPLE_UNLOCK_TYPE_WRAPPED_PRIVATEMaster key wrapped by a public key, stored as public key wrapped key
3CSSM_APPLE_UNLOCK_TYPE_KEYBAGMaster key wrapped by keybag

Passphrase wrapped key

The passphrase wrapped key is 616 bytes in size and consists of:

OffsetSizeValueDescription
04Key derivation method
48Key derivation number of iterations
124Key derivation salt size, in number of bytes
1632Key derivation salt
484Encryption initialization vector size, in number of bytes
5232Encryption initialization vector
844Encryption key size, in number of bits
884Encryption method
924Padding type
964Encryption mode
1004Wrapped key data size
10464Wrapped key data
168448Unknown (empty values)

Key data can be obtained from the wrapped key data using the following approach:

  • Use the specified key derivation method, e.g. PDBKDF2, with salt and number of iterations to determine the key encryption key (KEK) based on a passphrase.
  • Pad the initialization vector with 0-byte values if necessesary, e.g. if initialization vector is 8 bytes but the encryption method (AES) requires an initialization vector of 16 bytes.
  • Decrypt the wrapped key data using the encryption method and mode, e.g. DES3-CBC, with the number of bits of the KEK (defined by encryption key size) and the initialization vector if applicable.
  • Remove the padding, specified by the padding type.

The decypted key data is of variable size and consists of:

OffsetSizeValueDescription
0...Block (or master) data encryption key (DEK)
......Block HMAC key
...5"CKIE\x00"Signature

Public key wrapped key

TODO: complete section

The public key wrapped key is 564 bytes in size and consists of:

OffsetSizeValueDescription
04Public key hash size
420Public key hash
244Unknown
284Unknown
324Unknown
364Unknown (encryption method?)
404Unknown
444Unknown
484Unknown (size)
52256Unknown
308256Unknown (empty values)

Keybag wrapped key

TODO: complete section

Algorithm identifiers

ValueIdentifierDescription
0CSSM_ALGID_NONENo algorithm (none)
1CSSM_ALGID_CUSTOMCustom algorithm
2CSSM_ALGID_DHDiffie Hellman key exchange
3CSSM_ALGID_PHPohlig Hellman key exchange
4CSSM_ALGID_KEAKey Exchange Algorithm
5CSSM_ALGID_MD2MD2
6CSSM_ALGID_MD4MD4
7CSSM_ALGID_MD5MD5
8CSSM_ALGID_SHA1SHA-1
9CSSM_ALGID_NHASHN-Hash
10CSSM_ALGID_HAVALHAVAL
11CSSM_ALGID_RIPEMDRIPE-MD
12CSSM_ALGID_IBCHASHIBC-Hash
13CSSM_ALGID_RIPEMACRIPE-MAC
14CSSM_ALGID_DESDES
15CSSM_ALGID_DESXDESX
16CSSM_ALGID_RDESRDES
17CSSM_ALGID_3DES_3KEY_EDE (or CSSM_ALGID_3DES_3KEY)Triple-DES with 3 keys applied encrypt, decrypt, encrypt (EDE)
18CSSM_ALGID_3DES_2KEY_EDE (or CSSM_ALGID_3DES_2KEY)Triple-DES with 2 keys applied encrypt, decrypt, encrypt (EDE), with the first key used for the first and last operation
19CSSM_ALGID_3DES_1KEY_EEETriple-DES with 1 keys applied encrypt, encrypt, encrypt (EEE), with the first key used for all operation
20CSSM_ALGID_3DES_3KEY_EEETriple-DES with 3 keys applied encrypt, encrypt, encrypt (EEE)
21CSSM_ALGID_3DES_2KEY_EEETriple-DES with 2 keys applied encrypt, encrypt, encrypt (EEE), with the first key used for the first and last operation
22CSSM_ALGID_IDEAIDEA
23CSSM_ALGID_RC2RC2
24CSSM_ALGID_RC5RC5
25CSSM_ALGID_RC4RC4
26CSSM_ALGID_SEALSEAL
27CSSM_ALGID_CASTCAST
28CSSM_ALGID_BLOWFISHBlowfish
29CSSM_ALGID_SKIPJACKSkipjac
30CSSM_ALGID_LUCIFERLucifer
31CSSM_ALGID_MADRYGAMadryga
32CSSM_ALGID_FEALFEAL
33CSSM_ALGID_REDOCREDOC 2
34CSSM_ALGID_REDOC3REDOC 3
35CSSM_ALGID_LOKILOKI
36CSSM_ALGID_KHUFUKHUFU
37CSSM_ALGID_KHAFREKHAFRE
38CSSM_ALGID_MMBMMB
39CSSM_ALGID_GOSTGOST
40CSSM_ALGID_SAFERSAFER (K-40, K-64, K-128)
41CSSM_ALGID_CRABCRAB
42CSSM_ALGID_RSARSA
43CSSM_ALGID_DSADSA
44CSSM_ALGID_MD5WithRSAMD5/RSA
45CSSM_ALGID_MD2WithRSAMD2/RSA
46CSSM_ALGID_ElGamalElGamal
47CSSM_ALGID_MD2RandomMD2-based random numbers
48CSSM_ALGID_MD5RandomMD5-based random numbers
49CSSM_ALGID_SHARandomSHA-based random numbers
50CSSM_ALGID_DESRandomDES-based random numbers
51CSSM_ALGID_SHA1WithRSASHA-1/RSA
52CSSM_ALGID_CDMFCDMF
53CSSM_ALGID_CAST3CAST3
54CSSM_ALGID_CAST5CAST5
55CSSM_ALGID_GenericSecretGeneric secret
56CSSM_ALGID_ConcatBaseAndKeyConcatenate base key with key
57CSSM_ALGID_ConcatKeyAndBaseConcatenate key with base key
58CSSM_ALGID_ConcatBaseAndDataConcatenate base key with data
59CSSM_ALGID_ConcatDataAndBaseConcatenate data with base key
60CSSM_ALGID_XORBaseAndDataXOR base key with data
61CSSM_ALGID_ExtractFromKeyExtract key from base key
62CSSM_ALGID_SSL3PreMasterGenSSL 3 with 48 byte pre-master key
63CSSM_ALGID_SSL3MasterDeriveDerive an SSL 3 key from a pre-master key
64CSSM_ALGID_SSL3KeyAndMacDeriveDerive SSL3 key and MAC
65CSSM_ALGID_SSL3MD5_MACSSL 3 with MD5 MAC
66CSSM_ALGID_SSL3SHA1_MACSSL 3 with SHA-1 MAC
67CSSM_ALGID_PKCS5_PBKDF1_MD5PKCS5 key derivation using PBKDF1 with MD5
68CSSM_ALGID_PKCS5_PBKDF1_MD2PKCS5 key derivation using PBKDF1 with MD2
69CSSM_ALGID_PKCS5_PBKDF1_SHA1PKCS5 key derivation using PBKDF1 with SHA-1
70CSSM_ALGID_WrapLynksSpyrus LYNKS DES based wrapping scheme with checksum
71CSSM_ALGID_WrapSET_OAEPSET key wrapping
72CSSM_ALGID_BATONFortezza BATON
73CSSM_ALGID_ECDSAElliptic Curve DSA
74CSSM_ALGID_MAYFLYFortezza MAYFLY
75CSSM_ALGID_JUNIPERFortezza JUNIPER
76CSSM_ALGID_FASTHASHFortezza FASTHASH
77CSSM_ALGID_3DESGenerix 3DES
78CSSM_ALGID_SSL3MD5SSL 3 with MD5
79CSSM_ALGID_SSL3SHA1SSL 3 with SHA-1
80CSSM_ALGID_FortezzaTimestampFortezza with timestamp
81CSSM_ALGID_SHA1WithDSASHA-1 with DSA
82CSSM_ALGID_SHA1WithECDSASHA-1 with Elliptic Curve DSA
83CSSM_ALGID_DSA_BSAFEDSA with BSAFE Key
84CSSM_ALGID_ECDHElliptic Curve DiffieHellman Key Exchange
85CSSM_ALGID_ECMQVElliptic Curve MQV key exchange
86CSSM_ALGID_PKCS12_SHA1_PBEPKCS12 SHA-1 PBE key derivation
87CSSM_ALGID_ECNRAElliptic Curve Nyberg-Rueppel
88CSSM_ALGID_SHA1WithECNRASHA-1 with Elliptic Curve Nyberg-Rueppel
89CSSM_ALGID_ECESElliptic Curve Encryption Scheme
90CSSM_ALGID_ECAESElliptic Curve Authenticate Encryption Scheme
91CSSM_ALGID_SHA1HMACSHA1-MAC
92CSSM_ALGID_FIPS186RandomFIPS186 Random
93CSSM_ALGID_ECCElliptic Curve Encryption (ECC)
94CSSM_ALGID_MQVDiscrete-Log MQV key exchange
95CSSM_ALGID_NRADiscrete-Log Nyberg-Rueppel Signature scheme
96CSSM_ALGID_IntelPlatformRandomIntel Platform Random Number Generator
97CSSM_ALGID_UTCDate and time value in the form: "YYYYMMDDhhmmss"
98CSSM_ALGID_HAVAL3HAVAL3 Digest
99CSSM_ALGID_HAVAL4HAVAL4 Digest
100CSSM_ALGID_HAVAL5HAVAL5 Digest
101CSSM_ALGID_TIGERTIGER Digest
102CSSM_ALGID_MD5HMACHMAC-MD5
103CSSM_ALGID_PKCS5_PBKDF2PKCS5 key derivation using PBKDF2 with SHA-1 (PBKDF2-HMAC-SHA1)
104CSSM_ALGID_RUNNING_COUNTERRunning hardware counter
0x80000000CSSM_ALGID_VENDOR_DEFINEDVendor defined algorithm
0x80000001CSSM_ALGID_AESAdvanced Encryption Standard (AES)

Padding types

ValueIdentifierDescription
0CSSM_PADDING_NONENo padding
1CSSM_PADDING_CUSTOMUnknown
2CSSM_PADDING_ZEROPad with 0
3CSSM_PADDING_ONEPad with 1
4CSSM_PADDING_ALTERNATEUnknown
5CSSM_PADDING_FFUnknown (Pad with 0xff?)
6CSSM_PADDING_PKCS5Pad using Public-Key Cryptography Standard (PKCS) 5 (RFC 2898)
7CSSM_PADDING_PKCS7Pad using Public-Key Cryptography Standard (PKCS) 7 (RFC 2315)
8CSSM_PADDING_CIPHERSTEALINGUnknown
9CSSM_PADDING_RANDOMUnknown
10CSSM_PADDING_PKCS1Pad using Public-Key Cryptography Standard (PKCS) 1 (RFC 2437)

Encryption modes

ValueIdentifierDescription
0CSSM_ALGMODE_NONEUnknown (Null algorithm mode)
1CSSM_ALGMODE_CUSTOMUnknown (Custom mode)
2CSSM_ALGMODE_ECBElectronic CodeBook (ECB) mode, without padding
3CSSM_ALGMODE_ECBPadElectronic CodeBook (ECB) mode with padding
4CSSM_ALGMODE_CBCCipher Block Chaining (CBC) mode, without padding
5CSSM_ALGMODE_CBC_IV8Cipher Block Chaining (CBC) mode with 8 byte initialization vector, without padding
6CSSM_ALGMODE_CBCPadIV8Cipher Block Chaining (CBC) mode with 8 byte initialization vector, with padding
7CSSM_ALGMODE_CFBCipher feedback (CFB) mode
8CSSM_ALGMODE_CFB_IV8Cipher feedback (CFB) mode with 8 byte initialization vector
9CSSM_ALGMODE_CFBPadIV8Cipher feedback (CFB) mode with 8 byte initialization vector, with padding
10CSSM_ALGMODE_OFBOutput FeedBack (OFB) mode
11CSSM_ALGMODE_OFB_IV8Output FeedBack (OFB) mode mode with 8 byte initialization vector
12CSSM_ALGMODE_OFBPadIV8Output FeedBack (OFB) mode with 8 byte initialization vector, with padding
13CSSM_ALGMODE_COUNTERCounter mode
14CSSM_ALGMODE_BCBlock Chaining mode
15CSSM_ALGMODE_PCBCPropagating Cipher Block Chaining (CBC) mode
16CSSM_ALGMODE_CBCCCipher Block Chaining (CBC) with checksum mode
17CSSM_ALGMODE_OFBNLFOutput FeedBack (OFB) with non-linear function mode
18CSSM_ALGMODE_PBCPlaintext Block Chaining (PBC) mode
19CSSM_ALGMODE_PFBPlaintext FeedBack (PFB) mode
20CSSM_ALGMODE_CBCPDCipher Block Chaining (CBC) if Plaintext Difference mode
21CSSM_ALGMODE_PUBLIC_KEYPublic key mode
22CSSM_ALGMODE_PRIVATE_KEYPrivate key mode
23CSSM_ALGMODE_SHUFFLEFortezza shuffle mode
24CSSM_ALGMODE_ECB6464 byte Electronic CodeBook (ECB) mode
25CSSM_ALGMODE_CBC6464 byte Cipher Block Chaining (CBC) mode
26CSSM_ALGMODE_OFB6464 byte Output FeedBack (OFB) mode
28CSSM_ALGMODE_CFB3232 byte Cipher feedback (CFB) mode
29CSSM_ALGMODE_CFB1616 byte Cipher feedback (CFB) mode
30CSSM_ALGMODE_CFB88 byte Cipher feedback (CFB) mode
31CSSM_ALGMODE_WRAPUnknown
32CSSM_ALGMODE_PRIVATE_WRAPUnknown
33CSSM_ALGMODE_RELAYXUnknown
34CSSM_ALGMODE_ECB128128 byte Electronic CodeBook (ECB) mode
35CSSM_ALGMODE_ECB9696 byte Electronic CodeBook (ECB) mode
36CSSM_ALGMODE_CBC128128 byte Cipher Block Chaining (CBC) mode
37CSSM_ALGMODE_OAEP_HASHUnknown (Algorithm mode for SET key wrapping?)
38CSSM_ALGMODE_PKCS1_EME_V15Public-Key Cryptography Standard (PKCS) 1 version 1.5
39CSSM_ALGMODE_PKCS1_EME_OAEPPublic-Key Cryptography Standard (PKCS) 1 version 2.0
40CSSM_ALGMODE_PKCS1_EMSA_V15Unknown
41CSSM_ALGMODE_ISO_9796Unknown
42CSSM_ALGMODE_X9_31Unknown

Encrypted block data

The encrypted block data can be decrypted using the following approach:

  • Calculate the specified block HMAC, e.g. HMAC-SHA-1, with the block HMAC key and the block number stored as a 32-bit big-endian value, where 0 represents the first block. This HMAC is used as the initialization vector for decryption.
  • Decrypt the encrypted data using the block encryption method and mode, e.g. AES-CBC, with the number of bits of the block DEK (defined by the block encryption key size) and the initialization vector if applicable.

Mac OS sparse bundle (.sparsebundle) format

The Mac OS sparse bundle (.sparsebundle) format is one of the disk image formats supported natively by Mac OS.

Mac OS referers to the sparse image format as CSparseBundleDiskImage and was introduced in Mac OS X Leopard (10.5).

Overview

A sparse bundle consists of a directory (bundle) with the .sparsbundle suffix containing:

  • “Info.bckup” file
  • “Info.plist” file
  • “token” file
  • “bands” directory containing the band files

Sparse bundles can be encrypted. For an encrypted sparse bundle:

Characteristics

CharacteristicsDescription
Byte orderN/A
Date and time valuesN/A
Character stringsN/A

Info.plist and Info.bckup files

The Info.plist and its backup (Info.bckup) contain a XML plist.

This plist is also referred to as “Information Property List” and contains a single dictionary with the following key-value pairs.

IdentifierValueDescription
CFBundleInfoDictionaryVersion"6.0"The information property list format version
band-sizeThe maximum size of a band file in bytes
bundle-backingstore-version1Unknown
diskimage-bundle-type"com.apple.diskimage.sparsebundle"The bundle type
sizeThe media size in bytes
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>CFBundleInfoDictionaryVersion</key>
    <string>6.0</string>
    <key>band-size</key>
    <integer>8388608</integer>
    <key>bundle-backingstore-version</key>
    <integer>1</integer>
    <key>diskimage-bundle-type</key>
    <string>com.apple.diskimage.sparsebundle</string>
    <key>size</key>
    <integer>4194304</integer>
</dict>
</plist>

Token file

The token file of an unencrypted sparse bundle is empty.

The token file of an encryped spase bundle contains either an Encrypted Encoding container footer or an Encrypted Encoding container header.

Bands directory

The bands directory contains files containing the actual data of the bands. The files are named using a hexadecimal naming scheme where “0” is the 1st band, “a” the 10th, “f” the 15th, “10” the 16th, etc.

Mac OS sparse image (.sparseimage) format

The Mac OS sparse image (.sparseimage) format is one of the disk image formats supported natively by Mac OS.

Mac OS referers to the sparse image format as CSparseDiskImage.

Overview

Sparse images can be encrypted. An encrypted sparse image uses a Encrypted Encoding container.

Characteristics

CharacteristicsDescription
Byte orderbig-endian
Date and time valuesN/A
Character stringsN/A

The number of bytes per sector is 512.

Image formats

Known types of sparse image files are:

  • Sparse image file
  • Encrypted sparse image file

Sparse image file

A sparse image file consists of:

  • header data
  • bands data

Encrypted Encoding version 1 encrypted sparse image file

An Encrypted Encoding version 1 encryped sparse image file consists of:

Encrypted image format version 2 encrypted sparse image file

An Encrypted Encoding version 2 encryped sparse image file consists of:

  • Encrypted Encoding container header at the start of the file
  • Key protectors
  • Unknown (empty values), probably reserved for the key protectors
  • Data fork, containing encrypted sparse image data

Header data

The header data is 4096 bytes in size and consist of:

  • file header
  • band numbers array
  • trailing data, which should be filled with 0-byte values

File header

The file header is 64 bytes in size and consist of:

OffsetSizeValueDescription
04"sprs"Signature
44Unknown (format version?), seen 3
84Number of sectors per band
124Unknown, seen 1
164The media data size in sectors
20120Unknown (0-byte values)
324Unknown
36280Unknown (0-byte values)

Band numbers array

The band numbers array consists of:

  • one or more band numbers

Band number

A band number is 4 bytes in size and consist of:

OffsetSizeValueDescription
04Band number, where 0 indicates a sparse range and any other value refers to a location in the media data

Where the corresponding media offset can be calculated as following:

media_offset = (band_number - 1) * sectors_per_band * 512

The offset of band data can be calculated as following:

band_data_offset = 4096 + (array_index * sectors_per_band * 512)

For example if the first array entry contains a band number of 4, then the band data is located at offset 4096 and the corresponding media offset is: 3 * sectors_per_band * 512.

Parallels Disk Image (PDI) format

The Parallels Disk Image format used in Parallels virtualization products as one of its image formats. It is both used the store hard disk images and snapshots.

Overview

A Parallels Disk Image consists of a directory, typically named “{NAME}.hdd” containing:

  • Descriptor file (DiskDescriptor.xml) and backup (DiskDescriptor.xml.Backup)
  • {NAME}.hdd file
  • Storage data file ({NAME}.hdd.0.{GUID}.hds)
  • {NAME}.hdd.drh

Where {NAME} is an arbitrary name and {GUID} is a unique identifier.

Disk types

The Parallels Disk Image format support multiple disk types:

IdentifierDescription
ExpandingDisk that consists of a single (dynamic size) sparse storage data file
PlainDisk that consists of a single single (fixed size) raw storage data file
SplitDisk that consists of a one or more split storage data files, either expanding or plain, holding upto 2G of data

Characteristics

CharacteristicsDescription
Byte orderlittle-endian
Character stringsUTF-8 by default, the encoding is defined in the disk descriptor XML file

The number of bytes per sector is 512.

Descriptor file

The DiskDescriptor.xml and its backup (DiskDescriptor.xml.Backup) contain the “Parallels_disk_image” XML element tha consists of the following values:

IdentifierDescription
Disk_ParametersThe disk parameters
StorageDataInformation about the storage data files
SnapshotsInformation about snapshots
<?xml version='1.0' encoding='UTF-8'?>
<Parallels_disk_image Version="1.0">
    <Disk_Parameters>
        <Disk_size>134217728</Disk_size>
        <Cylinders>262144</Cylinders>
        <PhysicalSectorSize>4096</PhysicalSectorSize>
        <LogicSectorSize>512</LogicSectorSize>
        <Heads>16</Heads>
        <Sectors>32</Sectors>
        <Padding>0</Padding>
        <Encryption>
            <Engine>{00000000-0000-0000-0000-000000000000}</Engine>
            <Data></Data>
        </Encryption>
        <UID>{GUID}</UID>
        <Name>{NAME}</Name>
        <Miscellaneous>
            <CompatLevel>level2</CompatLevel>
            <Bootable>1</Bootable>
            <ChangeState>0</ChangeState>
            <SuspendState>0</SuspendState>
        </Miscellaneous>
    </Disk_Parameters>
    <StorageData>
        <Storage>
            <Start>0</Start>
            <End>134217728</End>
            <Blocksize>2048</Blocksize>
            <Image>
                <GUID>{GUID}</GUID>
                <Type>Compressed</Type>
                <File>{NAME}.hdd.0.{GUID}.hds</File>
            </Image>
            ...
        </Storage>
        ...
    </StorageData>
    <Snapshots>
        <Shot>
            <GUID>{GUID}</GUID>
            <ParentGUID>{GUID}</ParentGUID>
        </Shot>
        ...
    </Snapshots>
</Parallels_disk_image>

Disk parameters

The disk parameters are stored in the “Disk_Parameters” XML element and contains the following values.

IdentifierDescription
CylindersNumber of cylinders
Disk_sizeDisk size, in number of sectors
Encryption"Encryption" sub XML element
HeadsNumber of heads
Miscellaneous"Miscellaneous" sub XML element
NameName of the disk
LogicSectorSizeOptional logical sector size, which is 512 bytes by default
PaddingUnknown (padding)
PhysicalSectorSizeOptional physical sector size, which is 4096 bytes by default
SectorsNumber of sectors per cylinder
UIDUnknown (identifier)

Encryption

<Encryption>
    <Engine>{00000000-0000-0000-0000-000000000000}</Engine>
    <Data></Data>
    <Salt></Salt>
</Encryption>

Miscellaneous

<Miscellaneous>
    <CompatLevel>level2</CompatLevel>
    <Bootable>1</Bootable>
    <ChangeState>0</ChangeState>
    <SuspendState>0</SuspendState>
    <DupBlocksCnt>0</DupBlocksCnt>
    <CorruptBlocksCnt>0</CorruptBlocksCnt>
    <UnrefBlocksCnt>0</UnrefBlocksCnt>
    <OutOfDiskBlocksCnt>0</OutOfDiskBlocksCnt>
    <BatOverlapBlocksCnt>0</BatOverlapBlocksCnt>
    <BlocksCnt>0</BlocksCnt>
    <TruncatedBlocksCnt>0</TruncatedBlocksCnt>
    <ReferencedBlocksCnt>0</ReferencedBlocksCnt>
    <ShutdownState>0</ShutdownState>
    <GuestToolsVersion>17.1.1-51537</GuestToolsVersion>
</Miscellaneous>
CompatLevel

Seen: level0 and level2

Storage data

The “StorageData” XML element contains the following values.

IdentifierDescription
StorageOne or more "Storage" XML sub elements

Note that a split disk contains multiple “Storage” XML sub elements.

Storage

The “Storage” XML element contains the following values.

IdentifierDescription
StartStart sector number of the segment stored in the storage data file
EndEnd sector number of the segment stored in the storage data file
BlocksizeBlock size, in number of sectors
ImageOne or more "Image" sub XML elements
Image

The “Image” XML element contains the following values.

IdentifierDescription
GUIDIdentifier of snapshot (or layer)
TypeStorage data file type
FileName (or path) of the storage data file

Snapshots data

The “Snapshots” XML element contains the following values.

IdentifierDescription
ShotOne or more "Shot" sub XML elements

Shot

The “Shot” XML element contains the following values.

IdentifierDescription
GUIDIdentifier of snapshot (or layer)
ParentGUIDIdentifier of parent snapshot (or layer), which contains "{00000000-0000-0000-0000-000000000000}" if not set

Storage data file

Storage data file types

ValueDescription
"Compressed"Sparse storage data file
"Plain"Raw storage data file

Raw storage data file

The raw (or plain) storage data file contains the disk image data including free space.

Sparse storage data file

The sparse storage data file contains the actual disk image data without free space.

A sparse storage data file consists of:

  • file header
  • block allocation table (BAT)
  • data blocks

Sparse storage data file header

The sparse storage data file header is 64 bytes in size and consists of:

OffsetSizeValueDescription
016"WithoutFreeSpace" or "WithouFreSpacExt"Signature
1642Format version
204Number of heads
244Number of cylinders
284Block size (or number of tracks) in number of sectors
324Number of blocks, which is equivalent to the number of block allocation table entries
368Number of sectors
444Unknown (Creator?), seen: "\x00\x00\x00\x00", "pd17", "pd22"
484Data start sector number, which is relative to the start of the sparse storage data file
524Unknown (Flags?)
568Unknown (Features start sector?)

Block allocation table (BAT)

The block allocation table consists of 32-bit entries. An entry contains the sector number where the data block starts is set to 0 if the block is sparse or stored in the parent disk image.

For example block allocation table entry 0 corresponds to disk image offset 0. If contains a value of 0x800 the corresponding data block is stored at file offset 0x100000 (0x800 x 512).

QEMU Copy-On-Write (QCOW) image file format

The QEMU Copy-On-Write (QCOW) image file format is used by the QEMU Open Source Process Emulator to store disk images (storage media)

Overview

A QCOW image file consists of:

  • the file header
    • optional file header extensions
  • the level 1 table (cluster block aligned)
  • the reference count table (cluster block aligned)
  • reference count blocks
  • snapshot headers (8-byte aligned on cluster block boundary)
  • cluster blocks containing:
    • level 2 tables
    • storage media data

The storage media data is stored in cluster blocks. Each cluster block is a multitude of 512 bytes. The level 1 (L1) table contains level 1 reference of level 2 (L2) tables. The level 2 tables contain level 2 references of the storage media.

There are multiple versions of the QCOW image file format. QCOW (version 1) and QCOW2 (version 2 and later) are sometimes considered even as separate image formats. Version 3 is considered as an extended version of QCOW2.

Characteristics

CharacteristicsDescription
Byte orderbig-endian in most cases, note that some values are in little-endian
Date and time valuesNumber of seconds since Jan 1, 1970 00:00:00 UTC (POSIX epoch)
Character stringsUTF-8

Note that this document assumes that character strings are stored in UTF-8.

The number of bytes per sector is 512.

Encryption

The QCOW image format can encrypted the media data stored in the image format. Currently supported encryption methods are:

  • AES-CBC 128-bit
  • Linux Unified Key Setup (LUKS)

If no encryption is used the encryption method in the file header is set to none (0).

Note it is currently unknown if the format supports compression and encryption at the same time. It does not appear to be supported by qemu-img.

AES-CBC 128-bit

Both encryption and decryption use:

  • AES-CBC with a 128-bits key decryption of sector data

The key is direct copy of the first 16 characters of a user provided (narrow character) password. If the password is smaller than 16 characters. The remaining key data is set to 0-byte values.

Note that it is currently unclear which character sets are allowed and how characters outside the 7-bit ASCII set should be handled.

The initialization vector of the AES-CBC is using media data sector number (relative to the start of the disk) in little-endian format as the first 64 bits of the 128 bit initialization vector. The remaining initialization vector data is set to 0-byte values. The first sector number is 0 and the bytes per sector are 512.

Linux Unified Key Setup (LUKS)

TODO: complete section

File header

File header – version 1

The file header - version 1 is 48 bytes in size and consist of:

OffsetSizeValueDescription
04"QFI\xfb" or "\x51\x46\x49\xfb"The signature
441Format version
88Backing file name offset
164Backing file name size
204Modification date and time, which contains a POSIX timestamp
248Storage media size
321Number of cluster block bits
331Number of level 2 table bits
342Unknown (empty values)
364Encryption method
408Level 1 table offset

The cluster block size is calculated as:

cluster_block_size = 1 << number_of_cluster_block_bits

The level 2 table size is calculated as:

level2_table_size = (1 << number_of_level2_table_bits) * 8

The level 1 table size is calculated as:

level1_table_entry_size = cluster_block_size * (1 << number_of_level2_table_bits)

level1_table_size = media_size / level1_table_entry_size
if media_size % level1_table_entry_size != 0:
    level1_table_size += 1

level1_table_size *= 8

The backing file name is set in snapshot image files and is normally stored after the file header.

File header – version 2

The file header - version 2 is 72 bytes in size and consist of:

OffsetSizeValueDescription
04"QFI\xfb" or "\x51\x46\x49\xfb"The signature
442Format version
88Backing file name offset
164Backing file name size
204Number of cluster block bits
248Storage media size
324Encryption method
364Number of level 1 table references
408Level 1 table offset
488Reference count table offset
564Reference count table clusters
604Number of snapshots
648Snapshots offset

The cluster block size is calculated as:

cluster_block_size = 1 << number_of_cluster_block_bits

The number of level 2 table bits is calculated as:

number_of_level2_table_bits = number_of_cluster_block_bits - 3

The level 2 table size is calculated as:

level_table2_size = (1 << number_of_level2_table_bits) * 8

The level 1 table size is calculated as:

level1_table_size = number_of_level1_table_references * 8

The backing file name is set in snapshot image files and is normally stored after the file header.

File header – version 3

The file header - version 3 is 104 or 112 bytes in size and consist of:

OffsetSizeValueDescription
04"QFI\xfb" or "\x51\x46\x49\xfb"The signature
443Format version
88Backing file name offset
164Backing file name size
204Number of cluster block bits
248Storage media size
324Encryption method
364Number of level 1 table references
408Level 1 table offset
488Reference count table offset
564Reference count table clusters
604Number of snapshots
648Snapshots offset
728Incompatible feature flags
808Compatible feature flags
888Auto-clear feature flags
964Reference count order
1004104 or 112File header size, which contains the size of the file header, this value does not include the size of the file header extensions
If file header size equals 112
1041Compression method
1057Unknown (padding)

The cluster block size is calculated as:

cluster_block_size = 1 << number_of_cluster_block_bits

The number of level 2 table bits is calculated as:

number_of_level2_table_bits = number_of_cluster_block_bits - 3

The level 2 table size is calculated as:

level_table2_size = (1 << number_of_level2_table_bits) * 8

The level 1 table size is calculated as:

level1_table_size = number_of_level1_table_references * 8

The backing file name is set in snapshot image files and is normally stored after the file header.

Encryption methods

ValueIdentifierDescription
0QCOW_CRYPT_NONENo encryption
1QCOW_CRYPT_AESAES-CBC 128-bits encryption
2QCOW_CRYPT_LUKSLinux Unified Key Setup (LUKS) encryption

Incompatible feature flags

ValueIdentifierDescription
0x0000000000000001QCOW2_INCOMPAT_DIRTYIs dirty (or in use)
0x0000000000000002QCOW2_INCOMPAT_CORRUPTIs corrupt
0x0000000000000004QCOW2_INCOMPAT_DATA_FILEUses data file
0x0000000000000008QCOW2_INCOMPAT_COMPRESSIONUses non-standard compression, where "standard compression" refers to zlib
0x0000000000000010QCOW2_INCOMPAT_EXTL2Has extended L2 (table) entries

Compatible feature flags

ValueIdentifierDescription
0x0000000000000001QCOW2_COMPAT_LAZY_REFCOUNTSUses lazy reference counting

Auto-clear feature flags

ValueIdentifierDescription
0x0000000000000001QCOW2_AUTOCLEAR_BITMAPS
0x0000000000000002QCOW2_AUTOCLEAR_DATA_FILE_RAW

Compression methods

ValueIdentifierDescription
0zlib compression
1zstd compression (RFC 8878)

File header extensions

A file header extension consist of:

  • file header extension header
  • file header extension data

File header extension header

The file header extension header is 8 bytes in size and consist of:

OffsetSizeValueDescription
04The extension type (signature)
44The extension data size

File header extension types

ValueIdentifierDescription
0x0537be77QCOW2_EXT_MAGIC_CRYPTO_HEADERCrypto header
0x23852875QCOW2_EXT_MAGIC_BITMAPSBitmaps
0x44415441 or "DATA"QCOW2_EXT_MAGIC_DATA_FILEData-file
0x6803f857QCOW2_EXT_MAGIC_FEATURE_TABLEFeature table
0xe2792acaQCOW2_EXT_MAGIC_BACKING_FORMATBacking format

Backing format file header extension

The backing format file header extension header is of variable size and consist of:

OffsetSizeValueDescription
0...Backing format identifier, which contains an UTF-8 string without end-of-string character

Bitmaps file header extension

TODO: complete section

Crypto header file header extension

The crypto header file header extension header is 16 bytes in size and consist of:

OffsetSizeValueDescription
08The crypto data offset
88The crypto data size

Data-file file header extension

The data-file file header extension header is of variable size and consist of:

OffsetSizeValueDescription
0...Data-file file name, which contains an UTF-8 string without end-of-string character

Feature table file header extension

TODO: complete section

Level 1 table

The level 1 table contains level 2 table references.

A reference value of 0 represents unused or unallocated and is considered as sparse or stored in a corresponding backing file.

Level 2 table reference – version 1

The level 2 table reference is 8-bytes in size and consists of:

OffsetSizeValueDescription
0.063 bitsLevel 2 table offset, which contains an offset relative from the start of the file
7.71 bitQCOW_OFLAG_COMPRESSEDIs compressed flag

Level 2 table reference – version 2 or 3

The level 2 table reference is 8-bytes in size and consists of:

OffsetSizeValueDescription
0.062 bitsLevel 2 table offset, which contains an offset relative from the start of the file
7.61 bitQCOW_OFLAG_COMPRESSEDIs compressed flag
7.71 bitQCOW_OFLAG_COPIEDIs copied flag

The is copied flag indicates that the reference count of the corresponding level 2 table is exactly one.

Level 2 table

The level 2 table contains cluster block references.

The level 2 table size is calculated as:

level2_table_size = (1 << number_of_level2_table_bits) * 8

A reference value of 0 represents unused or unallocated and is considered as sparse or stored in a corresponding backing file.

Cluster block reference – version 1

The cluster block reference - version 1 is 8-bytes in size and consists of:

OffsetSizeValueDescription
0.063 bitsCluster block offset, which contains an offset relative to the start of the cluster block
7.71 bitQCOW_OFLAG_COMPRESSEDIs compressed flag

Cluster block reference – version 2 or 3

The cluster block reference - version 2 or 3 is 8-bytes in size and consists of:

OffsetSizeValueDescription
0.062 bitsCluster block offset, which contains an offset relative to the start of the cluster block
7.61 bitQCOW_OFLAG_COMPRESSEDIs compressed flag
7.71 bitQCOW_OFLAG_COPIEDIs copied flag

The is copied flag indicates that the reference count of the corresponding cluster block is exactly one.

Reference count table

The cluster data blocks are referenced counted. For every cluster data block a 16-bit reference count is stored in the reference count table.

The reference count table is stored in cluster block sizes. The file header contains the number of blocks (or reference count table clusters).

TODO: complete section

Cluster data block

To retrieve a cluster data block corresponding a certain storage media offset:

Determine the level 1 table index from the offset:

level1_table_index_bit_shift = number_of_cluster_block_bits + number_of_level2_table_bits

For version 1:

level1_table_index = (offset & 0x7fffffffffffffff) >> level1_table_index_bit_shift

For version 2 and 3:

level1_table_index = (offset & 0x3fffffffffffffff) >> level1_table_index_bit_shift

Retrieve the level 2 table offset from the level 1 table. If the level 2 table offset is 0 and the image has a backing file the cluster data block is stored in the backing file otherwise the cluster block is considered sparse.

Read the corresponding level 2 table.

Determine the level 2 table index from the offset:

level2_table_index_bit_mask = ~(0xffffffffffffffff << number_of_level2_table_bits)
level2_table_index = (offset >> number_of_cluster_block_bits) >> level2_table_index_bit_mask

Retrieve the cluster block offset from the level 2 table. If the cluster block offset is 0 and the image has a backing file the cluster data block is stored in the backing file otherwise the cluster block is considered sparse.

Uncompressed cluster data block

If the is compressed flag (QCOW_OFLAG_COMPRESSED) is not set:

cluster_block_bit_mask = ~(0xffffffffffffffff << number_of_cluster_block_bits)
cluster_block_data_offset = (offset & cluster_block_bit_mask) + cluster_block_offset

Note that in version 2 or 3 the last cluster block in the file can be smaller than the cluster block size defined by the number of cluster block bits in the file header. This does not seem to be the case for version 1.

Compressed cluster data block

If the is compressed flag (QCOW_OFLAG_COMPRESSED) is set the cluster block data is stored using the compression method defined by the file header or DEFLATE by default.

Multiple compressed cluster data blocks are stored together in cluster block sizes. The compressed cluster data blocks are sector (512 bytes) aligned.

The compressed data uses a DEFLATE (inflate) window bits value of -12

Compressed chunk data block – version 1

compressed_size_bit_shift = 63 - number_of_cluster_block_bits
compressed_block_size = (
    (cluster_block_offset & 0x7fffffffffffffff) >> compressed_size_bit_shift)
compressed_block_offset &= ~(0xffffffffffffffff << compressed_size_bit_shift)

Compressed chunk data block – version 2 or 3

compressed_size_bit_shift = 62 - (number_of_cluster_block_bits – 8)

According to “the QCOW2 Image Format” the compressed block size is calculated as following:

compressed_block_size = (
    (((cluster_block_offset & 0x3fffffffffffffff) >> compressed_size_bit_shift) + 1) * 512)

Since the compressed block size is stored in 512 byte sectors this value does not contain the exact byte size of the compressed cluster block data. It sometimes lacks the size of the last partially filled sector and one sector should be added if possible within the bounds of the cluster blocks size and the file size.

cluster_block_offset &= ~(0xffffffffffffffff << compressed_size_bit_shift)

Snapshots

As of version 1 QCOW can use the backing file name in the file header to point to a backing file (or parent image) that contains the snapshot image where the current image only contains the modifications. Version 2 adds support to store snapshot inside the image.

Snapshot header - version 2 or 3

An in-image snapshot is created by adding a snapshot header, copying the L1 table and incrementing the reference counts of all L2 tables and data clusters referenced by the L1 table.

The snapshot header is of variable size and consists of:

OffsetSizeValueDescription
08Level 1 table offset
84Level 1 size
122Identifier string size
142Name size
164Date in seconds
204Date in nano seconds
248VM clock in nano seconds
324VM state size
364Extra data size
40...Extra data
......Identifier string size
......Name

TODO: complete section

References

Universal Disk Image Format (UDIF)

The Universal Disk Image Format (UDIF) (.dmg) is one of the disk image formats supported natively by Mac OS. UDIF supersedes the New Disk Image Format (NDIF) format and was introduced in Max OS X 10.0 (Cheetah).

Mac OS referers to the UDIF image format as CUDIFEncoding.

Overview

An UDIF image can consists of one or more segment files, where:

  • the first segment file is named: “image.dmg”
  • successive segment files are named: “image.###.dmgpart”, where “###” represents a numeric value starting with 2 with 0 padding, e.g. “image.002.dmgpart”. Segment files after 999 are assumed to be named without the 0 padding, e.g. “image.1234.dmgpart”.

The data forks of the segment files are used as a contiguous data stream. A compressed block can be stored across multiple segment files.

Only the first segment file contains a resource fork or XML plist.

Known UDIF image types are:

IdentifierDescription
UDBZbzip2 compressed UDIF
UDCOApple Data Compression (ADC) compressed UDIF
UDIFRead-write uncompressed UDIF
UDRORead-only uncompressed UDIF
UDxxUncompressed UDIF
UDZOzlib/DEFLATE compressed UDIF
ULFOLZFSE compressed UDIF
ULMOLZMA compressed UDIF

UDIF images can be encrypted. An encrypted UDIF image consists of one of more UDIF segment files, where each segment file uses a Encrypted Encoding container with its own key protectors.

Terminology

TermDescription
Flattened imageThe disk image is a self-contained, a resource fork is stored within the image
Unflattened imageThe disk image uses the file system to store a resource fork

Image formats

Known types of UDIF segment files are:

  • Uncompressed segment file
  • Compressed segment file
  • Encrypted segment file

Uncompressed segment file format

An uncompressed UDIF segment file consist of:

Note that an uncompressed UDIF image without file footer is equivalent to a RAW storage media image (CRawDiskImage).

Compressed segment file format

A compressed UDIF segment file consist of:

  • Data fork, containing the image data
  • Optional XML plist
  • Optional resource fork
  • File footer at the end of the file

Encrypted Encoding version 1 encrypted UDIF segment file

An Encrypted Encoding version 1 encryped UDIF segment file consists of:

Note that the encrypted UDIF data can contain an uncompressed UDIF image without file footer.

Encrypted Encoding version 2 encrypted UDIF segment file

An Encrypted Encoding version 2 encryped UDIF segment file consists of:

  • Encrypted Encoding container header at the start of the file
  • Key protectors
  • Unknown (empty values), probably reserved for the key protectors
  • Data fork, containing encrypted UDIF data

Note that the encrypted UDIF data can contain an uncompressed UDIF image without file footer.

Characteristics

CharacteristicsDescription
Byte orderbig-endian
Date and time valuesN/A
Character stringsN/A

The number of bytes per sector is 512.

The file footer (also known as resource file or metadata) (UDIFResourceFile) is 512 bytes in size and consists of:

OffsetSizeValueDescription
04"koly"Signature
444Format version
84512File footer size, in number of bytes
124Image flags
168Segment logical offset
248Data fork offset, where the offset is relative from the start of the image file
328Data fork size, in number of bytes
408Resource fork offset, where the offset is relative from the start of the image file
488Resource fork size, in number of bytes
564Segment number, where 1 represents the first segment and contains 0 if not set
604Number of segments, which contains 0 if not set
6416Segment set identifier, which contains an UUID
804Data checksum type
844Data checksum size, in number of bits
88128Data checksum
Introduced in Mac OS 10.2
2168XML plist offset, where the offset is relative from the start of the image file
2248XML plist size
232120Unknown (Reserved)
3524Master checksum type
3564Master checksum size, in number of bits
360128Master checksum
4884Image type (or variant)
4928Media size, in number of sectors, which contains the total number of sectors in the (uncompressed) image
5004Unknown (reserved)
5044Unknown (reserved)
5084Unknown (reserved)

In an encrypted image file the offsets are relative from the start of the unencrypted image file.

Note that both the XML plist and resource fork size can be 0, such as in an UDIF stub (UDxx) image.

Image flags

ValueIdentifierDescription
0x00000001kUDIFFlagsFlattenedFlattened image (set by hdiutil flatten/unflatten)
0x00000002kUDIFFlagsInPlace
0x00000004kUDIFFlagsInternetEnabledInternet enabled (set by hdiutil internet-enable)
0x00000008kUDIFFlagsIsEncrypted

Checksum types

ValueIdentifierDescription
2CRC-32
4MD5

Image types

ValueIdentifierDescription
1kUDIFDeviceImageTypeDevice image
2kUDIFPartitionImageTypeParitition image

Resource fork

In older UDIF images the resource fork contains the image metadata, such as the block table. The resource fork consists of:

  • Resource fork header
  • Resource data
  • Resource map

Resource fork header

The resource fork header is 16 bytes in size and consists of:

OffsetSizeValueDescription
04Resource data offset, which contains the byte offset relative to the start of the resource fork
44Resource map offset, which contains the byte offset relative to the start of the resource fork
84Resource data size, in number of bytes
124Resource map size, in number of bytes

Resource data

OffsetSizeValueDescription
04Size, in number of bytes
4...Data

Resource map

The resource map consists of:

  • Resource map header
  • Entries list
  • Names

Resource map header

The resource map header is 28 bytes in size and consists of:

OffsetSizeValueDescription
016Unknown (reserved)
164Unknown (next resource map)
202Unknown (file reference number)
222Unknown (resource file attribute flags)
242Entries list offset, which contains the byte offset relative to the start of the resource map
262Names list offset, which contains the byte offset relative to the start of the resource map

Resource map entries list

The entries (or type) list is of variable size and consists of:

OffsetSizeValueDescription
02Number of entries, stored as value - 1
2...Array of entries

Resource map entry

The resource map entry is 8 bytes in size and consists of:

OffsetSizeValueDescription
04Type indicator (or signature)
42Number of resource descriptors, stored as value - 1
62Resource descriptors offset, which contains the byte offset relative to the start of the entries list

A resource map entry is comparable to an item in the XML plist resource-fork dictionary such as the “blkx” item.

Resource descriptor

The resource descriptor (or reference list) is 12 bytes in size and consists of:

OffsetSizeValueDescription
02Resource identifier. Corresponds to the "ID" value in the XML plist.
22Resource name offset, which contains the byte offset relative to the start of the names list where 0xffff indicates the resource has no name. Corresponds to the "Name" value in the XML plist.
41Resource flags (0x20: Purgeable, 0x40: Protected). Corresponds to the "Attributes" value in the XML plist.
53Resource data offset, which contains the byte offset relative to the start of the resource data
84Unknown (reserved)

Resource name

The resource name is of variable size and consists of:

OffsetSizeValueDescription
01Name size
2...Name string, without an end-of-string character

XML plist

The XML plist contains image metadata such as the block table.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>resource-fork</key>
    <dict>
        <key>blkx</key>
        <array>
            <dict>
                <key>Attributes</key>
                <string>0x0050</string>
                <key>CFName</key>
                <string>Protective Master Boot Record (MBR : 0)</string>
                <key>Data</key>
                <data>
                bWlzaAAAAAEAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAA
                AAgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
                AAIAAAAgQfL6MwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
                AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
                AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
                AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
                AAAAAAACgAAABQAAAAMAAAAAAAAAAAAAAAAAAAABAAAA
                AAAAIA0AAAAAAAAAH/////8AAAAAAAAAAAAAAAEAAAAA
                AAAAAAAAAAAAAAAAAAAAAAAAAAA=
                </data>
                <key>ID</key>
                <string>-1</string>
                <key>Name</key>
                <string>Protective Master Boot Record (MBR : 0)</string>
            </dict>
            ...
        </array>
        <key>plst</key>
        <array>
            <dict>
                <key>Attributes</key>
                <string>0x0050</string>
                <key>Data</key>
                <data>
                AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
                AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
                AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
                AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
                AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
                AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
                AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
                AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
                AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
                AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
                AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
                AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
                AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
                AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
                AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
                AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAQAAAAAAAAAA
                AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
                AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
                AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
                AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
                AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
                AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
                AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
                AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
                AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
                AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
                AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
                AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
                AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
                AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
                AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
                AAAAAAAAAAAA
                </data>
                <key>ID</key>
                <string>0</string>
                <key>Name</key>
                <string></string>
            </dict>
        </array>
    </dict>
</dict>
</plist>

The XML plist contains the following key-value pairs:

IdentifierDescription
resource-forkdictionary

XML plist resource-fork dictionary

The resource-fork dictionary contains the following key-value pairs:

IdentifierDescription
blkxarray of dictionaries, which contains Block table (or block extents) values
LPicoptional array of dictionaries, which contains values related to license information
plstarray of dictionaries, which contains values related to image properties
STR#optional array of dictionaries, which contains values related to license information
TEXToptional array of dictionaries, which contains values related to license information

XML plist array entry

An array entry contains the following key-value pairs:

IdentifierDescription
Attributesstring that contains a hexadecimal formatted integer value
CFNamestring
Datastring that contains base-64 encoded data
IDstring that contains a decimal formatted integer value
Namestring

Note the the blkx array appears the only one that uses CFName.

Block table

The block table (BLKXTable) is of variable size and consists of:

  • block table header
  • block table entries

The block table header

The block table header is 204 bytes in size and consists of:

OffsetSizeValueDescription
04"mish"Signature
441Format version
88Start sector, which contains the sector number relative to the start of the media data
168Number of sectors
248Base data offset, which contains the byte offset relative to the start of the segment data stream
324Unknown (BuffersNeeded)
364Unknown (BlockDescriptors)
406 x 4 = 240Unknown (reserved)
644Checksum type
684Checksum size
72128Checksum
2004Number of entries

Block table entry

The block table entry (BLKXChunkEntry) is 40 bytes in size and consists of:

OffsetSizeValueDescription
04Entry type
44Unknown (comment related?)
88Start sector, which contains the sector number relative to the start of the start sector of the block table
168Number of sectors
248Data offset, which contains the byte offset relative to the base data offset in the block table header
328Data size, which contain the number of bytes of data stored, which is 0 for sparse data

UDIF block table entry types

ValueIdentifierDescription
0x00000000Unknown (sparse)
0x00000001Uncompressed (raw) data
0x00000002Sparse (used for Apple_Free)
0x7ffffffeComment
0x80000004ADC compressed data
0x80000005zlib compressed data
0x80000006bzip2 compressed data
0x80000007LZFSE compressed data
0x80000008LZMA compressed data
0xffffffffBlock table entries terminator

UDIF comment

TODO: complete section

Notes

Is the maximum compressed chunk size 2048 sectors?

Comment seems to reference compressed data but has no size or number of sectors value.

Format edge cases and corruption scenarios

Non-sequential segment files

It is currently unknown if non-sequential segment files are supported.

XML plist and resource fork both in use

The XML plist and resource fork could be used simultaneously, allowing for a single UDIF to contain multiple images.

It is currently assumed that the XML plist is leading.

XML plist and/or resource fork in non-first segment files

The XML plist and/or resource fork could be used in non-first segment files.

Virtual Hard Disk (VHD) image format

The Virtual Hard Disk (VHD) format is used by Microsoft vitualization products as one of its image formats. It is both used the store hard disk images and snapshots.

Overview

There are multiple types of VHD images, namely:

  • Fixed-size VHD image
  • Dynamic-size (or sparse) VHD image
  • Differential (or differencing) VHD image

Fixed-size hard disk image

A fixed-size VHD image consists of:

  • data
  • file footer

Note that a fixed-size VHD image is equivalent to a raw storage media image with an additional footer.

Dynamic-size (or sparse) hard disk image

A dynamic-size (or sparse) VHD image consists of:

  • copy of file footer
  • dynamic disk header
  • block allocation table
  • data in blocks
  • file footer

Differential hard disk image

A differential (or differencing) VHD image consists of:

  • copy of file footer
  • dynamic disk header
  • block allocation table
  • data in blocks
  • file footer

Characteristics

CharacteristicsDescription
Byte orderbig-endian
Date and time valuesNumber of seconds since January 1, 2000 00:00:00 UTC
Character stringsUCS-2 big-endian, which allows for unpaired Unicode surrogates such as "U+d800" and "U+dc00"

The number of bytes per sector is 512.

Undo disk image

Virtual PC has a feature to create “Undo Disks”. This undo disk feature stores a differential hard disk image in files named something similar like:

VirtualPCUndo_<name>_0_0_hhmmssMMDDYYYY.vud

Where the date and time seems to be stored in UTC and <name> represents the name of the parent image.

The file footer is 512 bytes in size and consists of:

OffsetSizeValueDescription
08"conectix"Signature (also referred to as cookie)
84Features
1240x00010000Format version, where the upper 16-bit are the major version and the lower 16-bit the minor version
168Next offset, which contains the offset to the next (metadata) structure. The offset is relative from the start of the file. It should only be set in dynamic and differential disk images. In fixed disk images it should be set to 0xffffffffffffffff (-1)
244Modification time, which contains the number of seconds since January 1, 2000 00:00:00 UTC
284Creator application
324Creator version, where the upper 16-bit are the major version and the lower 16-bit the minor version
364Creator (host) operating system
408Disk size, which contains the size of the disk in bytes
488Data size, which contains the size of the data in bytes
564Disk geometry
604Disk type
644Checksum, which contains a one's complement of the sum of the file footer excluding the checksum itself
6816Identifier, which contains a big-endian UUID
841Saved state, which contains a flag to indicate the image is in saved state
854270Unknown (Reserved should contain 0-byte values)

Features

OffsetSizeValueDescription
0.01 bitIs temporary disk, which indicates that this disk is a candidate for deletion on shutdown
0.11 bitUnknown (Reserved, must be set to 1)
0.230 bitsUnknown (Reserved, must be set to 0)

A value of 0 represents no features are enabled.

Creator application

ValueIdentifierDescription
"d2v\x00"Disk2vhd
"qemu"Qemu
"vpc\x20"Virtual PC
"vs\x20\x20"Virtual Server
"win\x20"Windows (Disk Management)

Creator host operating system

ValueIdentifierDescription
"Mac\x20"Macintosh
"Wi2k"Windows

Disk geometry

The disk geometry is 4 bytes in size and consists of:

OffsetSizeValueDescription
02Number of cylinders
21Number of heads
31Number of sectors per track (cylinder)

Disk type

ValueIdentifierDescription
0None
1Unknown (Deprecated)
2Fixed hard disk
3Dynamic hard disk
4Differential hard disk
5Unknown (Deprecated)
6Unknown (Deprecated)

Dynamic disk header

The dynamic disk header is 1024 bytes in size and consists of:

OffsetSizeValueDescription
08"cxsparse"Signature (Cookie)
88Next offset, which contains the offset to the next (metadata) structure. The offset is relative from the start of the file. Currently this is unused and should be set to 0xffffffffffffffff (-1)
168Block allocation table offset, whic contains the offset to the block allocation table structure. The offset is relative from the start of the file
2440x00010000Format version, where the upper 16-bit are the major version and the lower 16-bit the minor version
284Number of blocks, which is equivalent to the number of block allocation table entries
324Block size. The block size must be a power-of-two multitude of the sector size and does not include the size of the sector bitmap. The default block size is 4096 x 512-byte sectors (2 MiB)
364Checksum, which contains a one's complement of the sum of the dynamic disk header excluding the checksum itself
4016Parent identifier, which contains a big-endian UUID that identifies the parent image. Only used by differential hard disk images
564Parent last modification time, which contains the number of seconds since January 1, 2000 00:00:00 UTC. Only used by differential hard disk images
6040Unknown (Reserved should contain 0-byte values)
64512Parent name, which contains an UCS-2 big-endian string. Only used by differential hard disk images
5768 x 24 = 192Array of parent locator entries. Only used by differential hard disk images
7682560Unknown (Reserved should contain 0-byte values)

The maximum number of block allocation table entries should match the maximum possible number of blocks in the disk.

Note that the parent name can also contain a full path, e.g. in .avhd files. The part segments are separated by the \ character.

Parent locator entry

The parent locator entry is 24 bytes in size and consists of:

OffsetSizeValueDescription
04Locator platform code
44Platform data space, which contains the number of 512-byte sectors needed to store the parent hard disk locator
84Locator data size
1240Unknown (Reserved should contain 0-byte values)
168Locator data offset, which contains the offset to the locator data. The offset is relative from the start of the file

Locator platform code

ValueIdentifierDescription
0None
"Mac\x20"Mac OS alias stored as a blob
"MacX"File URL with UTF-8 encoding conforming to RFC 2396
"W2ku"Absolute Windows path, which contains an UCS-2 big-endian string
"W2ru"Windows path relative to the differential image, which contains an UCS-2 big-endian string
"Wi2k"Unknown (Deprecated)
"Wi2r"Unknown (Deprecated)

Block allocation table

The block allocation table is only used in dynamic and differential disk images.

The block allocation table consists of 32-bit entries. An entry contains the sector number where the data block starts or is set to 0xffffffff (-1) if the block is sparse or stored in the parent disk image.

if block_allocation_table_entry == 0xffffffff:
    block is sparse or stored in parent
else:
    file_offset = (block_allocation_table_entry * 512 ) + sector_bitmap_size

Unused block in a dynamic disk are sparse and should be filled with zero byte values. In a differential disk the block is stored in the parent disk image.

Data blocks

Data blocks are only used in dynamic and differential disk images.

A data block consists of:

  • sector bitmap
  • sector data
size_of_bitmap (in bytes) = block_size / (512 * 8)

The size of the bitmap is rounded up to the next multitude of the sector size.

Sector bitmap

In dynamic disk images the sector bitmap indicates which sectors contain data (bit set to 1) or are sparse (bit set to 0).

In differential disk images the sector bitmap indicates which sectors are stored within the image (bit set to 1) or in the parent (bit set to 0).

The bitmap is padded to a 512-byte sector boundary.

The bitmap is stored on a per-byte basis with the MSB represents the first bit in the bitmap.

References

Virtual Hard Disk version 2 (VHDX) image format

The Virtual Hard Disk version 2 (VHDX) format is used by Microsoft vitualization products as one of its image formats. It is both used the store hard disk images and snapshots.

Overview

A VHDX image file consist of:

  • file header
  • 2x image headers
  • 2x region tables
  • log or metadata journal
  • block allocation table (BAT) region
  • metadata region
    • metadata table
    • metadata items
  • image (content) data

The elements are stored in 64 KiB (65536 bytes) aligned blocks

Characteristics

CharacteristicsDescription
Byte orderlittle-endian
Date and time valuesN/A
Character stringsUCS-2 little-endian, which allows for unpaired Unicode surrogates such as "U+d800" and "U+dc00"

The number of bytes per sector is 512 or 4096 depending on the logical sector size.

File header

The file header of (file type identifier) is 64 KiB (65536 bytes) in size and consists of:

OffsetSizeValueDescription
08"vhdxfile"Signature
8512Creator application and version, with contains an UCS-2 little-endian string with end-of-string character
52065016Unknown (reserved)

Image header

The image header is 4 KiB (4096 bytes) in size and consists of:

OffsetSizeValueDescription
04"head"Signature
44Checksum
88Sequence number
1616File write identifier, which contains a GUID
3216Data write identifier, which contains a GUID
4816Log identifier, which contains a GUID
642Log format version
6621Format version
684Log size, which according to MS-VHDX this value must be a multitude of 1 MiB
728Log offset, which according to MS-VHDX this value must be a multitude of 1 MiB and greater than or equal to 1 MiB
8040160Unknown (reserved), which according to MS-VHDX this value must be set to 0

Checksum calculation

The CRC32-C algorithm with the Castagnoli polynomial (0x1edc6f41) and initial value of 0 is used to calculate the checksum.

The checksum is calculated over the 4 KiB bytes of data of the image header, where the image header checkum value is considered to be 0 during calculation.

Region table

The region table is stored in a block of 64 KiB (65536 bytes) and consists of:

  • region table header
  • 0 or more region table entries
  • Unknown (reserved)

TODO: determine if 0 entries is actually supported

Region table header

The region table header is 16 bytes in size and consists of:

OffsetSizeValueDescription
04"regi"Signature
44Checksum
84Number of table entries, which according to MS-VHDX this value must be less than or equal to 2047
1240Unknown (reserved), which according to MS-VHDX this value must be set to 0

The CRC32-C algorithm with the Castagnoli polynomial (0x1edc6f41) and initial value of 0 is used to calculate the checksum.

The checksum is calculated over the 64 KiB bytes of data of the region table where the image header checkum value is considered to be 0 during calculation.

Region table entry

The region table entry is 32 bytes in size and consists of:

OffsetSizeValueDescription
016Region type identifier, which contains a GUID
168Region data offset, which contains an offset relative to the start of the file. According to MS-VHDX this value must be a multitude of 1 MiB and greater than or equal to 1 MiB
244Region data size, which according to MS-VHDX this value must be a multitude of 1 MiB
284Is required flag, which contains 1 to indicate the region type needs to be supported

Region type identifiers

ValueIdentifierDescription
2dc27766-f623-4200-9d64-115e9bfd4a08Block allocation table (BAT) region
8b7ca206-4790-4b9a-b8fe-575f050f886eMetadata region

Metadata region

The metadata region contains:

  • metadata table
  • metadata items

Metadata table

The metadata table is stored in a block of 64 KiB (65536 bytes) and consists of:

  • metadata table header
  • 0 or more metadata table entries
  • Unknown (reserved)

TODO: determine if 0 entries is actually supported

Metadata table header

The metadata table header is 32 bytes in size and consists of:

OffsetSizeValueDescription
08"metadata"Signature
820Unknown (reserved), which according to MS-VHDX this value must be set to 0
102Number of table entries, which according to MS-VHDX this value must be less than or equal to 2047
12200Unknown (reserved), which according to MS-VHDX this value must be set to 0

Metadata table entry

The metdata table entry is 32 bytes in size and consists of:

OffsetSizeValueDescription
016Metadata item identifier, which contains a GUID
164Metadata item offset, which contains an offset relative to the start of the metadata region. According to MS-VHDX this value must be greater than 64 KiB
204Metadata item size
248Unknown

TODO: describe last 8 bytes

ValueIdentifierDescription
0x00000001IsUser
0x00000002IsVirtualDisk
0x00000004IsRequired

Metadata items

Metadata item identifiers

ValueIdentifierDescription
2fa54224-cd1b-4876-b211-5dbed83bf4b8Virtual disk size
8141bf1d-a96f-4709-ba47-f233a8faab5fLogical sector size
a8d35f2d-b30b-454d-abf7-d3d84834ab0cParent locator
beca12ab-b2e6-4523-93ef-c309e000c746Virtual disk identifier
caa16737-fa36-4d43-b3b6-33f0aa44e76bFile parameters
cda348c7-445d-4471-9cc9-e9885251c556Physical sector size

File parameters metadata item

The file parameters metadata item is 8 bytes in size and consists of:

OffsetSizeValueDescription
04Block size, which according to MS-VHDX this value must be a power of 2 and greater than or equal to 1 MiB and not greater than 256 MiB
4.01 bitBlocks remain allocated flag, which is used to indicate the file is a fixed-size image
4.11 bitHas parent flag, which indicates if the VHDX file contains a differential image that has a parent image
4.230 bits0Unknown (reserved), which according to MS-VHDX this value must be set to 0

Logical sector size metadata item

The logical sector size metadata item is 4 bytes in size and consists of:

OffsetSizeValueDescription
04Logical sector size, which according to MS-VHDX this value must be either 512 or 4096

Parent locator metadata item

The parent locator metadata item is of variable size and consits of:

  • parent locator header
  • 0 or more parent locator entry
  • parent locator key and value data

TODO: determine if 0 entries is actually supported

Parent locator header

The parent locator header is 20 bytes in size and consists of:

OffsetSizeValueDescription
016Parent locator type indicator, which contains the GUID: b04aefb7-d19e-4a81-b789-25b8e9445913
1620Unknown (reserved), which according to MS-VHDX this value must be set to 0
182Number of entries (or key-value pairs)
Parent locator entry

The parent locator entry is 12 bytes in size and consists of:

OffsetSizeValueDescription
04Key data offset, which contains the offset relative from the start of the parent locator header
44Value data offset, which contains the offset relative from the start of the parent locator header
82Key data size
102Value data size
Parent locator key and value data

A parent locator key or value is stored as UCS-2 little-endian string without end-of-string character.

Known keys are:

ValueDescription
absolute_win32_pathThe value contains an absolute drive Windows path "\?\c:\file.vhdx"
parent_linkageThe value contains a string of a GUID. This GUID should correspond to the data write identifier of the parent image
parent_linkage2The value contains a string of a GUID
relative_pathThe value contains a relative Windows path "..\file.vhdx"
volume_pathThe value contains an absolute volume Windows path with "\?\Volume{%GUID%}\file.vhdx"

Physical sector size metadata item

The physical sector size metadata item is 4 bytes in size and consists of:

OffsetSizeValueDescription
04Physical sector size, which according to MS-VHDX this value must be either 512 or 4096

Virtual disk identifier metadata item

The virtual disk identifier metadata item is 16 bytes in size and consists of:

OffsetSizeValueDescription
016Virtual disk identifier, which contains a GUID

Note that in contrast to VHD (version 1) the virtual disk identifier does not change between a differential image and its parent. The data write identifier seems to be used instead.

Virtual disk size metadata item

The virtual disk size metadata item is 8 bytes in size and consists of:

OffsetSizeValueDescription
08Virtual disk size

Block allocation table (BAT) region

The block allocation table (BAT) region contains the block allocation table. The entries of this table describe the location of either blocks containing image content data (or payload blocks) or blocks containing a sector bitmap.

The size of an individual sector bitmap block is 1 MiB which allows for 2^23 sectors to be represented by the bitmap.

Block allocation table (BAT) entries are grouped in chunks. The size of a chunk can be calculated as following:

number_of_entries_per_chunk = (2^23 * logical_sector_size) / block_size

The block allocation table (BAT) consists of:

  • one or more chunks containing:
    • number of entries per chunk x BAT entry describing image content data
    • 1 x BAT entry describing the a sector bitmap

Unused BAT entries are filled with 0-byte values.

The block allocation table (BAT) of:

  • a fixed-size image does not contain sector bitmap entries;
  • a dynamic-size image does contain sector bitmap entries, although according to MS-VHDX are not used;
  • a differential image does contain sector bitmap entries.

Block allocation table (BAT) entry

The block allocation table (BAT) entry is 64 bits in size and consists of:

OffsetSizeValueDescription
0.03 bitsBlock state
0.317 bits0Unknown (reserved), which according to MS-VHDX this value must be set to 0
2.444 bitsBlock offset, which contains the offset relative from the start of the file as a multitude of 1 MiB

Block states

Payload block states

ValueIdentifierDescription
0PAYLOAD_BLOCK_NOT_PRESENTBlock is new and therefore not (yet) stored in the file
1PAYLOAD_BLOCK_UNDEFINEDBlock is not stored in the file
2PAYLOAD_BLOCK_ZEROBlock is sparse and therefore filled with 0-byte values
3PAYLOAD_BLOCK_UNMAPPEDBlock has been unmapped
6PAYLOAD_BLOCK_FULLY_PRESENTBlock is stored in the file
7PAYLOAD_BLOCK_PARTIALLY_PRESENTBlock is stored in the parent

Sector bitmap block states

ValueIdentifierDescription
0SB_BLOCK_NOT_PRESENTBlock is new and therefore not (yet) stored in the file
6SB_BLOCK_PRESENTBlock is stored in the file

Sector bitmap

In differential disk images the sector bitmap indicates which sectors are stored within the image (bit set to 1) or in the parent (bit set to 0).

The bitmap is stored in a 1 MiB block.

The bitmap is stored on a per-byte basis with the LSB represents the first bit in the bitmap.

Log (metadata journal)

TODO: complete section

The log serves as metadata journal is of variable size and consist of contiguous circular (ring) buffer that contains log entries.

Log entry

TODO: complete section

4 KiB (4096 bytes) in size

Log entry header

TODO: complete section

Zero descriptor

TODO: complete section

Data descriptor

TODO: complete section

Data sector

TODO: complete section

References

VMware Virtual Disk (VMDK) format

The VMware Virtual Disk (VMDK) format is used by VMware virtualization products as one of its image format.

Overview

A VMDK disk image can consist of multiple files, such as:

  • descriptor file
  • extent data files
  • raw extent data file
  • VMDK sparse extent data file
  • COWD sparse extent data file

Characteristics

CharacteristicsDescription
Byte orderlittle-endian
Date and time values
Character stringsnarrow character (Single Byte Character (SBC) or Multi Byte Character (MBC)) stored using a codepage defined in the descriptor file

The number of bytes per sector is 512.

Disk types

There are multiple types of VMKD images, namely:

The 2GbMaxExtentFlat (or twoGbMaxExtentFlat) disk image, which consists of:

  • a descriptor file (<name>.vmdk)
  • raw data extent files (<name>-f###.vmdk), where ### is contains a decimal value starting with 1.

The 2GbMaxExtentSparse (or twoGbMaxExtentSparse) disk image, which consists of:

  • a descriptor file (<name>.vmdk)
  • VMDK sparse data extent files (<name>-s###.vmdk), where ### is contains a decimal value starting with 1.

The monolithicFlat disk image, which consists of:

  • a descriptor file (<name>.vmdk)
  • raw data extent file (<name>-f001.vmdk)

The monolithicSparse disk image, which consists of:

  • VMDK sparse data extent file (<name>.vmdk) also contains the descriptor file data.

The vmfs disk image, which consists of:

  • a descriptor file (<name>.vmdk)
  • raw data extent file (<name>-flat.vmdk)

The vmfsSparse differential disk image, which consists of:

  • a descriptor file (<name>.vmdk)
  • COWD sparse data extent files (<name>-delta.vmdk)

TODO: describe more disk types

A delta link is similar to a differential image where the image contains the changes (or delta) in comparison of a parent image. According to the Virtual Disk Format 5.0 specification one delta image can chain to another delta image.

TODO: Name <name>-delta.vmdk

Descriptor file

The descriptor file is a case-insensitive text based file that contains the following information:

  • optional comment and empty lines
  • header
  • extent descriptions
  • optional change tracking file
  • disk data base (DDB)

Note that the descriptor file can contains leading and trailing whitespace. Lines are separated by a line feed character (0x0a). And leading comment (starting with #) and empty lines.

The header of a descriptor file looks similar to the data below.

# Disk DescriptorFile
version=1
CID=12345678
parentCID=ffffffff
createType="twoGbMaxExtentSparse"

The header consists of the following values:

ValueDescription
"# Disk DescriptorFile"Section header (or file signature)
versionFormat version
encodingEncoding
CIDContent identifier, which contains a random 32-bit value updated the first time the content of the virtual disk is modified after the virtual disk is opened
parentCIDThe content identifier of the parent, which contains a 32-bit value identifying the parent content, where a value of 'ffffffff' (-1) represents no parent content
isNativeSnapshotTODO: add description. A value of "no" has been observed in a VMWare Player 9 descriptor file
createTypeDisk type
parentFileNameHintContains the path to the parent image, which is only present if the image is a differential image (delta link)

TODO: confirm if a content identifier of ‘fffffffe’ (-2) represents that the long content identifier should be used

Format versions

ValueDescription
1TODO: add description
2TODO: add description
3TODO: add description

Encodings

Note that it is currently unknown which encodings are supported, currently it is assumed that at least the Windows codepages are supported and that the default is UTF-8.

ValueDescription
Big5Big5 assumed to be equivalent to Windows codepage 950
GBKGBK assumed to be equivalent to Windows codepage 936, which was observed in VMWare Workstation for Windows, Chinese edition
Shift_JISShift_JIS assumed to be equivalent to Windows codepage 932, which was observed in VMWare Workstation for Windows, Japanese edition
UTF-8UTF-8
windows-949-2000Windows codepage 949, 2000 version
windows-1252Windows codepage 1252, which was observed in VMWare Player 9 descriptor file

Disk types

ValueDescription
2GbMaxExtentFlat, twoGbMaxExtentFlatThe disk is split into fixed-size extents of maximum 2 GB, which consists of raw extent data files
2GbMaxExtentSparse, twoGbMaxExtentSparseThe disk is split into sparse (dynamic-size) extents of maximum 2 GB, which consists of VMDK sparse extent data files
customTODO: add description. Descriptor file with arbitrary extents, used to mount v2i-format
fullDeviceThe disk uses a full physical disk device
monolithicFlatThe disk is a single raw extent data file
monolithicSparseThe disk is a single VMDK sparse extent data file
partitionedDeviceThe disk uses a full physical disk device, using access per partition
streamOptimizedThe disk is a single compressed VMDK sparse extent data file
vmfsThe disk is a single raw extent data file, which is similar to the "monolithicFlat"
vmfsEagerZeroedThickThe disk is a single raw extent data file
vmfsPreallocatedThe disk is a single raw extent data file
vmfsRawThe disk uses a full physical disk device
vmfsRDM, vmfsRawDeviceMapThe disk uses a full physical disk device, which is also referred to as Raw Device Map (RDM)
vmfsRDMP, vmfsPassthroughRawDeviceMapThe disk uses a full physical disk device, which is similar to the Raw Device Map (RDM), but sends SCSI commands to underlying hardware
vmfsSparseThe disk is split into COWD sparse (dynamic-size) extents
vmfsThinThe disk is split into COWD sparse (dynamic-size) extents

Extent descriptions

The extent descriptions of a descriptor file looks similar to the data below.

# Extent description
RW 4192256 SPARSE "test-s001.vmdk"
# Extent description
RW 1048576 FLAT "test-f001.vmdk" 0

The extent descriptions consists of the following values:

ValueDescription
"# Extent description"Section header
Extent descriptors

Extent descriptor

The extent descriptor consists of the following values:

ValueDescription
1stAccess mode
2ndThe number of sectors
3rdExtent type
If extent type is not ZERO
4thPath of the VMDK extent data file, relative to the location of the VMDK descriptor file
Optional
5thThe extent start sector
Seen in VMWare Player 9 in combination with a physical device extent on Windows
6th and 7th"partitionUUID" followed by a device identifier

The extent offset is specified only for flat extents and corresponds to the offset in the file or device where the extent data is located. For device-backed virtual disks (physical or raw disks) the extent offset can be non-zero. For raw extent data files the extent offset should be zero.

Extent access mode

The extent access mode consists of the following values:

ValueDescription
NOACCESSNo access
RDONLYRead only
RWRead write

Extent types

The extent type consists of the following values:

ValueDescription
FLATraw extent data file
SPARSEVMDK sparse extent data file
ZEROSparse extent that consists of 0-byte values
VMFSraw extent data file
VMFSSPARSECOWD sparse extent data file
VMFSRDMUnknown (Physical disk device that uses RDM?)
VMFSRAWUnknown (Physical disk device?)

Note that VMWare Player 9 has been observed to use “FLAT” for Windows devices

Change tracking file section

The change tracking file section was introduced in version 3 and looks similar to:

# Change Tracking File
changeTrackPath="test-flat.vmdk"

The change tracking file section consists of the following values:

ValueDescription
"# Change Tracking File"Section header
changeTrackPathUnknown (The path to the change tracking file?)

Disk database

The disk data base of a descriptor file looks similar to the data below.

# The Disk Data Base
#DDB

ddb.virtualHWVersion = "4"
ddb.geometry.cylinders = "16383"
ddb.geometry.heads = "16"
ddb.geometry.sectors = "63"
ddb.adapterType = "ide"
ddb.toolsVersion = "0"

The disk data base consists of the following values:

ValueDescription
"# The Disk Data Base"Section header
"#DDB"Currently assumed to be part of the section header
ddb.deletableUnknown (seen: "true")
ddb.virtualHWVersionThe virtual hardware version. For VMWare Player and Workstation this seems to correspond with the application version
ddb.longContentIDThe long content identifier, which contains a 128-bit base16 encoded value, without spaces
ddb.uuidUUIDm which contains a 128-bit base16 encoded value, with spaces between bytes
ddb.geometry.cylindersThe number of cylinders
ddb.geometry.headsThe number of heads
ddb.geometry.sectorsThe number of sectors
ddb.geometry.biosCylindersThe number of cylinders as reported by the BIOS
ddb.geometry.biosHeadsThe number of heads as reported by the BIOS
ddb.geometry.biosSectorsThe number of sectors as reported by the BIOS
ddb.adapterTypeDisk adapter type
ddb.toolsVersionString containing the version of the installed VMWare tools version
ddb.thinProvisionedUnknown (seen: "1")

VirtualBox has been observed to use a different case for “disk” in the section header:

# The disk Data Base

Virtual hardware version

ValueDescription
4TODO: add description
 
6TODO: add description
7TODO: add description
 
9VMWare Player/Workstation 9.0

Disk adapter types

ValueDescription
ideTODO: add description
buslogicTODO: add description
lsilogicTODO: add description
legacyESXTODO: add description

The buslogic and lsilogic values are for SCSI disks and show which virtual SCSI adapter is configured for the virtual machine. The legacyESX value is for older ESX Server virtual machines when the adapter type used in creating the virtual machine is not known.

The raw extent data file

The raw extent data file contains the actual disk data. The raw extent data file can be a file or a device.

This type of extent data file is also known as “Simple” or “Flat Extent”.

The VMDK sparse extent data file

The VMDK sparse extent data file contains the actual disk data. A VMDK sparse extent data file consists of:

  • file header
  • optional embedded descriptor file
  • optional secondary grain directory
    • optional secondary grain tables
  • (primary) grain directory
    • (primary) grain tables
  • grains
  • optional backup file header

This type of extent data file is also known as “Hosted Sparse Extent” or “Stream-Optimized Compressed Sparse Extent” when markers are used.

Note that the actual layout can vary per file, Stream-Optimized Compressed Sparse Extent have been observed to use secondary file headers.

Changes in format version 2:

  • added encrypted disk support (though this feature never seem to never have been implemented).

Changes in format version 3:

  • the size of extent files is no longer limited to 2 GiB;
  • added support for persistent changed block tracking (CBT).

Note that “CBT”, the changeTrackPath value in the descriptor file references a file that describes changed areas on the virtual disk.

File header

The file header is 512 bytes in size and consists of:

OffsetSizeValueDescription
04"KDMV"Signature
441, 2 or 3Format version
84Flags
128Maximum data number of sectors (capacity)
208Sectors per grain, which must be a power of 2 and > 8
288Embedded descriptor file start sector, which is relative from the start of the file or 0 if not set
368Embedded descriptor file size in sectors
444512The number of grains table entries
488Secondary grain directory start sector, which is relative from the start of the file or 0 if not set
568Primary grain directory start sector, which is relative from the start of the file, 0 if not set or 0xffffffffffffffff (GD_AT_END) if relative from the end of the file
648Metadata size in sectors
721Value to determine if the extent data file was cleanly closed (or dirty flag)
731'\n'Single end of line character
741' 'Non end of line character
751'\r'First double end of line character
761'\n'Second double end of line character
772Compression method
794330Unknown (Padding)

The end of line characters are used to detect corruption due to file transfers that alter line end characters.

According to Virtual Disk Format 5.0 specification the maximum data number of sectors (capacity) should be a multitude of the sectors per grain. Note that it has been observed that this is not always the case.

If the primary grain directory start sector is 0xffffffffffffffff (GD_AT_END) in a Stream-Optimized Compressed Sparse Extent there should be a secondary file header stored at offset -1024 relative from the end of the file (stream) that contains the correct grain directory start sector.

Flags

The flags consist of the following values:

ValueIdentifierDescription
0x00000001Valid new line detection test
0x00000002Use secondary grain directory. The secondary (redundant) grain directory should be used instead of the primary grain directory
As of format version 2
0x00000004Use zeroed-grain table entry. The zeroed-grain table entry overloads grain data sector number 1 to indicate the grain is sparse
Common
0x00010000Has compressed grain data
0x00020000Contains metadata, where the file contains markers to identify metadata or data blocks

Compression method

The compression method consist of the following values:

ValueIdentifierDescription
0x00000000COMPRESSION_NONENo compression
0x00000001COMPRESSION_DEFLATECompression using Deflate (RFC1951)

Markers

The markers are used in Stream-Optimized Compressed Sparse Extents. The corresponding flag must be set for markers to be present. An example of the layout of a Stream-Optimized Compressed Sparse Extent that uses markers is:

  • file header
  • embedded descriptor
  • compressed grain markers
  • grain table marker
  • grain table
  • grain directory marker
  • grain directory
  • footer marker
  • secondary file header
  • end-of-stream marker

The marker

The marker is 512 bytes in size and consists of:

OffsetSizeValueDescription
08Value
84Marker data size
If marker data size equals 0
124Marker type
164960Unknown (Padding)
If marker data size > 0
12...Compressed grain data

If the marker data size > 0 the marker is a compressed grain marker.

Marker types

ValueIdentifierDescription
0x00000000MARKER_EOSEnd-of-stream marker
0x00000001MARKER_GTGrain table (metadata) marker
0x00000002MARKER_GDGrain directory (metadata) marker
0x00000003MARKER_FOOTERFooter (metadata) marker

Compressed grain marker

The compressed grain marker indicates that compressed data follows.

OffsetSizeValueDescription
Compressed grain header
080Logical sector number
84Compressed data size
 
12...Compressed data, which contains Deflate compressed data

Note that the compressed grain data can be larger than the grain data size.

End of stream marker

The end-of-stream marker indicates the end of the virtual disk. Basically the end-of-stream marker is an empty sector block.

OffsetSizeValueDescription
080Value
840Marker data size
124MARKER_EOSMarker type
164960Unknown (Padding)

Grain table marker

The grain table marker indicates that a grain table follows the marker sector block.

OffsetSizeValueDescription
080Value
840Marker data size
124MARKER_GTMarker type
164960Unknown (Padding)
512...Grain table

Grain directory marker

The grain directory marker indicates that a grain directory follows the marker sector block.

OffsetSizeValueDescription
080Value
840Marker data size
124MARKER_GDMarker type
164960Unknown (Padding)
512...Grain directory

The footer marker indicates that a footer follows the marker sector block.

OffsetSizeValueDescription
080Value
840Marker data size
124MARKER_FOOTERMarker type
164960Unknown (Padding)
512...Footer

Grain directory

The grain directory is also referred to as level 0 metadata.

The size of the grain directory is dependent on the number of grains in the extent data file. The number of entries in the grain directory can be determined as following:

grain_table_size = number_of_grain_table_entries * grain_size

number_of_grain_directory_entries = maximum_data_size / grain_table_size
if maximum_data_size % grain_table_size > 0:
	number_of_grain_directory_entries += 1

The grain directory consists of 32-bit grain table offsets:

OffsetSizeValueDescription
04Grain table start sector, which is relative from the start of the file or 0 if sparse or the sector is stored in the parent image

The grain directory is stored in a multitude of 512 byte sized blocks.

Note that as of VMDK sparse extent data file version 2 if the “use zeroed-grain table entry” flag is set, a start sector of 1 indicates the grain table is sparse.

Grain table

The grain table is also referred to as level 1 metadata.

The size of the grain table is of variable size. The number of entries in the grain table is stored in the file header. Note that the number of entries in the last grain table is dependent on the maximum data size and not necessarily the same as the value stored in the file header.

The grain directory consists of 32-bit grain table offsets:

OffsetSizeValueDescription
04Grain data sector number, which is relative from the start of the file or 0 if sparse or the sector is stored in the parent image

The number of entries in a grain table and should be 512, therefore the size of the grain table is 512 x 4 = 2048 bytes.

The grain table is stored in a multitude of 512 byte sized blocks.

Note that as of VMDK sparse extent data file version 2 if the “use zeroed-grain table entry” flag is set, a sector number of 1 indicates the grain table is sparse.

Grain data

In an uncompressed sparse extent data file the data is stored at the grain data sector number.

In a compressed sparse extent data file every non-sparse grain is assumed to be stored compressed.

Compressed grain data

The compressed grain data is of variable size and consists of:

OffsetSizeValueDescription
Compressed grain header
080Logical sector number
84Compressed data size
 
12...Compressed data, which contains zlib compressed data
......Unknown (Padding)

The uncompressed data size should be the grain size or less for the last grain.

The footer is only used in Stream-Optimized Compressed Sparse Extents. The footer is the same as the file header. The footer should be the last block of the disk and immediately followed by the end-of-stream marker so that they together make up the last two sectors of the disk.

The header and footer differ in that the grain directory offset value in the header is set to 0xffffffffffffffff (GD_AT_END) and in the footer to the correct value.

Changed block tracking (CBT)

TODO: complete section

The COWD sparse extent data file

The copy-on-write disk (COWD) sparse extent data file contains the actual disk data. The COW sparse extent data file consists of:

  • file header
  • grain directory
  • grain tables
  • grains

This type of extent data file is also known as ESX Server Sparse Extent.

File header

The file header is 2048 bytes in size and consists of:

OffsetSizeValueDescription
04"COWD"Signature
441Format version
840x00000003Unknown (Flags)
124Maximum data number of sectors (capacity)
164Sectors per grain
2044Grain directory start sector, which is relative from the start of the file or 0 if not set
244Number of grain directory entries
284The next free sector
In root extent data file
324The number of cylinders
364The number of heads
404The number of sectors
441016Unknown (Empty values)
In child extent data files
321024Parent file name
10564Parent generation
Common
10604Generation
106460Name
1124512Description
16364Saved generation
16408Unknown (Reserved)
16484Value to determine if the extent data file was cleanly closed (or dirty flag)
1652396Unknown (Padding)

Note that the parent file name seems not to be set in recent delta sparse extent files.

Grain directory

The grain directory is also referred to as level 0 metadata.

The size of the grain directory is dependent on the number of grains in the extent data file. The number of entries in the grain directory is stored in the file header.

The grain directory consists of 32-bit grain table offsets:

OffsetSizeValueDescription
04Grain table start sector, which is relative from the start of the file or 0 if not set

The grain directory is stored in a multitude of 512 byte sized blocks. Unused bytes are set to 0.

Grain table

The grain table is also referred to as level 1 metadata.

The size of the grain table is of variable size. The number of entries in a grain table is the fixed value of 4096.

The grain directory consists of 32-bit grain table offsets:

OffsetSizeValueDescription
04Grain sector number, which is relative from the start of the file or 0 if not set

The grain table is stored in a multitude of 512 byte sized blocks. Unused bytes are set to 0.

Change tracking file

TODO: complete section

OffsetSizeValueDescription
04"\xa2\x72\x19\xf6"Unknown (signature?)
441Unknown (version?)
84Unknown (empty values)
1240x200Unknown
168Unknown
248Unknown
324Unknown
364Unknown
404Unknown
4416Unknown (UUID?)
60...Unknown (empty values?)

Format edge cases and corruption scenarios

The total size specified by the number of grain table entries is lager than size specified by the maximum number of sectors. Seen in VMDK images generated by qemu-img.

Notes

The markers can be used to scan for the individual parts of the VMDK sparse extent data file if the stream has been truncated, but not that this can be very expensive process IO-wise.

References

Volume system formats

A volume (or logical drive) is a single continous accessible storage area, typically containing a file system. A volume system is used to manage the storage of one or more volumes.

A partition is a part of (typically) storage media. A partition is different conceptually, but its usage is comparable to a volume.

This documentation uses the term volume systems in a broad sense to describe:

  • encrypted volumes;
  • logical volume managers;
  • partitioning schemes;
  • and volume snapshots.

Formats

Also see: hybrid volume and file system formats

Apple Partition Map (APM) format

The Apple Partition Map (APM) format is used on Motorola based Macintosh computers. On Intel based Macintosh computers the GUID Partition Table (GPT) format is used.

Overview

An Apple Partition Map (APM) consists of:

  • a drive descriptor
  • partition map entry of type “Apple_partition_map”
  • zero or more partition map entries

Characteristics

CharacteristicsDescription
Byte orderbig-endian
Date and time valuesN/A
Character stringsASCII

The number of bytes per sector is 512 or 2048.

Terminology

TermDescription
Physical blockA fixed location on the storage media defined by the storage media
Logical blockAn abstract location on the storage media defined by software

The drive descriptor

The driver descriptor identifies the device drivers installed on a storage medium. The driver descriptor can contain refer to multiple device drivers. Every device driver is stored in a separate partition.

The drive descriptor is situated in the first block of the storage medium. This block is referred to as the device driver block. The driver descriptor block is not considered part of any partition.

The drive descriptor is 512 bytes in size and consists of:

OffsetSizeValueDescription
02"\x45\x52" or "ER"Signature
22The block size of the device in bytes
44The number of blocks on the device
82Device type (Reserved)
102Device identifier (Reserved)
124Device data (Reserved)
162The number of driver descriptors
188The first device driver descriptor
26484Additional driver descriptors, where unused entries are 16-bit integer values filled with 0

The device driver descriptor

The device driver descriptor is 8 bytes in size and consists of:

OffsetSizeValueDescription
04Start block of the device driver
42Device driver number of blocks
62Operating system type, where is 1 represents "Mac OS"

The partition map

The partition map is stored after the drive descriptor. The partition map consists of multiple entries that must be stored continuously. The partition map itself is considered a partition therefore the first entry in the partition map describes the partition map itself.

The partition map entry

A partition map entry is 512 bytes in size and consists of:

OffsetSizeValueDescription
02"\x50\x4d" or "PM"Signature
220x00Unknown (Reserved)
44Total number of entries in the partition map
84Partition start sector
124Partition number of sectors
1632Partition name, which contains an ASCII string
4832Partition type, which contains an ASCII string
804Data area start sector
844Data area number of sectors
884Status flags
924Boot code start sector
964Boot code number of sectors
1004Boot code address
1044Unknown (Reserved)
1084Boot code entry point
1124Unknown (Reserved)
1164Boot code checksum
12016Processor type
136188 x 2 = 3760x00Unknown (Reserved)

Note that the partition name can be empty.

Partition types

The partition types consist of the following values:

ValueIdentifierDescription
"Apple_Boot"
"Apple_Boot_RAID"
"Apple_Bootstrap"
"Apple_Driver"
"Apple_Driver43"
"Apple_Driver43_CD"
"Apple_Driver_ATA"
"Apple_Driver_ATAPI"
"Apple_Driver_IOKit"
"Apple_Driver_OpenFirmware"
"Apple_Extra"
"Apple_Free"
"Apple_FWDriver"
"Apple_HFS"
"Apple_HFSX"
"Apple_Loader"
"Apple_MDFW"
"Apple_MFS"
"Apple_partition_map"
"Apple_Patches"
"Apple_PRODOS"
"Apple_RAID"
"Apple_Rhapsody_UFS"
"Apple_Scratch"
"Apple_Second"
"Apple_UFS"
"Apple_UNIX_SVR2"
"Apple_Void"
"Be_BFS"
"MFS"

Status flags

The partition status flags consist of the following values:

ValueIdentifierDescription
0x00000001Is valid
0x00000002Is allocated
0x00000004Is in use
0x00000008Contains boot information
0x00000010Is readable
0x00000020Is writable
0x00000040Boot code is position independent
0x00000100Contains a chain-compatible driver
0x00000200Contains a real driver
0x00000400Contains a chain driver
0x40000000Automatic mount at startup
0x80000000Is startup partition

Note that the “is in use” status flags does not appear to be used consistently.

BitLocker Drive Encryption (BDE) format

The BitLocker Drive Encryption (BDE) format is used by Microsoft Windows to encrypt volumes.

Overview

There are multiple versions of BitLocker Drive Encryption (BDE):

  • BitLocker Windows Vista, Windows 7 and 10; used to encrypt volumes on fixed storage media, like harddisks, which typically contain NTFS file systems.
  • BitLocker To Go; introduced in Windows 7; used to encrypt removable drives, which typically contain FAT file systems.
  • BitLocker Used Disk Space Only encryption; used to encrypt only the used space of volumes, which presumably was introduced in Windows 8.
  • BitLocker Encrypt-on-Write (EOW), which presumably was introduced in Windows 10 (1511).

Note that Windows treats NTFS volumes on removable drives are treated as NTFS volumes on fixed storage media.

Characteristics

CharacteristicsDescription
Byte orderlittle-endian
Date and time valuesFILETIME in UTC
Character stringsUCS-2 little-endian, which allows for unpaired Unicode surrogates such as "U+d800" and "U+dc00"

Identifiers

BitLocker is known to use the following identifiers:

  • 4967d63b-2e29-4ad8-8399-f6a339e3d001, for BitLocker and BitLocker To Go
  • 92a84d3b-dd80-4d0e-9e4e-b1e3284eaed8, for BitLocker Used Disk Space Only encryption

Metadata files

BitLocker exposes various files in the “\System Volume Information” directory of the unencrypted volume that correspond to the BitLocker metadata areas.

The contents of the metadata files, on an unencrypted volume, consists of 0-byte values. It is assumed that these files are used to prevent the BitLocker metadata to be overwritten.

Note that not all tools zero out the metadata areas.

BitLocker Windows Vista

In BitLocker Windows Vista the “\System Volume Information” directory contains the following BitLocker related files:

  • “FVE.{e40ad34d-dae9-4bc7-95bd-b16218c10f72}.[123]” maps a metadata block; typically 16384 bytes in size.

BitLocker Windows Windows 7 and later

In BitLocker Windows 7 and later the “\System Volume Information” directory contains the following BitLocker related files:

  • “FVE2.{09cf57b8-9e6c-43d4-ae1f-0408882a397d}.[1-6]”, maps an Encrypt-on-Write (EOW) block map area, used by “Used Disk Space Only encryption”.
  • “FVE2.{24e6f0ae-6a00-4f73-984b-75ce9942852d}” maps the block that contains the encrypted boot record; typically 8192 bytes in size.
  • “FVE2.{93de4bce-e958-48b6-9fac-602d0294e5ef}.[12]”, maps Encrypt-on-Write (EOW) descriptor, used by “Used Disk Space Only encryption”.
  • “FVE2.{aff97bac-a69b-45da-aba1-2cfbce434750}.[12]”, introduced in Windows 8, typically 512 bytes in size (possibly 1 sector in size?).
  • “FVE2.{c9ca54a3-6983-46b7-8684-a7e5e23499e3}.[1-6]”, maps an Encrypt-on-Write (EOW) relocation log area, used by “Used Disk Space Only encryption”.
  • “FVE2.{da392a22-cae0-4f0f-9a30-b8830385d046}”, introduced in Windows 10, typically 65536 bytes in size.
  • “FVE2.{e40ad34d-dae9-4bc7-95bd-b16218c10f72}.[1-3]” maps a metadata block; typically 65536 bytes in size.

BitLocker To Go

BitLocker To Go uses a hybrid volume that has a encrypted and an unencrypted part. The unencrypted part contains various files. Application files for the BitLocker To Go helper application; which can also be found in:

C:\Windows\BitLockerDiscoveryVolumeContents\
  • “COV 0000. BL” maps the block that contains the BitLocker To Go GUID and the offsets to the metadata; typically 32768 bytes in size.
  • “COV 0000. ER” maps the encrypted data.
  • “PAD 0000. PD” maps padding.
  • “PAD 0000. NG” unknown; typically 0 bytes in size.

It has been observed that the “COV 0000. ER” and “PAD 0000. NG” files can be split in multiple 4294934528 byte (4 GiB - 32768) on a FAT32 volume, such as “COV 0001. ER”, “COV 0002. ER”, … or “PAD 0001. NG”, …

The “PAD 0000. NG” are presumaly used to fill the root directory with entries so that no new files may be created on the volume.

Keys

To encrypt storage media BitLocker uses different kind of keys.

Volume Master Key (VMK)

The Volume Master Key (VMK) is 256-bit of size and is stored in multiple Volume Master Key (VMK) structures. The VMK is stored encrypted with either the recovery password, external key, or the TPM.

It is also possible that the VMK is stored unencrypted which is referred to as clear key.

Full Volume Encryption Key (FVEK)

The Full Volume Encryption Key (FVEK) is stored encrypted with the Volume Master Key (VMK). The size of the FVEK is dependent on the encryption method used:

  • For AES 128-bit the key is 128-bit of size
  • For AES 256-bit the key is 256-bit of size

When Elephant Diffuser is used the key data of the structure that hold the FVEK is always 512-bit of size. The First 256-bit are reserved for the FVEK and the other 256-bit for the TWEAK key. Only 128-bit of the 256-bits are used when the encryption method is AES 128-bit.

TWEAK key

The TWEAK is stored encrypted with the Volume Master Key (VMK). The size of the TWEAK key is dependent on the encryption method used:

  • For AES 128-bit the key is 128-bit of size
  • For AES 256-bit the key is 256-bit of size

The TWEAK key is only present when Elephant Diffuser is used. The TWEAK key is stored in the key data of the structure that hold the Full Volume Encryption Key (FVEK) is always 512-bit of size. The First 256-bit are reserved for the FVEK and the other 256-bit for the TWEAK key. Only 128-bit of the 256-bits are used when the encryption method is AES 128-bit.

Recovery password

BitLocker provides for a recovery (or numerical) password to unlock the encrypted data. The recovery password is used to determine a recovery password key. Not to be confused with the “recovery key” key protector.

Example recovery password:

471207-278498-422125-177177-561902-537405-468006-693451

A valid recovery password consists of 48 digits where every number is dividable by 11 with a remainder of 0. The result of a division by 11 of a number is a 16-bit value. The individual 16-bit values make up a 128-bit key.

The corresponding recovery password key is calculated using the following approach, written partially in pseudo C:

Initialize a structure consisting of:

uint8_t last_sha256[ 32 ];
uint8_t initial_sha256[ 32 ];
uint8_t salt[ 16 ];
uint64_t count;

Initialize both the last SHA-256 and the count to 0.

Calculate the SHA-256 of the 128-bit key and update the initial SHA-256 value.

The salt is stored on disk in the stretch key which is stored in the recovery password key protected Volume Master Key (VMK).

Loop for 1048576 (0x100000) times:

  • calculate the SHA-256 of the structure and update the last SHA-256 value
  • increment the count by 1

The last SHA-256 value contains the 256-bit key which is recovery pass key that can unlock the recovery password key protected Volume Master Key (VMK).

Clear key

The clear key is an unprotected 256-bit key stored on the volume to decrypt the VMK. It is used when the encrypted volume is being decrypted.

External key

The external key is used by the “startup key” and “recovery key” key protectors. The external key is stored in a file named “{%GUID%}.BEK”. The GUID in the filename equals the key identifier in the BitLocker metadata.

There can be multiple external keys for a single BitLocker encrypted volume. Each key is identified a by a different key identifier.

User key

BitLocker To Go provides for a user password (or passphrase) to unlock the encrypted data. The user password is used to determine a user key.

TODO: check if the password can be maximal 49 characters in size.

Convert the user password into a UCS-2 little-endian string.

Initialize a structure consisting of:

uint8_t last_sha256[ 32 ];
uint8_t initial_sha256[ 32 ];
uint8_t salt[ 16 ];
uint64_t count;

Initialize both the last SHA-256 and the count to 0.

Calculate the SHA-256 of the user password.

Calculate the SHA-256 of the SHA-256 of the user password, and set it as the initial SHA-256 value.

The salt is stored on disk in the stretch key which is stored in the user key (or password) protected Volume Master Key (VMK).

Loop for 1048576 (0x100000) times:

  • calculate the SHA-256 of the structure and update the last SHA-256 value
  • increment the count by 1

The last SHA-256 value contains the 256-bit key which is user key that can unlock the user key (or password) protected Volume Master Key (VMK).

Encryption methods

BitLocker uses different kind of encryption methods. To encrypt the sector data it either uses AES-CBC (Cipher Block Chaining) with or without Elephant Elephant Diffuser or AES-XTS (XEX-based tweaked-codebook mode with ciphertext stealing).

To encrypt the key data BitLocker uses AES-CCM (Counter with cipher block chaining message authentication code (CBC-MAC)).

AES-CBC

Both encryption and decryption use:

  • AES-CBC with FVEK decryption of sector data

The initialization vector of the AES-CBC is the sector offset AES-ECB encrypted with the FVEK stored as a 16-byte little-endian value. The sector offset is the offset of the sector relative from the start of the volume.

AES-CBC with Elephant Diffuser

Encryption:

  • XOR with sector key
  • Elephant Elephant Diffuser A
  • Elephant Elephant Diffuser B
  • AES-CBC with FVEK

Decryption:

  • AES-CBC with FVEK
  • Elephant Elephant Diffuser B
  • Elephant Elephant Diffuser A
  • XOR with sector key

The initialization vector of the AES-CBC is the sector offset AES-ECB encrypted with the FVEK stored as a 16-byte little-endian value. The sector offset is the offset of the sector relative from the start of the volume.

The sector key 32-byte of size and contains:

  • the lower 16-byte contain a little-endian version of the offset of the sector, relative from the start of the volume, AES-ECB encrypted with the TWEAK key
  • the upper 16-byte contain a 16-byte little-endian version of the offset of the sector, relative from the start of the volume, with the most upper bit set (or upper byte set to 0x80) AES-ECB encrypted with the TWEAK key

AES-CCM

The key data is encrypted using AES-CCM with an initialization vector of 0.

AES-XTS

The FVEK contains both XTS keys.

Both encryption and decryption use:

  • AES-XTS with FVEK decryption of sector data

The initialization vector of the AES-XTS is the sector number stored as a 16-byte little-endian value. The sector number is the offset of the sector relative from the start of the volume divided by the sector size.

Elephant Diffuser

The Elephant Diffuser A and B variants are described in “AES-CBC + Elephant diffuser - A Disk Encryption Algorithm for Windows Vista”.

Virtual sector(s)

In BitLocker the certain sector(s) of the encrypted storage media are handled in a specific manner. These are sectors to store:

  • the unencrypted boot record
  • the BitLocker metadata

BitLocker Windows Vista

In BitLocker Windows Vista the first sector of the unencrypted boot recored sector is reconstructed by replacing values in the BitLocker boot record, namely

  • replacing the “File system signature” with “NTFS\x20\x20\x20\x20”
  • replacing the “metadata block 1 cluster block number” with the “MTF mirror cluster block number”

The 15 sectors directly following the first sector are also unencrypted.

The sectors that contain the BDE metadata are shown as empty sectors; containing 0-byte values.

BitLocker Windows 7 and To Go

Both BitLocker Windows 7 and To Go store an encrypted version of the unencrypted boot record in a specific location. This location is defined in the metadata area descriptors.

The encrypted boot record is commonly 8192 bytes an size, entailing the first 16 sectors.

The sectors that contain the encrypted boot recored and the BDE metadata are shown as empty sectors; containing 0-byte values.

BitLocker Windows 10

In later versions of Bitlocker Windows 10 the metadata area descriptors is not always present.

The number of boot record sectors in the metadata block header can be used to determine the boot record size.

The encrypted boot record is commonly 8192 bytes an size, entailing the first 16 sectors.

Boot record

BitLocker Windows Vista

The BitLocker Windows Vista boot record is similar to a NTFS boot record. The differences have been emphasized in bold. The boot record is 512 bytes of size and consists of:

OffsetSizeValueDescription
03"\xeb\x52\x90"Boot entry point
38"-FVE-FS-"File system signature
DOS version 2.0 BIOS parameter block (BPB)
112Bytes per sector. Note that the following values are supported by mkntfs: 256, 512, 1024, 2048 and 4096
131Number of sectors per cluster block
1420Unknown (Reserved Sectors), which is not used by NTFS and must be 0
1610Number of cluster block allocation tables, which is not used by NTFS and must be 0
1720Number of root directory entries, which is not not used by NTFS and must be 0
1920Number of sectors (16-bit), which is not used by NTFS must be 0
211Media descriptor
2220Cluster block allocation table size (16-bit) in number of sectors, which is not used by NTFS and must be 0
DOS version 3.4 BIOS parameter block (BPB)
2420x3fSectors per track, which is not used by NTFS
2620xffNumber of heads, which is not used by NTFS
2840x3fNumber of hidden sectors, which is not used by NTFS
3240x00Number of sectors (32-bit), which is not used by NTFS must be 0
NTFS version 8.0 BIOS parameter block (BPB) or extended BPB, which was introduced in Windows NT 3.1
3610x80Unknown (Disc unit number), which is not used by NTFS
3710x00Unknown (Flags), which is not used by NTFS
3810x80Unknown (BPB version signature byte), which is not used by NTFS
3910x00Unknown (Reserved), which is not used by NTFS
408Number of sectors (64-bit)
488Master File Table (MFT) cluster block number
568Metadata block 1 cluster block number
644MFT entry size
684Index entry size
728Volume serial number
8040Checksum, which is not used by NTFS
Common
84426Boot code
5102"\x55\xaa"The (boot) signature

Note that the number of sectors can be 1 less then the value indicated in the partition table.

BitLocker Windows 7 and later

The BitLocker Windows 7 boot record for a NTFS volume is similar to a FAT32 boot record. The differences have been emphasized in bold. The boot record is 512 bytes of size and consists of:

OffsetSizeValueDescription
03"\xeb\x58\x90"Boot entry point Boot entry point (JMP +90, NOP)
38"-FVE-FS-"File system signature (or OEM name)
DOS version 2.0 BIOS parameter block (BPB)
112Bytes per sector, which must be 512, 1024, 2048 or 4096
131Sectors per cluster block, which must be 1, 2, 4, 8, 16, 32, 64 or 128
142Number of reserved sectors (reserved region), which starts at the first sector of the volume (sector 0) and must be 1 or more (typically 1 or 32)
161Number of cluster block allocation tables, which must be 1 or more (typically 2)
172Number of root directory entries
192Total number of sectors (16-bit)
211Media descriptor
222Cluster block allocation table size (16-bit)
DOS version 3.4 BIOS parameter block (BPB)
242Number of sectors per track
262Number of heads
284Number of hidden sectors, which contains the volume start sector number
324Total number of sectors (32-bit)
 
364Cluster block allocation table size (32-bit), in number of sectors
402Extended flags
421Format revision minor number
431Format revision major number
444Root directory start cluster
482File system information (FSINFO) sector number
502Boot record sector number
5212Unknown (reserved)
641Drive number
651Unknown (reserved for Windows NT)
661Extended boot signature
If extended boot signature == 0x29
674Volume serial number, which can be derived from the system current date and time
7111Volume label, which contains a narrow character string or "NO\x20NAME\x20\x20\x20\x20" if not set
828"FAT32\x20\x20\x20"File system hint, which is informational and not required
If extended boot signature != 0x29
6723Unknown
Common
9070Bootcode
16016BitLocker identifier, which contains a GUID
1768Metadata block 1 offset, which is relative to the start of the volume
1848Metadata block 2 offset, which is relative to the start of the volume
1928Metadata block 3 offset, which is relative to the start of the volume
200310Unknown (part of bootcode)
51020x55 0xaaSector signature

BitLocker To Go

BitLocker To Go on an NTFS volume is similar to BitLocker Windows 7. The BitLocker Windows To Go boot record for a FAT volume is similar to FAT32 boot record. The differences have been emphasized in bold. The boot record is 512 bytes in size and consists of:

OffsetSizeValueDescription
03"\xeb\x58\x90"Boot entry point
38"MSWIN4.1"File system signature (or OEM name)
DOS version 2.0 BIOS parameter block (BPB)
112Bytes per sector, which must be 512, 1024, 2048 or 4096
131Sectors per cluster block, which must be 1, 2, 4, 8, 16, 32, 64 or 128
142Number of reserved sectors (reserved region), which starts at the first sector of the volume (sector 0) and must be 1 or more (typically 1 or 32)
161Number of cluster block allocation tables, which must be 1 or more (typically 2)
172Number of root directory entries
192Total number of sectors (16-bit)
211Media descriptor
222Cluster block allocation table size (16-bit)
DOS version 3.4 BIOS parameter block (BPB)
242Number of sectors per track
262Number of heads
284Number of hidden sectors
324Total number of sectors (32-bit)
 
364Cluster block allocation table size (32-bit), in number of sectors
402Extended flags
421Format revision minor number
431Format revision major number
444Root directory start cluster
482File system information (FSINFO) sector number
502Boot record sector number
5212Unknown (reserved)
641Drive number
651Unknown (reserved for Windows NT)
661Extended boot signature
If extended boot signature == 0x29
674Volume serial number, which can be derived from the system current date and time
7111Volume label, which contains a narrow character string or "NO\x20NAME\x20\x20\x20\x20" if not set
828"FAT32\x20\x20\x20"File system hint, which is informational and not required
If extended boot signature != 0x29
6723Unknown
Common
90334Bootcode
42416BitLocker identifier, which contains a GUID
4408Metadata block 1 offset, which is relative to the start of the volume
4488Metadata block 2 offset, which is relative to the start of the volume
4568Metadata block 3 offset, which is relative to the start of the volume
46446Unknown
51020x55 0xaaSector signature

BitLocker Used Disk Space Only encryption

The BitLocker Used Disk Space Only encryption boot record for a NTFS volume is similar to a BitLocker Windows 7 and later boot record. The differences have been emphasized in bold. The boot record is 512 bytes of size and consists of:

OffsetSizeValueDescription
03"\xeb\x58\x90"Boot entry point Boot entry point (JMP +90, NOP)
38"-FVE-FS-"File system signature (or OEM name)
DOS version 2.0 BIOS parameter block (BPB)
112Bytes per sector, which must be 512, 1024, 2048 or 4096
131Sectors per cluster block, which must be 1, 2, 4, 8, 16, 32, 64 or 128
142Number of reserved sectors (reserved region), which starts at the first sector of the volume (sector 0) and must be 1 or more (typically 1 or 32)
161Number of cluster block allocation tables, which must be 1 or more (typically 2)
172Number of root directory entries
192Total number of sectors (16-bit)
211Media descriptor
222Cluster block allocation table size (16-bit)
DOS version 3.4 BIOS parameter block (BPB)
242Number of sectors per track
262Number of heads
284Number of hidden sectors, which contains the volume start sector number
324Total number of sectors (32-bit)
 
364Cluster block allocation table size (32-bit), in number of sectors
402Extended flags
421Format revision minor number
431Format revision major number
444Root directory start cluster
482File system information (FSINFO) sector number
502Boot record sector number
5212Unknown (reserved)
641Drive number
651Unknown (reserved for Windows NT)
661Extended boot signature
If extended boot signature == 0x29
674Volume serial number, which can be derived from the system current date and time
7111Volume label, which contains a narrow character string or "NO\x20NAME\x20\x20\x20\x20" if not set
828"FAT32\x20\x20\x20"File system hint, which is informational and not required
If extended boot signature != 0x29
6723Unknown
Common
9070Bootcode
16016BitLocker Used Disk Space Only identifier, which contains a GUID
1768Metadata block 1 offset, which is relative to the start of the volume
1848Metadata block 2 offset, which is relative to the start of the volume
1928Metadata block 3 offset, which is relative to the start of the volume
2008Encrypt-on-Write descriptor 1 offset, which is relative to the start of the volume
2088Encrypt-on-Write descriptor 2 offset, which is relative to the start of the volume
216294Unknown (part of bootcode)
51020x55 0xaaSector signature

Note that Windows 10 version for Bitlocker without “Used Disk Space Only encryption” can also contain Encrypt-on-Write structures within the metadata blocks, these might be remnants of of encrypting the volume.

Metadata block

A BitLocker encrypted volume contains 3 metadata blocks. Which is typically:

  • 12384 bytes in size for BitLocker Windows Vista;
  • 65536 bytes in size for BitLocker Windows 7 and later.

A metadata block consists of:

  • a (metadata) block header
  • a metadata header
  • an array of metadata entries
  • padding (0-byte values)

Metadata block header

Metadata block header version 1 - Windows Vista

The metadata block header version 1 is 64 bytes in size and consists of:

OffsetSizeValueDescription
08"-FVE-FS-"Signature
82Unknown (Header size?)
1021Format version
122Unknown, which is commonly 0x04
142Unknown, which is commonly 0x04
16160Unknown (empty values)
328metadata block 1 offset, which is relative to the start of the volume
408metadata block 2 offset, which is relative to the start of the volume
488metadata block 3 offset, which is relative to the start of the volume
568MFT mirror cluster block number

Metadata block header version 2 – Windows 7 and later

The metadata block header version 2 is 64 bytes in size and consists of:

OffsetSizeValueDescription
08"-FVE-FS-"Signature
82Unknown (Header size?)
1022Format version
122Unknown, which is commonly 0x04, but 0x05 has been observed in a partial decrypted volume (protection status?)
142Unknown, which is commonly 0x04, but 0x01 has been observed in a partial decrypted volume
168Encrypted volume size, in number of bytes
244Unknown
284Number of boot record sectors
328metadata block 1 offset, which is relative to the start of the volume
408metadata block 2 offset, which is relative to the start of the volume
488metadata block 3 offset, which is relative to the start of the volume
568Boot record offset, which is relative to the start of the volume and contains the offset of the boot record of the unencrypted bolume

Note that when decrypting BitLocker will decrypt from the back to the front. The encrypted volume size contains the number of bytes of the volume that are still encrypted (or need to be decrypted).

Metadata header

The metadata header is 48 bytes in size and consists of:

OffsetSizeValueDescription
04Metadata size, which includes the size value but not the size of the metadata block header
441Format version
8448Metadata header size
124Metadata size copy
1616Volume identifier, which contains a GUID
324Next nonce counter
362Encryption method
382Copy of encryption method
408Creation time, which contains a FILETIME

Note that it is currently unknown what the copy of encryption method value is used for.

Encryption methods

ValueIdentifierDescription
0x0000Unknown (Not encrypted/External Key)
0x1000Unknown (Used in stretch key)
0x1001Unknown (Used in stretch key)
0x2000Unknown (Used in AES-CCM encrypted key)
0x2001Unknown (Used in AES-CCM encrypted key)
0x2002Unknown (Used in AES-CCM encrypted key)
0x2003Unknown (Used in AES-CCM encrypted key)
0x2004Unknown (Used in AES-CCM encrypted key)
0x2005Unknown (Used in AES-CCM encrypted key)
0x8000AES-128-CBC with Elephant Diffuser
0x8001AES-256-CBC with Elephant Diffuser
0x8002AES-128-CBC
0x8003AES-256-CBC
0x8004AES-128-XTS
0x8005AES-256-XTS

Metadata entry

The metadata entry is of variable size and consists of:

OffsetSizeValueDescription
02Entry size, which includes the size value
22Entry type
42Value type
62Unknown (Flags? Values of 0x0001, 0x0003, 0x0005 and 0x0105 have been observed)
8...Entry data

Metadata entry types

ValueIdentifierDescription
0x0000None, entry is a property
0x0002Volume Master Key (VMK)
0x0003Full Volume Encryption Key (FVEK)
0x0004Unknown (Validation)
0x0006Startup key
0x0007Description (Drive label), which contains computer name, volume name and date
0x000bUnknown (FVEAutoUnlock key?)
0x000fMetadata area descriptors

Note that older versions of BitLocker use a locale dependent date format in the description, such as “MM/DD/YYYY”. Recent versions of BitLocker use “YYYY-MM-DD”.

Metadata value types

ValueIdentifierDescription
0x0000Erased
0x0001Key
0x0002String, which contains an UCS-2 little-endian string with end-of-string character
0x0003Stretch Key
0x0004Use Key
0x0005AES-CCM encrypted key
0x0006TPM encoded key
0x0007Validation
0x0008Volume master key
0x0009External key
0x000aUpdate
0x000bError
0x000fMetadata area descriptors

Key encrypted key (KEK)

The key encrypted key has value type 0x0001 and is variable in size and consists of:

OffsetSizeValueDescription
02Encryption method
22Unknown
4...Key data

Stretch encrypted key

The stretch encrypted key has value type 0x0003 and is variable in size and consists of:

OffsetSizeValueDescription
02Encryption method
22Unknown
416Salt
20...Metadata entry, which contains an AES-CCM encrypted key

AES-CCM encrypted key

The AES-CCM encrypted key has value type 0x0005 and is variable in size and consists of:

OffsetSizeValueDescription
Nonce
08Nonce date and time, which contains a FILETIME
84Nonce counter
 
1216AES-CCM tag (CBC-MAC)
28...AES-CCM encrypted data

Unencrypted (AES-CCM encrypted) data

The unencrypted (AES-CCM encrypted) data is of variable size and consist of:

OffsetSizeValueDescription
04Size, which does not include the size of the MAC
421Unknown (Format version)
62Unknown
82Encryption method
102Unknown
12...Unencrypted key data

TPM encoded key

The TPM encoded key has value type 0x0006 and is variable in size and consists of:

TODO: complete section

Validation

The validation has value type 0x0007 and is variable in size and consists of:

TODO: complete section

Volume Master Key (VMK)

The Volume Master Key has value type 0x0008 and is variable in size and consists of:

OffsetSizeValueDescription
016Key identifier, which contains a GUID
168Last modification date and time, which contains a FILETIME
242Unknown
262Protector type
28...Properties, which contains an array of metadata entries, where entry type is 0

The available properties depend on the VMK type.

The clear key protected VMK consists of:

The external key protected VMK consists of:

The password protected VMK consists of:

The recovery password key protected VMK consists of:

The TPM protected VMK consists of:

  • optional description string containing “TPM Protection\x00”
  • TPM encoded key

Key protector types

ValueIdentifierDescription
0x0000VMK protected with clear key, which basically is an unprotected VMK
0x0100VMK protected with TPM
0x0200VMK protected with external key (startup key or recovery key)
0x0500VMK protected with TPM and PIN
0x0800VMK protected with recovery password
0x2000VMK protected with password (or passphrase)

TODO: SID (or Active Directory account or group) protector

External Key

The External Key has value type 0x0009 and is variable in size and consists of:

OffsetSizeValueDescription
016Key identifier, which contains a GUID
168Last modification date and time, which contains a FILETIME
24...Properties, which contains an array of metadata entries where the entry type is set to 0

The available properties:

  • optional description string containing “ExternalKey\x00”
  • key

Metadata area descriptors

The metadata area descriptors has value type 0x000f and is 16 or more bytes in size and consists of:

OffsetSizeValueDescription
08Boot record offset
88Boot record size
If size > 16, related to "FVE2.{aff97bac-a69b-45da-aba1-2cfbce434750}.[12]"?
1623, 4 or 5Unknown (format version or number of descriptors?)
18236, 60 or 76Unknown (size of additional data?)
204Unknown
248Unknown (flags?)
328Unknown (offset?)
404Unknown (size?)
444512Logical sector size
484512 or 4096Physical sector size
If additional data size > 36
52810Unknown
6040x0000295a, 0x00004a61, 0x00004a62 or 0x00004a65Unknown
6482Unknown
7240x02010110Unknown
If additional data size > 60
768Unknown area offset, related to "FVE2.{da392a22-cae0-4f0f-9a30-b8830385d046}"
848Unknown area size, related to "FVE2.{da392a22-cae0-4f0f-9a30-b8830385d046}"

The metadata area descriptors seems to have been introduced in Windows 7. They specify the location, within the encrypted volume, where certain metadata is stored, such as the unencrypted boot record.

The unencrypted boot record is commonly 8192 bytes in size for BitLocker Windows 7 (and later) and 5365760 bytes for BitLocker To Go.

Unknown flags

ValueIdentifierDescription
0x01
0x02
0x04
0x08
0x10
0x20
0x40Unknown (related to pause? seen: 0x4b while paused of used disk space only)
0x80Unknown (related to pause? seen: 0xcb after initialization of used disk space only)

BitLocker External Key (BEK) file

A BitLocker External Key (BEK) file is commonly 156 bytes in size and consists of:

  • a file header
  • an array of metadata entries

BEK file header

The BEK file header is similar to the metadata header. The BEK file header is 48 bytes in size and consists of:

OffsetSizeValueDescription
04Metadata size, which includes the size value
441Format version
8448Metadata header size
124Unknown (Metadata size copy)
1616Volume identifier, which contains a GUID
324Next nonce counter
364Encryption method
408Creation time, which contains a FILETIME

The key identifier in the file must match the key identifier in the Volume Master Key (VMK).

BEK metadata entry

The format of a BEK metadata entry is similar to the format of a metadata entry.

The metadata in a BEK file consists of an external key, which contains 256-bits of unprotected key data.

The identifier of the VMK should match the identifier in the BEK file header.

Encrypt-on-Write (EOW)

Checksums use a CRC-32 with the polynominal 0xedb88320 and initial value 0.

Encrypt-on-Write (FVE-EOW) descriptor

The Encrypt-on-Write (FVE-EOW) descriptor is variable of size and consists of:

OffsetSizeValueDescription
Header
08"FVE-EOW\x00"Signature
8256Header size
102Data size
124Logical sector size (or EOW data sector size?)
164Physical sector size (or block record size?)
204Relocation block size
244Encrypt-on-Write relocation log area size
284Encrypt-on-Write relocation log entry size
324Number of block map offsets
364Checksum of the data from the start of the Encrypt-on-Write descriptor upto data size with the checksum value set to 0
408Encrypt-on-Write descriptor 1 offset
488Encrypt-on-Write descriptor 2 offset
 
56number x 8Array of 64-bit block map area offsets
......Unknown (empty values)

Note that Encrypt-on-Write descriptor 1 and 2 are copies and should reference the same block map areas.

Encrypt-on-Write block map area

The Encrypt-on-Write block map area is variable of size and consists of:

  • Encrypt-on-Write block map (FVE-EOWBM)
  • One or more Encrypt-on-Write block (map) records

Note that “FVE2.{09cf57b8-9e6c-43d4-ae1f-0408882a397d}.[1-6]” masks the Encrypt-on-Write block map area, with a 4096 aligment size.

Encrypt-on-Write block map (FVE-EOWBM)

The Encrypt-on-Write block map (FVE-EOWBM) is variable of size, stored as a (physical) sector, and consists of:

OffsetSizeValueDescription
Header
010"FVE-EOWBM\x00"Signature
10260Header size
124Block map size, including the size of the block records
164Block map index, corresponds to the index in the offset array of the EOW data
208Volume region offset, region (or area) of the volume this block map represents
288Volume region size
368Encrypt-on-Write relocation log area offset
444Block record offset 1, relative to start of the block map
484Block record offset 2, relative to start of the block map
524Block record size
564Checksum, of the (physical) sector data with the checksum value set to 0
 
60...Unknown (empty values)

Encrypt-on-Write block (map) record (FVE-EOWBR)

The Encrypt-on-Write block (map) record (FVE-EOWBR) is variable of size, stored as one or more (physical) sectors, and consists of:

OffsetSizeValueDescription
Header
010"FVE-EOWBR\x00"Signature
10236Header size
124Physical sector size
164Unknown (bitmap size, in number of bits?)
204Sequence number
2440Unknown
284Unknown (flags?, seen 0 and 1)
324Checksum, of the (physical) sectors data with the checksum value set to 0
 
36...Bitmap
......Unknown (empty values)

Encrypt-on-Write relocation log area

The Encrypt-on-Write Encrypt-on-Write relocation log area is variable of size and consists of:

  • Encrypt-on-Write relocation log area (OLRDHEVF2) header
  • Encrypt-on-Write relocation log entries
    • Encrypt-on-Write relocation log entry descriptor
    • encrypted sector data or 0-byte values
    • backup of Encrypt-on-Write relocation log entry descriptor
  • backup of Encrypt-on-Write relocation log area (OLRDHEVF2) header
  • Unknown (empty values)

Note that “FVE2.{c9ca54a3-6983-46b7-8684-a7e5e23499e3}.[1-6]” masks the Encrypt-on-Write relocation log area, with a 4096 aligment size.

Encrypt-on-Write relocation log area (OLRDHEVF2) header

The Encrypt-on-Write relocation log area (OLRDHEVF2) header is variable of size, stored as a (logical) sector, and consists of:

OffsetSizeValueDescription
010"OLRDHEVF2\x00"Signature
1021Unknown
1222Unknown (Number of entries?)
144Unknown (Logical sector or entry descriptor size?)
188(Encrypted) volume size
264Relocation block size
304Encrypt-on-Write relocation log entry size
34432Unknown
3842Unknown
428Volume region offset, region (or area) of the volume this relocation log represents

Encrypt-on-Write relocation log entry descriptor

The Encrypt-on-Write relocation log entry descriptor is variable of size, stored as a (logical) sector, and consists of:

OffsetSizeValueDescription
0232Unknown
221Unknown
42Unknown (0 if unencrypted region?)
620Unknown
840Unknown
128Volume region offset, region (or area) of the volume this relocation log entry represents, or 0 if the region is not used by the relocation log
204(Used) encrypted sector data size
384Checksum of the encrypted sectors data
424Unknown (checksum of the unencrypted sectors data?)

Note that an Encrypt-on-Write relocation log entry descriptor can be empty (filled with 0-byte values).

Encrypt-on-Write encrypted sector data

  • 16 bytes of encrypted sector data per sector? decryption sector key is the corresponding volume region offset

TODO: determine if 32 is a compression factor, given 16 x 32 = 512

References

BSD disklabel format

The BSD disklabel format is a partitioning schema mainly used by BSD operating systems.

Overview

A BSD disklabel consists of one or more partition entries, labeled alphabetically from “a” to “h” (or “p” in some BSD variants).

Note that BSD disklabel originally contained 8 entries for describing partitions and some BSD variants have since increased this to 16 partitions.

Certain labels have a predefined meaning, such as:

  • “a” is the “root” partition
  • “b” is the “swap” partition
  • “c” is the volume used by disklabel
  • “d” is the entire physical disk

Note that information about partition “d” is not stored in the corresponding BSD disklabel partition entry and typically filled with 0-byte values.

Characteristics

CharacteristicsDescription
Byte orderlittle-endian
Date and time valuesN/A
Character stringsASCII

The number of bytes per sector is 512.

BSD disklabel

The BSD disklabel is stored at offset 512. It can be preceded by a MBR with a single partition of type 0xa5 (FreeBSD).

The BSD disklabel is of variable size and consists of:

OffsetSizeValueDescription
04"WEV\x82"Signature
42Drive type
62Controller specific drive sub type
816Drive type name, which contains an ASCII string
2416Unknown (Pack identifier?), which contains an ASCII string
404Bytes per sector
444(Data) Sectors per track
484Tracks per cylinder
524(Data) Cylinders per unit
564(Data) Sectors per cylinder
604(Data) Sectors per unit
642Spare sectors per track
662Spare sectors per cylinder
684Alternate cylinders per unit
722Unknown (Rotational speed?)
742Unknown (Hardware sector interleave?)
762Unknown (Sector 0 skew per track?)
782Unknown (Sector 0 skew per cylinder?)
804Unknown (Head switch time in microseconds?)
844Unknown (Track-to-track seek time in microseconds?)
884Flags
925 x 4Unknown (Drive-type specific information?)
1125 x 4Unknown (Reserved)
1324"WEV\x82"Signature
1362Checksum, which contains a XOR of the BSD disklabel
1382Number of partition entries, should not exceed 16 (MAXPARTITIONS)
1404Boot area size in bytes
1444Maximum superblock size in bytes
148number of partitions x 16Array of partition entries

Note that the number of partition entries contains the total number of entries in the array, not the number of partitions in use.

The checksum is calculated as following:

  • set the checksum value to 0
  • XOR every 16-bit value in the disklabel

Drive types

ValueIdentifierDescription
1DTYPE_SMDSMD, XSMD
2DTYPE_MSCPMSCP
3DTYPE_DECDEC (rk, rl)
4DTYPE_SCSISCSI
5DTYPE_ESDIESDI
6DTYPE_ST506ST506
7DTYPE_HPIBCS/80 on HP-IB
8DTYPE_HPFLHP Fiber-link
10DTYPE_FLOPPYFloppy drive

Flags

ValueIdentifierDescription
0x00000001D_REMOVABLERemovable media
0x00000002D_ECCMedia supports error-correction codes (ECC)
0x00000004D_BADSECTMedia suppors bad sectro forwarding
0x00000008D_RAMDISKEmulated media using RAM
0x00000010D_CHAINMedia can do back-to-back transfers

Partition entry

The partition entry is 16 bytes in size and consists of:

OffsetSizeValueDescription
04Number of sectors
44Start sector
84File system (basic) fragment size
121File system type
131File system fragments per block
142Unknown (File system specific value)

Note that an emtpy partition entry consists of 0-byte values.

File system types

ValueIdentifierDescription
0FS_UNUSEDUnused
1FS_SWAPSwap
2FS_V66th edition
3FS_V77th edition
4FS_SYSVSystem V
5FS_V71K7th edition with 1 KiB blocks
6FS_V88th edition with 4 KiB blocks
7FS_BSDFFSBSD 4.2 fast file system (FFS)
8FS_MSDOSMS-DOS file system
9FS_BSDLFSBSD 4.4 log-structured file system
10FS_OTHEROther (unspecified) file system
11FS_HPFSOS/2 high-performance file system (HPFS)
12FS_ISO9660ISO 9660 (CD-ROM) file system
13FS_BOOTBoot code
14Unknown (Vinum)

References

Core Storage

Core Storage is a logical volume management system for Mac OS and was introduced in Mac OS X Lion (10.7).

TODO: complete documentation.

GUID Partition Table (GPT) format

The GUID Partition Table (GPT) is a partitioning schema that is the successor to the Master Boot Record (MBR) Partition Table for Intel x86 based computers.

Overview

A GUID Partition Table (GPT) consists of:

  • A protective or hybrid Master Boot Record (MBR) stored in block (LBA) 0
  • A GPT partition table header stored in block (LBA) 1
  • GPT partition entries stored in blocks (LBA) 2 - 33
  • partitions area
    • GPT partitions
    • MBR partitions if hybrid MBR/GPT
  • backup GPT partition entries (typically stored the blocks (LBA) before the last block -33 - -2)
  • A backup GPT partition table header (typically stored in the last block (LBA) -1)

The GPT partition table header signature can be used to determine the block (LBA) (or sector) size.

Note that the maximum number of partitions is typically 128, but can be 256 as well.

Characteristics

CharacteristicsDescription
Byte orderlittle-endian
Date and time valuesN/A
Character stringsUTF-16 little-endian without byte order mark (BOM)

Master Boot Record (MBR)

Hybrid Master Boot Record (MBR)

In hybrid configuration both GPT and MBR are used concurrently. Depending on the operating system one might have precedence over the other.

Protective Master Boot Record (MBR)

The Protective Master Boot Record (MBR) is an MBR with a single partition of type “EFI GPT protective partition” (0xee) that allocated as much of the drive as possible.

GPT partition table header

The GPT partition table header is 92 bytes in size and consists of:

OffsetSizeValueDescription
08"EFI PART"Signature
820Minor format version
1021Major format version
12492Header data size, which contains the size of the GPT partition table header data
164Header data checksum
2040Unknown (Reserved)
248Partition header block number (LBA)
328Backup partition header block number (LBA)
408Partitions area start block number (LBA)
488Partitions area end block number (LBA), where the block number is included in the partitions area block range
5616Disk identifier (GUID)
728Partition entries start block number (LBA)
804Number of partition entries
844128Partition entry data size
884Partition entries data checksum
92...0Unknown (Reserved)

The partition entries start block number (LBA) of the backup GPT partition table header points to backup GPT partition entries.

Note that the number of partition entries value contains the number of available partition entries not the number of used partition entries. Empty partition entries have a unused entry partition type identifier.

Checksum calculation

The CRC-32 algorithm with polynominal 0x04c11db7 and initial value of 0 is used to calculate the checksums.

The checksum is calculated over the 92 bytes of the table header data, where the header data checkum value is considered to be 0 during calculation.

GPT partition entries

GPT Partition entry

The GPT partition entry is 128 bytes in size and consists of:

OffsetSizeValueDescription
016Partition type identifier (GUID)
1616Partition identifier (GUID)
328Partition start block number (LBA)
408Partition end block number (LBA), where the block number is included in the partition block range
488Attribute flags
5672Partition name, which contains a UTF-16 little-endian string

Partition types

ValueIdentifierDescription
00000000-0000-0000-0000-000000000000Unused entry
024dee41-33e7-11d3-9d69-0008c781f39fMBR partition scheme
c12a7328-f81f-11d2-ba4b-00a0c93ec93bEFI System
21686148-6449-6e6f-744e-656564454649BIOS boot partition
d3bfe2de-3daf-11df-ba40-e3a556d89593Intel Fast Flash (iFFS) partition (for Intel Rapid Start technology)
f4019732-066e-4e12-8273-346c5641494fSony boot partition
bfbfafe7-a34f-448a-9a5b-6213eb736c22Lenovo boot partition
Windows
e3c9e316-0b5c-4db8-817d-f92df00215aeMicrosoft reserved
ebd0a0a2-b9e5-4433-87c0-68b6b72699c7(Microsoft) Basic data
5808c8aa-7e8f-42e0-85d2-e1e90434cfb3Logical Disk Manager (LDM) metadata partition
af9b60a0-1431-4f62-bc68-3311714a69adLogical Disk Manager data partition
de94bba4-06d1-4d40-a16a-bfd50179d6acWindows recovery environment
37affc90-ef7d-4e96-91c3-2d7ae055b174IBM General Parallel File System (GPFS) partition
e75caf8f-f680-4cee-afa3-b001e56efc2dStorage Spaces partition
HP-UX
75894c1e-3aeb-11d3-b7c1-7b03a0000000Data partition
e2a1e728-32e3-11d6-a682-7b03a0000000Service Partition
Linux
0fc63daf-8483-4772-8e79-3d69d8477de4Linux filesystem data
a19d880f-05fc-4d3b-a006-743f0f84911eRAID partition
44479540-f297-41b2-9af7-d131d5f0458aRoot partition (x86)
4f68bce3-e8cd-4db1-96e7-fbcaf984b709Root partition (x86-64)
69dad710-2ce4-4e3c-b16c-21a1d49abed3Root partition (32-bit ARM)
b921b045-1df0-41c3-af44-4c6f280d3faeRoot partition (64-bit ARM/AArch64)
0657fd6d-a4ab-43c4-84e5-0933c84b4f4fSwap partition
e6d6d379-f507-44c2-a23c-238f2a3df928Logical Volume Manager (LVM) partition
933ac7e1-2eb4-4f13-b844-0e14e2aef915/home partition
3b8f8425-20e0-4f3b-907f-1a25a76f98e8/srv (server data) partition
7ffec5c9-2d00-49b7-8941-3ea10a5586b7Plain dm-crypt partition
ca7d7ccb-63ed-4c53-861c-1742536059ccLUKS partition
8da63339-0007-60c0-c436-083ac8230908Reserved
FreeBSD
83bd6b9d-7f41-11dc-be0b-001560b84f0fBoot partition
516e7cb4-6ecf-11d6-8ff8-00022d09712bData partition
516e7cb5-6ecf-11d6-8ff8-00022d09712bSwap partition
516e7cb6-6ecf-11d6-8ff8-00022d09712bUnix File System (UFS) partition
516e7cb8-6ecf-11d6-8ff8-00022d09712bVinum volume manager partition
516e7cba-6ecf-11d6-8ff8-00022d09712bZFS partition
Darwin / Mac OS
48465300-0000-11aa-aa11-00306543ecacHierarchical File System Plus (HFS+) partition
7c3457ef-0000-11aa-aa11-00306543ecacApple APFS
55465300-0000-11aa-aa11-00306543ecacApple UFS container
6a898cc3-1dd2-11b2-99a6-080020736631ZFS
52414944-0000-11aa-aa11-00306543ecacApple RAID partition
52414944-5f4f-11aa-aa11-00306543ecacApple RAID partition, offline
426f6f74-0000-11aa-aa11-00306543ecacApple Boot partition (Recovery HD)
4c616265-6c00-11aa-aa11-00306543ecacApple Label
5265636f-7665-11aa-aa11-00306543ecacApple TV Recovery partition
53746f72-6167-11aa-aa11-00306543ecacApple Core Storage (i.e. Lion FileVault) partition
b6fa30da-92d2-4a9a-96f1-871ec6486200SoftRAID_Status
2e313465-19b9-463f-8126-8a7993773801SoftRAID_Scratch
fa709c7e-65b1-4593-bfd5-e71d61de9b02SoftRAID_Volume
bbba6df5-f46f-4a89-8f59-8765b2727503SoftRAID_Cache
Solaris / illumos
6a82cb45-1dd2-11b2-99a6-080020736631Boot partition
6a85cf4d-1dd2-11b2-99a6-080020736631Root partition
6a87c46f-1dd2-11b2-99a6-080020736631Swap partition
6a8b642b-1dd2-11b2-99a6-080020736631Backup partition
6a898cc3-1dd2-11b2-99a6-080020736631/usr partition
6a8ef2e9-1dd2-11b2-99a6-080020736631/var partition
6a90ba39-1dd2-11b2-99a6-080020736631/home partition
6a9283a5-1dd2-11b2-99a6-080020736631Alternate sector
6a8d2ac7-1dd2-11b2-99a6-080020736631Reserved partition
6a945a3b-1dd2-11b2-99a6-080020736631Reserved partition
6a96237f-1dd2-11b2-99a6-080020736631Reserved partition
6a9630d1-1dd2-11b2-99a6-080020736631Reserved partition
6a980767-1dd2-11b2-99a6-080020736631Reserved partition
NetBSD
49f48d32-b10e-11dc-b99b-0019d1879648Swap partition
49f48d5a-b10e-11dc-b99b-0019d1879648FFS partition
49f48d82-b10e-11dc-b99b-0019d1879648LFS partition
49f48daa-b10e-11dc-b99b-0019d1879648RAID partition
2db519c4-b10f-11dc-b99b-0019d1879648Concatenated partition
2db519ec-b10f-11dc-b99b-0019d1879648Encrypted partition
Chrome OS
fe3a2a5d-4f32-41a7-b725-accc3285a309Chrome OS kernel
3cb8e202-3b7e-47dd-8a3c-7ff2a13cfcecChrome OS rootfs
2e0a753d-9e48-43b0-8337-b15192cb1b5eChrome OS future use
Container Linux by CoreOS
5dfbf5f4-2848-4bac-aa5e-0d9a20b745a6/usr partition (coreos-usr)
3884dd41-8582-4404-b9a8-e9b84f2df50eResizable rootfs (coreos-resize)
c95dc21a-df0e-4340-8d7b-26cbfa9a03e0OEM customizations (coreos-reserved)
be9067b9-ea49-4f15-b4f6-f36f8c9e1818Root filesystem on RAID (coreos-root-raid)
Haiku
42465331-3ba3-10f1-802a-4861696b7521Haiku BFS
MidnightBSD
85d5e45e-237c-11e1-b4b3-e89a8f7fc3a7Boot partition
85d5e45a-237c-11e1-b4b3-e89a8f7fc3a7Data partition
85d5e45b-237c-11e1-b4b3-e89a8f7fc3a7Swap partition
0394ef8b-237e-11e1-b4b3-e89a8f7fc3a7Unix File System (UFS) partition
85d5e45c-237c-11e1-b4b3-e89a8f7fc3a7Vinum volume manager partition
85d5e45d-237c-11e1-b4b3-e89a8f7fc3a7ZFS partition
Ceph
45b0969e-9b03-4f30-b4c6-b4b80ceff106Journal
45b0969e-9b03-4f30-b4c6-5ec00ceff106dm-crypt journal
4fbd7e29-9d25-41b8-afd0-062c0ceff05dOSD
4fbd7e29-9d25-41b8-afd0-5ec00ceff05ddm-crypt OSD
89c57f98-2fe5-4dc0-89c1-f3ad0ceff2beDisk in creation
89c57f98-2fe5-4dc0-89c1-5ec00ceff2bedm-crypt disk in creation
cafecafe-9b03-4f30-b4c6-b4b80ceff106Block
30cd0809-c2b2-499c-8879-2d6b78529876Block DB
5ce17fce-4087-4169-b7ff-056cc58473f9Block write-ahead log
fb3aabf9-d25f-47cc-bf5e-721d1816496bLockbox for dm-crypt keys
4fbd7e29-8ae0-4982-bf9d-5a8d867af560Multipath OSD
45b0969e-8ae0-4982-bf9d-5a8d867af560Multipath journal
cafecafe-8ae0-4982-bf9d-5a8d867af560Multipath block
7f4a666a-16f3-47a2-8445-152ef4d03f6cMultipath block
ec6d6385-e346-45dc-be91-da2a7c8b3261Multipath block DB
01b41e1b-002a-453c-9f17-88793989ff8fMultipath block write-ahead log
cafecafe-9b03-4f30-b4c6-5ec00ceff106dm-crypt block
93b0052d-02d9-4d8a-a43b-33a3ee4dfbc3dm-crypt block DB
306e8683-4fe2-4330-b7c0-00a917c16966dm-crypt block write-ahead log
45b0969e-9b03-4f30-b4c6-35865ceff106dm-crypt LUKS journal
cafecafe-9b03-4f30-b4c6-35865ceff106dm-crypt LUKS block
166418da-c469-4022-adf4-b30afd37f176dm-crypt LUKS block DB
86a32090-3647-40b9-bbbd-38d8c573aa86dm-crypt LUKS block write-ahead log
4fbd7e29-9d25-41b8-afd0-35865ceff05ddm-crypt LUKS OSD
OpenBSD
824cc7a0-36a8-11e3-890a-952519ad3f61Data partition
QNX
cef5a9ad-73bc-4601-89f3-cdeeeee321a1Power-safe (QNX6) file system
Plan 9
c91818f9-8025-47af-89d2-f030d7000c2cPlan 9 partition
VMware ESX
9d275380-40ad-11db-bf97-000c2911d1b8vmkcore (coredump partition)
aa31e02a-400f-11db-9590-000c2911d1b8VMFS filesystem partition
9198effc-31c0-11db-8f78-000c2911d1b8VMware Reserved
Android-IA
2568845d-2332-4675-bc39-8fa5a4748d15Bootloader
114eaffe-1552-4022-b26e-9b053604cf84Bootloader2
49a4d17f-93a3-45c1-a0de-f50b2ebe2599Boot
4177c722-9e92-4aab-8644-43502bfd5506Recovery
ef32a33b-a409-486c-9141-9ffb711f6266Misc
20ac26be-20b7-11e3-84c5-6cfdb94711e9Metadata
38f428e6-d326-425d-9140-6e0ea133647cSystem
a893ef21-e428-470a-9e55-0668fd91a2d9Cache
dc76dda9-5ac1-491c-af42-a82591580c0dData
ebc597d0-2053-4b15-8b64-e0aac75f4db1Persistent
c5a0aeec-13ea-11e5-a1b1-001e67ca0c3cVendor
bd59408b-4514-490d-bf12-9878d963f378Config
8f68cc74-c5e5-48da-be91-a0c8c15e9c80Factory
9fdaa6ef-4b3f-40d2-ba8d-bff16bfb887bFactory (alt)
767941d0-2085-11e3-ad3b-6cfdb94711e9Fastboot / Tertiary
ac6d7924-eb71-4df8-b48d-e267b27148ffOEM
Android 6.0+ ARM
19a710a2-b3ca-11e4-b026-10604b889dcfAndroid Meta
193d1ea4-b3ca-11e4-b075-10604b889dcfAndroid EXT
Open Network Install Environment (ONIE)
7412f7d5-a156-4b13-81dc-867174929325Boot
d4e6e2cd-4469-46f3-b5cb-1bff57afc149Config
PowerPC
9e1a2d38-c612-4316-aa26-8b49521e5a8bPReP boot
freedesktop.org OSes (Linux, etc.)
bc13c2ff-59e6-4262-a352-b275fd6f7172Shared boot loader configuration
Atari TOS
734e5afe-f61a-11e6-bc64-92361f002671Basic data partition (GEM, BGM, F32)

Partition attribute flags

OffsetSizeValueDescription
0.01 bitPartition is required by the platform, e.g. an OEM partition
0.11 bitEFI firmware should ignore the content of the partition
0.21 bitPartition contains bootable legacy BIOS, equivalent to MBR active flag
0.345 bitsUnknown (Reserved)
6.016 bitsFlags specific to the partition type

Microsoft basic partition type attribute flags

OffsetSizeValueDescription
7.41 bitPartition is read-only
7.51 bitPartition is a shadow copy (of another partition)
7.61 bitPartition is hidden
7.71 bitPartition should not have a drive letter assigned (no auto-mount)

ChromeOS partition type attribute flags

OffsetSizeValueDescription
6.04 bitsPriority, where 15 is thehighest priority, 1 is the lowest and 0 indicates the partition is not bootable
6.44 bitsNumber of tries to attempt to boot from the partition
7.01 bitPartition was previously successfully booted from

Linux Logical Volume Manager (LVM) format

The Linux Logical Volume Manager (LVM) format is used by the Logical Volume Manager (LVM) on Linux.

Overview

A Linux LVM consist of:

  • Volume group
  • Physical volumes
  • Logical volumes

Characteristics

CharacteristicsDescription
Byte orderlittle-endian
Date and time valuesPOSIX timestamp in local timezone and/or ctime date and time string
Character stringsASCII string with an end-of-string character

According to “RHEL 5 - Logical Volume Manager Administration” the number of bytes per sector is 512.

Checksums use a “weak” CRC-32, which is a CRC-32 without the initial and final XOR with 0xffffffff, using the polynominal 0xedb88320 and initial value 0xf597a6cf.

Terminology

TermDescription
logical extent (LE)An extent (data range) that makes up the logical volume
logical volume (LV)A volume within the LVM, comparable to a partition in a MBR or GPT volume system
physical extent (PE)An extent (data range) that makes up the physical volume
physical volume (PV)Typically a physical volume is a hard disk, though it may well just be any other device that behaves like a hard disk, such as a software RAID device
volume group (VG)A collection of Logical Volumes and Physical Volumes

Physical volume

A physical volume consist of:

  • Empty sector
  • The physical volume label header
    • The physical volume header
      • data area descriptor list
      • metadata area descriptor list
  • The metadata area
  • Data area (or data extents)

Physical volume label

The physical volume label is stored in the second sector of the physical volume. The physical volume label is currently 512 bytes in size and consists of:

  • physical volume label header
  • physical volume header

Note that according to “RHEL 5 - Logical Volume Manager Administration” the physical volume label can be stored in any of the first 4 sectors.

Physical volume label header

The physical volume label header (struct label_header) is 32 bytes in size and consist of:

OffsetSizeValueDescription
08"LABELONE"Signature (or identifier)
88Sector number, which contains the sector number of the physical volume label header
164Checksum, which contains a CRC-32 for offset 20 to end of the physical volume label sector
204Data offset (or header size), which contains an offset in bytes relative from the start of the physical volume label header
248"LVM2\x20001"Type indicator

Physical volume header

The physical volume header (struct pv_header) is of variable size and consist of:

OffsetSizeValueDescription
032Physical volume identifier, which contains a UUID stored as an ASCII string
328Physical volume size, in number of bytes
40...List of data area descriptors, where the last descriptor in the list is terminator and consists of 0-byte values
......List of metadata area descriptors, where the last descriptor in the list is terminator and consists of 0-byte values

The physical volume identifier can be used to uniquely identify a physical volume. The physical volume identifier is stored as “9LBcEB7PQTGIlLI0KxrtzrynjuSL983W” but is equivalent to its formatted variant “9LBcEB-7PQT-GIlL-I0Kx-rtzr-ynju-SL983W”, which is used in the metadata.

Note that the data area size can be 0, and currently it is assumed that this represents all remaining (available) space within the physical volume.

Data area descriptor

OffsetSizeValueDescription
08Data area offset, which contains an offset in bytes relative to the start of the physical volume
88Data area size, in number of bytes

The metadata area

The metadata area consist of:

  • Metadata area header
  • Metadata

According to “RHEL 5 - Logical Volume Manager Administration” the metadata area is a circular buffer. New metadata is appended to the old metadata and then the pointer to the start of it is updated. The metadata area, therefore, can contain copies of older versions of the metadata.

Metadata area header

The metadata area header (struct mda_header) is 512 bytes in size and consist of:

OffsetSizeValueDescription
04Checksum, which contains the CRC-32 for offset 4 to end of the metadata area header
416"\x20LVM2\x20x[5A%r0N*>"Signature
2041Format version
248Metadata area offset, which contains an offset in bytes relative to the start of the physical volume
328Metadata area size, in number of bytes
404 x 24 = 96List of raw location descriptors, where the last descriptor in the list is terminator and consists of 0-byte values
1363760Unknown (unused)

Raw location descriptor

The raw location descriptor (struct raw_locn) is 24 bytes in size and consist of:

OffsetSizeValueDescription
08Data area offset, which contains an offset in bytes relative to the start of the metadata area
88Data area size, in number of bytes
164Checksum, which contains the CRC-32 of the data area described by the raw location descriptor
204Flags

Note that the data area size can be 0. It is assumed it represents the remaining available data.

Raw location descriptor flags

ValueIdentifierDescription
0x00000001RAW_LOCN_IGNOREDThe raw location descriptor should be ignored

Metadata

The metadata consist of:

  • Volume group main section
    • Physical volumes object
      • Physical volume object
    • Logical volumes object
      • Logical volume object
        • Segment object
  • Top level properties

According to “RHEL 5 - Logical Volume Manager Administration” by default, an identical copy of the metadata is maintained in every metadata area in every physical volume within the volume group. The metadata is stored as ASCII.

The metadata can also be stored in a stand-alone file.

Example

# Generated by LVM2: Tue Jan 30 16:28:15 2007

contents = "Text Format Volume Group"
version = 1

description = "Created *before* executing 'lvextend -L+5G /dev/myvg/mylv /dev/sdc'"

creation_host = "tng3-1"  # Linux tng3-1 2.6.18-8.el5 #1 SMP Fri Jan 26 14:15:21 EST 2007 i686
creation_time = 1170196095  # Tue Jan 30 16:28:15 2007

myvg {
  id = "0zd3UT-wbYT-lDHq-lMPs-EjoE-0o18-wL28X4"
  seqno = 3
  status = ["RESIZEABLE", "READ", "WRITE"]
  extent_size = 8192    # 4 Megabytes
  max_lv = 0
  max_pv = 0

  physical_volumes {

    pv0 {
      id = "ZBW5qW-dXF2-0bGw-ZCad-2RlV-phwu-1c1RFt"
      device = "/dev/sda"   # Hint only

      status = ["ALLOCATABLE"]
      dev_size = 35964301   # 17.1491 Gigabytes
      pe_start = 384
      pe_count = 4390 # 17.1484 Gigabytes
    }

    ...
  }
  logical_volumes {

    mylv {
      id = "GhUYSF-qVM3-rzQo-a6D2-o0aV-LQet-Ur9OF9"
      status = ["READ", "WRITE", "VISIBLE"]
      segment_count = 2

      segment1 {
        start_extent = 0
        extent_count = 1280   # 5 Gigabytes

        type = "striped"
        stripe_count = 1  # linear

        stripes = [
          "pv0", 0
        ]
      }
      segment2 {
        start_extent = 1280
        extent_count = 1280   # 5 Gigabytes

        type = "striped"
        stripe_count = 1  # linear

        stripes = [
          "pv1", 0
        ]
      }
    }
  }
}

Properties

The metadata is textual and uses properties, where a property is defined as:

<identifier> = <value>

The identifier contains an unique name of the property and <value> is one of the following types:

ValueDescription
[0-9]+An integer
"..."A string
["...", "...", ...]A list (or array) of strings

Note that white space, such as space and new line characters, seem to be ignored.

The # character is used for comments. A comment continues to the end-of-line.

Note that for now it is assumed that the # character is not allowed to be used in any of the values.

Top level properties

ValueDescription
"contents"The contents of the metadata area, which contains the string "Text Format Volume Group"
"creation_host"The hostname of the system on which metadata area was created, which can contain a trailing comment that contains the output equivalent to "uname -a"
"creation_time"The creation time of the metadata area, which contains an interger containing the number of seconds since January 1, 1970 00:00:00 UTC and can contain a trailing comment that contains the creation time as a ctime (function) string in UTC
"description"Unknown (Description of the metadata area?)
<volume group name>Volume group object
"version"The metadata area version, which contains an integer value of 1

Note it is assumed that there can only be 1 volume group object.

Volume group and logical volume names

  • Allowed characters: “a-z”, “A-Z”, “0-9”, “_”, “+”, “.”, and “-” (hypen)
  • A volume group name should not start with a hypen
  • A logical volume name can start with a hypen, but it is reserved for logical volumes that have been removed but are stil being tracked by the format

Note that some implementations use lv_ as the prefix for a logical volume, however this is not enforced by the format.

Volume group object

The volume group object contains the following properties:

ValueDescription
"extent_size"The size of an extent, in number of sectors
"flags"Flags
"format"Optional format identifier, such as "lvm2"
"id"Volume group identifier (VG UUID), which contains an ASCII string in the following format: fg1fKZ-xoHz-CfAD-yQPx-l2HL-Y7kA-9kJ9LD
"logical_volumes"Logical volumes object
"max_lv"Maximum number of logical volumes
"max_pv"Maximum number of physical volumes
"metadata_copies"Unknown (The number of metadata copies?)
"physical_volumes"Physical volumes object
"seqno"Metadata sequence number
"status"The status flags, which contains a list of strings

Physical volumes object

The physical volumes object contains the following properties:

ValueDescription
pv#Individual physical volume object, where # is a place holder for a the physical volume number e.g. pv0. 0 appears to be the first number that is used

Physical volume object

Each physical volume object contains the following properties:

ValueDescription
"device"The device filename, which contains an ASCII string, e.g. /dev/dm-0
"device_id"Unknown (device identifier "/tmp/lvm.raw")
"device_id_type"Unknown (device type "loop_file")
"dev_size"The physical volume size including non-usable space, in number of sectors
"flags"Flags
"id"Physical volume identifier (PV UUID), which contains an ASCII string in the following format: 9LBcEB-7PQT-GIlL-I0Kx-rtzr-ynju-SL983W
"pe_count"The number of (allocated) extents in the physical volume
"pe_start"The start extent, which contains an offset in bytes relative from the start of the physical volume
"status"The status flags, which contains a list of strings

Logical volumes object

The logical volumes object contains the following properties:

ValueDescription
<logical volume name>Individual logical volume object, where <name> is a place holder for a the logical volume name

Logical volume object

Each logical volume object contains the following properties:

ValueDescription
"creation_host"The hostname of the system on which the logical volume was created
"creation_time"The creation time of the metadata area, which contains an interger containing the number of seconds since January 1, 1970 00:00:00 UTC and can contain a trailing comment that contains the creation time as a ctime (function) string in UTC
"flags"Flags
"idPhysical volume identifier (PV UUID), which contains an ASCII string in the following format: 9LBcEB-7PQT-GIlL-I0Kx-rtzr-ynju-SL983W
"segment_count"The number of segments
"segment#"Individual segment objects, where # is a place holder for the segment number e.g. segment1. 1 appears to be the first number that is used
"status"Status flags, which contains a list of strings

Segment object

Each segment object contains the following properties:

ValueDescription
"extent_count"The number of extents in the segment (or current logical extent)
"start_extent"The start extent of the segment, which contains an offset in number of extents relative from the start of the segment
"stripe_count"The number of stripes in the segment, where 1 represents linear striping
"stripes"Stripes list
"type"Segment type

Segment types

ValueDescription
cacheSegment that is used as a cache, e.g. SSD for a HDD
cache-poolSegment used as a cache for both data and metadata
errorSegment that fails read and write operations, intended for testing
freeUnallocated segment
integritySegment with integrity checksum
linearLinear physical volume
mirrorSegment that mirrors data across multiple physical volumes (comparable to RAID1)
raid0Segment that contains a stripe of data (RAID0)
raid0_metaRAID0 physical volume that contains data and metadata
raid1Segment that mirrors data across multiple physical volumes (RAID1)
raid10Segment that contains a stripe of data (RAID0) that mirrors data across multiple physical volumes (RAID1)
raid10_nearRAID10 segment that copies data sectors near each other
raid4Segment with stripes across multiple physical volumes with parity data (RAID4)
raid5Segment with stripes across multiple physical volumes with parity data (RAID5)
raid5_laRAID5 variant that uses left asymmetric layout
raid5_lsRAID5 variant that uses left symmetric layout
raid5_nRAID5 variant with dedicated parity layout
raid5_raRAID5 variant that uses right asymmetric layout
raid5_rsRAID5 variant that uses right symmetric layout
raid6Segment with stripes across multiple physical volumes with dual parity data (RAID6)
raid6_la_6RAID6 variant that uses left asymmetric layout
raid6_ls_6RAID6 variant that uses left symmetric layout
raid6_n_6RAID6 variant with dedicated parity layout
raid6_ncRAID6 variant that uses no-change layout
raid6_nrRAID6 variant that uses non-rotating layout
raid6_ra_6RAID6 variant that uses right asymmetric layout
raid6_rs_6RAID6 variant that uses right symmetric layout
raid6_zrRAID6 variant that uses zero-restart layout
snapshotSegment that contains a snapshot
stripedSegment that contains a stripe of data (comparable to RAID0)
thinSegment that allocated on write
thin-poolSegment that manages a shared pool of data and metadata
vdoVirtual Data Optimizer (VDO) physical volume
vdo-poolVirtual Data Optimizer (VDO) pool
writecacheSegment that is used as a write-only cache
zeroSegment that is sparse (filled with 0-byte values)

Note that a comparable list can be retrieved using lvm segtypes.

Stripes list

stripes = [
<physical volume name>, <start extent number>
]

Where:

  • <physical volume name> is a string containing the physical volume name e.g. “pv0”.
  • <start extent number> the segment start extent number relative from the start of the data area.
start_extent_offset = (
    (start_extent_number * extent_size * sector_size) + physical_volume_data_area_start_offset
)

Status flags

ValueDescription
ALLOCATABLEIs allocatable (physical volume only)
RESIZEABLECan be re-sized (volume group only)
READCan be read
VISIBLEIs visible (logical volume only). Hidden if not set.
WRITECan be written

Flags

TODO: complete section

Comments

Textual metadata such as:

# Generated by LVM2 version 2.02.39 (2008-06-27): Sat Jan 17 11:45:29 2009

References

Linux Unified Key Setup (LUKS) Disk Encryption format

Linux Unified Key Setup (LUKS) Disk Encryption is commonly used by Linux to encrypt storage media volumes.

Overview

There are 2 versions of the Linux Unified Key Setup (LUKS) Disk Encryption format, each with a separate layout.

Characteristics

CharacteristicsDescription
Byte orderbig-endian
Date and time valuesN/A
Character stringsASCII string with an end-of-string character

Layout version 1

A LUKS version 1 encrypted volume consist of:

The total reserved size of the LUKS metadata (volume header and split master key material) seems to commonly be 2 MiB.

The number of bytes per sector is 512.

Layout version 2

A LUKS version 2 encrypted volume consist of:

  • metadata area
  • backup metadata area
    • backup volume header
    • backup JSON area
  • keyslots area
  • encrypted (volume) data

The number of bytes per sector is stored in the JSON metadata and can be 512, 1024, 2048, or 4096.

Keys

To encrypt storage media LUKS Disk Encryption uses different kind of keys.

Master Key (MK)

The Master Key (MK) is derived from the Split Master Key (SMK). The size of the MK is dependent on the master key size value in the volume header. Commonly the MK is 128-bit or 256-bit of size. The MK is used to de/encrypt the encrypted (volume) data.

Split Master Key (SMK)

The Split Master Key (SMK) is stored encrypted with a specific user key (UK) in the split master key material. The size of the key material and hence the SMK is the size of the Master Key (MK) times the number of stripes.

The MK is determined from the SMK using the anti-forensic (AF) diffuser using the hashing method.

The resulting MK can be validated with the master key validation hash stored in the volume header. The validation hash can be calculated using the PBKDF2 algorithm with:

  • The hashing method stored in the volume header (format version 1) or metadata (format version 2).
  • The number of iterations as stored in the volume header.
  • A salt, as stored in the volume header.
  • The master key as the input data.

User Key (UK)

The User Key (UK) is derived from the user password. The UK is used to de/encrypt the corresponding split master key material.

The user key is calculated using the PBKDF2 algorithm with:

  • The hashing method stored in the volume header (format version 1) or metadata (format version 2).
  • The number of iterations as stored in the corresponding key slot.
  • A salt, as stored in the corresponding key slot.
  • The password string as the input data (bytes).
  • A (output) key size that is the same as that of the Master Key (MK).

Encryption methods

LUKS supports multiple encryption methods, different encryption chaining modes and initialization vector modes.

Initialization vector modes

The null initialization vector mode

In the null initialization vector mode the initialization vector (IV) is filled with 0‑byte values.

The plain initialization vector modes

In the plain and plain64 initialization vector mode the initialization vector (IV) is filled with respectively a 32-bit or 64-bit little-endian representation of the corresponding sector number padded with 0-byte values.

The sector number is relative to the start of the data not relative to the start of the volume header.

The encrypted sector-salt initialization vector (ESSIV) mode

Int the encrypted sector-salt initialization vector (ESSIV) mode the initialization vector (IV) is determined by:

  1. hashing the encryption key with hashing method defined in the initialization vector mode options.
  2. encrypting the little-endian representation of the corresponding sector number padded with 0-byte values with the hash of the encryption key.

Note that the sector number is relative to the start of the data not relative to the start of the volume header.

The benbi initialization vector mode

In the benbi initialization vector mode the initialization vector (IV) is filled with a 64-bit big-endian representation of the corresponding cipher block (or narrow block)-count (starting at 1) padded with 0-byte values.

The sector number is relative to the start of the data not relative to the start of the volume header.

The cipher block-count is calculated as:

cipher_block_count = (sector_number << (log2(bytes_per_sectory) - log2(iv_size))) + 1

Benbi is presumably the abbreviation of big-endian numeric block index, or equivalent.

The lmk initialization vector mode

TODO: complete section

AES-CBC

Decryption uses:

  • AES-CBC with Master Key (MK) decryption of sector data
  • The initialization vector of the AES-CBC is dependent on the initialization vector mode defined in the volume header. In recent versions of Linux, AES-CBC is combined with the ESSIV initialization vector mode by default.
  • The initialization vector is 16 bytes in size.

AES-ECB

Decryption uses:

  • AES-ECB with Master Key (MK) decryption of sector data
  • No initialization vector is used.
  • The initialization vector is 16 bytes in size.

AES-XTS

TODO: complete section

  • The initialization vector is 16 bytes in size.

Anubis

TODO: complete section

Default encryption mode is cbc-plain Size of initialization vector?

Blowfish

TODO: complete section

Default encryption mode is cbc-plain Size of initialization vector?

Cast5

TODO: complete section

RFC 2144 Size of initialization vector?

Cast6

TODO: complete section

RFC 2612 Default encryption mode is cbc-plain Size of initialization vector?

Serpent

TODO: complete section

Default encryption mode is cbc-plain Size of initialization vector?

Twofish

TODO: complete section

Default encryption mode is cbc-plain Size of initialization vector?

Volume header

Volume header - format version 1

The volume header - format version 1 is 4096 bytes in size and consists of:

OffsetSizeValueDescription
06"LUKS\xba\xbe"Signature
621Format version
832Encryption method (Cipher name), which contains an ASCII string with an end-of-string character
4032Encryption mode (Cipher mode), which contains an ASCII string with an end-of-string character
7232Hashing method, which contains an ASCII string with an end-of-string character
1044Encrypted data start sector
1084Master key size, in number of bytes
11220Master key validation hash
13232Master key derivation salt
1644Master key derivation number of iterations
16840Volume identifier, which contains an ASCII string with an end-of-string character that consists of a lower-case UUID
2088 x 48Array of key slots
5923504Unknown (empty values)

The hashing method is used for the user key calculation and the anti-forensic (AF) diffuser.

Volume header - format version 2

The volume header - format version 2 (or binary header) is 4096 bytes in size and consists of:

OffsetSizeValueDescription
06"LUKS\xba\xbe"Signature
622Format version
88Metadata area size, which consists of the size of the volume header and JSON area
168Epoch (or sequence identifier)
2448Volume label, which contains an ASCII string with an end-of-string character
7232Metadata area checksum method (or algorithm), which contains an ASCII string with an end-of-string character
10464Salt
16840Volume identifier, which contains an ASCII string with an end-of-string character that consists of a lower-case UUID
20848Unknown (subsystem), which contains an ASCII string with an end-of-string character
2568Metadata area offset, which is relative from the start of the storage media in which the LUKS volume is stored
264184Unknown (padding), which according to "LUKS2 On-Disk Format Specification" this must be filled with 0-byte values
44864Metadata area checksum
5127 x 512 = 3584Unknown (padding), which according to "LUKS2 On-Disk Format Specification" this must be filled with 0-byte values

JSON area

The JSON area is stored directly after the volume header and must be 4096-byte aligned. The JSON area is of variable size and constists of:

OffsetSizeValueDescription
0...JSON string, which contains an ASCII string with an end-of-string character
......Unknown (padding), which according to "LUKS2 On-Disk Format Specification" this must be filled with 0-byte values

Example

{
  "keyslots": {
    "0": {
      "type": "luks2",
      "key_size": 32,
      "af": {
        "type": "luks1",
        "stripes": 4000,
        "hash": "sha1"
      },
      "area": {
        "type": "raw",
        "offset": "32768",
        "size": "131072",
        "encryption": "aes-ecb",
        "key_size": 32
      },
      "kdf": {
        "type": "argon2i",
        "time": 6,
        "memory": 1048576,
        "cpus": 4,
        "salt": "X3OghBqUPLPkYuaFlSu4w/4VsRlRNDBzN+IW5Y5JQSU="
      }
    }
  },
  "tokens": {},
  "segments": {
    "0": {
      "type": "crypt",
      "offset": "16777216",
      "size": "dynamic",
      "iv_tweak": "0",
      "encryption": "aes-ecb",
      "sector_size": 512
    }
  },
  "digests": {
    "0": {
      "type": "pbkdf2",
      "keyslots": [
        "0"
      ],
      "segments": [
        "0"
      ],
      "hash": "sha1",
      "iterations": 154931,
      "salt": "wxT97+jYHKhAat3rZb6XXuwXVRn3DM7tvGy8+ZukM38=",
      "digest": "WHT1SoOLP3tummIDhiNTxP39dfw="
    }
  },
  "config": {
    "json_size": "12288",
    "keyslots_size": "16744448"
  }
}

Top level properties

ValueDescription
"config"Config object
"digests"One or more digests object
"keyslots"One or more keyslots object
"segments"One ore more segments object
"tokens"Zero or more tokens object

Config object

ValueDescription
"flags"List of strings
"json_size"String containing an integer
"keyslots_size"String containing an integer
"requirements"

Digests object

TODO: complete section

ValueDescription
"digest"
"hash"type "pbkdf2"
"iterations"type "pbkdf2"
"keyslots"
"salt"
"segments"
"type"

Keyslots object

Contains zero or more keyslot object.

Keyslot object

TODO: complete section

ValueDescription
"af"Anti-forensics (diffuser) object, which should only be present in type "luks2"
"area"Key slot area object
"direction"Re-encryption direction, which should only be present in type "reencrypt"
"kdf"Key derivation object, which should only be present in type "luks2"
"key_size"Key size, in number of bytes
"mode"Re-encryption mode, which should only be present in type "reencrypt"
"priority"Priority, where 0 represents "ignore", 1 "normal" and 2 "high"
"type"Keyslot type, which can be "luks2" or "reencrypt"

Anti-forensics (diffuser) object

TODO: complete section

ValueDescription
"hash"type "luks1"
"stripes"type "luks1"
"type"Anti-forensics type, which can be "luks1"

Keyslot area object

TODO: complete section

ValueDescription
"encryption"type "raw"
"hash"types "checksum" and "datashift-checksum"
"key_size"type "raw"
"offset"
"sector_size"types "checksum" and "datashift-checksum"
"shift_size"types "datashift", "datashift-checksum" and "datashift-journal"
"size"
"type"Area type, which can be "raw", "checksum", "none", "journal"

Key derivation object

TODO: complete section

ValueDescription
"cpus"types "argon2i" and "argon2id"
"hash"type "pbkdf2"
"iterations"type "pbkdf2"
"memory"types "argon2i" and "argon2id"
"salt"
"time"types "argon2i" and "argon2id"
"type"The PBKDF type, which can be "pbkdf2", "argon2i" and "argon2id"

Segments object

TODO: complete section

ValueDescription
"encryption"type "crypt"
"flags"
"integrity"type "crypt"
"iv_tweak"type "crypt"
"offset"
"sector_size"type "crypt"
"size"
"type"Segment type, which can be "linear" or "crypt"

Segment integrity object

TODO: complete section

ValueDescription
"journal_encryption"
"journal_integrity"
"key_size"
"type"

Tokens object

TODO: complete section

ValueDescription
"key_description"type "luks2-keyring"
"keyslots"
"type"

Backup metadata area

To make recovery easier the backup metadata area starts at a fixed offset:

OffsetMaximum JSON area size
16384 (0x004000)12 KiB
32768 (0x008000)28 KiB
65536 (0x010000)60 KiB
131072 (0x020000)124 KiB
262144 (0x040000)252 KiB
524288 (0x080000)508 KiB
1048576 (0x100000)1020 KiB
2097152 (0x200000)2044 KiB
4194304 (0x400000)4092 KiB

Backup volume header - format version 2

The backup (or secondary) volume header - format version 2 is the same as the Volume header - format version 2 with a different signature: “SKUL\xba\xbe”.

Keyslots

Key slot - format version 1

The key slot - format version 1 is 48 bytes in size and consists of:

OffsetSizeValueDescription
04State (of key slot), where 0x0000dead represents inactive (dead) and 0x00ac71f3 represents active
44Key material number of iterations
832Key material salt
404Key material start sector
444Key material number of (anti-forensic) stripes

String identifiers

LUKS uses various string values as identifiers.

Note that it is assumed that these identifiers are case insensitive.

Encryption method

Known values of encryption method are:

ValueDescription
arc4Alleged RC4 (ARC4)
aesAdvanced Encryption Standard (AES)
anubisAnubis
blowfishBlowfish
cast5Cast5 (RFC 2144)
cast6Cast6 (RFC 2612)
serpentSerpent
tnepresReversed variant of Serpent
twofishTwofish

Encryption mode

The encryption mode consists of a string in the format:

chaining_mode[-initialization_vector_mode[:initialization_vector_options]]

Chaining mode

Known values of chaining mode are:

ValueDescription
cbcCipher-block chaining (CBC)
ecbElectronic codebook (ECB), which should not have a initialization vector mode set
xtsXEX-based tweaked-codebook mode with ciphertext stealing (XTS)

Note that it is assumed that these identifiers are case insensitive.

TODO: determine ctr and lrw

Initialization vector mode and options

Known values of initialization vector mode and options are:

ValueDescription
benbiThe initialization vector is the 64-bit big-endian cipher block (or narrow block)-count (starting at 1)
essivEncrypted sector-salt initialization vector (ESSIV). The "essiv" initialization vector mode requires a hash algorithm to be defined as an initialization vector option. This is specified in the form "essiv:hash", e.g. "essiv:sha256"
lmkCompatible implementation of the block chaining mode used by the Loop-AES block device encryption system
nullThe initialization vector is always zero
plainThe initialization vector is the 32-bit little-endian version of the sector number, padded with zeros if necessary
plain64The initialization vector is the 64-bit little-endian version of the sector number, padded with zeros if necessary
plumbUnknown

Hashing method

Known values of hashing method are:

ValueDescription
ripemd160RIPEMD-160
sha1SHA-1
sha224SHA-224
sha256SHA-256
sha512SHA-512
wd256Unknown

The hashing method must at least produce 20 bytes of hash data. Therefore hashing methods like ghash and MD5 are unsupported.

Format edge cases and corruption scenarios

Uninitialized encrypted volume data

Running “cryptsetup luksFormat” will not initialize the encrypted volume data, the data is initialized on write. The uninitialized encrypted data is treated as-is on decryption.

References

Master Boot Record (MBR) partition table format

The Master Boot Record (MBR) partition table is mainly used on the family of Intel x86 based computers.

Overview

A MBR partition table consists of:

  • Master Boot Record (MBR)
  • Extended Partition Records (EPRs)

Characteristics

CharacteristicsDescription
Byte orderlittle-endian
Date and time valuesN/A
Character stringsN/A

Terminology

TermDescription
Physical blockA fixed location on the storage media defined by the storage media
Logical blockAn abstract location on the storage media defined by software

Sector size(s)

Traditionally the size of sector is 512 bytes, but modern hard disk drives use 4096 bytes. The linux fdisk utility supports sector sizes of: 512, 1024, 2048 and 4096.

The location of of the “boot signature” of the MBR does not indicate the sector size. Methods to derive the sector size from the data:

  • check the “boot signature” of the first EPR, if present
  • check the content of well known partition types

Cylinder Head Sector (CHS) address

The Cylinder Head Sector (CHS) address is 24 bits in size and consists of:

OffsetSizeValueDescription
0.0 8 bitsHead
1.0 6 bitsSector
1.510 bitsCylinder

The logical block address (LBA) can be determined from the CHS with the following calculation:

lba = (((cylinder * heads_per_cylinder) + head) * sectors_per_track) + (sector - 1)

The Master Boot Record (MBR)

The Master Boot Record (MBR) is a data structure that describes the properties of the storage medium and its partitions.

The classical MBR can only contain 4 partition table entries. Additional partition entries must be stored using extended partition records (EPR). The classical MBR has evolved into different variants like:

  • The modern MBR
  • The Advanced Active Partitions (AAP) MBR
  • The NEWLDR MBR
  • The AST/NEC MS-DOS and SpeedStor MBR
  • The Disk Manager MBR

The classical MBR

The classical MBR is 512 bytes in size and consists of:

OffsetSizeValueDescription
0446The boot (loader) code
44616Partition table entry 1
46216Partition table entry 2
47816Partition table entry 3
49416Partition table entry 4
5102"\x55\xaa"The (boot) signature

The modern MBR

The modern MBR is 512 bytes in size and consists of:

OffsetSizeValueDescription
0218The first part of the boot (loader) code
Disk timestamp used by Microsoft Windows 95, 98 and ME
21820x0000Unknown (Reserved)
2201Unknown (Original physical drive), which contains a value that ranges from 0x80 to 0xff, where 0x80 is the first drive, 0x81 the second, etc.
2211Seconds, which contains a value that ranges from 0 to 59
2221Minutes, which contains a value that ranges from 0 to 59
2231Hours, which contains a value that ranges from 0 to 23
Without disk identity
224222The second part of the boot (loader) code
With disk identity, used by UEFI, Microsoft Windows NT or later
224216The second part of the boot (loader) code
4404Disk identity (signature)
44420x0000 or 0x5a5acopy-protection marker
Common
44616Partition table entry 1
46216Partition table entry 2
47816Partition table entry 3
49416Partition table entry 4
5102"\x55\xaa"The (boot) signature

The extended partition record

The extended partition record (EPR) (also referred to as extended boot record (EBR)) starts with a 64 byte (extended) partition record (EPR) like the MBR. This partition table contains information about the logical partition (volume) and additional extended partition tables.

OffsetSizeValueDescription
04460x00Unknown (Unused), which should contain zero bytes
44616Partition table entry 1, contains the logical partition
46216Partition table entry 2, which should contain an extended partition (of type 0x05) or contain zero bytes if unused
478160x00Partition table entry 3, which should be unused and contain zero bytes
494160x00Partition table entry 4, which should be unused and contain zero bytes
5102"\x55\xaa"Signature

The second partition entry contains an extended partition which points to the next EPR. The LBA addresses in the EPR are relative to the start of the first EPR.

The first EPR typically has a partition type of “Extended (CHS)” (0x05) or “Extended (LBA)” (0x0f).

Note that an extended boot record can be empty.

The partition table entry

The partition table entry is 16 bytes in size and consists of:

OffsetSizeValueDescription
01Partition flags
13The partition start CHS address, which is relative from the start of the MBR
41Partition type
53The partition end CHS address, which is relative from the start of the MBR
84The partition start LBA (sector address)
124Size of the partition in number of sectors

For partition table entry 1 (logical partition), the partition start LBA is relative from the start of the current extended partition record.

For partition table entry 2 (next extended partition), the partition start LBA is relative from the start of the first extended partition record.

Partition flags

The partition flags consist of the following values:

ValueIdentifierDescription
0x80Partition is boot-able

Partition types

The partition types consist of the following values:

ValueIdentifierDescription
0x00Empty
0x01FAT12 (CHS)
0x02XENIX root
0x02XENIX user
0x04FAT16 (16 MiB -32 MiB CHS)
0x05Extended (CHS)
0x06FAT16 (32 MiB - 2 GiB CHS)
0x07HPFS/NTFS
0x08AIX
0x09AIX bootable
0x0aOS/2 Boot Manager
0x0bFAT32 (CHS)
0x0cFAT32 (LBA)
0x0eFAT16 (32 MiB - 2 GiB LBA)
0x0fExtended (LBA)
0x10OPUS
0x11Hidden FAT12 (CHS)
0x12Compaq diagnostics
0x14Hidden FAT16 (16 MiB - 32 MiB CHS)
0x16Hidden FAT16 (32 MiB - 2 GiB CHS)
0x17Hidden HPFS/NTFS
0x18AST SmartSleep
0x1bHidden FAT32 (CHS)
0x1cHidden FAT32 (LBA)
0x1eHidden FAT16 (32 MiB - 2 GiB LBA)
0x24NEC DOS
0x27Unknown (PackardBell recovery/installation partition)
0x39Plan 9
0x3cPartitionMagic recovery
0x40Venix 80286
0x41PPC PReP Boot
0x42SFS or LDM: Microsoft MBR (Dynamic Disk)
0x4dQNX4.x
0x4eQNX4.x 2nd part
0x4fQNX4.x 3rd part
0x50OnTrack DM
0x51OnTrack DM6 Aux1
0x52CP/M
0x53OnTrack DM6 Aux3
0x54OnTrackDM6
0x55EZ-Drive
0x56Golden Bow
0x5cPriam Edisk
0x61SpeedStor
0x63GNU HURD or SysV
0x64Novell Netware 286
0x65Novell Netware 386
0x70DiskSecure Multi-Boot
0x75PC/IX
0x78XOSL
0x80Old Minix
0x81Minix / old Linux
0x82Solaris x86 or Linux swap
0x83Linux
0x84Hibernation or OS/2 hidden C: drive
0x85Linux extended
0x86NTFS volume set
0x87NTFS volume set
0x8eLinux LVM
0x93Amoeba
0x94Amoeba BBT
0x9fBSD/OS
0xa0IBM Thinkpad hibernation
0xa1Hibernation
0xa5FreeBSD
0xa6OpenBSD
0xa7NeXTSTEP
0xa8Mac OS X
0xa9NetBSD
0xabMac OS X Boot
0xafMac OS X
0xb7BSDI
0xb8BSDI swap
0xbbBoot Wizard hidden
0xc1DRDOS/sec (FAT-12)
0xc4DRDOS/sec (FAT-16 < 32M)
0xc6DRDOS/sec (FAT-16)
0xc7Syrinx
0xdaNon-FS data
0xdbCP/M / CTOS / ...
0xdeDell Utility
0xdfBootIt
0xe1DOS access
0xe3DOS R/O
0xe4SpeedStor
0xebBeOS
0xeeEFI GPT protective partition
0xefEFI system partition (FAT)
0xf0Linux/PA-RISC boot
0xf1SpeedStor
0xf2DOS secondary
0xf4SpeedStor
0xfbVMWare file system
0xfcVMWare swap
0xfdLinux RAID auto-detect
0xfeLANstep
0xffBBT

SGI (Silicon Graphics) disklabel format

The SGI disklabel format is a partitioning schema mainly used by the SGI Irix operating system.

Overview

A SGI disklabel consists of one or more partition entries.

Certain paritions have a predefined meaning, such as:

  • entry 9 the volume header (partition type 0);
  • entry 11 the entire volume (partition type 6).

Characteristics

CharacteristicsDescription
Byte orderbig-endian
Date and time valuesN/A
Character stringsASCII

SGI disklabel

The SGI disklabel (or volume header) is stored at offset 0.

The SGI disklabel is 512 bytes in size and consists of:

OffsetSizeValueDescription
04"\x0b\xe5\xa9\x41"Signature
42Root partition number
62Swap partition number
816ARCS boot file name, with consists of an ASCII string
2448Device parameters
7215 x 16 = 240Array of volume descriptors
31216 x 12 = 192Array of partition entries
5044Checksum
5084Unknown (padding)

Device parameters

The device parameters are 48 bytes in size and consist of:

OffsetSizeValueDescription
01Skew
11Gap 1 size
21Gap 2 size
31Number of spare cylinders (per volume)
42Number of (physical) cylinders
62Heads per volume
82Tracks per cylinder
101Unknown (cmd_tag_queue_depth)
113Unknown (unused)
142Sectors per track
162Bytes per sector
182Unknown (ilfact)
204Unknown (flags)
244Unknown (datarate)
284Unknown (retries_on_error)
324Unknown (ms_per_word)
362Unknown (xylogics_gap1)
382Unknown (xylogics_syncdelay)
402Unknown (xylogics_readdelay)
422Unknown (xylogics_gap2)
442Unknown (xylogics_readgate)
462Unknown (xylogics_writecont)

Volume descriptor

The volume descriptors contain a flat file system, where each individual descriptor describes a execute boot file. These execute boot files are stored within the volume header partition.

The volume descriptor is 16 bytes in size and consists of:

OffsetSizeValueDescription
08File name, with consists of an ASCII string
84Start sector number, relative to the start of the volume header partition
124Size, in number of bytes

Partition entry

The partition entry is 12 bytes in size and consists of:

OffsetSizeValueDescription
04Number of sectors, relative to the start of the SGI disklabel
44Start sector number
84Partition type

Partition types

ValueIdentifierDescription
0SGI_VOLHDRVolume header
1SGI_TRKREPLTrack Replacements
2SGI_SECREPLSector Replacements
3SGI_SWAPIRIX Swap
4SGI_BSD or SGI_RAWSGI BSD or raw
5SGI_SYSV or SGI_BOARDSGI SystemV, board or overlay
6SGI_VOLUMEEntire Volume
7SGI_EFSIRIX EFS
8SGI_LVOLSGI Logical Volume
9SGI_RVOLSGI raw logical volume
10SGI_XFSXFS
11SGI_XFSLOGXFS journal
12SGI_XLVSGI XLV Volume Manager
13SGI_XVMSGI XVM Volume Manager

Volume Shadow Snapshot (volsnap) format

As of Windows Vista the Volume Shadow Snapshot (VSS) stores persistent shadow copies on the local NTFS volume.

Overview

According to “Shadow Copies and Shadow Copy Sets” a shadow copy is a snapshot of a volume. A shadow copy can be part of a set which contains a collection of shadow copies of various volumes, taken at the same time.

Volume Shadow Snapshot (VSS) can use different providers to store shadow copies, this document focuses on the “Microsoft Software Shadow Copy provider 1.0” (GUID: b5946137-7b9f-4925-af80-51abd60b20d5) and will refer to it as volsnap. The volsnap provider stores the copies on the local volume using 16 KiB blocks.

Volsnap uses the GUID 3808876b-c176-4e48-b7ae-04046e6cc752 to identify its data or metadata files. It leverages several metadata files in “\System Volume Information” directory:

  • Volsnap catalog; stored in the metadata file named {%VOLSNAPGUID%}
  • Volsnap store; stored in the metadata file named {%GUID%}{%VOLSNAPGUID%}

Where %VOLSNAPGUID% (_VSP_DIFF_AREA_FILE_GUID) contains the volsnap identifier and %GUID% contains a time/MAC based GUID.

CharacteristicsDescription
Byte orderlittle-endian
Date and time valuesFILETIME in UTC
Character stringsUCS-2 little-endian, which allows for unpaired Unicode surrogates such as "U+d800" and "U+dc00"

Volume header

The volsnap volume header is part of the NTFS volume header (or $Boot metadata file). The volsnap volume header data is stored at offset 7680 (0x1e00) of the volume and is at least 100 bytes in size, but presumably 512 bytes, and consists of:

OffsetSizeValueDescription
016volsnap identifier, which contains a GUID
164Format version
2040x01Record type
2480x1e00Current offset, which is relative to the start of the volume
3280x1e00Unknown (Next offset?), which is relative to the start of the volume
408Unknown (empty value)
488Catalog offset, which is relative to the start of the volume or contains 0 if there is no catalog
568Maximum size, in number of bytes or contains 0 if unbounded
6416Volume identifierwhich contains a GUID
8016Shadow copy storage volume identifier, which contains a GUID
964Unknown
100412Unknown (empty values)

Version

ValueIdentifierDescription
1Windows Vista, Windows 7
2Windows 8

Catalog

The catalog contains information about the individual stores. The catalog consists of one or more catalog blocks. Each catalog block is 16384 (0x4000) bytes in size and consists of:

  • catalog block header
  • an array of catalog entries

The volsnap catalog metadata files contains the catalog blocks stored directly after one-and-other.

If the volume does not contain a catalog when there are no snapshots (stored) but volsnap is enabled.

Catalog block header

The catalog block header is 128 bytes in size and consists of:

OffsetSizeValueDescription
016volsnap identifier, which contains a GUID
1640x01Version
2040x02Record type
248Relative (catalog block) offset, which is relative to the start of the first catalog block
328Current (catalog block) offset, which is relative to the start of the volume
408Next (catalog block) offset, which is relative to the start of the volume or contains 0 if this is the last block
4880Unknown (empty values)

Catalog entry

Each catalog entry consists of a catalog entry type 0x02. A corresponding type 0x03 is required if the shadow copy is stored in a store, which is the case as of Windows Vista.

Note that a Windows 2003 R2 catalog does not contain catalog entry type 0x03.

TODO: Determine how Windows 2003 R2 volumes store the snapshot data

The type 0x02 and type 0x03 entries are not necessarily stored directly after one-and-other and can be scattered over the catalog. For now it is assumed that entry type 0x02 must be defined before entry type 0x03.

Also these entries are not necessarily stored in order of age.

There can be unused catalog entries (of type 0x01) as well. Empty catalog entries seem to consist entirely of 0-bytes.

Unused catalog entry (type 0x01)

An unused catalog entry (type 0x01) is 128 bytes in size and consists of:

OffsetSizeValueDescription
080x01Catalog entry type
8120Unknown (empty values)

Catalog entry type 0x02

A catalog entry type 0x02 is 128 bytes in size and consists of:

OffsetSizeValueDescription
080x02Catalog entry type
88Volume size
1616Store identifier, which contains a GUID that is used in the store filename
328Unknown (Sequence number)
408Unknown (Flags?), seen 0x40 in Windows in Vista and 7 and 0x440 in Windows 8 (file backup?)
488Shadow copy creation time, which contains a FILETIME
5672Unknown (empty values)

Catalog entry type 0x03

A catalog entry type 0x03 is 128 bytes in size and consists of:

OffsetSizeValueDescription
080x03Catalog entry type
88Store block list offset, which is relative to the start of the volume
1616Store identifier, which contains a GUID, that is used in the store filename
328Store header offset, which is relative to the start of the volume
408Store block range list offset, which is relative to the start of the volume
488Store (current) bitmap offset, which is relative to the start of the volume
568NTFS (metadata) file reference
648Unknown (Allocated size)
728Store previous bitmap offset, which is relative to the start of the volume or contains 0 if not used
808Unknown (store index?)
8840Unknown (empty)

Store

The store contains information about the shadow volume; it actually contains copies of previous versions of data blocks on the volume.

The stores must be applied starting with the most recent on top of the current volume. E.g. if there are 3 stores and we want to access the state of the oldest (number 1) we must first apply the changes in store 3 over the current volume, the changes in store 2 over the resulting volume, and finally the changes in store 1 over the resulting volume.

The store consists of:

  • store header
  • store block list
  • store block range list
  • store bitmaps
  • data blocks

Store block header

The store block header is 128 bytes in size and consists of:

OffsetSizeValueDescription
016volsnap identifier, which contains a GUID
1640x01Version
204Record type
248Relative (block) offset, which is relative to the start of the store
328Current (block) offset, which is relative to the start of the volume
408Next (block) offset, which is relative to the start of the volume or contains 0 if this is the last block
488Size of store information, whichis only used in first block header and should be 0 in successive block headers
5672Unknown (empty value)

Store block record types

ValueIdentifierDescription
0x0000Unknown
0x0001Volume header
0x0002Catalog block header
0x0003Block descriptor list (Diff area table)
0x0004Store header
0x0005Unknown (Store block ranges list)
0x0006Store bitmap

Store information

The store information is stored directly after the store header.

The store information is of variable size and consists of:

OffsetSizeValueDescription
016Unknown (identifier?), which contains a GUID
1616Shadow copy identifier, which contains a GUID
3216Shadow copy set identifier, which contains a GUID
484Snapshot context
524Unknown (Provider?)
564Attribute flags
604Unknown (empty values)
642Operating machine string size, in number of bytes
66(size)Operating machine string, which contains an UCS-2 little-endian string without end-of-string character
...2Service machine string size, in number of bytes
...(size)Service machine string, which contains an UCS-2 little-endian string without end-of-string character
......Unknown (empty value)

Note that the difference between the operating machine and the service machine is currently unknown.

Store snapshot context

ValueIdentifierDescription
0x00000000VSS_CTX_BACKUP (or Backup)Standard backup context
0x00000009VSS_CTX_APP_ROLLBACK (or ApplicationRollback)Persistent shadow copy
0x0000000dVSS_CTX_CLIENT_ACCESSIBLE_WRITERS (or ClientAccessibleWriters)Read-only shadow copy created with writer involvement
0x00000010VSS_CTX_FILE_SHARE_BACKUPNon-persistent shadow copy created
0x00000019VSS_CTX_NAS_ROLLBACKPersistent shadow copy of a NAS volume
0x0000001dVSS_CTX_CLIENT_ACCESSIBLERead-only shadow copy for Shared Folders
0xffffffffVSS_CTX_ALLAll types of shadow copy are available for administrative operations

Note that the store snapshot context value is a combination of (some of the) store attribute flags.

Store attribute flags

“VSS_VOLUME_SNAPSHOT_ATTRIBUTES enumeration (vss.h)” refers to the store attribute flags as _VSS_VOLUME_SNAPSHOT_ATTRIBUTES.

ValueIdentifierDescription
0x00000001VSS_VOLSNAP_ATTR_PERSISTENTThe shadow copy is persistent across reboots
0x00000002VSS_VOLSNAP_ATTR_NO_AUTORECOVERY (or VSS_VOLSNAP_ATTR_READ_WRITE)Auto-recovery is disabled, which appears to not be shown by vssadmin
0x00000004VSS_VOLSNAP_ATTR_CLIENT_ACCESSIBLEThe specified shadow copy is a client-accessible
0x00000008VSS_VOLSNAP_ATTR_NO_AUTO_RELEASEThe shadow copy is not automatically deleted when the shadow copy requester process ends (no auto release)
0x00000010VSS_VOLSNAP_ATTR_NO_WRITERSNo writers are involved in creating the shadow copy
0x00000020VSS_VOLSNAP_ATTR_TRANSPORTABLEThe shadow copy is to be transported and therefore should not be exposed locally
0x00000040VSS_VOLSNAP_ATTR_NOT_SURFACEDThe shadow copy is not currently exposed (surfaced)
0x00000080VSS_VOLSNAP_ATTR_NOT_TRANSACTEDNot transacted, which appears to not be shown by vssadmin
0x00010000VSS_VOLSNAP_ATTR_HARDWARE_ASSISTEDIndicates that a given provider is a hardware provider
0x00020000VSS_VOLSNAP_ATTR_DIFFERENTIALIndicates that a given provider uses differential data or a copy-on-write mechanism to implement shadow copies
0x00040000VSS_VOLSNAP_ATTR_PLEXIndicates that a given provider uses a PLEX or mirrored split mechanism to implement shadow copies
0x00080000VSS_VOLSNAP_ATTR_IMPORTEDThe shadow copy of the volume was imported onto this machine
0x00100000VSS_VOLSNAP_ATTR_EXPOSED_LOCALLYThe shadow copy is locally exposed
0x00200000VSS_VOLSNAP_ATTR_EXPOSED_REMOTELYThe shadow copy is remotely exposed
0x00400000VSS_VOLSNAP_ATTR_AUTORECOVERIndicates that the writer will need to auto-recover the on post snapshot
0x00800000VSS_VOLSNAP_ATTR_ROLLBACK_RECOVERYIndicates that the writer will need to auto-recover the on post snapshot if the snapshot is used for rollback
0x01000000VSS_VOLSNAP_ATTR_DELAYED_POSTSNAPSHOTDelayed post snapshot, which is reserved for system use and appears to not be shown by vssadmin
0x02000000VSS_VOLSNAP_ATTR_TXF_RECOVERYIndicates that Transactional NTFS (TxF) recovery should be enforced during shadow copy creation, which appears to be not shown by vssadmin

Store block list

The store block list contains information about the data block ranges used by the snapshot.

The store block list is stored in blocks of 16384 (0x4000) bytes. Each store block list block consists of:

  • a store block header of type 3
  • an array of store block descriptors

Block descriptor

The block descriptor is 32 bytes in size and consists of:

OffsetSizeValueDescription
08Original data block offset, which is relative to the start of the volume
88Relative store data block offset, which is relative to the start of the store. TODO: determine if the lower bits are used for different purpose
168Store data block offset, which is relative to the start of the volume
244Flags
284Allocation bitmap, which is used if flag 0x02 is set, otherwise is should contain a value of 0

Store block descriptor flags

ValueIdentifierDescription
0x00000001Is forwarder. The absolute offset is set to 0 and the relative offset maps to the original offset of the next block
0x00000002Overlay. The block descriptor is an overlay. The allocation bitmap value contains information about the block fill
0x00000004Not used. If set, the block is ignored
0x00000008Unknown
0x00000010Unknown
0x00000020Unknown
0x00000040Unknown
0x00000080Unknown

Successive block descriptors

Note that this section is not complete yet, since the meaning of several flags is unknown.

Successive block descriptors with the same original offset are be handled differently based on their flags and position in the block list. The block list is scanned front to back.

For the new block descriptor:

* If the not used flag is set (0x04):
    * Ignore the new block descriptor

* If the overlay flag (0x02) is not set:
    * If there is a corresponding block descriptor in the reverse block list:
      Meaning that the original offset (of the new block descriptor) matches
      the relative offset of a forwarder block descriptor in the reverse block
      list.
        * Replace the original offset with that of the forwarder block
          descriptor in the reverse block list.
        * Remove the forwarder block descriptor from the reverse block list.
        * If the forwarder flag (0x01) (of the new block descriptor) is set:
            * If the original offset (of the new block descriptor) is the same
              as the relative offset:
                * Ignore the new block descriptor

* If no previous block descriptor was found:
    * Add the new block descriptor to the block list.
* Else:
    * If the overlay flag (0x02) is set:
      The new block descriptor contains an overlay. The allocation bitmap
      contains information about which part of the block is used. Every bit
      in the allocation bitmap signifies a block of 512 bytes. The LSB in
      the allocation bitmap represent the first 512 bytes in the block.
      Normally the relative offset is should not be 1, but this seems to be
      ignored if it is.

        * If an existing overlay block descriptor was defined:
            * Extended the existing overlay.
              Normally the relative offset should be 1 and the original offset
              should match that of the existing overlay block descriptor. If
              not these values seem to be ignored and the existing overlay
              is extended with the allocation bitmap in the new block descriptor.
        * Else:
            * Replace the existing block descriptor. Existing overlay block
              descriptors are applied to the new block descriptor.

* If the forwarder flag (0x01) is set:
    * If no previous reverse block descriptor was found:
        * Add the new block descriptor to the reverse block list.
    * Else:
        * Replace the existing reverse block descriptor.

Store block range list

The store block range list contains information about the data block ranges used by the store itself. It is probably used to maintain these ranges on the volume layer, since the corresponding NTFS file entry data runs are applied on the file system layer.

The store block range list is stored in blocks of 16384 (0x4000) bytes. Each store block range list block consists of:

  • a store block header of type 5
  • an array of store block range list entries

Store block range entry

The store block range entry is 24 bytes in size and consists of:

OffsetSizeValueDescription
08Store (block range start) offset, which is relative to the start of the volume
88Relative (block range start) offset, which is relative to the start of the store
168Block range size

Store bitmap

The store bitmap contains information about the allocation of blocks.

The store bitmap is stored in blocks of 16384 (0x4000) bytes. Each store bitmap block consists of:

  • a store block header of type 6
  • a bitmap

Store (current) bitmap data

Every bit in the store (current) bitmap represents a block of 16384 (0x4000) bytes, where the LSB is the first bit in a byte.

If a bit is set, the corresponding block is considered not in-use (or not allocated) by the store.

The use of this bitmap is described in the section: reading snapshot data.

Store previous bitmap data

Every bit in the store previous bitmap represents a block of 16384 (0x4000) bytes, where the LSB is the first bit in a byte.

If a bit is set, the corresponding block is not in-use (or not allocated) by the previous store.

Note that the first store can also contain a previous bitmap if an older store before it was removed.

The use of this bitmap is described in the section: reading snapshot data.

Store data block

The store data is stored in blocks of 16384 (0x4000) bytes.

Reading snapshot data

For the size of the data that will fit in the buffer:

* If the block offset has a corresponding block descriptor:
    * The data is defined by block descriptor and has a maximum size accordingly
    * If this is the active store and the block has an overlay:
        * If the overlay applies:
            * use the overlay block descriptor

    * If the forwarder flag (0x01) is set
      and there is a next store:
        * read the block from the next store using the relative store offset
    * Else:
        * read the block from the current volume using the store offset

* Else:
    * If there is a next store:
        * read the block from the next store
    * Else if the block offset has a corresponding reverse block descriptor:
        * read the block from the current volume
    * Else if the active store is the most recent (last) store
      and the block is flagged in the current bitmap
      and ( the store has no previous bitmap
            or the block is flagged in the previous bitmap ):
        * zero-fill the block
    * Else:
        * read the block from the current volume

    * Increment the block offset with the size of the block data that was read

Note that on Windows the actual behavior of unused block is undefined. A read of a corresponding block will return successful but will not alter the buffer passed to the read. For sanitation purposes Keramics will zero-fill the block.

Format edge cases and corruption scenarios

This chapter contains several corruption scenarios that have been encountered “in the wild”.

Catalog volume size out of bounds

Note that this currently considered a corruption scenario future findings may or may not prove otherwise.

The volume size of one of the catalog entries exceeds the size of the underlying volume and does not corresponds with the volume size defined by the rest of the catalog entries.

Scope snapshots

Technically scoped snaphots are a feature of volsnapa as of of Windows 8 or Windws Server 2012 and not a corruption scenario. It has been captured as a corruption scenario since it leads to some interesting side effects within file content of the snapshot.

Scope snapshots functionality can be controlled via the Windows Registry value:

Key path: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\SystemRestore
Value name: ScopeSnapshots

Per “Scoped Snapshots vmicvss Error 13 on Server 2012, Windows 8” a scope snapshot is a special volume snapshot for volsnap performance, which is mainly used by Windows critical updates. Scope means the volsnap only creates Copy on Write (Shadow) volume for the files that are involved in the updates instead of all the files on the volume.

References

File system formats

A file system format is used to manage the storage of files.

Terminology

  • File entry (file system entry): an object that represent an element within the file system, such as a file or directory. A file system typically stores metadata of a file entry, such as the name, size, permissions, date and time values, and location of the content.
  • Data fork (or data stream): a file system object that represents the content of a file entry. NTFS and HFS support multiple data forks (or data streams) for an individual file entry.
  • Extended attribute: A file system object that represents additional (or extended) metadata of an individual file entry.
  • Reparse point: a file system object that redirects to another location or implementation (filter driver), such as Windows Overlay Filter (WOF) compression. NTFS and ReFS support reparse points.
  • Data range: a contiguous storage space, such as a file system extent or sequence of blocks or sectors. Can be compressed, encrypted or sparse.

Formats

Also see: hybrid volume and file system formats

Apple File System Compression (decmpfs)

Hierarchical File System (HFS) and Apple File System (APFS) use Apple File System Compression (decmpfs) to compress file contents.

decmpfs is sometimes referred to as AFSC (Apple File System Compression) or HFS/HFS+ compression and was introduced in Mac OS X 10.6 (Snow Leopard).

Overview

An Apple File System Compression (decmpfs) compressed file consists of:

  • an extended attribute named “com.apple.decmpfs”
  • compressed file content data

Characteristics

CharacteristicsDescription
Byte orderlittle-endian

decmpfs extended attribute

The decmpfs extended attribute consists of:

  • decmpfs header
  • optional compressed data

decmpfs header

The decmpfs header is 16 bytes in size and consists of:

OffsetSizeValueDescription
04"fpmc"Signature
44Compression method
88Uncompressed data size

Note that the signature is likely stored in little-endian and represents “cmpf”.

Compression methods

ValueIdentifierDescription
1CMP_Type1Unknown (uncompressed extended attribute data)
3kAFSCTypeZLibChunkzlib compressed extended attribute data, where the compressed data is stored in the extended attribute after the compressed data header
4kAFSCTypeZLib64k chunked zlib compressed resource fork, where the compressed data is stored in the resource fork
5Unknown (sparse compressed extended attribute data), where the uncompressed data contains 0-byte values. According to copyfile.c specifies de-dup within the generation store
6Unknown (unused)
Added in Mac OS X Yosemite (10.10)
7kAFSCTypeLZVNChunkLZVN compressed extended attribute data, where the compressed data is stored in the extended attribute after the compressed data header
8kAFSCTypeLZVN64k chunked LZVN compressed resource fork, where the compressed data is stored in the resource fork
9kAFSCTypeRawChunkUncompressed (raw) extended attribute data
10kAFSCTypeRaw64k chunked uncompressed (raw) data resource fork, where the compressed data is stored in the resource fork
Added in Mac OS X El Capitan (10.11)
11kAFSCTypeLZFSEChunkLZFSE compressed extended attribute data, where the compressed data is stored in the extended attribute after the compressed data header
12kAFSCTypeLZFSE64k chunked LZFSE compressed resource fork, where the compressed data is stored in the resource fork
Added in macOS Ventura (13.0)
13kAFSCTypeLZBitmapChunkLZBITMAP compressed extended attribute data, where the compressed data is stored in the extended attribute after the compressed data header
14kAFSCTypeLZBitmapLZBITMAP compressed resource fork, where the compressed data is stored in the resource fork
255CMP_MAXMaximum supported compression method
0x80000001DATALESS_CMPFS_TYPEUnknown (faulting file or dataless file or directory)
0x80000002DATALESS_PKG_CMPFS_TYPEUnknown (dataless package)

Note that copyfile.c indicates faulting files are deprecated since Mac OS X Yosemite (10.10).

Compressed file content data

The location of the compressed file content data depends on the compression method:

  • sparse data
  • compressed data stored in extended attribute
  • compressed data stored in resource fork

Sparse data

Compression method 5 has been observed to be used for sparse data, the file content data contains 0-byte values.

There are 12 bytes stored after the decmpfs compressed data header that consists of:

OffsetSizeValueDescription
04Unknown (Seen: 1)
44Unknown
84Unknown (Seen: 0)

Compressed data stored in extended attribute

Compression method 3, 5, 7, 9 and 11 store the compressed file content data in the extended attribute after the decmpfs compressed data header.

The compressed data consist of 1 compressed data block.

Compressed data stored in resource fork

Compression method 4, 8, 10 and 12 store the compressed file content data in the resource fork of the file.

The compressed data starts with metadata that contains the offsets of the compressed data blocks.

LZFSE compressed data

OffsetSizeValueDescription
04 x ...Array of compressed data block offsets, where an offset is relative from the start of the LZFSE compressed data
......LZFSE compressed data blocks

LZFSE compressed data block

If the first byte in the LZFSE compressed data block is 0xff, the block contains uncompressed data, otherwise the block should start with a LZFSE block marker.

LZVN compressed data

OffsetSizeValueDescription
04 x ...Array of compressed data block offsets, where an offset is relative from the start of the LZVN compressed data
......LZVN compressed data blocks

LZVN compressed data block

If the first byte in the LZVN compressed data block is 0x06 (end of stream oppcode), the block contains uncompressed data.

A compressed data block can contains a maximum of 65536 bytes of data. The compressed data block therefore should not exceed 65537 bytes in size.

Raw compressed data

OffsetSizeValueDescription
04 x ...Array of compressed data block offsets, where an offset is relative from the start of the raw compressed data
......raw compressed data blocks

Raw compressed data block

If the first byte in the raw compressed data block is 0xcc, the block contains uncompressed data.

The behavior of other byte values is unknown, it has been observed that Mac OS returns no data.

zlib compressed data

  • zlib compressed header
  • zlib compressed data block descriptors
  • zlib compressed data blocks
  • zlib compressed footer

zlib compressed header

The zlib compressed header is 260 bytes size and consists of:

OffsetSizeValueDescription
04256Unknown (header size or offset?)
44Compressed footer offset, where the offset is relative from the start of the zlib compressed data
84Unknown (total size - header size?)
12450Compressed footer size
16240Unknown (empty values)
2564Unknown

Note that the values in the zlib compressed header are stored in big-endian.

zlib compressed data block descriptors

The zlib compressed data block descriptors are variable size and consist of:

OffsetSizeValueDescription
04Number of block descriptors (offset and size tuples)
48 x ...Array of compressed data block descriptors

Note that the values in the zlib compressed data block descriptors are store in little-endian.

zlib compressed data block descriptor

The zlib compressed data block descriptor is 8 bytes in size and consists of:

OffsetSizeValueDescription
04Compressed block offset, where the offset is relative from the start of the zlib compressed data block descriptors
44Compressed block size

The zlib compressed footer is 50 bytes size and consists of:

OffsetSizeValueDescription
024Unknown (empty values)
242Unknown (signature offset?)
262Unknown (footer size?)
282Unknown
304"cmpf"signature (DECMPFS_MAGIC)
342Unknown (empty values?)
362Unknown
382Unknown
402Unknown (uncompressed block size?)
428Unknown (empty values)

Note that the values in the zlib compressed header are stored in big-endian.

zlib compressed data block

If the first byte in the zlib compressed data block is 0xff, the block contains uncompressed data, otherwise the block should start with 0x78.

Extended File System (ext) format

The Extended File System (ext) is one of the more common file system used in Linux.

There are multiple version of ext.

VersionRemarks
1Introduced in April 1992
2Introduced in January 1993
3Introduced in November 2001, which featured journaling, dynamic growth and large directory indexing (HTree)
4Introduces in October 2006 as unstable and becmae stable in October 2008, which featured extents and improved timestamps

Overview

An Extended File System (ext) consists of:

  • one or more block groups

Characteristics

CharacteristicsDescription
Byte orderlittle-endian, with the exception of UUID values that are stored in big-endian
Date and time valuesnumber of seconds since January 1, 1970 00:00:00 (POSIX epoch), disregarding leap seconds. Or number of nanoseconds, when extra precision is enabled. Date and time values are stored in UTC
Character stringsUTF-8 or a narrow character (Single Byte Character (SBC) or Multi Byte Character (MBC)) stored using a system defined codepage

Block group

A block group consists of:

  • optional 1024 bytes of boot code or zero bytes (at offset: 0)
  • optional superblock
  • optional group descriptor table
  • block bitmap
  • inode bitmap
  • allocated and unallocated blocks

The primary superblock is stored at offset 1024 relative from the start of the volume. Backup superblocks are stored at offset 1024 relative from the start of the block group if block size <= 1024 or otherwise at offset 0 from the start of the block group.

The group descriptor table is stored in the block after the superblock.

An ext2 file system with revision 0 stores a copy at the start of every block group, along with backups of the group descriptor table. Later revisions reduce the number of backup copies by only putting backups in specific groups (sparse superblock feature EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER).

Not all values in a backup superblock and backup group descriptor tables match those of the primary superblock and group descriptor table.

Note that backup superblocks can be empty (filled with 0-byte values) or contain remnant data on an Android ext file system with sparse_super.

Flex block groups

Flex (or flexible) block groups are a set of block groups that treated as a single logical block group. Metadata such as the superblock, group descriptors, data block bitmaps spans the entire logical block group and not the individual block groups part of the set.

Meta block groups

Meta block groups (META_BG) are a set (or cluster) of block groups, for which its group descriptor structures can be stored in a single block.

The first meta block group value in the superblock indicates what the first meta block group is to cluster as a meta block group. For example if the first meta block group value is 256, and the number of group descriptors that can be stored in a single block 64, then the group descriptors for the block groups [0, 16383] are stored in the group descriptor table after the primary superblock and corresponding locations of backups.

Successive group descriptor tables, for example [16384, 16447], are stored in the first block group of a meta block group and backups in the second and last block groups of the meta block group.

Blocks

The volume is devided in blocks:

block offset = block number * block size

The block size is defined in the superblock.

Note that mke2fs indicates the maximum block size is 65536.

The superblock

The ext2 superblock

The ext2 superblock is 208 bytes in size and consists of:

OffsetSizeValueDescription
04Number of inodes
44Number of blocks
84Number of reserved blocks. Reserved blocks are used to prevent the file system from filling up
124Number of unallocated blocks
164Number of unallocated inodes
204First data block number. The block number is relative from the start of the volume
244Block size, which contains the number of bits to shift 1024 to the MSB (left)
284Fragment size, which contains the number of bits to shift 1024 to the MSB (left)
324Number of blocks per block group
364Number of fragments per block group
404Number of inodes per block group
444Last mount time, which contains the number of seconds since January 1, 1970 00:00:00 UTC (POSIX epoch)
484Last written time, which contains the number of seconds since January 1, 1970 00:00:00 UTC (POSIX epoch)
522The (current) mount count
542Maximum mount count
562"\x53\xef"Signature
582File system state flags
602Error-handling status
622Minor format revision
644Last consistency check time, which contains the number of seconds since January 1, 1970 00:00:00 UTC (POSIX epoch)
684Consistency check interval, which which contains the number of seconds since January 1, 1970 00:00:00 UTC (POSIX epoch)
724Creator operating system
764Format revision
802Reserved block owner (or user) identifier (UID)
822Reserved block group identifier (GID)
Dynamic inode information, if major version is EXT2_DYNAMIC_REV
844First non-reserved inode
882Inode size. Note that the inode size must be a power of 2 larger or equal to 128, the maximum supported by mke2fs is 1024
902Block group, which contains a block group number
924Compatible feature flags
964Incompatible feature flags
1004Read-only compatible feature flags
10416File system identifier, which contains a big-endian UUID
12016Volume label, which contains a narrow character string without end-of-string character
13664Last mount path, which contains a narrow character string without end-of-string character
2004Algorithm usage bitmap
Performance hints, if EXT2_COMPAT_PREALLOC is set
2041Number of pre-allocated blocks per file
2051Number of pre-allocated blocks per directory
2062Unknown (padding)

The ext3 superblock

The ext3 superblock is 336 bytes in size and consists of:

OffsetSizeValueDescription
04Number of inodes
44Number of blocks
84Number of reserved blocks. Reserved blocks are used to prevent the file system from filling up
124Number of unallocated blocks
164Number of unallocated inodes
204First data block number. The block number is relative from the start of the volume
244Block size, which contains the number of bits to shift 1024 to the MSB (left)
284Fragment size, which contains the number of bits to shift 1024 to the MSB (left)
324Number of blocks per block group
364Number of fragments per block group
404Number of inodes per block group, which can be 0 in combination with EXT3_FEATURE_INCOMPAT_JOURNAL_DEV
444Last mount time, which contains the number of seconds since January 1, 1970 00:00:00 UTC (POSIX epoch)
484Last written time, which contains the number of seconds since January 1, 1970 00:00:00 UTC (POSIX epoch)
522The (current) mount count
542Maximum mount count
562"\x53\xef"Signature
582File system state flags
602Error-handling status
622Minor format revision
644Last consistency check time, which contains the number of seconds since January 1, 1970 00:00:00 UTC (POSIX epoch)
684Consistency check interval, which which contains the number of seconds since January 1, 1970 00:00:00 UTC (POSIX epoch)
724Creator operating system
764Format revision
802Reserved block owner (or user) identifier (UID)
822Reserved block group identifier (GID)
Dynamic inode information, if major version is EXT2_DYNAMIC_REV
844First non-reserved inode
882Inode size. Note that the inode size must be a power of 2 larger or equal to 128, the maximum supported by mke2fs is 1024
902Block group, which contains a block group number
924Compatible feature flags
964Incompatible feature flags
1004Read-only compatible feature flags
10416File system identifier, which contains a big-endian UUID
12016Volume label, which contains a narrow character string without end-of-string character
13664Last mount path, which contains a narrow character string without end-of-string character
2004Algorithm usage bitmap
Performance hints, if EXT2_COMPAT_PREALLOC is set
2041Number of pre-allocated blocks per file
2051Number of pre-allocated blocks per directory
2062Unknown (padding)
Journalling support, if EXT3_FEATURE_COMPAT_HAS_JOURNAL is set
20816Journal identifier, which contains a big-endian UUID
2244Journal inode
2284Unknown (Journal device)
2324Unknown (Head of orphan inode list). The orphan inode list is a list of inodes to delete
2364 x 4hash-tree seed
2521Default hash version
2531Journal backup type
2542Group descriptor size
2564Default mount options
2604First meta block group (or metablock)
2644File system creation time, which contains the number of seconds since January 1, 1970 00:00:00 UTC (POSIX epoch)
26817 x 4Backup journal inodes

The ext4 superblock

The superblock is 1024 bytes in size and consists of:

OffsetSizeValueDescription
04Number of inodes
44Number of blocks, which contains the lower 32-bit of the value
84Number of reserved blocks, which contains the lower 32-bit of the value. Reserved blocks are used to prevent the file system from filling up
124Number of unallocated blocks, which contains the lower 32-bit of the value
164Number of unallocated inodes, which contains the lower 32-bit of the value
204Root group block number. The block number is relative from the start of the volume
244Block size, which contains the number of bits to shift 1024 to the most-significant-bit (MSB)
284Fragment size, which contains the number of bits to shift 1024 to the most-significant-bit (MSB)
324Number of blocks per block group
364Number of fragments per block group
404Number of inodes per block group, which can be 0 in combination with EXT4_FEATURE_INCOMPAT_JOURNAL_DEV
444Last mount time, which contains the number of seconds since January 1, 1970 00:00:00 UTC (POSIX epoch)
484Last written time, which contains the number of seconds since January 1, 1970 00:00:00 UTC (POSIX epoch)
522The (current) mount count
542Maximum mount count
562"\x53\xef"Signature
582File system state flags
602Error-handling status
622Minor format revision
644Last consistency check time, which contains the number of seconds since January 1, 1970 00:00:00 UTC (POSIX epoch)
684Consistency check interval, which which contains the number of seconds since January 1, 1970 00:00:00 UTC (POSIX epoch)
724Creator operating system
764Format revision
802Reserved block owner (or user) identifier (UID)
822Reserved block group identifier (GID)
Dynamic inode information, if major version is EXT2_DYNAMIC_REV
844First non-reserved inode
882Inode size. Note that the inode size must be a power of 2 larger or equal to 128, the maximum supported by mke2fs is 1024
902Block group
924Compatible feature flags
964Incompatible feature flags
1004Read-only compatible feature flags
10416File system identifier, which contains a big-endian UUID
12016Volume label, which contains a narrow character string without end-of-string character
13664Last mount path, which contains a narrow character string without end-of-string character
2004Algorithm usage bitmap
Performance hints, if EXT2_COMPAT_PREALLOC is set
2041Number of pre-allocated blocks per file
2051Number of pre-allocated blocks per directory
2062Unknown (padding)
Journalling support, if EXT3_FEATURE_COMPAT_HAS_JOURNAL is set
20816Journal identifier, which contains a big-endian UUID
2244Journal inode
2284Unknown (Journal device)
2324Unknown (Head of orphan inode list). The orphan inode list is a list of inodes to delete
2364 x 4hash-tree seed
2521Default hash version
2531Journal backup type
2542Group descriptor size
2564Default mount options
2604First meta block group (or metablock)
2644File system creation time, which contains the number of seconds since January 1, 1970 00:00:00 UTC (POSIX epoch)
26817 x 4Backup journal inodes
If 64-bit support (EXT4_FEATURE_INCOMPAT_64BIT) is enabled
3364Number of blocks, which contains the upper 32-bit of the value
3404Number of reserved blocks, which contains the upper 32-bit of the value
3444Number of unallocated blocks, which contains the upper 32-bit of the value
3482Minimum inode size
3502Reserved inode size
3524Miscellaneous flags
3562RAID stride
3582Multiple mount protection (MMP) update interval in seconds
3608Block for multi-mount protection
3684Unknown (blocks on all data disks (N*stride))
3721Number of block groups per flex block group, which is stored as: 2 ^ value
3731Checksum type
3741Unknown (encryption level)
3751Unknown (padding)
3768Unknown (s_kbytes_written)
3844Inode number of active snapshot
3884Identifier of active snapshot
3928Unknown (reserved s_snapshot_r_blocks_count)
4004Inode number of snapshot list head
4044Unknown (s_error_count)
4084Unknown (s_first_error_time)
4124Unknown (s_first_error_ino)
4168Unknown (s_first_error_block)
42432Unknown (s_first_error_func)
4564Unknown (s_first_error_line)
4604Unknown (s_last_error_time)
4644Unknown (s_last_error_ino)
4684Unknown (s_last_error_line)
4728Unknown (s_last_error_block)
48032Unknown (s_last_error_func)
51264Unknown (s_mount_opts)
5764Unknown (s_usr_quota_inum)
5804Unknown (s_grp_quota_inum)
5844Unknown (s_overhead_clusters)
5882 x 4Unknown (s_backup_bgs)
5964Unknown (s_encrypt_algos)
60016Unknown (s_encrypt_pw_salt)
6164Unknown (s_lpf_ino)
6204Unknown (s_prj_quota_inum)
6244Metadata checksum seed
6281Unknown (s_wtime_hi)
6291Unknown (s_mtime_hi)
6301Unknown (s_mkfs_time_hi)
6311Unknown (s_lastcheck_hi)
6321Unknown (s_first_error_time_hi)
6331Unknown (s_last_error_time_hi)
6341Unknown (s_first_error_errcode)
6351Unknown (s_last_error_errcode)
6362Unknown (s_encoding)
6382Unknown (s_encoding_flags)
6404Unknown (s_orphan_file_inum)
64494 x 4 = 376Unknown (reserved)
10204Checksum

If checksum type is CRC-32C, the checksum is stored as 0xffffffff - CRC-32C.

Note that some versions of mkfs.ext set the file system creation time even for ext2 and when EXT3_FEATURE_COMPAT_HAS_JOURNAL is not set.

TODO: Is the only way to determine the file system version the compatibility and equivalent flags?

Checksum calculation

If checksum type is CRC-32C, the CRC32-C algorithm with the Castagnoli polynomial (0x1edc6f41) and initial value of 0 is used to calculate the checksum.

The checksum is calculated over the 1020 bytes of data of the suberblock.

Metadata checksum seed calculation

If checksum type is CRC-32C, the CRC32-C algorithm with the Castagnoli polynomial (0x1edc6f41) and initial value of 0 is used to calculate the checksum.

The checksum is calculated over:

  • the 16 byte file system identifier in the superblock

If EXT4_FEATURE_INCOMPAT_CSUM_SEED is set the metadata checksum seed value stored in the superblock should be used instead of calculating it based on the file system identifier.

If checksum type is CRC-32C, the metadata checksum seed is stored as:

0xffffffff - CRC-32C

File system state flags

ValueIdentifierDescription
0x0001Is clean
0x0002Has errors
0x0004Recovering orphan inodes

Error-handling status

ValueIdentifierDescription
1Continue
2Remount as read-only
3Panic

Creator operating system

ValueIdentifierDescription
0Linux
1GNU Hurd
2Masix
3FreeBSD
4Lites

Format revision

ValueIdentifierDescription
0EXT2_GOOD_OLD_REVOriginal version with a fixed inode size of 128 bytes
1EXT2_DYNAMIC_REVVersion with dynamic inode size support

Compatible feature flags

ValueIdentifierDescription
0x00000001EXT2_COMPAT_PREALLOCPre-allocate directory blocks, which is intended to reduce fragmentation
0x00000002EXT2_FEATURE_COMPAT_IMAGIC_INODESHas AFS server inodes
0x00000004EXT3_FEATURE_COMPAT_HAS_JOURNALHas a journal
0x00000008EXT2_FEATURE_COMPAT_EXT_ATTRHas extended attributes
0x00000010EXT2_FEATURE_COMPAT_RESIZE_INO, EXT2_FEATURE_COMPAT_RESIZE_INODEIs resizeable, the file system has reserved GDT blocks for expansion, which also requires RO_COMPAT_SPARSE_SUPER
0x00000020EXT2_FEATURE_COMPAT_DIR_INDEXHas indexed directories
0x00000040COMPAT_LAZY_BGUnknown (Lazy block group)
0x00000080COMPAT_EXCLUDE_INODEUnknown (Exclude inode), which is not yet implemented and intended for a future file system snapshot feature
0x00000100COMPAT_EXCLUDE_BITMAPUnknown (Exclude bitmap), which is not yet implemented and intended for a future file system snapshot feature
0x00000200EXT4_FEATURE_COMPAT_SPARSE_SUPER2Has sparse superblock version 2
0x00000400EXT4_FEATURE_COMPAT_FAST_COMMITUnknown (fast commit)
0x00000800EXT4_FEATURE_COMPAT_STABLE_INODESUnknown (stable inodes)
0x00001000EXT4_FEATURE_COMPAT_ORPHAN_FILEHas orphan file

Note that EXT2_FEATURE_COMPAT_, EXT3_FEATURE_COMPAT_, EXT4_FEATURE_COMPAT_ and COMPAT_ can be used interchangeably.

Incompatible feature flags

ValueIdentifierDescription
0x00000001EXT2_FEATURE_INCOMPAT_COMPRESSIONHas compression, which is not yet implemented
0x00000002EXT2_FEATURE_INCOMPAT_FILETYPEDirectory entry has file type
0x00000004EXT3_FEATURE_INCOMPAT_RECOVERNeeds recovery
0x00000008EXT3_FEATURE_INCOMPAT_JOURNAL_DEVJournal device
0x00000010EXT2_FEATURE_INCOMPAT_META_BGHas meta (or metadata) block groups
0x00000040EXT4_FEATURE_INCOMPAT_EXTENTSHas extents
0x00000080EXT4_FEATURE_INCOMPAT_64BITHas 64-bit support, which supports more than 2^32 blocks
0x00000100EXT4_FEATURE_INCOMPAT_MMPMultiple mount protection
0x00000200EXT4_FEATURE_INCOMPAT_FLEX_BGHas flex (or flexible) block groups
0x00000400EXT4_FEATURE_INCOMPAT_EA_INODEHas large inodes, which are larger than 128 bytes
0x00001000EXT4_FEATURE_INCOMPAT_DIRDATAData in directory entry, which is not yet implemented
0x00002000EXT4_FEATURE_INCOMPAT_CSUM_SEED, EXT4_FEATURE_INCOMPAT_BG_USE_META_CSUMInitial metadata checksum value (or seed) is stored in the superblock
0x00004000EXT4_FEATURE_INCOMPAT_LARGEDIRLarge directory >2GB or 3-level hash tree (HTree)
0x00008000EXT4_FEATURE_INCOMPAT_INLINE_DATAHas data stored in inode
0x00010000EXT4_FEATURE_INCOMPAT_ENCRYPTHas encrypted inodes
0x00020000EXT4_FEATURE_INCOMPAT_CASEFOLDHash case folding

Note that EXT2_FEATURE_INCOMPAT_, EXT3_FEATURE_INCOMPAT_, EXT4_FEATURE_INCOMPAT_ and INCOMPAT_ can be used interchangeably.

Read-only compatible feature flags

ValueIdentifierDescription
0x00000001EXT2_FEATURE_RO_COMPAT_SPARSE_SUPERHas sparse superblocks and group descriptor tables. If set a superblock is stored in block groups 0, 1 and those that are powers of 3, 5 and 7. If not set a superblock is stored in every block group
0x00000002EXT2_FEATURE_RO_COMPAT_LARGE_FILEContains large files
0x00000004EXT2_FEATURE_RO_COMPAT_BTREE_DIRIntended for hash-tree directory (or directory B-tree), which is not yet implemented
0x00000008EXT4_FEATURE_RO_COMPAT_HUGE_FILEHas huge file support
0x00000010EXT4_FEATURE_RO_COMPAT_GDT_CSUMHas group descriptors with checksums
0x00000020EXT4_FEATURE_RO_COMPAT_DIR_NLINKThe ext3 32000 subdirectory limit does not apply. A directory's number of links will be set to 1 if it is incremented past 64999
0x00000040EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZEHas large inodes. The size of an inode can be larger than 128 bytes
0x00000080EXT4_FEATURE_RO_COMPAT_HAS_SNAPSHOTHas snapshots, which is not yet implemented and intended for a future file system snapshot feature
0x00000100EXT4_FEATURE_RO_COMPAT_QUOTAQuota is handled transactionally with the journal
0x00000200EXT4_FEATURE_RO_COMPAT_BIGALLOCHas big block allocation bitmaps. Block allocation bitmaps are tracked in units of clusters (of blocks) instead of blocks
0x00000400EXT4_FEATURE_RO_COMPAT_METADATA_CSUMFile system metadata has checksums
0x00000800EXT4_FEATURE_RO_COMPAT_REPLICASupports replicas
0x00001000EXT4_FEATURE_RO_COMPAT_READONLYRead-only file system image
0x00002000EXT4_FEATURE_RO_COMPAT_PROJECTFile system tracks project quotas
0x00004000EXT4_FEATURE_RO_COMPAT_SHARED_BLOCKSFile system has (read-only) shared blocks
0x00008000EXT4_FEATURE_RO_COMPAT_VERITYUnknown (Verity inodes may be present on the filesystem)
0x00010000EXT4_FEATURE_RO_COMPAT_ORPHAN_PRESENTOrphan file may be non-empty

Note that EXT2_FEATURE_RO_COMPAT_, EXT3_FEATURE_RO_COMPAT_, EXT4_FEATURE_RO_COMPAT_ and RO_COMPAT_ are used interchangeably.

In some ext file systems, such as those used by ChromeOS, it has been observed that the upper 8-bits of the read-only compatible feature flags are set as in 0xff000003. debugfs identifies these as FEATURE_R24 - FEATURE_R31.

Checksum types

ValueIdentifierDescription
1EXT4_CRC32C_CHKSUMCRC-32C (or CRC32-C), which uses the Castagnoli polynomial (0x1edc6f41)

The group descriptor table

The group descriptor table is stored in the block following the superblock.

The group descriptor table consist of:

  • one or more group descriptors

The ext2 and ext3 group descriptor

The ext2 and ext3 group descriptor is 32 bytes in size and consists of:

OffsetSizeValueDescription
04Block bitmap block number. The block number is relative from the start of the volume
44Inode bitmap block number. The block number is relative from the start of the volume
84Inode table block number. The block number is relative from the start of the volume
122Number of unallocated blocks
142Number of unallocated inodes
162Number of directories
182Unknown (padding)
203 x 4Unknown (reserved)

Note that it has been observed that implementations that support ext4 can set a value in the padding. It is currently assumed that this value contains block group flags.

The ext4 group descriptor

The ext4 group descriptor is 68 bytes in size and consists of:

OffsetSizeValueDescription
04Block bitmap block number, which contains the lower 32-bit of the value. The block number is relative from the start of the volume
44Inode bitmap block number, which contains the lower 32-bit of the value. The block number is relative from the start of the volume
84Inode table block number, which contains the lower 32-bit of the value. The block number is relative from the start of the volume
122Number of unallocated blocks, which contains the lower 16-bit of the value
142Number of unallocated inodes, which contains the lower 16-bit of the value
162Number of directories, which contains the lower 16-bit of the value
182Block group flags
204Exclude bitmap block number, which contains the lower 32-bit of the value. The block number is relative from the start of the volume
242Block bitmap checksum, which contains the lower 16-bit of the value
262Inode bitmap checksum, which contains the lower 16-bit of the value
282Number of unused inodes, which contains the lower 16-bit of the value
302Checksum
If 64-bit support (EXT4_FEATURE_INCOMPAT_64BIT) is enabled and group descriptor size > 32
324Block bitmap block number, which contains the upper 32-bit of the value. The block number is relative from the start of the volume
364Inode bitmap block number, which contains the upper 32-bit of the value. The block number is relative from the start of the volume
404Inode table block number, which contains the upper 32-bit of the value. The block number is relative from the start of the volume
442Number of unallocated blocks, which contains the upper 16-bit of the value
462Number of unallocated inodes, which contains the upper 16-bit of the value
482Number of directories, which contains the upper 16-bit of the value
502Number of unused inodes, which contains the upper 16-bit of the value
524Exclude bitmap block number, which contains the upper 32-bit of the value. The block number is relative from the start of the volume
562Block bitmap checksum, which contains the upper 16-bit of the value
602Inode bitmap checksum, which contains the upper 16-bit of the value
644Unknown (padding)

If checksum type is CRC-32C, the checksum is stored as the lower 16-bits of 0xffffffff - CRC-32C, otherwise the checksum is stored as a CRC-16.

Checksum calculation

If checksum type is CRC-32C, the CRC32-C algorithm with the Castagnoli polynomial (0x1edc6f41) and initial value of 0 is used to calculate the checksum.

The checksum is calculated over:

  • the 16 byte file system identifier in the superblock
  • the group number as a 32-bit little-endian integer
  • the data of the group descriptor with the checksum set to 0-byte values

TODO: describe the block bitmap checksum calculation: crc32c(s_uuid+grp_num+bbitmap)

TODO: describe the inode bitmap checksum calculation: crc32c(s_uuid+grp_num+ibitmap)

Block group flags

ValueIdentifierDescription
0x0001EXT4_BG_INODE_UNINITThe inode table and bitmap are not initialized
0x0002EXT4_BG_BLOCK_UNINITThe block bitmap is not initialized
0x0004EXT4_BG_INODE_ZEROEDThe inode table is filled with 0

Direct and indirect blocks

Direct blocks are blocks that part of the data stream of a file entry.

A direct block number is 0 that is part of the data stream represents a sparse data block.

Indirect blocks are blocks that refer to blocks containing direct or indirect block numbers. There are multiple levels of indirect block:

  • indirect blocks (level 1), that refer to direct blocks
  • double indirect blocks (level 2), that refer to indirect blocks
  • triple indirect blocks (level 3), that refer to double indirect blocks

An indirect block number is 0 that is part of the data stream represents sparse data blocks.

Extents

Extents were introduced in ext4 and are controlled by EXT4_FEATURE_INCOMPAT_EXTENTS.

Extents form an extent B-tree, where:

An extents B-tree node consists of:

  • extents header
  • extents entries
  • extents footer

Note that inodes can have an implicit last sparse extent if the the inode data size is greater than the total data size defined by the extent descriptors.

The ext4 extents header

The ext4 extents header (ext4_extent_header) is 12 bytes in size and consists of:

OffsetSizeValueDescription
02"\x0a\xf3"Signature
22Number of entries
42Maximum number of entries
62Depth, where 0 reprensents a leaf node and 1 to 5 different levels of branch nodes
84Generation, which is used by Lustre, but not by standard ext4

The ext4 extent descriptor

The ext4 extent descriptor (ext4_extent) is 12 bytes in size and consists of:

OffsetSizeValueDescription
04Logical block number
42Number of blocks
62Upper 16-bits of physical block number
84Lower 32-bits of physical block number

If number of blocks > 32768 the extent is considered “uninitialized” which is (as far as currently known) comparable to extent being sparse. The number of blocks of the sparse extent can be determined as following:

sparse_number_of_blocks = number_of_blocks - 32768

Sparse extents can exist between the extent descriptors. In such a case the logical block number will not align with the information from the previous extent descriptors.

Note that the native Linux ext implementation expects the extents to be stored in order of logical block number.

The ext4 extents index

The ext4 extent index (ext4_extent_idx) is 12 bytes in size and consists of:

OffsetSizeValueDescription
04Logical block number, which contains the first logical block number of next depth extents block
44Lower 32-bits of physical block number, which contains the block number of the next depth extents block
82Upper 16-bits of physical block number, which contains the block number of the next depth extents block
102Unknown (unused)

The ext4 extents footer (ext4_extent_tail) is 4 bytes in size and consists of:

OffsetSizeValueDescription
04Checksum of an extents block, which contains a CRC32

The inode

The size of the inode is defined in the superblock when dynamic inode information is present.

Note that the ext4 inode format can be used on ext2 formatted file system. This was observed in combination with format revision 1 and inode size > 128 created by mkfs.ext2.

The ext2 inode

The ext2 inode is 128 bytes in size and consists of:

OffsetSizeValueDescription
02File mode, which contains file type and permissions
22Lower 16-bits of owner (or user) identifier (UID)
44Data size
84(last) access time, which contains the number of seconds since January 1, 1970 00:00:00 UTC (POSIX epoch)
124(last) inode change (or modification) time, which contains the number of seconds since January 1, 1970 00:00:00 UTC (POSIX epoch)
164(last) content modification time, which contains the number of seconds since January 1, 1970 00:00:00 UTC (POSIX epoch)
204Deletion time, which contains the number of seconds since January 1, 1970 00:00:00 UTC (POSIX epoch)
242Lower 16-bits of group identifier (GID)
262Number of (hard) links
284Numer of blocks
324Flags
364Unknown (reserved)
4012 x 4Array of direct block numbers. A block number is relative from the start of the volume
884Indirect block number. A block number is relative from the start of the volume
924Double indirect block number. A block number is relative from the start of the volume
964Triple indirect block number. A block number is relative from the start of the volume
1004NFS generation number
1044File ACL (or extended attributes) block number
1084Unknown (Directory ACL)
1124Fragment block address
1161Fragment block index
1171Fragment size
1182Unknown (padding)
1202Upper 16-bits of owner (or user) identifier (UID)
1222Upper 16-bits of group identifier (GID)
1244Unknown (reserved)

Note that for a character and block device the first 2 bytes of the array of direct block numbers contain the minor and major device number respectively.

If the inode size is larger than 128 bytes, the additional data can be stored using an ext4 inode extension.

The ext3 inode

The ext3 inode is 132 bytes in size and consists of:

OffsetSizeValueDescription
02File mode, which contains file type and permissions
22Lower 16-bits of owner (or user) identifier (UID)
44Data size
84(last) access time, which contains the number of seconds since January 1, 1970 00:00:00 UTC (POSIX epoch)
124(last) inode change (or modification) time, which contains the number of seconds since January 1, 1970 00:00:00 UTC (POSIX epoch)
164(last) content modification time, which contains the number of seconds since January 1, 1970 00:00:00 UTC (POSIX epoch)
204Deletion time, which contains the number of seconds since January 1, 1970 00:00:00 UTC (POSIX epoch)
242Lower 16-bits of group identifier (GID)
262Number of (hard) links
284Numer of blocks
324Flags
364Unknown (reserved)
4012 x 4Array of direct block numbers. A block number is relative from the start of the volume
884Indirect block number. A block number is relative from the start of the volume
924Double indirect block number. A block number is relative from the start of the volume
964Triple indirect block number. A block number is relative from the start of the volume
1004NFS generation number
1044File ACL (or extended attributes) block number
1084Unknown (Directory ACL)
1124Fragment block address
1161Fragment block index
1171Fragment size
1182Unknown (padding)
1202Upper 16-bits of owner (or user) identifier (UID)
1222Upper 16-bits of group identifier (GID)
1244Unknown (reserved)
Extension (if inode size > 128)
1282Extended inode size
1302Unknown (padding)

Note that for a character and block device the first 2 bytes of the array of direct block numbers contain the minor and major device number respectively.

If the inode size is larger than 128 bytes, the additional data can be stored using an ext4 inode extension.

The ext4 inode

The ext4 inode is 160 bytes in size and consists of:

OffsetSizeValueDescription
02File mode, which contains file type and permissions
22Lower 16-bits of owner (or user) identifier (UID)
44Lower 32-bits of data size
If EXT4_EA_INODE_FL is not set
84(last) access time, which contains the number of seconds since January 1, 1970 00:00:00 UTC (POSIX epoch)
124(last) inode change (or modification) time, which contains the number of seconds since January 1, 1970 00:00:00 UTC (POSIX epoch)
164(last) content modification time, which contains the number of seconds since January 1, 1970 00:00:00 UTC (POSIX epoch)
If EXT4_EA_INODE_FL is set
84Unknown (extended attribute value data checksum)
124Unknown (lower 32-bits of extended attribute reference count)
164Unknown (inode number that owns the extended attribute)
Common
204Deletion time, which contains the number of seconds since January 1, 1970 00:00:00 UTC (POSIX epoch)
242Lower 16-bits of group identifier (GID)
262Number of (hard) links
284Lower 32-bits of number of blocks
324Flags
If EXT4_EA_INODE_FL is not set
364Lower 32-bits of version
If EXT4_EA_INODE_FL is set
364Unknown (upper 32-bits of extended attribute reference count)
If EXT4_EXTENTS_FL and EXT4_INLINE_DATA_FL are not set
4012 x 4Array of direct block numbers. A block number is relative from the start of the volume
884Indirect block number. A block number is relative from the start of the volume
924Double indirect block number. A block number is relative from the start of the volume
964Triple indirect block number. A block number is relative from the start of the volume
If EXT4_EXTENTS_FL is set
4012Extents header
524 x 12extent descriptors or extents indexes
If EXT4_INLINE_DATA_FL is set
4060File content data
Common
1004NFS generation number
1044Lower 32-bits of file ACL (or extended attributes) block number
1084Upper 32-bits of data size
1124Fragment block address
1162Upper 16-bits of number of blocks
1182Upper 16-bits of file ACL (or extended attributes) block number
1202Upper 16-bits of owner (or user) identifier (UID)
1222Upper 16-bits of group identifier (GID)
1242Lower 16-bits of checksum
1262Unknown (reserved)
Extension (if inode size > 128)
1282Extended inode size, which can vary, values of 4, 28 and 32 have been observed
1302Upper 16-bits of checksum
1324(last) inode change (or modification) time extra precision
1364(last) content modification time extra precision
1404(last) access time extra precision
1444Creation time
1484Creation time extra precision
1524Upper 32-bits of version
1564Unknown (i_projid)

If checksum type is CRC-32C, the checksum is stored as 0xffffffff - CRC-32C.

Note that for a character and block device the first 2 bytes of the array of direct block numbers contain the minor and major device number respectively.

Checksum calculation

If checksum type is CRC-32C, the CRC32-C algorithm with the Castagnoli polynomial (0x1edc6f41) and initial value of 0 is used to calculate the checksum.

The checksum is calculated from:

  • the 16 byte file system identifier in the superblock
  • the inode number as a 32-bit little-endian integer
  • the NFS generation number in the inode as a 32-bit little-endian integer
  • the data of the inode with the lower and upper part of the checksum set to 0-byte values.

Extra precision

The ext4 extra precision is 4 bytes in size and consists of:

OffsetSizeValueDescription
0.02 bitsExtra epoch value
0.230 bitsFraction of second in nanoseconds

The 34 bits extra precision timestamp (in number of seconds) can be calculated as following:

extra_precision_timestamp = (extra_epoch_value * 0x100000000) + timestamp

Notes

It has been observed that when EXT4_EA_INODE_FL is set the (last) modification time can contain a valid timestamp.

According to The Linux Kernel documentation

For backward compatibility with older versions of this feature, the i_mtime/i_generation may store a back-reference to the inode number and i_generation of the one owning inode (in cases where the EA inode is not referenced by multiple inodes) to verify that the EA inode is the correct one being accessed.

File mode

ValueIdentifierDescription
Access other, Bitmask: 0x0007 (S_IRWXO)
0x0001S_IXOTHX-access for other
0x0002S_IWOTHW-access for other
0x0004S_IROTHR-access for other
Access group, Bitmask: 0x0038 (S_IRWXG)
0x0008S_IXGRPX-access for group
0x0010S_IWGRPW-access for group
0x0020S_IRGRPR-access for group
Access owner (or user), Bitmask: 0x01c0 (S_IRWXU)
0x0040S_IXUSRX-access for owner (or user)
0x0080S_IWUSRW-access for owner (or user)
0x0100S_IRUSRR-access for owner (or user)
Other
0x0200S_ISTXTSticky bit
0x0400S_ISGIDSet group identifer (GID) on execution
0x0800S_ISUIDSet owner (or user) identifer (UID) on execution
Type of file, Bitmask: 0xf000 (S_IFMT)
0x1000S_IFIFONamed pipe (FIFO)
0x2000S_IFCHRCharacter device
0x4000S_IFDIRDirectory
0x6000S_IFBLKBlock device
0x8000S_IFREGRegular file
0xa000S_IFLNKSymbolic link
0xc000S_IFSOCKSocket

Inode flags

ValueIdentifierDescription
0x00000001EXT2_SECRM_FL, EXT3_SECRM_FL, EXT4_SECRM_FL, EXT4_INODE_SECRMSecure deletion
0x00000002EXT2_UNRM_FL, EXT3_UNRM_FL, EXT4_UNRM_FL, EXT4_INODE_UNRMUndelete
0x00000004EXT2_COMPR_FL, EXT3_COMPR_FL, EXT4_COMPR_FL, EXT4_INODE_COMPRCompressed file, which is not yet implemented
0x00000008EXT2_SYNC_FL, EXT3_SYNC_FL, EXT4_SYNC_FL, EXT4_INODE_SYNCSynchronous updates
0x00000010EXT2_IMMUTABLE_FL, EXT3_IMMUTABLE_FL, EXT4_IMMUTABLE_FL, EXT4_INODE_IMMUTABLEImmutable file
0x00000020EXT2_APPEND_FL, EXT3_APPEND_FL, EXT4_APPEND_FL, EXT4_INODE_APPENDWrites to file may only append
0x00000040EXT2_NODUMP_FL, EXT3_NODUMP_FL, EXT4_NODUMP_FL, EXT4_INODE_NODUMPDo not remove (or dump) file
0x00000080EXT2_NOATIME_FL, EXT3_NOATIME_FL, EXT4_NOATIME_FL, EXT4_INODE_NOATIMEDo not update access time (atime)
0x00000100EXT2_DIRTY_FL, EXT3_DIRTY_FL, EXT4_DIRTY_FL, EXT4_INODE_DIRTYDirty compressed file, which is not yet implemented
0x00000200EXT2_COMPRBLK_FL, EXT3_COMPRBLK_FL, EXT4_COMPRBLK_FL, EXT4_INODE_COMPRBLKOne or more compressed clusters, which is not yet implemented
0x00000400EXT2_NOCOMP_FL, EXT3_NOCOMP_FL, EXT4_NOCOMPR_FL, EXT4_INODE_NOCOMPRDo not compress, which is not yet implemented
ext2 and ext3
0x00000800EXT2_ECOMPR_FL, EXT3_ECOMPR_FLEncrypted Compression error
ext4
0x00000800EXT4_ENCRYPT_FL, EXT4_INODE_ENCRYPTEncrypted file
Common
0x00001000EXT2_BTREE_FL, EXT2_INDEX_FL, EXT3_INDEX_FL, EXT4_INDEX_FL, EXT4_INODE_INDEXHash-indexed directory (previously referred to as B-tree format)
0x00002000EXT2_IMAGIC_FL, EXT3_IMAGIC_FL, EXT4_IMAGIC_FL, EXT4_INODE_IMAGICAFS directory
0x00004000EXT2_JOURNAL_DATA_FL, EXT3_JOURNAL_DATA_FL, EXT4_JOURNAL_DATA_FL, EXT4_INODE_JOURNAL_DATAFile data must be written using the journal
0x00008000EXT2_NOTAIL_FL, EXT3_NOTAIL_FL, EXT4_NOTAIL_FL, EXT4_INODE_NOTAILFile tail should not be merged, which is not used by ext4
0x00010000EXT2_DIRSYNC_FL, EXT3_DIRSYNC_FL, EXT4_DIRSYNC_FL, EXT4_INODE_DIRSYNCDirectory entries should be written synchronously (dirsync)
0x00020000EXT2_TOPDIR_FL, EXT3_TOPDIR_FL, EXT4_TOPDIR_FL, EXT4_INODE_TOPDIRTop of directory hierarchy
ext4
0x00040000EXT4_HUGE_FILE_FL, EXT4_INODE_HUGE_FILEIs a huge file
0x00080000EXT4_EXTENTS_FL, EXT4_INODE_EXTENTSInode uses extents
0x00100000EXT4_INODE_VERITYVerity protected inode
0x00200000EXT4_EA_INODE_FL, EXT4_INODE_EA_INODEInode used for large extended attribute
0x00400000EXT4_EOFBLOCKS_FL, EXT4_INODE_EOFBLOCKSBlocks allocated beyond EOF
0x01000000EXT4_SNAPFILE_FLInode is a snapshot
0x02000000EXT4_INODE_DAXInode is direct-access (DAX)
0x04000000EXT4_SNAPFILE_DELETED_FLSnapshot is being deleted
0x08000000EXT4_SNAPFILE_SHRUNK_FLSnapshot shrink has completed
0x10000000EXT4_INLINE_DATA_FL, EXT4_INODE_INLINE_DATAInode has inline data
0x20000000EXT4_PROJINHERIT_FL, EXT4_INODE_PROJINHERITCreate sub file entries with the same project identifier
0x40000000EXT4_INODE_CASEFOLDCasefolded directory
0x80000000EXT4_INODE_RESERVEDUnknown (reserved)

Reserved inode numbers

ValueIdentifierDescription
1EXT2_BAD_INO, EXT3_BAD_INO, EXT4_BAD_INOBad blocks inode
2EXT2_ROOT_INO, EXT3_ROOT_INO, EXT4_ROOT_INORoot inode
3EXT4_USR_QUOTA_INOOwner (or user) quota inode
4EXT4_GRP_QUOTA_INOGroup quota inode
5EXT2_BOOT_LOADER_INO, EXT3_BOOT_LOADER_INO, EXT4_BOOT_LOADER_INOBoot loader inode
6EXT2_UNDEL_DIR_INO, EXT3_UNDEL_DIR_INO, EXT4_UNDEL_DIR_INOUndelete directory inode
7EXT3_RESIZE_INO, EXT4_RESIZE_INOReserved group descriptors inode
8EXT3_JOURNAL_INO, EXT4_JOURNAL_INOJournal inode

Inline data

ext4 supports storing file entry data inline when the inode flag EXT4_INLINE_DATA_FL is set.

Note that inodes can have an implicit last sparse extent if the the inode data size is greater than 60 bytes.

Huge files

TODO: complete section

Directory entries

Directories entries are stored in the data blocks of a directory inode. The directory entries can be stored in multiple ways:

  • as linear directory entries
  • as inline data directory entries
  • as hash-tree directory entries

Linear directory entries

Linear directories entries are stored in a series of allocation blocks.

Linear directory entries contain:

  • directory entry for “.” (self)
  • directory entry for “..” (parent)
  • directory entry for other file system entries

The directory entry

The directory entry is of variable size, at most 263 bytes, and consists of:

OffsetSizeValueDescription
04Inode number
42Directory entry size, which must be a multitude of 4
61Name size, which contains the size of the name without the end-of-string character and has a maximum of 255
71File type
8...Name, which contains a narrow character string without end-of-string character

Older directory entry structures considered the name size a 16-bit value, but the upper byte was never used.

The name can contain any character value except the path segment separator (‘/’) and the NUL-character (‘\0’).

File types

ValueIdentifierDescription
0EXT2_FT_UNKNOWNUnknown
1EXT2_FT_REG_FILERegular file
2EXT2_FT_DIRDirectory
3EXT2_FT_CHRDEVCharacter device
4EXT2_FT_BLKDEVBlock device
5EXT2_FT_FIFOFIFO queue
6EXT2_FT_SOCKSocket
7EXT2_FT_SYMLINKSymbolic link

Inline data directory entries

ext4 supports storing the directory entries as inline data when the inode flag EXT4_INLINE_DATA_FL is set.

The inline data directory entries is of variable size, at most 60 bytes, and consists of:

OffsetSizeValueDescription
04Parent inode number
4...Array of directory entries

Hash tree directory entries

The data of the hash tree (HTree) is stored in the data blocs or extent defined by the directory inode. The hash-indexed directory entries are read-compatible with the linear directory entry.

Hash tree root

The hash tree root consists of:

  • dx_root
    • directory entry for “.” (self)
    • directory entry for “..” (parent)
    • dx_root_info
    • Array of dx_entry
  • directory entry for other file system entries

dx_root_info

OffsetSizeValueDescription
040Unknown (reserved)
41Hash method (or version)
518Root information size
61Number of indirect levels in the hash tree
71Unknown (unused flags)

dx_entry

TODO: complete section

struct dx_entry
{
        __le32 hash;
        __le32 block;
};

If the target path of a symbolic link is less than 60 characters long, it is stored in the 60 bytes in the inode that are normally used for the 12 direct and 3 indirect block numbers. If the target path is longer than 60 characters, a block is allocated, and the block contains the target path. The inode data size contains the length of the target path.

Extended attributes

Extended attributes can be stored:

  • in the inode block after the inode data
  • in the block referenced by the file ACL (or extended attributes) block number, if not 0

Note that both should be read to get the all the extended attributes.

Extended attributes consists of:

  • An extended attributes header
  • Extended attributes entries with a terminator

The extended attributes inode header

The extended attributes inode header (ext2_xattr_ibody_header, ext3_xattr_ibody_header, ext4_xattr_ibody_header) is 4 bytes in size and consists of:

OffsetSizeValueDescription
04"\x00\x00\x02\xea"Signature

The extended attributes block header

The ext2 and ext3 extended attributes block header

The ext2 and ext3 extended attributes block header (ext2_xattr_header, ext3_xattr_header) is 32 bytes in size and consists of:

OffsetSizeValueDescription
04"\x00\x00\x02\xea"Signature
44Unknown (reference count)
84Number of blocks
124Attributes hash
164 x 4Unknown (reserved)

The ext4 extended attributes block header

The ext4 extended attributes block header (ext4_xattr_header) is 32 bytes in size and consists of:

OffsetSizeValueDescription
04"\x00\x00\x02\xea"Signature
44Unknown (Reference count)
84Number of blocks
124Attributes hash
164Checksum
203 x 4Unknown (reserved)

The extended attributes entry

The extended attributes entry (ext2_xattr_entry, ext3_xattr_entry, ext4_xattr_entry) is of variable size and consists of:

OffsetSizeValueDescription
01Name size, which contains the size of the name without the end-of-string character
11Name index
22Value data offset, which contains the offset of the value data relative from the start of the extended attributes block or after the extended attributes signature in the inode block data
44Value data inode number, which contains the inode number that contains the value data or 0 to indicate the current block
84Value data size
124Unknown (Attribute hash)
16...Name string, which contains an ASCII string without end-of-string character and can be empty, for example in combination with a prefix or with an encrypted file
......32-bit alignment padding

The last extended attributes entry has the first 4 values set to 0 (8 bytes) and is used as a terminator.

Note that some implementations of older Android versions of ext appear to only set the first 4 bytes to 0 for the terminator.

The extended attribute name index

The name index indicates the prefix of the extended attribute name.

Name indexName prefixDescription
0""No prefix
1"user."
2"system.posix_acl_access"
3"system.posix_acl_default"
4"trusted."
6"security."
7"system."
8"system.richacl"

Journal

The journal was introduced in ext3.

TODO: complete section

Exclude bitmap

TODO: complete section

Note that the excluded bitmap is used for snapshots.

Format edge cases and corruption scenarios

File entry with invalid extents header signature

File content inaccessible but file entry metadata and extended attributes accessible.

References

Extensible File Allocation Table (exFAT) file system format

The Extensible File Allocation Table (exFAT) file system format is a successor of the File Allocation Table (FAT) file system format.

Overview

An exFAT file system consists of:

  • Main boot region (11 sectors)
    • boot sector (or boot record)
    • 7 extended boot sectors; can contain a sector signature (“\x55\xaa”)
    • OEM parameters sector; can contain a sector signature (“\x55\xaa”)
    • Reserved sector; can contain a sector signature (“\x55\xaa”)
    • boot checksum sector
  • Backup boot region (11 sectors)
    • boot sector (or boot record)
    • 7 extended boot sectors; can contain a sector signature (“\x55\xaa”)
    • OEM parameters sector; can contain a sector signature (“\x55\xaa”)
    • Reserved sector; can contain a sector signature (“\x55\xaa”)
    • boot checksum sector
  • File Allocation Table region
    • Aligment padding
    • First cluster block allocation tables
    • Zero or more backup block allocation tables
  • Data region
    • Aligment padding
    • Cluster heap
    • File and directory data

Characteristics

CharacteristicsDescription
Byte orderlittle-endian
Date and time valuesFAT date and time, in local time with UTC offset
Character stringsUCS-2 little-endian, which allows for unpaired Unicode surrogates such as "U+d800" and "U+dc00"

Boot record

The boot record is stored in the first sector of the volume.

The boot record is at least 512 bytes in size and consists of:

OffsetSizeValueDescription
03"\xeb\x76\x90"Boot entry point (JMP +120, NOP)
38"EXFAT\x20\x20\x20"File system signature (or OEM name)
11530Unknown (reserved), which must be 0
648Partition offset
728Total number of sectors
804Cluster block allocation table start sector
844Cluster block allocation table size, in number of sectors, which must be non 0
884Cluster heap start sector
924Number of clusters
964Root directory start cluster
1004Volume serial number
1041Format revision minor number
10511Format revision major number
1062Volume flags
1081Bytes per sector, which is stored as 2^n, for example 9 is 2^9 = 512. The bytes per sector value must be 512, 1024, 2048 or 4096
1091Sectors per cluster block, which is stored as 2^n, for example 3 is 2^3 = 8. The sectors per cluster block must be 1 upto 32M (2^25)
1101Number of cluster block allocation tables
1111Drive number
1121Unknown (percent in use), which contains the percentage of allocated cluster blocks in the cluster heap of 0xff if not available
1137Unknown (reserved)
120390Used for boot code
5102"\x55\xaa"Sector signature

Volume flags

ValueIdentifierDescription
0x0001ActiveFatActive FAT, where 0 represents the first FAT
0x0002VolumeDirtyIs dirty
0x0004MediaFailureHas media failures
0x0008ClearToZeroMust be cleared
0xfff0Unknown (reserved)

Boot checksum sector

The boot checksum sector is at least 512 bytes in size and consists of:

OffsetSizeValueDescription
04Boot checksum
44Copy of boot checksum
84Copy of boot checksum
124Copy of boot checksum
16496Unknown (empty values)
checksum = 0

for index in range(0, 11 * bytes_per_sector):
    # Ignore the volume flags and percent in use values.
    if index in (106, 107, 112):
        continue

    carry = 0x80000000 if (checksum & 1) else 0
    checksum = carry + (checksum >> 1) + sectors[index]
    checksum &= 0xFFFFFFFF

Cluster block allocation table

A cluster block allocation table consists of:

  • One ore more cluster block allocation table entries

Cluster block allocation table entry

A cluster block allocation table entry is 32 bits in size and consists of:

OffsetSizeValueDescription
032 bitsData cluster number

Where the data cluster number has the following meanings:

Value(s)Description
0x00000000Unused (free) cluster
0x00000001Unknown (invalid)
0x00000002 - 0xffffffefUsed cluster
0xfffffff0 - 0xfffffff6Reserved
0xfffffff7Bad cluster
0xfffffff8 - 0xffffffffEnd of cluster chain

Cluster heap

A cluster heap consists of:

  • One ore more sector allocation table entries

Sector allocation table entry

A sector allocation table entry is 32 bits in size and consists of:

OffsetSizeValueDescription
032 bitsData sector number

Directory

A directory consists of:

  • Zero or more directory entries
  • Terminator directory entry

Directory entry

A directory entry is 32 bytes in size and consists of:

OffsetSizeValueDescription
01Entry type
11Entry flags
119Entry data
204Data start cluster
248Data size

Directory entry type

OffsetSizeValueDescription
0.05 bitsType type code
0.51 bitIs non-critical (also referred to as type importance)
0.61 bitIs secondary entry (also referred to as type category)
0.71 bitIn use
ValueDescription
0x00Terminator directory entry
0x01 - 0x7fUnused
0x80Invalid
0x81 - 0xffUsed
Directory entry type codes
ValueDescription
Critical and primary
0x81Allocation bitmap
0x82Case folding mappings
0x83Volume label
0x85File entry
Non-critical and primary
0xa0Volume identifier
0xa1TexFAT padding
Critical and secondary
0xc0Data stream
0xc1File (entry) name
Non-critical and secondary
0xe0Vendor extension
0xe1Vendor allocation

Directory entry flags

OffsetSizeValueDescription
0.01 bitUnknown (AllocationPossible)
0.11 bitContinuous allocation (NoFatChain), if set do not use the cluster block allocation table
0.26 bitsUnknown
offset = ( ( cluster_block_number - 2 ) * cluster_block_size ) + cluster_chain_offset
Allocation bitmap record
OffsetSizeValueDescription
010x81Entry type
11Bitmap flags
2180Unknown (Reserved)
204Data start cluster
248Data size
Allocation bitmap flags
OffsetSizeValueDescription
0.01 bitUnknown (BitmapIdentifier)
0.17 bitsUnknown (reserved)
Case folding mappings record
OffsetSizeValueDescription
010x82Entry type
130Unknown (Reserved)
44Checksum of the case folding mappings data
8120Unknown (Reserved)
204Data start cluster
248Data size
Volume label record
OffsetSizeValueDescription
010x83Entry type
11Name size, in number of characters
222Name string, which contains an UCS-2 little-endian string without an end-of-string character
2480Unknown (Reserved)

Note that the volume label record should only be stored in the first and/or second directory entry of the root directory.

File entry record
OffsetSizeValueDescription
010x85Entry type
11Entry flags
22Entry set checksum
42File attribute flags
620Unknown (Reserved)
82Creation time
102Creation date
122Last modification time
142Last modification date
162Last access time
182Last access date
201Creation time fraction of seconds, which contains fraction of 2-seconds in 10 ms intervals
211Last modification time fraction of seconds, which contains fraction of 2-seconds in 10 ms intervals
221Creation time UTC offset, which contains number of 15 minute intervals of the time relative to UTC, where an MSB of 1 indicates the offset is valid (and 0 invalid)
231Last modification time UTC offset, which contains number of 15 minute intervals of the time relative to UTC, where an MSB of 1 indicates the offset is valid (and 0 invalid)
241Last access time UTC offset, which contains number of 15 minute intervals of the time relative to UTC, where an MSB of 1 indicates the offset is valid (and 0 invalid)
2570Unknown (Reserved)
Volume identifier record
OffsetSizeValueDescription
010xa0Entry type
11Entry flags
22Entry set checksum
42Unknown (Flags)
616Volume identifier, which contains a GUID
22100Unknown (Reserved)
Data stream record
OffsetSizeValueDescription
010xc0Entry type
11Entry flags
210Unknown (Reserved)
31Name size, in number of characters
42Name hash
620Unknown (Reserved)
88Valid data size
1640Unknown (Reserved)
204Data start cluster
248Data size
File name record
OffsetSizeValueDescription
010xc1Entry type
11Entry flags
230Name string, which contains an UCS-2 little-endian string without an end-of-string character

File attribute flags

ValueDescription
0x0001Read-only
0x0002Hidden
0x0004System
0x0008Is volume label
0x0010Is directory
0x0020Archive
0x0040Is device
0x0080Unused (reserved)

Checksum

The checksum calculation uses Rotate Right by 1 (ROR1).

checksum = 0

for byte_value in data:
    msb = 0x80000000 if (checksum & 1) else 0
    checksum = (msb + (checksum >> 1) + byte_value) & 0xffffffff

References

File Allocation Table (FAT) file system format

The File Allocation Table (FAT) is widely used a file sytem and is the default file system for DOS and Windows.

There are multiple known variants or derivatives of FAT, such as:

  • (original) 8-bit FAT
  • FAT-12
  • FAT-16
  • FAT-32
  • exFAT

Overview

A FAT file system consists of:

  • One or more reserved sectors
    • a boot record (or boot sector)
    • file system informartion for FAT-32
  • One or more cluster block allocation tables
  • Root directory data for FAT-12 and FAT-16
  • File and directory data

Note that FAT-32 stores the root directory as part of the file and directory data.

Characteristics

CharacteristicsDescription
Byte orderlittle-endian
Date and time valuesFAT date and time, in local time
Character stringsA narrow character Single Byte Character (SBC) ASCII string

Terminology

TermDescription
Hidden sectorsThe sectors stored before the FAT volume, such as those used to store a partition table

Determing the FAT format version

To distinguish between FAT-12, FAT-16 and FAT-32, compute the number of clusters in the data area:

data_area_size = total_number_of_sectors - (number_of_reserved_sectors + (
    number_of_allocation_tables * allocation_table_size) + size_of_root_directory)
number_of_clusters = round down (data_area_size / sectors_per_cluster)
  • FAT-12 is used if the number of clusters is less than 4085
  • FAT-16 is used if the number of clusters is less than 65525
  • FAT-32 is used otherwise

Boot record

The boot record is stored in the first sector of the volume.

FAT-12 and FAT-16 boot record

The FAT-12 and FAT-16 boot record is at least 512 bytes in size and consists of:

OffsetSizeValueDescription
03"\xeb\x3c\x90"Boot entry point (JMP +62, NOP)
38File system signature (or OEM name)
DOS version 2.0 BIOS parameter block (BPB)
112Bytes per sector, which must be 512, 1024, 2048 or 4096
131Sectors per cluster block, which must be 1, 2, 4, 8, 16, 32, 64 or 128
142Number of reserved sectors (reserved region), which starts at the first sector of the volume (sector 0) and must be 1 or more (typically 1 or 32)
161Number of cluster block allocation tables, which must be 1 or more (typically 2)
172Number of root directory entries
192Total number of sectors (16-bit)
211Media descriptor
222Cluster block allocation table size (16-bit), in number of sectors
DOS version 3.4 BIOS parameter block (BPB)
242Number of sectors per track
262Number of heads
284Number of hidden sectors
324Total number of sectors (32-bit)
 
361Drive number
3710Unknown (reserved for Windows NT)
381Extended boot signature
If extended boot signature == 0x29
394Volume serial number, which can be derived from the system current date and time
4311Volume label, which contains a narrow character string or "NO\x20NAME\x20\x20\x20\x20" if not set
548"FAT12\x20\x20\x20" or "FAT16\x20\x20\x20"File system hint, which is informational and not required
If extended boot signature != 0x29
3923Unknown
Common
62448Used for boot code
5102"\x55\xaa"Sector signature

Note that the sector signature must be set at offset 512 but in addition can be set in the last 2 bytes of the sector.

FAT-32 boot record

The FAT-32 boot record is at least 512 bytes in size and consists of:

OffsetSizeValueDescription
03"\xeb\x58\x90"Boot entry point (JMP +90, NOP)
38File system signature (or OEM name)
DOS version 2.0 BIOS parameter block (BPB)
112Bytes per sector, which must be 512, 1024, 2048 or 4096
131Sectors per cluster block, which must be 1, 2, 4, 8, 16, 32, 64 or 128
142Number of reserved sectors (reserved region), which starts at the first sector of the volume (sector 0) and must be 1 or more (typically 1 or 32)
161Number of cluster block allocation tables, which must be 1 or more (typically 2)
1720Number of root directory entries, which must be 0 for FAT-32
1920Total number of sectors (16-bit), which must be 0 for FAT-32
211Media descriptor
2220Cluster block allocation table size (16-bit), in number of sectors, which must be 0 for FAT-32
DOS version 3.4 BIOS parameter block (BPB)
242Number of sectors per track
262Number of heads
284Number of hidden sectors
324Total number of sectors (32-bit)
 
364Cluster block allocation table size (32-bit), in number of sectors, which must be non 0 for FAT-32
402Extended flags
4210Format revision minor number
4310Format revision major number
444Root directory start cluster
482File system information (FSINFO) sector number
502Boot record sector number
52120Unknown (reserved)
641Drive number
6510Unknown (reserved for Windows NT)
661Extended boot signature
If extended boot signature == 0x29
674Volume serial number, which can be derived from the system current date and time
7111Volume label, which contains a narrow character string or "NO\x20NAME\x20\x20\x20\x20" if not set
828"FAT32\x20\x20\x20"File system hint, which is informational and not required
If extended boot signature != 0x29
6723Unknown
Common
90420Used for boot code
5102"\x55\xaa"Sector signature

Note that the sector signature must be set at offset 512 but in addition can be set in the last 2 bytes of the sector.

FAT-32 extended flags

OffsetSizeValueDescription
0.04 bitsActive FAT, where 0 represents the first FAT
0.43 bitsUnknown (reserved)
0.71 bitFAT mirroring disabled
1.08 bitsUnknown (reserved)

OEM names

ValueDescription
"MSWIN4.1"
"MSDOS 5.0"

Media descriptors

ValueIdentifierDescription
0xe5
0xed
0xee
0xef
0xf0removable media
0xf4
0xf5
0xf8fixed (non-removable) media
0xf9
0xfa
0xfb
0xfc
0xfd
0xfe
0xff

Cluster block allocation table

A cluster block allocation table consists of:

  • One ore more cluster block allocation table entries

FAT 12 cluster block allocation table entry

A FAT 12 cluster block allocation table entry is 12 bits in size and consists of:

OffsetSizeValueDescription
012 bitsData cluster number

Where the data cluster number has the following meanings:

Value(s)Description
0x000Unused (free) cluster
0x001Unknown (invalid)
0x002 - 0xfefUsed cluster
0xff0 - 0xff6Reserved
0xff7Bad cluster
0xff8 - 0xfffEnd of cluster chain

FAT 16 cluster block allocation table entry

A FAT 16 cluster block allocation table entry is 16 bits in size and consists of:

OffsetSizeValueDescription
016 bitsData cluster number

Where the data cluster number has the following meanings:

Value(s)Description
0x0000Unused (free) cluster
0x0001Unknown (invalid)
0x0002 - 0xffefUsed cluster
0xfff0 - 0xfff6Reserved
0xfff7Bad cluster
0xfff8 - 0xffffEnd of cluster chain

FAT 32 cluster block allocation table entry

A FAT 32 cluster block allocation table entry is 32 bits in size and consists of:

OffsetSizeValueDescription
032 bitsData cluster number

Note that only the lower 28-bits are used

Where the data cluster number has the following meanings:

Value(s)Description
0x00000000Unused (free) cluster
0x00000001Unknown (invalid)
0x00000002 - 0x0fffffefUsed cluster
0x0ffffff0 - 0x0ffffff6Reserved
0x0ffffff7Bad cluster
0x0ffffff8 - 0x0fffffffEnd of cluster chain
0x10000000 - 0xffffffffUnknown

Directory

A directory consists of:

  • self (“.”) directory entry (not used in root directory)
  • parent (“..”) directory entry (not used in root directory)
  • Zero or more directory entries
  • Terminator directory entry

Directory entry

Determining the root directory location

first_allocation_table_offset = number_of_reserved_sectors * bytes_per_sector

FAT-12 and FAT-16 root directory

root_directory_start_offset = first_allocation_table_offset + (
    number_of_allocation_tables * allocation_table_size * bytes_per_sector)
first_cluster_offset = directory_start_sector + (number_of_root_directory_entries * 32)

FAT-32 root directory

first_cluster_offset = first_allocation_table_sector + (
    number_of_allocation_tables * allocation_table_size * bytes_per_sector)
root_directory_start_offset = first_cluster_sector + (
    (root_directory_cluster - 2) * number_of_sectors_per_cluster)

FAT-12 and FAT-16 directory entry

A FAT-12 and FAT-16 directory entry is 32 bytes in size and consists of:

OffsetSizeValueDescription
08Name, which is padded with spaces and the first character can have a special meaning
83Extension, which is padded with spaces
111File attribute flags
121Flags
131Creation time fraction of seconds, which contains fraction of 2-seconds in 10 ms intervals
142Creation time
162Creation date
182Last access date
202Unknown (OS/2 extended attribute)
222Last modification time
242Last modification date
262Data stream start cluster
284Data stream data size

FAT-32 directory entry

A FAT-32 directory entry is 32 bytes in size and consists of:

OffsetSizeValueDescription
08Name, which is padded with spaces and the first character can have a special meaning
83Extension, which is padded with spaces
111File attribute flags
121Flags
131Creation time fraction of seconds, which contains fraction of 2-seconds in 10 ms intervals
142Creation time
162Creation date
182Last access date
202Data stream data size, which contains the upper 16-bit of the value
222Last modification time
242Last modification date
262Data stream start cluster, which contains the lower 16-bit of the value
284Data stream data size

Short (or 8.3) file name

A FAT short (or 8.3) file name is stored in an OEM character set (codepage). The first character can have a special meaning.

Valid FAT short file name characters are:

ValueDescription
'A-Z'Upper case character
'0-9'Numeric character
' 'Space, where trailing spaces are considered padding and therefore ignored
'.'Dot, with the exception of "." and "..", where trailing dot characters are ignored
'!'Exclamation mark
'#'Hash
'$'Dollar sign
'%'Percent sign
'&'Ampersand
'''Single quote
'('Left parenthesis
')'Right parenthesis
'-'Hyphen
'@'At sign
'^'Caret
'_'Underscore
'`'Grave accent
'{'Left curly brace
'}'Right curly brace
'~'Tilde
0x80 - 0xffExtended ASCII character, which are codepage dependent

Note that other characters such as plus sign (‘+’) have been observed in FAT short file names.

First character

ValueDescription
0x00Last (or terminator) directory entry
0x01 - 0x13VFAT long file name directory entry
0x05Directory entry pending deallocation (deprecated since DOS 3.0) or substitution of a 0xe5 value
0x41 - 0x54Last VFAT long file name directory entry
0xe5Unallocated directory entry

File attribute flags

ValueDescription
0x01Read-only
0x02Hidden
0x04System
0x08Is volume label
0x10Is directory
0x20Archive
0x40Is device
0x80Unused (reserved)

Flags

ValueDescription
0x01Data is EFS encrypted
0x02Data contains large EFS header
0x08Name should be represented in lower case
0x10Extension should be represented in lower case

VFAT long file name entry

VFAT long file names entries are stored in directory entries. Multiple VFAT long file name entries can be used to store a single long file name, where the highest (last) sequence number is stored first. A maximum of 20 VFAT long file name entries can be used to store a long file name of 255 UCS-2 characters.

VFAT long file names are stored using UCS-2 little-endian, which allows for unpaired Unicode surrogates such as “U+d800” and “U+dc00”

VFAT long file name entries are stored before the directory entry containing the short file name and additional file entry information.

A VFAT long file name entry is 32 bytes in size and consists of:

OffsetSizeValueDescription
01Sequence number
110First name segment string, which contains 5 UCS-2 string characters
1110x0fUnknown (attributes)
1210x00Unknown (type)
131Checksum of the short (8.3) file name
1412Second name segment string, which contains 6 UCS-2 string characters
2620Unknown (first cluster)
284Third name segment string, which contains 2 UCS-2 string characters

Note that unused characters in the VFAT long file segment strings after the end-of-string character (0x0000) are padded with 0xffff.

VFAT long file name sequence number

OffsetSizeValueDescription
05 bitsNumber
0.51 bit0Unknown (reserved)
0.61 bit0Unknown (last logical, first physical LFN entry)
0.71 bit0Unknown

References

Hierarchical File System (HFS) format

The Hierarchical File System (HFS) was the default file system for Mac OS after Macintosh File System (MFS) and before Apple File System (APFS).

Note that this document uses Mac OS to refer to the Macintosh Operating System in general, instead of specific versions like Mac OS X or macOS. Mac OS X is used to refer to version of Mac OS 10.0 or later.

There are multiple known variants or derivatives of HFS, such as:

  • HFS
  • HFS+ 8.10, used by Mac OS 8.1 to 9.2.2
  • HFS+ 10.0, introduced in Mac OS 10.0
  • HFSX, introduced in Mac OS 10.3

Note that HFS can be referred to as “HFS Standard” and HFS+ or HFSX as “HFS Extended”.

HFSX (or HFS/X) is an extension to HFS+ to allow additional features that are incompatible with HFS+. One such feature is case-sensitive file names. A HFSX volume may be either case-sensitive or case-insensitive. Case sensitivity (or lack thereof) applies to all file and directory names on the volume.

Overview

FeatureHFSHFS+ and HFSX
Maximum file size231 (2 GiB)263 (8 EiB)
Maximum file name size31 characters255 characters
Maximum number of blocks216 (65535 bytes)232 (4294967296 bytes)
Character setnarrow character with codepageUnicode UTF-16 big-endian
Time stampsIn local timeIn UTC
Catalog B-tree file node size512 bytes4096 bytes
File attributesnoneBasic and extended

HFS

A HFS file system consists of:

The backup master directory block (MDB), is stored in the last 2 sectors of the volume.

Characteristics

CharacteristicsDescription
Byte orderbig-endian
Date and time valuesHFS timestamp, in local time
Character stringsNarrow character (Single Byte Character (SBC) or Multi Byte Character (MBC)) stored using a system defined codepage

HFS+ and HFSX

A HFS+ or HFSX file system consists of:

The backup volume header, is stored in the last 1024 bytes of the volume.

Characteristics

CharacteristicsDescription
Byte orderbig-endian
Date and time valuesHFS timestamp, in UTC
Character stringsUTF-16 big-endian

Terminology

TermDescription
Clump sizeSize of the group of (allocation) blocks (or clump), in bytes, to avoid fragmentation

Unicode strings

Unicode strings are stored as UTF-16 big-endian in Normalization Form Canonical Decomposition (NFD) based on Unicode 3.2, with exclusions. Unicode values in the ranges U+2000 - U+2FFF, U+F900 - U+FAFF and U+2F800 - U+2FAFF are not decomposed.

On Mac OS 8.1 through 10.2.x decomposition was based on Unicode 2.1.

TODO: determine what the impact of the different Unicode versions is.

Note that based on observations on Mac OS 10.15.7 on HFS+ the range U+1D000 - U+1D1FF is excluded from decomposition and U+2400 is replaced by U+0.

HFS timestamp

Date and time values are stored as an unsigned 32-bit integer containing the number of seconds since January 1, 1904 at 00:00:00 (midnight), where:

  • MFS and HFS use local time;
  • HFS+ and HFSX use Coordinated Universal Time (UTC).

This document will refer to both forms as HFS timestamp.

The maximum representable date is February 6, 2040 at 06:28:15 UTC.

The HFS timestamp does not account for leap seconds. It includes a leap day in every year that is evenly divisible by 4. This is sufficient given that the range of representable dates does not contain 1900 or 2100, neither of which have leap days.

File names

TN1150 states that HFS file names are compared in case-insensitive assuming a MacRoman encoding.

Upper caseLower case
0x41 - 0x5a (A - Z)0x61 - 0x7a (a - z)
0x80 (Ä)0x8a (ä)
0x81 (Å)0x8c (å)
0x82 (Ç)0x8d (ç)
0x83 (É)0x8e (é)
0x84 (Ñ)0x96 (ñ)
0x85 (Ö)0x9a (ö)
0x86 (Ü)0x9f (ü)
0xae (Æ)0xbe (æ)
0xaf (Ø)0xbf (ø)
0xcb (À)0x88 (à)
0xcc (Ã)0x8b (ã)
0xcd (Õ)0x9b (õ)
0xce (Œ)0xcf (œ)
0xd9 (Ÿ)0xd8 (ÿ)
0xe5 (Â)0x89 (â)
0xe6 (Ê)0x90 (ê)
0xe7 (Á)0x87 (á)
0xe8 (Ë)0x91 (ë)
0xe9 (È)0x8f (è)
0xea (Í)0x92 (í)
0xeb (Î)0x94 (î)
0xec (Ï)0x95 (ï)
0xed (Ì)0x93 (ì)
0xee (Ó)0x97 (ó)
0xef (Ô)0x99 (ô)
0xf1 (Ò)0x98 (ò)
0xf2 (Ú)0x9c (ú)
0xf3 (Û)0x9e (û)
0xf4 (Ù)0x9d (ù)

HFS+ allows for the “/” character in file names. On Mac OS, Finder this will be represented as a “/” but in Terminal it is replaced by “:” since the same character is used as path segment separator. A file name with a “:” created in Terminal will be shown as “/” in Finder. Finder does not allow the creation of a file containing “:” in the name. A symbolic link created in Terminal to a file with a “:” in name will not convert the “:” character in the link target data. The Linux HFS+ implementation appears to apply a similar conversion logic as Terminal.

B-tree files

HFS, HFS+ and HFSX use multiple B-trees files.

A B-tree file consists of fixed sized nodes:

  • header node
  • map nodes
  • index (root and branch) nodes
  • leaf nodes

Note that only the data fork of a B-tree file is used. The resource fork should be unused.

The size of a B-tree file can be calculated in the following manner:

size = number_of_nodes * node_size

Node size

The node size is determined when the B-tree file is created.

FeatureHFSHFS+ and HFSX
Node size512 byteswhere the value must be a power of 2 in the range 512 - 32768

In a HFS+ the B-tree node size is stored in the header node.

Default node sizes:

FeatureHFSHFS+ and HFSX
catalog file5124 KiB (8 KiB in Mac OS X)
extents overflow file5121 KiB (4 KiB in Mac OS X)
attributes fileN/A4 KiB

B-tree (file) node

A B-tree file node consists of:

  • node descriptor
  • node records
  • node record offsets

The first node in the file is referenced by node number 0.

The node offset relative to the start of the file and can be calculated in the following manner:

node_offset = node_number * node_size

B-tree node descriptor

The B-tree node descriptor (BTNodeDescriptor) is 14 bytes in size and consists of:

OffsetSizeValueDescription
04Next tree node number (forward link), which contains 0 if empty
44Previous tree node number (backward link), which contains 0 if empty
81Node type, which consists of a signed 8-bit integer
91Node level, which consists of a signed 8-bit integer
102Number of records
1220Unknown (Reserved), should contain 0

The root node level is 0, with a maximum depth of 8.

B-tree node types
ValueIdentifierDescription
-1kBTLeafNodeleaf node
0kBTIndexNodeindex node
1kBTHeaderNodeheader node
2kBTMapNodemap node

B-tree node record

The B-tree node record contains (leaf) data or a reference to an index node and consists of:

  • a key
  • value data

B-tree record offsets

The B-tree record offsets are an array of 16-bit integers relative from the start of the B-tree node descriptor. The first record offset is found at node size - 2, e.g. 512 - 2 = 510, the second 2 bytes before that, e.g. 508, etc.

An additional record offset is added at the end to signify the start of the free space.

Note that the record offsets are not necessarily stored in linear order.

B-tree header node

The B-tree header node is stored in the first node of the B-tree file and contains 3 records:

  • the B-tree header record;
  • the user data record, which consist of 128 bytes (reserved within HFS);
  • the B-tree map record.

Note that the records in the B-tree header node do not have keys.

B-tree header record

The B-tree header record (BTHeaderRec) is 106 bytes in size and consists of:

OffsetSizeValueDescription
02Depth of the tree
24Root node number
64Number of data records contained in leaf nodes
104First leaf node number
144Last leaf node number
182Node size, in bytes, where the value must be a power of 2 in the range 512 - 32768
202Maximum key size, in bytes
224Number of nodes
264Number of unused nodes
HFS
3076Unknown (Reserved)
HFS+/HFSX
302Unknown (Reserved)
324Clump size, in bytes
361B-tree file type
371Key comparision method
384Flags (or attributes)
4216 x 4 = 64Unknown (Reserved)

TODO: does the number of data records equal the number of leaf nodes?

File type
ValueIdentifierDescription
0x00Control file
0x80First user B-tree type
0xffReserved B-tree type
Key comparision methodtype
ValueIdentifierDescription
0x00Unknown (not set), observed on HFS standard, HFS+ and an empty HFSX file system
0xbcBinary compare (case-sensitive)
0xcfUnicode case folding (case-insensitive)
Flags
ValueIdentifierDescription
0x00000001kBTBadCloseMaskBad close, which indicates that the B-tree was not closed properly and should be checked for consistency (Not used by HFS+ and HFSX)
0x00000002kBTBigKeysMaskBig keys, which indicates the key data size value of the keys in index and leaf nodes is 16-bit integer, otherwise, it is an 8-bit integer (Must be set for HFS+ and HFSX)
0x00000004kBTVariableIndexKeysMaskVariable-size (index) keys, which indicates that the keys in index nodes occupy the number of bytes indicated by their key size; otherwise, the keys in index nodes always occupy maximum key size (must be set for the HFS+ and HFSX Catalog B-tree, and cleared for the HFS+ and HFSX Extents overflow B-tree)

B-tree map record

The B-tree map record contains of a bitmap that indicates which nodes in the B-tree file are used and which are not. If a bit is set, then the corresponding node in the B-tree file is in use.

The bitmap is 256 bytes in size and can represent a maximum of 2048 nodes. If more nodes are needed a map node is used to store additional mappings.

The map node

If a B-tree file contains more than 2048 nodes, which are enough for about 8000 files, a map node is used to store additional node-mapping information.

The next tree node value in the B-tree node descriptor of the header node is used to refer to the first map node.

A map node consists of a B-tree node descriptor and one B-tree map record. The map record is 494 bytes in size 512 - (14 + 2) and can therefore contain mapping information for 3952 nodes.

If a B-tree contains more than 6000 nodes (enough for about 25000 files) a second map node is needed. The next tree node value in the B-tree node descriptor of the first map node is used to refer to the second.

If more map nodes are required, each additional map node is similarly linked to the previous one.

The root node

The root node is the start of the B-tree structure; usually the root node is an index node, but it might be a leaf node if there are no index nodes.

The root node number is stored in the B-tree header record and is 0 if the B-tree is empty.

The index node

The records stored in an index node are called pointer records. A pointer record consists of a key followed by the node number of the corresponding node. The size of the key varies according to the type of B-tree file.

  • In a catalog file, the search key is a combination of the file or directory name and the parent identifier of that file or directory.
  • In an extents overflow file, the search key is a combination of that file’s type, its file identifier and the index of the first block in the extent.

The immediate descendants of an index node are called the children of the index node. An index node can have from 1 to 15 children, depending on the size of the pointer records that the index node contains.

The leaf node

The leaf nodes contain data records. The structure of the leaf node data records varies according to the type of B-tree.

  • In an extents overflow file, the leaf node data records consist of a key and an extent record.
  • In a catalog file, the leaf node data records can be any one of four kinds of records.

HFS Master Directory Block (MDB)

The primary Master Directory Block (MDB) (or volume information block (VIB)) is located at offset 1024 of the volume.

The MDB is 162 bytes in size and consists of:

OffsetSizeValueDescription
02"BD" (or "\x42\x44")Volume signature
24Creation time, which contains a HFS timestamp in local time
64(last) modification time, which contains a HFS timestamp in local time
102Volume attribute flags
122Number of files in the root directory
142Volume bitmap block number, contains a block number relative from the start of the volume, where 0 is the first block number, typically 3
162Next allocation search block number
182Number of blocks, where a volume can contain at most 65535 blocks
204Block size (drAlBlkSiz), in bytes, must be a multitude of 512
244Clump size, in bytes
282Data area start sector (drAlBlSt), contains a sector number relative from the start of the volume, where 0 is the first sector number and bytes per sector is 512
304Next available catalog node identifier (CNID), which can be a directory or file record identifier
342Number of unused blocks
361Volume label size, with a maximum of 27
3727Volume label
644(last) backup time, which contains a HFS timestamp in local time
682Backup sequence number
704Volume write count, which contains the number of times the volume has been written to
744Extents overflow file clump size, in bytes
784Catalog file clump size, in bytes
822Number of sub directories in the root directory
844Total number of files, which does not include file system metadata files
884Total number of directories (folders), which does not include the root folder
9232Finder information
1242Embedded volume signature (drEmbedSigWord, previously used for drVCSize)
1264Embedded volume extent descriptor (drEmbedExtent, previously used for drVBMCSize and drCtlCSize)
1304Extents overflow file size
13412Extents overflow file extents record
1464Catalog file size
15012Catalog file extents record

Note that the volume modification time is not necessarily the data and time when the volume was last flushed.

Notes

TODO: check

  • drVCSize => Volume cache block size (16-bit)
  • drVBMCSize => Volume bitmap cache block size (16-bit)
  • drCtlCSize => Common volume cache block size (16-bit)

HFS Volume Bitmap

The volume bitmap is used to keep track of block allocation. The bitmap contains one bit for each block in the volume.

  • If a bit is set, the corresponding block is currently in use by some file.
  • If a bit is clear, the corresponding block is not currently in use by any file and is available.

The volume bitmap does not indicate which files occupy which blocks. The actual file-mapping information in maintained in two locations:

  • in the corresponding catalog entry;
  • in the corresponding extents overflow file entry.

The size of the volume bitmap depends on the number of blocks in the volume.

A 800 KiB floppy disk with a block size of 512 bytes has a volume bitmap size of:

((800 * 1024) / (512 * 8)) = 1600 bits (200 bytes).

A 32 MiB volume containing 32 MiB with a block size of 512 bytes has a volume bitmap size of:

((32 * 1024 * 1024) / (512 * 8)) = 65536 bits (8192 bytes).

The number of blocks in the volume in the MDB consists of a 16-bit integer, so no more than 65535 blocks can be addressed. The volume bitmap is never larger than 8192 bytes (or 16 physical blocks). For volumes containing more than 32 MiB of space, the block size must be increased.

A volume containing 40 MiB of space must have an block size that is at least 2 x 512 bytes.

A volume containing 80 MiB of space must have an block size that is at least 3 x 512 bytes.

HFS+ and HFSX Volume Header

The volume header (HFSPlusVolumeHeader) replaces the master directory block (MDB). The volume header starts at offset 1024 of the volume.

The block containing the first 1536 bytes (reserved space plus volume header) are marked as used in the allocation file.

The volume header is 512 bytes in size and consists of:

OffsetSizeValueDescription
02"H+" (or "\x48\x2b") or "HX" (or "\x48\x58")Volume signature, where "H+" (kHFSPlusSigWord) is used for HFS+ and "HX" (kHFSXSigWord) for HFSX
22Format version, where 4 (kHFSPlusVersion) is used for HFS+ and 5 (kHFSXVersion) for HFSX
44Volume attribute flags
84Last mounted version
124Journal information block number, contains a block number relative from the start of the volume
164Creation time, which contains a HFS timestamp in UTC
204(last) content modification time, which contains a HFS timestamp in UTC
244(last) backup time, which contains a HFS timestamp in UTC
284Checked time, which contains a HFS timestamp in UTC
324Total number of files, which does not include file system metadata files
364Total number of directories (folders), which does not include the root folder
404Block size, in bytes
444Total number of blocks
484Number of unused blocks
524Next allocation search block number (nextAllocation)
564Clump size, in bytes, of a resource fork
604Clump size, in bytes, of a data fork
644Next available catalog node identifier (CNID), which can be a directory or file record identifier
684Volume write count, which contains the number of times the volume has been written to
728Encodings bitmap
8032Finder information
11280Allocation file fork descriptor
19280Extents overflow file fork descriptor
27280Catalog file fork descriptor
35280Attributes file fork descriptor
43280Startup file fork descriptor

Total number of blocks

For a disk whose size is an even multiple of the block size, all areas on the disk are included in an block, including the volume header and backup volume header. For a disk whose size is not an even multiple of the block size, only the blocks that will fit entirely on the disk are counted here. The remaining space at the end of the disk is not used by the volume format (except for storing the backup volume header, as described above).

Volume attribute flags

The volume attributes flags are specified as following.

ValueIdentifierDescription
0x00000080kHFSVolumeHardwareLockBitVolume hardware lock, set if the volume is write-protected due to a hardware setting
0x00000100kHFSVolumeUnmountedBitVolume unmounted, set if the volume was correctly flushed before being unmounted or ejected
0x00000200kHFSVolumeSparedBlocksBitVolume spared blocks, set if there are any records in the extents overflow file for bad blocks
0x00000400kHFSVolumeNoCacheRequiredBitVolume no cache required, set if the blocks from this volume should not be cached
0x00000800kHFSBootVolumeInconsistentBitBoot volume inconsistent, set if the volume was mounted for writing
0x00001000kHFSCatalogNodeIDsReusedBitCatalog node identifiers reused, set when the next catalog identifier value overflows 32 bits, forcing smaller catalog node identifiers to be reused
0x00002000kHFSVolumeJournaledBitJournaled, set if the file system uses a journal
0x00004000kHFSVolumeInconsistentBitUnknown (Reserved)
0x00008000kHFSVolumeSoftwareLockBitVolume software lock, set if the volume is write-protected due to a software setting
0x40000000kHFSContentProtectionBitUnknown (Reserved)
0x80000000kHFSUnusedNodeFixBitUnknown (Reserved)

Last mounted version

ValueIdentifierDescription
"8.10"used by Mac OS 8.1 to 9.2.2
"10.0"kHFSPlusMountVersionused by Mac OS X
"FSK!" or "fsck"used by fsck_hfs on Mac OS X
"HFSJ"kHFSJMountVersionused by journaled HFS+ or HFSX

TODO: add text about HFS standard

HFS+ supports both hard links and symbolic links.

Hard links to directories are not supported (allowed).

Hard links in HFS+/HFSX are represented by multiple different types of file records:

  • one indirect node file record, named “iNode#”, where # is the link reference. This file contains the content of the file shared by the hard links.
  • one or more hard link file records, that reference the indirect node file record.

Note that indirect node records named “dir_#” and “temp#” also have been observed.

Indirect node files are stored in a file system metadata directory referred to as the metadata directory with the name “/\u{2400}\u{2400}\u{2400}\u{2400}HFS+ Private Data”.

The link reference corresponds to the catalog node identifier (CNID) of the indirect node file, where 0 is not a valid link reference.

Note that TN1150 states that a new link reference randomly chosen from the range 100 to 1073741923. However link references that fall outside of this range have been observed such as “iNode20”.

The special permission data of the hard link file records contains the link reference if:

  • the catalog file record flag kHFSHasLinkChainMask is set;
  • and the first 8 bytes of the file information contains “hlnkhfs+”
ValueIdentifierDescription
"hlnk"kHardLinkFileTypeHard link file type
"hfs+"kHFSPlusCreatorHard link file creator

The hard link file’s creation date should be set to the creation date of the metadata directory, but the creation date may also be set to the creation date of the volume’s root directory though this is deprecated.

Device identifier

The Special permission data contains the device identifier. The device identifier can be stored in different formats, such as: “native”, “386bsd”, “4bsd”, “bsdos”, “freebsd”, “hpux”, “isc”, “linux”, “netbsd”, “osf1”, “sco”, “solaris”, “sunos”, “svr3”, “svr4” and “ultrix”.

The “native” and “hpux” device identifier is 4 bytes in size and consists of:

OffsetSizeValueDescription
01Major device number
13Minor device number

The “386bsd”, “4bsd”, “freebsd”, “isc”, “linux”, “netbsd”, “sco”, “sunos”, “svr3” and “ultrix” device identifier is 4 bytes in size and consists of:

OffsetSizeValueDescription
020Unknown
21Major device number
31Minor device number

The “solaris” and “svr4” device identifier is 4 bytes in size and consists of:

OffsetSizeValueDescription
0.018 bitsMinor device number
2.214 bitsMajor device number

The “bsdos” and “osf1” device identifier is 4 bytes in size and consists of:

OffsetSizeValueDescription
0.020 bitsMinor device number
2.412 bitsMajor device number

The “bsdos” alternative device identifier is 4 bytes in size and consists of:

OffsetSizeValueDescription
0.08 bitsSub unit number
1.012 bitsUnit number
2.412 bitsMajor device number

The data fork of a symbolic link contains the path of the directory or file it refers to.

On HFS+/HFSX the symbolic link target contains a POSIX pathname, as used by the Mac OS BSD and Cocoa programming interfaces; not a traditional Mac OS or Carbon, path.

The path is stored as an UTF-8 encoded string without an end-of-string character. The length of the path should be 1024 bytes or less. The path may be full or partial, with or without a leading forward slash.

The first 8 bytes of the file information should contain “slnkrhap”.

ValueIdentifierDescription
"slnk"kSymLinkFileTypeSymbolic link file type
"rhap"kSymLinkCreatorSymbolic link file creator

The resource fork of a symbolic link is reserved and should be 0 bytes in size.

The catalog file

The catalog file is a B-tree file used to maintain information about the hierarchy of files and directories of a volume.

The block number of the first file extent of the catalog file (the header node) is stored in the master directory block (HFS) or the volume header (HFS+). The B-tree structure is described in section: B-tree files.

Each node in the catalog file is assigned a unique catalog node identifier (CNID). The CNID is used for both directory and file identifiers. For any given file or directory the parent identifier is the CNID of the parent directory. The first 16 CNIDs are reserved for use by Apple and include the following standard assignments:

CNIDIdentifierAssignment
0Unknown (Reserved)
1kHFSRootParentIDParent identifier of the root directory (folder)
2kHFSRootFolderIDDirectory identifier of the root directory (folder)
3kHFSExtentsFileIDExtents overflow file
4kHFSCatalogFileIDCatalog file
5kHFSBadBlockFileIDBad allocation block file
6kHFSAllocationFileIDAllocation file (HFS+)
7kHFSStartupFileIDStartup file (HFS+)
8kHFSAttributesFileIDAttributes file (HFS+)
14kHFSRepairCatalogFileIDUsed temporarily by fsck_hfs when rebuilding the catalog file
15kHFSBogusExtentFileIDBogus extent file, which is used temporarily during exchange files operations
16kHFSFirstUserCatalogNodeIDFirst available CNID for user's files and folders

Catalog file keys

In a catalog file a key consists of:

  • parent directory identifier
  • (optional) file or directory name

The volume reference number is not included in the search key.

Text encoding hint

Encoding typeValueEncodings bitmap number
MacRoman00
MacJapanese11
MacChineseTrad22
MacKorean33
MacArabic44
MacHebrew55
MacGreek66
MacCyrillic77
MacDevanagari99
MacGurmukhi1010
MacGujarati1111
MacOriya1212
MacBengali1313
MacTamil1414
MacTelugu1515
MacKannada1616
MacMalayalam1717
MacSinhalese1818
MacBurmese1919
MacKhmer2020
MacThai2121
MacLaotian2222
MacGeorgian2323
MacArmenian2424
MacChineseSimp2525
MacTibetan2626
MacMongolian2727
MacEthiopic2828
MacCentralEurRoman2929
MacVietnamese3030
MacExtArabic3131
MacSymbol3333
MacDingbats3434
MacTurkish3535
MacCroatian3636
MacIcelandic3737
MacRomanian3838
MacFarsi14049
MacUkrainian15248

HFS catalog key

The HFS catalog key is of variable size and consists of:

OffsetSizeValueDescription
01Key data size, in bytes, which consists of a signed 8-bit integer
If key data size >= 6
11Unknown (Reserved)
24Parent identifier (CNID)
61Name size without the end-of-string character
7...Name string, which contains a narrow character string without end-of-string character
......Unknown (Alignment padding)

Note that a key data size of 0 indicates a records that is no longer in use.

The catalog node name always is stored as 32 bytes and therefore the maximum key size within an index node should be 37. In a leaf node the catalog node name varies in size.

Keys in a leaf node must be stored 16-bit aligned within the node data. The size of the alignment padding is not included in the key data size.

HFS+ and HFSX catalog key

The HFS+ and HFSX catalog key is of variable size and consists of:

OffsetSizeValueDescription
02Key data size, in bytes
If key data size >= 4
24Parent identifier, which contains a CNID
If key data size >= 6
62Number of characters in the name string
8...Name string, which contains an UTF-16 big-endian string without end-of-string character

Note that the characters ‘:’ and U+2400 are stored as ‘/’ and U+0 respectively and must be converted before comparision.

The catalog data

A catalog leaf node can contain four different types of records:

  • a folder record, which contains information about a single directory.
  • a file record, which contains information about a single file.
  • a folder thread record, which provides a link between a directory and its parent directory.
  • a file thread record, which provides a link between a file and its parent directory.

The thread records are used to find the name and directory identifier of the parent of a given file or directory.

Each catalog data record consists of:

  • the catalog data record header;
  • the catalog data record data.

The catalog data record header

HFS catalog data record header

The HFS catalog data record header is 2 bytes in size and consists of:

OffsetSizeValueDescription
01Record type, which consists of a signed 8-bit integer
110x00Unknown (Reserved), which consists of a signed 8-bit integer

Note that to distinguish between HFS and HFS+ record types, record type should be treated as a 16-bit big-endian value.

HFS+ and HFSX catalog data record header

The HFS+ and HFSX catalog data record header is 2 bytes in size and consists of:

OffsetSizeValueDescription
02Record type
The catalog data record types
ValueIdentifierDescription
0x0001kHFSPlusFolderRecordHFS+/HFSX Folder record
0x0002kHFSPlusFileRecordHFS+/HFSX File record
0x0003kHFSPlusFolderThreadRecordHFS+/HFSX Folder thread record
0x0004kHFSPlusFileThreadRecordHFS+/HFSX File thread record
0x0100kHFSFolderRecord (or cdrDirRec)HFS Folder record
0x0200kHFSFileRecord (or cdrFilRec)HFS File record
0x0300kHFSFolderThreadRecord (or cdrThdRec)HFS Folder thread record
0x0400kHFSFileThreadRecord (or cdrFThdRec)HFS File thread record

The catalog folder record

HFS catalog folder record

The HFS catalog folder record (cdrDirRec, kHFSFolderRecord) is 70 bytes in size and consists of:

OffsetSizeValueDescription
020x0100Record type
22Folder flags
42Number of directory entries (valence)
64Identifier (CNID)
104Creation time, which contains a HFS timestamp in local time
144(last) content modification time, which contains a HFS timestamp in local time
184(last) backup time, which contains a HFS timestamp in local time
2216Folder information
3816Extended folder information
544 x 4 = 16Unknown (Reserved), which consists of an array of 32-bit integer values
HFS catalog folder record flags

Not defined. The HFS catalog folder record appears to always have a corresponding folder thread record.

HFS+ and HFSX catalog folder record

The HFS+ and HFSX catalog folder record (HFSPlusCatalogFolder) is 88 bytes in size and consists of:

OffsetSizeValueDescription
020x0001Record type
22Flags
44Number of directory entries (valence)
84Identifier (CNID)
124Creation time, which contains a HFS timestamp in UTC
164(last) content modification time, which contains a HFS timestamp in UTC
204(last) record (or attribute) modification (or change) time, which contains a HFS timestamp in UTC
244(last) access time, which contains a HFS timestamp in UTC
284(last) backup time, which contains a HFS timestamp in UTC
Permissions
324Owner identifier
364Group identifier
401Administration flags
411Owner flags
422File mode
444Special permission data
Folder information
4816Folder information
Extended folder information
6416Extended folder information
 
804Text encoding hint
8440x00Unknown (Reserved)

The catalog file record

HFS catalog file record

The HFS catalog file record (cdrFilRec, kHFSFileRecord) is 102 bytes in size and consists of:

OffsetSizeValueDescription
020x0200Record type
21Flags, which consists of a signed 8-bit integer
310x00File type, which consists of a signed 8-bit integer and should contain 0
416File information
204Identifier (CNID)
242Data fork block number
264Data fork size
304Data fork allocated size
342Resource fork block number
364Resource fork size
404Resource fork allocated size
444Creation time, which contains a HFS timestamp in local time
484(last) content modification time, which contains a HFS timestamp in local time
524(last) backup time, which contains a HFS timestamp in local time
5616Extended file information
722Clump size
7412Data fork extents record
8612Resource fork extents record
9840x00Unknown (Reserved)

TODO: determine if the data and resource fork block number values are used

HFS catalog file record flags
ValueIdentifierDescription
0x0001File is locked and cannot be written to
0x0002Has thread record
0x0080kHFSHasDateAddedMaskHad added time
HFS+ and HFSX catalog file record

The HFS+ and HFSX catalog file record (kHFSPlusFileRecord) is 248 bytes in size and consists of:

OffsetSizeValueDescription
020x0002Record type
22Flags
440x00Unknown (Reserved)
84Identifier (CNID)
124Creation time, which contains a HFS timestamp in UTC
164(last) content modification time, which contains a HFS timestamp in UTC
204(last) record (or attribute) modification time, which contains a HFS timestamp in UTC
244(last) access time, which contains a HFS timestamp in UTC
284(last) backup time, which contains a HFS timestamp in UTC
Permissions
324Owner identifier
364Group identifier
401Administration flags
411Owner flags
422File mode
444Special permission data
File information
4816File information (or user information)
Extended file information
6416Extended file information (or finder information)
 
804Text encoding hint
8440x00Unknown (Reserved)
8880Data fork descriptor
16880Resource fork descriptor
HFS+ catalog file record flags
ValueIdentifierDescription
0x0001kHFSFileLockedMaskFile is locked and cannot be written to
0x0002kHFSThreadExistsMaskHas thread record, which should be always set for a file record on HFS+/HSFX
0x0004kHFSHasAttributesMaskHas extended attributes
0x0008kHFSHasSecurityMaskHas ACLs
0x0010kHFSHasFolderCountMaskHas number of sub-folder
0x0020kHFSHasLinkChainMaskHas a hard link target (link chain), where the CNID of the hard link target is stored in the special permission data
0x0040kHFSHasChildLinkMaskHas a child that is a directory link
0x0080kHFSHasDateAddedMaskHad added time, where the extended folder of file information contains the time the folder or file was added (date_added)
0x0100kHFSFastDevPinnedMaskUnknown
0x0200kHFSDoNotFastDevPinMaskUnknown
0x0400kHFSFastDevCandidateMaskUnknown
0x0800kHFSAutoCandidateMaskUnknown

The catalog thread record

The file thread record is similar to the folder thread record except that it refers to a file, instead of a directory.

HFS catalog file thread record

The HFS catalog thread record (kHFSFolderThreadRecord (or cdrThdRec), kHFSFileThreadRecord (or cdrFThdRec)) is of variable size and consists of:

OffsetSizeValueDescription
020x0300 or 0x0400Record type
22 x 4 = 80x00Unknown (Reserved), which consists of an array of 32-bit integer values
104Parent identifier (CNID)
141Number of characters in the name string, with a maximum of 31
15...Name string, which contains a narrow character string without end-of-string character
HFS+ and HFSX catalog file thread record

The HFS+ and HFSX catalog thread record (kHFSPlusFolderThreadRecord, kHFSPlusFileThreadRecord) is of variable size and consists of:

OffsetSizeValueDescription
020x0003 or 0x0004Record type
220x00Unknown (Reserved), which consists of a unsigned 16-bit integer
44Parent identifier (CNID)
82Number of characters in the name string, with a maximum of 255
10...Name string, which contains an UTF-16 big-endian string without end-of-string character

Permissions

For each file and folder HFS+ maintains basic access permissions record for each file and folder. These are similar to basic Unix file permissions.

TODO: add note about permissions on HFS

Owner and group identifier

The Mac OS X user ID of the owner of the file or folder. Mac OS X versions prior to 10.3 treats user ID 99 as if it was the user ID of the user currently logged in to the console. If no user is logged in to the console, user ID 99 is treated as user ID 0 (root). Mac OS X version 10.3 treats user ID 99 as if it was the user ID of the process making the call (in effect, making it owned by everyone simultaneously). These substitutions happen at run-time. The actual user ID on disk is not changed.

The Mac OS X group ID of the group associated with the file or folder. Mac OS X typically maps group ID 99 to the group named “unknown.” There is no run-time substitution of group IDs in Mac OS X.

Administration flags

ValueIdentifierDescription
0x01SF_ARCHIVEDFile has been archived
0x02SF_IMMUTABLEFile is immutable and may not be changed
0x04SF_APPENDWrites to file may only append

Owner flags

ValueIdentifierDescription
0x01UF_NODUMPDo not backup (dump) this file
0x02UF_IMMUTABLEFile is immutable and may not be changed
0x04UF_APPENDWrites to file may only append
0x08UF_OPAQUEDirectory is opaque

File mode

ValueIdentifierDescription
0xf000 (0170000)S_IFMTFile type bitmask
0x1000 (0010000)S_IFIFONamed pipe
0x2000 (0020000)S_IFCHRCharacter-special file (Character device)
0x4000 (0040000)S_IFDIRDirectory
0x6000 (0060000)S_IFBLKBlock-special file (Block device)
0x8000 (0100000)S_IFREGRegular file
0xa000 (0120000)S_IFLNKSymbolic link
0xc000 (0140000)S_IFSOCKSocket
0xe000 (0160000)S_IFWHTWhiteout, which is a file entry that covers up all entries of a particular name from lower branches

HFS+ uses the BSD file type and mode bits. Note that the constants from the header shown below are in octal (base eight), not hexadecimal.

Octal valueIdentifierDescription
0004000S_ISUIDSet user identifier on execution
0002000S_ISGIDSet group identifier on execution
0001000S_ISTXTSticky bit
0000700S_IRWXURead, write and execute access for owner
0000400S_IRUSRRead access for owner
0000200S_IWUSRWrite access for owner
0000100S_IXUSRExecute access for owner
0000070S_IRWXGRead, write and execute access for group
0000040S_IRGRPRead access for group
0000020S_IWGRPWrite access for group
0000010S_IXGRPExecute access for group
0000007S_IRWXORead, write and execute access for other
0000004S_IROTHRead access for other
0000002S_IWOTHWrite access for other
0000001S_IXOTHExecute access for other

Note that if the sticky bit is set for a directory, then Mac OS restricts movement, deletion, and renaming of files in that directory. Files may be removed or renamed only if the user has write access to the directory; and is the owner of the file or the directory, or is the super-user.

HFS+ file special permission data

The special permission data is used to store the following information:

  • hard link reference (iNodeNum)
  • number of (hard) links (linkCount) in indirect node files
  • device numbers of block (S_IFBLK) and character (S_IFCHR) devices files

File system hierarchy

File and folder records have a search key with a non-empty name string. In thread records the name string in the search key is empty. E.g. to list the file entries in a directory:

  • find all the file or folder records given the parent CNID

Finding a file or directory by its CNID is a two-step process:

  1. use the CNID to look up the thread record for the file or directory
  2. use the thread record to look up the file or folder record

File forks

Forks in HFS and HFS+ can be compared to data streams in NTFS. In HFS+ the fork values are grouped in a separate fork descriptor structure. HFS+ also defines extended attributes (named forks). These are not stored in the catalog file but in the attributes file.

HFS+ fork descriptor structure

HFS+ maintains information about file contents using the HFS+ fork descriptor structure (HFSPlusForkData).

The fork descriptor structure is 80 bytes in size and consists of:

OffsetSizeValueDescription
08Size, in bytes
84Clump size, in bytes
124Number of blocks
1664Data extents record

The extents overflow file

In HFS and HFS+ extents (contiguous ranges of blocks) are used to track which blocks belong to a file. The first three (HFS) and eight (HFS+) are stored in the catalog file. Additional extents are stored in the extents overflow file.

The structure of an extents overflow file is relatively simple compared to that of a catalog file. The function of the extents overflow file is to store those file extents that are not contained in the master directory block (MDB) or volume header and the catalog file

Note that the file system B-tree files can have additional extents in the extents overflow file. This has been observed with the attributes file. It is currently unknown if the extents (overflow) file itself can have overflow extents.

The extents overflow key (record)

Disks initialized using the enhanced Disk Initialization Manager introduced in system software version might contain extent records for some blocks that do not belong to any actual file in the file system. These extent records have been marked as a bad block (CNID 5). See the chapter “Disk Initialization Manager” in this book for details on bad block sparing.

The key has been selected so that the extent records for a particular fork are grouped together in the B-tree, right next to all the extent records for the other fork of the file. The fork offset of the preceding extent record is needed to determine the key of the next extent record

In an extents overflow file the search key consists of:

  • fork type
  • file identifier
  • first block in the extent

HFS extents overflow key (record)

The HFS extents overflow key (record) is 8 bytes in size and consists of:

OffsetSizeValueDescription
017Key data size, in bytes, which consists of a signed 8-bit integer
11Fork type, which consists of a signed 8-bit integer
24File identifier (CNID)
62Logical block number

The first 8 extents in a fork are held in its catalog file record. So the number of extent records for a fork is:

(number_of_extents - 3 + 2) / 4

HFS+ and HFSX extents overflow key (record)

The HFS+ and HFSX extents overflow key (record) is 12 bytes in size and consists of:

OffsetSizeValueDescription
0210Key data size, in bytes, which consists of an unsigned 16-bit integer
21Fork type, which consists of a signed 8-bit integer
310x00Unknown (Padding)
44File identifier (CNID)
84Logical block number

The first 8 extents in a fork are held in its catalog file record. So the number of extent records for a fork is:

(number_of_extents - 8 + 7) / 8

HFS fork types

ValueIdentifierDescription
-1 (0xff)Resource fork
0 (0x00)Data fork

The extent (data) record

An extent is a contiguous range of blocks that have been allocated to an individual file. An extent is represented by an extent descriptor.

HFS extents record

The HFS extents record (HFSExtentRecord) is 12 bytes in size and consists of:

OffsetSizeValueDescription
03 x 4 = 12Array of HFS extent descriptors

HFS extent descriptor

The HFS extents descriptor (HFSExtentDescriptor) is 4 bytes in size and consists of:

OffsetSizeValueDescription
02Physical block number, which contains a block number relative from the start of the data area
22Number of blocks
extent_offset = (data_area_block_number + extent_block_number) * block_size

An unused extent descriptor should have both the block number and number of blocks set to 0.

HFS+ and HFSX extents record

The HFS+ and HFSX extents record (HFSPlusExtentRecord) is 64 bytes in size and consists of:

OffsetSizeValueDescription
08 x 8 = 64Array of HFS+ extent descriptors

HFS+ and HFSX extent descriptor

The HFS+ and HFSX extents descriptor (HFSPlusExtentDescriptor) is 8 bytes in size and consists of:

OffsetSizeValueDescription
04Physical block number, which contains a block number relative from the start of the volume
44Number of blocks
extent_offset = extent_block_number * block_size

An unused extent descriptor should have both the block number and number of blocks set to 0.

Bad Block File

The extents overflow file is also used to hold information about the bad blocks; refered to as the bad block file. The bad block file is used to mark areas on the disk as bad, unable to be used for storing data; typically to map out bad sectors on the storage medium.

Typically, blocks are larger than sectors. If a single sector is found to be bad, the entire block is unusable. The bad block file is sometimes used to mark blocks as unusable when they are not bad, e.g. in the HFS wrapper.

Bad block extent records are always assumed to reference the data fork (fork type of 0).

Allocation (bitmap) file

The allocation file is uzed to keep track of whether each block in a volume is currently allocated to some file system structure or not. The contents of the allocation file is a bitmap. The bitmap contains one bit for each block in the volume.

  • If a bit is set, the corresponding block is currently in use by some file system structure.
  • If a bit is clear, the corresponding block is not currently in use, and is available for allocation.

The size of the allocation file depends on the number of blocks in the volume, which in turn depends both on the size of the disk and on the size of the volume’s blocks. For example, a volume on a 1 GB disk and having an block size of 4 KB needs an allocation file size of 256 Kbits (32 KiB, or 8 blocks). Since the allocation file itself is allocated using blocks, it always occupies an integral number of blocks (its size may be rounded up).

The allocation file may be larger than the minimum number of bits required for the given volume size. Any unused bits in the bitmap must be set to 0.

Each byte in the allocation file holds the state of eight blocks. The byte at offset X into the file contains the allocation state of allocations blocks (N x 8) through (N x 8 + 7). Within each byte, the most significant bit holds information about the block with the lowest number, the least significant bit holds information about the block with the highest number. Listing 1 shows how you would test whether an block is in use, assuming that you’ve read the entire allocation file into memory.

Method to determine whether a block is used:

byte_value = allocation_file_data[block_number // 8]

is_used = (byte_value & (1 << (7 - (block_number % 8)))) != 0

Attributes file

The attributes file is a B-tree file used to store extended attributes.

The location of the attributes file can be found in the HFS+ and HFSX volume header.

Attributes file keys

An attributes file key (HFSPlusAttrKey) is of variable size and consists of:

OffsetSizeValueDescription
02Key data size, in bytes
If key data size >= 12
220Unknown (padding)
44Identifier (CNID)
84Logical block number
122Number of characters in the name string
14...Name string, which contains an UTF-16 big-endian string without end-of-string character

Note that the name of an extended attribute appears to be case senstive even on a case insensitive file system.

The attributes file data

The attributes file defines two types of attributes:

  1. Fork data attributes, which are used for attributes whose data is large. The attribute’s data is stored in extents on the volume and the attribute merely contains a reference to those extents.
  2. Extension attributes, which are used to augment fork descriptor structure, allowing a forks to have more than eight extents.

Attributes file data record header

Each attributes file data record starts with a type value, which describes the type of attribute data record.

The attributes file data record header is 4 bytes in size and consists of:

OffsetSizeValueDescription
04Record type
The attributes data record types
ValueIdentifierDescription
0x00000010kHFSPlusAttrInlineDataAttribute record with inline data
0x00000020kHFSPlusAttrForkDataAttribute record with fork descriptor
0x00000030kHFSPlusAttrExtentsExtents overflow record for a kHFSPlusAttrForkData record

Note that at the moment it is unclear when an attribute record of type kHFSPlusAttrExtents is created and how it should be handled.

The inline data attribute record

The inline data attribute record (HFSPlusAttrData) is of variable size and consists of:

OffsetSizeValueDescription
040x00000010Record type
42 x 4 = 80Unknown (reserved)
124Attribute data size
16...Attribute data

Note that is also a HFSPlusAttrInlineData record, which is obsolete and has not been observed to be used.

The fork descriptor attribute record

The fork descriptor attribute record (HFSPlusAttrForkData) is 88 bytes in size and consists of:

OffsetSizeValueDescription
040x00000020Record type
440Unknown (reserved)
880Attribute fork descriptor

The extents attribute record

The extents attribute record (HFSPlusAttrExtents) is 72 bytes in size and consists of:

OffsetSizeValueDescription
040x00000030Record type
440Unknown (reserved)
864Attribute extents record

Startup file

The startup file is a file system metadata file intended to hold information needed when booting a system that does not have built-in (ROM) support for HFS+ (or HFSX). A boot loader can find the startup file without full knowledge of the format using the first eight extents of the startup file located in the volume header.

Format wise it is valid for the startup file to contain more than eight extents, but in doing so the purpose of the startup file is defeated.

The next block number is used by Mac OS as a hint for where to start searching for available blocks when allocating space for a file.

Metadata zone and hot files

In Mac OS X 10.3 a metadata zone was instroduced to store certain file system metadata, such as allocation bitmap file, extents overflow file, and the catalog file, the journal file and frequently used small files (also referred to as “hot files”) near each other to reduces seek time for typical accesses.

Hot File B-tree

The hot file B-tree is a file named “.hotfiles.btree” stored the root directory.

Journal

A HFS+ (or HFSX) volume may have an optional journal to speed recovery when mounting a volume that was not unmounted safely. The purpose of the journal is to ensure that when a group of related changes are being made, that either all of those changes are actually made, or none of them are made. The journal makes it quick and easy to restore the volume structures to a consistent state, without having to scan all of the structures. The journal is used only for the volume structures and metadata; it does not protect the contents of a fork.

The volume header specifies if journalling is activated.

The journal data stuctures consist of:

  • a journal information block, contains the location and size of the journal header and journal buffer;
  • a journal header, describes which part of the journal buffer is active and contains transactions waiting to be committed;
  • a journal buffer, a cyclic buffer to hold the file system meta data transactions.

On HFS+ volumes, the journal information block is stored as a file. The name of that file is “.journal_info_block” and it is stored in the volume’s root directory.

The journal header and journal buffer are stored together in a different file named “.journal”, also in the volume’s root directory. Each of these files are contiguous on disk, they occupy exactly one extent.

The volume header contains the extent of the journal information block file. The journal information block contains the location of the journal file.

Journal information block

The journal information block describes where the journal header and journal buffer are stored. The journal information block is stored at the start of the block referred to by the volume header.

The journal information block is 44 bytes in size and consists of:

OffsetSizeValueDescription
04Journal flags
48 x 4 = 32Device signature
368Journal header offset
448Journal size, in bytes, which includes the size of the journal header and the journal buffer, but not the journal information block
5232 x 4 = 1280x00Unknown (Reserved)

Journal flags

The journal flags consist of the following values:

Value(s)Description
0x00000001On volume, where the journal header offset is relative to the start of the volume
0x00000002On other device, where the device signature identifies the device containing the journal and the journal header offset is relative to the start of the device
0x00000004Needs initialization, to indicate that there are no valid transactions in the journal and needs to be initialized

Note that according to TN1150 journals stored on a separate device are not supported.

The journal header

The journal header is 44 bytes in size and consists of:

OffsetSizeValueDescription
04"\x4a\x4e\x4c\x78"Signature
44"\x12\x34\x56\x78"Byte order (or endian) signature
88First transaction start offset
168Next transaction start offset
248Journal size, in bytes, which includes the size of the journal header and buffer
324Journal block header size, in bytes, typically ranges from 4096 to 16384
364checksum
404Journal header size, in bytes, typically the size of one sector

First and next transaction offset

The first transaction offset contains the offset in bytes from the start of the journal header to the start of the first (oldest) transaction.

The next transaction offset contains the offset in bytes from the start of the journal header to the end of the last (newest) transaction. Note that this field may be less than the start field, indicating that the transactions wrap around the end of the journal’s circular buffer. If end equals start, then the journal is empty, and there are no transactions that need to be replayed.

Journal transactions

A single transaction is stored in the journal as several blocks. These blocks include both the data to be written and the location where that data is to be written. This is represented on storage medium by a block list header, which describes the number and sizes of the blocks, immediately followed by the contents of those blocks.

Since block list headers are of limited size, a single transaction may consist of several block list headers and their associated block contents. If the next value in the first block information structure is non-zero, then the next block list header is a continuation of the same transaction.

The journal buffer is treated as a circular buffer. When reading or writing the journal buffer, the I/O operation must stop at the end of the journal buffer and resume (wrap around) immediately following the journal header. Block list headers or the contents of blocks may wrap around in this way. Only a portion of the journal buffer is active at any given time; this portion is indicated by the start and end fields of the journal header. The part of the journal buffer that is not active contains no meaningful data, and must be ignored.

To prevent ambiguity when start equals end, the journal is never allowed to be perfectly full (all of the journal buffer used by block lists and blocks). If the journal was perfectly full, and start was not equal to jhdr_size, then end would be equal to start. You would then be unable to differentiate between an empty and full journal.

When the journal is not empty (contains transactions), it must be replayed to be sure the volume is consistent. That is, the data from each of the transactions must be written to the correct blocks on disk.

The journal block list header

The block list header describes a list of blocks included in a transaction. A transaction may include several block lists if it modifies more blocks than can be represented in a single block list.

The journal block list header is 16 bytes in size and consists of:

OffsetSizeValueDescription
02Maximum number of journal blocks
22Number of journal blocks following the journal block header, typically 1
44Block list size, in bytes, which includess the size of the header and blocks
84Checksum
1240x00Unknown (Alignment padding)
16...Journal block information array

Note that the number of journal blocks includes the first journal block, The first journal block is reserved to be used when multiple blocks need to be chained, therefore the number of journal blocks actually containing data is minus one (-1).

Journal block information

The journal block information is 16 bytes in size and consists of:

OffsetSizeValueDescription
08Block sector number
84Block size, in bytes
124Next journal block

Journal checksum

The journal header and block list header both contain checksum values. The checksums are verified as part of a basic consistency check of these journal data structures. To verify the checksum, temporarily set the checksum field to 0 and then call the hfs_plus_calculate_checksum routine as specified below.

uint32_t hfs_plus_calculate_checksum(
          uint8_t *buffer,
          size_t buffer_size )
{
    size_t buffer_offset = 0;
    uint32_t checksum    = 0;

    for( buffer_offset = 0;
         buffer_offset < buffer_size;
         buffer_offset++)
    {
        checksum = ( checksum << 8 ) ^ ( checksum + buffer[ buffer_offset ] );
    }
    return( ~checksum );
}

Application specific data structures

HFS, HFS+ and HFSX contain application specific data structures.

Finder information

The finder information in the master directory block (MDB) and volume header consists of an array of 32-bit values. This array contains information used by the Mac OS Finder and the system software boot process.

Array entryDescription
0Bootable system directory identifier (CNID), i.e. "System Folder" in Mac OS 8 or 9, or "/System/Library/CoreServices" in Mac OS X. Typically 3 or 5, is 0 if the volume is not bootable
1Startup application parent identifier (CNID), i.e. "Finder". Is 0 if the volume is not bootable
2Directory identifier (CNID) to display in Finder on mount, or 0 if none
3Directory identifier (CNID) of a bootable Mac OS 8 or 9 System Folder, or 0 if none
4Unknown (Reserved)
5Directory identifier (CNID) of a bootable Mac OS X system, the "/System/Library/CoreServices" directory, or 0 if none
6 and 7Mac OS X Volume Status Database (VSDB) volume identifier

To convert the VSDB volume identifier into a UUID:

  • Append the volume identifier to HFS_UUID_NAMESPACE_ID (B3E20F39-F292-11D6-97A4-00306543ECAC)
  • Calculate the MD5 digest hash of the byte sequence
  • Convert the MD5 digest hash into the UUID, see below
data = bytes.fromhex("b3e20f39f29211d697a400306543ecac") + volume_identifier
hash = hashlib.md5(data).hexdigest()
part1 = hash[0:8]
part2 = hash[8:12]
part3 = "".join(["3", hash[13:16]])
digit = (int(hash[16], 16) & 3) | 8
part4 = "".join([f"{digit:x}", hash[17:20])
part5 = hash[20:]
uuid = "-".join([part1, part2, part3, part4, part5])

Note that on Mac OS the finder information can be viewed using bless --info volume_mount_path.

File information

HFS file information

The HFS file information is 16 bytes in size and consists of:

OffsetSizeValueDescription
04 x 1 = 4File type, which consists of an array of unsigned 8-bit integers
44 x 1 = 4File creator, which consists of an array of unsigned 8-bit integers
82Finder flags
104Location within the parent, which contains x and y-coordinate values. If set to {0, 0}, the Finder will place the item automatically
142File icon window, which contains the window in which the file's icon appears

HFS extended file information

The HFS extended file information is 16 bytes in size and consists of:

OffsetSizeValueDescription
02Finder icon identifier
23 x 2 = 6Unknown (Reserved), which consists of an array of signed 16-bit integers
81Extended finder script code flags
91Extended finder flags
102Finder comment identifier, which consists of a signed 16-bit integer
124Put away folder identifier (CNID)

HFS+ and HFSX file information

The HFS+ and HFSX file information (FileInfo) is 16 bytes in size and consists of:

OffsetSizeValueDescription
04 x 1 = 4File type, which consists of an array of unsigned 8-bit integers
44 x 1 = 4File creator, which consists of an array of unsigned 8-bit integers
82Finder flags
104Location within the parent, which contains x and y-coordinate values. If set to {0, 0}, the Finder will place the item automatically
142Unknown (Reserved)

HFS+ and HFSX extended file information

The HFS+ and HFSX extended file information (ExtendedFileInfo) is 16 bytes in size and consists of:

OffsetSizeValueDescription
04Unknown (Reserved)
If kHFSHasDateAddedMask is not set
44Unknown (Reserved)
If kHFSHasDateAddedMask is set
44Added time, which contains a POSIX timestamp in UTC
Common
82Extended finder flags
102Unknown (Reserved), which consists of a signed 16-bit integer
124Put away folder identifier (CNID)

Folder information

HFS folder information

The HFS folder information is 16 bytes in size and consists of:

OffsetSizeValueDescription
08Window position and dimension (boundaries), which contains the top, left, bottom, right-coordinate values
82Finder flags
104Location within the parent, which contains x and y-coordinate values. If set to {0, 0}, the Finder will place the item automatically
142Folder view

HFS extended folder information

The HFS extended folder information is 16 bytes in size and consists of:

OffsetSizeValueDescription
04Scroll position for icon view, which contains x and y-coordinate values
If kHFSHasDateAddedMask is not set
44Open folder identifier chain, which consists of a signed 32-bit integer
If kHFSHasDateAddedMask is set
44Added time, which contains a POSIX timestamp in UTC
Common
81Extended finder script code flags
91Extended finder flags
102Finder comment identifier, which consists of a signed 16-bit integer
124Put away folder identifier (CNID)

HFS+ and HFSX folder information

The HFS+ and HFSX folder information is 16 bytes in size and consists of:

OffsetSizeValueDescription
08Window position and dimension (boundaries), which contains the top, left, bottom, right-coordinate values
82Finder flags
104Location within the parent, which contains x and y-coordinate values. If set to {0, 0}, the Finder will place the item automatically
142Unknown (Reserved)

HFS+ and HFSX extended folder information

The HFS+ and HFSX extended folder information is 16 bytes in size and consists of:

OffsetSizeValueDescription
04Scroll position for icon view, which contains x and y-coordinate values
44Unknown (Reserved), which consists of a signed 32-bit integer
82Extended finder flags
102Unknown (Reserved), which consists of a signed 16-bit integer
124Put away folder identifier (CNID)

Finder flags

The finder flags consists of the following values:

Value(s)Applies toDescription
0x0001Files and foldersIs on desktop
0x000eFiles and foldersColor
0x0040FilesIs shared
0x0080FilesHas no INITs
0x0100FilesHas been inited
0x0400Files and foldersHas custom icon
0x0800FilesIs stationary
0x1000Files and foldersName locked
0x2000FilesHas bundle
0x4000Files and foldersIs invisible
0x8000FilesIs alias

Extended finder flags

The extended finder flags consists of the following values:

Value(s)Description
0x0004Has routing information
0x0100Has custom badge resource
0x8000Extended flags are invalid, which indicates that set the other extended flags should be ignored

Notes

struct Point {
  SInt16              v;
  SInt16              h;
};
typedef struct Point  Point;

struct Rect {
  SInt16              top;
  SInt16              left;
  SInt16              bottom;
  SInt16              right;
};
typedef struct Rect   Rect;

/* OSType is a 32-bit value made by packing four 1-byte characters
   together. */
typedef UInt32        FourCharCode;
typedef FourCharCode  OSType;

File content

HFS supports multiple ways to store file content:

  • Data fork
  • Resource fork
  • Extended attribute (named fork)
  • Apple File System Compression (decmpfs)

Data fork

The file content size is stored in the data fork descriptor of the catalog file record.

The extents of the file content are stored in the fork descriptor and extents overflow file.

Resource fork

The file content size is stored in the resource fork descriptor of the catalog file record.

The extents of the file content are stored in the fork descriptor and extents overflow file.

Note that the resource fork is sometimes represented as an extended attribute with the name: “com.apple.ResourceFork”.

Extended attribute (named fork)

Extended attributes, also referred to as named forks, are stored in the HFS+ attributes file.

Apple File System Compression (decmpfs)

The file has an extended attribute named “com.apple.decmpfs” and the content is stored using Apple File System Compression (decmpfs).

HFS wrapper

A HFS wrapped HFS+ file system consists of a HFS file system where the master directory block (MDB) contains:

  • an embedded volume signature of “H+”;
  • an embedded volume extent descriptor that describes the blocks in which the embedded volume is stored;
  • the embedded volume extent is marked in the bad block file.

Note that Mac OS supports a HFS+ to be wrapped in a HFS volume, but not HFSX.

embedded volume offset = (
    (data area start sector * 512) + (embedded volume block number * block size)
)

References

Macintosh File System (MFS)

The Macintosh File System (MFS) is the first file system created for Mac OS, intended for 400 KiB floppy disks.

Overview

A MFS file system consists of:

The backup master directory block (MDB), is stored in the last 2 sectors of the volume.

Characteristics

CharacteristicsDescription
Byte orderbig-endian
Date and time valuesTODO
Character stringsNarrow character (Single Byte Character (SBC) or Multi Byte Character (MBC)) stored using a system defined codepage

Terminology

TermDescription
Clump sizeSize of the group of (allocation) blocks (or clump), in bytes, to avoid fragmentation

Boot Block

If a volume is bootable, the first 2 blocks of the volume contain boot block. The boot block consists of:

  • boot block header
  • boot code
  • unknown (filler)

Boot Block Header

The boot block header is 138 or 144 bytes in size and consists of:

OffsetSizeValueDescription
02"LK" (or "\x4c\x4b")Boot block signature
24Boot code entry point
61Flags
71Format version
82Page flags (or Secondary Sound and Video Pages)
101System file name size, with a maximum of 15
1115System file name
261Finder (or shell) file name size, with a maximum of 15
2715Finder (or shell) file name, typically "Finder"
421Debugger file name size, with a maximum of 15
4315Debugger file name, typically "Macsbug"
581Disassembler (or second debugger) file name size, with a maximum of 15
5915Disassembler (or second debugger) file name, typically "Disassembler"
741Startup screen file name size, with a maximum of 15
7515Startup screen file name, typically "StartUpScreen"
901Startup (or bootup) file name size, with a maximum of 15
9115Startup (or bootup) file name, typically "Finder"
1061Clipboard (or scrap) file name size, with a maximum of 15
10715Clipboard (or scrap) file name, typically "Clipboard"
1222Number of allocated file control blocks (FCBs)
1242Number of elements in the event queue, typically 20
1264System heap size on Macintosh computer with 128 KiB of RAM
1304System heap size on Macintosh computer with 256 KiB of RAM
1344System heap size on Macintosh computer with +512 KiB of RAM
Newer boot block header format
1384Additional system heap space
1404Fraction of available RAM for the system heap

Note that “LK” presumably is short for “Larry Kenyon” who originally designed MFS.

Boot code entry point

The boot code entry point contains machine-language instructions that translate to:

BRA.S *+ 0x90

Or for older versions of the boot block header:

BRA.S *+ 0x88
BRA.W *+ 0x88
BRA     $88(PC)         * $6000,$0086

This instruction jumps to the main boot code following the boot block header.

This field is ignored, however, if bit 6 is clear in the high-order byte of the boot block version number or if the low-order byte contains 0x0d.

Boot Block Header Flags

Bit(s)Description
0 - 4Unknown (Reserved), should contain 0
5Use relative system heap sizing
6Execute boot code
7Newer boot block header format is used

If bit 7 of the flag byte is clear, then bits 5 and 6 are ignored and the version number is set in the format version value.

If the format version value is:

  • less than 21, the values in the system heap size on 128K Mac and 256K Mac should be ignored and the value in system heap size on all machines should be used.
  • 13 the boot code should be executed using the value in boot code entry point.
  • greater than or equal to 21 the value in system heap size on all machines should be used.

If bit 7 of the flag byte is set

  • bit 6 should be used to determine whether to execute the boot code using the value in boot code entry point.
  • bit 5 should be used to determine whether to use relative System heap sizing. If bit 5 is
    • clear the value in system heap size on all machines should be used.
    • is set the System heap is extended by the value in the additional system heap space plus the fraction of available RAM for the system heap.

Master Directory Block (MDB)

The Master Directory Block (MDB) is located at offset 1024 of the volume and consists of:

  • master directory block header
  • block map

Master Directory Block (MDB) header

The Master Directory Block (MDB) header is 64 bytes in size and consists of:

OffsetSizeValueDescription
02"\xd2\xd7"Volume signature
24Creation date and time, which contains a HFS timestamp in local time
64Last modification date and time, which contains a HFS timestamp in local time
102Volume attribute flags
122Number of files in the root directory
142File directory area sector number, contains a sector number relative from the start of the volume, where 0 is the first sector number
162File directory area size, in number of sectors
182Number of blocks
204Block size, in bytes, must be a multitude of 512
244Clump size, in bytes
282Data area sector number, contains a sector number relative from the start of the volume, where 0 is the first sector number
304Next available file identifier
342Number of unused blocks
361Volume label size, with a maximum of 27
3727Volume label

Block map

TODO: describe similar to FAT-12 block allocation table

File Directory Area

The file directory area consists of:

  • one or more file directory entries, where an individual file directory entry does not span multiple blocks

File Directory Entry

A file directory entry is of variable size and consists of:

OffsetSizeValueDescription
01Flags, where 0x80 indicates the file directory entry is in use
110Format version
24"\x3f\x3f\x3f\x3f"File type
64File creator
102Finder flags
124Window position and dimension (boundaries), which contains the top, left, bottom, right-coordinate values
162Folder file identifier, where 0 represents the main volume, -2 the desktop, -3 the trash, otherwise, if positive, a file identifier
184File identifier
222Data fork block number, contains 0 if the file entry has no data fork
244Data fork size, in bytes
284Data fork allocated size, in bytes
322Resource fork block number, contains 0 if the file entry has no resource fork
344Resource fork size, in bytes
384Resource fork allocated size, in bytes
424Creation date and time, which contains a HFS timestamp in local time
464(Content) modification date and time, which contains a HFS timestamp in local time
501File name size, with a maximum of 255
51...File name
......16-bit alignment padding

New Technologies File System (NTFS) format

The New Technologies File System (NTFS) format is the primary file system for Microsoft Windows versions that are based on Windows NT.

Overview

An New Technologies File System (NTFS) consists of:

  • boot record
  • boot loader
  • Master File Table (MFT)
  • Mirror Master File Table (MFT)

Characteristics

CharacteristicsDescription
Byte orderlittle-endian
Date and time valuesFILETIME in UTC
Character stringsUCS-2 little-endian, which allows for unpaired Unicode surrogates such as "U+d800" and "U+dc00"

Versions

Format versionRemarks
1.0Introduced in Windows NT 3.1
1.1Introduced in Windows NT 3.5, also seen to be used by Windows NT 3.1
1.2Introduced in Windows NT 3.51
3.0Introduced in Windows 2000
3.1Introduced in Windows XP

Note that the format versions mentioned above are the version as used by NTFS. Another common versioning schema uses the Windows version, e.g. NTFS 5.0 is the version of NTFS used on Windows XP which is version 3.1 in schema mentioned above.

Windows does not necessarily uses the latest format version, e.g. Windows 10 (1809) has been observed to use NTFS version 1.2 for 64k cluster block size.

Terminology

Cluster

NTFS refers to it file system blocks as clusters. Note that these are not the same as the physical clusters of a harddisk. For clarity this document will refer to these as cluster blocks. In other sources they are also referred to as logical clusters.

Typically a cluster block is 8 sectors (or 8 x 512 = 4096 bytes) in size. A cluster block number is relative to the start of the boot record.

Virtual cluster

The term virtual cluster refers to cluster blocks which are relative to the start of a data stream.

Long and short (file) name

In Windows terminology the name of a file (or directory) can either be short or long. The short name is an equivalent of the file name in the (DOS) 8.3 format. The long name is actual the (full) name of the file. The term long refers to the aspect that the name is longer than the short variant. Because most documentation refer to the (full) name as the long name, for clarity sake so will this document.

Metadata files

NTFS uses the Master File Table (MFT) to store information about files and directories. The MFT entries reference the different volume and file system metadata. There are several predefined metadata files.

The following metadata files are predefined and use a fixed MFT entry number.

MFT entry numberFile nameDescription
0"$MFT"Master File Table
1"$MFTMirr"Back up of the first 4 entries of the Master File Table
2"$LogFile"Metadata transaction journal
3"$Volume"Volume information
4"$AttrDef"MFT entry attribute definitions
5"."Root directory
6"$Bitmap"Cluster block allocation bitmap
7"$Boot"Boot record (or boot code)
8"$BadClus"Bad clusters
Used in NTFS version 1.2 and earlier
9"$Quota"Quota information
Used in NTFS version 3.0 and later
9"$Secure"Security and access control information
Common
10"$UpCase"Case folding mappings
11"$Extend"A directory containing extended metadata files
12-15Unknown (Reserved), which are marked as in-use but are empty
16-23Unused, which are marked as unused
Used in NTFS version 3.0 and later
24"$Extend$Quota"Quota information
25"$Extend$ObjId"Unique file identifiers for distributed link tracking
26"$Extend$Reparse"Backreferences to reparse points
Transactional NTFS metadata files, which have been observed in Windows Vista and later
27"$Extend$RmMetadata"Resource manager metadata directory
28"$Extend$RmMetadata$Repair"Repair information
29 or 30"$Extend$RmMetadata$TxfLog"Transactional NTFS (TxF) log metadata directory
30 or 31"$Extend$RmMetadata$Txf"Transactional NTFS (TxF) metadata directory
31 or 32"$Extend$RmMetadata$TxfLog$Tops"TxF Old Page Stream (TOPS) file, which is used to store data that has been overwritten inside a currently active transaction
32 or 33"$Extend$RmMetadata$TxfLog$TxfLog.blf"Transactional NTFS (TxF) base log metadata file
Observed in Windows 10 and later
29"$Extend$Deleted"Temporary location for files that have an open handle but a request has been made to delete them
Common
...A file or directory

The following metadata files are predefined, however the MFT entry number is commonly used but not fixed.

MFT entry numberFile nameDescription
"$Extend$UsnJrnl"USN change journal

The boot record

The boot record is stored at the start of the volume (in the $Boot metadata file) and contains:

  • the file system signature
  • the BIOS parameter block
  • the boot loader
OffsetSizeValueDescription
03Boot entry point
38"NTFS\x20\x20\x20\x20"File system signature (Also known as OEM identifier or dummy identifier)
DOS version 2.0 BIOS parameter block (BPB)
112Bytes per sector. Note that the following values are supported by mkntfs: 256, 512, 1024, 2048 and 4096
131Number of sectors per cluster block
1420Unknown (Reserved Sectors), which is not used by NTFS and must be 0
1610Number of cluster block allocation tables, which is not used by NTFS and must be 0
1720Number of root directory entries, which is not not used by NTFS and must be 0
1920Number of sectors (16-bit), which is not used by NTFS must be 0
211Media descriptor
2220Cluster block allocation table size (16-bit) in number of sectors, which is not used by NTFS and must be 0
DOS version 3.4 BIOS parameter block (BPB)
2420x3fSectors per track, which is not used by NTFS
2620xffNumber of heads, which is not used by NTFS
2840x3fNumber of hidden sectors, which is not used by NTFS
3240x00Number of sectors (32-bit), which is not used by NTFS must be 0
NTFS version 8.0 BIOS parameter block (BPB) or extended BPB, which was introduced in Windows NT 3.1
3610x80Unknown (Disc unit number), which is not used by NTFS
3710x00Unknown (Flags), which is not used by NTFS
3810x80Unknown (BPB version signature byte), which is not used by NTFS
3910x00Unknown (Reserved), which is not used by NTFS
408Number of sectors (64-bit)
488Master File Table (MFT) cluster block number
568Mirror MFT cluster block number
644MFT entry size
684Index entry size
728Volume serial number
8040Checksum, which is not used by NTFS
Common
84426Boot code
5102"\x55\xaa"The (boot) signature

Note that the number of sectors can be 1 less then the value indicated in the partition table.

Boot entry point

The boot entry point often contains a jump instruction to the boot code at offset 84 followed by a no-operation, e.g.

eb52   jmp 0x52
90     nop

Number of sectors per cluster block

The number of sectors per cluster block value as used by mkntfs is defined as following:

  • Values 0 to 128 represent sizes of 0 to 128 sectors.
  • Values 244 to 255 represent sizes of 2^(256-n) sectors.
  • Other values are unknown.

Cluster block size

The cluster block size can be determined as following:

cluster block size = bytes per sector x sectors per cluster block

Different NTFS implementations support different cluster block sizes. Known supported cluster block size:

Cluster block sizeBytes per sectorSupported by
256256mkntfs
512256 - 512mkntfs, ntfs3g, Windows
1024256 - 1024mkntfs, ntfs3g, Windows
2048256 - 2048mkntfs, ntfs3g, Windows
4096256 - 4096mkntfs, ntfs3g, Windows
8192256 - 4096mkntfs, ntfs3g, Windows
16K (16384)256 - 4096mkntfs, ntfs3g, Windows
32K (32768)256 - 4096mkntfs, ntfs3g, Windows
64K (65536)256 - 4096mkntfs, ntfs3g, Windows
128K (131072)256 - 4096mkntfs, ntfs3g, Windows 10 (1903)
256K (262144)256 - 4096mkntfs, ntfs3g, Windows 10 (1903)
512K (524288)256 - 4096mkntfs, ntfs3g, Windows 10 (1903)
1M (1048576)256 - 4096mkntfs, ntfs3g, Windows 10 (1903)
2M (2097152)512 - 4096mkntfs, ntfs3g, Windows 10 (1903)

Note that Windows 10 (1903) requires the partition containing the NTFS file system to be aligned with the cluster block size. For example for a cluster block size of 128k the partition must 128 KiB aligned. The default partition partition alignment appears to be 64 KiB.

mkntfs restricts the cluster size to:

bytes_per_sector >= cluster_block_size > 4096 * bytes_per_sector

Master File Table (MFT) offset

The Master File Table (MFT) offset can be determined as following:

mft_offset = boot_record_offset + (mft_cluster_block_number * cluster_block_size)

The lower 32-bit part of the NTFS volume serial number is the Windows API (WINAPI) volume serial number. This can be determined by comparing the output of:

fsutil fsinfo volumeinfo C:
fsutil fsinfo ntfsinfo C:

Master File Table (MFT) and index entry size

The Master File Table (MFT) entry size and index entry size are defined as following:

  • Values 0 to 127 represent sizes of 0 to 127 cluster blocks.
  • Values 128 to 255 represent sizes of 2^(256-n) bytes or 2^(-n) if considered as a signed byte.
  • Other values are not considered valid.

BitLocker Drive Encryption (BDE)

BitLocker Drive Encryption (BDE) uses the file system signature: “-FVE-FS-”. Where FVE is an abbreviation of Full Volume Encryption.

The data structures of BDE on Windows Vista and 7 differ.

A Windows Vista BDE volume starts with:

eb 52 90 2d 46 56 45 26 46 53 2d

A Windows 7 BDE volume starts with:

eb 58 90 2d 46 56 45 26 46 53 2d

BDE is largely a stand-alone but has some integration with NTFS.

TODO: link to BDE format documentation

Volume Shadow Snapshots (VSS)

Volume Shadow Snapshots (VSS) uses the GUID 3808876b-c176-4e48-b7ae-04046e6cc752 (stored in little-endian) to identify its data.

VSS is largely a stand-alone but has some integration with NTFS.

TODO: link to VSS format documentation

Media descriptor

OffsetSizeValueDescription
0.01 bitSides, where single-sided (0) and double-sided (1)
0.11 bitTrack size, where 9 sectors per track (0) and 8 sectors per track (1)
0.21 bitDensity, where 80 tracks (0) and 40 tracks (1)
0.31 bitType, where Fixed disc (0) and Removable disc (1)
0.44 bitsAlways set to 1

The boot loader

OffsetSizeValueDescription
512Windows NT (boot) loader (NTLDR/BOOTMGR)

The Master File Table (MFT)

The MFT consist of an array of MFT entries. The offset of the MFT table can be found in the volume header and the size of the MFT is defined by the MFT entry of the $MFT metadata file.

Note that the MFT can consists of multiple data ranges, defined by the data runs in the $MFT metadata file.

MFT entry

Although the size of a MFT entry is defined in the volume header is commonly 1024 bytes in size and consists of:

  • The MFT entry header
  • The fix-up values
  • An array of MFT attribute values
  • Padding, which should contain 0-byte values

Note that the MFT entry can be filled entirely with 0-byte values. Seen in Windows XP for MFT entry numbers 16 - 23.

MFT entry header

The MFT entry header (FILE_RECORD_SEGMENT_HEADER) is 42 or 48 bytes in size and consists of:

OffsetSizeValueDescription
MULTI_SECTOR_HEADER
04"BAAD", "FILE"Signature
42The fix-up values (or update sequence array) offset, which contain an offset relative from the start of the MFT entry
62The number of fix-up values (or update sequence array size)
Common
88Metadata transaction journal sequence number, which contains a $LogFile Sequence Number (LSN)
162Sequence (number)
182Reference (link) count
202Attributes offset (or first attribute offset), which contains an offset relative from the start of the MFT entry
222MFT entry flags
244Used size in bytes
284MFT entry size in bytes
328Base record file reference
402First available attribute identifier
If NTFS version is 3.0
422Unknown (wfixupPattern)
444Unknown
If NTFS version is 3.1
422Unknown (wfixupPattern)
444MFT entry number
“BAAD” signature

According to NTFS documentation if during chkdsk, when a multi-sector item is found where the multi-sector header does not match the values at the end of the sector, it marks the item as “BAAD” and fill it with 0-byte values except for a fix-up value at the end of the first sector of the item. The “BAAD” signature has been seen to be used on Windows NT4 and XP.

Sequence number

According to FILE_RECORD_SEGMENT_HEADER structure the sequence number is incremented each time that a file record segment is freed; it is 0 if the segment is not used.

Base record file reference

The base record file reference is used to store additional attributes for another MFT entry, e.g. for attribute lists.

MFT entry flags

ValueIdentifierDescription
0x0001FILE_RECORD_SEGMENT_IN_USE, MFT_RECORD_IN_USEIn use
0x0002FILE_FILE_NAME_INDEX_PRESENT, FILE_NAME_INDEX_PRESENT, MFT_RECORD_IS_DIRECTORYHas file name (or $I30) index. When this flag is set the file entry represents a directory
0x0004MFT_RECORD_IN_EXTENDUnknown. According to ntfs_layout.h this is set for all system files present in the $Extend directory
0x0008MFT_RECORD_IS_VIEW_INDEXIs index. When this flag is set the file entry represents an index. According to ntfs_layout.h this is set for all indices other than $I30

The fix-up values

The fix-up values are of variable size and consists of:

OffsetSizeValueDescription
02Fix-up placeholder value
22 x number of fix-up valuesFix-up (original) value array

On disk the last 2 bytes for each 512 byte block is replaced by the fix-up placeholder value. The original value is stored in the corresponding fix-up (original) value array entry.

Note that there can be more fix-up values than the number of 512 byte blocks in the data.

According to MULTI_SECTOR_HEADER structure the update sequence array must end before the last USHORT value in the first sector. It also states that the update sequence array size value contains the number of bytes, but based on analysis of data samples it seems to be more likely to the number of words.

In NT4 (version 1.2) the MFT entry is 42 bytes in size and the fix-up values are stored at offset 42. This is likely where the name wfixupPattern originates from.

TODO: provide examples on applying the fix-up values.

The file reference

The file reference (FILE_REFERENCE or MFT_SEGMENT_REFERENCE) is 8 bytes in size and consists of:

OffsetSizeValueDescription
06MFT entry number
62Sequence number

Note that the index value in the MFT entry is 32-bit in size.

MFT attribute

The MFT attribute consist of:

  • the attribute header
  • the attribute resident or non-resident data
  • the attribute name
  • Unknown data, likely alignment padding (4-byte alignment)
  • resident attribute data or non-resident attribute data runs
  • alignment padding (8-byte alignment), can contain remnant data

MFT attribute header

The MFT attribute header (ATTRIBUTE_RECORD_HEADER) is 16 bytes in size and consists of:

OffsetSizeValueDescription
04Attribute type (or type code)
44Attribute size (or record length), which includes the 8 bytes of the attribute type and size
81Non-resident flag (or form code), where RESIDENT_FORM (0) and NONRESIDENT_FORM (1)
91Name size (or name length), which contains the number of characters without the end-of-string character
102Name offset, which contains an offset relative from the start of the MFT attribute
122Attribute data flags
142Attribute identifier (or instance), which contains an unique identifier to distinguish between attributes that contain segmented data

MFT attribute data flags

ValueIdentifierDescription
0x0001Is LZNT1 compressed
0x00ffATTRIBUTE_FLAG_COMPRESSION_MASK
0x4000ATTRIBUTE_FLAG_ENCRYPTEDIs encrypted
0x8000ATTRIBUTE_FLAG_SPARSEIs sparse

TODO: determine the meaning of compression flag in the context of resident $INDEX_ROOT. Do the data flags have a different meaning for different attributes?

Resident MFT attribute

The resident MFT attribute data is present when the non-resident flag is not set (0). The resident data is 8 bytes in size and consists of:

OffsetSizeValueDescription
04Data size (or value length)
42Data offset (or value size), which contains an offset relative from the start of the MFT attribute
61Indexed flag
710x00Unknown (Padding)

TODO: determine the meaning of indexed flag bits, other than the LSB

Non-resident MFT attribute

The non-resident MFT attribute data is present when the non-resident flag is set (1). The non-resident data is 48 or 56 bytes in size and consists of:

OffsetSizeValueDescription
08First (or lowest) Virtual Cluster Number (VCN) of the data
88Last (or highest) Virtual Cluster Number (VCN) of the data
162Data runs offset (or mappings pairs offset), which contains an offset relative from the start of the MFT attribute
182Compression unit size, which contains the compression unit size as 2^(n) number of cluster blocks
204Unknown (Padding)
248Allocated data size (or allocated length), which contains the allocated data size in number of bytes. This value is not valid if the first VCN is nonzero
328Data size (or file size), which contains the data size in number of bytes. This value is not valid if the first VCN is nonzero
408Valid data size (or valid data length), which contains the valid data size in number of bytes. This value is not valid if the first VCN is nonzero
If compression unit size > 0
488Compressed data size

The total size of the data runs should be larger or equal to the data size.

Note that Windows will fill data beyond the valid data size with 0-byte values. The data size remains unchanged. This applies to compressed and uncompressed data. If the first VCN is zero a valid data size of 0 represents a file entirely filled with 0-byte values.

TODO: determine the meaning of a VCN of -1

For more information about compressed MFT attributes see compression.

Attribute name

The attribute name is of variable size and consists of:

OffsetSizeValueDescription
0...Name, which contains an UCS-2 little-endian string without end-of-string character

Data runs

The data runs are stored in a variable size (data) runlist. This runlist consists of runlist elements.

A runlist element is of variable size and consists of:

OffsetSizeValueDescription
0.0 4 bitsNumber of cluster blocks value size, which contains the number of bytes used to store the data run size
0.44 bitsCluster block number value size, which contains the number of bytes used to store the data run size
1Size value sizeData run number of cluster blocks, which contains the number of cluster blocks
...Cluster block number value sizeData run cluster block number

The data run cluster block number is a singed value, where the MSB is the singed bit, e.g. if the data run cluster block contains “dbc8” it corresponds to the 64-bit value 0xffffffffffffdbc8.

The first data run offset contains the absolute cluster block number where successive data run offsets are relative to the last data run offset.

Note that the cluster block number byte size is the first nibble when reading the byte stream, but here it is represented as the upper nibble of the first byte.

The last runlist element is (0, 0), which is stored as a 0-byte value.

According to NTFS documentation the size of the runlist is rounded up to the next multitude of 4 bytes, but based on analysis of data samples it seems that the size of the trailing data can be even larger than 3 and are not always 0-byte values.

TODO: provide examples of data runs

Sparse data runs

The MFT attribute data flag (ATTRIBUTE_FLAG_SPARSE) indicates if the data stream is sparse or not, where the runlist can contain both sparse and non-sparse data runs.

A sparse data run has a cluster block number value size of 0, representing there is no offset (cluster block number). A sparse data run is filled with 0-byte values.

Compressed data streams also define sparse data runs without setting the ATTRIBUTE_FLAG_SPARSE flag.

Note that $BadClus:$Bad also defines a data run with a cluster block number value size of 0, without setting the ATTRIBUTE_FLAG_SPARSE flag.

Compresssed data runs

The MFT attribute data flags (0x00ff) indicate if the data stream is compressed or not.

Windows supports compressed data runs for NTFS file systems with a cluster block size of 4096 bytes or less.

Windows 10 supports Windows Overlay Filter (WOF) compressed data, which stores the LZXPRESS Huffman or LZX compressed data in alternate data stream named WofCompressedData and links it to the default data stream using a reparse point.

The data is stored in compression unit blocks. A compression unit typically consists of 16 cluster blocks. However the actual value is stored in the non-resident MFT attribute.

Also see compression.

The attributes

Known attribute types

The attribute types are stored in the $AttrDef metadata file.

ValueIdentifierDescription
0x00000000Unused
0x00000010$STANDARD_INFORMATIONStandard information
0x00000020$ATTRIBUTE_LISTAttributes list
0x00000030$FILE_NAMEThe file or directory name
Used in NTFS version 1.2 and earlier
0x00000040$VOLUME_VERSIONVolume version
Used in NTFS version 3.0 and later
0x00000040$OBJECT_IDObject identifier
Common
0x00000050$SECURITY_DESCRIPTORSecurity descriptor
0x00000060$VOLUME_NAMEVolume label
0x00000070$VOLUME_INFORMATIONVolume information
0x00000080$DATAData stream
0x00000090$INDEX_ROOTIndex root
0x000000a0$INDEX_ALLOCATIONIndex allocation
0x000000b0$BITMAPBitmap
Used in NTFS version 1.2 and earlier
0x000000c0$SYMBOLIC_LINKSymbolic link
Used in NTFS version 3.0 and later
0x000000c0$REPARSE_POINTReparse point
Common
0x000000d0$EA_INFORMATION(HPFS) extended attribute information
0x000000e0$EA(HPFS) extended attribute
Used in NTFS version 1.2 and earlier
0x000000f0$PROPERTY_SETProperty set
Used in NTFS version 3.0 and later
0x00000100$LOGGED_UTILITY_STREAMLogged utility stream
Common
0x00001000First user defined attribute
0xffffffffEnd of attributes marker

Attribute chains

Multiple attributes can be chained to make up a single attribute data stream, e.g. the attributes:

  1. $INDEX_ALLOCATION ($I30) VCN: 0
  2. $INDEX_ALLOCATION ($I30) VCN: 596

The first attribute will contain the size of the data defined by all the attributes and successive attributes should have a size of 0.

It is assumed that the attributes in a chain must be continuous and defined in-order.

The standard information attribute

The standard information attribute ($STANDARD_INFORMATION) contains the basic file entry metadata. It is stored as a resident MFT attribute.

The standard information data (STANDARD_INFORMATION) is either 48 or 72 bytes in size and consists of:

OffsetSizeValueDescription
08Creation date and time, which contains a FILETIME
88Last modification (or last written) dat and time, which contains a FILETIME
168MFT entry last modification date and time, which contains a FILETIME
248Last access date and time, which contains a FILETIME
324File attribute flags
364Unknown (Maximum number of versions)
404Unknown (Version number)
444Unknown (Class identifier)
If NTFS version 3.0 or later
484Owner identifier
524Security descriptor identifier, which contains the entry number in the security ID index ($Secure:$SII). Also see Access Control
568Quota charged
648Update Sequence Number (USN)

Note that MFT entries have been observed without a $STANDARD_INFORMATION attribute, but with other attributes such as $FILE_NAME and an $I30 index.

Recent version of NTFS support case-sentive file names. If a directory is case-sensitive the corresponding $STANDARD_INFORMATION attribute will have a maximum number of versions of 0 and a version number of 1.

The attribute list attribute

The attribute list attribute ($ATTRIBUTE_LIST) is used to store MFT attributes outside the MFT entry, e.g. when the MFT entry is too small to store all the attributes.

The entries in the list reference the location of MFT attributes. The attribute list attribute can be stored as either a resident (for a small amount of data) or non-resident MFT attribute.

Note that MFT entry 0 also can contain an attribute list and allows to store listed attributes beyond the first data run.

The attribute list

An attribute list consists of:

  • one or more attribute list entries

The attribute list entry

An attribute list entry (ATTRIBUTE_LIST_ENTRY) is of variable size and consists of:

OffsetSizeValueDescription
04Attribute type (or type code)
42Size (or record length), which includes the 6 bytes of the attribute type and size
61Name size (or name length), which contains the number of characters without the end-of-string character
71Name offset, which contains an offset relative from the start of the attribute list entry
88Data first (or lowest) VCN
168File reference (or segment reference), which contains a reference to the MFT entry that contains (part of) the attribute data
242Attribute identifier (or instance), which contains an unique identifier to distinguish between attributes that contain segmented data
26...Name, which contains an UCS-2 little-endian string without end-of-string character
......alignment padding (8-byte alignment), can contain remnant data

The file name attribute

The file name attribute ($FILE_NAME) contains the basic file system information, like the parent file entry, various date and time values and name. It is stored as a resident MFT attribute.

The file name data (FILE_NAME) is of variable size and consists of:

OffsetSizeValueDescription
08Parent file reference
88Creation date and time, which contains a FILETIME
168Last modification (or last written) date and time, which contains a FILETIME
248MFT entry last modification date and time, which contains a FILETIME
328Last access date and time, which contains a FILETIME
408Allocated (or reserved) file size
488Data size
564File attribute flags
If FILE_ATTRIBUTE_REPARSE_POINT is set
604Reparse point tag
If FILE_ATTRIBUTE_REPARSE_POINT is not set
604Unknown (extended attribute data size)
Common
641Name string size, which contains the number of characters without the end-of-string character
651Namespace of the name string
66...Name, which contains an UCS-2 little-endian string without end-of-string character

An MFT attribute can contain multiple file name attributes, e.g. for a separate (long) name and short name.

In several cases on a Vista NTFS volume the MFT entry contained both a DOS & Windows and POSIX name space $FILE_NAME attribute. However the directory entry index ($I30) of the parent directory only contained the DOS & Windows name.

In case of a hard link the MFT entry will contain additional file name attributes with the parent file reference of each hard link.

Namespace

ValueIdentifierDescription
0POSIXCase-sensitive character set that consists of all Unicode characters except for: "\0" (zero character), "/" (forward slash). The ":" (colon) is valid for NTFS but not for Windows
1FILE_NAME_NTFS, WINDOWSCase-insensitive sub set of the POSIX character set that consists of all Unicode characters except for: " * / : < > ? \ | +. Note that names cannot end with a "." (dot) or " " (space)
2FILE_NAME_DOS, DOSCase-insensitive sub set of the WINDOWS character set that consists of all upper case ASCII characters except for: " * + , / : ; < = > ? \. Note that the name must follow the 8.3 format
3DOS_WINDOWSBoth the DOS and WINDOWS names are identical, which is the same as the DOS character set, with the exception that lower case is used as well

Note that the Windows API function CreateFile allows to create case-sensitive file names when the flag FILE_FLAG_POSIX_SEMANTICS is set.

Long to short name conversion

A short name can be determined from a long name with the following approach. In the long name:

  • ignore Unicode characters beyond the first 8-bit (extended ASCII)
  • ignore control characters and spaces (character < 0x20)
  • ignore non-allowed characters " * + , / : ; < = > ? \
  • ignore dots except the last one, which is used for the extension
  • make all letters upper case

Additional observations:

  • [ or ] are replaced by an underscore (_)

Make the name unique:

  1. use the characters 1 to 6 add ~1 and if the long name has an extension add the a dot and its first 3 letters, e.g. “Program Files” becomes “PROGRA~1” or “ ~PLAYMOVIE.REG“ becomes “~PLAYM~1.REG”
  2. if the name already exists try ~2 up to ~9, e.g. “Program Data”, in the same directory as “Program Files”, becomes “PROGRA~2”
  3. if the name already exists use a 16-bit hexadecimal value for characters 3 to 6 with ~1, e.g. “x86_microsoft-windows-r..ry-editor.resources_31bf3856ad364e35_6.0.6000.16386_en-us_f89a7b0005d42fd4” in a directory with a lot of file names starting with “x86_microsoft”, becomes “X8FCA6~1.163”

TODO: determine if the behavior is dependent on a setting that can be changed with fsutil

The volume version attribute

The volume version attribute ($VOLUME_VERSION) contains volume version.

TODO: complete section. Need a pre NTFS version 3.0 volume with this attribute. $AttrDef indicates the attribute to be 8 bytes in size.

The object identifier attribute

The object identifier attribute ($OBJECT_ID) contains distributed link tracker properties. It is stored as a resident MFT attribute.

The object identifier attribute data is either 16 or 64 bytes in size and consists of:

OffsetSizeValueDescription
016Droid file identifier, which contains a GUID
1616Birth droid volume identifier, which contains a GUID
3216Birth droid file identifier, which contains a GUID
4816Birth droid domain identifier, which contains a GUID

Droid in this context refers to CDomainRelativeObjId.

The security descriptor attribute

TODO: determine if this override any value in $Secure:$SDS?

The security descriptor attribute ($SECURITY_DESCRIPTOR) contains a Windows NT security descriptor. It can be stored as either a resident (for a small amount of data) and non-resident MFT attribute.

TODO: link to security descriptor format documentation

The volume name attribute

The volume name attribute ($VOLUME_NAME) contains the volume label. It is stored as a resident MFT attribute.

The volume name attribute data is of variable size and consists of:

OffsetSizeValueDescription
0...Volume label, which contains an UCS-2 little-endian string without end-of-string character

The volume name attribute is used in the $Volume metadata file MFT entry.

The volume information attribute

The volume information attribute ($VOLUME_INFORMATION) contains information about the volume. It is stored as a resident MFT attribute.

The volume information attribute data is 12 bytes in size and consists of:

OffsetSizeValueDescription
08Unknown
81Major format version
91Minor format version
102Volume flags

The volume information attribute is used in the $Volume metadata file MFT entry.

Volume flags

ValueIdentifierDescription
0x0001VOLUME_IS_DIRTYIs dirty
0x0002VOLUME_RESIZE_LOG_FILERe-size journal ($LogFile)
0x0004VOLUME_UPGRADE_ON_MOUNTUpgrade on next mount
0x0008VOLUME_MOUNTED_ON_NT4Mounted on Windows NT 4
0x0010VOLUME_DELETE_USN_UNDERWAYDelete USN in progress
0x0020VOLUME_REPAIR_OBJECT_IDRepair object identifiers
0x0080Unknown
0x4000VOLUME_CHKDSK_UNDERWAYchkdsk in progress
0x8000VOLUME_MODIFIED_BY_CHKDSKModified by chkdsk

The data stream attribute

The data stream attribute ($DATA) contains the file data. It can be stored as either a resident (for a small amount of data) and non-resident MFT attribute.

Multiple data attributes for the same data stream can be used in the attribute list to define different parts of the data stream data. The first data stream attribute will contain the size of the entire data stream data. Other data stream attributes should have a size of 0. Also see attribute chains.

The index root attribute

The index root attribute ($INDEX_ROOT) contains the root of the index tree. It is stored as a resident MFT attribute.

Also see the index and the index root.

The index allocation attribute

The index allocation attribute ($INDEX_ALLOCATION) contains an array of index entries. It is stored as a non-resident MFT attribute.

The index allocation attribute itself does not define which attribute type it contains in the index value data. For this information it needs the corresponding index root attribute.

Multiple index allocation attributes for the same index can be used in the attribute list to define different parts of the index allocation data. The first index allocation attribute will contain the size of the entire index allocation data. Other index allocation attributes should have a size of 0. Also see attribute chains.

Also see the index.

The bitmap attribute

The bitmap attribute ($BITMAP) contains the allocation bitmap. It can be stored as either a resident (for a small amount of data) and non-resident MFT attribute.

It is used to maintain information about which entry is used and which is not. Every bit in the bitmap represents an entry. The index is stored byte-wise with the LSB of the byte corresponds to the first allocation element. The allocation element can represent different things:

  • an MFT entry in the MFT (nameless) bitmap;
  • an index entry in an index ($I30).

The allocation element is allocated if the corresponding bit contains 1 or unallocated if 0.

The symbolic link attribute ($SYMBOLIC_LINK) contains a symbolic link.

TODO: complete section. Need a pre NTFS version 3.0 volume with this attribute. $AttrDef indicates the attribute is of variable size.

The reparse point attribute

The reparse point attribute ($REPARSE_POINT) contains information about a file system-level link. It is stored as a resident MFT attribute.

Als see the reparse point.

The (HPFS) extended attribute information

The (HPFS) extended attribute information ($EA_INFORMATION) contains information about the extended attribute ($EA).

The extended attribute information data is 8 bytes in size and consists of:

OffsetSizeValueDescription
02Size of an extended attribute entry
22Number of extended attributes which have the NEED_EA flag set
44Size of the extended attribute ($EA) data

The (HPFS) extended attribute

The (HPFS) extended attribute ($EA) contains the extended attribute data.

The extended attribute data is of variable size and consists of:

OffsetSizeValueDescription
04Offset to next extended attribute entry, where the offset is relative from the start of the extended attribute data
41Extended attribute flags
51Number of characters of the extended attribute name
62Value data size
8...The extended attribute name, which contains an ASCII string
......Value data
......Unknown

TODO: determine if the name is 2-byte aligned

Extended attribute flags

ValueIdentifierDescription
0x80NEED_EAUnknown (Need EA) flag

TODO: determine what the NEED_EA flag is used for

UNITATTR extended attribute value data

OffsetSizeValueDescription
04Unknown (equivalent of st_mode?)

The property set attribute

The property set attribute ($PROPERTY_SET) contains a property set.

TODO: complete section. Need a pre NTFS version 3.0 volume with this attribute. $AttrDef does not seem to always define this attribute.

The logged utility stream attribute

TODO: complete section

ValueIdentifierDescription
$EFSEncrypted NTFS (EFS)
$TXF_DATATransactional NTFS (TxF)

The attribute types

The attribute types are stored in the $AttrDef metadata file.

OffsetSizeValueDescription
0128Attribute which contains an UCS-2 little-endian string with end-of-string character. Unused bytes are filled with 0-byte values
1284Attribute type (or type code)
1328Unknown
1404Unknown (flags?)
1448Unknown (minimum attribute size?)
1528Unknown (maximum attribute size?)

The index

The index structures are used for various purposes one of which are the directory entries.

The root of the index is stored in index root. The index root attribute defines which type of attribute is stored in the index and the root index node.

If the index is too large part of the index is stored in an index allocation attribute with the same attribute name. The index allocation attribute defines a data stream which contains index entries. Each index entry contains an index node.

An index consists of a tree, where both the branch and index leaf nodes contain the actual data. E.g. in case of a directory entries index, any node that contains index value data make up for the directory entries.

The index value data in a branch node signifies the upper bound of the values in the that specific branch. E.g. if directory entries index branch node contains the name “textfile.txt” all names in that index branch are smaller than “textfile.txt”.

Note the actual sorting order is dependent on the collation type defined in the index root attribute.

The index allocation attribute is accompanied by a bitmap attribute with the corresponding attribute name. The bitmap attribute defines the allocation of virtual cluster blocks within the index allocation attribute data stream. Every bit in the bitmap represents a block the size of an index entry.

Note that the index allocation attribute can be present even though it is not used.

Common used indexes

Indexes commonly used by NTFS are:

ValueIdentifierDescription
$I30Directory entries (used by directories)
$SDHSecurity descriptor hashes (used by $Secure)
$SIISecurity descriptor identifiers (used by $Secure)
$OObject identifiers (used by $ObjId)
$OOwner identifiers (used by $Quota)
$QQuotas (used by $Quota)
$RReparse points (used by $Reparse)

The index root

The index root consists of:

  • index root header
  • index node header
  • an array of index values

The index root header

The index root header is 16 bytes in size and consists of:

OffsetSizeValueDescription
04Attribute type, which contains the type of the indexed attribute or 0 if none
44Collation type, which contains a value to indicate the ordering of the index entries
84Index entry size
124Number of cluster blocks per index entry

Note that for NTFS version 1.2 the index entry size does not have to match the index entry size in the volume header. The correct size seems to be the value in the index root header.

Collation type

ValueIdentifierDescription
0x00000000COLLATION_BINARYBinary, where the first byte is most significant
0x00000001COLLATION_FILENAMEUCS-2 strings case-insensitive, where the case folding is stored in $UpCase
0x00000002COLLATION_UNICODE_STRINGUCS-2 strings case-sensitive, where upper case letters should come first
0x00000010COLLATION_NTOFS_ULONGUnsigned 32-bit little-endian integer
0x00000011COLLATION_NTOFS_SIDNT security identifier (SID)
0x00000012COLLATION_NTOFS_SECURITY_HASHSecurity hash first, then NT security identifier
0x00000013COLLATION_NTOFS_ULONGSAn array of unsigned 32-bit little-endian integer values

The index entry

The index entry consists of:

  • the index entry header
  • the index node header
  • The fix-up values
  • alignment padding (8-byte alignment), contains zero-bytes
  • an array of index values

The index entry header

The index entry header is 24 bytes in size and consists of:

OffsetSizeValueDescription
04"INDX"Signature
42The fix-up values offset, which contains an offset relative from the start of the index entry header
62The number of fix-up values
88Metadata transaction journal sequence number, which contains a $LogFile Sequence Number (LSN)
168Virtual Cluster Number (VCN) of the index entry

Note that there can be more fix-up values than supported by the index entry data size.

The index node header

The index node header is 16 bytes in size and consists of:

OffsetSizeValueDescription
04Index values offset, where the offset is relative from the start of the index node header
44Index node size, where the value includes the size of the index node header
84Allocated index node size, where the value includes the size of the index node header
124Index node flags

In an index entry (index allocation attribute) the index node size includes the size of the fix-up values and the alignment padding following it.

The remainder of the index node contains remnant data and/or zero-byte values.

The index node flags

ValueIdentifierDescription
0x00000001Is branch node, which is used to indicate if the node is a branch node that has sub nodes

The index value

The index value is of variable size and consists of:

OffsetSizeValueDescription
08File reference
82Size, which includes the 10 bytes of the file reference and size
102Key data size
124Index value flags
If index key data size > 0
16...Key data
......Data
If index value flag 0x00000001 (is branch node) is set
...8Sub node Virtual Cluster Number (VCN)

The index values are stored 8 byte aligned.

Note that some other sources define the index value flags as a 16-bit value followed by 2 bytes of padding.

The index value flags

ValueIdentifierDescription
0x00000001Has sub node, when set the index value contains a sub node Virtual Cluster Number (VCN)
0x00000002Is last, when set the index value is the last in the index values array

Index key and value data

Directory entry index value

The MFT attribute name of the directory entry index is: $I30.

The directory entry index value contains a file name attribute in the index key data.

Note that the index value data can contain remnant data.

The short and long names of the same file have a separate index values. The short name uses the DOS name space and the long name the WINDOWS name space. Index values with a single name use either the POSIX or DOS_WINDOWS name space.

A hard link to a file in the same directory has separate index values.

Security descriptor hash index value

The MFT attribute name of the security descriptor hash index is: $SDH. It appears to only to be used by the $Secure metadata file.

Also see the security descriptor hash index value.

Security descriptor identifier index value

The MFT attribute name of the security descriptor identifier index is: $SII. It appears to only to be used by the $Secure metadata file.

Also see the security descriptor identifier index value.

Compression

Compressed data-runs

NTFS compression groups 16 cluster blocks together. This group of 16 cluster blocks also named a compression unit, which is either “compressed” or uncompressed.

The term compressed is quoted here because the group of cluster blocks can also contain uncompressed data. A group of cluster blocks is “compressed” when it is compressed size is smaller than its uncompressed data size. Within a group of cluster blocks each of the 16 blocks is “compressed” individually.

The compression unit size is stored in the non-resident MFT attribute. The maximum uncompressed data size is always the cluster size (in most case 4096).

Note that a resident $DATA attribute with the compression type in the data flags is stored uncompressed.

The data runs in the $DATA attribute define cluster block ranges, e.g.

21 02 35 52

This data run defines 2 data blocks starting at block number 21045 followed by 14 sparse blocks. The total number of blocks in the compression unit is 16. Compressed data is stored in the first 2 blocks and the 14 sparse blocks are only there to make sure the data runs add up to the compression unit size. They do not define actual sparse data.

Another example:

21 40 37 52

This data run defines 64 data blocks starting at block number 21047. Since this data run is larger than the compression unit size the data is stored uncompressed.

If the data run was e.g. 60 data blocks followed by 4 sparse blocks the first 3 compression units (blocks 1 to 48) would be uncompressed and the last compression unit (blocks 49 to 64) would be compressed.

Also “sparse data” and “sparse compression unit” data runs can be mixed. If in the previous example the 60 data blocks would be followed by 20 sparse blocks the last compression unit (blocks 65 to 80) would be sparse.

A compression unit can consists of multiple compressed data runs, e.g. 1 data block followed by 4 data blocks followed by 11 sparse blocks. Data runs have been observed where the last data run size does not align with the compression unit size.

The sparse blocks data run can be stored in a subsequent attribute in an attribute chain and can be stored in multiple data runs.

NTFS compression stores the “compressed” data in blocks. Each block has a 2 byte block header.

The block is of variable size and consists of:

OffsetSizeValueDescription
02Block size
2compressed data sizeUncompressed or LZNT1 compressed data

The upper 4 bits of the block size are used as flags:

Bit(s)Description
0 - 11Compressed data size
12 - 14Unknown
15Data is compressed

TODO: link to LZNT1 documentation

Windows Overlay Filter (WOF) compressed data

A MFT entry that contains Windows Overlay Filter (WOF) compressed data has the following attributes:

  • reparse point attribute with tag 0x80000017, which defines the compression method
  • a nameless data attribute that is sparse and contains the uncompressed data size
  • a data attribute named WofCompressedData that contains LZXPRESS Huffman or LZX compressed data
OffsetSizeValueDescription
Chunk offset table
0...Array of 32-bit of 64-bit compressed data chunk offsets, where the offset is relative from the start of the data chunks
Data chunks
......One or more compressed or uncompressed data chunks

Note that if the chunk size equals the size of the uncompressed data the chunk is stored (as-is) uncompressed.

The size of the chunk offset table is:

number of chunk offsets = uncompressed size / compression unit size

The offset of the first compressed data chunk is at the end of the chunk offset table and is not stored in the chunk offset table.

If the uncompressed size of a chunk is smaller than the compression unit size the chunk is stored uncompressed.

Also see Windows Overlay Filter (WOF) compression method.

The reparse point

The reparse point is used to create file system-level links. Reparse data is stored in the reparse point attribute. The reparse point data (REPARSE_DATA_BUFFER) is of variable size and consists of:

OffsetSizeValueDescription
04Reparse point tag
42Reparse data size
620Unknown (Reserved)
8...Reparse data

TODO: determine if non-native (Microsoft) reparse points are stored with their GUID

The reparse point tag

OffsetSizeValueDescription
0.0 16 bitsType
2.0 12 bitsUnknown (Reserved)
3.44 bitsFlags

Reparse point tag flags

ValueIdentifierDescription
0x1Unknown (Reserved)
0x2Is alias (Name surrogate bit), when this bit is set, the file or directory represents another named entity in the system
0x4Is high-latency media (Reserved)
0x8Is native (Microsoft-bit)

Known reparse point tags

ValueIdentifierDescription
0x00000000IO_REPARSE_TAG_RESERVED_ZEROUnknown (Reserved)
0x00000001IO_REPARSE_TAG_RESERVED_ONEUnknown (Reserved)
0x00000002IO_REPARSE_TAG_RESERVED_TWOUnknown (Reserved)
0x80000005IO_REPARSE_TAG_DRIVE_EXTENDERUsed by Home server drive extender
0x80000006IO_REPARSE_TAG_HSM2Used by Hierarchical Storage Manager Product
0x80000007IO_REPARSE_TAG_SISUsed by single-instance storage (SIS) filter driver
0x80000008IO_REPARSE_TAG_WIMUsed by the WIM Mount filter
0x80000009IO_REPARSE_TAG_CSVUsed by Clustered Shared Volumes (CSV) version 1
0x8000000aIO_REPARSE_TAG_DFSUsed by the Distributed File System (DFS)
0x8000000bIO_REPARSE_TAG_FILTER_MANAGERUsed by filter manager test harness
0x80000012IO_REPARSE_TAG_DFSRUsed by the Distributed File System (DFS)
0x80000013IO_REPARSE_TAG_DEDUPUsed by the Data Deduplication (Dedup)
0x80000014IO_REPARSE_TAG_NFSUsed by the Network File System (NFS)
0x80000015IO_REPARSE_TAG_FILE_PLACEHOLDERUsed by Windows Shell for placeholder files
0x80000016IO_REPARSE_TAG_DFMUsed by Dynamic File filter
0x80000017IO_REPARSE_TAG_WOFUsed by Windows Overlay Filter (WOF), for either WIMBoot or compression
0x80000018IO_REPARSE_TAG_WCIUsed by Windows Container Isolation (WCI)
0x8000001bIO_REPARSE_TAG_APPEXECLINKUsed by Universal Windows Platform (UWP) packages to encode information that allows the application to be launched by CreateProcess
0x8000001eIO_REPARSE_TAG_STORAGE_SYNCUsed by the Azure File Sync (AFS) filter
0x80000020IO_REPARSE_TAG_UNHANDLEDUsed by Windows Container Isolation (WCI)
0x80000021IO_REPARSE_TAG_ONEDRIVEUnknown (Not used)
0x80000023IO_REPARSE_TAG_AF_UNIXUsed by the Windows Subsystem for Linux (WSL) to represent a UNIX domain socket
0x80000024IO_REPARSE_TAG_LX_FIFOUsed by the Windows Subsystem for Linux (WSL) to represent a UNIX FIFO (named pipe)
0x80000025IO_REPARSE_TAG_LX_CHRUsed by the Windows Subsystem for Linux (WSL) to represent a UNIX character special file
0x80000036IO_REPARSE_TAG_LX_BLKUsed by the Windows Subsystem for Linux (WSL) to represent a UNIX block special file
0x9000001cIO_REPARSE_TAG_PROJFSUsed by the Windows Projected File System filter, for files managed by a user mode provider such as VFS for Git
0x90001018IO_REPARSE_TAG_WCI_1Used by Windows Container Isolation (WCI)
0x9000101aIO_REPARSE_TAG_CLOUD_1Used by the Cloud Files filter, for files managed by a sync engine such as OneDrive
0x9000201aIO_REPARSE_TAG_CLOUD_2Used by the Cloud Files filter, for files managed by a sync engine such as OneDrive
0x9000301aIO_REPARSE_TAG_CLOUD_3Used by the Cloud Files filter, for files managed by a sync engine such as OneDrive
0x9000401aIO_REPARSE_TAG_CLOUD_4Used by the Cloud Files filter, for files managed by a sync engine such as OneDrive
0x9000501aIO_REPARSE_TAG_CLOUD_5Used by the Cloud Files filter, for files managed by a sync engine such as OneDrive
0x9000601aIO_REPARSE_TAG_CLOUD_6Used by the Cloud Files filter, for files managed by a sync engine such as OneDrive
0x9000701aIO_REPARSE_TAG_CLOUD_7Used by the Cloud Files filter, for files managed by a sync engine such as OneDrive
0x9000801aIO_REPARSE_TAG_CLOUD_8Used by the Cloud Files filter, for files managed by a sync engine such as OneDrive
0x9000901aIO_REPARSE_TAG_CLOUD_9Used by the Cloud Files filter, for files managed by a sync engine such as OneDrive
0x9000a01aIO_REPARSE_TAG_CLOUD_AUsed by the Cloud Files filter, for files managed by a sync engine such as OneDrive
0x9000b01aIO_REPARSE_TAG_CLOUD_BUsed by the Cloud Files filter, for files managed by a sync engine such as OneDrive
0x9000c01aIO_REPARSE_TAG_CLOUD_CUsed by the Cloud Files filter, for files managed by a sync engine such as OneDrive
0x9000d01aIO_REPARSE_TAG_CLOUD_DUsed by the Cloud Files filter, for files managed by a sync engine such as OneDrive
0x9000e01aIO_REPARSE_TAG_CLOUD_EUsed by the Cloud Files filter, for files managed by a sync engine such as OneDrive
0x9000f01aIO_REPARSE_TAG_CLOUD_FUsed by the Cloud Files filter, for files managed by a sync engine such as OneDrive
0xa0000003IO_REPARSE_TAG_MOUNT_POINTJunction (or mount point)
0xa000000cIO_REPARSE_TAG_SYMLINKSymbolic link
0xa0000010IO_REPARSE_TAG_IIS_CACHEUsed by Microsoft Internet Information Services (IIS) caching
0xa0000019IO_REPARSE_TAG_GLOBAL_REPARSEUsed by NPFS to indicate a named pipe symbolic link from a server silo into the host silo
0xa000001aIO_REPARSE_TAG_CLOUDUsed by the Cloud Files filter, for files managed by a sync engine such as Microsoft OneDrive
0xa000001dIO_REPARSE_TAG_LX_SYMLINKUsed by the Windows Subsystem for Linux (WSL) to represent a UNIX symbolic link
0xa000001fIO_REPARSE_TAG_WCI_TOMBSTONEUsed by Windows Container Isolation (WCI)
0xa0000022IO_REPARSE_TAG_PROJFS_TOMBSTONEUsed by the Windows Projected File System filter, for files managed by a user mode provider such as VFS for Git
0xa0000027IO_REPARSE_TAG_WCI_LINKUsed by Windows Container Isolation (WCI)
0xa0001027IO_REPARSE_TAG_WCI_LINK_1Used by Windows Container Isolation (WCI)
0xc0000004IO_REPARSE_TAG_HSMUsed by Hierarchical Storage Manager Product
0xc0000014IO_REPARSE_TAG_APPXSTRMUnknown (Not used)

Junction or mount point reparse data

A reparse point with tag IO_REPARSE_TAG_MOUNT_POINT (0xa0000003) contains junction or mount point reparse data. The junction or mount point reparse data is of variable size and consists of:

OffsetSizeValueDescription
02Substitute name offset, where the offset is relative from the start of the reparse name data
22Substitute name size in bytes, where the size of the end-of-string character is not included
42Display name offset, where the offset is relative from the start of the reparse name data
62Display name size in bytes, where the size of the end-of-string character is not included
Reparse name data
8...Substitute name, which contains an UCS-2 little-endian string without end-of-string character
......Display name, which contains an UCS-2 little-endian string without end-of-string character

Note that it is currently unclear if the names contain an end-of-string character or if they are followed by alignment padding.

TODO: determine what character values like 0x0002 represent in the substitute name

00000010: 5c 00 3f 00 3f 00 02 00  43 00 3a 00 5c 00 55 00   \.?.?... C.:.\.U.
00000020: 73 00 65 00 72 00 73 00  5c 00 74 00 65 00 73 00   s.e.r.s. \.t.e.s.
00000030: 74 00 5c 00 44 00 6f 00  63 00 75 00 6d 00 65 00   t.\.D.o. c.u.m.e.
00000040: 6e 00 74 00 73 00 00 00                            n.t.s...

A reparse point with tag IO_REPARSE_TAG_SYMLINK (0xa000000c) contains symbolic link reparse data. The symbolic link reparse data is of variable size and consists of:

OffsetSizeValueDescription
02Substitute name offset, where the offset is relative from the start of the reparse name data
22Substitute name size in bytes
42Display name offset, where the offset is relative from the start of the reparse name data
62Display name size, in bytes
84Symbolic link flags
Reparse name data
12...Substitute name, which contains an UCS-2 little-endian string without end-of-string character
......Display name, which contains an UCS-2 little-endian string without end-of-string character
ValueIdentifierDescription
0x00000001SYMLINK_FLAG_RELATIVEThe substitute name is a path name relative to the directory containing the symbolic link

Windows Overlay Filter (WOF) reparse data

A reparse point with tag IO_REPARSE_TAG_WOF (0x80000017) contains Windows Overlay Filter (WOF) reparse data. The Windows Overlay Filter (WOF) reparse data is 16 bytes in size and consists of:

OffsetSizeValueDescription
External provider information
041Unknown (WOF version)
442Unknown (WOF provider)
Internal provider information
841Unknown (file information version)
124Compression method

Windows Overlay Filter (WOF) compression method

ValueIdentifierDescription
0LZXPRESS Huffman with 4k window (compression unit)
1LZX with 32k window (compression unit)
2LZXPRESS Huffman with 8k window (compression unit)
3LZXPRESS Huffman with 16k window (compression unit)

TODO: link to LZXPRESS Huffman and LZX documentation

Windows Container Isolation (WCI) reparse data

A reparse point with tag IO_REPARSE_TAG_WCI (0x80000018) contains Windows Container Isolation (WCI) reparse data. The Windows Container Isolation (WCI) reparse data is of variable size and consists of:

OffsetSizeValueDescription
041Version
440Unknown (reserved)
816Look-up identifier, which contains a GUID
242Name size in bytes
26...Name, which contains an UCS-2 little-endian string without end-of-string character

The cluster block allocation bitmap

The metadata file $Bitmap contains the cluster block allocation bitmap.

Every bit in the allocation bitmap represents a block the size of the cluster block, where the LSB is the first bit in a byte.

TODO: describe what the $SRAT data stream is used for.

Access control

The $Secure metadata file contains the security descriptors used for access control.

TypeNameDescription
Data$SDSSecurity descriptor data stream, which contains all the Security descriptors on the volume
Index$SDHSecurity descriptor hash index
Index$SIISecurity descriptor identifier index, which contains the mapping of the security descriptor identifier (in $STANDARD_INFORMATION) to the offset of the security descriptor data (in $Secure:$SDS)

Security descriptor hash ($SDH) index

The security descriptor hash index value

OffsetSizeValueDescription
Key data
04Security descriptor hash
44Security descriptor identifier
Value data
84Security descriptor hash
124Security descriptor identifier
168Security descriptor data offset (in $SDS)
244Security descriptor data size (in $SDS)
284Unknown

Security descriptor identifier ($SII) index

The security descriptor identifier index value

OffsetSizeValueDescription
Key data
04Security descriptor identifier
Value data
44Security descriptor hash
84Security descriptor identifier
128Security descriptor data offset (in $SDS)
204Security descriptor data size (in $SDS)

TODO: describe the hash algorithm

Security descriptor ($SDS) data stream

OffsetSizeValueDescription
04Security descriptor hash
44Security descriptor identifier
128Security descriptor data offset (in $SDS)
204Security descriptor data size (in $SDS)
24...Security descriptor data
......Alignment padding (2-byte alignment)

TODO: link to security descriptor format documentation

The object identifiers

$ObjID:$O

OffsetSizeValueDescription
Key data
016File (or object) identifier, which contains a GUID
Value data
48File reference
1216Birth droid volume identifier, which contains a GUID
2816Birth droid file (or object) identifier, which contains a GUID
4416Birth droid domain identifier, which contains a GUID

Metadata transaction journal (log file)

TODO: complete section

The metadata file $LogFile contains the metadata transaction journal and consists of:

Log File service restart page header

The Log File service restart page header (LFS_RESTART_PAGE_HEADER) is 30 bytes in size and consists of:

OffsetSizeValueDescription
MULTI_SECTOR_HEADER
04"CHKD", "RCRD", "RSTR"Signature
42The fix-up values (or update sequence array) offset, which contain an offset relative from the start of the restart page header
62The number of fix-up values (or update sequence array size)
Common
88Checkdisk last LSN
164System page size
204Log page size
242Restart offset
262Minor format version
282Major format version

Log File service restart page versions

Major format versionRemarks
-1Beta Version
0Transition
1Update sequence support

USN change journal

The metadata file $Extend$UsnJrnl contains the USN change journal. It is a sparse file in which NTFS stores records of changes to files and directories. Applications make use of the journal to respond to file and directory changes as they occur, like e.g. the Windows File Replication Service (FRS) and the Windows (Desktop) Search service.

The USN change journal consists of:

  • the $UsnJrnl:$Max data stream, containing metadata like the maximum size of the journal
  • the $UsnJrnl:$J data stream, containing the update (or change) entries. The $UsnJrnl:$J data stream is sparse.

USN change journal metadata

The USN change journal metadata is 32 bytes in size and consists of:

OffsetSizeValueDescription
08Maximum size in bytes
88Allocation (size) delta in bytes
168Update (USN) journal identifier, which contains a FILETIME
248Unknown (empty)

USN change journal entries

The $UsnJrnl:$J data stream consists of an array of USN change journal entries. The USN change journal entries are stored on a per block-basis and 8-byte aligned. Therefore the remainder of the block can contain 0-byte values.

TODO: describe journal block size

Once the stream reaches maximum size the earliest USN change journal entries are removed from the stream and replaced with a sparse data run.

USN change journal entry

The USN change journal entry (USN_RECORD_V2) is of variable size and consists of:

OffsetSizeValueDescription
04Entry (or record) size
422Major format version
620Minor format version
88File reference
168Parent file reference
248Update sequence number (USN), which contains the file offset of the USN change journal entry which is used as a unique identifier
328Update date and time, which contains a FILETIME
404Update reason flags
444Update source flags
484Security descriptor identifier, which contains the entry number in the security ID index ($Secure:$SII). Also see Access Control
524File attribute flags
562Name size in bytes
582Name offset, which is relative from the start of the USN change journal entry
60(name size)Name, which contains an UCS-2 little-endian string without end-of-string character
......0x00Unknown (Padding)

Update reason flags

ValueIdentifierDescription
0x00000001USN_REASON_DATA_OVERWRITEThe data in the file or directory is overwritten
0x00000002USN_REASON_DATA_EXTENDThe file or directory is extended
0x00000004USN_REASON_DATA_TRUNCATIONThe file or directory is truncated
0x00000010USN_REASON_NAMED_DATA_OVERWRITEOne or more named data streams ($DATA attributes) of file were overwritten
0x00000020USN_REASON_NAMED_DATA_EXTENDOne or more named data streams ($DATA attributes) of file were extended
0x00000040USN_REASON_NAMED_DATA_TRUNCATIONOne or more named data streams ($DATA attributes) of a file were truncated
0x00000100USN_REASON_FILE_CREATEThe file or directory was created
0x00000200USN_REASON_FILE_DELETEThe file or directory was deleted
0x00000400USN_REASON_EA_CHANGEThe extended attributes of the file were changed
0x00000800USN_REASON_SECURITY_CHANGEThe access rights (security descriptor) of a file or directory were changed
0x00001000USN_REASON_RENAME_OLD_NAMEThe name changed, where the USN change journal entry contains the old name
0x00002000USN_REASON_RENAME_NEW_NAMEThe name changed, where the USN change journal entry contains the new name
0x00004000USN_REASON_INDEXABLE_CHANGEContent indexed status changed. The file attribute FILE_ATTRIBUTE_NOT_CONTENT_INDEXED was changed
0x00008000USN_REASON_BASIC_INFO_CHANGEBasic file or directory attributes changed. One or more file or directory attributes were changed e.g. read-only, hidden, system, archive, or sparse attribute, or one or more time stamps
0x00010000USN_REASON_HARD_LINK_CHANGEA hard link was created or deleted
0x00020000USN_REASON_COMPRESSION_CHANGEThe file or directory was compressed or decompressed
0x00040000USN_REASON_ENCRYPTION_CHANGEThe file or directory was encrypted or decrypted
0x00080000USN_REASON_OBJECT_ID_CHANGEThe object identifier of a file or directory was changed
0x00100000USN_REASON_REPARSE_POINT_CHANGEThe reparse point that in a file or directory was changed, or a reparse point was added to or deleted from a file or directory
0x00200000USN_REASON_STREAM_CHANGEA named data stream ($DATA attribute) is added to or removed from a file, or a named stream is renamed
0x00400000USN_REASON_TRANSACTED_CHANGEUnknown
0x80000000USN_REASON_CLOSEThe file or directory was closed

Update source flags

ValueIdentifierDescription
0x00000001USN_SOURCE_DATA_MANAGEMENTThe operation added a private data stream to a file or directory. The modifications did not change the application data
0x00000002USN_SOURCE_AUXILIARY_DATAThe operation was caused by the operating system. Although a write operation is performed on the item, the data was not changed
0x00000004USN_SOURCE_REPLICATION_MANAGEMENTThe operation was caused by file replication

Alternate data streams (ADS)

Data stream nameDescription
"♣BnhqlkugBim0elg1M1pt2tjdZe", "♣SummaryInformation", "{4c8cc155-6c1e-11d1-8e41-00c04fb9386d}"Used to store properties, where ♣ (black club) is Unicode character U+2663
"{59828bbb-3f72-4c1b-a420-b51ad66eb5d3}.XPRESS"Used during remote differential compression
"AFP_AfpInfo", "AFP_Resource"Used to store Macintosh operating system property lists
"encryptable"Used to store attributes relating to thumbnails in the thumbnails database
"favicon"Used to store favorite icons for web pages
"ms-properties"Used to store properties
"OECustomProperty"Used to store custom properties related to email files
"Zone.Identifier"Used to store the Internet Explorere URL security zone of the origin

ms-properties

The ms-properties alternate data stream contains a Windows Serialized Property Store (SPS).

TODO: link to Windows Serialized Property Store (SPS) format documentation

Zone.Identifier

The Zone.Identifier alternate data stream contains ASCII text in the form:

[ZoneTransfer]
ZoneId=3

Where ZoneId refers to the Internet Explorer URL security zone of the origin.

Transactional NTFS (TxF)

As of Vista Transactional NTFS (TxF) was added.

In TxF the resource manager (RM) keeps track of transactional metadata and log files. The TxF related metadata files are stored in the metadata directory:

$Extend\$RmMetadata

Resource manager repair information

The resource manager repair information metadata file “$Extend$RmMetadata$Repair” consists of the following data streams:

  • the default (unnamed) data stream
  • the $Config data stream, contains the resource manager repair configuration information

TODO: determine the purpose of the default (unnamed) data stream

Resource manager repair configuration information

TODO: complete section

The $Repair:$Config data streams contains:

OffsetSizeValueDescription
04Unknown
44Unknown

Transactional NTFS (TxF) metadata directory

TODO: complete section

The transactional NTFS (TxF) metadata directory “$Extend$RmMetadata$Txf” is used to isolate files for delete or overwrite operations.

TxF Old Page Stream (TOPS) file

The TxF Old Page Stream (TOPS) file “$Extend$RmMetadata$TxfLog$Tops” consists of the following data streams:

  • the default (unnamed) data stream, contains metadata about the resource manager, such as its GUID, its CLFS log policy, and the LSN at which recovery should start
  • the $T data stream, contains the file data that is partially overwritten by a transaction as opposed to a full overwrite, which would move the file into the Transactional NTFS (TxF) metadata directory

TxF Old Page Stream (TOPS) metadata

TODO: complete section

The $Tops default (unnamed) data streams contains:

OffsetSizeValueDescription
02Unknown
22Size of TOPS metadata
44Unknown (Number of resource managers/streams?)
816Resource Manager (RM) identifier, which contains a GUID
248Unknown (empty)
328Base (or log start) LSN of TxFLog stream
408Unknown
488Last flushed LSN of TxFLog stream
568Unknown
648Unknown (empty)
728Unknown (Restart LSN?)
8020Unknown

TxF Old Page Stream (TOPS) file data

The $Tops:$T data streams contains the file data that is partially overwritten by a transaction. It consists of multiple pending transaction XML-documents.

TODO: describe start of each sector containing 0x0001

A pending transaction XML-document starts with an UTF-8 byte-order-mark. Is roughly contains the following data:

<?xml version='1.0' encoding='utf-8'?>
<PendingTransaction Version="2.0" Identifier="...">
   <Transactions>
      <Transaction TransactionId="...">
      <Install Application="..., Culture=..., Version=..., PublicKeyToken=...,
                           ProcessorArchitecture=..., versionScope=..."
               RefGuid="..."
               RefIdentifier="..."
               RefExtra="..."/>
      ...
      </Transaction>
   </Transactions>
   <ChangeList>
      <Change Family="..., Culture=..., PublicKeyToken=...,
                     ProcessorArchitecture=..., versionScope=..."
              New="..."/>
      ...
   </ChangeList>
   <POQ>
      <BeginTransaction id="..."/>

      <CreateFile path="..."
                  fileAttribute="..."/>
      <DeleteFile path="..."/>
      <MoveFile source="..." destination="..."/>
      <HardlinkFile source="..." destination="..."/>
      <SetFileInformation path="..."
                          securityDescriptor="binary base64:..."
                          flags="..."/>

       <CreateKey path="..."/>
       <SetKeyValue path="..."
                    name="..."
                    type="..."
                    encoding="base64"
                    value="..."/>
      <DeleteKeyValue path="..."
                      name="..."/>

      ...
   </POQ>
   <InstallerQueue Length="...">
      <Action Installer="..."
              Mode="..."
              Phase="..."
              Family="..., Culture=..., PublicKeyToken=...,
                     ProcessorArchitecture=..., versionScope=..."
              Old="..."
              New="..."/>

      ...
   </InstallerQueue >
</PendingTransaction>

Transactional NTFS (TxF) Common Log File System (CLFS) files

TxF uses a Common Log File System (CLFS) log store and the logged utility stream attribute named $TXF_DATA.

TODO: link to CLFS format documentation

The base log file (BLF) of the TxF log store is:

$Extend\$RmMetadata\$TxfLog\TxfLog.blf

Commonly the corresponding container files are:

$Extend\$RmMetadata\$TxfLog\TxfLogContainer00000000000000000001
$Extend\$RmMetadata\$TxfLog\TxfLogContainer00000000000000000002

TxF uses a multiplexed log store which contains the following streams:

  • the KtmLog stream used for Kernel Transaction Manager (KTM) metadata records
  • TxfLog stream, which contains the TxF log records.

Transactional data logged utility stream attribute

The transactional data ($TXF_DATA) logged utility stream attribute is 56 bytes in size and consist of:

OffsetSizeValueDescription
06Unknown (remnant data)
68Resource manager root file reference, which contains an NTFS file reference that refers to the MFT
148Unknown (USN index?)
228File identifier (TxID), which contains a TxF file identifier
308Data LSN, which contains a CLFS LSN of file data transaction records
388Metadata LSN, which contains a CLFS LSN of file system metadata transaction records
468Directory index LSN, which contains a CLFS LSN of directory index transaction records
542Unknown (Flags?)

Note that a single MFT entry can contain multiple Transactional data logged utility stream attributes.

Windows definitions

File attribute flags

The file attribute flags consist of the following values:

ValueIdentifierDescription
0x00000001FILE_ATTRIBUTE_READONLYIs read-only
0x00000002FILE_ATTRIBUTE_HIDDENIs hidden
0x00000004FILE_ATTRIBUTE_SYSTEMIs a system file or directory
0x00000008Is a volume label, which is not used by NTFS
0x00000010FILE_ATTRIBUTE_DIRECTORYIs a directory, which is not used by NTFS
0x00000020FILE_ATTRIBUTE_ARCHIVEShould be archived
0x00000040FILE_ATTRIBUTE_DEVICEIs a device, which is not used by NTFS
0x00000080FILE_ATTRIBUTE_NORMALIs normal file. Note that none of the other flags should be set
0x00000100FILE_ATTRIBUTE_TEMPORARYIs temporary
0x00000200FILE_ATTRIBUTE_SPARSE_FILEIs a sparse file
0x00000400FILE_ATTRIBUTE_REPARSE_POINTIs a reparse point or symbolic link
0x00000800FILE_ATTRIBUTE_COMPRESSEDIs compressed
0x00001000FILE_ATTRIBUTE_OFFLINEIs offline. The data of the file is stored on an offline storage
0x00002000FILE_ATTRIBUTE_NOT_CONTENT_INDEXEDDo not index content. The content of the file or directory should not be indexed by the indexing service
0x00004000FILE_ATTRIBUTE_ENCRYPTEDIs encrypted
0x00008000Unknown (seen on Windows 95 FAT)
0x00010000FILE_ATTRIBUTE_VIRTUALIs virtual

The following flags are mainly used in the file name attribute and sparsely in the standard information attribute. It could be that they have a different meaning in both types of attributes or that the standard information flags are not updated. For now the latter is assumed.

ValueIdentifierDescription
0x10000000Unknown (Is directory or has $I30 index? Note that an $Extend directory without this flag has been observed)
0x20000000Is index view

Format edge cases and corruption scenarios

Data steam with inconsistent data flags

An MFT entry contains an $ATTRIBUTE_LIST attribute that contains multiple $DATA attributes. The $DATA attributes define a LZNT1 compressed data stream though only the first $DATA attribute has the compressed data flag set.

MFT entry: 220 information:
    Is allocated                   : true
    File reference                 : 220-59
    Base record file reference     : Not set (0)
    Journal sequence number        : 51876429013
    Number of attributes           : 5

Attribute: 1
    Type                           : $STANDARD_INFORMATION (0x00000010)
    Creation time                  : Jun 05, 2019 06:56:26.032730300 UTC
    Modification time              : Oct 05, 2019 06:56:04.150940700 UTC
    Access time                    : Oct 05, 2019 06:56:04.150940700 UTC
    Entry modification time        : Oct 05, 2019 06:56:04.150940700 UTC
    Owner identifier               : 0
    Security descriptor identifier : 5862
    Update sequence number         : 11553149976
    File attribute flags           : 0x00000820
       Should be archived (FILE_ATTRIBUTE_ARCHIVE)
       Is compressed (FILE_ATTRIBUTE_COMPRESSED)

Attribute: 2
    Type                           : $ATTRIBUTE_LIST (0x00000020)

Attribute: 3
    Type                           : $FILE_NAME (0x00000030)
    Parent file reference          : 33996-57
    Creation time                  : Jun 05, 2019 06:56:26.032730300 UTC
    Modification time              : Oct 05, 2019 06:56:03.510061800 UTC
    Access time                    : Oct 05, 2019 06:56:03.510061800 UTC
    Entry modification time        : Oct 05, 2019 06:56:03.510061800 UTC
    File attribute flags           : 0x00000020
       Should be archived (FILE_ATTRIBUTE_ARCHIVE)
    Namespace                      : POSIX (0)
    Name                           : setupapi.dev.20191005_085603.log

Attribute: 4
    Type                           : $DATA (0x00000080)
    Data VCN range                 : 513 - 1103
    Data flags                     : 0x0000

Attribute: 5
    Type                           : $DATA (0x00000080)
    Data VCN range                 : 0 - 512
    Data size                      : 4487594 bytes
    Data flags                     : 0x0001

Note that it is unclear if this is a format edge case or corruption scenario.

Directory entry with outdated file reference

The directory entry “\ProgramData\McAfee\Common Framework\Task\5.ini”

File entry:
    Path                           : \ProgramData\McAfee\Common Framework\Task\5.ini
    File reference                 : 51106-400
    Name                           : 5.ini
    Parent file reference          : 65804-10
    Size                           : 723
    Creation time                  : Sep 16, 2011 20:47:54.561041200 UTC
    Modification time              : Apr 07, 2012 21:07:02.684060000 UTC
    Access time                    : Apr 07, 2012 21:07:02.652810200 UTC
    Entry modification time        : Apr 07, 2012 21:07:02.684060000 UTC
    File attribute flags           : 0x00002020
       Should be archived (FILE_ATTRIBUTE_ARCHIVE)
       Content should not be indexed (FILE_ATTRIBUTE_NOT_CONTENT_INDEXED)

The corresponding MFT entry:

MFT entry: 51106 information:
    Is allocated                   : true
    File reference                 : 51106-496
    Base record file reference     : Not set (0)
    Journal sequence number        : 0
    Number of attributes           : 3

Attribute: 1
    Type                           : $STANDARD_INFORMATION (0x00000010)
    Creation time                  : Sep 16, 2011 20:47:54.561041200 UTC
    Modification time              : Apr 07, 2012 21:07:02.684060000 UTC
    Access time                    : Apr 07, 2012 21:07:02.652810200 UTC
    Entry modification time        : Apr 07, 2012 21:07:02.684060000 UTC
    Owner identifier               : 0
    Security descriptor identifier : 1368
    Update sequence number         : 1947271600
    File attribute flags           : 0x00002020
       Should be archived (FILE_ATTRIBUTE_ARCHIVE)
       Content should not be indexed (FILE_ATTRIBUTE_NOT_CONTENT_INDEXED)

Attribute: 2
    Type                           : $FILE_NAME (0x00000030)
    Parent file reference          : 65804-10
    Creation time                  : Sep 16, 2011 20:47:54.561041200 UTC
    Modification time              : Apr 07, 2012 21:07:02.652810200 UTC
    Access time                    : Apr 07, 2012 21:07:02.652810200 UTC
    Entry modification time        : Apr 07, 2012 21:07:02.652810200 UTC
    File attribute flags           : 0x00002020
       Should be archived (FILE_ATTRIBUTE_ARCHIVE)
       Content should not be indexed (FILE_ATTRIBUTE_NOT_CONTENT_INDEXED)
    Namespace                      : DOS and Windows (3)
    Name                           : 1.ini

Attribute: 3
    Type                           : $DATA (0x00000080)
    Data size                      : 723 bytes
    Data flags                     : 0x0000

TODO: determine if $LogFile could be used to recover from this corruption scenario

Directory entry referencing MFT entry with base record

The directory entry “\System Volume Information\DFSR\Config\Replica_F68AA759-069D-48B1-BE6F-205F26A792D0.XML”.

File entry:
    Path                           : \System Volume Information\DFSR\Config\Replica_F68AA759-069D-48B1-BE6F-205F26A792D0.XML
    File reference                 : 77019-345
    Name                           : Replica_F68AA759-069D-48B1-BE6F-205F26A792D0.XML
    Parent file reference          : 19780-3
    Size                           : 0

The corresponding MFT entry:

MFT entry: 77019 information:
    Is allocated                   : true
    File reference                 : 77019-345
    Base record file reference     : 296-623
    Journal sequence number        : 24747653240
    Number of attributes           : 1

Attribute: 1
    Attribute type                 : $DATA (0x00000080)
    Data VCN range                 : 0 - 249
    Data size                      : 1023546 bytes
    Data flags                     : 0x0000

The parent MFT entry:

MFT entry: 296 information:
    Is allocated                   : true
    File reference                 : 296-623
    Base record file reference     : Not set (0)
    Journal sequence number        : 24747648692
    Number of attributes           : 4

Attribute: 1
    Attribute type                 : $STANDARD_INFORMATION (0x00000010)
    Creation time                  : Dec 05, 2009 20:39:34.765625000 UTC
    Modification time              : Apr 08, 2012 17:33:45.756367200 UTC
    Access time                    : Apr 08, 2012 06:06:11.653828200 UTC
    Entry modification time        : Apr 08, 2012 17:33:45.756367200 UTC
    Owner identifier               : 0
    Security descriptor identifier : 408
    Update sequence number         : 6855921000
    File attribute flags           : 0x00000020
        Should be archived (FILE_ATTRIBUTE_ARCHIVE)

Attribute: 2
    Attribute type                 : $ATTRIBUTE_LIST (0x00000020)
    Data size                      : 96 bytes
    Number of entries              : 3
    Entry: 0                       : $STANDARD_INFORMATION (0x00000010) in file reference: 296-623
    Entry: 1                       : $FILE_NAME (0x00000030) in file reference: 296-623
    Entry: 2                       : $DATA (0x00000080) in file reference: 77019-345

Attribute: 3
    Attribute type                 : $FILE_NAME (0x00000030)
    Parent file reference          : 1371-1
    Creation time                  : Dec 05, 2009 20:39:34.765625000 UTC
    Modification time              : Apr 08, 2012 06:06:11.653828200 UTC
    Access time                    : Apr 08, 2012 06:06:11.653828200 UTC
    Entry modification time        : Apr 08, 2012 06:06:11.653828200 UTC
    File attribute flags           : 0x00000020
        Should be archived (FILE_ATTRIBUTE_ARCHIVE)
    Name space                     : DOS and Windows (3)
    Name                           : winlogon.log

Attribute: 4
    Attribute type                 : $DATA (0x00000080)
    Data VCN range                 : 0 - 249
    Data size                      : 1023546 bytes
    Data flags                     : 0x0000

Note it is currently assumed this is a corruption scenario and the data is part of the attribute list of MFT entry 296 not of the file “Replica_F68AA759-069D-48B1-BE6F-205F26A792D0.XML”. The VOLUME_IS_DIRTY volume flag was not set.

LZNT1 compressed block with data size of 0

Not sure if this is a corruption scenario or a data format edge case.

A compression unit (index 30) consisting of the following data runs:

reading data run: 60.
data run:
00000000: 11 01 01                                           ...

value sizes                               : 1, 1
number of cluster blocks                  : 1 (size: 4096)
cluster block number                      : 687143 (1) (offset: 0xa7c27000)

reading data run: 61.
data run:
00000000: 01 0f                                              ..

value sizes                               : 1, 0
number of cluster blocks                  : 15 (size: 61440)
cluster block number                      : 0 (0) (offset: 0x00000000)
        Is sparse

Contains the following data:

a7c27000  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
...
a7c27ff0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|

This relates to an empty LZNT1 compressed block.

compressed data offset                    : 0 (0x00000000)
compression chunk header                  : 0x0000
compressed chunk size                     : 1
signature value                           : 0
is compressed flag                        : 0

It was observed in 2 differnt NTFS implementations that the entire block is filled with 0-byte values.

TODO: verify behavior of Windows NTFS implementation.

Truncated LZNT1 compressed block

Not sure if this is a corruption scenario or a data format edge case.

A compression unit (index 0) consisting of the following data runs:

reading data run: 0.
data run:
00000000: 31 08 48 d8 01                                     1.H..

value sizes                               : 1, 3
number of cluster blocks                  : 8 (size: 32768)
cluster block number                      : 120904 (120904) (offset: 0x1d848000)

reading data run: 1.
data run:
00000000: 01 08                                              ..

value sizes                               : 1, 0
number of cluster blocks                  : 8 (size: 32768)
cluster block number                      : 0 (0) (offset: 0x00000000)
        Is sparse

Contains the following data:

1d848000  bd b7 50 44 46 50 00 01  00 01 00 40 e0 00 07 0b  |..PDFP.....@....|
...
1d84c000  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
1d84fff0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|

This relates to a LZNT1 compressed block that appears to be truncated at offset 16384 (0x00004000).

compressed data offset                    : 16384 (0x00004000)
compression flag byte                     : 0x00

Different behavior was observed in 2 differnt NTFS implementations:

  • one implementation fills the compressed block with the uncompressed data it could read and the rest with with 0-byte values
  • another implementation seems to provide the data that was already in its buffer

TODO: verify behavior of Windows NTFS implementation.

References

X File System (XFS)

The X File System (XFS) is a file system that originates from SGI but is used in various Linux distributions like RHEL. Some sources indicate that X was a a placeholder for a name that never given.

Overview

CharacteristicsDescription
Byte orderbig-endian
Date and time valuesnumber of seconds since January 1, 1970 00:00:00 UTC (POSIX epoch) and fraction of second in number of nanoseconds, or in bigtime (number of nanoseconds since December 13, 1901 20:45:52 UTC)
Character stringsUTF-8 or a narrow character (Single Byte Character (SBC) or Multi Byte Character (MBC)) stored using a system defined codepage

Terminology

Absolute and relative inode numbers

A relative inode number is an inode number used within a specific allocation group. An absolute inode number combines the allocation group number and the relative inode number.

number_of_relative_inode_number_bits = (
    allocation_group_size_log2 + number_of_inodes_per_block_log2
)
absolute_inode_number = (
    (allocation_group_number << number_of_relative_inode_number_bits) | relative_inode_number
)

File system block number

A relative block number is a block number relative to the start of an allocation group. A file system block number (xfs_fsblock_t) combines the allocation group number and the relative block number.

number_of_relative_block_number_bits = allocation_group_size_log2

file_system_block_number = (
    (allocation_group_number << number_of_relative_block_number_bits) | relative_block_number
)
file_offset = (allocation_group_block_number + relative_block_number) * block_size

The allocation group

An allocation group consists of:

  • a sector containing a superblock
  • a sector containing free block information
  • a sector containing inode tree information
  • a sector containing internal free list
  • blocks containing
    • root of the inode tree
    • root of the free space B+ tree
    • free list
    • inodes table

The superblock

The XFS superblock (xfs_sb_t) is (at least) 512 bytes in size and consists of:

OffsetSizeValueDescription
04"XFSB"Signature
44Block size, which is typicaly 4096 bytes (4 KiB) and can range from 512 to 65536 bytes
88Total number of blocks
168Number of real-time (device) blocks
248Number of real-time (device) extents
3216File system (or volume) identifier, which contains an UUID
488Journal block number, which contains a file system block number or 0 if the journal is stored on a separate device
568Root directory (absolute) inode number, which contains -1 (0xffffffffffffffff) if not set
648Real-time bitmap extents inode number, which contains -1 (0xffffffffffffffff) if not set
728Real-time bitmap summary inode number, which contains -1 (0xffffffffffffffff) if not set
804Real-time extent size, in number of blocks
844Allocation group size, in number of blocks
884Number of allocation groups
924Real-time bitmap size, in number of blocks
964Journal size, in number of blocks
1002Format version and feature flags
1022Sector size (in bytes)
1042Inode size (in bytes), which can range from 256 to 2048
1062Number of inodes per block
10812Volume label (or name)
1201Block size in log2, where value = ( 2 ^ value in log2 ) or 0 if value in log2 is 0
1211Sector size in log2, where value = ( 2 ^ value in log2 ) or 0 if value in log2 is 0
1221Inode size in log2, where value = ( 2 ^ value in log2 ) or 0 if value in log2 is 0
1231Number of inodes per block in log2, where value = ( 2 ^ value in log2 ) or 0 if value in log2 is 0
1241Allocation group size in log2, where value = ( 2 ^ value in log2 ) or 0 if value in log2 is 0
1251Number of real-time (device) extents in log2, where value = ( 2 ^ value in log2 ) or 0 if value in log2 is 0
1261Creation flag, which contains a value to indicate file system is being created
1271Inodes percentage, which contains the percentage of the maximum space of the volume to use for inodes
Only used in the first superblock
1288Number of inodes
1368Number of free inodes
1448Number of free data blocks
1528Number of free real-time extents
Only used if the XFS_SB_VERSION_QUOTABIT feature flag is set
1608User quota inode number
1688Group (or project) quota inode number
1762Quota flags
Common
1781Miscellaneous flags
17910Unknown (reserved or shared version number)
Only used if the XFS_SB_VERSION_ALIGNBIT feature flag is set
1804Inode chunk alignment size, in number of blocks
Common
1844Stripe (or RAID) unit size, in number of blocks
1884Stripe (or RAID) width, in number of blocks
1921Directory block size in log2, in number of blocks
1931Journal device sector size in log2
1942Journal device sector size (in bytes)
Only used if the XFS_SB_VERSION_LOGV2BIT feature flag is set
1964Journal device stripe or RAID unit size
Common
2004Secondary feature flags
2044Copy of secondary feature flags, which was introduced to work-around 64-bit alignment errors
If superblock format version >= 5 (XFS_SB_VERSION_5)
2084(Read-write) compatible feature flags
2124Read-only compatible feature flags
2164(Read-write) incompatible feature flags
2204Journal (read-write) incompatible feature flags
2244Checksum of the superblock
2284Unknown (Sparse inode chunk alignment in number of blocks)
2324Project quota inode number
2368Journal log sequence number (LSN) of the last superblock update
Only used if the XFS_SB_FEAT_INCOMPAT_META_UUID incompatible feature flag is set
24416Metadata identifier, which contains an UUID
Only used if the XFS_SB_FEAT_RO_COMPAT_RMAPBT incompatible feature flag is set
2608Real-time Reverse Mapping B+tree inode number
268244Unknown (empty values)

Note that the allocation group size and allocation group size in log2 are not necessarily equivalent.

Format version and feature flags

The 4 LSB contain the version the remaining bits are used to store feature flags.

VersionIdentifierIntroduced in
First generation
1XFS_SB_VERSION_1Introduced in Irix 5.3
2XFS_SB_VERSION_2Introduced in Irix 6.2, added extended attribute support
3XFS_SB_VERSION_3Introduced in Irix 6.2, added inode version 2 support
Second generation
4XFS_SB_VERSION_4Introduced in Irix 6.2, added directory version 2 support
Third generation
5XFS_SB_VERSION_5Introduced in Linux 3.10
ValueIdentifierDescription
Introduced in XFS_SB_VERSION_2
0x0010XFS_SB_VERSION_ATTRBITInodes support extended attributes
Introduced in XFS_SB_VERSION_3
0x0020XFS_SB_VERSION_NLINKBITInodes use a 32-bit number of links value
Introduced in XFS_SB_VERSION_4
0x0040XFS_SB_VERSION_QUOTABITQuotas enabled
0x0080XFS_SB_VERSION_ALIGNBITUse inode chunk alignment
0x0100XFS_SB_VERSION_DALIGNBITHas underlying stripe or RAID. The Stripe (or RAID) unit size and width values in the superblock should be set
0x0200XFS_SB_VERSION_SHAREDBITUnknown (set if reserved shared version is used)
0x0400XFS_SB_VERSION_LOGV2BITHas version 2 journaling logs
0x0800XFS_SB_VERSION_SECTORBITSector size is not 512 bytes
0x1000XFS_SB_VERSION_EXTFLGBITUnwritten extents are used, which should always be set
0x2000XFS_SB_VERSION_DIRV2BITVersion 2 directories are used
0x4000XFS_SB_VERSION_BORGBITUnknown (ASCII only case-insensitive)
0x8000XFS_SB_VERSION_MOREBITSBITSecondary feature flags are used

Secondary feature flags

ValueIdentifierDescription
0x00000001XFS_SB_VERSION2_RESERVED1BITUnknown (reserved)
0x00000002XFS_SB_VERSION2_LAZYSBCOUNTBITHas lazy global counters. Free space and inode values are only tracked in the primary superblock
0x00000004XFS_SB_VERSION2_RESERVED4BITUnknown (reserved)
0x00000008XFS_SB_VERSION2_ATTR2BITVersion 2 extended attributes are used
0x00000010XFS_SB_VERSION2_PARENTBITInodes have a parent pointer
0x00000080XFS_SB_VERSION2_PROJID32BITHas 32-bit project identifiers
0x00000100XFS_SB_VERSION2_CRCBITHas metadata checksums
0x00000200XFS_SB_VERSION2_FTYPEDirectory entries contain a file type

Miscellaneous flags

ValueIdentifierDescription
0x01XFS_SBF_READONLYRead-only file system

Quota flags

ValueIdentifierDescription
0x0001XFS_UQUOTA_ACCTUser quota accounting is enabled
0x0002XFS_UQUOTA_ENFDUser quotas are enforced
0x0004XFS_UQUOTA_CHKDUser quotas have been checked and updated on disk
0x0008XFS_PQUOTA_ACCTProject quota accounting is enabled
0x0010XFS_OQUOTA_ENFDOther (group/project) quotas are enforced
0x0020XFS_OQUOTA_CHKDOther (group/project) quotas have been checked
0x0040XFS_GQUOTA_ACCTGroup quota accounting is enabled
0x0080XFS_GQUOTA_ENFDGroup quotas are enforced
0x0100XFS_GQUOTA_CHKDGroup quotas have been checked
0x0200XFS_PQUOTA_ENFDProject quotas are enforced
0x0400XFS_PQUOTA_CHKDProject quotas have been checked

Compatible feature flags

Currently no compatible feature flags are defined.

Read-only compatible feature flags

ValueIdentifierDescription
0x00000001XFS_SB_FEAT_RO_COMPAT_FINOBTHas free inode btree
0x00000002XFS_SB_FEAT_RO_COMPAT_RMAPBTHas reverse map btree
0x00000004XFS_SB_FEAT_RO_COMPAT_REFLINKHas reflinked files
0x00000008XFS_SB_FEAT_RO_COMPAT_INOBTCNTHas inobt block counts

Incompatible feature flags

ValueIdentifierDescription
0x00000001XFS_SB_FEAT_INCOMPAT_FTYPEHas filetype in dirent
0x00000002XFS_SB_FEAT_INCOMPAT_SPINODESHas sparse inode chunks
0x00000004XFS_SB_FEAT_INCOMPAT_META_UUIDUse a metadata identifier
0x00000008XFS_SB_FEAT_INCOMPAT_BIGTIMEInode (v3) contains bigtime timestamps
0x00000010XFS_SB_FEAT_INCOMPAT_NEEDSREPAIRNeeds repair
0x00000020XFS_SB_FEAT_INCOMPAT_NREXT64Inode (v3) contains a 64-bit number of data extents and 32-bit number of (extended) attribute extent values
0x00000040XFS_SB_FEAT_INCOMPAT_EXCHRANGEHas exchangerange
0x00000080XFS_SB_FEAT_INCOMPAT_PARENTHas parent directory reference attributes
0x00000100XFS_SB_FEAT_INCOMPAT_METADIRHas metadata directory (tree)
0x00000200XFS_SB_FEAT_INCOMPAT_ZONEDHas zoned RT allocator
0x00000400XFS_SB_FEAT_INCOMPAT_ZONE_GAPSRTGs have LBA gaps

Journal incompatible feature flags

Currently no journal incompatible feature flags are defined.

Free block information

The free block information stores references:

  • the block offset B+ tree, that tracks the free space by block number
  • the block count B+ tree, that tracks the size of the free space block

The free block information (xfs_agf_t) is 64 or 224 bytes in size and consists of:

OffsetSizeValueDescription
04"XAGF"Signature
441Version
84Sequence number, which contains the allocation group number of the corresponding sector
124Unknown (Allocation group size), in number of blocks
164Free space counts B+ tree root block number
204Free space sizes B+ tree root block number
244Unknown (reserved)
284Free space counts B+ tree height/depth
324Free space sizes B+ tree height/depth
364Unknown (reserved)
404Index of the first "free list" block
444Index of the last "free list" block
484"Free list" size, in number of blocks
524Number of free blocks in the allocation group
564Longest contiguous free space in the allocation group, in number of blocks
Only used if the XFS_SB_VERSION2_LAZYSBCOUNTBIT feature flag is set
604Number of blocks used for the free space B+ trees
If superblock format version >= 5 (XFS_SB_VERSION_5)
6416Block type identifier, which contains an UUID that should correspond to sb_uuid or sb_meta_uuid
804Unknown (Size of the reverse mapping B+ tree in blocks)
844Unknown (Size of the reference count B+ tree in blocks)
884Reverse mapping B+ tree root block number, which contains a block number relative to the start of the allocation group
924Reference count B+ tree root block number, which contains a block number relative to the start of the allocation group
9614 x 8Unknown (reserved)
2088Log sequence number
2164Unknown (Checksum of the free sector)
2204Unknown (reserved)

Free list

A free list consists of:

  • As of version 5, free list header
  • Array of free block numbers

Free list header

The free list header is 36 bytes in size and consist of:

OffsetSizeValueDescription
04"AGFL"Signature
44Sequence number, which contains the allocation group number of the corresponding sector
816Block type identifier, which contains an UUID that should correspond to sb_uuid or sb_meta_uuid
248Log sequence number
324Checksum

TODO: describe sb_uuid or sb_meta_uuid

Inode information

The inode information (xfs_agi_t) is (at least) 512 bytes in size and consists of:

OffsetSizeValueDescription
04"XAGI"Signature
441Version
84Sequence number, which contains the allocation group number of the corresponding sector
124Unknown (Allocation group size), in number of blocks
164Number of inodes in the allocation group
204Inode tree root block number, which contains a block number relative to the start of the allocation group
244Inode tree height/depth
284Number of unused (free) inodes in the allocation group
324First inode number of the last allocated inode chunk, which contains an inode number relative to the allocation group
364-1 (0xffffffff)Unknown
4064 x 4Hash table of 32-bit unlinked (deleted) inode numbers that are still being referenced, which contains -1 (0xffffffff) if not set
If superblock format version >= 5 (XFS_SB_VERSION_5)
29616Block type identifier, which contains an UUID that should correspond to sb_uuid or sb_meta_uuid
3124Checksum
3164Unknown (padding)
3208Log sequence number
3284Free inode tree root block number, which contains a block number relative to the start of the allocation group
3324Free inode tree height/depth
3364Unknown
3404Unknown
344168Unknown (empty values)

B+ tree

XFS uses B+ trees to store various types of information. There are 2 different types of B+ trees, namely:

  • Free space block B+ tree
  • Inode tree
  • Reference count B+ tree

B+ tree block

A B+ tree block consists of:

  • B+ tree block header
  • Array of branch or leaf block records

B+ tree block header

B+ tree block header 32-bit

The B+ tree block header 32-bit (xfs_btree_sblock_t or xfs_btree_iblock_t) is 16 or 56 bytes of size and consist of:

OffsetSizeValueDescription
04Signature
42Level (or depth/height), which contains 0 for a leaf block
62Number of records
84Previous B+ tree block number, which is relative to the start of the allocation group or contains -1 (0xffffffff) if not set
124Next B+ tree block number, which is relative to the start of the allocation group or contains -1 (0xffffffff) if not set
If superblock format version >= 5 (XFS_SB_VERSION_5)
168Block number
248Log sequence number
3216Block type identifier, which contains an UUID that should correspond to sb_uuid or sb_meta_uuid
484Owner allocation group, which contains the allocation group the block is part of
524Checksum

B+ tree block header 64-bit

The B+ tree block header 64-bit (xfs_btree_lblock_t) is 24 or 72 bytes in size and consist of:

OffsetSizeValueDescription
04Signature
42Level (or depth/height), where 0 represents a leaf block
62Number of records
88Previous B+ tree block number, which is relative to the start of the allocation group or contains -1 (0xffffffffffffffff) if not set
168Next B+ tree block number, which is relative to the start of the allocation group or contains -1 (0xffffffffffffffff) if not set
If superblock format version >= 5 (XFS_SB_VERSION_5)
248Block number
328Log sequence number
4016Block type identifier, which contains an UUID that should correspond to sb_uuid or sb_meta_uuid
568Owner allocation group, which contains the allocation group the block is part of
644Checksum
6840Unknown (padding)

B+ tree block extended header

TODO: complete section

TODO: determine where this is defined, it seems to be represented in the examples.

B+ tree block header signatures

SignatureDescription
"AB3B"Free space block offset B+ tree (file system version 5)
"AB3C"Free space block count B+ tree (file system version 5)
"ABTB"Free space block offset B+ tree
"ABTC"Free space block count B+ tree
"FIB3"Free inode B+tree (file system version 5)
"FIBT"Free inode B+tree
"IAB3"(Allocated) inode B+tree (file system version 5)
"IABT"(Allocated) inode B+tree
"R3FC"Reference count B+ tree (file system version 5)

Free space B+ tree

TODO: complete section

Free space B+ tree branch node record

The free space B+ tree branch node record (xfs_alloc_ptr_t) is 4 bytes in size and consist of:

OffsetSizeValueDescription
04Unknown

Free space B+ tree leaf node record

The free space B+ tree leaf node record (xfs_alloc_key_t) is 8 bytes in size and consist of:

OffsetSizeValueDescription
04Unknown (ar_startblock)
44Unknown (ar_blockcount)

Inode tree

The inode tree uses the B+ tree block header 32-bit.

Inode tree branch node

The inode tree branch node consists of:

  • node header
  • array of inode tree branch node entry keys
  • array of inode tree branch node entry values

The number of key-value pairs is calculated as following:

number_of_key_value_pairs = node_records_data_size / 8
Inode tree branch node key

The inode tree branch node key (xfs_inobt_key_t) is 4 bytes in size and consist of:

OffsetSizeValueDescription
04Number of the first inode in the branch, which contains an inode number relative to the allocation group

Note that the inode number of the last key can be 0.

Inode tree branch node value

The inode tree branch node key is 4 bytes in size and consist of:

OffsetSizeValueDescription
04Block number of the inode tree sub node, which contains a block number relative to the start of the allocation group

Inode tree leaf node

The inode tree branch node consists of:

  • node header
  • array of inode tree leaf node entry records
Inode tree leaf node record

The inode tree leaf node record (xfs_inobt_rec_t) is 16 bytes in size and consist of:

OffsetSizeValueDescription
04Number of the first inode of the inode chunk, which contains an inode number relative to the allocation group
44Number of unused (free) inodes of the inode chunk
88Inode chunk allocation bitmap, which tracks which inodes of the inode chunk are unused (free)

The inode chunk is a group of 64 inodes. The file offset of the inode chunk is calculated as following:

file_offset = allocation_group_file_offset + (inode_number * inode_size)

Inode

The inode can be followed by:

  • data fork (descriptor)
    • device identifier (fork type is XFS_DINODE_FMT_DEV)
    • inline data fork (fork type is XFS_DINODE_FMT_LOCAL)
    • extents list data fork (fork type is XFS_DINODE_FMT_EXTENTS)
    • extents tree data fork (fork type is XFS_DINODE_FMT_BTREE)
  • optional (extended) attributes data fork (descriptor)
    • inline attributes fork (fork type is XFS_DINODE_FMT_LOCAL)
    • extents list attributes fork (fork type is XFS_DINODE_FMT_EXTENTS)
    • extents tree attributes fork (fork type is XFS_DINODE_FMT_BTREE)

Inode version 1

The inode version 1 (xfs_dinode_core_t) is 100 bytes in size and consist of:

OffsetSizeValueDescription
02"IN"Signature
22File mode, which contains file type and permissions
411Format version
51(Data) fork type
62Number of links
84Owner (or user) identifier (UID)
124Group identifier (GID)
16140Unknown (contains data in XFS_SB_VERSION_1)
302Flush counter, which contains a value that is incremented on flush
324(last) access time, which contains a POSIX timestamp in seconds
364(last) access time fraction of second, which contains number of nanoseconds
404(last) modification time, which contains a POSIX timestamp in seconds
444(last) modification time fraction of second, which contains number of nanoseconds
484(last) inode change time, which contains a POSIX timestamp in seconds
524(last) inode change time fraction of second, which contains number of nanoseconds
568(Data) size
648Number of (data) blocks
724Extent size
764Number of data extents
802Number of (extended) attributes extents, which can contain 0 if an attributes fork of type XFS_DINODE_FMT_EXTENTS is empty
821(Extended) attributes fork descriptor offset, which contains an offset (value x 8) relative to the end of the inode
831(Extended) attributes fork type
844Unknown (DMAPI event mask)
882Unknown (DMAPI state)
902Inode flags
924Generation number
Non-inode core field
964Unknown (next unlinked inode), which contains -1 (0xffffffff) if not set

Inode version 2

The inode version 2 (xfs_dinode_core_t) is 100 bytes in size and consist of:

OffsetSizeValueDescription
02"IN"Signature
22File mode, which contains file type and permissions
412Format version
51(Data) fork type
62Unknown
84Owner (or user) identifier (UID)
124Group identifier (GID)
164Number of links
202Project identifier
2280Unknown (padding)
302Flush counter, which contains a value that is incremented on flush
324(last) access time, which contains a POSIX timestamp in seconds
364(last) access time fraction of second, which contains number of nanoseconds
404(last) modification time, which contains a POSIX timestamp in seconds
444(last) modification time fraction of second, which contains number of nanoseconds
484(last) inode change time, which contains a POSIX timestamp in seconds
524(last) inode change time fraction of second, which contains number of nanoseconds
568(Data) size
648Number of (data) blocks
724Extent size
764Number of data extents
802Number of (extended) attributes extents, which can contain 0 if an attributes fork of type XFS_DINODE_FMT_EXTENTS is empty
821(Extended) attributes fork descriptor offset, which contains an offset (value x 8) relative to the end of the inode
831(Extended) attributes fork type
844Unknown (DMAPI event mask)
882Unknown (DMAPI state)
902Inode flags
924Generation number
Non-inode core field
964Unknown (next unlinked inode), which contains -1 (0xffffffff) if not set

Inode version 3

The inode version 3 (xfs_dinode_core_t) is 176 bytes in size and consist of:

OffsetSizeValueDescription
02"IN"Signature
22File mode, which contains file type and permissions
413Format version
51(Data) fork type
62Unknown
84Owner (or user) identifier (UID)
124Group identifier (GID)
164Number of links
202Project identifier lower 16-bit
222Project identifier upper 16-bit
If incompatible feature flag XFS_SB_FEAT_INCOMPAT_NREXT64 not is set
2480Unknown (padding)
If incompatible feature flag XFS_SB_FEAT_INCOMPAT_NREXT64 is set
248Number of data extents (64-bit)
Common
If incompatible feature flag XFS_SB_FEAT_INCOMPAT_BIGTIME not is set
324(last) access time, which contains a POSIX timestamp in seconds
364(last) access time fraction of second, which contains number of nanoseconds
404(last) modification time, which contains a POSIX timestamp in seconds
444(last) modification time fraction of second, which contains number of nanoseconds
484(last) inode change time, which contains a POSIX timestamp in seconds
524(last) inode change time fraction of second, which contains number of nanoseconds
If incompatible feature flag XFS_SB_FEAT_INCOMPAT_BIGTIME is set
328(last) access time, which contains a bigtime timestamp
408(last) modification time, which contains a bigtime timestamp
488(last) inode change time, which contains a bigtime timestamp
Common
568(Data) size
648Number of (data) blocks
724Extent size
If incompatible feature flag XFS_SB_FEAT_INCOMPAT_NREXT64 not is set
764Number of data extents
802Number of (extended) attributes extents, which can contain 0 if an attributes fork of type XFS_DINODE_FMT_EXTENTS is empty
If incompatible feature flag XFS_SB_FEAT_INCOMPAT_NREXT64 is set
764Number of (extended) attributes extents (32-bit), which can contain 0 if an attributes fork of type XFS_DINODE_FMT_EXTENTS is empty
802Unknown (padding)
Common
821(Extended) attributes fork descriptor offset, which contains an offset (value x 8) relative to the end of the inode
831(Extended) attributes fork type
844Unknown (DMAPI event mask)
882Unknown (DMAPI state)
902Inode flags
924Generation number
Pre version 3 non-inode core field
964Unknown (next unlinked inode), which contains -1 (0xffffffff) if not set
Introduced in version 3
1004Checksum
1048Change count, which contains the number of changes made to the inode
1128Log sequence number
1208Extended inode flags
1284Copy-on-write (COW) extent size
13212Unknown (padding)
If incompatible feature flag XFS_SB_FEAT_INCOMPAT_BIGTIME not is set
1444Creation time, which contains a POSIX timestamp in seconds
1484Creation time fraction of second, which contains number of nanoseconds
If incompatible feature flag XFS_SB_FEAT_INCOMPAT_BIGTIME is set
1448Creation time, which contains a bigtime timestamp
Common
1528Inode number, which contains an absolute inode number
16016Inode type identifier, which contains an UUID that should correspond to sb_uuid or sb_meta_uuid

File mode

ValueIdentifierDescription
Access other, bitmask: 0x0007 (S_IRWXO)
0x0001S_IXOTHX-access for other
0x0002S_IWOTHW-access for other
0x0004S_IROTHR-access for other
Access group, bitmask: 0x0038 (S_IRWXG)
0x0008S_IXGRPX-access for group
0x0010S_IWGRPW-access for group
0x0020S_IRGRPR-access for group
Access owner (or user), bitmask: 0x01c0 (S_IRWXU)
0x0040S_IXUSRX-access for owner (or user)
0x0080S_IWUSRW-access for owner (or user)
0x0100S_IRUSRR-access for owner (or user)
Other
0x0200S_ISTXTSticky bit
0x0400S_ISGIDSet group identifer (GID) on execution
0x0800S_ISUIDSet owner (or user) identifer (UID) on execution
Type of file, bitmask: 0xf000 (S_IFMT)
0x1000S_IFIFONamed pipe (FIFO)
0x2000S_IFCHRCharacter device
0x4000S_IFDIRDirectory
0x6000S_IFBLKBlock device
0x8000S_IFREGRegular file
0xa000S_IFLNKSymbolic link
0xc000S_IFSOCKSocket

Fork type

ValueIdentifierDescription
0XFS_DINODE_FMT_DEVDevice identifier is stored inline (in the inode)
1XFS_DINODE_FMT_LOCALData is stored inline (in the inode)
2XFS_DINODE_FMT_EXTENTSData is referrenced by extents stored in an extents list
3XFS_DINODE_FMT_BTREEData is referrence by extents stored in an extents tree
4XFS_DINODE_FMT_UUIDUnknown (currently not used)
5XFS_DINODE_FMT_RMAPData is referrence by a reverse mapping

Inode flags

ValueIdentifierDescription
0x0001XFS_DIFLAG_REALTIMEThe data is located on the real-time device
0x0002XFS_DIFLAG_PREALLOCThe extents have been preallocated
0x0004XFS_DIFLAG_NEWRTBMUses the new real-time bitmap format
0x0008XFS_DIFLAG_IMMUTABLEImmutable (cannot be modified)
0x0010XFS_DIFLAG_APPENDAppend only
0x0020XFS_DIFLAG_SYNCUse synchronous write
0x0040XFS_DIFLAG_NOATIMEDo not update access time (atime)
0x0080XFS_DIFLAG_NODUMPDo not "dump", which indicates that xfsdump should ignore the file
0x0100XFS_DIFLAG_RTINHERITSub directories inherit XFS_DIFLAG_REALTIME
0x0200XFS_DIFLAG_PROJINHERITSub directories inherit the project identifier
0x0400XFS_DIFLAG_NOSYMLINKSNo symbolic links can be created for sub directories
0x0800XFS_DIFLAG_EXTSIZEHas extent size
0x1000XFS_DIFLAG_EXTSZINHERITSub directories inherit extent size
0x2000XFS_DIFLAG_NODEFRAGDo not defragment
0x4000XFS_DIFLAG_FILESTREAMUnknown (Use filestream allocator)

Extents list

The extents list consists of:

Packed extent

The packed extent (xfs_bmbt_rec_t) is 128 bits of size and consist of:

OffsetSizeValueDescription
021 bitsNumber of blocks
2.452 bitsPhysical block number, which contains a file system block number
9.154 bitsLogical block number
15.71 bitUninitialized (unwritten) extent

Note that uninitialized extents are treated as sparse extents when read.

Extents tree

Extents tree root node

The root node of the extents tree is stored in the inode and equivalent to an extents tree branch node.

The number of key-value pairs is calculated as following:

number_of_key_value_pairs = (node_data_size - 4) / 16

Where “node data size” is (attributes_fork_descriptor_offset * 8) if the value is not 0, or otherwise the remaining inode block size.

Extents tree sub node block

An extents tree sub nodes is stored in a B+ tree block.

The extents tree uses the B+ tree block header 64-bit.

Extents tree sub node block header

The sub node block header (xfs_bmbt_block_t) is equivalent to B+ tree block header.

Extents tree sub node block header signatures
SignatureDescription
"BMA3"Extents tree sub node block ((file system version 5)
"BMAP"Extents tree sub node block

Extents tree branch node

The extents tree branch node record consists of:

  • node header
  • array of extents tree branch node entry keys
  • array of extents tree branch node entry values

The number of key-value pairs is calculated as following:

number_of_key_value_pairs = node_records_data_size / 16
Extents tree branch node header

The branch node header (xfs_bmdr_block_t) is 4 byte of size and consist of:

OffsetSizeValueDescription
02Node level
22Number of used key-value pairs in the node
Extents tree branch node entry key

The branch node entry key (xfs_bmbt_key_t) is 8 byte of size and consist of:

OffsetSizeValueDescription
08Data offset
Extents tree branch node entry value

The branch node entry value (xfs_bmbt_ptr_t or xfs_bmdr_ptr_t) is 8 byte of size and consist of:

OffsetSizeValueDescription
08Block number of the extents tree sub node, which contains a file system block number

Extents tree leaf block node

The extents tree leaf block node consists of:

Directory entries

Directories entries are stored in the data fork of a directory inode. The directory entries can be stored in multiple ways:

  • as a short-form directory table
  • as an extent-based directory list if the XFS_SB_VERSION_DIRV2BIT flag in the superblock is set
  • as an extent-based directory tree if the XFS_SB_VERSION_DIRV2BIT flag in the superblock is not set

Short-form directory table

The short-form directory table (xfs_dir_sf_t or xfs_dir2_sf_t) is stored in the inode (as inline data), where fork type is XFS_DINODE_FMT_LOCAL. The short-form directory table consist of:

  • Short-form directory table header
  • Short-form directory table entries

The XFS_SB_VERSION_DIRV2BIT flag in the superblock indicates if version 2 is used.

Short-form directory table header version 1

The short-form directory table header version 1 (xfs_dir_sf_hdr_t) is 9 bytes in size and consists of:

OffsetSizeValueDescription
08Parent inode number, which contains an absolute inode number
81Number of entries

Short-form directory table header version 2

The short-form directory table header version 2 (xfs_dir2_sf_hdr_t) is 6 or 10 bytes in size and consists of:

OffsetSizeValueDescription
01Number of 32-bit entries
11Number of 64-bit entries
24 or 8Parent inode number, which contains an absolute inode number

Note that if the inode numbers are stored as 32-bit values then number of 32-bit entries is set and number of 64-bit entries must be 0. If the inode numbers are stored as 64-bit values then number of 64-bit entries is set and number of 32-bit entries must be 0.

Short-form directory table entry version 1

The short-form directory table entry version 1 (xfs_dir_sf_entry_t) is of variable size and consists of:

OffsetSizeValueDescription
08Inode number, which contains an absolute inode number
91Name size, which does not include the end-of-string character
10...Name

Short-form directory table entry version 2

The short-form directory table entry version 2 (xfs_dir2_sf_entry_t) is of variable size and consists of:

OffsetSizeValueDescription
01Name size, which does not include the end-of-string character
12Unknown (offset, tag)
3...Name
Only present if XFS_SB_VERSION2_FTYPE is set
...1File type
Common
...4 or 8Inode number, which contains an absolute inode number

Note that file type seems to be present on format version even if XFS_SB_VERSION2_FTYPE is not set.

Directory list

A directory list (xfs_dir2_block_t) consist of one or more elements (block) that consist of:

  • a directory list element header
  • array of used and unused directory entries
  • hash values of the entries
  • a directory list element footer

Directory list element header

Directory list element header version 2

The directory list element header version 2 (xfs_dir2_data_hdr_t) is 16 bytes in size and consist of:

OffsetSizeValueDescription
04"XD2B" or "XD2D"Signature
44 x 3Array of free regions in the block
Directory list element header version 3

The directory list element header version 3 (xfs_dir3_data_hdr_t) is 64 bytes in size and consist of:

OffsetSizeValueDescription
Block header (xfs_dir3_blk_hdr_t)
04"XDB3" or "XDD3"Signature
44Checksum
88Block number
168Log sequence number
2416Block type identifier, which contains an UUID that should correspond to sb_uuid or sb_meta_uuid
408Owner inode number, which contains the absolute inode number the block is part of
 
484 x 3Array of free regions in the block
604Unknown (padding)
Directory list element header version signatures
SignatureDescription
"XD2B"Version 2 directory entries B+ tree (single block)
"XD2D"Version 2 directory entries B+ tree (multi block)
"XD2F"Version 2 directory free space B+ tree
"XDB3"Version 3 directory entries B+ tree (single block)
"XDD3"Version 3 directory entries B+ tree (multi block)
"XDF3"Version 3 directory free space B+ tree
Block free region version 2

The block free region version 2 (xfs_dir2_data_free_t) is 4 bytes in size and consist of:

OffsetSizeValueDescription
02Free region offset, which is relative to the start of the directory block
22Free region size

Directory list element entries

Directory list element entry version 2

The directory list element entry version 2 (xfs_dir2_data_entry_t) is of variable size and consists of:

OffsetSizeValueDescription
08Inode number, which contains an absolute inode number
81Name size, which does not include the end-of-string character
9...Name
Only present if XFS_SB_VERSION2_FTYPE is set
...1Unknown (ftype)
Common
......Unknown (8-byte alignment padding?)
...2Unknown (offset, tag)
Unused directory list element entry version 2

The unused directory list element entry version 2 (xfs_dir2_data_unused_t) is of variable size and consists of:

OffsetSizeValueDescription
020xffffSignature (free tag)
22Entry size, which contains the size of the unused entry including the size of the signature and entry size
42Unknown (padding)
...2Unknown (offset, tag)

Directory list element hash value

The directory list element hash value (xfs_dir_leaf_entry_t or xfs_dir2_leaf_entry_t) is 8 bytes of size and consists of:

OffsetSizeValueDescription
04Hash value of the name of the directory entry
44Entry offset, which is relative to the start of the block

The directory list element footer version 2 (xfs_dir2_block_tail_t) is 8 bytes in size and consists of:

OffsetSizeValueDescription
04Number of used entries
44Number of unused entries

Directory tree

The first block in the extents is the root block.

Directory tree branch node

A directory tree branch node consist of:

Directory tree branch node header

A directory tree branch node header is 16 bytes in size and consist of:

OffsetSizeValueDescription
012File system block header version 1 with signature 0xfebe
Block tree branch header version 1
122Number of entries
142Node level
Directory tree branch node entry

A directory tree branch node entry is 8 bytes in size and consists of:

OffsetSizeValueDescription
04Name hash
44Sub block number, which contains a block number relative to the start of the directory tree

Directory leaf branch node

A directory leaf branch node consist of:

  • a directory leaf branch node header
  • array of directory tree leaf node entries

Directory tree leaf node

A directory tree leaf node (xfs_dir_leafblock_t) consist of:

  • a directory tree leaf node header
  • array of directory tree leaf node entries
  • array of directory tree leaf node values
  • a directory tree leaf node footer
Directory tree leaf node header version 1

A directory tree leaf node header version 1 (xfs_dir_leaf_hdr_t) is 16 bytes in size and consists of:

OffsetSizeValueDescription
012File system block header version 1
Block tree leaf header version 1
122Number of entries
142Used (block) data size, in number of bytes
162Used data offset
181Flag to indicate block compaction is needed
191Unknown (padding)
204 x 3Array of free regions in the block

Note that a directory tree leaf node header version 2 (xfs_dir2_leaf_hdr_t) is equivalent to version 1.

Directory tree leaf node entry version 1

The directory tree leaf node entry (xfs_dir_leaf_entry_t) is 8 bytes in size and consist of:

OffsetSizeValueDescription
04Name hash
42Value offset, which contains an offset relative to the start of the directory block
61Name size, which does not include the end-of-string character
71Unknown (padding)

Note that a directory tree leaf node entry version 2 (xfs_dir2_leaf_entry_t) is equivalent to version 1.

Directory tree leaf node value

The directory tree leaf node value (xfs_dir_leaf_name_t) is of variable size and consist of:

OffsetSizeValueDescription
08Inode number, which contains an absolute inode number
8...Name

A directory tree leaf node footer version 1 (xfs_dir_leaf_tail_t) is 4 bytes in size and consists of:

OffsetSizeValueDescription
04Unknown (bestcount)

Note that a directory tree leaf node footer version 2 (xfs_dir2_leaf_tail_t) is equivalent to version 1.

Device identifier

Character and block devices identifiers are stored as inline data with fork type is XFS_DINODE_FMT_DEV.

The device identifier (xfs_dev_t) is 4 bytes in size and consists of:

OffsetSizeValueDescription
0.018 bitsMinor device number
2.214 bitsMajor device number

File content

XFS supports multiple ways to store file content:

  • inline data (fork type is XFS_DINODE_FMT_LOCAL)
  • extents defined by either an extents list (fork type is XFS_DINODE_FMT_EXTENTS) or an extent B+ tree (fork type is XFS_DINODE_FMT_BTREE)

Inline data

The file content data is stored in the inode data fork.

Extents

The file content data is stored in the block defined by the extents.

If the logical block numbers of successive extents are non-contiguous this means the file content data has an implicit sparse extent (or hole).

TODO: determine if the hole can be at the start or end of the file content data.

File system block B+ tree

The file system block B+ tree is a structure used to store the directory and attributes trees.

File system block header

File system block header version 1

If the superblock format version <= 4 the file system block header version 1 is used. The file system block header version 1 (xfs_da_blkinfo_t) is 12 bytes in size and consist of:

OffsetSizeValueDescription
04(Logical) block number of the next B+ tree block at the same level
44(Logical) block number of the previous B+ tree block at the same level
82Signature
102Unknown (padding)

Note that a file system block header version 2 is equivalent to version 1.

File system block header version 3

If the superblock format version >= 5 the file system block header version 3 is used. The file system block header version 3 (xfs_da3_blkinfo_t) is 56 bytes in size and consist of:

OffsetSizeValueDescription
04(Logical) block number of the next B+ tree block at the same level
44(Logical) block number of the previous B+ tree block at the same level
82Signature
102Unknown (padding)
124Checksum
168Block number
248Log sequence number
3216Block type identifier, which contains an UUID that should correspond to sb_uuid or sb_meta_uuid
488Owner inode number, which contains the absolute inode number the block is part of

File system block header signatures

SignatureIdentifierDescription
0x3beeXFS_ATTR_LEAF_MAGICAttributes tree leaf node (file system version 5)
0x3ebeXFS_DA3_NODE_MAGICDirectory or attributes tree branch node (file system version 5)
0xd2f1XFS_DIR2_LEAF1_MAGIC
0xd2ffXFS_DIR2_LEAFN_MAGIC
0xfbeeXFS_ATTR_LEAF_MAGICAttributes tree leaf node
0xfebeXFS_DA_NODE_MAGICDirectory or attributes tree branch node
0xfeebXFS_DIR_LEAF_MAGICDirectory tree leaf node

A symbolic link can be maximum 1024 bytes (XFS_SYMLINK_MAXLEN).

Extended attributes

Extended attributes are stored in the attributes fork of an inode. The extended attributes can be stored in multiple ways:

The start of the attributes fork can be determined using the attributes fork descriptor offset.

Short-form attributes table

If the inode attributes fork type is XFS_DINODE_FMT_LOCAL the extended attributes are stored in a short-form attributes table (xfs_attr_shortform) inline in the attribtes fork. The short-form attributes table consist of:

  • a short-form attributes table header
  • one or more short-form attributes table entries

The short-form attributes table header

The short-form attributes table header (xfs_attr_sf_hdr) is 4 bytes in size and consists of:

OffsetSizeValueDescription
02Data size, which contains the size of the short form attributes table data
21Number of entries
31Unknown (padding?)

Note that the size of the short-form attribute header deviates from [SGI18] based on analysis of test data.

The short-form attribute entry

The short-form attributes table entry (xfs_attr_sf_entry) is of variable size and consists of:

OffsetSizeValueDescription
01Name size
11Value data size
21Attribute flags
3...Name string, which contains an ASCII string without end-of-string character
......Value data

Attributes tree

If the inode attributes fork type is XFS_DINODE_FMT_BTREE the extended attributes are stored in an attributes tree. The attributes fork contains an extents tree.

The first block in the extents is the B+ tree root block.

Attributes tree branch node

An attributes tree branch node consist of:

Attributes tree branch node header

Attributes tree branch node header version 2

If the superblock format version <= 4 the attributes tree branch node header version 2 is used. The attributes tree branch node header version 2 (xfs_da_blkinfo_t) is 16 bytes in size and consist of:

OffsetSizeValueDescription
012File system block header version 1 with signature 0xfebe
Block tree branch header version 1
122Number of entries
142Node level
Attributes tree branch node header version 3

If the superblock format version >= 5 the attributes tree branch node header version 3 is used. The attributes tree branch node header version 3 (xfs_da3_blkinfo_t) is 64 bytes in size and consist of:

OffsetSizeValueDescription
056File system block header version 3 with signature 0x3ebe
Block tree branch header version 3
562Number of entries
582Node level
604Unknown (padding)
Attributes tree branch node block entry
OffsetSizeValueDescription
04Name hash
44Sub block number, which is relative to the start of the attributes tree

Attributes tree leaf node

If the inode attributes fork type is XFS_DINODE_FMT_EXTENTS the extended attributes are stored as attributes tree. The attributes fork contains an extents list.

Attributes tree (xfs_attr_leafblock_t or xfs_attr3_leafblock_t) consist of:

If more than one block is needed to store the extended attributes an attributes tree is used.

Note that since extended attributes were introduced in superblock format version 2 there are no version 1 structures.

Attributes tree leaf node header

Attributes tree leaf node header version 2

If the superblock format version <= 4 the attributes tree leaf node header version 2 is used. The attributes tree leaf node header version 2 (xfs_attr_leaf_hdr_t) is 32 bytes in size and consist of:

OffsetSizeValueDescription
012File system block header version 1 with signature 0xfbee
Block tree leaf header version 1
122Number of entries
142Used (block) data size, in number of bytes
162Used data offset
181Flag to indicate block compaction is needed
191Unknown (padding)
204 x 3Array of free regions in the block
Attributes tree leaf node header version 3

If the superblock format version >= 5 the attributes tree leaf node header version 3 is used. The attributes tree leaf node header version 3 (xfs_attr3_leaf_hdr_t) is 80 bytes in size and consist of:

OffsetSizeValueDescription
056File system block header version 3 with signature 0x3bee
Block tree leaf header version 3
562Number of entries
582Used (block) data size, in number of bytes
602Used data offset
621Flag to indicate block compaction is needed
631Unknown (padding)
644 x 3Array of free regions in the block
764Unknown (padding)

Attributes tree leaf node entry

The attributes tree leaf node entry (xfs_attr_leaf_entry_t) is 8 bytes in size and consist of:

OffsetSizeValueDescription
04Name hash
42Value offset, which is relative to the start of the leaf node
61Attribute flags
71Unknown (padding)

Attributes tree leaf node value

If the attributes tree leaf node entry flag XFS_ATTR_LOCAL is set the attribute value is stored as local attribute value otherwise as remote attribute value. The value data of remote attribute value are stored in a remote attribute value data block.

Local attribute value

The local attributes value (xfs_attr_leaf_name_local_t) is of variable size and consist of:

OffsetSizeValueDescription
02Value data size
21Name size
3...Name string, which contains an ASCII string without end-of-string character
Remote attribute value

The remote attributes value (xfs_attr_leaf_name_remote_t) is of variable size and consist of:

OffsetSizeValueDescription
04Value data block number, which is relative to the start of the attributes tree
44Value data size
81Name size
9...Name string, which contains an ASCII string without end-of-string character

The attribute flags

The attribute flags indicate the prefix (or namespace) of the attribute name.

ValueIdentifierName prefixDescription
0x00"user."The attribute is part of the user namespace
0x01XFS_ATTR_LOCALThe attribute value is contained within the current block, which should be ignored in an attributes table
0x02XFS_ATTR_ROOT"trusted."The attribute is part of the trusted namespace
0x04XFS_ATTR_SECURE"secure."The attribute is part of the secure namespace
0x08XFS_ATTR_PARENTThe attribute contains a parent directory reference, where the attribute name contains the file tentry name and the attribute value data a reference to the parent directory
0x80XFS_ATTR_INCOMPLETEThe attribute is being modified

Remote attribute value data block

If the superblock format version <= 4 the attribute value data is stored directly in remote attribute value data blocks.

If the superblock format version >= 5 each individual remote attribute value data block will start with a remote attribute value data block header version 3 followed by attribute value data.

The attributes extents contain the physical location of the individual remote attribute value data blocks.

Remote attribute value data block header version 3

The remote attribute value data block header (xfs_attr3_rmt_hdr) is 52 bytes in size and consist of:

OffsetSizeValueDescription
04"XARM"Signature
44Value data offset
84Value data size
124Checksum of the remote attribute value data block
1616Block type identifier, which contains an UUID that should correspond to sb_uuid or sb_meta_uuid
328Owner inode number, which contains the absolute inode number the block is part of
408Block number
488Log sequence number
Parent directory attribute value data

The parent directory attribute value data (xfs_parent_rec) is 12 bytes in size and consist of:

OffsetSizeValueDescription
08Parent directory inode number
84Parent directory generation number

References

Hybrid volume and file system formats

A hybrid volume and file system format is a format that combines traits of both a volume and file system.

Formats

Apple File System (APFS)

The Apple File System (APFS) is a volume and file system mainly used on platforms such as Mac OS and iOS. APFS supersedes the Hierarchical File System (HFS) and was introduced in macOS High Sierra (10.13) and iOS 10.3.

Overview

APFS consists of:

  • A container
    • Zero or more logical volumes that contain a file system

Characteristics

CharacteristicsDescription
Byte orderlittle-endian
Date and time valuesnumber of nanoseconds since January 1, 1970 00:00:00 UTC (POSIX epoch), disregarding leap seconds
Character stringsUnicode strings are stored in UTF-8

Note that date and values are signed integers to represent dates before January 1, 1970. Other sources are known to claim the date and time values are unsigned including Apple’s own Apple File System Reference documentation.

Note that (some) sources claim that APFS uses Unicode version 9.0. Support for codepoints of more recent Unicode versions has been observed.

Terminology

TermDescription
Physical volumeA volume in which the APFS container is stored
Logical volumeA volume in which an APFS file system is stored

Keys

To encrypt storage media APFS uses different kind of keys.

Volume master key

The Volume Master Key (VMK) is used to encrypt the data of a specific volume.

Volume key

For every volume on an Mac OS system with APFS, APFS provides for a volume password to unlock the encrypted data. The volume password is used to determine a volume key.

Encryption methods

APFS uses the AES-XTS encryption method to encrypt the key bag, file system metadata and content data.

AES-XTS

The AES-XTS encryption method uses:

  • a primary key (key 1) to encrypt/decrypt the data (the whitened plaintext/ciphertext).
  • a secondary key (key 2) to encrypt/ decrypt the tweak value, also referred to as the tweak key. The encrypted tweak value is used to whiten the plaintext/ciphertext.
  • a tweak value

The cipher block size is 128 bytes.

The container key bag is encrypted using the “container identifier” of the container as both the primary and tweak key. The sector number, relative to the start of the container, is used as the tweak value.

Note that when a T2 chip is present, it is currently assumed that the T2 is used to encrypted the container key bag instead of the “container identifier”.

The unit size is the sector size, which is assumed to be 512 bytes also for 4 KiB sector media.

The volume key bag is encrypted using the “volume identifier” of the corresponding key bag entry, as both the primary and tweak key. The sector number, relative to the start of the container, is used as the tweak value.

The file system B-tree is encrypted using the volume master key and the sector number, relative to the start of the container, is used as the tweak value.

Objects

APFS uses the “object” data type to distinguish between different data types.

Object header

The object header (obj_phys_t) is 32 bytes in size and consists of:

OffsetSizeValueDescription
08Object checksum (o_cksum), which contains 0 if not set
88Object identifier (o_oid)
168Object transaction identifier (o_xid), which contains the identifier of the most recent transaction that this object was modified in
244Object type (o_type)
284Object subtype (o_subtype)

Object checksum

The checksum algorithm:

Fletcher-64 checksum of the data without the object checksum value and an initial value of 0
checksum_lower_32bit = 0xffffffff - ((fletcher_lower_32bit + fletcher_upper_32bit) mod 0xffffffff)
checksum_upper_32bit = 0xffffffff - ((fletcher_lower_32bit + checksum_lower_32bit) mod 0xffffffff)
checksum = (checksum_upper_32bit << 32) | checksum_lower_32bit

Object identifiers

  • For a physical object, its identifier is the logical block address on disk where the object is stored.
  • For an ephemeral object, its identifier is a number.
  • For a virtual object, its identifier is a number.
ValueIdentifierDescription
0OID_INVALIDInvalid
1OID_NX_SUPERBLOCKContainer superblock
1024OID_RESERVED_COUNTNumber of reserved object identifiers

Object types

The object type (o_type) value consists of a type and flags.

ValueIdentifierDescription
0x00000000OBJECT_TYPE_INVALIDInvalid. For a subtype this value represents not set or not specified
0x00000001OBJECT_TYPE_NX_SUPERBLOCKContainer superblock
0x00000002OBJECT_TYPE_BTREEB-tree (root)
0x00000003OBJECT_TYPE_BTREE_NODEB-tree node
0x00000004Unknown (MTree?)
0x00000005OBJECT_TYPE_SPACEMANSpace manager header
0x00000006OBJECT_TYPE_SPACEMAN_CABSpace manager chunk information address block
0x00000007OBJECT_TYPE_SPACEMAN_CIBSpace manager chunk information block
0x00000008OBJECT_TYPE_SPACEMAN_BITMAPSpace manager bitmap
0x00000009OBJECT_TYPE_SPACEMAN_FREE_QUEUESpace manager free queue
0x0000000aOBJECT_TYPE_EXTENT_LIST_TREEExtent list tree
0x0000000bOBJECT_TYPE_OMAPObject map
0x0000000cOBJECT_TYPE_CHECKPOINT_MAPCheckpoint map
0x0000000dOBJECT_TYPE_FSVolume (or file system) superblock
0x0000000eOBJECT_TYPE_FSFile system tree
0x0000000fOBJECT_TYPE_BLOCKREFTREEExtent-reference tree
0x00000010OBJECT_TYPE_SNAPMETATREESnapshot metadata tree
0x00000011OBJECT_TYPE_NX_REAPERReaper
0x00000012OBJECT_TYPE_NX_REAP_LISTReaper list
0x00000013OBJECT_TYPE_OMAP_SNAPSHOTObject map snapshot
0x00000014OBJECT_TYPE_EFI_JUMPSTARTEFI jumpstart
0x00000015OBJECT_TYPE_FUSION_MIDDLE_TREEFusion middle tree
0x00000016OBJECT_TYPE_NX_FUSION_WBCFusion write-back cache
0x00000017OBJECT_TYPE_NX_FUSION_WBC_LISTFusion write-back cache list
0x00000018OBJECT_TYPE_ER_STATEUnknown (ER state?)
0x00000019OBJECT_TYPE_GBITMAPUnknown (G Bitmap?)
0x0000001aOBJECT_TYPE_GBITMAP_TREEUnknown (G Bitmap tree?)
0x0000001bOBJECT_TYPE_GBITMAP_BLOCKUnknown (G Bitmap block?)
0x000000ffOBJECT_TYPE_TESTUnknown (test?)
0x0000ffffOBJECT_TYPE_MASKObject type bitmask
Flags used in combination with some of the object types
0x08000000OBJ_NONPERSISTENTUnknown (Non-persistent?)
0x10000000OBJ_ENCRYPTEDIs encrypted
0x20000000OBJ_NOHEADERHas no object (obj_phys_t) header
0x00000000OBJ_VIRTUALIs virtual object
0x40000000OBJ_PHYSICALIs physical object
0x80000000OBJ_EPHEMERALIs ephemeral object
0xffff0000OBJECT_TYPE_FLAGS_MASKObject type flags bitmask
0xc0000000OBJ_STORAGETYPE_MASKObject storage type bitmask
0xf8000000OBJECT_TYPE_FLAGS_DEFINED_MASKUnknown
Object types without flags
0x6b657973 ("syek")Container key bag
0x72656373 ("scer")Volume key bag

Object subtypes

The object subtype is used by specific object types such as:

  • B-tree root
  • B-tree node

The object subtypes are the same as the Object types.

B-tree

A B-tree consists of:

  • B-tree root object
    • Zero or more B-tree node objects

B-tree root or node object

A B-tree root or node (or object) consists of:

  • Object header
  • B-tree node header
  • B-tree entries (table of contents)
  • keys data, where the first key is stored after the entries in increasing order
  • Optional key free list
  • unused data
  • Optional value free list
  • values data, where the first value is stored before the footer in descending order
  • Optional B-tree footer, which is only stored in the root node

Note that the Apple File System Reference documentation combines the B-tree object and B-tree node header into a single structure referred to as btree_node_phys_t.

B-tree root object header

OffsetSizeValueDescription
Object header (btn_o)
08Object checksum, which contains 0 if not set
88Object identifier
168Object transaction identifier (xid)
2440x00000002 or 0x40000002Object type
284Object subtype

Note that object type can be 0x00000000 if the B-tree is empty.

B-tree node object header

OffsetSizeValueDescription
Object header (btn_o)
08Object checksum, which contains 0 if not set
88Object identifier
168Object transaction identifier (xid)
2440x00000003 or 0x40000003Object type
284Object subtype

B-tree node header

The B-tree node header is stored after the B-tree root or node object.

The B-tree node header is 24 bytes in size and consists of:

OffsetSizeValueDescription
02Flags (btn_flags)
22Level (btn_level)
44Number of keys in the node (btn_nkeys)
Table space (btn_table_space)
82Entries data offset, which contains an offset relative to the end of the B-tree node header or -1 (0xffff) if not set (invalid)
102Entries data size, in number of bytes
Free space (btn_free_space)
122Unused data offset, which contains an offset relative to the end of the entries data or -1 (0xffff) if not set (invalid)
142Unused data size, in number of bytes
Key free list (btn_key_free_list)
162Unused key list offset, which contains an offset relative to unknown or -1 (0xffff) if not set (invalid)
182Unused key list size, in number of bytes
Value free list (btn_val_free_list)
202Unused value list offset, which contains an offset relative to unknown or -1 (0xffff) if not set (invalid)
222Unused value list size, in number of bytes

B-tree node flags

ValueIdentifierDescription
0x0001BTNODE_ROOTIs root
0x0002BTNODE_LEAFIs leaf
0x0004BTNODE_FIXED_KV_SIZEHas a fixed-size entry (key and value)
0x0008BTNODE_HASHEDB-tree branch nodes contain a hash of their sub nodes
0x0010BTNODE_NOHEADERThe B-tree node are stored without object header, where the object header is filled with 0-byte values
0x8000BTNODE_CHECK_KOFF_INVALIn transient state, which is used for in-memory purposes only

B-tree entries

The B-tree entries are stored after the B-tree node header.

Fixed-size B-tree entry

The fixed-size B-tree entry is 4 bytes in size and consists of:

OffsetSizeValueDescription
02Key data offset (key_offs), which contains an offset relative to the end of the entries data
22Value data offset (value_offs), which contains a reversed offset relative to the start of the B-tree footer

Variable-size B-tree entry

The variable-size B-tree entry is 8 bytes in size and consists of:

OffsetSizeValueDescription
02Key data offset (key_offs), which contains an offset relative to the end of the entries data
22Key data size (key_len), in number of bytes
42Value data offset (value_offs), which contains a reversed offset relative to the start of the B-tree footer
62Value data size (value_len), in number of bytes

The B-tree footer is stored at the end of the block that contains the B-tree root object.

The B-tree footer (btree_info_t) is 40 bytes in size and consists of:

OffsetSizeValueDescription
Static information (btree_info_fixed_t)
04Flags (bt_flags)
44Node size (bt_node_size), in number of bytes
84Key size (bt_key_size), in number of bytes and is set to 0 if key has a variable size
124Value size (bt_val_size), in number of bytes and is set to 0 if value has a variable size
 
164Maximum key size (bt_longest_key), in number of bytes
204Maximum value size (bt_longest_val), in number of bytes
248Total number of keys (bt_key_count)
328Total number of nodes (bt_node_count)

B-tree flags

ValueIdentifierDescription
0x00000001BTREE_UINT64_KEYSUnknown
0x00000002BTREE_SEQUENTIAL_INSERTUnknown
0x00000004BTREE_ALLOW_GHOSTSUnknown
0x00000008BTREE_EPHEMERALUnknown
0x00000010BTREE_PHYSICALUnknown
0x00000020BTREE_NONPERSISTENTUnknown
0x00000040BTREE_KV_NONALIGNEDUnknown
0x00000080BTREE_HASHEDB-tree branch nodes contain a hash of their sub nodes
0x00000100BTREE_NOHEADERThe B-tree node are stored without object header, where the object header is filled with 0-byte values

The container

APFS stores volumes inside a container. The maximum number of volumes is dependent on the size of the container.

Container sizeMaximum number of volumes
1 GiB2
2 GiB4
5 GiB10
10 GiB20
20 GiB40
100 GiB100
12 TiB100
1.2 PiB100
7.5 EiB100

The container consists of:

  • current container superblock
  • stored in the container checkpoint descriptor area:
    • current checkpoint map
    • previous checkpoint map(s)
    • previous container superblock(s)
  • stored in the container:
    • space manager
    • container object map
    • reaper
    • crypto key
    • zero or more volumes
  • Unknown: backup of current container superblock?

Container superblock

The container superblock (nx_superblock_t) is 4096 bytes in size and consists of:

OffsetSizeValueDescription
Object header
08Object checksum, which contains 0 if not set
88Object identifier
168Object transaction identifier (xid)
2440x80000001Object type
2840x00000000Object subtype
Object values
324"NXSB"Signature (nx_magix)
364Block size (nx_block_size), in number of bytes
408Number of blocks (nx_block_count)
488Container feature flags (nx_features)
568Read-only compatible feature flags (nx_readonly_compatible_features)
648Incompatible feature flags (nx_incompatible_features)
7216Container identifier (nx_uuid), which contains a big-endian UUID
888Next (available) object identifier (nx_next_oid)
968Next (available) transaction identifier (nx_next_xid)
1044Checkpoint descriptor area number of blocks (nx_xp_desc_blocks), which contains the size of the checkpoint descriptor area and the MSB is a flag
1084Checkpoint data area number of blocks (nx_xp_data_blocks), which contains the size of the checkpoint data area and the MSB is a flag
1128Checkpoint descriptor area block number (nx_xp_desc_base), where the block number is relative to the start of the container of the checkpoint descriptor area if the MSB of nx_xp_desc_blocks is not set, otherwise the value contains the physical object identifier of a checkpoint descriptor area B-tree
1208Checkpoint data area block number (nx_xp_data_base), where the block number is relative to the start of the container of the checkpoint data area if the MSB of nx_xp_data_blocks is not set
1284Next available index in the checkpoint descriptor area (nx_xp_desc_next)
1324Next available index in the checkpoint data area (nx_xp_data_next)
1364Index of the checkpoint in the checkpoint descriptor area (nx_xp_desc_index)
1404Size of the checkpoint in the checkpoint descriptor area, in number of blocks (nx_xp_desc_len)
1444Index of the checkpoint in the checkpoint data area (nx_xp_data_index)
1484Size of the checkpoint in the checkpoint data area, in number of blocks (nx_xp_data_len)
1528Space manager object identifier (nx_spaceman_oid), where the object identifier can be resolved in the checkpoint map
1608Object map block number (nx_omap_oid), where the block number is relative to the start of the container of the object map
1688Reaper object identifier (nx_reaper_oid), where the object identifier can be resolved in the checkpoint map
1764Unknown (reserved for testing) (nx_test_type)
1804Maximum number of volumes (nx_max_file_systems) supported by the container
184100 x 8 = 800Array of volume object identifiers (nx_fs_oid), which can be resolved to a "physical" location using the object map
98432 x 8 = 256Container counters (nx_counters)
Reserved (or blocked out) data area (nx_blocked_out_prange)
12408Reserved data area block number (nx_blocked_out_base), which contains a block number relative to the start of the container
12488Reserved data area number of blocks (nx_blocked_out_blocks)
 
12568Eviction tree (physical) object identifier (nx_evict_mapping_tree_oid)
12648Container flags (nx_flags)
12728EFI jumpstart (physical) object identifier (nx_efi_jumpstart), which contains a block number relative to the start of the container
128016Fusion set identifier (nx_fusion_uuid), which contains a big-endian UUID
Container key bag area (nx_keylocker)
12968Container key bag block number (nx_keybag_base), which contains a block number relative to the start of the container
13048Container key bag number of blocks (nx_keybag_blocks)
 
13124 x 8 = 32Ephemeral information (nx_ephemeral_info)
13448Unknown (reserved for testing) (nx_test_oid)
13528Fusion middle tree block number (nx_fusion_mt_oid), which contains a block number relative to the start of the container
13608Fusion write-back cache state object identifier (nx_fusion_wbc_oid), where the object identifier can be resolved in the checkpoint map
Fusion write-back cache area (nx_fusion_wbc)
13688Fusion write-back cache area block number (nx_fusion_wbc_base), which contains a block number relative to the start of the container
13768Fusion write-back cache area number of blocks (nx_fusion_wbc_blocks)
 
13848Newest version of software that mounted the container (nx_newest_mounted_version)
Media key area (nx_mkb_locker)
13928Media key area block number, which contains a block number relative to the start of the container
14008Media key area number of blocks
 
14082688Unknown (empty values)

Note that NXSB presumably is an abbreviation of NX superblock. At this point it is unclear what NX stands for.

Container flags

ValueIdentifierDescription
0x00000001NX_RESERVED_1Unknown (reserved)
0x00000002NX_RESERVED_2Unknown (reserved)
0x00000004NX_CRYPTO_SWThe encryption is performed in software

Container feature flags

ValueIdentifierDescription
0x0000000000000001NX_FEATURE_DEFRAGSupports defragmentation
0x0000000000000002NX_FEATURE_LCFDUses low-capacity Fusion Drive mode

Container read-only compatible feature flags

Current no read-only compatible feature flags are defined.

Container incompatible feature flags

ValueIdentifierDescription
0x0000000000000001NX_INCOMPAT_VERSION1Pre-release version 1 of APFS
0x0000000000000002NX_INCOMPAT_VERSION2Release version 2 of APFS
0x0000000000000100NX_INCOMPAT_FUSIONSupports Fusion Drives

Note that according to the Apple File System Reference documentation the pre-release version 1 and release version 2 are incompatble.

Container counters

ValueIdentifierDescription
0NX_CNTR_OBJ_CKSUM_SETNumber of times a checksum has been calculated when wrting to disk
1NX_CNTR_OBJ_CKSUM_FAILNumber of checksum errors when reading from disk

Note that the other 30 counters are presumed to be unused at this point.

Checkpoint map

The checkpoint map contains a mapping between container metadata object identifiers and their location in the container.

Note that multiple successive checkpoint map objects can be used to store a check point map.

Checkpoint map object

The checkpoint map object (checkpoint_map_phys_t) is 4096 bytes in size and consists of:

OffsetSizeValueDescription
Object header
08Object checksum, which contains 0 if not set
88Object identifier
168Object transaction identifier (xid)
2440x4000000cObject type
2840x00000000Object subtype
Object values
324Flags (cpm_flags)
364Number of entries (cpm_count)
40101 x 40 = 4040Array of checkpoint map entries (cpm_map)
408016Unknown (empty values)

Checkpoint flags

ValueIdentifierDescription
0x00000001CHECKPOINT_MAP_LASTLast checkpoint map object

Checkpoint map entry

The checkpoint map entry (checkpoint_mapping_t) is 40 bytes in size and consists of:

OffsetSizeValueDescription
04Object type (cpm_type)
44Object subtype (cpm_subtype)
84Size (cpm_size), in number of bytes
124Unknown (padding) (cpm_pad)
168File system object identifier (cpm_fs_oid)
248(Container) object identifier (cpm_oid)
328Physical address (cpm_paddr), which contains a block number relative to the start of the container

Object map

The object map contains a mapping between object identifiers and their “physical” location.

The object map consists of:

  • object map (object)
  • object map B-tree

Object map object

The object map object (omap_phys_t) is 4096 bytes in size and consists of:

OffsetSizeValueDescription
Object header
08Object checksum, which contains 0 if not set
88Object identifier
168Object transaction identifier (xid)
2440x4000000bObject type
2840x00000000Object subtype
Object values
324Flags (om_flags)
364Number of snapshots (om_snap_count)
404Object map B-tree type (om_tree_type)
444Object map snapshots B-tree type (om_snapshot_tree_type)
488Object map B-tree (root node) block number (om_tree_oid), which contains a block number relative to the start of the container
568Object map snapshots B-tree (root node) block number (om_snapshot_tree_oid), which contains a block number relative to the start of the container
648Most recent snapshot object identifier (om_most_recent_snap)
728Unknown transaction identifier (om_pending_revert_min)
808Unknown transaction identifier (om_pending_revert_max)
884008Unknown (empty values)

Object map flags

ValueIdentifierDescription
0x00000001OMAP_MANUALLY_MANAGEDNo snapshot support
0x00000002OMAP_ENCRYPTINGEncryption in progress
0x00000004OMAP_DECRYPTINGDecryption in progress
0x00000008OMAP_KEYROLLINGRe-encryption with new key in progress
0x00000010OMAP_CRYPTO_GENERATIONEncryption configuration has changed

Object map B-tree

The object map values are stored in a B-tree.

Object map B-tree key

The object map B-tree key (omap_key_t) is 16 bytes in size and consists of:

OffsetSizeValueDescription
08Key object identifier (ok_oid)
88Key object transaction identifier (ok_xid)

Object map B-tree branch node value

An object map B-tree node contains branch node values if BTNODE_LEAF is not set. The corresponding object map B-tree key represents the first key in the branch.

An object map B-tree branch node value is 8 bytes in size and consists of:

OffsetSizeValueDescription
08Sub node block number, which contains a block number relative to the start of the container

Object map value

An object map B-tree node contains object map values if BTNODE_LEAF is set.

The object map value (omap_val_t) is 16 bytes in size and consists of:

OffsetSizeValueDescription
04Value object flags (ov_flags)
44Value object size (ov_size), in number of bytes
88Value object physical address (ov_paddr), which contains a block number relative to the start of the container
Object map value flags
ValueIdentifierDescription
0x00000001OMAP_VAL_DELETEDUnknown
0x00000002OMAP_VAL_SAVEDUnknown
0x00000004OMAP_VAL_ENCRYPTEDUnknown
0x00000008OMAP_VAL_NOHEADERUnknown
0x00000010OMAP_VAL_CRYPTO_GENERATIONUnknown

Notes

TODO: document omap_snapshot_t TODO: document Object Map Reaper Phases

Space manager

The space manager (spaceman_phys_t) is of variable size and consists of:

OffsetSizeValueDescription
Object header (sm_o)
08Object checksum, which contains 0 if not set
88Object identifier
168Object transaction identifier (xid)
2440x80000005Object type
2840x00000000Object subtype
Object values
324Block size (sm_block_size), in number of bytes
364Number of blocks per chunk (sm_blocks_per_chunk)
404Number of chunks per chunk information block (CIB) (sm_chunks_per_cib)
444Number of chunk information blocks (CIBs) per chunk information address block (CAB) (sm_cibs_per_cab)
Space manager devices (sm_dev)
4848Main device (SD_MAIN), which contains a Space manager device
9648Tier2 device (SD_TIER2), which contains a Space manager device
 
1444Flags
1484Unknown (sm_ip_bm_tx_multiplier)
1528Unknown (sm_ip_block_count)
1604Unknown (sm_ip_bm_size_in_blocks)
1644Unknown (sm_ip_bm_block_count)
1688Unknown (sm_ip_bm_base)
1768Unknown (sm_ip_base)
1848Unknown (sm_fs_reserve_block_count)
1928Unknown (sm_fs_reserve_alloc_count)
Space manager free queues (sm_fq)
20040Unknown space free queue (SFQ_IP)
24040Main space free queue (SFQ_MAIN)
28040Tier2 space free queue (SFQ_TIER2)
 
3202Unknown (sm_ip_bm_free_head)
3222Unknown (sm_ip_bm_free_tail)
3244Unknown (sm_ip_bm_xid_offset), which contains an offset in bytes relative to the start of the space manager
3284Unknown (sm_ip_bitmap_offset), which contains an offset in bytes relative to the start of the space manager
3324Unknown (sm_ip_bm_free_next_offset), which contains an offset in bytes relative to the start of the space manager
33641Unknown (sm_version)
3404Unknown (sm_struct_size)
Space manager data zone (sm_datazone)
3448 x 72Main allocation zones
9208 x 72Tier2 allocation zones
 
1492...Unknown (data)

Space manager flags

ValueIdentifierDescription
0x00000001SM_FLAG_VERSIONEDUnknown

Space manager device

A space manager device (spaceman_device_t) is 48 bytes in size and consists of:

OffsetSizeValueDescription
08Number of blocks (sm_block_count)
88Number of chunks (sm_chunk_count)
164Number of chunk information blocks (CIBs) (sm_cib_count)
204Number of chunk information address blocks (CABs) (sm_cab_count)
248Number of unused blocks (sm_free_count)
324Unknown (sm_addr_offset), which contains an offset in bytes relative to the start of the space manager
364Unknown (sm_reserved)
408Unknown (sm_reserved2)

Space manager free queue

A space manager free queue (spaceman_free_queue_t) is 40 bytes in size and consists of:

OffsetSizeValueDescription
08Unknown (sfq_count)
88Space manager free queue tree object identifier (sfq_tree_oid)
168Space manager free queue oldest transaction identifier (sfq_oldest_xid)
242Unknown (sfq_tree_node_limit)
262Unknown (sfq_pad16)
284Unknown (sfq_pad32)
328Unknown (sfq_reserved)

Space manager allocation zone

A space manager allocation zone (spaceman_allocation_zone_info_phys_t) is 72 bytes in size and consists of:

OffsetSizeValueDescription
08Current allocation zone boundaries (saz_current_boundaries)
87 x 8Previous allocation zone boundaries (saz_previous_boundaries)
642Unknown (saz_zone_id)
662Unknown (saz_previous_boundary_index)
684Unknown (saz_reserved)

Space manager zone_boundaries

A space manager zone boundaries (spaceman_allocation_zone_boundaries_t) is 8 bytes in size and consists of:

OffsetSizeValueDescription
08Unknown (saz_zone_start)
88Unknown (saz_zone_end)

Notes

sm_addr_offset points to block number which points to a OBJECT_TYPE_SPACEMAN_CIB block. Probably an OBJECT_TYPE_SPACEMAN_CAB block when necessary.

Chunk information address block

The chunk information address block (cib_addr_block_t) is of variable size and consists of:

OffsetSizeValueDescription
Object header (cab_o)
08Object checksum, which contains 0 if not set
88Object identifier
168Object transaction identifier (xid)
2440x40000006Object type
2840x00000000Object subtype
Object values
324Unknown (cab_index)
364Number of chunk information blocks (CIBs) (cab_cib_count)
Chunk information block physical addresses (cab_cib_addr)
408 x Number of CIBsPhysical address of chunk information blocks (CIB)

Chunk information block

The chunk information block (chunk_info_block_t) is of variable size and consists of:

OffsetSizeValueDescription
Object header (cib_o)
08Object checksum, which contains 0 if not set
88Object identifier
168Object transaction identifier (xid)
2440x40000007Object type
2840x00000000Object subtype
Object values
324Unknown (cib_index)
364Number of chunk information entries (cib_chunk_info_count)
Chunk information entries (cib_chunk_info)
408 x Number of entriesArray of chunk information entries

Chunk information entry

The chunk information entry (chunk_info_t) is 32 bytes in size and consists of:

OffsetSizeValueDescription
08Unknown (ci_xid)
88Unknown (ci_addr)
164Unknown (ci_block_count)
204Unknown (ci_free_count)
248Unknown (ci_bitmap_addr)

Reaper

The reaper is of unknown size and consists of:

OffsetSizeValueDescription
Object header
08Object checksum, which contains 0 if not set
88Object identifier
168Object transaction identifier (xid)
2440x80000011Object type
2840x00000000Object subtype
Object values
328Unknown
8Unknown
8Unknown
8Unknown
4Unknown
4Unknown
4Unknown
4Unknown
8Unknown
8Unknown
8Unknown
4Unknown
4Unknown

Reaper list

The reaper list entry is of unknown size and consists of:

OffsetSizeValueDescription
Object header
08Object checksum, which contains 0 if not set
88Object identifier
168Object transaction identifier (xid)
2440x80000012Object type
2840x00000000Object subtype
Object values
324Unknown
364Unknown
404Unknown
444Unknown (max_record_count)
484Unknown (record_count)
524Unknown (first_index)
564Unknown (last_index)
604Unknown (free_index)
64100 x ...Array of reaper list entries (nrle)

Reaper list entry

The reaper list entry is 40 bytes in size and consists of:

OffsetSizeValueDescription
04Forward link (fwlink)
44Unknown
84Type (type)
124Block size (blksize), in number of bytes
168Object identifier (oid)
248Physical address (paddr), which contains a block number relative to the start of the container
328Object transaction identifier (xid)

Key bag

The key bag consists of:

  • Container or volume key bag object
  • Key bag header
  • Key bag entries

Container key bag object

The container key bag object contains key data of the container.

The container key bag object is 32 bytes in size and consists of:

OffsetSizeValueDescription
Object header
08Object checksum, which contains 0 if not set
88Object identifier
168Object transaction identifier (xid)
2440x6b657973 ("syek")Object type
2840x00000000Object subtype

Volume key bag object

The volume key bag object contains key data of a specific volume.

The volume key bag object is 32 bytes in size and consists of:

OffsetSizeValueDescription
Object header
08Object checksum, which contains 0 if not set
88Object identifier
168Object transaction identifier (xid)
2440x72656373 ("scer")Object type
2840x00000000Object subtype

Key bag header

The key bag header (kb_locker_t) is 16 bytes in size and consists of:

OffsetSizeValueDescription
022Format version (kl_version)
22Number of entries (kl_nkeys)
44Key bag data size (kl_nbytes), in number of bytes and includes the size of key bag header
88Unknown (padding)

Key bag entries

A key bag entry consists of:

  • a key bag entry header
  • a key bag entry data
  • alignment padding

The key bag entry header specifies the type of the key bag entry data.

The key bag entries are 16-byte aligned.

Key bag entry header

The key bag entry header (keybag_entry_t) is 24 bytes in size and consists of:

OffsetSizeValueDescription
016Volume identifer (ke_uuid), which contains a big-endian UUID
162Entry type (ke_tag)
182Entry data size (ke_keylen), in number of bytes
204Unknown (padding)

Key bag entry types

Container key bag entry types
ValueIdentifierDescription
0x00KB_TAG_UNKNOWNUnknown
0x01KB_TAG_WRAPPING_KEY (or KB_TAG_RESERVED_1)Wrapping key
0x02KB_TAG_VOLUME_KEYVolume master key, which contains a Key encrypted key (KEK) packed object
0x03KB_TAG_VOLUME_UNLOCK_RECORDSVolume key bag extent
0x04KB_TAG_VOLUME_PASSPHRASE_HINTPassphrase hint
0x05KB_TAG_WRAPPING_M_KEYKey used to wrap a media key
0x06KB_TAG_VOLUME_M_KEYKey used to wrap a media key
0xf8KB_TAG_USER_PAYLOAD (or KB_TAG_RESERVED_F8)Unknown (user payload)

The volume master key is encryped with a volume key.

Volume key bag entry types
ValueIdentifierDescription
3Volume key, which contains a Key encrypted key (KEK) packed object
4Password hint, which contains a string without end-of-string character

The volume key is encryped with an user key.

Key bag packed object

The packed object consist of an object packed value that embeds attribute packed values.

Key bag packed value

The key bag packed value is of variable size and consists of:

OffsetSizeValueDescription
01Value tag (or value type), where the most-significant bit represents a flag
11Value data size, in number of bytes, where the most-significant bit represents a flag
......Value data

A packed value with a tag and size of 0 signifies the end of the packed values.

Note that the meaning of the value tags differ per packed object type.

Key encrypted key (KEK) packed object

The packed object value tag of a key encrypted key is 0x30 and contains the following attribute value tags:

ValueIdentifierDescription
0x80Unknown
0x81HMAC
0x82Unknown (salt?)
0xa3Wrapped Key Encryption Key (KEK) packed object
Wrapped Key Encryption Key (KEK) packed object

The packed object value tag of a wrapped kek encrypted key is 0xa3 and contains the following attribute value tags:

ValueIdentifierDescription
0x80Unknown
0x81Volume identifer, which contains a big-endian UUID
0x82Wrapped Key Encryption Key (KEK) metadata
0x83Wrapped Key Encryption Key (KEK) data
0x84Number of iterations for the PBKDF2 algorithm
0x85Salt for the PBKDF2 algorithm

Wrapped Key Encryption Key (KEK) metadata

The Wrapped Key Encryption Key (KEK) metadata is 8 bytes in size and consists of:

OffsetSizeValueDescription
04Encryption method
42Unknown
61Unknown
71Unknown
Encryption methods
ValueIdentifierDescription
0Unknown (AES-256)
2Unknown (AES-128 FVDE (CoreStorage FileVault) compatible)
16Unknown (AES-256), which has been observed in combination with recovery password protected volume key

Key bag data extent

The key bag data extent is 16 bytes in size and consists of:

OffsetSizeValueDescription
08Key bag block number
88Key bag number of blocks

Volume

The volume consists of:

  • volume superblock
  • volume object map

Note that an APFS volume has a corresponding “synthesized” device file though this cannot be directly read.

Volume superblock

The volume superblock (apfs_superblock_t) is 4096 bytes in size and consists of:

OffsetSizeValueDescription
Object header
08Object checksum, which contains 0 if not set
88Object identifier
168Object transaction identifier (xid)
2440x0000000d or 0x4000000d (for snapshots)Object type
2840x00000000Object subtype
Object values
324"APSB"Signature (apfs_magic)
364File system index (apfs_fs_index)
408Volume feature flags (apfs_features)
488Read-only compatible feature flags (apfs_readonly_compatible_features)
568Incompatible feature flags (apfs_incompatible_features)
648(Last) unmount date and time (apfs_unmount_time), which consists of a signed integer that contains the number of nanoseconds since January 1, 1970 00:00:00 UTC or 0 if not set
728Number of reserved blocks (apfs_reserve_block_count)
808Number of quota blocks (apfs_quota_block_count)
888Number of allocated blocks (apfs_fs_alloc_count)
9620Encryption state (apfs_meta_crypto)
1164File system root tree object type (apfs_root_tree_type)
1204Extent-reference tree object type (apfs_extentref_tree_type)
1244Snapshot metadata tree object type (apfs_snap_meta_tree_type)
1288Object map block number (apfs_omap_oid), which contains a block number relative to the start of the container of the object_map
1368File system root tree object identifier (apfs_root_tree_oid)
1448Extent-reference tree block number (apfs_extentref_tree_oid)
1528Snapshot metadata tree block number (apfs_snap_meta_tree_oid)
1608Rollback transaction identifier (apfs_revert_to_xid)
1688Rollback (physical) object identifier (apfs_revert_to_sblock_oid)
1768Next (available) file system object identifier (apfs_next_obj_id), where the upper 32-bit can contain 0xffffffff
1848Number of files (apfs_num_files)
1928Number of directories (apfs_num_directories)
2008Number of symbolic links (apfs_num_symlinks)
2088Number of other file system objects (apfs_num_other_fsobjects)
2168Number of snapshots (apfs_num_snapshots)
2248Total number of blocks allocated (apfs_total_blocks_alloced)
2328Total number of blocks freed (apfs_total_blocks_freed)
24016Volume identifier (apfs_vol_uuid), which contains a big-endian UUID
2568Modification date and time (apfs_last_mod_time), which consists of a signed integer that contains the number of nanoseconds since January 1, 1970 00:00:00 UTC or 0 if not set
2648Volume flags (apfs_fs_flags)
27248Creation change information (apfs_formatted_by)
3208 x 48 = 3848 most recent modification change information (apfs_modified_by)
704256Volume label (or name) (apfs_volname)
9604Next (available) document identifier (apfs_next_doc_id)
9642Volume role flags (apfs_role)
9662Unknown (reserved)
9688Active snapshot transaction identifier (apfs_root_to_xid)
9768Encryption progress state (apfs_er_state_oid)
9848Largest clone object identifier (apfs_cloneinfo_id_epoch)
9928Largest clone transaction identifier (apfs_cloneinfo_xid)
10008Extended snapsnot metadata (virtual) object identifier (apfs_snap_meta_ext_oid)
100816Volume group identifier (apfs_volume_group_id), which contains a big-endian UUID
10248Integrity metadata (virtual) object identifier (apfs_integrity_meta_oid)
10328Extent tree (virtual) object identifier (apfs_fext_tree_oid)
10404Extent tree object type (apfs_fext_tree_type)
10444Unknown (reserved_type)
10488Unknown (reserved_oid)
105680Unknown
11362960Unknown (empty values)

Encryption state

The encryption state (wrapped_meta_crypto_state_t) is 20 bytes in size and consists of:

OffsetSizeValueDescription
02Major format version (major_version)
22Minor format version (minor_version)
44Flags (cpflags)
84Unknown (persistent_class)
124Unknown (key_os_version)
162Unknown (key_revision)
182Unknown (unused)

Encryption state flags

TODO: complete this section.

Change information

The change information (apfs_modified_by_t) is 48 bytes in size and consists of:

OffsetSizeValueDescription
032Application (id), which consist of a string with the first 31 characters of the name and version of the application that changed the file system and 0 if not set
328Change date and time (timestamp), which consists of a signed integer that contains the number of nanoseconds since January 1, 1970 00:00:00 UTC or 0 if not set
408Change object transaction number (last_xid) or 0 if not set

Volume flags

ValueIdentifierDescription
0x0000000000000001APFS_FS_UNENCRYPTEDVolume is unencrypted
0x0000000000000002APFS_FS_EFFACEABLE (or APFS_FS_RESERVED_2)Unknown (Volume supports effaceable storage?)
0x0000000000000004APFS_FS_RESERVED_4Unknown (reserved)
0x0000000000000008APFS_FS_ONEKEYVolume uses software encryption with a single key (volume master key)
0x0000000000000010APFS_FS_SPILLEDOVERVolume has run out of allocated space on the solid-state drive
0x0000000000000020APFS_FS_RUN_SPILLOVER_CLEANERVolume has spilled over and the spillover cleaner must be run
0x0000000000000040APFS_FS_ALWAYS_CHECK_EXTENTREFVolume extent reference tree must be consulted before overwriting an extent
0x0000000000000080APFS_FS_RESERVED_80Unknown (reserved)
0x0000000000000080APFS_FS_RESERVED_100Unknown (reserved)

Volume features flags

ValueIdentifierDescription
0x0000000000000001APFS_FEATURE_DEFRAG_PRERELEASEUnknown
0x0000000000000002APFS_FEATURE_HARDLINK_MAP_RECORDSUnknown
0x0000000000000004APFS_FEATURE_DEFRAGUnknown
0x0000000000000008APFS_FEATURE_STRICTATIMEUnknown
0x0000000000000010APFS_FEATURE_VOLGRP_SYSTEM_INO_SPACEUnknown

Volume read-only compatible feature flags

Current no read-only compatible feature flags are defined

Volume incompatible feature flags

ValueIdentifierDescription
0x0000000000000001APFS_INCOMPAT_CASE_INSENSITIVEFilenames are case insensitive
0x0000000000000002APFS_INCOMPAT_DATALESS_SNAPSVolume contains one or more snapshots without data
0x0000000000000004APFS_INCOMPAT_ENC_ROLLEDEncryption keys of the volume have been changed
0x0000000000000008APFS_INCOMPAT_NORMALIZATION_INSENSITIVEFilenames are normalization insensitive
0x0000000000000010APFS_INCOMPAT_INCOMPLETE_RESTOREUnknown
0x0000000000000020APFS_INCOMPAT_SEALED_VOLUMEUnknown
0x0000000000000040APFS_INCOMPAT_RESERVED_40Unknown

Volume role flags

ValueIdentifierDescription
0x0000APFS_VOL_ROLE_NONENone
0x0001APFS_VOL_ROLE_SYSTEMSystem
0x0002APFS_VOL_ROLE_USERUser
0x0004APFS_VOL_ROLE_RECOVERYRecovery
0x0008APFS_VOL_ROLE_VMVM
0x0010APFS_VOL_ROLE_PREBOOTPreboot
0x0020APFS_VOL_ROLE_INSTALLERInstaller

File system B-tree

The file system structures are stored in a B-tree.

The file system B-tree uses identifiers similar to catalog identifiers (CNIDs) on Hierarchical File System (HFS). In this document these identifiers are referred to as File System object identifiers (FSOIDs) to contrast other object identifiers (OIDs).

FSOIDIdentifierAssignment
0Unknown (Reserved)
1Parent identifier of the root directory (folder), nameless
2Directory identifier of the root directory (folder), named "root"
3Unknown, named "private-dir"

File system B-tree key

The file system B-tree key is of variable size and consists of:

OffsetSizeValueDescription
Object identifier and type (obj_id_and_type)
060 bitsFile system object identifier (FSOID)
7.44 bitsFile system data type
8...Optional additional key data dependent on the data type

File system data types

ValueIdentifierDescription
0x0APFS_TYPE_ANYUnknown (Any)
0x1APFS_TYPE_SNAP_METADATASnapshot metadata
0x2APFS_TYPE_EXTENTExtent
0x3APFS_TYPE_INODEInode
0x4APFS_TYPE_XATTRExtended attribute (xattr)
0x5APFS_TYPE_SIBLING_LINKSibling link
0x6APFS_TYPE_DSTREAM_IDData stream identifier
0x7APFS_TYPE_CRYPTO_STATEEncryption state
0x8APFS_TYPE_FILE_EXTENTFile extent
0x9APFS_TYPE_DIR_RECDirectory record
0xaAPFS_TYPE_DIR_STATSDirectory stats
0xbAPFS_TYPE_SNAP_NAMESnapshot name
0xcAPFS_TYPE_SIBLING_MAPSibling map
0xfAPFS_TYPE_INVALIDInvalid

File system B-tree branch node value

A file system B-tree node contains branch node values if BTNODE_LEAF is not set. The corresponding file system B-tree key represents the first key in the branch.

A file system B-tree branch node value is 8 bytes in size and consists of:

OffsetSizeValueDescription
08B-tree sub node object identifier, which can be resolved to a "physical" location using the object map

Snapshot metadata

The snapshot metadata value (j_snap_metadata_val_t) is of variable size and consists of:

OffsetSizeValueDescription
08Extent-reference tree block number, which contains a block number relative to the start of the container
88Volume superblock block number, which contains a block number relative to the start of the container
168Creation time, which consists of a signed integer that contains the number of nanoseconds since January 1, 1970 00:00:00 UTC or 0 if not set
248Change (or last modification) time, which consists of a signed integer that contains the number of nanoseconds since January 1, 1970 00:00:00 UTC or 0 if not set
328Unknown (inum)
404Extent-reference tree object type (extentref_tree_type)
444Flags
482Name string size (name_len), in number of bytes, which includes the size of the end-of-string character
50...Name string (name), which contains an UTF-8 encoded string with an end-of-string character

Snapshot metadata flags

ValueIdentifierDescription
0x00000001SNAP_META_PENDING_DATALESSUnknown

Extent

Extent key data

The extent key data (j_phys_ext_key_t) is 8 bytes in size and consists of:

OffsetSizeValueDescription
060 bitsFile system object identifier (FSOID)
7.44 bits0x2File system data type

Extent value data

The extent value data (j_phys_ext_val_t) is 20 bytes in size and consists of:

OffsetSizeValueDescription
Extent size and data type (len_and_kind)
060 bitsExtent size, in number of bytes
7.44 bitsFile system data type
 
88File system object identifier of owner (owning_obj_id)
164Reference count (refcnt)

Inode

Inode key data

The inode key data (j_inode_key_t) is 8 bytes in size and consists of:

OffsetSizeValueDescription
060 bitsFile system object identifier (FSOID)
7.44 bits0x3File system data type

Inode value data

The inode value data (j_inode_val_t) is of variable size and consists of:

OffsetSizeValueDescription
08Parent file system object identifier (parent_id)
88Data stream file system object identifier (private_id), which contains the file system object identifier of the file extents that make up the data stream
168Creation date and time (create_time), which consists of a signed integer that contains the number of nanoseconds since January 1, 1970 00:00:00 UTC or 0 if not set
248Modification date and time (mod_time), which consists of a signed integer that contains the number of nanoseconds since January 1, 1970 00:00:00 UTC or 0 if not set
328Inode change date and time (change_time), which consists of a signed integer that contains the number of nanoseconds since January 1, 1970 00:00:00 UTC or 0 if not set
408Access date and time (access_time), which consists of a signed integer that contains the number of nanoseconds since January 1, 1970 00:00:00 UTC or 0 if not set
488Inode flags (internal_flags)
564Number of children (nchildren) or number of (hard) links (nlink)
604Unknown (default_protection_class)
644Unknown (write_generation_counter)
684BSD file entry flags (bsd_flags)
724Owner user identifier (owner)
764Group identifier (gid)
802File mode
822Unknown (pad1)
848Unknown (pad2)
92...Extended fields (xfields)

Note that Mac OS stat command treats nchildren equivalent to nlink.

Inode flags
ValueIdentifierDescription
0x0000000000000001INODE_IS_APFS_PRIVATEThe inode is used internally, typically for a data stream
0x0000000000000002INODE_MAINTAIN_DIR_STATSThe inode tracks the size of all of its children
0x0000000000000004INODE_DIR_STATS_ORIGINThe inode has the INODE_MAINTAIN_DIR_STATS flag set explicitly, not due to inheritance
0x0000000000000008INODE_PROT_CLASS_EXPLICITThe inode data protection class was set explicitly when the inode was created
0x0000000000000010INODE_WAS_CLONEDThe inode was created by cloning another inode
0x0000000000000020INODE_FLAG_UNUSEDUnknown (Reserved)
0x0000000000000040INODE_HAS_SECURITY_EAThe inode has an access control list (security extended attribute)
0x0000000000000080INODE_BEING_TRUNCATEDThe inode was truncated
0x0000000000000100INODE_HAS_FINDER_INFOThe inode has a Finder info extended field
0x0000000000000200INODE_IS_SPARSEThe inode has a sparse byte count extended field
0x0000000000000400INODE_WAS_EVER_CLONEDThe inode has been cloned at least once
0x0000000000000800INODE_ACTIVE_FILE_TRIMMEDThe inode is an overprovisioning file that has been trimmed
0x0000000000001000INODE_PINNED_TO_MAINThe inode file content is always on the main storage device. This flag is used for Fusion drives where the main storage is a solid-state drive
0x0000000000002000INODE_PINNED_TO_TIER2The inode file content is always on the secondary storage device. This flag is used for Fusion drives where the secondary storage is a (magnetic) hard drive
0x0000000000004000INODE_HAS_RSRC_FORKThe inode has a resource fork
0x0000000000008000INODE_NO_RSRC_FORKThe inode does not have a resource fork
0x0000000000010000INODE_ALLOCATION_SPILLEDOVERThe inode file content has some space allocated outside of the preferred storage tier for that file
File modes
ValueIdentifierDescription
0xf000 (0170000)S_IFMTFile type bitmask
0x1000 (0010000)S_IFIFONamed pipe
0x2000 (0020000)S_IFCHRCharacter-special file (Character device)
0x4000 (0040000)S_IFDIRDirectory
0x6000 (0060000)S_IFBLKBlock-special file (Block device)
0x8000 (0100000)S_IFREGRegular file
0xa000 (0120000)S_IFLNKSymbolic link
0xc000 (0140000)S_IFSOCKSocket
0xe000 (0160000)S_IFWHTWhiteout

A whiteout is a file entry that covers up all entries of a particular name from lower branches.

BSD file entry flags

The BSD file entry flags are defined in the <sys/stat.h> header file.

ValueIdentifierDescription
0x0000ffffUF_SETTABLEbitmask of owner changeable flags
0x00000001UF_NODUMPdo not dump file entry
0x00000002UF_IMMUTABLEfile entry is immutable and may not be changed
0x00000004UF_APPENDwrites to file entry may only append
0x00000008UF_OPAQUEdirectory is opaque wrt. union
0x00000010UF_NOUNLINKfile entry may not be removed or renamed, which is not implement in Mac OS
0x00000020UF_COMPRESSEDfile entry is compressed
0x00000040UF_TRACKEDnotify about file entry changes
0x00000080UF_DATAVAULTentitlement required for reading and writing
0x00008000UF_HIDDENfile entry is hidden
0xffff0000SF_SETTABLEbitmask of superuser changeable flags
0x001f0000SF_SUPPORTEDbitmask of superuser supported flags
0x00010000SF_ARCHIVEDfile entry is archived
0x00020000SF_IMMUTABLEfile entry is immutable and may not be changed
0x00040000SF_APPENDwrites to file entry may only append
0x00080000SF_RESTRICTEDentitlement required for writing
0x00100000SF_NOUNLINKfile entry may not be removed, renamed or used as mount point
0x00200000SF_SNAPSHOTsnapshot inode, which is not implement in Mac OS

Extended attribute

Extended attribute key data

The extended attribute key data (j_xattr_key_t) is of variable size and consists of:

OffsetSizeValueDescription
060 bitsFile system object identifier (FSOID)
7.44 bits0x4File system data type
82Name string size (name_len), in number of bytes, which includes the size of the end-of-string character
10...Name string (name), which contains an UTF-8 encoded string with an end-of-string character

Note that the name of an extended attribute appears to be case senstive even on a case insensitive file system.

Extended attribute value data

The extended attribute value data (j_xattr_val_t) is of variable size and consists of:

OffsetSizeValueDescription
02Flags (flags)
22Extended attribute data size, in number of bytes
4...Extended attribute data

Note that extended attribute data size can contain 0 if the extended attribute flag XATTR_DATA_EMBEDDED is set.

Extended attribute names

NameDescription
com.apple.assetsd.dbRebuildInProgress
com.apple.assetsd.dbRebuildUuid
com.apple.assetsd.thumbnailCameraPreviewImageAssetID
com.apple.assetsd.UUID
com.apple.decmpfsApple File System Compression (decmpfs) extended attribute
com.apple.FinderInfo
com.apple.fs.symlinkSymbolic link
com.apple.genstore.info
com.apple.genstore.origdisplayname
com.apple.genstore.orig_perms_v1
com.apple.genstore.origposixname
com.apple.GeoServices.SHA1
com.apple.installd.installType
com.apple.installd.uniqueInstallID
com.apple.lastuseddate#PS
com.apple.metadata:_kMDItemUserTags
com.apple.metadata:com_apple_backup_excludeItem
com.apple.metadata:kMDItemDownloadedDate
com.apple.metadata:kMDItemWhereFroms
com.apple.metadata:kMDLabel_fwlfb7nbt2o7degof3q2o2btjy
com.apple.quarantine
com.apple.ResourceForkResource fork
com.apple.rootless
com.apple.system.Security
com.apple.TextEncoding
LastUpgradeCheck
lock
org.chromium.crashpad.database.initialized

Extended attribute flags

ValueIdentifierDescription
0x0001XATTR_DATA_STREAMExtended attribute data is stored in a data stream, where the attribute data contains an 8-byte file system object identifier of the corresponding data stream
0x0002XATTR_DATA_EMBEDDEDExtended attribute data is stored directly in the record
0x0004XATTR_FILE_SYSTEM_OWNEDExtended attribute is part of the file system, such as "com.apple.fs.symlink"
0x0008XATTR_RESERVED_8Unknown (Reserved)

Extended attribute data stream

The extended attribute data stream (j_xattr_dstream_t) is 48 bytes in size and consists of:

OffsetSizeValueDescription
08Data stream file system object identifier (xattr_obj_id), which contains the file system object identifier of the file extents that make up the data stream
840Data stream descriptor

The sibling link key data (j_sibling_key_t) is 16 bytes in size and consists of:

OffsetSizeValueDescription
060 bitsFile system object identifier (FSOID)
7.44 bits0x4File system data type
88Sibling map identifier (sibling_id), which contains the file system object identifier of the sibling map record

The sibling link value data (j_sibling_val_t) is of variable size and consists of:

OffsetSizeValueDescription
08Parent file system object identifier (parent_id)
82Name string size (name_len), in number of bytes, which includes the size of the end-of-string character
10...Name string (name), which contains an UTF-8 encoded string with an end-of-string character

Data stream identifier

Data stream identifier key data

The data stream key data (j_dstream_id_key_t) is 8 bytes in size and consists of:

OffsetSizeValueDescription
060 bitsFile system object identifier (FSOID)
7.44 bits0x6File system data type

Data stream identifier value data

The data stream value data (j_dstream_id_val_t) is 4 bytes in size and consists of:

OffsetSizeValueDescription
04Reference count (refcnt)

File extent

File extent key data

The file extent key data (j_file_extent_key_t) is 16 bytes in size and consists of:

OffsetSizeValueDescription
060 bitsFile system object identifier (FSOID)
7.44 bits0x8File system data type
88Logical extent offset (or address) (logical_addr), which contains an offset relative to the start of the file entry data

File extent value data

The file extent value data (j_file_extent_val_t) is 24 bytes in size and consists of:

OffsetSizeValueDescription
Extent size and flags (len_and_flags)
07Extent size, in number of bytes
71Flags
 
88Physical block number (phys_block_num), which contains a block number relative to the start of the container
168Encryption identifier (crypto_id), which contains an unknown value and 0 if not set

File extent flags

ValueIdentifierDescription
0x01Unknown (Is encrypted?)

Note that according to the Apple File System Reference documentation there are currently no flags defined. The reference documentation also refers to len_and_flags as len_and_kind interchangeably.

Directory record

The directory record can have 2 different types of keys:

  • Key with name
  • Key with name and hash

Note that apprears that current APFS file system use a key with name and hash. Apple File System Reference documentation does not indicate how to distinguish between the two, but one method is to compare calculated and stored size of the key data.

Note that B-tree branch nodes are sorted using the case-sensitive name, even when the file system is case-insensitive.

Directory record key data with name

The directory record key data with name (j_drec_key_t) is of variable size and consists of:

OffsetSizeValueDescription
Object identifier and type (hdr)
060 bitsFile system object identifier (FSOID)
7.44 bits0x9File system data type
 
82Name string size (name_len), in number of bytes, which includes the size of the end-of-string character
10...Name string (name), which contains an UTF-8 encoded string with an end-of-string character

Directory record key data with name and hash

The directory record key data with name and hash (j_drec_hashed_key_t) is of variable size and consists of:

OffsetSizeValueDescription
Object identifier and type (hdr)
060 bitsFile system object identifier (FSOID)
7.44 bits0x9File system data type
Name string size and hash (name_len_and_hash)
811 bitsName string size, in number of bytes, which includes the size of the end-of-string character
9.321 bitsName hash
 
12...Name string (name), which contains an UTF-8 encoded string with an end-of-string character

Directory record value data

The directory record value data (j_drec_val_t) is of variable size and consists of:

OffsetSizeValueDescription
08File system object identifier of the directory entry (file_id)
88Date and time the directory entry was added (date_added), which consist of a signed integer that contains the number of nanoseconds since January 1, 1970 00:00:00 UTC or 0 if not set
162Directory entry flags
18...Extended fields (xfields)
Directory entry flags
ValueIdentifierDescription
0x0000DT_UNKNOWNUnknown
0x0001DT_FIFONamed pipe
0x0002DT_CHRCharacter-special file (Character device)
0x0004DT_DIRDirectory
0x0006DT_BLKBlock-special file (Block device)
0x0008DT_REGRegular file
0x000aDT_LNKSymbolic link
0x000cDT_SOCKSocket
0x000eDT_WHTWhiteout
0x000fDREC_TYPE_MASKDirectory type bitmask
0x0010RESERVED_10Unknown (reserved)

A whiteout is a file entry that covers up all entries of a particular name from lower branches.

Directory entry name hash

The name hash of a directory entry is calculated as following:

  • If the file system is case-insensitive represent the name in lower-case
  • Represent the name as an Unicode string in Normalization Form Canonical Decomposition (NFD)
  • Format the Unicode string as a little-endian UTF-32 stream without a byte-order-mark or end-of-string character
  • Calculate a CRC-32c checksum of the UTF-32 stream with an initial checksum of 0xffffffff (-1)
  • The lower 22-bits of checksum form the hash

The CRC-32 calculation uses the Castagnoli polynomial (0x1edc6f41), also known as CRC-32C (or CRC32-C). The CRC-32 calculation does not use the XOR with 0xffffffff before and after the calculation, which is also referred to as weak CRC-32 calculation.

Directory stats

Directory stats key data

The directory stats key data (j_dir_stats_key_t) is 8 bytes in size and consists of:

OffsetSizeValueDescription
060 bitsFile system object identifier (FSOID)
7.44 bits0xaFile system data type

Directory stats value data

The directory stats value data (j_dir_stats_val_t) is 32 bytes in size and consists of:

OffsetSizeValueDescription
08Number of children (num_children)
88Total size (total_size), in number of bytes
168Parent directory file system object identifier (chained_key)
248Generation count (gen_count)

Snapshot name

The snapshot name (j_snap_name_val_t) is 8 bytes in size and consists of:

OffsetSizeValueDescription
060 bitsSnapshot metdata object identifier
7.44 bits0x1File system data type

Sibling map

Sibling map key data

The sibling map key data (j_sibling_map_key_t) is 8 bytes in size and consists of:

OffsetSizeValueDescription
060 bitsFile system object identifier (FSOID)
7.44 bits0x4File system data type

Sibling map value data

The sibling map value data (j_sibling_map_val_t) is 8 bytes in size and consists of:

OffsetSizeValueDescription
08File system object identifier (file_id)

Extended fields

Directory entries and inodes use extended fields to store additional attributes, such as the filename.

The extended fields (xf_blob_t) consists of:

OffsetSizeValueDescription
02Number of extended fields (xf_num_exts)
22Extended fields data size (xf_used_data), in number of bytes
Extended fields data (xf_data)
4...Array of extended field descriptors
......Extended fields data

Note that extended field values are stored 8-byte aligned in the extended field value data.

Extended field descriptor

An extended field descriptor (x_field_t) is 4 bytes in size and consists of:

OffsetSizeValueDescription
01Extended field type (x_type)
11Extended field flags (x_flags)
22Extended field data size (x_size), in number of bytes

Extended field types

Directory record extended field types
ValueIdentifierDescription
1DREC_EXT_TYPE_SIBLING_IDHard link sibling identifier, where the extended field data contains a 64-bit integer value
Inode extended field types
ValueIdentifierDescription
1INO_EXT_TYPE_SNAP_XIDTransaction identifier of a snapshot, where the extended field data contains a 64-bit integer value
2INO_EXT_TYPE_DELTA_TREE_OIDObject identifier of the snapshot extent delta list, where the extended field data contains a 64-bit integer value
3INO_EXT_TYPE_DOCUMENT_IDDocument identifier, where the extended field data contains a 32-bit integer value
4INO_EXT_TYPE_NAMEFilename, where the extended field data contains an UTF-8 string with end-of-string character
5INO_EXT_TYPE_PREV_FSIZEPrevious file size, in number of bytes, where the extended field data contains a 64-bit integer value
6INO_EXT_TYPE_RESERVED_6Unknown (Reserved)
7INO_EXT_TYPE_FINDER_INFOFinder information, where the extended field data contains a 32-bit integer value
8INO_EXT_TYPE_DSTREAMData stream, where the extended field data contains a data stream descriptor
9INO_EXT_TYPE_RESERVED_9Unknown (Reserved)
10INO_EXT_TYPE_DIR_STATS_KEYDirectory statistics; it is unknown if the extended field data contains an object identifier of the directory statistics or a j_dir_stats_val_t structure, seen 8 byte value
11INO_EXT_TYPE_FS_UUIDMounted file system identifier, where the extended field data contains a 128-bit UUID value
12INO_EXT_TYPE_RESERVED_12Unknown (Reserved)
13INO_EXT_TYPE_SPARSE_BYTESNumber of sparse bytes in the data stream, where the extended field data contains a 64-bit integer value
14INO_EXT_TYPE_RDEVBlock or character device identifier, where the extended field data contains a 32-bit integer value
15INO_EXT_TYPE_PURGEABLE_FLAGSInformation about a purgeable file; unknown, defined as reserved, seen 8 byte value
16INO_EXT_TYPE_ORIG_SYNC_ROOT_IDUnknown (Inode number of the sync-root hierarchy)

Extended field flags

ValueIdentifierDescription
0x01XF_DATA_DEPENDENTContents of the extended field is dependent on the data stream (file contents)
0x02XF_DO_NOT_COPYDo not duplicate the extended field when copied
0x04XF_RESERVED_4Unknown (Reserved)
0x08XF_CHILDREN_INHERITNewly created sub directory entries (children) inherit the extended field
0x10XF_USER_FIELDExtended field was added by an user-space program
0x20XF_SYSTEM_FIELDExtended field was added by the system (kernel)
0x40XF_RESERVED_40Unknown (Reserved)
0x80XF_RESERVED_80Unknown (Reserved)

Device identifier

The device identifier can be stored in different formats, such as: native, 386bsd, 4bsd, bsdos, freebsd, hpux, isc, linux, netbsd, osf1, sco, solaris, sunos, svr3, svr4 and ultrix.

The “native” and “hpux” device identifier is 4 bytes in size and consists of:

OffsetSizeValueDescription
01Major device number
120Unknown
31Minor device number

The “386bsd”, “4bsd”, “freebsd”, “isc”, “linux”, “netbsd”, “sco”, “sunos”, “svr3” and “ultrix” device identifier is 4 bytes in size and consists of:

OffsetSizeValueDescription
020Unknown
21Major device number
31Minor device number

The “solaris” and “svr4” device identifier is 4 bytes in size and consists of:

OffsetSizeValueDescription
0.018 bitsMinor device number
2.214 bitsMajor device number

The “bsdos” and “osf1” device identifier is 4 bytes in size and consists of:

OffsetSizeValueDescription
0.020 bitsMinor device number
2.412 bitsMajor device number

The “bsdos” alternative device identifier is 4 bytes in size and consists of:

OffsetSizeValueDescription
0.08 bitsSub unit number
1.012 bitsUnit number
2.412 bitsMajor device number

Data stream descriptor

The data stream descriptor (j_dstream_t) is 40 bytes in size and consist of:

OffsetSizeValueDescription
08Used size (size), in number of bytes
88Allocated size (alloced_size), in number of bytes
168(Default) encryption identifier (default_crypto_id)
248Total number of bytes written to data stream (total_bytes_written)
328Total number of bytes read from data stream (total_bytes_written)

File content

APFS supports multiple ways to store file content:

  • Data fork
  • Compressed data extended attribute
  • Compressed data extended attribute with resource fork
  • Resource fork
  • Extended attribute (named fork)

Data fork

The file content size is stored in an INO_EXT_TYPE_DSTREAM inode extended field type.

The file content data can be located through the file extents for the data stream file system object identifier in the file system tree.

If the volume is encrypted the file content is encrypted with the encryption identifier in defined by the file extent.

If the inode flag INODE_IS_SPARSE is set the file contains one or more spare file extents. A sparse file extent has a physical block number of 0.

Compressed data extended attribute

The file content data and size are stored in the compressed data header of a “com.apple.decmpfs” extended attribute.

Note it is currently assumed that the file entry either must not have a data fork or it the data fork must be of size 0.

Also see: Apple File System Compression (decmpfs).

Compressed data extended attribute with resource fork

The file content size is stored in the compressed data header of a “com.apple.decmpfs” extended attribute.

The file content data is stored in a “com.apple.ResourceFork” extended attribute.

Note it is currently assumed that the file entry either must not have a data fork or it the data fork must be of size 0.

Also see: Apple File System Compression (decmpfs).

Resource fork

TODO: complete this section.

Extended attribute (named fork)

TODO: complete this section.

EFI jumpstart

The EFI jumpstart (nx_efi_jumpstart_t) is of variable size and consists of:

OffsetSizeValueDescription
Object header
08Object checksum, which contains 0 if not set
88Object identifier
168Object transaction identifier (xid)
2440x00000014Object type
2840x00000000Object subtype
Object values
324"RDSJ"Signature (nej_magic)
3641Format version (nej_version)
404Unknown (nej_efi_file_len?)
444Number of extents (nej_num_extents)
4816 x 8Unknown (nej_reserved?)
176number of extents x 16EFI jumpstart extents (nej_rec_extents), which contains the location where the EFI driver is stored

EFI jumpstart extent

The EFI jumpstart extent (prange_t) is 16 bytes in size and consists of:

OffsetSizeValueDescription
08Block number
88Number of blocks

Extent-reference tree

TODO: complete this section.

Snapshots

TODO: complete this section.

Snapshot metadata tree

The snapshot metadata tree consists of:

  • snapshot metadata tree (object)
  • snapshot metadata B-tree

Snapshot metadata tree object

The snapshot metadata tree object is 32 bytes in size and consists of:

OffsetSizeValueDescription
Object header
08Object checksum, which contains 0 if not set
88Object identifier
168Object transaction identifier (xid)
2440x40000002 or 0x40000003Object type
2840x00000010Object subtype

Snapshot metadata B-tree

The object map values are stored in B-tree.

Snapshot metadata B-tree key

The snapshot metadata B-tree key (j_snap_metadata_key_t or j_snap_name_key_t) is of variable size and consists of:

OffsetSizeValueDescription
08Key object identifier (hdr)
If key object identifier data type is APFS_TYPE_SNAP_NAME
8...Snapshot name string, which contains an UTF-8 encoded string with an end-of-string character

Snapshot metadata B-tree branch node value

A snapshot metadata B-tree node contains branch node values if BTNODE_LEAF is not set. The corresponding inapshot metadata B-tree key represents the first key in the branch.

A snapshot metadata B-tree branch node value is 8 bytes in size and consists of:

OffsetSizeValueDescription
08Sub node block number, which contains a block number relative to the start of the container

Snapshot metadata B-tree leaf node value

The contents of a snapshot metadata B-tree leaf node depends on the file system data type of the key object identifier.

ValueDescription
APFS_TYPE_SNAP_METADATASnapshot metadata object identifier
APFS_TYPE_SNAP_NAMESnapshot name

Fusion drives

A Fusion drive consists of a main SSD and a tier2 magnetic disk that together form one logical APFS container.

Fusion middle tree

TODO: complete this section.

OffsetSizeValueDescription
Object header
08Object checksum, which contains 0 if not set
88Object identifier
168Object transaction identifier (xid)
2440x40000002Object type
2840x00000015Object subtype
Object values
......Unknown

Format edge cases and corruption scenarios

Container key bag is hardware encrypted but volume is not encrypted

Seen in APFS containers created by certain digital forensics tools. The container key bag is either hardware encrypted or contains random data but the volume is not encrypted.

Notes

TODO describe evict_mapping_val_t

References

Assorted formats

Apple Data Compression (ADC) data format

ADC compression is used in various data formats used on Mac OS, including Universal Disk Image Format (UDIF) files (.dmg).

Overview

ADC compressed data consist of:

Characteristics

CharacteristicsDescription
Byte orderbig-endian

ADC chunk

An ADC chunk is of variable size and consists of consists of:

OffsetSizeValueDescription
0.01 bitLiteral chunk flag
If literal chunk flag is set (1)
0.17 bitsLiteral data size, in number of bytes, where size = value + 1
1.0...Literal (uncompressed) data
If literal chunk flag is not set (0)
0.11 bitExtended-size chunk flags
If extended-size chunk flag is not set (0)
0.24 bitsCompressed data size, in number of bytes, where size = value + 3
0.610 bitsCompressed data distance, where 0 is the offset of the last previously uncompressed byte
If extended-size chunk flag is set (1)
0.26 bitsCompressed data size, in number of bytes, where size = value + 4
1.016 bitsCompressed data distance, where 0 is the offset of the last previously uncompressed byte

LZFSE compressed data format

LZFSE compression is used in various data formats used on Mac OS, including Universal Disk Image Format (UDIF) files (.dmg) and Apple File System Compression (decmpfs), which is used in Hierarchical File System (HFS) and Apple File System (APFS).

Overview

LZFSE compressed data stream consist of:

Characteristics

CharacteristicsDescription
Byte orderlittle-endian

LZFSE block

A LZFSE block is of variable size and consits of:

OffsetSizeValueDescription
04Block signature
4...Block data

Block signatures

ValueIdentifierDescription
0x00000000LZFSE_NO_BLOCK_MAGICInvalid
0x24787662 ("bvx$")LZFSE_ENDOFSTREAM_BLOCK_MAGICEnd-of-stream block (marker)
0x2d787662 ("bvx-")LZFSE_UNCOMPRESSED_BLOCK_MAGICUncompressed (raw) block
0x31787662 ("bvx1")LZFSE_COMPRESSEDV1_BLOCK_MAGICLZFSE compressed block with uncompressed tables
0x32787662 ("bvx2")LZFSE_COMPRESSEDV2_BLOCK_MAGICLZFSE compressed block with compressed tables
0x6e787662 ("bvxn")LZFSE_COMPRESSEDLZVN_BLOCK_MAGICLZVN compressed block

End-of-stream block

An end-of-stream block is 4 bytes in size and consits of:

OffsetSizeValueDescription
Block header
04"bvx$"Block signature

Uncompressed block

An uncompressed block is of variable size and consits of:

OffsetSizeValueDescription
Block header
04"bvx-"Block signature
44Uncompressed data size
 
8...Uncompressed data

LZFSE compressed block with uncompressed tables

A LZFSE compressed block with uncompressed tables (lzfse_compressed_block_header_v1) is of variable size and consits of:

OffsetSizeValueDescription
Block header
04"bvx1"Block signature
44Uncompressed data size
84Compressed data size
124Number of literals
164Number of L, M, D values
204Number of bytes used to encode literals
244Number of bytes used to encode matches
284Unknown (Final accum_nbits for literals stream)
322First literal state
342Second literal state
362Third literal state
382Fourth literal state
404Unknown (accum_nbits for the l, m, d stream)
442L value state
462M value state
482D value state
50720Frequency table
 
770...encoded literals
......encoded L, M, D values

LZFSE compressed block with compressed tables

A LZFSE compressed block with compressed tables (lzfse_compressed_block_header_v2) is of variable size and consits of:

OffsetSizeValueDescription
Block header
04"bvx2"Block signature
44Uncompressed data size
3 x 64-bit packed fields
8.020 bitsNumber of literals
10.420 bitsNumber of bytes used to encode literals
13.020 bitsNumber of L, M, D values
15.43 bitsUnknown (Final accum_nbits for literals stream)
14.71 bitUnknown (unused)
16.010 bitsFirst literal state
17.210 bitsSecond literal state
18.410 bitsThird literal state
19.610 bitsFourth literal state
21.020 bitsNumber of bytes used to encode matches
22.43 bitsUnknown (accum_nbits for the l, m, d stream)
23.71 bitUnknown (unused)
24.032 bitsBlock header size
28.010 bitsL value state
29.210 bitsM value state
30.410 bitsD value state
31.62 bitsUnknown (unused)
If block header size > 32
32...Bit stream containing Huffman encoded frequency table
Common
......encoded literals
......encoded L, M, D values

Note that if the block header size is 32 the block does not contain frequency tables.

LZVN compressed block

A LZVN compressed block is of variable size and consits of:

OffsetSizeValueDescription
Block header
04"bvxn"Block signature
44Uncompressed data size
84Compressed data size
 
12...LZVN compressed data

LZFSE frequency table

A LZFSE frequency table consist of 360 16-bit values:

OffsetSizeValueDescription
020Literal run-lengths (L stream) frequency values
2020Match sizes (M stream) frequency values
4064Match distances (D stream) frequency values
104256Literal frequency values

Decoding the Huffman encoded frequency table

TODO: describe how to decode the Huffman encoded frequency table.

5-bits encoded value, special cases 8 and 14

lzfse_freq_nbits_table[32] = {
    2, 3, 2, 5, 2, 3, 2, 8, 2, 3, 2, 5, 2, 3, 2, 14,
    2, 3, 2, 5, 2, 3, 2, 8, 2, 3, 2, 5, 2, 3, 2, 14 };

lzfse_freq_value_table[32] = {
    0, 2, 1, 4, 0, 3, 1, -1, 0, 2, 1, 5, 0, 3, 1, -1,
    0, 2, 1, 6, 0, 3, 1, -1, 0, 2, 1, 7, 0, 3, 1, -1 };

LZVN compressed data format

LZVN compression is used in various data formats used on Mac OS, including Apple File System Compression (decmpfs), which is used in Hierarchical File System (HFS) and Apple File System (APFS).

Overview

LZVN compressed data consist of:

Characteristics

CharacteristicsDescription
Byte orderbig-endian

Opcodes

The opcodes consist of:

OppcodeDataDescription
0xe011100000 LLLLLLLL <literal>Large literal of size: L + 16
0xe1 - 0xef1110LLLL <literal>Small literal of size: L
0x00 - 0x05, 0x08 - 0x0d, 0x10 - 0x15, 0x18 - 0x1d, 0x20 - 0x25, 0x28 - 0x2d, 0x30 - 0x35, 0x38 - 0x3d, 0x40 - 0x45, 0x48 - 0x4d, 0x50 - 0x55, 0x58 - 0x5d, 0x60 - 0x65, 0x68 - 0x6d, 0x80 - 0x85, 0x88 - 0x8d, 0x90 - 0x95, 0x98 - 0x9d, 0xc0 - 0xc5, 0xc8 - 0xcdLLMMMDDD DDDDDDDD <literal>Small distance: M + 3
0xa0 - 0xbf101LLMMM DDDDDDMM DDDDDDDD <literal>Medium distance: M + 3
0x07, 0x0f, 0x17, 0x1f, 0x27, 0x2f, 0x37, 0x3f, 0x47, 0x4f, 0x57, 0x5f, 0x67, 0x6f, 0x87, 0x8f, 0x97, 0x9f, 0xc7, 0xcfLLMMM111 DDDDDDDD DDDDDDDD <literal>Large distance: M + 3
0x46, 0x4e, 0x56, 0x5e, 0x66, 0x6e, 0x86, 0x8e, 0x96, 0x9e, 0xc6, 0xceLLMMM110Previous distance
0x0e, 0x16None (nop)
0x06End of stream (eos)
0xf1 - 0xff1111MMMMSmall match
0xf011110000 MMMMMMMMLarge match: M + 16
0x1e, 0x26, 0x2e, 0x36, 0x3e, 0x70 - 0x7f, 0xd0 - 0xdfInvalid

Property list (plist) format

The property list (plist) formats are used to store various kinds of data, for example configuration data. The format is know to be used stand-alone as well as embedded in other data formats.

Overview

Known plist formats are:

  • ASCII plist format
  • Binary plist format
  • XML plist format

TODO: What about other plist formats like JSON?

Value types

TypeDescription
arrayCollection of plist values without key
booleanBoolean value
dataBinary data
dateDate and time value
dictionaryCollection of plist values with key
integerSigned integer value
realFloating-point value
stringString value

ASCII plist format

TODO: complete section

Binary plist format

A binary plist file consists of:

  • header
  • object table
  • offset table
  • trailer
CharacteristicsDescription
Byte orderbig-endian
Date and time valuesNumber of seconds since Jan 1, 2001 00:00:00 UTC
Character stringsUTF-16 big-endian

Binary plist header

The binary plist header (CFBinaryPlistHeader) is 8 bytes in size and consists of:

OffsetSizeValueDescription
06"bplist"Signature
62Format version

Format versions

VersionDescription
"00"Supported as of Tiger
"01"Supported as of Leopard
"0x"Supported as of Snow Leopard, where x is any character

Object table

The object table consists of:

  • zero or more objects

Objects are of variable size and consist of:

  • an object maker byte
  • (optional) object data

Object marker byte

ValueIdentifierDescription
0x00kCFBinaryPlistMarkerNullEmpty value (NULL)
0x08kCFBinaryPlistMarkerFalseBoolean False
0x09kCFBinaryPlistMarkerTrueBoolean True
0x0fkCFBinaryPlistMarkerFillUnknown (Fill byte?)
0x1#kCFBinaryPlistMarkerIntInteger, where 2^# is the number of bytes
0x2#kCFBinaryPlistMarkerIntFloating point, where 2^# is the number of bytes
0x33kCFBinaryPlistMarkerDateDate and time value, which is stored as a 64-bits floating point that contains the number of seconds since Jan 1, 2001 00:00:00 UTC
0x4#kCFBinaryPlistMarkerDataBinary data, where # is the number of bytes. If # is 15 then the object marker byte is followed by a 32-bit integer that contains the size of the data
0x5#kCFBinaryPlistMarkerASCIIStringASCII string, where # is the number of characters. If # is 15 then the object marker byte is followed by an integer object that contains the number of characters in the string. The string is stored in ASCII (with codepage?) without an end-of-string marker
0x6#kCFBinaryPlistMarkerUnicode16StringUnicode string, where # is the number of characters. If # is 15 then the object marker byte is followed by an integer object that contains the number of characters in the string. The string is stored in UTF-16 big-endian without an end-of-string marker
0x7#Unused
0x8#kCFBinaryPlistMarkerUIDUID, where # + 1 is the number of bytes
0x9#Unused
0xa#kCFBinaryPlistMarkerArrayArray of objects, where # is the number of elements. If # is 15 then the object marker byte is followed by an integer object that contains the number of elements in the array
0xb#Unused
0xc#kCFBinaryPlistMarkerSetSet of objects, where # is the number of elements. If # is 15 then the object marker byte is followed by an integer object that contains the number of ele,emts in the set
0xd#kCFBinaryPlistMarkerDictDictionary of key value pairs, where # is the number of key value pairs. If # is 15 then the object marker byte is followed by an integer object that contains the number of key value pairs in the dictionary
0xe#Unused
0xf#Unused

Array object

The array object consists of:

  • array object marker with number of elements
  • array of object references that identify the element objects.
  • the element object data

The byte size of the object reference is defined in the trailer. An object reference of 1 will refer to the first object in the (object) offset table.

Set object

The set object consists of:

  • set object marker with number of elements
  • array of object references that identify the element objects.
  • the element object data

The byte size of the object reference is defined in the trailer. An object reference of 1 will refer to the first object in the (object) offset table.

Dictionary object

The dictionary object consists of:

  • dictionary object marker with number of key and value pairs
  • array of key references that identify key objects.
  • array of object references that identify the value objects.
  • the key/value object data

The byte size of the key and object reference is defined in the trailer. A key and object reference of 1 will refer to the first object in the (object) offset table.

(Object) offset table

The offset table consists of an array of offsets. The trailer defines:

  • The location of the offset table
  • The offset byte size
  • The number of offsets in the table

The offset values are relative from the start of the file.

Binary plist trailer

The binary plist trailer (CFBinaryPlistTrailer) is 32 bytes in size and consists of:

OffsetSizeValueDescription
05 x 10Unknown (0-byte values)
510Unknown (Sort version)
61Offset byte size
71Key and object reference byte size
88Number of objects
168Root (or top-level) object
248Offset table offset, where the offset is relative to the start of the file

XML plist format

A XML plist file consists of:

  • optional XML declaration
  • optional Document Type Definition (DTD)
  • plist root XML element
  • key-value pair XML elements

For example:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist SYSTEM "file://localhost/System/Library/DTDs/PropertyList.dtd">
<plist version="1.0">
...
</plist>

Zlib compressed data format

Zlib compression is commonly used in file formats. The zlib compressed data format, as defined in RFC1950, allows for multiple techniques but only the Deflate compression method, a variation of LZ77, is used.

Overview

Zlib compressed data consist of:

  • data header
  • compressed data
  • Adler-32 checksum of the uncompressed data

Characteristics

CharacteristicsDescription
Byte orderbig-endian

Data header

The data header is 2 or 6 bytes in size and consist of:

OffsetSizeValueDescription
The bit values are stored a 8-bit values
0.04 bitsCompression method
0.44 bitsCompression information
Flags
1.05 bitsCheck bits
1.51 bitPreset dictionary flag
1.62 bitsCompression level. The compression level is used mainly for re-compression
If the dictionary identifier flag is set
24Preset dictionary identifier, which contains an Adler-32 used to identifier the preset dictionary
Common
......Compressed data
...4Checksum, which contains an Adler-32 of the compressed data

The check bits value must be such that when the first 2 bytes are represented as a 16-bit unsigned integer in big-endian byte order the value is a multiple of 31, such that:

((first * 256) + second) % 31 = 0

Compression method

ValueIdentifierDescription
8Deflate (RFC1951), with a maximum window size of 32 KiB
15Reserved for additional header data

Note that RFC1950 only defines 8 as a valid compression method.

Compression information

The value of the compression information is dependent on the compression method.

Compression information - compression method 8 (Deflate)

For compression method 8 (Deflate) the compression information contains the base-2 logarithm of the LZ77 window size minus 8.

OffsetSizeValueDescription
0.04 bitsWindow size, which consists of a base-2 logarithm (2n), with a maximum value of 7 (32 KiB)

To determine the corresponding window size:

1 << (7 + 8)

E.g. a compression information value of 7 indicates a 32768 bytes window size. Values larger than 7 are not allowed according to RFC1950 and thus the maximum window size is 32768 bytes.

Compression level

ValueIdentifierDescription
0Fastest
1Fast
2Default
3Slowest, maximum compression

Compressed data

Deflate compressed data

The deflate compressed data consists of one or more deflate compressed blocks. Each block consists of:

  • block header
  • block data

Note that a block can reference uncompressed data that is stored in a previous block.

Block header

The block header is 3 bits in size and consists of:

OffsetSizeValueDescription
01 bitLast block (in stream) marker, where 1 represents the last block and 0 otherwise
0.12 bitsBlock type

Block types

ValueIdentifierDescription
0Uncompressed (or stored) block
1Fixed Huffman compressed block
2Dynamic Huffman compressed block
3Reserved (not used)

Uncompressed block data

The uncompressed block data is of variable size and consists of:

OffsetSizeValueDescription
0.35 bitsEmpty values (not used)
12Uncompressed data size
32Copy of uncompressed data size, which contains a 1s complement of the uncompressed data size
5...Uncompressed data

The uncompressed data size can range between 0 and 65535 bytes.

Huffman compressed block data

The uncompressed block data is of variable size and consists of:

  • Optional dynamic Huffman table
  • Encoded bit-stream
  • End-of-stream (or end-of-block or end-of-data) marker
Dynamic Huffman table

The dynamic Huffman table consists of:

OffsetSizeValueDescription
0.35 bitsNumber of literal codes, which is value + 257. The number of literal codes must be smaller than 286
1.05 bitsNumber of distance codes, which is value + 1. The number of distance codes must be smaller than 30
1.54 bitsThe number of Huffman codes for the code sizes, which is value + 4
2.1...The code sizes
......Huffman encoded stream of the Huffman codes for the literals
......Huffman encoded stream of the Huffman codes for the distances

A single code size value is 3 bits of size. A value of 0 means the code size is not used in the Huffman encoding of the literal and distance codes.

The codes size values are stored in the following sequence:

16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15

The first value applies to a code size of 16, the second to 17, etc. Code sizes that are not stored default to 0.

The code size values are used to construct the code sizes Huffman table. This must be a complete Huffman table which is used to decode the literal and distance codes. The corresponding codes size Huffman encoding is defined as:

ValueIdentifierDescription
0 - 15Represents a code size of 0 - 15
16Copy the previous code size 3 - 6 times. The next 2 bits indicate repeat length (0 = 3, ... , 3 = 6), e.g. codes 8, 16 (+2 bits 11), 16 (+2 bits 10) will expand to 12 code lengths of 8 (1 + 6 + 5)
17Repeat a code length of 0 for 3 - 10 times (3 bits of length)
18Repeat a code length of 0 for 11 - 138 times (7 bits of length)

Both the literal and distance Huffman codes are stored Huffman encoded using the code sizes Huffman table. Code sizes that are not stored default to 0. The code size for the literal code 256 (end-of-block) should be set and thus not 0.

Encoded bit-stream

The encoded bit-stream is stored in 8-bit integers, where bit values are stored back-to-front. So that 3 least-significant bits (LSB) would represent a 3-bit value at the start of the -stream. Note that the LSB of the 3-bit value is the LSB of the byte value.

Deflate uses a Huffman tree of 288 Huffman codes (or symbols) where the values:

  • 0 - 255; represent the literal byte values: 0 - 255
  • 256: represents the end of (compressed) stream (or block)
  • 257 - 285 (combined with extra-bits): represent a (size, offset) tuple (or match length) of 3 - 258 bytes
  • 286, 287: are not used (reserved) and their use is considered illegal although the values are still part of the tree

This document refers to this Huffman tree as the literals Huffman tree.

The bits in the encoded bit-stream correspond to values in the literals Huffman tree. If a symbol is found that represents a compression size and offset tuple (or match length code) the bits following the literals symbol contains a distance (Huffman) code. The match length coedes might require additional (or extra) bits to store the length (or size).

The distances Huffman tree contains space for 32 symbols. The distance codes might require additional (or extra) bits to store the distance.

Literal codes

The literal codes consist of:

ValueIdentifierDescription
0x00 – 0xffliteral byte values
0x100end-of-block marker
0 additional bits
0x101Size of 3
0x102Size of 4
0x103Size of 5
0x104Size of 6
0x105Size of 7
0x106Size of 8
0x107Size of 9
0x108Size of 10
1 additional bit
0x109Size of 11 to 12
0x10aSize of 13 to 14
0x10bSize of 15 to 16
0x10cSize of 17 to 18
2 additional bits
0x10dSize of 19 to 22
0x10eSize of 23 to 26
0x10fSize of 27 to 30
0x110Size of 31 to 34
3 additional bits
0x111Size of 35 to 42
0x112Size of 43 to 50
0x113Size of 51 to 58
0x114Size of 59 to 66
4 additional bits
0x115Size of 67 to 82
0x116Size of 83 to 98
0x117Size of 99 to 114
0x118Size of 115 to 130
5 additional bits
0x119Size of 131 to 162
0x11aSize of 163 to 194
0x11bSize of 195 to 226
0x11cSize of 227 to 257
0 additional bits
0x11dSize of 258
Distance codes

The distance codes consist of:

ValueIdentifierDescription
0distance of 1
1distance of 2
2distance of 3
3distance of 4
1 additional bit
4distance of 5 - 6
5distance of 7 - 8
2 additional bits
6distance of 9 - 12
7distance of 13 - 16
3 additional bits
8distance of 17 - 24
9distance of 25 - 32
4 additional bits
10distance of 33 - 48
11distance of 49 - 64
5 additional bits
12distance of 65 - 96
13distance of 97 - 128
6 additional bits
14distance of 129 - 192
15distance of 193 - 256
7 additional bits
16distance of 257 - 384
17distance of 385 - 512
8 additional bits
18distance of 513 - 768
19distance of 769 - 1024
9 additional bits
20distance of 1025 - 1536
21distance of 1537 - 2048
10 additional bits
22distance of 2049 - 3072
23distance of 3073 - 4096
11 additional bits
24distance of 4097 - 6144
25distance of 6145 - 8192
12 additional bits
26distance 8193 - 12288
27distance 12289 - 16384
13 additional bits
28distance 16385 - 24576
29distance 24577 - 32768
other
30-31not used, reserved and illegal but still part of the tree

TODO: complete this section

Additional bits

The additional bits are stored in big-endian (MSB first) and indicate the index into the corresponding array of size values (or base size + additional size).

ValueIdentifierDescription
0 additional bits
0Offset of 1
1Offset of 2
2Offset of 3
3Offset of 4
1 additional bit

TODO: complete this section

Decompression

The decompression in pseudo code:

if( block_header.type == HUFFMANN_FIXED )
{
    initialize the fixed Huffman trees
}

do
{
    read block_header from input stream

    if( block_header.type == UNCOMPRESSED )
    {
        align with next byte
        read and check block_header.size and block_header.size_copy
        read data of block_header.size
    }
    else
    {
        if( block_header.type == HUFFMANN_DYNAMIC )
        {
            read the dynamic Huffman trees (see subsection below)
        }
        loop (until end of block code recognized)
        {
            decode literal/length value from input stream

            if( value < 256 )
            {
                copy value (literal byte) to output stream
            }
            else if value = end of block (256)
            {
                 break from loop
            }
            else (value = 257..285)
            {
                 decode distance from input stream

                 move backwards distance bytes in the output
                 stream, and copy length bytes from this
                 position to the output stream.
            }
        }
    }
}
while( block_header.last_block_flag == 0 );

Adler-32 checksum

Zlib provides a highly optimized version of the algorithm provided below.

uint32_t adler32(
          uint8_t *buffer,
          size_t buffer_size,
          uint32_t previous_key )
{
    size_t buffer_iterator = 0;
    uint32_t lower_word    = previous_key & 0xffff;
    uint32_t upper_word    = ( previous_key >> 16 ) & 0xffff;

    for( buffer_iterator = 0;
         buffer_iterator < buffer_size;
         buffer_iterator++ )
    {
        lower_word += buffer[ buffer_iterator ];
        upper_word += lower_word;

        if( ( buffer_iterator != 0 )
         && ( ( buffer_iterator % 0x15b0 == 0 )
          ||  ( buffer_iterator == buffer_size - 1 ) ) )
        {
            lower_word = lower_word % 0xfff1;
            upper_word = upper_word % 0xfff1;
        }
    }
    return( ( upper_word << 16 ) | lower_word );
}

References