Студопедия

Главная страница Случайная страница

КАТЕГОРИИ:

АвтомобилиАстрономияБиологияГеографияДом и садДругие языкиДругоеИнформатикаИсторияКультураЛитератураЛогикаМатематикаМедицинаМеталлургияМеханикаОбразованиеОхрана трудаПедагогикаПолитикаПравоПсихологияРелигияРиторикаСоциологияСпортСтроительствоТехнологияТуризмФизикаФилософияФинансыХимияЧерчениеЭкологияЭкономикаЭлектроника






Файловая система NTFS. Файловую систему NTFS принято описывать как сложную реляционную базу данных.




Файловую систему NTFS принято описывать как сложную реляционную базу данных.

Служебные структуры файловой системы NTFS не остаются постоянными, а слегка меняются от одной версии Windows NT к другой.

 

Версия NTFS Операционная система Условное обозначение
1.2 Windows NT NT
3.0 Windows 2000 W2K
3.1 Windows XP XP, Windows Server 2003/08, Vista, Windows 7

 

Основным структурным элементом всякой файловой системы является том (volume), в случае с FAT совпадающий с разделом (partition). NTFS поддерживает тома, состоящие из нескольких разделов. Для простоты можно считать, что том представляет собой отформатированный раздел (т.е. раздел, содержащий служебные структуры файловой системы).

Большинство файловых систем трактуют том, как совокупность файлов, свободного дискового пространства и служебных структур файловой системы, но в NTFS все служебные структуры представлены файлами, которые могут находиться в любом месте тома, при необходимости фрагментируя себя на несколько частей.

Самым главным служебным файлом является $MFT - Master File Table (Главная Файловая Таблица) - своеобразная база данных, хранящая информацию обо всех файлах тома – их именах, атрибутах, способе и порядке размещения на диске (каталог также является файлом особого типа со списком принадлежащих ему файлов и подкаталогов внутри). Важно подчеркнуть, что в MFT присутствуют все файлы, находящиеся во всех подкаталогах тома, поэтому для восстановления диска наличия $MTF-файла будет вполне достаточно.

Остальные служебные файлы, называемые метафайлами или метаданнымиmetafile/metadata, соответственно, и всегда предваряются знаком доллара '$', носят сугубо вспомогательный характер, интересный только самой файловой системе. К ним в первую очередь относится: $LogFile – файл транзакций, $Bitmap – карта свободного/занятого пространства, $BadClust - перечень плохих кластеров и т.д. Текущие версии Windows блокируют доступ к служебным файлам с прикладного уровня (даже с правами администратора) и всякая попытка открытия/создания такого файла в корневом каталоге обречена на неудачу.

Классическое определение отождествляет файл с именованной записью на диске. Большинство файловых систем добавляет к этому понятие атрибута (attribute) – некоторой вспомогательной характеристики, описывающей время создания, права доступа и т.д. В NTFS имя файла, данные файла и его атрибуты полностью уравнены в правах. Можно сказать, что всякий NTFS-файл представляет собой совокупность атрибутов, каждый из которых хранится как отдельный поток (stream) байтов, поэтому во избежание путаницы атрибуты, хранящие данные файла, часто называют потоками.



Каждый атрибут состоит из тела (body) и заголовка (header). Атрибуты делятся на резидентные (resident) и нерезидентные (non-resident). Резидентные атрибуты хранятся непосредственно в $MTF, что существенно уменьшает грануляцию (потерю) дискового пространства и сокращает время доступа. Нерезидентные хранят в $MTF лишь свой заголовок, описывающий порядок размещения атрибута на диске.

