error
Регистрация

APFS: алгоритм восстановления данных файловой системы и ее структура

Рубрика: «Личное»
Автор: Hetman Software
Опубликовано: 17.11.2020 в 23:02:48

Суперблок контейнера содержит ссылку на структуру контрольной точки. Контрольная точка ссылается на предыдущий суперблок контейнера, который содержит информацию в более старом состоянии файловой системы. Таким образом, можно восстановить несколько старых состояний путем анализа цепочки суперблока контейнера.

Контейнеры и Тома

Структура файловой системы 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 X 10.11 Yosemite и более ранними версиями операционной системы.

Block Header (Заголовок блока)

Каждая структура файловой системы в «ApFS» начинается с заголовка блока. А сам заголовок начинается с контрольной суммы. Другая информация в заголовке включает в себя версию блока с копией при записи, идентификатор блока и его тип.

Из таблицы мы видим, что 1uint = 1 бит, 8 бит = 1 байту, из этого uint64 = 8, uint32 = 4, и uint16 = 2 байтам.

Container Superblock

Суперблок контейнера (Container Superblock) – это входная точка в файловую систему. Из-за структуры файловой системы с контейнерами и гибкими томами, распределение необходимо обрабатывать на уровне контейнера. Суперблок контейнера содержит информацию о размере блока, их количестве и указателях в менеджере пространства для этой задачи. Кроме того, в суперблоке хранятся идентификаторы (ID) блоков всех томов. Для сопоставления идентификаторов блоков блокам смещения, сохраняется указатель на карту блоков B-дерева. Это дерево содержит записи для каждого тома с его идентификатором и смещением. Суперблок контейнера – это самый высокий уровень файловой системы.

С определением типов:

uint8  tApFS_Uuid;
uint64 tApFS_Ident;
uint64 tApFS_Transaction;
int64  tApFS_Address;
uint64 tApFS_BTreeKey;

и

struct tApFS_BlockRange
{
    tApFS_Address       First;          // Первый блок
    uint64              Count;          // Количество блоков
}
struct tApFS_COH
{
    uint64              CheckSum;       // Контрольная сумма блока
    tApFS_Ident         Ident;          // Идентификатор
    tApFS_Transaction   Transaction;    // Object change transaction number
    uint16              Type;           // Тип объекта
    uint16              Flags;          // Флаги объекта
    uint32              SubType;        // Подтип объекта
};

с перечнем типов объектов:

