Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лек 008.doc
Скачиваний:
14
Добавлен:
07.02.2015
Размер:
47.62 Кб
Скачать

3. Низкоуровневый доступ к structured storage

Широко известен народный персонаж по имени Чукча, который служил "писателем" и по этой причине не считал для себя нужным учиться читать. Наверное, имеются автомобилисты, которые никогда не заглядывали под капот своего четырехколесного друга. Не исключено, что существуют нежно любящие друг друга супруги, которые ни разу в жизни... гм... надеюсь, мы к их числу не относимся?

Давайте же приоткроем "кошмарную тайну кровавой фирмы Microsoft": посмотрим на составной файл невооруженными глазками и пощупаем его голыми ручками. Впрочем, "программисты", которые умеют только кликать по иконкам и таскать мышом картинки между окошкам, могут этот раздел с чистой совестью пропустить.

Составной файл состоит из целого числа "больших блоков" (big blocks), размер каждого из которых соответствует одному дисковому сектору, т.е. 512 байт. Поэтому, в отличие от англоязычной документации, мы будем называть их просто секторами. Все сектора в файле пронумерованы следующим образом: -1, 0, 1, 2... и т.д.

Сектор с номером -1 содержит заголовок составного файла:

struct DOC_FILE_HEADER

{

DWORD Сигнатура; // +00h - "магическое" число E011CFD0h

DWORD КодВерсииOLE; // +04h - "магическое" число E11AB1A2h

DWORD НеИспользуется1[9];

DWORD РазмерBBD; // +2Ch - количество секторов в BBD

DWORD НачалоКаталога; // +30h - стартовый сектор каталога

DWORD НеИспользуется2[2];

DWORD НачалоSBD; // +3Сh - стартовый сектор SBD

DWORD РазмерСектора; // +40h - обычно имеет значение 1

DWORD НеИспользуется3[2];

DWORD НачалоBBD; // +4Ch - стартовый сектор BBD

};

Примечание. Есть предположние, что по смещению 40h располагается поле, описывающее размер сектора. В подавляющем большинстве DOC-файлов длиной до 1 Мб в этом поле содержится значение 1 (т.е. размер сектора равен 512), но изредка встречается 2 (т.е. размер сектора равен 1024). Вероятно, возможны 3, 4, и так далее. В этом случае лучше говорить не о "секторах", но о "кластерах". Но идеология организации составного файла от этого не меняется.

Теперь очень легко проверить, организован ли какой-нибудь файл по правилам структурированного хранилища: достаточно проверить его первые 4 байта. Они должны быть: 0D0h, 0CFh, 11h, E0h.

Все остальное, не занятое заголовком, пространство составного файла разбито на четыре (не обязательно непрерывных!) области:

  1. область каталогов;

  2. FAT данных, организованных в виде 512-байтовых больших блоков (в оригинале это BBD - big blocks depot);

  3. FAT даных, организованных в виде 64-байтовых малых блоков (в оригинале это SBD - small blocks depot);

  4. область собственно данных.

3.1. Fat "Больших Блоков"

Я не случайно пошел вразрез с англоязычной терминологией. Дело в том, что структура, о которой пойдет речь в этом разделе, является ничем иным, как FAT - File Allocation Table, т.е. таблицей секторов, занимаемых файлом (вернее, занимаемых потоком или каким-либо другим объектом). А оригинальный термин "BBD - big blocks depot" может только ввести в заблуждение.

FAT - она и в Африке FAT. Это последовательный список 4-байтовых "строчек", каждая из которых соответствует одному сектору. Нулевая запись соответствует сектору с номером 0 (т.е. 512-байтовому сектору, начинающемуся в файле по абсолютному смещению 200h), первая - сектору с номером 1 (смещение 400h) и т.д. Еще раз напомним: сектора нумеруются с -1, т.е. самый первый сектор составного файла в этой таблице просто не упоминается!

Содержимое 4-байтовой строчки FAT может быть выбрано из следующих вариантов:

  1. -3 = 0FFFFFFFDh - признак специального сектора;

  2. -2 = 0FFFFFFFEh - конец цепочки секторов;

  3. -1 = 0FFFFFFFFh - неиспользуемый сектор;

  4. иное >0 - номер сектора, следующего за текущим.

Если мы знаем номер стартового сектора для какого-либо объекта (например, для потока), мы легко можем вытянуть всю цепочку принадлежащих ему секторов. Вот конкретный пример, фрагмент дампа файла, содержащий начало FAT:

01 00 00 00 - 02 00 00 00 - 05 00 00 00 - 06 00 00 00

07 00 00 00 - 03 00 00 00 - FF FF FF FE - 08 00 00 00

FF FF FF FE - FF FF FF FD - FF FF FF FF - FF FF FF FF

Давайте выпишем значения "строчек" таблицы в более удобной для глаза форме и в скобочках каждой строчке припишем ее номер:

(00) 01

(01) 02

(02) 05

(03) 06

(04) 07

(05) 03

(06) -2

(07) 08

(08) -2

(09) -3

(0A) -1

(0B) -1

Допустим, известно, что стартовый сектор потока имеет значение 0, т.е. этот сектор заведомо уже принадлежит потоку. В нулевой строчке читаем: следующий сектор потока имеет номер 1. Переходим к строчке номер 1, и т.д., окончательно получаем цепочку номеров секторов: {0, 1, 2, 5, 3, 6}. Именно так, именно в таком порядке и разместил MS Word фрагменты какого-то потока внутри составного файла!

Кстати, обратите внимание на вклинившиеся куски какого-то другого объекта, живущего в секторах {4, 7, 8} и на пустые сектора с адресами 0A и 0B. Вероятно, это свидетельство того, что над документом долго и мучительно работали: многократно удаляли и вставляли фрагменты текста, рисунки, формулы и т.п.

Осталось выяснить, как же до этой FAT добраться. Смотрим на заголовок составного файла: по смещению 4Ch живет адрес стартового сектора в составном файле, а количество этих секторов живет по смещению 2Ch. Сектора располагаются непрерывно.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]