В это трудно поверить, но так называемые «непродвинутые» пользователи иногда удаляют важные данные и потом громко о них сожалеют. Расхлебывать их проблемы приходится программистам, поэтому сейчас мы разберемся в том, как Mac OS X хранит данные на носителях, и как эти данные можно восстановить.

 

Intro

Для использования в Mac OS, Apple разработала свою собственную файловую систему HFS (Hierarchical File System). В настоящее время ей на смену пришла HFS+, которая используется в Mac OS, начиная с версии 8.1. Структура тома, использующего HFS+, близка к HFS, но в то же время содержит некоторые отличия.
Основные характеристики этих двух систем:

Длина имени файла:

  • HFS:31
  • HFS+: 255

Кодировка имен файлов

  • HFS: Mac Roman
  • HFS+: Unicode

Нода каталога

  • HFS: 512 байт
  • HFS+: 4 Kбайт

Максимальный размер файла

  • HFS: 2^31
  • HFS+: 2^63

Как видишь, HFS+ была создана, чтобы наиболее эффективно ис пользовать дисковое пространство для томов больших размеров и фрагментированных файлов.

 

HFS+ внутри

HFS делит дисковое пространство на блоки одинакового размера. Для идентификации блока используется 16 бит, стало быть, всего может быть 65536 таких блоков, при этом каждый блок занимает целое число секторов. Очевидно, что такая система приводит к потере большого пространства на больших томах.

В свою очередь HFS+ использует 32 бита для нумерации блоков, что позволяет использовать пространство более рационально.

Для управления размещением данных на диске HFS+ хранит на нем также и служебную информацию — метаданные. Среди них наиболее важны для работы файловой системы и наиболее интересны нам в деле поиска пропавших данных:

  • Volume header (заголовок тома).Содержит общую информацию о томе. Например, размер блока данных и информацию о расположении других блоков метаданных на диске.
  • Allocation file (файл размещения или карта тома).Bitmap, в котором отмечен статус каждого блока на диске. (1 — занят, 0 — свободен.)
  • Catalog file (каталог).В нем хранится большая часть данных о размещении файлов и папок на диске.
  • Extents overflow file.Содержит метаданные, которые не разместились в каталоге.
  • Attributes file (файл атрибутов).Используются для контроля доступа и т.п.
  • Journal file (журнал).Хранит данные о транзакциях, выполненных для данного тома.

Catalog file, extents overflow file и attribute file — представляют собой B-деревья.

Заголовок тома всегда размещается по фиксированному смещению 1024 байта от начала тома. Он содержит общую информацию о томе — в том числе и о размещении других служебных структур HFS+ на диске. Так, например, journalInfoBlock — размещение журнала, если для этой системы ведется журналирование, allocationFile-блок, с которого начинается карта размещения файлов на диске, catalogFile — размещение файла каталога.

 

Заголовок тома HFS+

struct HFSPlusVolumeHeader
{
UInt16 signature;
UInt16 version;
UInt32 attributes;
UInt32 lastMountedVersion;
UInt32 journalInfoBlock;
UInt32 createDate;
UInt32 modifyDate;
UInt32 backupDate;
UInt32 checkedDate;
UInt32 fi leCount;
UInt32 folderCount;
UInt32 blockSize;
UInt32 totalBlocks;
UInt32 freeBlocks;
UInt32 nextAllocation;
UInt32 rsrcClumpSize;
UInt32 dataClumpSize;
HFSCatalogNodeID nextCatalogID;
UInt32 writeCount;
UInt64 encodingsBitmap;
UInt32 fi nderInfo[8];
HFSPlusForkData allocationFile;
HFSPlusForkData extentsFile;
HFSPlusForkData catalogFile;
HFSPlusForkData attributesFile;
HFSPlusForkData startupFile;
};

Запись catalog file

struct HFSPlusCatalogFile
{
SInt16 recordType;
UInt16 fl ags;
UInt32 reserved1;
HFSCatalogNodeID fi leID;
UInt32 createDate;
UInt32 contentModDate;
UInt32 attributeModDate;
UInt32 accessDate;
UInt32 backupDate;
HFSPlusPermissions permissions;
FInfo userInfo;
FXInfo fi nderInfo;
UInt32 textEncoding;UInt32 reserved2;
HFSPlusForkData dataFork;
HFSPlusForkData resourceFork;
};

