Алгоритм відновлення даних APFS та структура файлової системи
«ApFS» пропонує можливість відновлення файлової системи, включаючи старі або видалені версії файлів. Суперблок контейнера містить посилання на структуру контрольної точки. Контрольна точка посилається на попередні суперблоки контейнера, який містить інформацію в більш старому стані файлової системи. Таким чином, можна відновити кілька минулих станів шляхом аналізу ланцюжка суперблоку контейнера.
- Контейнери та Томи
- Block Header (Заголовок блока)
- Container Superblock
- Volume Superblock (Суперблок тома)
- Checkpoint (Чекпоінт)
- Checkpoint Superblock Descriptor (Дескриптор чекпоінта суперблока)
- Bitmap Structures (Бітова карта або карта тома)
- Таблиці (Tables)
- Зведення таблиць
- Знімки (Snapshots)
- Nodes (вузли)
- Менеджер простору (Space Manager)
- Файл та папка B-дерева
- Extents (Екстенти B-дерева)
- 64-bit inodes (index descriptors) - індексні дескриптори
- Питання та відповіді
- Коментарі
Контейнери та Томи
Структура файлової системи APFS має вигляд b-дерева, де кореневий каталог з даними – це листя всього дерева. Усі гілки зберігають лише посилання на наступний вузол, поки не дійдуть до листя. Файлова система використовує контейнери в якості осередків зберігання. Ці контейнера можуть містити кілька томів. Також він є основним об’єктом для зберігання даних. Для одного тому розмір контейнера повинен бути понад 512 МБ, для двох томів – більше 1024Мб і т.д.
На малюнку нижче подана структура файлової системи «ApFS».
Кожен елемент цієї структури (крім файлу розподілу) починається з 32-байтового заголовка блоку, який містить деяку загальну інформацію про блок. Далі йде тіло файлової системи. Воно складається з наступних елементів:
- 0x01: Суперблок контейнера (Container Superblock);
- 0x02: Вузол (Node);
- 0x05: Менеджер простору (Space manager);
- 0x07: Файл розміщення (Allocation Info File);
- 0x0C: Контрольна точка (Checkpoint);
- 0x0D: Суперблок тома (Volume Superblock).
Контейнери зазвичай точно такі ж, як записи в таблиці розділів GUID (GPT). У них є власний захист від збоїв, і схема розподілу дискового простору. Кожен контейнер містить один або декілька томів, кожен з яких має власний простір імен, набір файлів та каталогів.
Файлова система «ApFS» не підтримує безпосередньо програмний «RAID», але його можна використовувати з томами Apple RAID для підтримки чергування (RAID 0), віддзеркалення (RAID 1) та склеювання (JBOD).
З 64-бітовим індексом томи «ApFS» підтримують до 9 квінтильйонів (1018) файлів.
Нова файлова система від Apple використовує наносекунди для встановлення міток часу. У HFS+ мітки часу були встановлені з точністю до секунди. Це зменшило кількість збоїв при передачі даних та інших файлових операціях.
«ApFS» має вбудовану систему шифрування та використовує системи AES-XTS або AES-CBC, в залежності від пристрою. Користувач може використовувати кілька ключів шифрування для безпеки даних навіть у разі фізичної поломки носія.
Це далеко не повний список нововведень, якими володіє «ApFS».
Розділи які відформатовані в «ApFS», не розпізнаються OS X10.11 Yosemite та більш ранніми версіями операційної системи.
Block Header (Заголовок блока)
Кожна структура файлової системи в «ApFS» починається з заголовка блоку. А сам заголовок починається з контрольної суми. Інша інформація в заголовку містить в собі версію блоку з копією при записі, ідентифікатор блоку та його тип.
Position | Size | Type | ID |
---|---|---|---|
0 | 8 | uint64 | Checksum |
8 | 8 | uint64 | block ID |
16 | 8 | uint64 | Version |
24 | 2 | uint16 | Block type |
26 | 2 | uint16 | Flags |
28 | 4 | uint32 | Padding |
З таблиці ми бачимо, що 1uint = 1 біт, 8 біт= 1 байту, з цього uint 64=8, uint32=4, і uint16 = 2 байтам.
Container Superblock
Суперблок контейнера (Container Superblock) – це вхідна точка в файлову систему. Через структуру файлової системи з контейнерами і гнучкими томами, розподіл необхідно обробляти на рівні контейнера. Суперблок контейнера містить інформацію про розмір блоку, їх кількість та покажчик в менеджері простору для цього завдання. Крім того, в суперблоці зберігаються ідентифікатори (ID) блоків всіх томів. Для зіставлення ідентифікаторів блоків блокам зміщення, зберігається покажчик на карту блоків B-дерева. Це дерево містить записи для кожного тому з його ідентифікатором та зміщенням. Суперблок контейнера – це найвищий рівень файлової системи.
Він має такий вигляд:
Offset (HEX) | Type | Id | Description |
---|---|---|---|
0 | tApFS_COH | Header | Container Object Header |
20 | uint32 | MagicNumber (NXSB) | The value to verify reading a Container Superblock. |
24 | uint32 | BlockSize | Container block size (bytes) |
28 | uint64 | BlocksCount | Number of container blocks |
30 | uint64 | Features | Bitmap for container’s main features |
38 | uint64 | ReadOnlyFeatures | Bitmap for container’s main features (read-only) |
40 | uint64 | IncompatibleFeatures | Bitmap for container’s incompatible features |
48 | tApFS_Uuid | Uuid | Container’s UUID |
58 | tApFS_Ident | NextIdent | Next identifier for new logical or virtual object |
60 | tApFS_Transaction | NextTransaction | Next transaction number |
68 | uint32 | DescriptorBlocks | Number of blocks used by descriptor |
6C | uint32 | DataBlocks | Number of blocks used by data |
70 | tApFS_Address | DescriptorBase | Descriptor base address or physical object identifier with address tree |
78 | int32 | DataBase | Database address or physical object identifier with address tree |
80 | uint32 | DescriptorNext | Next descriptor index |
84 | uint32 | DataNext | Next data index |
88 | uint32 | DescriptorIndex | Index of first valid element in descriptor segment |
8C | uint32 | DescriptorLength | Number of blocks in descriptor segment used by superblock |
90 | uint32 | DataIndex | Index of first valid element in data segment |
94 | uint32 | DataLength | Number of blocks in data segment used by superblock |
98 | tApFS_Ident | SpaceManagerIdent | Identifier for Space Manager logical object |
A0 | tApFS_Ident | ObjectsMapIdent | Identifier for container object map physical object |
A8 | tApFS_Ident | ReaperIdent | Logical object identifier |
B0 | uint32 | ReservedForTesting | |
B4 | uint32 | MaximumVolumes | Maximum possible number o volumes in container |
8 | tApFS_Ident | VolumesIdents[100] | Volume array of virtual object identifiers |
3D8 | uint64 | Counters[32] | Array of counters storing container information |
4D8 | tApFS_BlockRange | BlockedOutOfRange | Physical range of blocks that cannot be used |
4E8 | tApFS_Ident | MappingTreeIdent | Physical object identifier of the tree used to track objects moved from locked storage. |
4F0 | uint64 | OtherFlags | Bitmap of other container’s functions |
4F8 | tApFS_Address | JumpstartEFI | Physical object ID with EFI driver data |
500 | tApFS_Uuid | FusionUuid | Fusion container UUID or zero for non-Fusion containers |
510 | tApFS_BlockRange | KeyLocker | Container key tag location |
50 | uint64 | EphemeralInfo[4] | Field array used to manage ephemeral data |
540 | tApFS_Ident | ReservedForTesting | |
548 | tApFS_Ident | FusionMidleTreeIdent | Fusion devices only |
550 | tApFS_Ident | FusionWriteBackIdent | Fusion devices only |
558 | tApFS_BlockRange | FusionWriteBackBlocks | Blocks used for cache area |
З визначенням типів:
uint8 tApFS_Uuid;
uint64 tApFS_Ident;
uint64 tApFS_Transaction;
int64 tApFS_Address;
uint64 tApFS_BTreeKey;
і
struct tApFS_BlockRange
{
tApFS_Address First; // First block
uint64 Count; // Number of blocks
}
struct tApFS_COH
{
uint64 CheckSum; // Block checksum
tApFS_Ident Ident; // Identifier
tApFS_Transaction Transaction; // Object change transaction number
uint16 Type; // Object type
uint16 Flags; // Object flags
uint32 SubType; // Object subtype
};
з переліком типів об'єктів:
enum eApFS_ObjectType
{
eApFS_ObjectType_01_SuperBlock = 0x0001, //Container superblockа
eApFS_ObjectType_02_BTreeRoot = 0x0002, // B-Tree: root node
eApFS_ObjectType_03_BTreeNode = 0x0003, // B-Tree: non-root node
eApFS_ObjectType_05_SpaceManager = 0x0005, // Space manager
eApFS_ObjectType_06_SpaceManagerCAB = 0x0006, // Space manager: segments’ addresses
eApFS_ObjectType_07_SpaceManagerCIB = 0x0007, // Space manager: segments’ information
eApFS_ObjectType_08_SpaceManagerBitmap = 0x0008, // Free сspace bitmap used by Space manager
eApFS_ObjectType_09_SpaceManagerFreeQueue = 0x0009, // Free space used by Space manager_ (keys - _tApFS_09_SpaceManagerFreeQueue_Key_, values - _tApFS_09_SpaceManagerFreeQueue_Value_)
eApFS_ObjectType_0A_ExtentListTree = 0x000A, // Extents’ list tree (keys – offset beginning extent_tApFS_Address_, value – physical data location _tApFS_BlockRange_)
eApFS_ObjectType_0B_ObjectsMap = 0x000B, // Type – Objects map; subType – Object map record tree (keys - _tApFS_0B_ObjectsMap_Key_, values - _tApFS_0B_ObjectsMap_Value_)
eApFS_ObjectType_0C_CheckPointMap = 0x000C, // Check point map
eApFS_ObjectType_0D_FileSystem = 0x000D, // Volume file system
eApFS_ObjectType_0E_FileSystemTree = 0x000E, // File system tree (keys start from с _tApFS_BTreeKey_, describes key type and value)
eApFS_ObjectType_0F_BlockReferenceTree = 0x000F, // Block reference tree (keys - _tApFS_BTreeKey_, values - _tApFS_0F_BlockReferenceTree_Value_)
eApFS_ObjectType_10_SnapshotMetaTree = 0x0010, // Snapshot meta tree (keys - _tApFS_BTreeKey_, values - _tApFS_10_SnapshotMetaTree_Value_)
eApFS_ObjectType_11_Reaper = 0x0011, // Reaper
eApFS_ObjectType_12_ReaperList = 0x0012, // Reaper List
eApFS_ObjectType_13_ObjectsMapSnapshot = 0x0013, // Objects map snapshot tree (keys - _tApFS_Transaction_, values - _tApFS_13_ObjectsMapSnapshot_Value_)
eApFS_ObjectType_14_JumpStartEFI = 0x0014, // EFI Loader
eApFS_ObjectType_15_FusionMiddleTree = 0x0015, // Fusion devices tree to track SSD cached HDD, blocks (keys - _tApFS_Address_, values - _tApFS_15_FusionMiddleTree_Value_)
eApFS_ObjectType_16_FusionWriteBack = 0x0016, // Fusion devices writeback cache status
eApFS_ObjectType_17_FusionWriteBackList = 0x0017, // Fusion devices writeback cache list
eApFS_ObjectType_18_EncryptionState = 0x0018, // Encryption
eApFS_ObjectType_19_GeneralBitmap = 0x0019, // General Bitmap
eApFS_ObjectType_1A_GeneralBitmapTree = 0x001A, // General Bitmap Tree (keys - uint64, keys - uint64)
eApFS_ObjectType_1B_GeneralBitmapBlock = 0x001B, // General Bitmap Block
eApFS_ObjectType_00_Invalid = 0x0000, // Non-valid as a type or absent subtype
eApFS_ObjectType_FF_Test = 0x00FF // Reserved for testing (never stored on media)
eApFS_ObjectType_FF_Test = 0x00FF // Reserved for testing (never stored on media)
};
enum eApFS_ObjectFlag
{
eApFS_ObjectFlag_Virtual = 0x0000, // Virtual object
eApFS_ObjectFlag_Ephemeral = 0x8000, // Ephemeral object
eApFS_ObjectFlag_Physical = 0x4000, // Physical object
eApFS_ObjectFlag_NoHeader = 0x2000, // Object with no header _tApFS_ContainerObjectHeader_ (for example, Space (bitmap) manager bitmap)
eApFS_ObjectFlag_Encrypted = 0x1000, // Encrypted object
eApFS_ObjectFlag_NonPersistent = 0x0800, // Object with this flag is never saved on media
eApFS_ObjectFlag_StorageTypeMask = 0xC000, // Bitmask (bitmask) for для accessing к object category flags
eApFS_ObjectFlag_ValidMask = 0xF800 // Valid flag bit mask
};
struct tApFS_0B_ObjectsMap_Key
{
tApFS_Ident ObjectIdent; // Object identifier
tApFS_Transaction Transaction; // Transaction number
};
struct tApFS_0B_ObjectsMap_Value
{
uint32 Flags; // Flags
uint32 Size; // Object size in bytes (multiple of containerру block size)
tApFS_Address Address; // Object address
};
struct tApFS_09_SpaceManagerFreeQueue_Key
{
tApFS_Transaction sfqk_xid;
tApFS_Address sfqk_paddr;
};
struct tApFS_09_SpaceManagerFreeQueue_Value
{
uint64 sfq_count;
tApFS_Ident sfq_tree_oid;
tApFS_Transaction sfq_oldest_xid;
uint16 sfq_tree_node_limit;
uint16 sfq_pad16;
uint32 sfq_pad32;
uint64 sfq_reserved;
};
struct tApFS_10_SnapshotMetaTree_Value
{
tApFS_Ident ExtentRefIdent; // Identifier of B-Tree physical object, that stores the extent information
tApFS_Ident SuperBlockIdent; // Superblock identifier
uint64 CreatedTime; // Snapshot creation time (in nanoseconds from midnight 01/01/1970)
uint64 LastModifiedTime; // Snapshot last modified time (in nanoseconds from midnight 01/01/1970)
uint64 iNum;
uint32 ExtentRefTreeType; // Type of B-tree, that stores extent information
uint16 NameLength; // Snapshot name length (including end of line character)
uint8 Name[]; // Snapshot name (ending with 0)
};
struct tApFS_13_ObjectsMapSnapshot_Value
{
uint32 Flags; // Snapshot flags
uint32 Padding; // Reserved (for adjustment)
tApFS_Ident Reserved; // Reserved
};
struct tApFS_15_FusionMiddleTree_Value
{
tApFS_Address fmv_lba;
uint32 fmv_length;
uint32 fmv_flags;
};
Приклад структури файлової системи ApFS:
Volume Superblock (Суперблок тома)
Суперблок тома (Volume Superblock) - існує для кожного тому файлової системи. Він містить назву тому, ідентифікатор та позначку часу. Подібно суперблоку контейнера (Container Superblock), він містить покажчик на карту блоків, який відображає ідентифікатори блоків усунення. Крім того, в суперблоці тома зберігається покажчик на кореневий каталог, який зберігається як вузол.
Offset (HEX) | Type | Id | Description |
---|---|---|---|
0 | tApFS_COH | Header | Container Object Header |
20 | uint32 | MagicNumber (APSB) | A value that can be used to verify reading an instance of Volume Superblock |
24 | uint32 | IndexInSuperBlock | Object identifier index of this volume in the container volume array |
28 | uint64 | Features | Bitmap of the main features used by the volume |
30 | uint64 | ReadOnlyFeatures | Bitmap of the main features (read only) used by the volume |
38 | uint64 | IncompatibleFeatures | Bitmap of incompatible volume features |
40 | uint64 | LastUnmountTime | Time of the last volume dismount (in nanoseconds from midnight of 01/01/1970) |
48 | uint64 | ReservedBlocksCount | The number of blocks reserved to allocate the volume |
50 | uint64 | QuotaBlocksCount | The maximum number of blocks this volume can allocate |
58 | uint64 | AllocatedCount | The number of blocks currently allocated to the file system of this volume |
60 | uint8 | MetaCryptoState[20] | Information about the key used to encrypt metadata for this volume (wrapped_meta_crypto_state_t instance) |
74 | uint32 | RootTreeType | Type of the root folder tree (typically: type of (eApFS_ObjectFlag_Virtual << 16) \ eApFS_ObjectType_02_BTreeRoot, subtype of eApFS_ObjectType_0E_FileSystemTree) |
78 | uint32 | ExtentRefTreeType | Type of extent binding tree (typically: type of (eApFS_ObjectFlag_Physical << 16) \ eApFS_ObjectType_02_BTreeRoot, subtype of OBJECT_TYPE_BLOCKREF) |
7C | uint32 | SnapshotMetaTreeType | Snapshot metadata tree type (typically: type of (eApFS_ObjectFlag_Physical << 16) \ eApFS_ObjectType_02_BTreeRoot, subtype of OBJECT_TYPE_BLOCKREF) |
80 | tApFS_Ident | ObjectsMapIdent | Identifier of the physical object of the volume object map |
88 | tApFS_Ident | RootTreeIdent | Identifier of the virtual object of the root folder tree |
90 | tApFS_Ident | ExtentRefTreeIdent | Identifier of the physical object of the extent link tree |
98 | tApFS_Ident | SnapshotMetaTreeIdent | Identifier of the snapshot metadata tree virtual object |
A0 | tApFS_Transaction | RevertToXid | Transaction number of the snapshot to which the volume will be returned |
A8 | tApFS_Ident | RevertToSuperBlock | Identifier of the physical object of the VS to which the volume will return |
B0 | uint64 | NextObjectIdent | The next identifier to be assigned to the file system object in the volume. |
8 | uint64 | NumberOfFiles | The number of regular files in the volume |
C0 | uint64 | NumberOfDirectories | The number of folders in the volume |
C8 | uint64 | NumberOfSymbolicLinks | Number of symbolic links in the volume |
D0 | uint64 | NumberOfOtherObjects | Number of other objects in the volume (not including x0B8_NumberOfFiles, x0C0_NumberOfDirectories and x0C8_NumberOfSymbolicLinks) |
D8 | uint64 | NumberOfSnapshots | Number of snapshots in this volume |
E0 | uint64 | TotalBlocksAllocated | Total number of blocks allocated by this volume |
E8 | uint64 | TotalBlocksFreed | Total number of blocks freed by this volume |
F0 | tApFS_Uuid | Uuid | |
100 | uint64 | LastModifiedTime | Time of the last change of this volume (in nanoseconds from midnight 01/01/1970) |
108 | uint64 | Flags | |
110 | tApFS_0D_FSM | FormattedBy | Information about the software that created this volume |
140 | tApFS_0D_FSM | ModifiedBy[8] | Information about the software that changed this volume |
2C0 | uint8 | VolumeName[256] | UTF-8 String Zero Volume Name |
3C0 | uint32 | NextDocumentIdent | Next identifier of the document to be assigned (stored in the extended field APFS_0E_TYPE_DOCUMENT_ID of the document) |
3C4 | uint16 | Role | Volume Role Bitmap |
3C6 | uint16 | Reserved | |
3C8 | tApFS_Transaction | RootToXid | Snapshot transaction number for non-root or zero for root |
3D0 | tApFS_Ident | EncryptStateIdent | Current state of encryption or decryption, or zero if no encryption |
Детальна ілюстрація «APFS»:
Checkpoint (Чекпоінт)
Чекпоінт - це тимчасовий стан контейнера. Кожна контрольна точка ініціалізується в суперблоці контейнера, і поточний стан зазвичай є останнім. Чекпоінт включає метадані як контейнера, так і тома. Точки відновлення та знімки схожі один на одного. Основна відмінність між чекпоінтами та моментальним знімком полягає в можливості користувача відновити файлову систему зі збережених моментальних знімків за допомогою API файлової системи.
Checkpoint Superblock Descriptor (Дескриптор чекпоінта суперблока)
Цей блок містить інформацію про структуру метаданих в «ApFS» і є попереднім блоком дескрипторів. Найбільш важливою інформацією в цьому блоці є розташування Bitmap Structure (BMS), колишнього файлу розподілу в HFS+.
Дескриптор суперблоку контрольної точки:
Bitmap Structures (Бітова карта або карта тома)
Записи про використані та невикористані блоки. Існує тільки одна карта тома, яка покриває весь контейнер і є спільною для всіх томів файлової системі. «ApFS» використовує набір блоків для зберігання Карти тома (Bitmap Structures).
В «ApFS» карта є загальною для всіх томів в контейнері. У кожному томі вказані котирування блоку в контейнері, але самі блоки не перебувають в виділених областях. Посилання на карту тома лежить в дескрипторі чекпоінта суперблоку (CSBD), в якому знаходитися інформація про самий верхній рівень структури, дескриптори бітової карти (BMD). На малюнку нижче показана базова структура цієї карти. Вона розбита по рівнях, де BMD знаходитися зверху та встановлює межі. Внизу лежать «Bitmap Blocks» (BMB), які відстежують блоки в контейнері. Один байт в BMB відстежує вісім блоків, кожен біт яких забезпечує статус розподілу. Кожен біт - це статус окремого блоку.
Таблиці (Tables)
Таблиці використовуються в каталозі та екстентах B-дерева, списку томів та карті ідентифікатора об'єкта.
Поле типу таблиці складається з 2 байтів, розташованих в блоці зі зміщенням 0x20 безпосередньо після заголовка вузла. Існує вісім таблиць від 0 до 7. Наступні 2 байта забезпечують рівень таблиці від 0 і вище. У таблиці другого рівня будуть записи, які стосуються базової таблиці першого рівня. А таблиці нульового рівня відносяться до блоків, які часто містять метадані файлів.
Типи таблиць розрізняються за структурою, але заголовок таблиці для всіх типів має 24-байтовий вид.
На малюнку представлений зразок структури заголовка таблиці:
Опис значень полів в структурі заголовка:
Offset (HEX) | Field | Data type | Description |
---|---|---|---|
20 | tableType | uint16 | Possible values 0-7. It’s a table type 1 |
22 | tableLevel | uint16 | Indicates a level of a B-Tree. |
24 | tableRecords | uint16 | Number of records in the table |
26 | Unknown 1 | uint16 | |
28 | Unknown 2 | uint16 | |
2A | tableIndexSize | uint16 | Size of the table index area. |
2C | tableKeyAreaSize | uint16 | Size of the table key area. |
2E | tableFreeSpaceSize | uint16 | Size of the free area. The table data area ends at offset 0x38+tableIndexSize+tableKeyAreaSize+tableFreeSpaceSize. 0x38 + 0x80 + 0x170 + 0xd58. |
30 | Unknown 3 | uint16 | |
32 | Unknown 4 | uint16 | |
34 | Unknown 5 | uint16 | |
36 | Unknown 6 | uint16 |
Тут показаний загальний макет різних таблиць:
Не всі елементи на зображенні використовуються в усіх таблицях. На малюнку показаний повний блок з заголовком блоку верхнього вузла. Інша частина блоку складає таблицю.
Відразу після заголовка таблиці йде індекс запису. Їх є 2 типи. Один з двома значеннями: зміщенням в ключах та зміщенням в розділі даних, для кожного з Uint16. Другий використовує 4 значення Uint16 зі зміщенням і довжиною як для ключа, так і для розділів даних. Індекс запису таблиці містить інформацію про ключі та записи даних в таблиці. Ще одна відмінність між типами таблиць - це використання нижніх колонтитулів.
У таблицях 1, 3, 5 і 7, в кінці блоку використовується нижній колонтитул розміром 0x28 байтів. У цих таблицях все зміщення даних відносяться до зміщення 0xFD8, а нижній колонтитул містить різні значення, специфічні для типу таблиці. Інші типи таблиць не мають нижнього колонтитула, і всі посилання на вміст розділу даних відносяться до кінця блоку.
У B-деревах з кількома рівнями, таблиці 1, 3, 5 та 7 знаходяться на самому верхньому рівні, оскільки вони мають нижній колонтитул. Нижній колонтитул використовується для зберігання інформації про повне B-дерево. Одне зі значень в нижньому колонтитулі - це загальна кількість записів в структурі цього дерева.
Визначення таблиці починається зі зсуву 0x20 в блоці. Тут вказано тип таблиці, кількість рядків, розмір ключового розділу та проміжок між ключем і розділом даних. Після властивостей таблиці, визначення рядків і стовпців описуються зміщення 0x38. Таблиця містить заголовок, визначення записів, розділи ключів і даних. У деяких типів таблиць також є нижній колонтитул. Тема починається зі зсуву 0x20 і має довжину 0x18 байт. Тема цього типу таблиці починається з 16-бітового значення, яке представляє тип таблиці. За нею йдуть два байти, які представляють рівень в B-дереві, на якому використовується таблиця. Два наступних байта представляють кількість рядків в таблиці. Довжина запису визначення сканування знаходиться в 0x2A, за яким йде Uint16, який записує довжину ключового розділу. Далі, йде розрив між ключем та розділом даних. Нижній колонтитул таблиці завжди дорівнює 0x28 байтам і завжди займає кінець блоку. А індекси таблиці мають 4 або 8 байтів кожний. На 8-байтових індексах, два перших «Uint16» - це зміщення і довжина ключового запису. Наступні два «Uint16» - це зміщення і довжина запису даних в таблиці. Таблиці з 4-байтовими індексами мають два значення Uint16, які містять зміщення ключа та записів даних. Довжина даних у двох записах визначена. У таблицях з нижнього колонтитула зміщення запису даних щодо початку нижнього колонтитула - (0x28 байт). А для інших типів таблиць це зміщення відноситься до кінця блоку.
Більшість значень, що стосуються заголовка і нижнього колонтитула таблиці, зрозумілі для читання типу таблиці. Зсув 0x18 в нижньому колонтитулі (зміщення 0xFF в блоці 4 Кб) - це кількість записів в таблиці в усих базових таблицях (якщо це таблиця з рівнем вище 0, по зсуву 0x22). Зсув 0x20 в нижньому колонтитулі - це номер наступного запису в таблиці.
Таблиця 0
Таблиця 0 типу лежить в структурі каталогу B-дерева між вузлами листя і кореневим вузлом. Значення Невідомо (Unknown) з 3 по 6 представлені у вигляді зсуву і довжини ключа. Зміщення даних і довжини наступного доступного запису. Якщо вільних індексних записів немає, то зміщення встановлюються на «0xFFFF» та довжину «0x00».
Записи в таблиці представляють собою чотири значення «Uint16». Перші 2 - це зміщення та довжина значення в ключовому розділі, а наступні - це зміщення та значення вмісту в розділі даних.
Прикладом таблиці 0 типу може бути ідентифікатор вузла каталогу, іменний ключ в розділі ключів та ідентифікатором об'єкта в розділі даних. У цій таблиці немає нижнього колонтитула.
Таблиця 1
Перша таблиця має нижній колонтитул, а індекс таблиці містить чотири 16-бітних значень, де перші 2 значення представляють собою зсув запису в ключовому розділі, та довжину запису. Наступні 2 значення забезпечують зсув запису в розділі даних, та її довжину. Ця таблиця часто зустрічається як в структурі каталогу B-дерева, так і в дереві екстентів для вузла верхнього рівня. Прикладом є значення: «Parent ID» та ім'я ключа (ім'я файлу або папки в структурі каталогу, і початковий номер блоку в B-дереві екстентів), ідентифікатор об'єкта при використанні в якості кореневого вузла в структурі каталогу, або номер блоку, коли використовується в дереві екстентів.
Приклади цієї таблиці наведені нижче:
Таблиця 2
Друга таблиця. Спочатку ця таблиця ідентична з попередньою, але вона не має нижнього колонтитула. Цей тип таблиці дуже часто зустрічається в кінцевих вузлах структури каталогу B-дерева, де ключовий розділ представлений з «Parent ID» та ім'ям ключа.
Таблиця 3
Третя таблиця ідентична попередній. Індекс таблиці такий же, як у першій таблиці. Типові значення залежать від структури в якій вони використовуються. У структурі каталогу B-дерева та дереві екстентів, ця таблиця часто використовується як вузол верхнього рівня в невеликих обсягах, де кореневим вузлом одночасно є кореневий та листовий вузол. В такому прикладі використання, ключовий записом може бути «Parent ID». Іменний ключ та запис даних можуть бути файлом метаданих з великим варіюванням розміру.
Інші записи таблиці - це ідентифікатор об'єкта «Object ID» і його тип в ключового запису, з екстенти інформації про файли та записи даних. Третя таблиця має нижній колонтитул.
Приклад таблиці:
Таблиця 4
Четверта таблиця дещо відрізняється від попередніх. У таблиці немає нижнього колонтитула, а індекс таблиці має тільки 2 значення: зсув запису в ключовому розділі та значення для розділу даних. Довжина вмісту фіксована і складає 16 байтів в ключовому розділі, та 8 байт в розділі даних. Зміщення в розділі даних відносяться до кінця блоку.
Таблиця 5
П'ята таблиця схожа на четверту. Єдина відмінність полягає в тому, що у цього типу є нижній колонтитул, а всі зсуви даних починаються з «offset-0x28» (початок нижнього колонтитула). Записи в ключовому розділі становлять 16 байтів та 8 байт, в розділі даних. Цей тип таблиці найчастіше спостерігається на вузлах верхнього рівня, в структурі каталогу B-дерева та в великих контейнерах з багаторівневими деревами.
Таблиця 6
Шоста таблиця також схожа на четверту. Індекс таблиці має тільки зміщення до вмісту в розділі ключів та даних, але не її довжину. Довжина визначена заздалегідь. Кожен запис становить 16 байтів. Для цього типу таблиці немає нижнього колонтитула. Ця таблиця часто зустрічається в кінцевих вузлах структури каталогу B-дерева. Типовий вміст розділу ключа включає в себе ідентифікатор об'єкта та ID «Volume Checkpoint Superblock ID», в той час як в розділенні даних зазвичай записується їх розмір та номер блоку.
Таблиця 7
Таблиця 7 схожа на 6. Єдиною відмінністю є нижній колонтитул, який містить інформацію, аналогічну описаній Таблиці 1. Цей тип таблиці спостерігається в широкому діапазоні структур і часто зустрічається на самих верхніх рівнях багатошарової структури, або в одношарових структурах, таких як опис тома.
Наприклад,
Зведення таблиць
В даній таблиці показані основні властивості різних типів таблиць:
Type | Footer | Key section offset | Key section length | Data section offset | Data section length | Key length | Data length |
---|---|---|---|---|---|---|---|
0 | NO | uint16 | uint16 | uint16 | uint16 | Varies | Possible |
1 | YES | uint16 | uint16 | uint16 | uint16 | Varies | Possible |
2 | NO | uint16 | uint16 | uint16 | uint16 | Varies | Possible |
3 | YES | uint16 | uint16 | uint16 | uint16 | Varies | Possible |
4 | NO | uint16 | uint16 | 16 bytes | 8 bytes | ||
5 | YES | uint16 | uint16 | 16 bytes | 8 bytes | ||
6 | NO | uint16 | uint16 | 16 bytes | 16 bytes | ||
7 | YES | uint16 | uint16 | 16 bytes | 16 bytes |
Одним з найбільш важливих блоків в структурі каталогу B-дерева є кореневий вузол, який є найвищим рівнем в структурі папок. Цей вузол використовує ключі пошуку змінної довжини. Однією з поліпшених функцій «ApFS» є швидкий пошук в каталогах. Одне зі значень, яке тісно пов'язане з цією функцією, це кількість всіх записів в структурі дерева, розташованої в нижньому колонтитулі таблиці.
У кореневого вузла структури B-дерева є 2 варіанти вибору таблиці, оскільки в обох є кінцеві рядки. Таблиця 3, як кореневий вузол, спостерігається тільки в невеликих контейнерах з невеликою кількістю файлів, де кореневий вузол також є індексним та листовим вузлами.
У карті об'єктів для кореневого вузла використовується тільки Таблиця 5, за винятком дуже маленьких структур, де може зустрічатися Таблиця 7.
Інтерпретація таблиць показує, що таблиці 0 та 2 мають однакові значення. Те ж саме спостерігається між таблицями 1 та 3. Ці таблиці мають різне призначення залежно від того, в якій структурі вони знаходяться.
Знімки (Snapshots)
Снепшоти (Snapshots) - це знімки файлової системи тома, тільки для читання. Операційна система може використовувати ці знімки для більш ефективної процедури резервного копіювання. Завдяки ним Time Machine буде працювати швидше. І завдяки підтримці миттєвих образів «Time Machine», більше не потрібно зберігати декілька повних копій файлу на диск - вона може просто відстежувати певні зміни. Наприклад, якщо ви редагуєте файл, зміна з використанням HFS+, він зберігає дві копії файлу: в першому записані нові зміни, а другий, на випадок якщо ви захочете повернутися до попереднього стану. У «APFS» зберігається тільки вихідний файл та записуються відмінності між вихідним файлом та будь-якими оновленими версіями, займаючи менше місця на диску. Як і у випадку з поліпшеннями в Fusion Drive, інформація займає менше місця на диску.
Хоча «ApFS» і значно поступається за своїми можливостями 128-бітній ZFS, яка підтримується Linux, FreeBSD та іншими безкоштовними ОС, але з боку Apple це крок у правильному напрямку.
Як згадувалося вище, Apple довгий час намагалася перенести ZFS на OS X. Пізніше OpenZFS був реалізований для OS X та MacZFX.
Nodes (вузли)
Вузли - це гнучкі контейнери, які використовуються для зберігання різних видів записів. Вони можуть бути частиною B-дерева або існувати самі по собі. Вузли можуть містити записи гнучкого або фіксованого розміру. Вузол починається зі списку покажчиків на ключі входу та запису входу. Таким чином, для кожного запису вузол містить заголовок запису на початку вузла, ключ входу в середині вузла і запис входу в кінці вузла.
position | size | type | ID |
---|---|---|---|
0 | 4 | uint32 | alignment |
4 | 4 | uint32 | ENTRY_COUNT |
10 | 2 | uint16 | HEAD_SIZE |
16 | 8 | entry | meta_entry |
24 | ... | entry | entries (repeat entry_count times) |
Структура заголовка вузла (Node header):
Offset | field | Data type | Comments |
---|---|---|---|
0 | Checksum | Uint64 | Fletchers Checksum Algorithm |
8 | ID | Uint64 | Object-ID or Block# |
10 | Checkpoint | Uint64 | |
18 | Unknown | Uint16 | Possible level in B-Tree |
1A | Unknown | Uint16 | All observations show value 0x4000 |
1C | Unknown | Uint16 | Flag? |
1E | Unknown | Uint16 | Often seen value 0x0b, 0x0e and 0x0f |
Менеджер простору (Space Manager)
«Space Manager» (Менеджер простору) використовується для управління виділеними блоками в контейнері «ApFS». Зберігає кількість вільних блоків та покажчик на файли інформації про розміщення.
position | size | type | ID |
---|---|---|---|
0 | 4 | uint32 | block size |
16 | 8 | uint64 | totalblocks |
40 | 8 | uint64 | freeblocks |
144 | 8 | uint64 | prev_allocationinfofile_block |
352 | 8 | uint64 | allocationinfofile_block |
Allocation info file (Інформаційний файл розподілу)
Файл розподілу працює як відсутній заголовок. Тут зберігаються довжина файлів розміщення, версія і його зміщення.
position | size | type | ID |
---|---|---|---|
4 | 4 | uint32 | alloc_file_length |
8 | 4 | uint32 | alloc_file_version |
24 | 4 | uint32 | TOTAL_BLOCKS |
28 | 4 | uint32 | free_blocks |
32 | 4 | uint32 | allocationfile_block |
Файл та папка B-дерева
Записи всіх файлів і папок на томі. Вони виконують ту ж роль, що і файли каталогу в «HFS+».
Extents (Екстенти B-дерева)
Окреме B-дерево всіх екстентів тома. Екстенти - це посилання на вміст файлу з інформацією про те, де починається вміст даних, і про їх довжину в блоках. Файл з деяким вмістом матиме як мінімум один екстент. А фрагментований файл буде мати декілька екстентів. Дерево екстентів - це окрема структура.
У кожного запису файлу, екстенти визначаються для кожного з цих файлів в B-дереві. Ця окрема структура екстентів є частиною функції миттєвого знімка.
64-bit inodes (index descriptors) - індексні дескриптори
64-бітові inodes значно збільшують простір імен в порівнянні з 32-бітними ідентифікаторами в «HFS+». 64-розрядна файлова система «ApFS» підтримує понад 9 квінтильйонів файлів на кожному томі. Як сказав Білл Гейтс, цього має вистачити на всіх.
«ApFS» пропонує можливість відновлення певних станів файлової системи, включаючи старі або видалені версії файлів. Суперблок контейнера містить посилання на структуру контрольної точки. Контрольна точка посилається на попередній суперблок контейнера, який містить інформацію в більш старому стані файлової системи. Таким чином, можна відновити декілька старих станів шляхом аналізу ланцюжка суперблоку контейнера.
1. APFS надає підтримку для швидкого клонування файлів та папок, що дозволяє значно зробити процес резервного копіювання швидшим.
2. APFS має підтримку для декількох розділів на одному диску, що дозволяє користувачам просто розділяти свої файли на різні розділи.
3. APFS має систему запобігання помилок, яка автоматично виправляє помилки, якщо такі сталися.
4. APFS має вбудовану підтримку для структурування файлів, так як тепер вона підтримує структурування файлів, яке дозволяє користувачам легко знайти те, що вони шукають.
1. Файлова система APFS працює швидше ніж попередня система HFS+.
2. Ця файлова система має підтримку для бездротового з'єднання, такого як AirDrop, iCloud Drive та Time Machine.
3. APFS має підтримку для командного рядка, що дозволяє користувачам легко налаштувати та налагоджувати свої файли.
4. APFS підтримує знев'язування томів, яке дозволяє користувачам розділяти свої файли на декілька томів, які можна монтувати та знемонтувати.
5. APFS має підтримку для криптографічних томів, які дозволяють користувачам шифрувати свої файли.
6. APFS має підтримку для спрощення резервного копіювання, яке дозволяє користувачам легко створювати резервні копії своїх файлів.