Назначение атрибута определяется его типом (type) – четырехбайтовым шестнадцатеричным значением. При желании атрибуту можно дать еще и имя (name), состоящее из символов, входящих в соответствующее пространство имен. Подавляющее большинство файлов имеет, по меньшей мере, три атрибута: стандартная информация о файле (время создания, модификации, последнего доступа, правда доступа и т.д.) хранится в атрибуте типа 10h, условно обозначаемом $STANDARD_INFORMATION. Полное имя файла (не путать с путем!) хранится в атрибуте типа 30h ($FILE_NAME). Если у файла есть одно или более альтернативных имен (например, MS-DOS имя), таких атрибутов может быть и несколько. Здесь же хранится ссылка (file reference) на материнский каталог, позволяющая разобраться, к какому каталогу данный файл/подкаталог принадлежит. Данные файла по умолчанию хранятся в безымянном атрибуте типа 80h ($DATA), однако при желании прикладные приложения могут создавать дополнительные потоки данных, отделяя имя атрибута от имени файла знаком двоеточия (например, "ECHO xxx > file:attr1; ECHO yyy > file:attr2; more < file:attr1; more < file:attr2").



Изначально в NTFS была заложена способность индексации любых атрибутов, значительно сокращающая время поиска файла по заданному списку критериев (например, времени последнего доступа). Внутренне индексы хранятся в виде двоичных деревьев, поэтому среднее время выполнения запроса оценивается как O(lg n). Однако в текущих NTFS-драйверах реализована индексация лишь по одному атрибуту – имени файла. Как уже говорилось выше, каталог представляет собой особенный файл - файл индексов (INDEX). В отличие от FAT, где файл каталога представляет единственный источник данных об организации файлов, в NTFS файл каталога используется лишь для ускорения доступа к содержимому директории и не является обязательным, поскольку ссылка на материнский каталог всякого файла в обязательном порядке присутствует в атрибуте его имени ($FILE_NAME).

Каждый атрибут может быть зашифрован, разряжен или сжат.

 

 

Главная файловая запись (master file table)

В процессе форматирования логического раздела, в его начале создается так называемая MTF-зона (MFT-zone), по умолчанию занимающая 12.5% от емкости тома, однако в зависимости от значения от параметра NtfsMftZoneReservation она может составлять 25%, 37% или 50%.

В этой области расположен $MFT-файл, изначально занимающий порядка 64 секторов и растущий от начала MFT-зоны к ее концу по мере создания новых пользовательских файлов/подкаталогов. Таким образом, чем больше файлов содержаться на дисковом томе, тем больше размер MTF. Приблизительный размер MFT-файла можно оценить по следующей формуле: sizeof(FILE Record) * N Files, где sizeof(FILE Record) обычно равен 1 Кбайт, а N Files - полное количество файлов/подканалов раздела, включая недавно удаленные.

Для предотвращения фрагментации $MFT-файла MFT-зона держится зарезервированной, вплоть до полного исчерпания свободного пространства тома, затем незадействованный "хвост" MFT-зоны усекается в два раза, освобождая место для пользовательских файлов. Этот процесс может повторяться многократно, вплоть до полной отдачи всего зарезервированного пространства. Решение красивое, хотя и не новое. Многие из файловых систем восьмидесятых позволяли резервировать заданное дисковое пространство в хвосте активных файлов, тем самым сокращая их фрагментацию (причем любых файлов, а не только служебных). В частности, такая способность была у DOS 3.0.

Когда $MFT-файл достигает границ MFT-зоны, в ходе своего последующего роста он неизбежно фрагментируется, вызывая обвальное падение производительности файловой системы, причем подавляющее большинство дефрагментаторов $MFT-файл не обрабатывают, несмотря на то, что ведь API дефрагментации, встроенное в штатный NTFS-драйвер, это в принципе позволяет. Но, как бы там ни было, заполнять дисковый том более чем на 88% его емкости категорически не рекомендуется!

При необходимости, $MFT-файл может быть перемещен в любую часть диска и тогда в начале тома его уже не окажется. Стартовый адрес $MFT-файла хранится в Boot-секторе по смещению 30h байт от его начала и в подавляющем большинстве случаев этот адрес ссылается на 4-й кластер.

Рисунок Структура дискового тома под NTFS.

 

$MFT-файл представляет собой массив записей типа FILE Record (или в терминологии UNIX - inodes), каждая из которых описывает соответствующий ей файл или подкаталог. В подавляющем большинстве случаев один файл/подкаталог полностью описывается одной-единственной записью FILE Record, хотя, теоретически, этих записей может потребоваться и несколько.

