|
| |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
2009 г.
Записки исследователя NTFSСодержаниеОбщие сведенияNTFS (NT File System) – файловая система, которая разрабатывалась Microsoft специально для Windows NT. Написание NTFS шло параллельно с разработкой самой этой ОС. Известно, что NT зарождалась не в вакууме; в ее основу были положены идеи серверной системы VMS «high-end» класса компании DEC (в 1998 она была куплена Compaq, которая затем была поглощена Hewlett-Packard). ОС VMS работала на железе DEC, включая 32-битные компьютеры VAX и 64-битные машины на основе процессора Alpha. Каким-то образом команда, работавшая над созданием VMS, перекочевала в Microsoft для создания NT. Во главе этой команды находился Дэйв Катлер (Dave Cutler), крестный отец NT, разработчик ядра системы. Основная версия причины перехода Катлера в Microsoft – закрытие проекта разработки нового RISC-процессора и соответствующей ОС, в котором он работал вместе со своей командой инженеров. В результате, не без участия Билла Гейтса, Дэйв со своей командой оказался в Microsoft. Кстати, Гейтс был очень заинтересован в создании новой ОС, потому что у Microsoft на тот момент была только Windows, пригодная для домашних пользователей, а выхода на рынок серверов не было. Архитекторами NTFS были Том Миллер (Tom Miller) и Гэри Кимура (Gary Kimura), которые работали программистами в команде Катлера в DEC. Так же, как NT влила в себя идеи VMS, NTFS основывалась на идеях файловой системы VMS – Files-11, в которой, в частности, поддерживались списки контроля доступом (ACL), а также ввод/вывод, ориентированный на записи (record-oriented I/O) [1] [2]. NTFS разрабатывалась, прежде всего, как ФС для ОС корпоративного уровня, какой и являлась NT. Предыдущие файловые системы FAT и HPFS (ФС для OS/2) были способны удовлетворить потребностям рядовых пользователей, но не имели достаточных возможностей для корпоративной среды, таких как защищенность файлов, отказоустойчивость и восстанавливаемость. В связи с этим Microsoft выработала следующие требования к новой ФС класса «high end». (Эти требования были перечислены у Хелен Кастер в «Основах Windows NT и NTFS», первой книге, которая проливала свет на внутреннее устройство NT).
Разработка новой файловой системы, которая должна удовлетворять вышеперечисленным требованиям очень сложный процесс и здесь разработчики учли опыт MS в разработке FAT и HPFS. Том Миллер так описывает процесс разработки новой ФС: Работа над файловой системой – это, пожалуй, самое ужасное [при разработке операционной системы]. Если обнаружилась в ядре системы, или что-нибудь странное происходит с дисплеем, то можно просто перезагрузить машину и продолжать работу. Но если что-то случилось с жестким диском, то часто дальнейшая работа вообще невозможна. Всех страшно раздражают ошибки в файловой системе. Никому не хочется, чтобы его постоянная память стала не постоянной. NTFS имеет следующие версии.
Общие концепции NTFS
Формат загрузочного сектора NTFS описывается следующей таблицей (как и все остальные описываемые структуры, наилучшим руководством по ним может служить книга Брайана Кэрриэ «Криминалистический анализ файловых систем»).
Соответствующие структуры имеют вид (определения взяты из исходников Linux-NTFS Project, там же можно найти очень много информации о структурах ntfs). Так же как и FAT, NTFS хранит часть информации в блоке, называемом BIOS Parameter Block, который входит в состав boot sector. typedef struct _BIOS_PARAMETER_BLOCK
{
/*0x0b*/USHORT bytes_per_sector; /* Размер сектора, в байтах */
/*0x0d*/UCHAR sectors_per_cluster; /* Секторов в кластере */
/*0x0e*/USHORT reserved_sectors; /* должен быть ноль */
/*0x10*/UCHAR fats; /* должен быть ноль */
/*0x11*/USHORT root_entries; /* должен быть ноль */
/*0x13*/USHORT sectors; /* должен быть ноль */
/*0x15*/UCHAR media_type; /* тип носителя, 0xf8 = hard disk */
/*0x16*/USHORT sectors_per_fat; /* должен быть ноль */
/*0x18*/USHORT sectors_per_track; /* не используется */
/*0x1a*/USHORT heads; /* не используется */
/*0x1c*/ULONG hidden_sectors; /* не используется */
/*0x20*/ULONG large_sectors; /* должен быть ноль */
/* sizeof() = 25 (0x19) bytes */
} BIOS_PARAMETER_BLOCK, *PBIOS_PARAMETER_BLOCK;
typedef struct _NTFS_BOOT_SECTOR
{
/*0x00*/UCHAR jump[3]; /* переход на загрузочный код */
/*0x03*/ULARGE_INTEGER oem_id; /* сигнатура "NTFS ". */
/*0x0b*/BIOS_PARAMETER_BLOCK bpb;
/*0x24*/UCHAR physical_drive; /* не используется */
/*0x25*/UCHAR current_head; /* не используется */
/*0x26*/UCHAR extended_boot_signature; /* не используется */
/*0x27*/UCHAR reserved2; /* не используется */
/*0x28*/ULARGE_INTEGER number_of_sectors; /* Количество секторов на томе. */
/*0x30*/ULARGE_INTEGER mft_lcn; /* Стартовый кластер MFT. */
/*0x38*/ULARGE_INTEGER mftmirr_lcn;/* Стартовый кластер копии MFT */
/*0x40*/CHAR clusters_per_mft_record; /* Размер MFT записи в кластерах. */
/*0x41*/UCHAR reserved0[3]; /* зарезервировано */
/*0x44*/CHAR clusters_per_index_record;/* Размер индексной записи в кластерах. */
/*0x45*/UCHAR reserved1[3]; /* зарезервировано */
/*0x48*/ULARGE_INTEGER volume_serial_number; /* уникальный серийный номер тома */
/*0x50*/ULONG checksum; /* не используется */
/*0x54*/UCHAR bootstrap[426]; /* загрузочный-код */
/*0x1fe*/USHORT end_of_sector_marker; /* конец загрузочного сектора, сигнатура 0xaa55 */
/* sizeof() = 512 (0x200) bytes */
} NTFS_BOOT_SECTOR, *PNTFS_BOOT_SECTOR;
При проверке факта, что том является NTFS, необходимо прежде всего проверить сигнатуру «NTFS ». if( NtfsBootSector->oem_id.QuadPart != 0x202020205346544E ) return FALSE; Потом некоторые параметры бут сектора, как например кол-во байт в секторе и количество секторов в кластере на кратность двойки в степени. if( NtfsBootSector->bpb.bytes_per_sector < 0x100 ||
NtfsBootSector->bpb.bytes_per_sector > 0x1000 ) return FALSE;
//check sectors per cluster
switch( NtfsBootSector->bpb.sectors_per_cluster ) {
case 1: case 2: case 4: case 8: case 16: case 32: case 64: case 128:
break;
default:
return FALSE;
}
Все проверки в функции ntfs_boot_sector_is_ntfs из Linux-NTFS Project. Таблица MFTОб MFT слышал, наверное, каждый и информация по ней есть и у Руссиновича и в статьях, например у Касперски в «NTFS изнутри и снаружи», все же я продублирую и обобщу ее. В NTFS ключевым местом для хранения информации о файлах является таблица MFT (Master File Table). В ней содержится информацию обо всех файлах в системе. MFT состоит из записей (mft record) фиксированного размера, размер записи указывается в параметре clusters_per_mft_record структуры бут сектора. Ключевые моменты NTFS:
MFT состоит из заголовка записи MFT_RECORD, за которым следуют данные записи – атрибуты. typedef struct _MFT_RECORD
{
/*0x00*/ ULONG signature; //сигнатура 'FILE'
/*0x04*/ USHORT usa_offs;
/*0x06*/ USHORT usa_count;
/*0x08*/ ULARGE_INTEGER lsn;
/*0x10*/ USHORT sequence_number;
/*0x12*/ USHORT link_count;
/*0x14*/ USHORT attrs_offset;
/*0x16*/ USHORT flags;//флаги, см. MFT_RECORD_FLAGS
/*0x18*/ ULONG bytes_in_use;
/*0x1C*/ ULONG bytes_allocated;
/*0x20*/ ULARGE_INTEGER base_mft_record; //адрес базовой MFT-записи
/*0x28*/ USHORT next_attr_instance;
/*0x2A*/ USHORT reserved;
/*0x2C*/ ULONG mft_record_number;
//size - 48 b
} MFT_RECORD, *PMFT_RECORD;
Начало записи MFT идентифицируется сигнатурой “FILE”. Флаги указывают, является ли запись каталогом, или файлом и используется ли запись вообще. typedef enum {
MFT_RECORD_NOT_USED = 0, //запись не используется
MFT_RECORD_IN_USE = 1, //запись используется
MFT_RECORD_IS_DIRECTORY = 2 //запись описывает каталог
} MFT_RECORD_FLAGS;
Если файловая запись используется и описывает каталог, тогда поле flags равно MFT_RECORD_IN_USE | MFT_RECORD_IS_DIRECTORY (3). Для файла, flags равен MFT_RECORD_IN_USE. Записи адресуются через структуру struct MFT_REF
{
unsigned __int64 index : 48; //индекс элемента в таблице
unsigned __int64 ordinal : 16; //порядковый номер
};
Для адресации записей используется младшее поле index, а ordinal нужно для определения несоответствий внутри самой файловой системы. Смещение первого элемента MFT (в кластерах), т. е. его начало хранится в поле mft_lcn. Размер записи хранится в поле clusters_per_mft_record. Особенность этого поля заключается в том, что оно может хранить отрицательное значение, в таком случае это указание на то, что размер записи задается не в кластерах, а в байтах, причем задается не количество байт, а отрицательное значение степени двойки (логарифм двойки). Для получения количества байт нужно сделать инверсию значения в положительное и возвести двойку в степень этого значения. Например, так. if( boot_sect.clusters_per_mft_record > 0 ) bpmftrec = bps * spc * boot_sect.clusters_per_mft_record; else bpmftrec = 2 << ~boot_sect.clusters_per_mft_record; Задача с поиском элемента в MFT осложняется тем, что сам файл MFT может быть фрагментирован и тогда линейная индексация его как массива не представляется возможной. Для последующего чтения записей в MFT, лучше сразу скэшировать информацию об отрезках для файла MFT. Первые записи MFT стандартизированы и описывают служебные файлы самой NTFS. Утилита Руссиновича nfi позволяет сдампить элементы в MFT и просмотреть их атрибуты, например, nfi C. |
|
CITForum © 1997–2025