Catalog file содержит метаданные файлов и папок в виде отдельных записей. Node ID (CNID) — это уникальный номер ноды файловой системы. Самая важная информация в записи catalog file’а — это данные о размещении файла, в которые входят восемь записей из стартового блока и длины в блоках непрерывной части фрагмента файла (fork’а). Если этого недостаточно, остальные данные о форках файла есть в Extent overflow file.

 

Запись fork-а файла

struct HFSPlusForkData
{
UInt64 logicalSize;
UInt32 clumpSize;
UInt32 totalBlocks;
HFSPlusExtentRecord extents;
};

Журнал HFS+ — это непрерывный набор блоков транзакций, который никогда не перемещается и его размер не изменяется. Иначе говоря, он представляет собой циклический буфер фиксированного размера, который содержит записи транзакций HFS+. На одну транзакцию может быть выделен один или несколько списков блоков операций. Список состоит из заголовка списка, за которым следуют собственно данные. На этом, пожалуй, мы закончим скучное знакомство с внутренностями HFS+, поскольку ничего секретного тут нет — это открытый формат и более подробное описание ты можешь найти на официальном сайте Apple.

 

Низкоуровневый доступ к ФС и восстановление данных

По восстановлению информации в MacOS HFS и HFS+ написано гораздо меньше мануалов, чем для других систем, да и выполнить это восстановление сложнее. Трудности появляются из-за того, что HFS+ используются B-деревья для хранения метаданных о размещении файлов. После того как какой-то файл удален, B-дерево тут же обновляется, и информация о размещении удаленного файла теряется. С выпуском Mac OS X 10.2 в августе 2002 года Apple усовершенствовала HFS+, добавив журнал, который хранит все изменения файловой системы в блоках транзакций.

Журналирование может быть разрешено или запрещено пользователем в процессе работы. В Mac OS X версии 10.2 по умолчанию журналирование запрещено. В Mac OS X 10.3 и более поздних оно по умолчанию разрешено. То есть, на всей современной технике с Mac OS X изменения файловой системы журналируются. Однако журнал был добавлен в HFS+ не для восстановления утраченных данных, а для поддержания целостности ФС в случае исключительных ситуаций. Простое действие пользователя порождает множество изменений в файловой системе.

Так, при создании файла, например, происходит следующее:

  • В Catalog file добавляется нода нового файла.
  • Bitmap тома изменяется, чтобы корректно отразить информацию о занятых блоках.
  • Также записи будут добавлены в Extent overflow, если файл сильно фрагментирован.
  • Файл атрибутов обновляется.
  • Заголовок тома обновляется, чтобы зафиксировать факт изменения файловой системы.

Все эти изменения могут привести к тому, что файловая система будет повреждена, поскольку в процессе этих действий может произойти отключение питания или извлечение съемного носителя. Журналирование как раз и помогает решить эту проблему.

Транзакция в журналируемой HFS+ включает следующие шаги:

  1. Начать транзакцию копированием всех предполагаемых изменений в файл журнала.
  2. Записать журнал из буфера на диск.
  3. Записать факт транзакции в заголовок журнала.
  4. Провести запланированные изменения.
  5. Пометить транзакцию завершенной.

При монтировании файловой системы HFS+ система проверяет журнал на предмет незавершенных транзакций. Если таковые есть, то файловая система будет исправлена.

 

Наконец-то восстанавливаем данные!

Как же использовать журнал для восстановления поврежденных файлов? Необходимо выполнить следующие действия:

  1. Читаем заголовок тома
  2. Получаем доступ к Catalog File
  3. Находим размемещение файла журнала
  4. Читаем его в память
  5. Находим там записи об удаленных файлах
  6. Если блоки, принадлежащие удаленным файлам еще не перезаписаны (проверяем по Bitmap), читаем их и восстанавливаем данные.

Здесь вроде бы все понятно, но есть одна проблема — размер журнала ограничен и периодически его содержимое перекрывается. Журнал загрузочного тома Mac-mini обычно перекрывается за 5-10 минут. Журнал загрузочного тома MacBook'а перекрывается за 30 минут. Если на томе работает Time Machine, то журнал перекрывается каждые 20 секунд. В общем, перезапись идет довольно активно. Поэтому перед восстановлением том лучше смонтировать только для чтения:

mkdir /Volumes/MyVolume
mount -t hfs -r /dev/diskXXXX /Volumes/MyVolume

