APFS: algorytm odzyskiwania danych z systemu plików i jego struktura
“ApFS oferuje możliwość przywrócenia niektórych stanów systemu plików, w tym starych lub usuniętych wersji plików. Superblok kontenerowy zawiera odniesienie do struktury punktu kontrolnego. Punkt kontrolny odnosi się do poprzedniego superbloku kontenera, który zawiera informacje w starszym stanie systemu plików. Więc, można przywrócić kilka starych stanów poprzez analizę łańcucha superbloków kontenera.
- Kontenery i Toma
- Block Header (Nagłówek bloku)
- Container Superblock
- Volume Superblock (Superblok wolumina)
- Checkpoint (Punkt czekowy)
- Checkpoint Superblock Descriptor (Deskryptor punktów kontrolnych superbloków)
- Bitmap Structures (Karta bitowa lub woluminowa)
- Tabele (Tables)
- Zestawienie tabel
- Zdjęcia migawkowe (Snapshots)
- Nodes (węzły)
- Menedzer przestszeni (Space Manager)
- Allocation info file (Plik z informacjami o dystrybucji)
- Plik i folder drzewa B
- Extents (B-drzewa extenty)
- 64-bitowe inody (index descriptors) - deskryptory indeksów
- Pytania i odpowiedzi
- Komentarze
Kontenery i Toma
Struktura systemu plików APFS ma postać drzewa b, gdzie katalog główny z danymi jest liśćmi tego drzewa. Wszystkie gałęzie przechowują tylko odniesienia do następnego węzła, dopóki nie dotrą do liści. System plików wykorzystuje pojemniki jako komórki pamięci masowej. Pojemniki te mogą zawierać kilka objętości. Jest to również podstawowy obiekt do przechowywania danych. Pojemnik musi być większy niż 512MB na jedną objętość, większy niż 1024MB na dwie objętości itp.
Poniższy rysunek przedstawia strukturę systemu plików «ApFS».
Każdy element tej struktury (z wyjątkiem pliku dystrybucyjnego) zaczyna się od 32-bajtowego nagłówka bloku, który zawiera pewne ogólne informacje o bloku. Po tym następuje korpus systemu plików. Składa się on z następujących elementów:
- 0x01: Superblok kontenera (Container Superblock)
- 0x02: Węzeł (Node)
- 0x05: Menedżer przestrzeni (Space manager)
- 0x07: Plik lokacyjny(Allocation Info File)
- 0x0C: Punkt kontrolny (Checkpoint)
- 0x0D: Superblok objętości (Volume Superblock)
Kontenery są zazwyczaj takie same jak zapisy w tabeli partycji GUID (GPT). Mają one swój własny system ochrony przed awariami i przydział przestrzeni dyskowej. Każdy pojemnik zawiera jeden lub więcej tomów, z których każdy posiada własną przestrzeń nazw, zestaw plików i katalogów.
System plików “ApFS” nie obsługuje bezpośrednio oprogramowania “RAID”, ale może być używany z woluminami Apple RAID do obsługi pasowania (RAID 0), mirroringu (RAID 1) i łączenia (JBOD).
Przy 64-bitowym indeksie “ApFS” wolumenu, obsługiwanych jest do 9 kwintilionów (1018) plików.
Nowy system plików Apple wykorzystuje nanosekundy do ustawiania znaczników czasowych. W HFS + znaczniki czasu zostały ustawione na najbliższą sekundę. Pozwoli to na zmniejszenie liczby awarii w przesyłaniu danych i innych operacjach związanych z plikami.
“ApFS” posiada wbudowany system szyfrowania i używa AES-XTS lub AES-CBC, w zależności od urządzenia. Użytkownik może użyć wielu kluczy szyfrujących do zabezpieczenia danych nawet w przypadku “fizycznego hakowania” nośnika.
To w nie jest kompletna lista innowacji, które on ma «ApFS».
Partycje sformatowane w “ApFS” nie są rozpoznawane przez OS X 10.11 Yosemite i wcześniejsze wersje systemu operacyjnego.
Block Header (Nagłówek bloku)
Każda struktura systemu plików w “ApFS” zaczyna się od nagłówka bloku. A sam nagłówek zaczyna się od sumy kontrolnej. Pozostałe informacje w nagłówku obejmują wersję bloku z kopią podczas zapisu, identyfikator bloku oraz jego typ.
Przesunięcie | Rozmiar | Typ | ID |
---|---|---|---|
0 | 8 | uint64 | Suma kontrolna (checksum) |
8 | 8 | uint64 | Identyfikator (block_id) |
16 | 8 | uint64 | Wersja (version) |
24 | 2 | uint16 | Typ bloku (block_type) |
26 | 2 | uint16 | Flagi (flags) |
28 | 4 | uint32 | Odstęp (padding) |
Z tabeli widać, że 1uint = 1 bit, 8 bitów = 1 bajt, z czego uint64 = 8, uint32 = 4, a uint16 = 2 bajty.
Container Superblock
Superblock kontenera (Container Superblock) jest punktem wejściowym do systemu plików. Ze względu na strukturę systemu plików z pojemnikami i elastyczne objętości, dystrybucja musi być prowadzona na poziomie kontenerów. Superblock kontenera zawiera informacje o wielkości bloku, jego numerze i wskazówkach w menedżerze przestrzeni kosmicznej dla tego zadania. Dodatkowo, superblok zawiera identyfikatory (ID) bloków wszystkich woluminów. W celu porównania identyfikatorów bloków w celu odsunięcia bloków, wskaźnik na mapie bloków z drzewa B jest zapisywany. To drzewo zawiera wpisy dla każdego tomu z jego identyfikatorem i przesunięciem. Superblok kontenerowy jest najwyższym poziomem systemu plików.
Ma on następujący wygląd:
Przesunięcie (HEX) | Typ | Id | Opis |
---|---|---|---|
0 | tApFS_COH | Header | Nagłówek obiektu kontenera (Container Object Header) |
20 | uint32 | MagicNumber (NXSB) | Wartość do sprawdzania odczytu Super Block kontenera. |
24 | uint32 | BlockSize | Wielkość bloku kontenerowego (w bajtach) |
28 | uint64 | BlocksCount | Liczba bloków kontenerowych |
30 | uint64 | Features | Mapa (bitmapa) głównych funkcji kontenera |
38 | uint64 | ReadOnlyFeatures | Mapa (bitmapa) podstawowych funkcji kontenera (tylko do odczytu) |
40 | uint64 | IncompatibleFeatures | Mapa (bitmapa) głównych niekompatybilnych funkcji kontenera |
48 | tApFS_Uuid | Uuid | UUID kontenera |
58 | tApFS_Ident | NextIdent | Poniższy identyfikator dla nowego obiektu logicznego lub wirtualnego |
60 | tApFS_Transaction | NextTransaction | Numer kolejnej transakcji |
68 | uint32 | DescriptorBlocks | Liczba bloków użytych przez deskryptora |
6C | uint32 | DataBlocks | Liczba bloków wykorzystywanych przez dane |
70 | tApFS_Address | DescriptorBase | Adres bazowy deskryptora lub identyfikatora obiektu fizycznego z drzewem adresowym |
78 | int32 | DataBase | Adres bazy danych lub identyfikator obiektu fizycznego z drzewem adresowym |
80 | uint32 | DescriptorNext | Indeks kolejnego deskryptora |
84 | uint32 | DataNext | Następny indeks danych |
88 | uint32 | DescriptorIndex | Indeks pierwszego elementu rzeczywistego w segmencie deskryptora |
8C | uint32 | DescriptorLength | Liczba bloków w segmencie deskryptora używanych przez superblok |
90 | uint32 | DataIndex | Indeks pierwszego rzeczywistego elementu w segmencie danych |
94 | uint32 | DataLength | Liczba bloków w segmencie danych używanych przez superblok |
98 | tApFS_Ident | SpaceManagerIdent | Identyfikator obiektu logicznego Space Manager |
A0 | tApFS_Ident | ObjectsMapIdent | Identyfikator fizycznego obiektu na mapie obiektu kontenerowego |
A8 | tApFS_Ident | ReaperIdent | Identyfikator obiektu logicznego |
B0 | uint32 | ReservedForTesting | |
B4 | uint32 | MaximumVolumes | Maksymalna możliwa ilość objętości w pojemniku |
B8 | tApFS_Ident | VolumesIdents[100] | Objętość macierzy wirtualnych identyfikatorów obiektów |
3D8 | uint64 | Counters[32] | Szereg liczników, w których przechowywane są informacje o kontenerach |
4D8 | tApFS_BlockRange | BlockedOutOfRange | Zakres fizyczny bloków, które nie mogą być używane |
4E8 | tApFS_Ident | MappingTreeIdent | Identyfikator obiektu fizycznego w drzewie używany do śledzenia obiektów przeniesionych z zablokowanego magazynu. |
4F0 | uint64 | OtherFlags | Mapa innych funkcji kontenera |
4F8 | tApFS_Address | JumpstartEFI | Id obiekta fizycznego z danymi EFI-systemu |
500 | tApFS_Uuid | FusionUuid | UUID kontener fuzji jądrowej lub zero dla kontenerów innych niż Fusion |
510 | tApFS_BlockRange | KeyLocker | Umiejscowienie znacznika klucza na pojemniku |
520 | uint64 | EphemeralInfo[4] | Tablica pól używanych do zarządzania danymi logicznymi |
540 | tApFS_Ident | ReservedForTesting | |
548 | tApFS_Ident | FusionMidleTreeIdent | Tylko dla zunifikowanych urządzeń |
550 | tApFS_Ident | FusionWriteBackIdent | Tylko dla zunifikowanych urządzeń |
558 | tApFS_BlockRange | FusionWriteBackBlocks | Bloki stosowane w obszarze pamięci podręcznej |
Z definiowaniem typów:
uint8 tApFS_Uuid;
uint64 tApFS_Ident;
uint64 tApFS_Transaction;
int64 tApFS_Address;
uint64 tApFS_BTreeKey;
i
struct tApFS_BlockRange
{
tApFS_Address First; // Pierwszy blok
uint64 Count; // Ilość bloków
}
struct tApFS_COH
{
uint64 CheckSum; // Suma kontrolna bloku
tApFS_Ident Ident; // Identyfikator
tApFS_Transaction Transaction; // Object change transaction number
uint16 Type; // Typ objektu
uint16 Flags; // Flagi obiektu
uint32 SubType; // Podtyp obiektu
};
z listą typów obiektów:
enum eApFS_ObjectType
{
eApFS_ObjectType_01_SuperBlock = 0x0001, //Superblok kontenera
eApFS_ObjectType_02_BTreeRoot = 0x0002, // B dzerwo: węzełowy element
eApFS_ObjectType_03_BTreeNode = 0x0003, // B dzerwo: lista
eApFS_ObjectType_05_SpaceManager = 0x0005, // Menedzer przestrzeni
eApFS_ObjectType_06_SpaceManagerCAB = 0x0006, // Menedzer przestrzeni: adres segmentów
eApFS_ObjectType_07_SpaceManagerCIB = 0x0007, // Menedzer przestrzeni: informacja segmentów
eApFS_ObjectType_08_SpaceManagerBitmap = 0x0008, // Karta swobodnej przestrzeni wykorzystująca Menedzerem przestrzeni
eApFS_ObjectType_09_SpaceManagerFreeQueue = 0x0009, // Wolne miejsce wykorzystujące menedzerem przestrzeni_ (klucze - _tApFS_09_SpaceManagerFreeQueue_Key_, znaczenia - _tApFS_09_SpaceManagerFreeQueue_Value_)
eApFS_ObjectType_0A_ExtentListTree = 0x000A, // Dzrewo listy rozmiarów (klucze – przesunięcie początkowego rozmiaru_tApFS_Address_, znaczenie – fizyczne miejsce danych _tApFS_BlockRange_)
eApFS_ObjectType_0B_ObjectsMap = 0x000B, // Typ – Karta objektów; subType – Drzewo zapisów karty objektów (klucze - _tApFS_0B_ObjectsMap_Key_, znaczenie - _tApFS_0B_ObjectsMap_Value_)
eApFS_ObjectType_0C_CheckPointMap = 0x000C, // Karta kontrolnych punktów (punktów czekowych)
eApFS_ObjectType_0D_FileSystem = 0x000D, // System plików wolumena
eApFS_ObjectType_0E_FileSystemTree = 0x000E, // Dzrzewo systemu plików (klucze zaczynająsię c _tApFS_BTreeKey_, opisywać typ oraz wartość klucza)
eApFS_ObjectType_0F_BlockReferenceTree = 0x000F, // Drzewo linków na bloki (klucze - _tApFS_BTreeKey_, znaczenie - _tApFS_0F_BlockReferenceTree_Value_)
eApFS_ObjectType_10_SnapshotMetaTree = 0x0010, // Drzewo obrazów (klucze - _tApFS_BTreeKey_, znaczenie - _tApFS_10_SnapshotMetaTree_Value_)
eApFS_ObjectType_11_Reaper = 0x0011, // Reaper
eApFS_ObjectType_12_ReaperList = 0x0012, // Reaper List
eApFS_ObjectType_13_ObjectsMapSnapshot = 0x0013, // Drzewo obrazów karty objektów (klucze - _tApFS_Transaction_, znaczenia - _tApFS_13_ObjectsMapSnapshot_Value_)
eApFS_ObjectType_14_JumpStartEFI = 0x0014, // EFI Pobieracz
eApFS_ObjectType_15_FusionMiddleTree = 0x0015, // Dzrzewo łączących urządzeń dla sledzenia bloków twardych dysków, buforowanych SSD (klucze - _tApFS_Address_, wartości - _tApFS_15_FusionMiddleTree_Value_)
eApFS_ObjectType_16_FusionWriteBack = 0x0016, // Stan kesza zwrotnego zapisu zintegrowanych urządzeń
eApFS_ObjectType_17_FusionWriteBackList = 0x0017, // Lista pamięci podręcznej zapisu łączących urządzeń
eApFS_ObjectType_18_EncryptionState = 0x0018, // Szyfrowanie
eApFS_ObjectType_19_GeneralBitmap = 0x0019, // General Bitmap
eApFS_ObjectType_1A_GeneralBitmapTree = 0x001A, // Drzewo General Bitmap (keys - uint64, keys - uint64)
eApFS_ObjectType_1B_GeneralBitmapBlock = 0x001B, // Blok General Bitmap
eApFS_ObjectType_00_Invalid = 0x0000, // Nie istnieje jak typ albo nie istnieje jak podtyp
eApFS_ObjectType_FF_Test = 0x00FF // Zarezerwowano dla testowania (nigdy nie zapisuje się na nośniku)
eApFS_ObjectType_FF_Test = 0x00FF // Zarezerwowano dla testowania (nigdy nie zapisuje się na nośniku)
};
enum eApFS_ObjectFlag
{
eApFS_ObjectFlag_Virtual = 0x0000, // Wirtualny objekt
eApFS_ObjectFlag_Ephemeral = 0x8000, // Logiczny objekt
eApFS_ObjectFlag_Physical = 0x4000, // Fizyczny objekt
eApFS_ObjectFlag_NoHeader = 0x2000, // Objekt bez nagłowka _tApFS_ContainerObjectHeader_ (naprzykład, Karta (bitmap) menedzera przestrzeni)
eApFS_ObjectFlag_Encrypted = 0x1000, // Zaszyfrowany objekt
eApFS_ObjectFlag_NonPersistent = 0x0800, // Objekt z tym flagiem nigdy nie zapisuje się na nośniku
eApFS_ObjectFlag_StorageTypeMask = 0xC000, // Bitowa (bitmask) maska dla dostępa do flagi kategorii objektów
eApFS_ObjectFlag_ValidMask = 0xF800 // Istniejąca flaga bitowej maski
};
struct tApFS_0B_ObjectsMap_Key
{
tApFS_Ident ObjectIdent; // Identyfikator objektu
tApFS_Transaction Transaction; // Numer tranzakcji
};
struct tApFS_0B_ObjectsMap_Value
{
uint32 Flags; // Флаги
uint32 Size; // Rozmiar objektu w bajtach (wielokrotny rozmiaru bloku kontenera)
tApFS_Address Address; // Adres objektu
};
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; // Identyfikator fizycznego ;objektu drzewa B, w którym zapisane informacje o rozmiarze
tApFS_Ident SuperBlockIdent; // Identyfikator superbloku
uint64 CreatedTime; // Czas stworzenia obrazu (w nanosekundach z północy 01/01/1970)
uint64 LastModifiedTime; // Czas zmiany obrazu (w nanosekundach z północy 01/01/1970)
uint64 iNum;
uint32 ExtentRefTreeType; // Typ drzewo B, w którym zapisywane informacje o rozmiarach
uint16 NameLength; // Długość nazwy obrazu (włącząc symbol końca smyczki)
uint8 Name[]; // Imię obrazu (konczy się na 0)
};
struct tApFS_13_ObjectsMapSnapshot_Value
{
uint32 Flags; // Flagi obrazów
uint32 Padding; // Zarezerwowano (dla korekty)
tApFS_Ident Reserved; // Zarezerwowano
};
struct tApFS_15_FusionMiddleTree_Value
{
tApFS_Address fmv_lba;
uint32 fmv_length;
uint32 fmv_flags;
};
Przykładowa struktura systemu plików ApFS:
Volume Superblock (Superblok wolumina)
Superblock wolumina - istnieje dla każdego woluminu w systemie plików. Zawiera on nazwę objętości, identyfikator i znacznik czasu. Podobnie jak Container Superblock, zawiera on wskaźnik na mapie bloków, który wyświetla identyfikatory bloków na ich przesunięciach. Dodatkowo, superblokada wolumenu zawiera wskaźnik do katalogu głównego, który jest przechowywany jako węzeł.
Przesunięcie(HEX) | Typ | Id | Opis |
---|---|---|---|
0 | tApFS_COH | Header | Nagłowek objektu kontenera (Container Object Header) |
20 | uint32 | MagicNumber (APSB) | Wartość, która może być użyta do sprawdzenia, czy czytamy kopię Volume Superblock |
24 | uint32 | IndexInSuperBlock | Indeks identyfikatora obiektu tego wolumenu w tablicy wolumenu kontenera |
28 | uint64 | Features | Bitmap kluczowych funkcji wykorzystywanych przez objętość |
30 | uint64 | ReadOnlyFeatures | Bitowa mapa podstawowych funkcji (tylko do odczytu) wykorzystywanych przez wolumen |
38 | uint64 | IncompatibleFeatures | Bitmapa (Bitmapa) niekompatybilnych funkcji objętościowych |
40 | uint64 | LastUnmountTime | Czas ostatniego ustawienia objętości (w nanosekundach od północy) 01.01.1970) |
48 | uint64 | ReservedBlocksCount | Liczba bloków zarezerwowanych do wyboru objętości |
50 | uint64 | QuotaBlocksCount | Maksymalna liczba bloków, które ten wolumen może przydzielić |
58 | uint64 | AllocatedCount | Liczba bloków aktualnie przypisanych do systemu plików tego woluminu. |
60 | uint8 | MetaCryptoState[20] | Informacje o kluczu używanym do szyfrowania metadanych dla tego woluminu (np. wrapped_meta_crypto_state_t) |
74 | uint32 | RootTreeType | Typ drzewa katalogu głównego (zazwyczaj: typ drzewa katalogu głównego) ( eApFS_ObjectFlag_Virtual << 16) \ eApFS_ObjectType_02_BTreeRoot , podtyp eApFS_ObjectType_0E_FileSystemTree ) |
78 | uint32 | ExtentRefTreeType | Typ drzewa wiązania rozszerzonego (zazwyczaj: typ ( eApFS_ObjectFlag_Physical << 16) \ eApFS_ObjectType_02_BTreeRoot , podtyp OBJECT_TYPE_BLOCKREF ) |
7C | uint32 | SnapshotMetaTreeType | Typ drzewa metadanych obrazu (zazwyczaj: typ ( eApFS_ObjectFlag_Physical << 16) \ eApFS_ObjectType_02_BTreeRoot , podtyp OBJECT_TYPE_BLOCKREF ) |
80 | tApFS_Ident | ObjectsMapIdent | Identyfikator obiektu fizycznego na objętościowej mapie obiektów |
88 | tApFS_Ident | RootTreeIdent | Identyfikator obiektu wirtualnego w głównym drzewie folderów |
90 | tApFS_Ident | ExtentRefTreeIdent | Identyfikator obiektu fizycznego w drzewie powiązań Extents |
98 | tApFS_Ident | SnapshotMetaTreeIdent | Identyfikator obiektu wirtualnego w drzewie metadanych obrazu |
A0 | tApFS_Transaction | RevertToXid | Numer transakcji, do której zostanie zwrócony wolumen |
A8 | tApFS_Ident | RevertToSuperBlock | Identyfikator fizycznego obiektu VS, do którego powróci wolumen |
B0 | uint64 | NextObjectIdent | Następny identyfikator, który zostanie przypisany do obiektu systemu plików na woluminie. |
B8 | uint64 | NumberOfFiles | Liczba zwykłych plików w tomie |
C0 | uint64 | NumberOfDirectories | Liczba folderów w tomie |
C8 | uint64 | NumberOfSymbolicLinks | Liczba linków symbolicznych w tomie |
D0 | uint64 | NumberOfOtherObjects | Liczba innych obiektów w tomie (nie licząc x0B8_NumberOfFiles , x0C0_NumberOfDirectories и x0C8_NumberOfSymbolicLinks ) |
D8 | uint64 | NumberOfSnapshots | Liczba ujęć w tym tomie |
E0 | uint64 | TotalBlocksAllocated | Całkowita liczba bloków przypisanych do tego wolumenu |
E8 | uint64 | TotalBlocksFreed | Całkowita liczba bloków wydanych przez ten tom |
F0 | tApFS_Uuid | Uuid | |
100 | uint64 | LastModifiedTime | Czas ostatniej zmiany tego tomu (w nanosekundach od północy 01.01.1970) |
108 | uint64 | Flags | |
110 | tApFS_0D_FSM | FormattedBy | Informacje na temat oprogramowania, które stworzyło ten tom |
140 | tApFS_0D_FSM | ModifiedBy[8] | Informacje o oprogramowaniu, które zmieniło tę ilość |
2C0 | uint8 | VolumeName[256] | Nazwa zerowej objętości łańcucha UTF-8 |
3C0 | uint32 | NextDocumentIdent | Należy przypisać następujący identyfikator dokumentu (zapisany w rozszerzonym polu APFS_0E_TYPE_DOCUMENT_ID) |
3C4 | uint16 | Role | Rastrowy obraz roli tomu |
3C6 | uint16 | Reserved | |
3C8 | tApFS_Transaction | RootToXid | Numer transakcji Snapshot dla transakcji non-root lub zero dla root. |
3D0 | tApFS_Ident | EncryptStateIdent | Aktualny stan szyfrowania lub odszyfrowywania, lub zero, jeśli nie ma szyfrowania |
Szczegółowa ilustracja «APFS»:
Checkpoint (Punkt czekowy)
Punkt kontrolny to tymczasowy stan kontenera. Każdy punkt kontrolny jest inicjowany w Superblocku kontenera, a aktualny stan jest zazwyczaj ostatnim z nich. Punkt kontrolny zawiera metadane zarówno pojemnika, jak i jego objętości. Punkty odzyskiwania i ujęcia są podobne do siebie. Główną różnicą pomiędzy punktem kontrolnym a zrzutem jest możliwość przywrócenia systemu plików z zapisanych zrzutów za pomocą API systemu plików.
Checkpoint Superblock Descriptor (Deskryptor punktów kontrolnych superbloków)
Blok ten zawiera informacje o strukturach metadanych w "ApFS" i jest poprzednim blokiem Descriptor. Najważniejszą informacją w tym bloku jest lokalizacja Bitmap Structure (BMS), dawnego pliku dystrybucyjnego w HFS +.
Superblokowy deskryptor punktu odniesienia:
Bitmap Structures (Karta bitowa lub woluminowa)
Zapisy używanych i nieużywanych obiektów. Istnieje tylko jedna karta woluminów, która obejmuje cały pojemnik i jest wspólna dla wszystkich woluminów w systemie plików. "ApFS" używa zestawu bloków do przechowywania map objętościowych (Bitmap Structures).
W "ApFS" mapa jest wspólna dla wszystkich objętości w kontenerze. Każdy tom zawiera cytaty z bloków w pojemniku, ale same bloki nie znajdują się w wybranych obszarach. Odniesienie do mapy woluminu znajduje się w Super Block Checkpoint Descriptor (CSBD), który zawiera informacje o najwyższym poziomie struktury, Bitmap Descriptor (BMD). Poniższy rysunek przedstawia podstawową strukturę tego BMD. Jest on podzielony na poziomy, na których BMD znajduje się na górze i wyznacza granice. Na dole znajdują się "Bloki Bitmapy" (BMB), które śledzą bloki w kontenerze. Jeden bajt w BMB śledzi osiem bloków, z których każdy zapewnia status dystrybucji. Każdy bit jest statusem pojedynczego bloku.
Tabele (Tables)
Tabele są używane w rozszerzeniach katalogu i drzewa B, liście objętości i karcie identyfikacyjnej obiektu.
"Tabele używane w "ApFS" są małymi jednoblokowymi "bazami danych" o nieco innych celach w strukturach systemu plików. Pole typu tabela składa się z 2 bajtów umieszczonych w bloku z przesunięciem 0x20 bezpośrednio za nagłówkiem węzła. Istnieje osiem tabel od 0 do 7. Poniższe 2 bajty zapewniają poziom tabeli od 0 i więcej. Tabela drugiego poziomu będzie zawierać wpisy związane z tabelą poziomu podstawowego 1. A tabele poziomu zerowego odnoszą się do bloków, które często zawierają metadane plików.
Tabele różnią się strukturą, ale nagłówek tabeli dla wszystkich typów jest 24-bajtowy.
Rysunek przedstawia przykładową strukturę nagłówka tabeli:
Opis wartości pól w strukturze nagłówka:
Przesunięcie (HEX) | Pole | Typ danych | Opis |
---|---|---|---|
20 | tableType | uint16 | Możliwe wartości to 0-7. To jest tabela 1. |
22 | tableLevel | uint16 | Wskazuje poziom drzewa B. |
24 | tableRecords | uint16 | Liczba zapisów w tabeli |
26 | Unknown 1 | uint16 | |
28 | Unknown 2 | uint16 | |
2A | tableIndexSize | uint16 | Wielkość obszaru indeksu tabeli. |
2C | tableKeyAreaSize | uint16 | Wielkość obszaru kluczowego tabeli. |
2E | tableFreeSpaceSize | uint16 | Wielkość wolnego obszaru. Obszar danych w tabeli kończy się przesunięciem 0x38+tableIndexSize+tableKeyAreaSize+tableFreeSpaceSize. 0x38 + 0x80 + 0x170 + 0xd58 . |
30 | Unknown 3 | uint16 | |
32 | Unknown 4 | uint16 | |
34 | Unknown 5 | uint16 | |
36 | Unknown 6 | uint16 |
Tutaj pokazany ogólny układ poszczególnych tabel:
Nie wszystkie elementy na zdjęciu są używane we wszystkich tabelach. Zdjęcie przedstawia kompletny blok z nagłówkiem górnego bloku węzłowego. Reszta bloku to tabela.
Indeks zapisu pojawia się natychmiast po nagłówku tabeli. Są dwa rodzaje. Jeden z dwoma wartościami: przesunięcie w klawiszach, i przesunięcie w sekcji danych dla każdego z Uint16. Drugi wykorzystuje 4 wartości Uint16 z przesunięciem i długością zarówno dla kluczy jak i sekcji danych. Indeks zapisów tabeli zawiera informacje na temat kluczy i zapisów danych w tabeli. Kolejną różnicą pomiędzy typami tabel jest użycie stopek.
Tabele 1, 3, 5 i 7 zawierają stopkę 0x28 bajtów na końcu bloku. W tych tabelach wszystkie przesunięcia danych odnoszą się do przesunięcia 0xFD8, a stopka zawiera różne wartości specyficzne dla danego typu tabeli. Inne rodzaje tabel nie posiadają stopki, a wszystkie odniesienia do zawartości sekcji danych należą do końca bloku.
B Drzewa z kilkoma poziomami - Tabele 1, 3, 5 i 7 są na najwyższym poziomie, ponieważ mają stopkę. Dolna stopka, służąca do przechowywania informacji o pełnym drzewie B. Jedną z wartości w stopce jest całkowita liczba zapisów w tej strukturze drzewa.
Definicja tabeli zaczyna się od przesunięcia 0x20 w bloku. Określa typ tabeli, liczbę wierszy, rozmiar partycji klucza oraz odstęp między kluczem a partycją danych. Po właściwości tabeli, definicjach wierszy i kolumn opisane jest przesunięcie 0x38. Tabela zawiera nagłówek, definicje zapisów, klucze i partycje danych. Niektóre rodzaje tablic mają również stopkę. Nagłówek zaczyna się z przesunięciem 0x20 i ma długość 0x18 bajtów. Nagłówek tego typu tabeli zaczyna się od wartości 16-bitowej, która reprezentuje dany typ tabeli. Po nim następują dwa bajty reprezentujące poziom w drzewie B, na którym znajduje się tabela. Kolejne dwa bajty reprezentują liczbę wierszy w tabeli. Długość zapisu definicji skanowania wynosi 0x2A, a następnie Uint16, który zapisuje długość partycji kluczowej. Po tym następuje luka pomiędzy kluczem a partycją danych. Stopka stołu jest zawsze 0x28 bajtów i zawsze zajmuje koniec bloku. A indeksy tabel mają po 4 lub 8 bajtów każdy. Na 8-bajtowych indeksach pierwsze dwa "Uint16" są przesunięte i długość zapisu kluczowego. Kolejne dwa "Uint16" to przesunięcie i długość zapisu danych w tabeli. Tabele z indeksami 4-bajtowymi mają dwie wartości Uint16, które zawierają przesunięcie klucza i zapisy danych. Długość danych w obu zapisach jest z góry określona. W tabelach ze stopką, przesunięcie zapisu danych jest względne w stosunku do początku stopki (0x28 bajtów). A dla innych typów tabel przesunięcie to jest względne w stosunku do końca bloku.
Większość wartości dotyczących nagłówka i stopki tabeli jest czytelna, przynajmniej w przypadku odczytu typu tabeli. Przesunięcie stopki 0x18 (przesunięcie 0xFF w bloku 4 Kb) jest liczbą zapisów w tabeli i we wszystkich tabelach bazowych (jeśli jest to tabela z poziomem powyżej 0, przy przesunięciu 0x22). Przesunięcie 0x20 w stopce jest numerem kolejnego zapisu w tabeli.
Tabela 0
Tabela 0 typu leży w strukturze katalogu B-drzewa pomiędzy węzłami liści i węzłem głównym. Nieznane wartości od 3 do 6 są przedstawiane jako przesunięcia i długości kluczy. Przesunięcia danych i długość następnego dostępnego zapisu. Jeśli nie ma wolnych rekordów indeksowych, przesunięcia są ustawiane na "0xFFFF" i długość "0x00".
Wpisy w tabeli to cztery wartości "Uint16". Pierwsze 2 to przesunięcie i długość wartości w sekcji klucza, a następne 2 to przesunięcie i wartość zawartości w sekcji danych.
Przykładem tabeli typu 0 jest identyfikator węzła katalogowego, klucz nazwy w sekcji klucza oraz identyfikator obiektu w sekcji danych. Ta tabela nie ma stopki.
Tabela 1
Pierwsza tabela posiada stopkę, a indeks tabeli zawiera cztery wartości 16-bitowe, gdzie pierwsze 2 wartości są przesunięciem zapisu w sekcji klucza i długości zapisu. Poniższe 2 wartości określają przesunięcie zapisu w sekcji danych i jego długość. Tabela ta często znajduje się zarówno w strukturze katalogów drzewa B, jak i w drzewie rozszerzeń dla węzła górnego poziomu. Przykładami są: "Identyfikator rodzica" i nazwa klucza (nazwa pliku lub folderu w strukturze katalogów oraz początkowy numer bloku w drzewie B-rozmiarów), identyfikator obiektu w przypadku użycia jako węzeł główny w strukturze katalogów lub numer bloku w przypadku użycia w drzewie-rozmiarów.
Przykłady z tej tabeli są podane poniżej:
Tabela 2
Drugi tabela. Pierwotnie ta tabela jest identyczna z poprzednią, ale nie ma stopki. Ten typ tabeli jest bardzo popularny w węzłach końcowych struktury katalogów B-drzewa, gdzie sekcja klucza jest reprezentowana przez "Parent ID" oraz nazwę klucza.
Tabela 3
Tabela 3 jest identyczna z poprzedną. Indeks tabeli jest taki sam jak w przypadku pierwszej tabeli. Typowe wartości zależą od struktury, w której są stosowane. W strukturze katalogu B-drzewa i drzewa Extents, tabela ta jest często używana jako węzeł górnego poziomu w małych tomach, gdzie węzeł główny jest zarówno węzłem korzeniowym jak i liścia. W tym przykładzie użycia, zapisem kluczowym może być "Parent ID". Klucz nazwy, a rekord danych może być plikiem metadanych z dużymi zmianami rozmiaru.
Inne pozycje tabeli to identyfikator obiektu "Object ID" oraz jego typ w rekordzie klucza, z zakresem informacji o pliku i rekordami danych. 3 tabela ma stopkę.
Przykład tabeli:
Tabela 4
4 tabela jest nieco inna od poprzednich. W tabeli nie ma stopki, a indeks tabeli ma tylko 2 wartości: odsunięcie zapisu w sekcji kluczowej i 1 wartość dla sekcji danych. Długość zawartości jest stała i wynosi 16 bajtów w partycji kluczowej i 8 bajtów w partycji danych. Przesunięcia w sekcji danych znajdują się na końcu bloku.
Tabela 5
5 tabela jest podobna do 4. Jedyna różnica polega na tym, że ten typ ma stopkę, a wszystkie zmiany danych zaczynają się od "offset-0x28" (początek stopki). Zapisy w sekcji kluczowej to 16 bajtów i 8 bajtów w sekcji danych. Ten typ tabeli jest najczęściej obserwowany w węzłach górnego poziomu w strukturze katalogów drzewa B oraz w dużych kontenerach z drzewami wielopoziomowymi.
Tabela 6
6 tabela jest również podobna do 4. Indeks tabeli ma tylko przesunięcie względem zawartości w sekcji klucza i danych, ale nie jego długość. Długość jest ustalana z góry. Każdy zapis to 16 bajtów. Nie ma stopki dla tego typu stołów. Tabela ta często znajduje się w węzłach końcowych struktury katalogu B-drzewa. Typową zawartością partycji kluczowej jest identyfikator obiektu i identyfikator Superblokada punktu kontrolnego objętości "Identyfikator Superblokada punktu kontrolnego objętości", podczas gdy partycja danych zazwyczaj zapisuje ich rozmiar i numer bloku.
Tabela 7
7 Stół wygląda jak szósty. Jedyną różnicą jest stopka, która zawiera informacje podobne do tej opisanej dla 1 tabeli. Ten rodzaj tabeli jest obserwowany w szerokim zakresie struktur i często znajduje się na najwyższych poziomach struktury wielowarstwowej lub w strukturze jednowarstwowej, np. w opisie objętości.
Przykład
Zestawienie tabel
Ta tabela pokazuje główne właściwości różnych typów tabel:
Typ | Stopka | Przesunięcie sekcji kluczowej | Długość sekcji klucza | Sekcja danych przesunięcia | Długość sekcji danych | Długość klucza | Długość danych |
---|---|---|---|---|---|---|---|
0 | NIE | uint16 | uint16 | uint16 | uint16 | Varies | Possible |
1 | TAK | uint16 | uint16 | uint16 | uint16 | Varies | Possible |
2 | NIE | uint16 | uint16 | uint16 | uint16 | Varies | Possible |
3 | TAK | uint16 | uint16 | uint16 | uint16 | Varies | Possible |
4 | NIE | uint16 | uint16 | 16 bajtów | 8 bajtów | ||
5 | TAK | uint16 | uint16 | 16 bajtów | 8 bajtów | ||
6 | NIE | uint16 | uint16 | 16 bajtów | 16 bajtów | ||
7 | TAK | uint16 | uint16 | 16 bajtów | 16 bajtów |
Jednym z najważniejszych bloków w strukturze katalogów drzewa B jest węzeł główny, który jest najwyższym poziomem w strukturze katalogów. Ten węzeł wykorzystuje klucze wyszukiwania o zmiennej długości. Jedną z ulepszonych funkcji "ApFS" jest szybkie wyszukiwanie w katalogach. Jedną z wartości, która jest ściśle związana z tą funkcją jest liczba wszystkich wpisów w strukturze drzewa znajdujących się w dolnej stopce tabeli.
Węzeł główny struktury drzewa B ma 2 możliwości wyboru tabeli, ponieważ obie mają stopki. 3 Tabela - jako węzeł główny, obserwowany tylko w małych pojemnikach z małą ilością plików, gdzie węzeł główny jest również węzłem indeksu i arkusza.
W mapie obiektów dla węzła głównego wykorzystywana jest tylko 5 tabel, za wyjątkiem bardzo małych struktur, gdzie może wystąpić 7.
Tabela Interpretacja pokazuje, że tabele 0 i 2 mają te same wartości. To samo można zobaczyć między tabelami 1 i 3. Tabele te wydają się mieć różne cele w zależności od struktury, w której się znajdują.
Zdjęcia migawkowe (Snapshots)
Zdjęcia migawkowe są zdjęciami systemu plików woluminowych tylko do odczytu. System operacyjny może korzystać z tych migawek w celu uzyskania bardziej efektywnej procedury tworzenia kopii zapasowych. Dzięki nim Time Machine będzie działać szybciej. A dzięki obsłudze "Time Machine" migawkowych obrazów, nie trzeba już zapisywać kilku pełnych kopii pliku na dysk - może on po prostu śledzić pewne zmiany. Na przykład, jeśli edytujecie plik, zmianę za pomocą HFS +, zapisuje on dwie kopie pliku, pierwsza zapisuje nowe zmiany, a druga w przypadku, gdy chcecie wrócić do poprzedniego widoku. W "APFS" zapisywany jest tylko plik źródłowy i zapisywane są różnice między plikiem źródłowym a każdą zaktualizowaną wersją, co zajmuje mniej miejsca na dysku. Podobnie jak w przypadku ulepszeń w Fusion Drive, informacje zajmują mniej miejsca na dysku.
Podczas gdy "ApFS" i znacznie gorsze w swoich możliwościach do 128-bitowego ZFS, który jest obsługiwany przez Linux, FreeBSD i innych wolnych systemów operacyjnych, ale po stronie Apple jest to krok w dobrym kierunku.
Jak wspomniano powyżej, Apple od dawna stara się przenieść ZFS na OS X. Później OpenZFS został zaimplementowany dla OS X (O3X) i MacZFX.
Nodes (węzły)
Węzły są elastycznymi pojemnikami, które służą do przechowywania różnego rodzaju zapisów. Mogą one być częścią drzewa B lub istnieć same z siebie. Węzły mogą zawierać zapisy o elastycznych lub stałych rozmiarach. Węzeł rozpoczyna się od listy wskaźników do kluczy logowania i zapisu logowania. Tak więc, dla każdego zapisu, węzeł zawiera nagłówek zapisu na początku węzła, klucz zapisu w środku węzła i zapis logowania na końcu węzła.
pozycja | rozmiar | typ | 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) |
Struktura nagłówka węzła (Node header):
Przesunięcie | pole | Typ danych | Komentarze |
---|---|---|---|
0 | Checksum | Uint64 | Fletchers Checksum Algorithm |
8 | identyfikator | Uint64 | Object-ID lub Block # |
10 | Checkpoint | Uint64 | |
18 | Unknown | Uint16 | Possible level in B-Tree |
1A | Unknown | Uint16 | All observations shows value 0x4000 |
1C | Unknown | Uint16 | Flag? |
1E | Unknown | Uint16 | Often seen value 0x0b, 0x0e and 0x0f |
Menedzer przestszeni (Space Manager)
«Space Manager» (Manager przestrzeni) jest używany do kontroli przydzielonych bloków w kontenerze "ApFS". Przechowuje on liczbę wolnych bloków i wskaźnik do plików z informacjami o lokalizacji.
pozycja | rozmiar | typ | ID |
---|---|---|---|
0 | 4 | uint32 | rozmiar bloku |
16 | 8 | uint64 | totalblocks |
40 | 8 | uint64 | freeblocks |
144 | 8 | uint64 | prev_allocationinfofile_block |
352 | 8 | uint64 | alokacjainfofile_block |
Allocation info file (Plik z informacjami o dystrybucji)
Plik dystrybucyjny działa jak brakujący nagłówek. Przechowuje on długość plików alokacji, wersję i jej przesunięcie.
pozycja | rozmiar | typ | 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 |
Plik i folder drzewa B
Zapisy wszystkich plików i folderów na woluminie. Odgrywają one taką samą rolę jak pliki katalogowe w "HFS+".
Extents (B-drzewa extenty)
Oddzielne drzewo B wszystkich zakresów objętościowych. Rozszerzeniem są linki do zawartości pliku z informacją o miejscu rozpoczęcia zawartości danych i ich długości w blokach. Plik z pewną zawartością będzie miał co najmniej jeden zakres. A fragmentaryczny plik będzie miał kilka rozszerzeń. Drzewo ekstensywne jest odrębną strukturą.
W każdym zapisie pliku, rozszerzenia są zdefiniowane dla każdego z tych plików w drzewie B. Ta odrębna struktura fragmentów jest częścią funkcji migawkowej.
64-bitowe inody (index descriptors) - deskryptory indeksów
64-bitowe inody znacząco zwiększają przestrzeń nazw w porównaniu z 32-bitowymi identyfikatorami w "HFS+". 64-bitowy system plików "ApFS" obsługuje więcej niż 9 ekranów typu quintiles plików na każdym woluminie. Jak powiedział Bill Gates, to powinno wystarczyć dla wszystkich.
"ApFS" oferuje możliwość przywrócenia niektórych stanów systemu plików, w tym starych lub usuniętych wersji plików. Superblok kontenerowy zawiera odniesienie do struktury punktu kontrolnego. Punkt kontrolny odnosi się do poprzedniego superbloku kontenera, który zawiera informacje w starszym stanie systemu plików. Dzięki temu można przywrócić kilka starych stanów, analizując łańcuch superbloków kontenera.