NedoPC #6 2011 г.

Теория - FAT на Спектруме (по мотивам «FAT32 File System Specification»).


Автор: Savelij

Email: savelij13@yandex.ru

Cтатья основана на документе «FAT32 File System Specification» (fatgen), в которой описаны все разновидности FAT (целых 3 штуки-12, 16 и 32 битные), а не только FAT32 как гласит название. На основе этой спецификации был написан драйвер по работе с FAT всех трех разновидностей, определение разрядности делается при инициализации переменных драйвера.

В статье описано только то, что реально используется в драйвере, за более полной информацией обращаться к вышеуказанному документу или к другим соответствующим документам.

Некоторое отступление от темы или с чего начинается файловая система.

Любая файловая система может располагаться на дискетах, винчестерах, SD картах и других устройствах хранения информации. При размещении на носителях для каждой файловой системы выделяется место, называемое разделом (partition). Разделы подразделяются на основные (primary partition) и расширенные (extended partition). Расширенный раздел может быть только один. Внутри расширенного раздела можно создать любое количество логических дисков.

Для размещения информации о начале, типе и размерах разделов в самом первом секторе носителя располагается MBR (Master Boot Record-главная загрузочная запись). MBR состоит из предзагрузчика и 4-х 16-ти байтных описателей разделов. В драйвере используются только описатели разделов, если MBR обнаружен.

Структура MBR:

Смещение в секторе

Размер

Описание