Для ссылки на одну файловую запись из другой используется ее порядковый номер (он же индекс) в $MFT файле, отсчитываемый от нуля. Файловая ссылка (file reference) состоит из двух частей – 48-битного индекса и 16-битного номера последовательности (sequence number).

При удалении файла/каталога соответствующая ему файловая последовательность помечается как неиспользуемая. При создании новых файлов записи, помеченные как неиспользуемые, могут задействоваться вновь, при этом счетчик номера последовательности, хранящийся внутри файловой записи, увеличивается на единицу. Этот механизм позволяет отслеживать "мертвые" ссылки на уже удаленные файлы – очевидно, sequence number внутри file reference будет отличается от номера последовательности соответствующей файловой записи.

 

Смещение Размер Описание
00h Индекс файловой записи (FILE record number), отсчитываемый от нуля
06h Номер последовательности (sequence number)

Таблица Структура файловой ссылки (file reference).

 

Первые 12 записей в MFT всегда занимают служебные метафайлы: $MFT (собственно, сам $MFT), $MFTMirr (зеркало $MFT), $LogFile (файл транзакций), $Volume (сведения о дисковом томе), $AttrDef (определенные атрибуты), '.' (корневой каталог), $Bitmap (карта свободного пространства), $Boot (системный загрузчик), $BadClus (перечень плохих кластеров) и т.д.

Первые четыре записи настолько важны, что продублированы в специальном $MFTMirr-файле, находящимся приблизительно посередине диска (точное расположение хранится в boot-секторе по смещению 38h байт от его начала). Вопреки своему названию, $MFTMirr это отнюдь не зеркало всего $MFT-файла, это всего лишь копия первых четырех элементов.

Записи с 12 по 15 помечены как используемые, но в действительности же они пусты (как нетрудно догадаться, это задел на будущее). Записи с 16 по 23 не задействованы и честно помечены как неиспользуемые.

Начиная с 24-й записи, располагаются пользовательские файлы и каталоги. Четыре метафайла, появившихся в W2K - $ObjId, $Quota, $Reparse и $UsnJrnl могут располагаться в любой записи, номер которой равен 24 или больше (как мы помним, номера файловых записей отсчитываются, начиная с нуля).

 

Структурно файловая запись состоит из заголовка (header) и одного или нескольких атрибутов (attribute) произвольной длины, завершаемых маркером конца (end marker) - четырехбайтовым шестнадцатеричным значением FFFFFFFFh. Несмотря на то, что количество и длина атрибутов меняется от одной файловой записи к другой, размер самой структуры FILE Record строго фиксирован и в большинстве случаев равен 1 Кбайту (это значение хранится в $boot-файле, не путать с boot-сектором!). Причем, первый байт файловой записи всегда совпадает с началом сектора.

Если реальная длина атрибутов меньше размеров файловой записи, ее хвост просто не используется. Если же атрибуты не вмещаются в отведенное им пространство, создается дополнительная файловая запись (extra FILE Record), ссылающаяся на свою предшественницу.

Структура файловой записи имеет следующий вид.

FILE Record

Header ; заголовок

Attribute 1 ; атрибут 1

Attribute 2 ; атрибут 2

... ; ...

Attribute N ; атрибут N

End Marker (FFFFFFFFh) ; маркер конца

Первые четыре байта заголовка оккупированы последовательностью "FILE", сигнализирующей о том, что мы имеем дело с файловой записью типа FILE Record. При восстановлении сильно фрагментированного $MFT файла это обстоятельство играет решающую роль, поскольку позволяет отличить сектора, принадлежащие MFT, от всех остальных секторов.

Следом за сигнатурой идет 16-разрядный указатель, содержащий смещение последовательности обновления (update sequence). Под "указателем" подразумевается смещение от начала сектора, отсчитываемое от нуля и выраженное в байтах. В NT и W2K это поле всегда равно 002Ah, поэтому для поиска файловых записей можно использовать сигнатуру "FILE*\x00", что уменьшает вероятность ложных срабатываний. Правда, в XP и более старших системах последовательность обновления хранится по смещению 002Dh и поэтому сигнатура приобретает следующий вид "FILE-\x00".