enum eApFS_ObjectType
{
    eApFS_ObjectType_01_SuperBlock            = 0x0001, //Суперблок контейнера
    eApFS_ObjectType_02_BTreeRoot             = 0x0002, // Би-дерево: узловой элемент
    eApFS_ObjectType_03_BTreeNode             = 0x0003, // Би-дерево: лист
    eApFS_ObjectType_05_SpaceManager          = 0x0005, // Менеджер пространства
    eApFS_ObjectType_06_SpaceManagerCAB       = 0x0006, // Менеджер пространства: адреса сегментов
    eApFS_ObjectType_07_SpaceManagerCIB       = 0x0007, // Менеджер пространства: информация сегментов
    eApFS_ObjectType_08_SpaceManagerBitmap    = 0x0008, // Карта свободного пространства используемая Менеджером пространства
    eApFS_ObjectType_09_SpaceManagerFreeQueue = 0x0009, // Свободное место используемое менеджером пространства_ (ключи - _tApFS_09_SpaceManagerFreeQueue_Key_, значения - _tApFS_09_SpaceManagerFreeQueue_Value_)
    eApFS_ObjectType_0A_ExtentListTree        = 0x000A, // Дерево списка экстентов (ключи – смещение начального экстента_tApFS_Address_, значение – физическое расположение данных _tApFS_BlockRange_)
    eApFS_ObjectType_0B_ObjectsMap            = 0x000B, // Тип – Карта обьектов; subType – Дерево записей карты обьектов (ключи - _tApFS_0B_ObjectsMap_Key_, значения - _tApFS_0B_ObjectsMap_Value_)
    eApFS_ObjectType_0C_CheckPointMap         = 0x000C, // Карта контрольных точек (чекпоинтов)
    eApFS_ObjectType_0D_FileSystem            = 0x000D, // Файловая система тома
    eApFS_ObjectType_0E_FileSystemTree        = 0x000E, // Дерево файловой системы (ключи начинаются с _tApFS_BTreeKey_, описывает тип и значение ключа)
    eApFS_ObjectType_0F_BlockReferenceTree    = 0x000F, // Дерево ссылок на блоки (ключи - _tApFS_BTreeKey_, значения - _tApFS_0F_BlockReferenceTree_Value_)
    eApFS_ObjectType_10_SnapshotMetaTree      = 0x0010, // Дерево снимков (ключи - _tApFS_BTreeKey_, значения - _tApFS_10_SnapshotMetaTree_Value_)
    eApFS_ObjectType_11_Reaper                = 0x0011, // Reaper
    eApFS_ObjectType_12_ReaperList            = 0x0012, // Reaper List
    eApFS_ObjectType_13_ObjectsMapSnapshot    = 0x0013, // Дерево снимков карты обьектов (ключи - _tApFS_Transaction_, значения - _tApFS_13_ObjectsMapSnapshot_Value_)
    eApFS_ObjectType_14_JumpStartEFI          = 0x0014, // EFI Загрузчик
    eApFS_ObjectType_15_FusionMiddleTree      = 0x0015, // Дерево объединённых устройств для отслеживания блоков жестких дисков, кэшированных SSD (ключи - _tApFS_Address_, значения - _tApFS_15_FusionMiddleTree_Value_)
    eApFS_ObjectType_16_FusionWriteBack       = 0x0016, // Состояние кэша обратной записи объединённых устройств
    eApFS_ObjectType_17_FusionWriteBackList   = 0x0017, // Список кэша обратной записи объединённых устройств
    eApFS_ObjectType_18_EncryptionState       = 0x0018, // Шифрование
    eApFS_ObjectType_19_GeneralBitmap         = 0x0019, // General Bitmap
    eApFS_ObjectType_1A_GeneralBitmapTree     = 0x001A, // Дерево General Bitmap (keys - uint64, keys - uint64)
    eApFS_ObjectType_1B_GeneralBitmapBlock    = 0x001B, // Блок General Bitmap
    eApFS_ObjectType_00_Invalid               = 0x0000, // Недействителен как тип или отсутствует как подтип
    eApFS_ObjectType_FF_Test                  = 0x00FF  // Зарезервировано для тестирования (никогда не сохраняется на носителе)
    eApFS_ObjectType_FF_Test                  = 0x00FF  // Зарезервировано для тестирования (никогда не сохраняется на носителе)
};

enum eApFS_ObjectFlag
{
    eApFS_ObjectFlag_Virtual         = 0x0000, // Виртуальный объект
    eApFS_ObjectFlag_Ephemeral       = 0x8000, // Логический объект
    eApFS_ObjectFlag_Physical        = 0x4000, // Физический объект
    eApFS_ObjectFlag_NoHeader        = 0x2000, // Объект без заголовка _tApFS_ContainerObjectHeader_ (например, Карта (bitmap) менеджера пространства)
    eApFS_ObjectFlag_Encrypted       = 0x1000, // Зашифрованный объект
    eApFS_ObjectFlag_NonPersistent   = 0x0800, // Объект из этим флагом никогда не сохраняется на носителе
    eApFS_ObjectFlag_StorageTypeMask = 0xC000, // Битовая (bitmask) маска для доступа к флагам категорий обьектов
    eApFS_ObjectFlag_ValidMask       = 0xF800  // Действительный флаг битовой маски
};

struct tApFS_0B_ObjectsMap_Key
{
    tApFS_Ident       ObjectIdent; // Идентификатор объекта
    tApFS_Transaction Transaction; // Номер транзакции
};