446 (#1BE)

16 (#10)

Описатель 1-го раздела

462 (#1CE)

16 (#10)

Описатель 2-го раздела

478 (#1DE)

16 (#10)

Описатель 3-го раздела

494 (#1EE)

16 (#10)

Описатель 4-го раздела

Структура описателя раздела:

Смещение

Размер

Описание

0

1

Признак активности раздела

4

1

Код типа раздела

8

4

Смещение первого сектора

Признак активности раздела — может принимать два значения:

• #00-раздел не активен;

• #80-раздел активен.

Тип раздела — соответсвует типу файловой системы (всего типов файловых систем очень много). Для FAT может принимать значения:

• #01 - FAT12;

• #06, #0E - FAT16;

• #0B, #0C - FAT32.

Смещение первого сектора — смещение раздела от первого сектора носителя в секторах. При работе в LBA режиме на винчестере и при работе с SD картами достаточно знать смещение раздела.

Основных разделов можно создать только четыре. Возможно создать расширенный раздел (чтобы создать число разделов больше 4-х), под который может отводиться все оставшееся место на устройстве. Внутри расширенного раздела можно создать любое количество дополнительных разделов (secondary partition). Расширенный раздел может быть только один.

При создании на устройстве хранения данных одного раздела, MBR может отсутствовать и в самом первом секторе может располагаться непосредственно описатель раздела, который может занимать все пространство носителя. При отсутствии MBR имеет место быть некоторая проблема в

FAT на Спектруме. Теория.


правильном определении разрядности FAT.

FAT — File Allocation Table (таблица размещения файлов).

Раздел FAT подразделяется на следующие области:

1) загрузочный сектор - загрузчик раздела и BPB;

2) таблица размещения файлов -собственно FAT (традиционно в двух экземплярах, но вообще-то количество копий указано в загрузочном секторе). Содержит список всех кластеров;

3) корневой каталог;

4) файлы.

BPB (BIOS Parameter Block).

BPB (BIOS Parameter Block) - описатель FAT раздела. Описатель раздела — первый сектор раздела, на начало которого указывает 16-ти байтный описатель в MBR или при отсутствии MBR сектор находящийся в самом первом секторе носителя. Кроме описателя раздела в этом же секторе может находится загрузчик операционной системы. В связи с тем, что BPB не является целостной структурой и изменялся по мере повышения разрядности FAT некоторые значения BPB перемешаны со структурой самого загрузочного сектора.

Приведу описания некоторых значений, достаточных для работы с FAT любой разрядности (12, 16 или 32 битной). Полное описание можно найти в соответствующей документации. В дальнейшем описании, все поля, начинающиеся с BPB_, являются частью BPB. Все поля, начинающиеся с BS_, являются частью загрузочного сектора (к BPB не принадлежат). Смещение указано в байтах от начала сектора, размер указан также в байтах.

BPB структу

ра:

Имя

Смещ ение

Раз мер

Описание

BPB_BytsPerSec

11

(#0B)

2

Количество байтов в секторе.

BPB_SecPerClus

13 (#0D)

1

Количество секторов в кластере. Значение должно быть числом в степени 2, и больше 0. Разрешённые

значения: 1, 2, 4, 8, 16, 32, 64 и 128.

BPB_RsvdSecCnt

14

(#0E)

2

Количество секторов в Reserved region (начинается с первого сектора диска). Должно быть больше 0. Для FAT12 и FAT16 дисков, это значение должно быть только 1.

BPB_NumFATs

16 (#10)

1

Для FAT12 и FAT16 дисков, это поле содержит число 32-байтных элементов корневой директории. Для FAT32 дисков, это поле должно быть 0. Для FAT12 и FAT16 дисков значение этого поля, умноженное на 32 должно быть кратно BPB_BytsPerSec. Для максимальной совместимости FAT16 диски должны содержать значение 512.

BPB_RootEntCnt

17 (#11)

2

Для FAT12/16 дисков это поле содержит число 32-байтных элементов корневой директории. Для FAT32 дисков это поле должно быть 0. Для FAT12/16 дисков значение этого поля, умноженное на 32 должно быть кратно BPB_BytsPerSec. Для максимальной совместимости FAT16 диски должны содержать значение 512.

BPB_TotSec16

19 (#13)

2

Старое 16-битное поле: общее количество секторов на диске. Это количество включает в себя все четыре региона диска. Значение не 0, но если равно 0, то BPB_TotSec32 должно быть не 0. Для FAT32 дисков значение всегда 0. Для FAT12 и FAT16 дисков это поле содержит количество секторов, а BPB_TotSec32 равно 0, если значение «умещается» (меньше 0x10000).

BPB_FATSz16

22 (#16)

2

Для FAT12/FAT16 это количество секторов одной FAT. Для FAT32 это значение равно 0, а количество секторов одной


FAT содержится в BPB_FATSz32.

BPB_TotSec32

32 (#20)

4

Новое 32-битное поле: общее количество секторов на диске. Это количество включает в себя все четыре региона диска. Может быть 0, если 0 то BPB_TotSec16 должно быть не 0. Для FAT32 дисков значение всегда не 0. Для FAT12/FAT16 дисков поле содержит количество секторов, когда BPB_TotSec16 равно 0 (количество равно или больше 0x10000).

Начиная со смещения +36 могут находится один из двух описателей: для FAT12/16 или для FAT32 соответственно. Структура соответствующая FAT12/16 по этому смещению мной игнорируется, так как для работы с FAT12/16 достаточно предыдущих значений.

Структура FAT32:

Имя

Смещ ение

Раз мер

Описание

BPB_FATSz32

36 (#24)

4

Это поле есть только в FAT32 и отсутствует в FAT12/16. Это 32-битное поле FAT32 содержит количество секторов одной FAT. При этом BPB_FATSz16 должно быть 0.

BPB_RootClus

44 (#2C)

4

Это поле есть только в FAT32 и отсутствует в FAT12/16. Номер первого кластера корневой директории. Обычно 2, но может быть и другим.

BPB_FSInfo

48 (#30)

2

Это поле есть только в FAT32 и отсутствует в FAT12/16. Номер сектора со структурой FSINFO в зарезервированной части FAT32. Обычно 1.

FSInfo.

На разделе FAT32 таблица FAT может иметь значительный размер, в отличие от FAT16 ограниченного размером 128Кб и FAT12 ограниченного размером 6Кб. Поэтому "последнее известное" количество свободных кластеров хранится в специальном секторе, чтобы не вычислять его каждый раз когда

нужно узнать размер свободного места на диске. Смещение сектора FSInfo от начала раздела хранится в поле BPB_FSInfo. Структура сектора FSInfo:

Имя

Смеще ние

Раз мер

Описание

FSI_Free_Count

488 (#1E8)

4

Хранит "последнее известное" количество свободных кластеров диска. Если равно #FFFFFFFF, то количество неизвестно и должно быть вычислено. Может быть любое другое значение, при этом не обязательно корректное. Оно должно проверяться на выполнение условия <= количества кластеров на диске.

FSI_Nxt_Free

492 (#1EC)

4

Содержит номер кластера, начиная с которого надо искать свободный кластер. Поскольку FAT32 таблица FAT велика, могут происходить значительные затраты времени, когда в начале FAT много занятых кластеров, а драйвер ищет свободный, начиная с номера 2. Обычно здесь номер последнего выделенного кластера. Если здесь значение #FFFFFFFF, то нет вспомогательного значения и поиск должен производиться с номера 2. Любое другое значение может использоваться, но должно предварительно проверяться на условие <= количества кластеров на диске.

При совместном использовании носителя с FATом и на Спектруме и под Windows имеет место небольшая проблема. При записи под Windows старшие 16 бит значения FSI_Free_Count чаще всего обнуляются и содержимое FSI_Nxt_Free содержит неправильное значение. И поиск следующего свободного кластера на Спектруме может занимать много времени, тем большее чем больше размер носителя.


Файлы и директории.

Файл (англ. file — папка, скоросшиватель)

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

Директория FAT - ни что иное как "файл", состоящий из списка 32-байтных структур. Лишь одна специальная директория, которая всегда должна присутствовать это корневая директория. На дисках FAT12 и FAT16 корневая директория расположена в фиксированном месте - непосредственно после последней таблицы FAT и состоит из фиксированного количества секторов, вычисляемого из BPB_RootEntCnt. Чаще всего размер директории имеет размер, рассчитанный на 512 32-х байтных записей, а при использовании длинных имен это число еще меньше. Для дисков FAT12 и FAT16 номер первого сектора корневой директории зависит от номера первого сектора таблицы FAT:

FirstRootDirSecNum = BPB_ResvdSecCnt + (BPB_NumFATs * BPB_FATSz16)

Для FAT32 корневая директория может быть произвольного размера из

последовательности кластеров, так же как любая другая директория. Номер первого кластера корневой директории FAT32 хранится в BPB_RootClus. В отличие от других директорий корневая директория любой FAT не имеет штампа даты и времени, не имеет имени файла и не содержит "." и ".." в первых двух записях. Ещё один аспект

— только в корневой директории может содержаться файл у которого установлен единственный атрибут ATTR_VOLUME_ID

— фактическое имя раздела. Расположение корневой директории зависит

от разрядности FAT: для FAT12/16 под корневую директорию отведено несколько секторов между таблицей кластеров и началом области, где непосредственно находятся файлы и другие директории. На FAT32 корневая директория находится там же, где и остальные файлы/директории.

Все вновь создаваемые директории всегда начинаются с двух стандартных записей с именами «.» (точка) и «..» (две точки). У первой записи устанавливаются

DIR_F stClusLO и DIR_FstClusHI такие же, как у этой новой директории (номер кластера, который содержит эти записи точка и две точки), то есть указывает сама на себя. У второй записи DIR_FstClusLO и DIR_FstClusHI устанавливаются в номер первого кластера родительской директории или в 0, если она корневая, даже для FAT32.

Структура 32-х байтного описателя в директории: _ _

Имя

Смеще ние

Раз мер

Описание

DIR_Name

0

11

Короткое имя.

DIR_Attr

11

(#0B)

1

Атрибуты файла (по

битам):

7-всегда 0

6-всегда 0

5-ATTR ARCHIVE

4-ATTR DIRECTORY

3-ATTR VOLUME ID

2-ATTR SYSTEM

1-ATTR HIDDEN

0-ATTR_READ_ONLY

DIR_FstClusHI

20 (#14)

2

Старшее слово номера первого кластера (всегда 0 для FAT12/16).

DIR_FstClusLO

26 (#1A)

2

Младшее слово номера первого кластера.

DIR_FileSize

28 (#1C)

4

32-битный размер файла в байтах.

DIR_Name — состоит из двух частей, 8-символьная основная часть имени, и 3-символьное расширение (сокращенно называемое 8.3 или короткое имя). Свободные концы обеих частей заполнены байтами #20. Первый байт имени не может содержать байт #20 (пробел) и может содержать значение:

• #00 - первая свободная запись в директории, после этой записи ничего нет;

• #05 — настоящий байт имени равен #E5 - соответствует старшему байту японской кодировки KANJI;

• #E5 — запись в директории свободна, так как файл/директория были


удалены.

Следующие символы не разрешены в имени файла/директории: #22, #2A, #2B, #2C, #2E, #2F, #3A, #3B, #3C, #3D, #3E, #3F, #5B, #5C, #5D, #7C.

DIR_Attr — сочетание атрибутов ATTR_READ_ONLY, ATTR_HIDDEN,

ATTR_SYSTEM и ATTR_VOLUME_ID установленных в 1 указывает, что описатель файла принадлежит к части длинного имени.

DIR_FstClusHI и DIR_FstClusLO — номер кластера с которого начинается цепочка кластеров занятых файлом/директорией.

DIR_FileSize — собственно размер файла в байтах.

Длинные имена.

Файл/директория кроме короткого имени может иметь так называемое длинное имя. Длинное имя может иметь длину 255 символов. Каждый символ имени занимает 2 байта в кодировке Unicode. Для нас интересны только диапазон от #0020 до #007F содержащий ASCII символы и следующие последовательности #0401, #0410-#044F и #0451. Из этих кодов в драйвере соответственно получаются английские и русские имена, циферки и прочие печатные символы. Преобразование происходит в так называемую альтернативную кодировку.

Набор записей длинных имён всегда ассоциирован записи короткого имени, которому они предшествуют. Записи длинных имён не могут легально существовать сами по себе. Записи длинного имени всегда непосредственно предшествуют и физически прилегают к записи короткого имени.

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

Запись

Номер

N (последняя) запись длинного имени

LAST_LONG_ENTRY (0x40) | N

... дополнительные записи длинного имени

1 (первая) запись длинного имени

1

Запись короткого имени,

нет

которому предшествует

длинное имя

Структура длинного имени:

Поле

Смеще ние

Раз мер

Описание

LDIR_Ord

0

1

Порядковый номер этой записи в последовательности записей длинных имён, ассоциированных с записью короткого имени в конце списка. Если соответствует бит 6 включен, то запись является последней в списке записей длинных имён.

LDIR_Name1

1

10

Символы 1 -5 длинного имени в данном компоненте.

LDIR_Attr

11

1

Атрибуты - содержит ATTR_LONG_NAME

LDIR_Type

12

1

Если 0, то запись является компонентом длинного имени.

LDIR_Chksum

13

1

Контрольная сумма короткого имени (которое располагается в конце списка).

LDIR_Name2

14

12

Символы 6-11 длинного имени в данном компоненте.

LDIR_FstClusLO

26

2

Должно быть 0. Для длинного имени значение не используется.

LDIR_Name3

28

4

Символы 12-13 длинного имени в данном компоненте.

Являясь парой, запись короткого имени хранит многие важные поля: дата последнего обращения, время создания, дата создания, номер первого кластера, размер. В записи длинного имени содержится лишь длинное имя файла.

Таблица кластеров.

Все пространство FAT раздела разделено на кластера. Кластер — это непрерывное пространство состоящее, из одного или нескольких секторов. Количество секторов в кластере может быть от 1 (2Л0) до 128 (2Л7).

Каждый файл занимает один или несколько кластеров, занятые файлом кластера образуют цепочку. Цепочка кластеров необратима. Можно прочитать номер следующего кластера, но нет никакого способа узнать номер предыдущего кластера. Начало цепочки хранится в описателе файла и указывает на таблицу кластеров находящуюся на некотором расстоянии от начала раздела. На сколько секторов от начала раздела находится таблица кластеров зависит от разрядности FAT. Отсчет номеров кластеров начинается с номера 2. Кластера 0 и 1 зарезервированы. Кластер 0 содержит значение BPB_Media в младших 8 битах, а все остальные биты содержат 1. Данные файла ассоциируются с файлом следующим образом. В директории (32-х байтный описатель) содержится номер первого кластера, в котором располагаются данные файла. По номеру этого кластера вычисляется смещение в таблице кластеров из которого берется номер следующего кластера файла. Кластер, расположенный в FAT таблице может содержать значение EOC (End Of Clusterchain - конец цепочки кластеров) или номер следующего кластера файла. Значение EOC равно одному из следующих значений: #0FFF, #FFFF или #0FFFFFFF для FAT12, FAT16 или FAT32 соответственно и указывает на окончание цепочки кластеров. Все свободные кластеры имеют значение 0.


Сектор нахождения начала кластера вычисляется по нескольким формулам. Сначала вычисляется размер в секторах корневой директории:

RootDirSectors = ((BPB_RootEntCnt*32) + (BPB_BytsPerSec-1)) / BPB_BytsPerSec

Для FAT32 поле BPB_RootEntCnt всегда содержит 0, поэтому для FAT32 RootDirSectors всегда 0. Здесь число 32 это размер одного элемента директории FAT (в байтах). Далее вычисляется начало региона данных:

FirstDataSector = BPB_ResvdSecCnt + (BPB_NumFATs * FATSz) + RootDirSectors

FATSz - это значение взятое из BPB_FATSz16 (для FAT12/16) или BPB_FATSz32 (для FAT32). Этот первый сектор начала региона данных считается не от начала носителя, а от первого сектора

BPB. То есть сектор BPB равен 0, но BPB может находится и в нулевом секторе носителя и вначале раздела. Имея номер кластера N номер первого сектора этого кластера (от начала носителя) вычисляется так:

FirstSectorofCluster = ((N-2) * BPB_SecPerClus) + FirstDataSector

В драйвере первые две формулы рассчитываются на этапе инициализации переменных и при вычислении реального сектора начала кластера все сводится к последней формуле.

Проблемы определения разрядности FAT.

Перед определением какие разделы и сколько их находится на носителе, нужно определить присутствует ли на носителе MBR.

Как один из вариантов определения мной использован следующий метод: в каждой 16-ти байтовой записи проверяется -активность раздела. Возможные значения #00 или #80.

-тип раздела. Возможные значения: #01, #06, #0E, #0B, #0C - числа соответствующие одному из типов FAT. При других значениях тип раздела считается не поддерживаемым и пропускается. При неудаче делается попытка определить первый сектор как описатель раздела. Соответственно, проверяются несколько контрольных точек этого сектора, относящихся к BPB. Проверяются следующие значения (по смещению от начала сектора):

• +13 (байт) - число секторов в кластере. Являясь числом 2 в степени от 0 до 7, соответственно должен содержать только один установленный бит. Нестандартный размер кластера (произвольное число секторов в кластере) игнорируется.

• +14 (слово) - количество секторов в Reserved region (начинается с первого сектора диска). Должно быть больше 0. Для FAT12 и FAT16 дисков, это значение должно быть только 1. Для FAT32 дисков обычное значение 32.


• +19 (слово) и +32 (двойное слово) -общее количество секторов на разделе. Одно из этих значений должно быть равно ноль, в то же время другое значение не должно быть равно ноль.

• +21 (байт) - маркерный байт совпадающий с байтом, записанным в нулевом байте таблицы кластеров. Может принимать значения: #F0, #F8, #F9, #FA, #FB, #FC, #FD, #FE и #FF. Проверяется на равенство #F0, игнорируя младшие 4 бита.

Определение типа раздела и разрядности FAT делается легко и просто при наличии MBR. Сложность появляется, если на устройстве один раздел и отсутствует MBR, а в нулевом секторе устройства хранения находится непосредственно описатель раздела. Дело в том, что в описателе раздела FAT отсутствует конкретное указание разрядности FAT. Текстовая строка в нулевом секторе по смещению от начала сектора +54 (для FAT12 и FAT16) или +82 (для FAT32) ни на что не указывает и может отсутствовать или содержать что угодно. И определять по этой текстовой строке разрядность FAT не самое умное решение.

Поиски способа правильного определения ни к чему не привели. Способ, описанный в спецификации на FAT имеет недостатки и дает ложные срабатывания, которые приводят проблемам в работе драйвера. Способ заключается в проверке количества кластеров на разделе и принятии решения о разрядности: для FAT12 количество кластеров должно быть 4084 и менее, для FAT16 не менее 4085 и не более 65524, для FAT32 более 65525 кластеров. Проблема в том что в некоторых случаях носитель может быть отформатирован в FAT (под Windows), когда количество кластеров не соответствует этому правилу. Простой пример: SD карта объемом 512 мегабайт, отформатированная как FAT32, хотя по количеству кластеров это 100% должна быть FAT16.

Мной был «изобретен» способ правильного определения разрядности FAT при отсутствии MBR. Процедура инициализации

FAT драйвера фактически состоит из 3 этапов:

• на первом этапе определяется наличие MBR выше описанным способом;

• на втором этапе инициализируются переменные драйвера. На этом этапе разрядность FATа не важна, некоторые переменные переносятся из BPB, а некоторые вычисляются простой математикой;

• на последнем этапе для правильного определения используются переменные содержащие: количество кластеров на разделе (CLS_DSC) и размер FAT таблицы в секторах (SEC_FAT). Проверка производится по следующему алгоритму: это FAT16, если (SEC_FAT-((CLS_DSC*2)/512))<16 или это FAT32, если (SEC_FAT-((CLS_DSC*4)/512))<16 иначе это FAT12.

Число 2 (4) в формулах это соответственное число байт зависящее от разрядности FAT, то есть сколько байт занимает номер кластера. Проверка на число меньше 16 связано с тем, что таблица кластеров может занимать на несколько секторов больше реально необходимого количества.

Метод показал свою эффективность, ложных срабатываний не обнаружено.

Немного о грустном.

Что до сих пор не сделано: нет удаления (Delete), нет перемещения (Move), нет возможности переименовывать

файлы/директории с длинными именами (только чтение), не написаны утилитки по разметке (fdisk) и форматированию (format).

Пока не делалось никакой поддержки расширенных разделов и, соответственно, логических дисков, но это можно добавить и позже.




СОДЕРЖАНИЕ:


  Оставте Ваш отзыв:

  НИК/ИМЯ
  ПОЧТА (шифруется)
  КОД



Темы: Игры, Программное обеспечение, Пресса, Аппаратное обеспечение, Сеть, Демосцена, Люди, Программирование

Похожие статьи:
Pro-обзор - Nuotrauka GFX compo review: "наслушавшись мнений художников-техников, очевидно небезынтересно будет узнать мнение тех, кто видит работы под несколько другим углом зрения"
Дом 16а - продолжение рассказа.
Credits - авторы газеты.
Как это было в Ленинграде - 2011 год. Настоящий ZX Spectrum
анкета - Благодарим за заполнение анкеты. Просьба назвать этот файл своим ником и отослать нам.

В этот день...   20 апреля