Размер заголовка (кстати сказать, варьирующийся от одной операционной системы к другой) в явном виде нигде не хранится, вместо этого в заголовке присутствует указатель на первый атрибут, содержащий его смещение в байтах относительно начала FILE Record, расположенный по смещению 14h байт от начала сектора. Смещения последующих атрибутов (если они есть) определяются путем сложения размеров всех предыдущих атрибутов (размер каждого из атрибутов содержится в его заголовке) со смещением первого атрибута. За концом последнего атрибута находится маркер конца - FFFFFFFFh.

Вдобавок к этому, длина файловой записи хранится в двух полях - 32-разрядное поле реального размера (real size), находящееся по смещению 18h байт от начала сектора и содержащее совокупный размер заголовка, всех его атрибутов и маркера конца, округленный по 8 байтной границе и 32-разрядное поле выделенного размера (allocated size), находящееся по смещению 1Сh байт от начала сектора, содержащее действительный размер файловой записи в байтах, округленный по размеру сектора. Документация Linux-NTFS Project (версия 0.4) утверждает, что allocated size должен быть кратен размеру кластера, однако в действительности это не так.

16-разрядное поле флагов, находящееся по смещению 16h байт от начала сектора, в подавляющем большинстве случаев принимает одно из трех следующих значений: 00h - данная файловая запись не используется или ассоциированный с ней файл/каталог удален, 01h - файловая запись используется и описывает файл, 02h - файловая запись используется и описывает каталог.

64-разрядное поле, находящееся по смещению 20h байт от начала сектора содержит индекс базовой файловой записи. Для первой файловой записи это поле всегда равно нулю, а для всех последующих, расширенных (extra) записей - индексу первой файловой записи. Расширенные файловые записи могут находиться в любых частях MFT, не обязательно рядом с основной записью. А коль скоро так, необходим какой-то механизм, обеспечивающий быстрый поиск расширенных файловых записей, принадлежащих данному файлу (просматривать весь MFT целиком не предлагать!). И этот механизм основан на ведении списков атрибутов $ATTRIBUTE_LIST. Список атрибутов представляет собой специальный атрибут, добавляемый к первой файловой записи и содержащий индексы расширенных записей. Формат списка атрибутов приведен в разделе "типы атрибутов".

 

Смещение Размер ОС Описание
00h любая сигнатура (magic number) 'FILE'
04h любая смещение номера последовательности обновления (update sequence number)
06h любая размер в словах номера последовательности обновления и массива обновления (Update Sequence Number & Array), условно (S)
08h любая номер последовательности файла транзакций ($LogFile Sequence Number или сокращенно LSN)
10h любая номер последовательности (sequence number)
12h любая счетчик жестких ссылок (hard link)
14h любая смещение первого атрибута (attribute)
16h любая
Значение Описание
0x00 файловая запись не используется
0x01 файловая запись используется и описывает файл (file)
0x02 файловая запись используется и описывает каталог (directory)
0x04 только Билл Гейтс знает
0x08 только Билл Гейтс знает

 

18h любая реальный размер (real size) файловой записи
1Ch любая выделенный размер (allocated size) файловой записи
20h любая ссылка (file reference) на базовую файловую запись (base FILE record) или ноль, если данная файловая запись базовая
28h любая идентификатор следующего атрибута (next attribute ID)
2Ah XP для выравнивания
2Ch XP индекс данной файловой записи (number of this MFT record)
  любая номер последовательности обновления (update sequence number)
  2S-2 любая массив последовательности обновления (update sequence array)

Таблица Структура заголовка файловой записи (FILE Record).

Последовательности обновления (update sequence)

Будучи очень важными компонентами файловой системы, $MFT, INDEX и $LogFile нуждаются в механизме контроля целостности своего содержимого. Традиционно для этого используется ECC/EDC-коды, однако во времена проектирования NTFS процессоры были не настолько быстрыми, как теперь и расчет корректирующих кодов занимал значительное время, существенно снижающее производительность файловой системы. Поэтому от них пришлось отказаться. Вместо этого, разработчики NTFS применили так называемые последовательности обновления (update sequence), также называемые fix-up'ами.