struct tApFS_0B_ObjectsMap_Value
{
    uint32       Flags;    // Флаги
    uint32       Size;     // Размер объекта в байтах (кратный размеру блока контейнера)
    tApFS_Address 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;    // Идентификатор физического объекта Би-дерева, в котором хранится информация об экстенте
    tApFS_Ident SuperBlockIdent;   // Идентификатор суперблока
    uint64      CreatedTime;       // Время создания снимка (в наносекундах с полуночи 01/01/1970)
    uint64      LastModifiedTime;  // Время изменения снимка (в наносекундах с полуночи 01/01/1970)
    uint64      iNum;
    uint32      ExtentRefTreeType; // Тип Би-дерева, в котором хранится информация об экстентах
    uint16      NameLength;        // Длинна имени снимка (включая символ конца строки)
    uint8       Name[];            // Имя снимка (заканчивается на 0)
};

struct tApFS_13_ObjectsMapSnapshot_Value
{
    uint32      Flags;    // Флаги снимков
    uint32      Padding;  // Зарезервировано (для корректировки)
    tApFS_Ident Reserved; // Зарезервировано
};

struct tApFS_15_FusionMiddleTree_Value
{
    tApFS_Address fmv_lba;
    uint32        fmv_length;
    uint32        fmv_flags;
};

Пример структуры файловой системы ApFS:

Volume Superblock (Суперблок тома)

Суперблок тома (Volume Superblock) – существует для каждого тома в файловой системе. Он содержит название тома, идентификатор и отметку времени. Подобно суперблоку контейнера (Container Superblock), он содержит указатель на карту блоков, которая отображает идентификаторы блоков на их смещения. Кроме того, в суперблоке тома хранится указатель на корневой каталог, который хранится как узел.

Подробная иллюстрация «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-дерева, списке томов и карте идентификатора объекта.

Таблицы, используемые в «ApFS», представляют собой небольшие одноблочные «базы данных» с несколько иным назначением в структурах файловой системы. Поле типа таблицы состоит из 2 байтов, расположенных в блоке со смещением 0x20 непосредственно после заголовка узла. Существует восемь таблиц от 0 до 7. Последующие 2 байта обеспечивают уровень таблицы от 0 и выше. В таблице второго уровня будут записи, относящиеся к базовой таблице первого уровня. А таблицы нулевого уровня относятся к блокам, которые часто содержат метаданные файлов.

Типы таблиц различаются по структуре, но заголовок таблицы для всех типов имеет 24-байтовый вид.

На рисунке представлен образец структуры заголовка таблицы:

Здесь показан общий макет различных таблиц:

Не все элементы на картинке используются во всех таблицах. На рисунке показан полный блок с заголовком блока верхнего узла. Остальная часть блока составляет таблицу.

Сразу после заголовка таблицы идет индекс записи. Их есть 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) c 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» и его тип в ключевой записи, с экстентами информации о файлах и записями данных. 3 таблица имеет нижний колонтитул.

Пример таблицы:

Таблица 4

4 таблица несколько отличается от предыдущих. В таблице нет нижнего колонтитула, а индекс таблицы имеет только 2 значения: смещение записи в ключевом разделе и 1 значение для раздела данных. Длина содержимого фиксирована и составляет 16 байтов в ключевом разделе и 8 байт в разделе данных. Смещения в разделе данных относятся к концу блока.

Таблица 5

5 таблица похожа на 4. Единственное отличие состоит в том, что у этого типа есть нижний колонтитул, и все смещения данных начинаются с «offset-0x28» (начало нижнего колонтитула). Записи в ключевом разделе составляют 16 байтов и 8 байт в разделе данных. Этот тип таблицы чаще всего наблюдается на узлах верхнего уровня в структуре каталога B-дерева и в больших контейнерах с многоуровневыми деревьями.

Таблица 6

