Logo Море(!) аналитической информации!
IT-консалтинг Software Engineering Программирование СУБД Безопасность Internet Сети Операционные системы Hardware
2009 г.

Записки исследователя NTFS

Artem Baranov

Содержание

Общие сведения
Общие концепции NTFS
Таблица MFT
Атрибуты
Каталоги
Распространенные атрибуты
Ссылки

Общие сведения

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).

  • Восстанавливаемость. В случае сбоя диска, NTFS должна привести себя в рабочее, целостное состояние. В лучшем случае, NTFS вернется в состояние, которое непосредственно предшествовало сбою, в худшем какая-то пользовательская информация может быть потеряна, но том останется в рабочем состоянии. Восстанавливаемость реализуется через модель обработки транзакций. Транзакция не что иное, как операция I/O, которая изменяет структуры NTFS. Если такая операция не завершается полностью, то NTFS откатывает свои структуры данных до состояния перед выполнением транзакции.
  • Защита от несанкционированного доступа. Файлы и каталоги NTFS обладают дескрипторами защиты, что позволяет контролировать доступ к ним в рамках общей модели безопасности NT. Подобными дескрипторами защиты обладают все объекты NT (процессы, потоки, разделы и пр.).
  • Отказоустойчивость. Если восстанавливаемость гарантирует целостность тома после сбоя, то отказоустойчивость может гарантировать восстановление пользовательских данных. Это реализуется за счет избыточности данных и RAID. Дублирование данных осуществляется на уровне диспетчера томов, который копирует записываемые данные на другом диске.
  • Диски и файлы большого объема. В NTFS реализуется очень эффективная поддержка больших дисков и файлов. Для хранения номера кластера используется 64 бита или 8 байт. Т. о. NTFS позволяет адресовывать 2^64 кластеров, при стандартном размере кластера в 4KB и максимальном 64KB. Под размер файлов также выделено 8 байт, что позволяет адресовывать очень большие файлы.
  • Поддержка POSIX. Также как NT, NTFS полностью соответствует стандарту POSIX 1003.1. Главная особенность формата заключается в назначении имен файлам с учетом регистра символов, а также реализация жестких связей (hard links). Жесткие связи позволяют файлам из разных каталогов ссылаться на одни и те же данные. Жесткая связь создается для существующего файла и указывает на его данные, хотя для пользователя такой объект выглядит как файл.

Разработка новой файловой системы, которая должна удовлетворять вышеперечисленным требованиям очень сложный процесс и здесь разработчики учли опыт MS в разработке FAT и HPFS. Том Миллер так описывает процесс разработки новой ФС:

Работа над файловой системой – это, пожалуй, самое ужасное [при разработке операционной системы]. Если обнаружилась в ядре системы, или что-нибудь странное происходит с дисплеем, то можно просто перезагрузить машину и продолжать работу. Но если что-то случилось с жестким диском, то часто дальнейшая работа вообще невозможна. Всех страшно раздражают ошибки в файловой системе. Никому не хочется, чтобы его постоянная память стала не постоянной.

NTFS имеет следующие версии.

  • Версия 1.0. Была выпущена вместе с NT 3.1 в середине 1993. Включает самый основной функционал ФС.
  • Версия 1.1. Была выпущена вместе с NT 3.5 в 1994.
  • Версия 1.2. Была написана для NT 3.51 (середина 1995) и для NT 4 (середина 1996); последняя, также известна как «NTFS 4.0». Добавлена поддержка сжатия файлов, именованных потоков, защита файлов на основе списков ACL.
  • Версия 3.0. Поставляется с Windows 2000 (известна как «NTFS V5.0»). Добавлена поддержка дисковых квот, шифрования, разреженных файлов (sparse files), точек повторного разбора (reparse points), служебный метакаталог $Extend и его файлы
  • Версия 3.1. Поставляется с Windows XP (осень 2001, «NTFS V5.1»), Windows 2003 (весна 2003, «NTFS V5.2»), Windows Vista (середина 2005, «NTFS V6.0»).