В конец каждого из секторов, слагающих файловую запись (INDEX Record, RCRD Record или RSTR Record) записывается специальный 16-байтовый номер последовательности обновления (update sequence number), дублируемый в заголовке файловой записи. При каждой операции чтения два последних байта сектора сверяется с соответствующим полем заголовка и если NTFS-драйвер обнаруживает расхождение, данная файловая запись считается недействительной.

Основное назначение последовательностей обновления – защита от "обрыва записи". Если в процессе записи сектора на диск, исчезнет питающее напряжение, может случиться так, что половина файловой записи будет успешно записана, а половина - сохранит прежнее содержимое (файловая запись, как мы помним, обычно состоит из двух секторов). После восстановления питания, драйвер файловой системы не может уверенно сказать - была ли файловая запись записана целиком или нет. Вот тут-то последовательности обновления и выручают! При каждой перезаписи сектора update sequence увеличивается на единицу и потому, если произошел обрыв записи, значение последовательности обновления, находящейся в заголовке файловой записи не будет совпадать с последовательностью обновления, расположенной в конце сектора.

Оригинальное содержимое, расположенное "под" последовательностью обновления, хранится в специальном массиве обновления (update sequence array), расположенном в заголовке файловой записи непосредственно за концом update sequence number. Для восстановления файловой записи в исходный вид мы должны извлечь из заголовка указатель на update sequence number (он хранится по смещению 04h байт от начала заголовка) и сверить лежащее по этому адресу 16-байтное значение с последним словом каждого из секторов, слагающих файловую запись (INDEX Record, RCRD Record или RSTR Record). Если они не совпадут, значит, соответствующая структура данных повреждена и использовать ее следует с очень большой осторожностью (или не использовать вообще).

По смещению 006h от начала сектора находится 16-разрядное поле, хранящее совокупный размер номера последовательности обновления вместе с массивном последовательности обновления (sizeof(update sequence number) + sizeif(update sequence array)), выраженный в словах (не в байтах). Поскольку размер номера последовательности обновления всегда равен одному слову, то размер массива последовательности обновления, выпаженный в байтах, равен: (update sequence number & update sequence array ‑ 1) * 2. Соответственно, смещение массива оригинального содержимого равно (offset to update sequence number) + 2. В NT и W2K update sequence number всегда располагается по смещению 2Ah от начала FILE Record Header/INDEX Header, а update sequence array - по смещению 2Сh. В XP же и более старших системах - по смещениям 2Dh и 2Fh соответственно.

Первое слово массива последовательности обновления соответствует последнему слову первого сектора FILE Record/INDEX. Второе - последнему слову второго сектора, и т.д. Для восстановления сектора в исходный вид мы должны вернуть все элементы массива последовательности обновления на их законные места (естественно, модифицируется не сам сектор, а его копия в памяти).

Атрибуты (attribute)

Структурно всякий атрибут стоит из атрибутного заголовка (attribute header) и тела атрибута (attribute body). Заголовок атрибута всегда хранится в файловой записи, расположенной внутри MFT . Тела резидентных атрибутов хранятся там же. Нерезидентные атрибуты хранят свое тело вне MFT в одном или нескольких кластерах, перечисленных в заголовке данного атрибута в специальном списке. Если 8-разрдное поле, расположенное по смещению 08h байт от начала атрибутного заголовка, равно нулю – атрибут считается резидентным, а если единице, то – нет. Любые другие значения недопустимы.

Первые четыре байта атрибутного заголовка определяют его тип. Тип атрибута в свою очередь определяет формат представления тела атрибута. В частности, тело атрибута данных (тип: 80h - $DATA) представляет собой "сырую" последовательность байт. Тело атрибута стандартной информации (тип: 10h - $STANDARD_INFORMATION) описывает время его создания, права доступа и т.д.

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

Длина тела резидентных атрибутов, выраженная в байтах, хранится в 32-разрядном поле, расположенном по смещению 10h байт от начала атрибутного заголовка. 16-разрядное поле, следующее за его концом, хранит смещение резидентного тела, отсчитываемое от начала атрибутного заголовка. С нерезидентными атрибутами в этом плане все намного сложнее и для хранения длины их тела используется множество полей. Реальный размер тела атрибута (real size of attribute), выраженный в байтах, хранится в 64-разрядном поле, находящимся по смещению 30h байт от начала атрибутного заголовка. Следующее за ним 64-разрядное поле хранит инициализированный размер потока (initialized data size of the stream), выраженный в байтах и, судя по всему, всегда равный реальному размеру тела атрибута. 64-разрядное поле, расположенное по смещению 28h байт от начала атрибутного заголовка, хранит выделенный размер (allocated size of attribute), выраженный в байтах и равный реальному размеру тела атрибута округленному до размера кластера (в большую сторону).

