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

3.2. Fat "Малых Блоков"

Хранить множество малоразмерных объектов в 512-байтных секторах довольно нерационально. Поэтому в структуре составного файла предусмотрена возможность размещать данные в маленьких, 64-байтовых "блочках" (small blocks).

Идеология расположения 64-байтовых "блочков" мало отличается от рассмотренной нами в предыдущем разделе для 512- байтовых "больших блоков". Под них выделяются область составного файла, отдельные "блочки" в которой пронумерованы с 0.

Но область "блочков" носит подчиненный характер. Она описана в "главной" FAT как отдельный объект, под который отведена отдельная цепочка секторов. Для нее же существует отдельная FAT, которая тоже фактически представлена цепочкой 512-байтовых секторов в "главной" FAT.

Числа в строчках "маленькой" FAT соответствуют не абсолютным номерам 512-байтовых секторов, а относительным номерам 64-байтовых "блочков" внутри своей области.

Местоположение стартового сектора FAT "блочков" берется из заголовка составного файла (смещение 3Сh), остальные можно вытянуть по цепочке в "главной" FAT. Не хватает только информации о том, где брать стартовый сектор области, распределенной под "блочки", но речь об этом пойдет в следующем разделе.

Кстати, область "блочков" в файле может просто отсутствовать.

3.3. Структура каталога

Вопреки нашим предварительным предположениям, каталогов внутри составного файла не несколько, он - один единственный! Сей объект также представлен цепочкой секторов внутри "главной" FAT, а номер его стартового сектора можно найти в заголовке составного файла по смещению 30h.

Каталог состоит из 128-байтовых записей следующей структуры:

struct DIR_ENTRY

{

BYTE ИмяОбъекта[64]; // +00 - имя объекта в UNICODE

WORD РазмерИмени; // +40h - фактическая длина имени

BYTE ТипОбъекта; // +42h - 1,2,3 или 5

BYTE НеИспользуется1; // +43h

DWORD Предыдущий; // +44h - предыдущий объект

DWORD Следующий; // +48h - следующий объект

DWORD Первый; // +4Сh - первый подчиненный

DWORD НеИспользуется2[9]; // +50h

DWORD СтартСектор; // +74h - стартовый сектор объекта

DWORD РазмерОбъекта; // +78h - размер объекта в байтах

DWORD НеИспользуется3; // +7Сh

};

Хотя записи в каталогах обычно называются термином "entry" (вхождение), разработчики OLE решили (IMHO, напрасно!) взглянуть на них с точки зрения объектного подхода и назвали их (а также те объекты, которые они описывают) словом "property" (свойство). Остается только сокрушенно покачать головой по этому поводу и продолжать называть вещи пусть и "нелегальными", но более понятными именами.

Имя объекта записывается латинскими буквами и хранится в формате UNICODE, т.е. для того, чтобы перевести его в удобочитаемую форму, потребуется собрать вместе все нечетные байты. Имейте в виду: самый первый символ имени может оказаться "нечитабельным" и иметь значение, например, 05h ("трефы") или 01h ("рожица"). Не пугайтесь, это так и должно быть. Фактическая длина имени хранится в записи по смещению 40h.

Тип объекта описан байтом, хранящимся по смещению 42h:

  1. 1 - это подкаталог нижнего уровня;

  2. 2 - поток (т.е. набор каких-то данных);

  3. 3 - lock-bytes (?)

  4. 5 - корневой каталог.

Местоположение объекта задается номером его стартового сектора (см. смещение 74h), под которым его и нужно искать в FAT. А фактическая длина объекта (например, потока) располагается по смещению 78h. Необходимо иметь в виду: если длина объекта >= 1000h = 4096, то он располагается в больших 512- байтовых блоках (т.е. в секторах). В противном случае значение по адресу 74h указывает на стартовый "блочок" в области 64-байтовых "блочков". Сама эта область представлена в каталоге как "Root Entry", и искать ее следует в FAT больших блоков (даже если ее длина <4096) - вот она, недостававшая нам в предыдущем разделе информация!