Так мы сохраним журнал и к тому же предотвратим перезапись блоков удаленных файлов, которые помечены в bitmap'е тома как свободные.

По принципу анализа журнала HFS+ работает множество софтин, которые ты легко можешь найти в Сети, и большого смысла писать под это дело свою — нет.

Посмотрим, что можно сделать руками в консоли. Хорошо разобравшись в структуре HFS+, ты сможешь, используя стандартную утилиту «dd», которая позволяет дампить участки диска в файл, анализировать журнал и карту тома в консоли. Хотя это, конечно, очень утомительно :).

Вот пример чтения одного блока по заданному адресу:

sudo dd if=/dev/disk1 of=./evidence bs=4096 skip=4355500 count=1

Если есть какие-то предположения о содержимом файла и, тем более, если это текстовый файл, можно проделать такой трюк:

sudo cat /dev/disk1 | strings -o | grep -i 'secret code' -C 5

Если блоки удаленного файла еще не были перезаписаны, то этот способ позволит полностью восстановить файл.

Даже если блоки файла перезаписаны, например, с использованием специальных утилит, аналогичных shred, данные файла могут еще остаться в виртуальной памяти — то есть, в файле подкачки. В Mac OS X файл подкачки хранится в /var/vm

$ ls -al /var/vm
total 131072
drwxr-xr-x 4  root wheel 136      Oct 14 10:50 .
drwxr-xr-x 24 root wheel 816      Oct 14 10:52 ..
drwx--x--x 18 root wheel 612      Oct 11 11:20 app_profi le
-rw------T 1  root wheel 67108864 Oct 14 10:50 swapfi le

И тогда, проанализировав своп:

sudo strings -o /var/vm/swapfi le | grep 'secret code' -C 2

ты можешь найти фрагменты файла, которые еще остались висеть в буфере.

Для доступа к служебным структурам файловой системы в своем коде ты можешь использовать файлы raw-устройств. Как правило, на /dev/rdisk0s1 находится EFI раздел, а HFS+ раздел на /dev/rdisk0s2. Кроме того, в hfs/hfs_format.h уже есть готовые описания структур данных HFS+, которые тебе могут пригодиться.

#import <hfs/hfs_format.h>
#import <util.h>
void dump(unsigned char * buf, size_t len)
{
for (size_t i = 0; i < len; ++i)
printf("%02X ", buf[i]);
}
int main(int argc, char argv[])
{
// Открываем файл устройства
// Можно для краткости использовать и devopen
int fd = open("/dev/rdisk0s2", O_RDONLY );
// Описание заголовка есть в hfs_format.h
HFSPlusVolumeHeader volume_header;
// Заголовок лежит по смещению 1024
int rd = pread(fd, &volume_header, sizeof(volume_header), 0x400);
// Теперь у нас есть вся основная инфа
// о томе
printf("%un", volume_header.blockSize);
dump((char
)&volume_header, sizeof(volume_header));
// Не забываем закрывать устройство
close(fd);
}

Запускать проги, которые взаимодействуют с raw-устройствами, нужно через sudo, так как делать это может только админ и судоеры.

 

Time Machine

Начиная с Mac OS X Leopard, в состав системы входит Time Machine. Эта утилита создает резервные копии файлов, записывая все изменения, происходящие с файловой системой. Перечисленные действия позволяют пользователю восстановить всю систему, несколько файлов или один отдельный файл в том виде, в котором он находился в определенный момент времени.

Для работы Time Machine необходимо выделить отдельный диск. Apple выпускает специальное устройство Apple Time Capsule, которое используется как сетевой диск специально для резервных копий Time Machine. Time Machine может использоваться и с любым USB или eSata-диском. При первом запуске Time Machine создает папку на указанном резервном диске, содержащую все данные.

Потом Time Machine бдует копировать только измененные файлы. В общем, если для диска используется Time Machine, то восстановление утраченных данных не представляет особых проблем.

 

Outro

Информация очень редко исчезает бесследно. Хорошо зная работу файловой системы, можно восстановить даже то, что считалось безвозвратно потерянным, ну и вообще — узнать много интересного из личной жизни пользователя.

  • Подпишись на наc в Telegram!

    Только важные новости и лучшие статьи

    Подписаться

  • Подписаться
    Уведомить о
    0 комментариев
    Межтекстовые Отзывы
    Посмотреть все комментарии