Два 64-разрядных поля, расположенные по смещению 10h и 18h байт от начала атрибутного заголовка задают первый (starting VCN) и последний (last VCN) номер виртуального кластера, принадлежащего телу нерезидентного атрибута. Виртуальные кластеры представляют собой логические номера кластеров, не зависящие от своего физического расположения на диске. В подавляющем большинстве случаев номер первого кластера тела нерезидентного атрибута равен нулю, а последний - количеству кластеров занятых телом атрибута, уменьшенном на единицу. 16-разрядное поле, расположенное по смещению 20h от начала атрибутного заголовка содержит указатель на массив Data Runs, расположенный внутри этого заголовка и описывающий логический порядок размещения нерезидентного тела атрибута на диске.

Каждый атрибут имеет свой собственный идентификатор (attribute ID), уникальный для данной файловой записи и хранящийся в 16-разрядном поле, расположенном по смещению 0Eh от начала атрибутного заголовка.

Если атрибут имеет имя (attribute Name), то 16-разрядное поле, расположенное по смещению 0Ah байт от атрибутного заголовка, содержит указатель на него. Для безымянных атрибутов оно равно нулю (а большинство атрибутов безымянны!). Имя атрибута хранится в атрибутном заголовке в формате UNICODE, а его длина определяется 8-разрядным полем, расположенным по смещению 09h байт от начала атрибутного заголовка.

Если тело атрибута сжато, зашифровано или разряжено, 16-разряное поле флагов, расположенное по смещению 0Ch байт от начала атрибутного заголовка не равно нулю.

Смещение Размер Значение Описание
00h   тип (type) атрибута (например, 0x10, 0x60, 0xB0)
04h   длина атрибута, включая этот заголовок
08h 00h нерезидентный флаг (non-resident flag)
09h N длина имени атрибута (ноль, если атрибут безымянный)
0Ah 18h смещение имени (ноль, если атрибут безымянный)
0Ch 00h
Значение Описание
0001h сжатый атрибут (compressed)
4000h зашифрованный атрибут (encrypted)
8000h разряженный атрибут (sparse)

 

0Eh   идентификатор атрибута (attribute ID)
10h L длина тела атрибута, без заголовка
14h 2N+18h смещение тела атрибута
16h   индексный флаг
17h 00h для выравнивания
18h 2N UNICODE имя атрибута (если есть)
2N+18h L   тело атрибута

Структура резидентного атрибута.

 

Смещение Размер Значение Описание
00h   тип (type) атрибута (например, 0x20, 0x40)
04h   длина атрибута, включая этот заголовок
08h 01h нерезидентный флаг (non-resident flag)
09h N длина имени атрибута (ноль, если атрибут безымянный)
0Ah 40h смещение имени (ноль, если атрибут безымянный)
0Ch  
Значение Описание
0001h сжатый атрибут (compressed)
4000h зашифрованный атрибут (encrypted)
8000h разряженный атрибут (sparse)

 

0Eh   идентификатор атрибута (attribute ID)
10h   начальный виртуальный кластер (starting VCN)
18h   конечный виртуальный кластер (last VCN)
20h 2N+40h смещение списка отрезков (data runs)
22h   размер блока сжатия (compression unit size), округленный до 4 байт вверх
24h 00h для выравнивания
28h   выделенный размер (allocated size), округленный до размера кластера
30h   реальный размер (real size)
38h   инициализированный размер потока (initialized data size of the stream)
40h 2N UNICODE имя атрибута, если есть
2N+40h ...   список отрезков (data runs)

Структура нерезидентного атрибута.


mylektsii.ru - Мои Лекции - 2015-2019 год. (0.023 сек.)Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав Пожаловаться на материал