Три поля по смещениям 44h, 48h и 4Сh описывают отношения страшинства между объектами. Для каталогов и подкаталогов (но не для потков!) в поле "Первый" хранится номер записи для какого-то своего дочернего объекта, которые, в свою очередь, имеют своих "Следующих" и т. д. Таким образом, все записи в каталоге упорядочиваются в виде дерева.

Вот дамп одной из записей в каталоге:

05 00 44 00-6F 00 63 00-75 00 6D 00-65 00 06 00 ..D.o.c.u.m.e.n

74 00 53 00-75 00 6D 00-6D 00 61 00-72 00 79 00 t.S.u.m.m.a.r.y

49 00 06 00-66 00 6F 00-72 00 6D 00-61 00 74 00 I.n.f.o.r.m.a.t

69 00 6F 00-6E 00 00 00-00 00 00 00-00 00 00 00 .i.o.n.........

38 00 02 01-02 00 00 00-04 00 00 00-FF FF FF FF 8..............

00 00 00 00-00 00 00 00-00 00 00 00-00 00 00 00 ...............

00 00 00 00-00 00 00 00-00 00 00 00-00 00 00 00 ...............

00 00 00 00-10 00 00 00-00 10 00 00-00 00 00 00 ...............

Легко видеть, что:

  1. имя объекта \5DocumentSummaryInformation;

  2. длина имени 38h = 56 байтов;

  3. тип объекта = 2, т.е. это поток;

  4. предыдущий объект имеет номер = 2;

  5. следующий объект имеет номер = 4;

  6. стартовый сектор = 10h, т.е. файловая позиция = 2200h;

  7. размер = 1000h = 4096 байтов, т.е. искать его надо в "больших блоках".

А вот пример полного каталога:

# „I„}„‘ „S„y„Ѓ „P„‚„u„t „R„|„u„t „P„u„‚„r „R„„„p„‚„„ „Q„p„x„}

0 Root Entry 5 -1 -1 3 24 1440

1 \1Table 2 -1 -1 -1 8 1000

2 WordDocument 2 5 -1 -1 0 1000

3 \5SummaryInformation 2 2 4 -1 10 1000

4 \5DocumentSummaryInformation 2 -1 -1 -1 18 1000

5 Macros 1 1 C B 0 0

6 VBA 1 -1 -1 7 0 0

7 ThisDocument 2 9 8 -1 0 44D

8 _VBA_PROJECT 2 -1 -1 -1 12 AA5

9 dir 2 -1 -1 -1 3D 2A3

A PROJECTwm 2 -1 -1 -1 48 29

B PROJECT 2 6 A -1 49 151

C \1CompObj 2 -1 D -1 4F 6A

D ObjectPool 1 -1 -1 -1 0 0

Попробуем выполнить упорядочивание. Начнем с узла "0" ("Root Entry"), его первым "сыном" является узел "3". Собрав воедино все узлы, связанные с узлом "0" и между собой, получим следующее множество: {1, 2, 3, 4, 5, С, D}. Оно образует первый уровень дерева.

На первом уровне присутствуют три объекта со статусом каталогов: "5" и "D". Дочерними объектами каталога "5" являются узел "B" и все связанные с ним объекты: {A, B, 6}. Каталог "D" не имеет дочерних объектов, т.е. он пуст. И так далее...

Можно написать несложный рекурсивный алгоритм, который построит желаемое дерево:

Итак, с составным файлом можно работать не только через OLE API, но и напрямую - например, из DOS-овской программы.

Данный раздел является существенно упорядоченным и несколько дополненным изложением статьи M. Schwartz. LAOLA file system. Единственный известный мне перевод этой статьи на русский язык можно найти, например, в материалах 4 -го выпуска электронного журнала "Земский Фершал".

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