Общие концепции NTFS

  • Метафайлы NTFS – служебные файлы, используемые NTFS для поддержания своей внутренней структуры.
  • Том (volume) NTFS – раздел, отформатированный под NTFS.
  • Главная загрузочная запись (Master Boot Record) – первый сектор жесткого диска, который содержит загрузочный код (bootstrap code) и таблицу разделов (partition table). Загрузочный код читает таблицу разделов, ищет активный (флаг 0x80) раздел и передает управление на его первый сектор (загрузочный сектор).
  • Загрузочный сектор (boot sector) – первый сектор тома, в котором хранятся параметры ФС. Также в загрузочный сектор входит код, который отвечает за чтение ntldr в память. Такой код несет смысл только если том является системным (т. е. только для диска C). В процессе монтирования тома, ntfs.sys проводит валидацию загрузочного сектора и признает его своим в случае совпадение необходимых параметров.
  • Системный том (system volume) – том, на котором располагается ntldr. Для NT системным томом может быть только первый том – С:. Загрузочный том (boot volume) – том, на котором располагается папка windows (winnt).

Формат загрузочного сектора NTFS описывается следующей таблицей (как и все остальные описываемые структуры, наилучшим руководством по ним может служить книга Брайана Кэрриэ «Криминалистический анализ файловых систем»).
Смещение Размер в байтах Описание
0x0 3 Команда перехода на загрузочный код.
0x3 8 Сигнатура ‘NTFS    ’.
0xB 2 Количество байт на сектор
0xD 1 Количество секторов в кластере.
0xE 2 Должно равняться нулю.
0x10 1 Должно равняться нулю.
0x11 2 Должно равняться нулю.
0x13 2 Должно равняться нулю.
0x15 1 Тип носителя
0x16 2 Должно равняться нулю.
0x18 2 Должно равняться нулю.
0x1A 2 Должно равняться нулю.
0x1C 4 Не используется.
0x20 4 Должно равняться нулю.
0x24 4 Не используется.
0x28 8 Число секторов в томе.
0x30 8 Стартовый кластер MFT.
0x38 8 Стартовый кластер копии MFT.
0x40 1 Кластеров на запись MFT.
0x41 3 Не используется.
0x44 1 Кластеров на индексную запись.
0x45 3 Не используется.
0x48 8 Серийный номер тома. Уникален. Создается в процессе форматирования.
0x50 4 Не используется.
0x54 426 Загрузочный код.
0x1FE 2 Маркер конца. Равен 0xAA55.

Соответствующие структуры имеют вид (определения взяты из исходников 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 и, по сути, является файлом. Например, бут сектор - файл $Boot, сам MFT – $Mft.
  • Файл представляет собой набор атрибутов, в которых хранятся все данные. Например, атрибут $STANDART_INFORMATION хранит информацию о файле. Атрибутом также являются и данные. Если файл имеет альтернативные потоки (streams), то таких атрибутов несколько, по числу потоков.
  • LCN – смещение в кластерах относительно тома, VCN – смещение в кластерах относительно файла. Для перевода LCN в смещение на томе следует использовать формулу offs = lcn * bytes_per_sector * sectors_per_cluster, соответствующие значения хранятся в BIOS_PARAMETER_BLOCK в бут секторе.

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.

Содержание Вперёд

NTFS - файловая система, получившая начало в семействе Windows NT и получившая продолжение в новой Windows 7 (обсудить Windows 7 на форуме).

Новости мира IT:

Архив новостей

Последние комментарии:

Loading

IT-консалтинг Software Engineering Программирование СУБД Безопасность Internet Сети Операционные системы Hardware

Информация для рекламодателей PR-акции, размещение рекламы — adv@citforum.ru,
тел. +7 985 1945361
Пресс-релизы — pr@citforum.ru
Обратная связь
Информация для авторов
Rambler's Top100 TopList liveinternet.ru: показано число просмотров за 24 часа, посетителей за 24 часа и за сегодня This Web server launched on February 24, 1997
Copyright © 1997-2000 CIT, © 2001-2015 CIT Forum
Внимание! Любой из материалов, опубликованных на этом сервере, не может быть воспроизведен в какой бы то ни было форме и какими бы то ни было средствами без письменного разрешения владельцев авторских прав. Подробнее...