6 таблица тоже похожа на 4. Индекс таблицы имеет только смещение к содержимому в разделе ключей и данных, но не ее длину. Длинна определена предварительно. Каждая запись составляет 16 байтов. Для этого типа таблицы нет нижнего колонтитула. Эта таблица часто встречается в конечных узлах структуры каталога B-дерева. Типичное содержимое раздела ключа включает в себя идентификатор объекта и ID Тома Чекпоинта Суперблока «Volume Checkpoint Superblock ID», в то время как в разделе данных обычно записывается их размер и номер блока.

Таблица 7

7 Таблица похожа на 6-ю. Единственным отличием является нижний колонтитул, который содержит информацию, аналогичную описанной для 1 таблицы. Этот тип таблицы наблюдается в широком диапазоне структур и часто встречается на самых верхних уровнях многослойной структуры или в однослойных структурах, таких как описание тома.

Пример

Моментальные снимки (Snapshots)

Моментальные снимки – это снимки файловой системы тома только для чтения. Операционная система может использовать эти снимки для более эффективной процедуры резервного копирования. Благодаря им «Time Machine» будет работать быстрее. И благодаря поддержке мгновенных образов «Time Machine», больше не нужно сохранять несколько полных копий файла на диск – она может просто отслеживать определенные изменения. Например, если вы редактируете файл, изменение с использованием HFS +, он сохраняет две копии файла, в первом записаны новые изменения, и второй на случай, если вы захотите вернуться к прежнему виду. В «APFS» сохраняется только исходный файл и записываются различия между исходным файлом и любыми обновленными версиями, занимая меньше места на диске. Как и в случае с улучшениями в «Fusion Drive», информация занимает меньше места на диске.

Хотя «ApFS» и значительно уступает по своим возможностям 128-битной ZFS, которая поддерживается Linux, FreeBSD и другими бесплатными ОС, но со стороны Apple это шаг в правильном направлении.

Как упоминалось выше, Apple долгое время пыталась перенести ZFS на OS X. Позже OpenZFS был реализован для OS X (O3X) и MacZFX.

Nodes (узлы)

Узлы – это гибкие контейнеры, которые используются для хранения различных видов записей. Они могут быть частью B-дерева или существовать сами по себе. Узлы могут содержать записи гибкого или фиксированного размера. Узел начинается со списка указателей на ключи входа и записи входа. Таким образом, для каждой записи узел содержит заголовок записи в начале узла, ключ входа в середине узла и запись входа в конце узла.

Файл и папка B-дерева

Записи всех файлов и папок на томе. Они выполняют ту же роль, что и файлы каталога в «HFS+».

Extents (Экстенты B-дерева)

Отдельное B-дерево всех экстентов тома. Экстенты – это ссылки на содержимое файла с информацией о том, где начинается содержимое данных, и о их длине в блоках. Файл с некоторым содержимым будет иметь как минимум один экстент. А фрагментированный файл будет иметь несколько экстентов. Дерево экстентов – это отдельная структура.

В каждой записи файла, экстенты, определяются для каждого из этих файлов в B-дереве. Эта отдельная структура экстентов является частью функции моментального снимка.

64-bit inodes (index descriptors) – индексные дескрипторы

64-битные inodes значительно увеличивают пространство имен по сравнению с 32-битными идентификаторами в «HFS+». 64-разрядная файловая система «ApFS» поддерживает более 9 квинтиллионов файлов на каждом томе. Как сказал Билл Гейтс, этого должно хватить на всех.

«ApFS» предлагает возможность восстановления определенных состояний файловой системы, включая старые или удаленные версии файлов. Суперблок контейнера содержит ссылку на структуру контрольной точки. Контрольная точка ссылается на предыдущий суперблок контейнера, который содержит информацию в более старом состоянии файловой системы. Таким образом, можно восстановить несколько старых состояний путем анализа цепочки суперблока контейнера.

Полную версию статьи со всеми дополнительными видео уроками читайте в нашем блоге...

 
Просмотры: 106
 

Комментарии: