PicoFat

picofat.tgz

PicoFat — миниатюрная библиотека работы с файловой системой FAT, предназначенная для работы в условиях очень малого ресурса памяти. Не требует даже 512-байтового буфера сектора, так как считывает сектора короткими фрагментами.

На данный момент сделано только чтение файлов, что для многих приложений (типа звонков со сменными мелодиями, информационных табло) вполне достаточно. Реализация записи — в процессе разработки.

Характеристики

Параметр Значение
Поддерживаемые файловые системы
— MBR да, только первый основной раздел
— FAT12 нет, инициализация работает, нет считывания
— FAT16 да
— FAT32 да
Максимальный объём носителя 4294967296 секторов
(2 Тибайт при размере сектора 512 байт)
Размеры сектора 512, 1024, 2048, 4096
Операции
— чтение да
— запись нет
— форматирование нет
— дефрагментирование нет
Требуемое ОЗУ
— на носитель 24 байт (может быть немного больше)
— на открытый файл 20 байт (может быть немного больше)
— локальные данные ~ 80 байт
Размер программного кода ~ 2,5 Кибайт

Состав

Библиотека состоит из двух файлов:

  1. picofat.c — компилируемый файл в на языке си, «внутренности» библиотеки.
  2. picofat.h — заголовочный файл для программ на си и си-плюс-плюс, включающий объявления функций, типво данных, констант.

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

Работа с библиотекой

Общая организация

Всё, касающееся работы с FAT можно условно поделить на три уровня (от верхнего к нижнему):

  1. приложение пользователя,
  2. библиотека работы с FAT,
  3. драйвер накопителя.

Таким образом библиотеке необходимо два программных интерфейса:

  1. интерфейс приложения пользователя или фроненд (англ. frontend — передний край);
  2. интерфейс драйвера накопителя или бэкенд (англ. backend — задний край).

Библиотека, таким образом, управляемая через фронтенд приложением, через бэкенд работает с драйвером устройства.

Необходимое окружение для работы библиотеки

В первую очередь для работы библиотеки необходимо обеспечить бэкенд для работы с физическим носителем в лице драйвера. В данном случае та часть, которая будет взаимодействовать с библиотекой, состоит из всего лишь одной функции: pfat_rawread. Это, конечно, не исключает необходимости правильной инициализации устройства, и обеспечения прочих сервисных функций, но это всё уже никак напрямую с библиотекой PicoFAT не связано, и каким образом это будет сделано, не имеет никакого значения.

Единственная функция бэкенда будет выглядеть примерно таким образом:

int pfat_rawread(pfat_device dev, void *buffer, unsigned long sec, unsigned int offset, unsigned int length) {
    ... // читаем данные в буфер
    if(success) return 0;
    else return -1;
}

Более подробно — см. описание функции pfat_rawread.

Сценарий работы с библиотекой

Примерный сценарий работы с библиотекой имеет следующий вид:

  1. инициализация драйвера накопителя;
  2. инициализация библиотеки FAT;
  3. открытие файлового потока;
  4. чтение из файла;
  5. закрытие файлового потока (в данной версии не требуется никаких действий);
  6. завершение работы с библиотекой FAT (в данной версии не требуется никаких действий);
  7. завершение работы драйвера;

Причём пункты 3—6 могут выполнять многократно и даже параллельно. Инициализация и завершение работы драйвера никак не связанно с библиотекой, тем не менее устройство должно быть инициализировано перед началом работы с FAT и отключено только после окончания работы.

Инициализация

Инициализация библиотеки FAT производится вызовом функции pfat_init, которой передаётся указатель на уже созданную структуру pfat_volume. При этом в структуре должен быть уже прописан элемент dev, если это требуется.

    init_block_device(my_device);  // любая функция инициализации физического устройства
    my_volume->dev = my_device;    // сохраняем дескриптор физического устройства;
    status = pfat_init(my_volume); // инициализируем библиотеку;

Программный интерфейс для работы с носителем (backend)

Работа с носителем информации из библиотеки обеспечивается посредством вызовов импортируемой функции драйвера.

Импортируемые функции

В данной версии требуется только функция чтения с носителя, pfat_rawread.

pfat_rawread

int pfat_rawread(pfat_device dev, void *buffer, unsigned long sec, unsigned int offset, unsigned int length);

Параметры:

dev
Специальная переменная — дескриптор устройства, её содержимое может определяться драйвером носителя. Нужна в случае, если в системе присутствует несколько блочных устройств. По умолчанию её тип (pfat_device) определён как void *, однако его можно переопределить как любой другой (кроме массива), библиотека не производит над ним никаких операций.
buffer
Адрес буфера, в который сохраняются считанные с носителя. Буфер является массивом типа char, каждый элемент которого по возврату из функции должен содержать по 1 байту данных с носителя.
sec
Номер сектора, подлежащего считыванию. Самый младший сектор в устройстве должен иметь номер 0. Библиотека может работать только в режиме LBA, поэтому требуется, чтобы сектора нумеровались по порядку, без разрывов.
offset
Смещение в байтах относительно начала сектора, с которого следует начинать класть в буфер, то есть элементу буфера со смещением 0 должен соответствовать байт сектора со смещением offset, элементу 1 — байт offset+1 и т. д.
length
Длина куска считываемых данных в байтах и, соответственно, размер буфера.

Результат:

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

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

Несмотря на то, что теоретически значение параметров offset, length или их суммы, могут быть за пределами длины сектора, библиотека, если загрузочные сектора инициализированы правильно, никогда не использует такие значения, а значит такая ситуация не требует особой обработки драйвером, однако в диагностических целях возможно возвращать ошибку.

Библиотека не тестировалась, но должна правильно работать с секторами длиной не только 512 байтов, но и любыми другими разрешёнными файловой системой FAT: 1024, 2048 или 4096 байтов. И если такие носители возможны, работа с ними организована описанным образом. Смысл номера сектора в этом случае не меняется: каждый номер должен соответствовать отдельному сектору диска соответствующей длины (а не 512-байтному).

В качестве отступления хочу отметить, что нельзя прямо, ни простой переупаковкой секторов, ни сектор в сектор, скопировать образ диска с одним размером секторов, на диск с другим размером. Именно поэтому правильная работа с номерами секторов необходима для работы с диском, и именно поэтому я не заменил отдельные параметры sec и offset одним адресом относительно начала — процедура предварительного выяснения размера сектора у драйвера и пересчёта этих самых смещений (особенно если учесть возникающую необходмость в 64-битной арифметике) только бессмысленно усложнит процедуры.

Программный интерфейс для пользовательских приложений (frontend)

Типы данных

Для для работы библиотекой используются две структуры данных. Первая, pfat_volume, содержит необходимую информацию о накопителе целиком, и нужна в единственном экземпляре. Другая, pfat_file — используется для доступа к отдельным файлам, и создаётся отдельно для каждого открытого файла.

Библиотека не использует динамической памяти, поэтому место под эти структуры должно предоставлять приложение. Они могут быть как статически скомпилированы, так создаваться в стеке или динамически выделяться.

Константы и макросы

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

Функциональная группа Макрос Значение Описание
Работа с кодами ошибок pfat_is_error(x) ((x)<0) Макрос проверки на ошибку
pfaterr_format (-2) Ошибка формата данных
pfaterr_read (-3) Ошибка считывания
Работа с директориями FATDIR_SIZE 0x20 Размер директории
ld_FATDIR_SIZE 5 log2 размера
Смещения элементов файловых записей FATDIR_Name 0x00 Имя файла до точки
FATDIR_Ext 0x08 Расширение (после точки)
FATDIR_Attr 0x0B Атрибуты
FATDIR_NTRes 0x0C Резерв
FATDIR_CrtTimeTenth 0x0D Сотые секунд времени создания
FATDIR_CrtTime 0x0E Время создания
FATDIR_CrtDate 0x10 Дата создания
FATDIR_LstAccDate 0x12 Дата последнего доступа
FATDIR_FstClusHi 0x14 Начальный кластер (старшая часть)
FATDIR_WrtTime 0x16 Время записи
FATDIR_WrtDate 0x18 Дата записи
FATDIR_FstClusLo 0x1A Начальный кластер (младшая часть)
FATDIR_FileSize 0x1C Размер файла
Атрибуты файловых записей FATATTR_READ_ONLY 0x01 Только для чтения
FATATTR_HIDDEN 0x02 Скрытый
FATATTR_SYSTEM 0x04 Системный
FATATTR_VOLUME_ID 0x08 Метка носителя
FATATTR_DIRECTORY 0x10 Директория
FATATTR_ARCHIVE 0x20 Изменён с момента архивации
FATATTR_LONG_FILE_NAME 0x0F Маркер длинного имени (LFN)
Маркеры особых файловых записей FATNAME_FREE 0xE5 Удалённый файл
FATNAME_END 0x00 Конец директории

Функции

Для работы с FAT используется всего несколько функций:

pfat_init
Инициализация записи насителя
pfat_reopen
Открытие файла (или директории)
pfat_read
Чтение из файла (или директории)

pfat_init

int pfat_init(struct pfat_volume *vol);

Аргументы:

vol
Указатель дескриптора логического устройства. Должен указывать на действительную структуру. Перед вызовом следует установить элемент pfat_device, который будет использоваться для доступа к носителю.

Результат:

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

Функция производит инициализацию структуры vol посредство чтения системных областей диска. В случае, если структура этих областей разрушена, может возвратить ошибку. Впрочем, проверка валидности нестрогая, поэтому возможна неправильная работа в этом случае, хотя тяжёлых последствий (зависания, перезагрузки, повреждения данных) это вызвать не должно.

На данный момент реализована только инициализация первого основного раздела на носителях с таблицей разделов MBR. Работа без MBR, как и работа с другими разделами не предусмотрена, однако может быть сделана. Однако по моему мнению на текущий в этом нет необходимости.

pfat_reopen

int pfat_reopen(struct pfat_file *f, char *name, struct pfat_volume *vol);

Аргументы:

f
Указатель на файловый дескриптор. Должен быть действительным: текущее содержимое не имеет значения.
name
Путь к файлу. Обычная текстовая строка в формате, используемом unix. Регистрозависим.
vol
Дескриптор логического устройства. Должен быть проинициализирован через pfat_init.

Результат:

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

Так как система не использует динамического выделения памяти, место под файловый дескриптор должно быть выделено заранее любым способом, и библиотекой предоставляется функция именно в таком варианте, функционально подобном стандартному freopen. Текущее содержимого дескриптора теряется, однако нет ничего страшного при повторном его использовании — дескриптор не требует специальной процедуры закрытия (и поэтому отсутствует соответствующая функция).

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

Функция позволяет открывать и считывать директории точно таким же образом, как и файлы, достаточно указать в качестве пути имя директории. При этом директория считывается как массив записей по 32 байта в полном соответствии со спецификацией FAT. Для работы с директориями в заголовочнов файле определена серия констант FATDIR_*, FATATTR_*, FATNAME_*.

При инициализации текущая позиция в файле устанавливается на его начало, после чего он может быть считан функцией pfat_read.

pfat_read

int pfat_read(struct pfat_file *f, void *buffer, int bytes);

Аргументы:

f
Файловый дескриптор. Должен быть инициализирован посредством pfat_reopen.
buffer
Буффер, куда будут считываться данные. Должен быть действительным и размером не меньше указанного в bytes.
bytes
Размер данных в байтах, которое необходимо считать. Должен быть больше нуля.

Результат:

Возвращает количество считанных данных в байтах или код ошибки (меньший нуля).

Последовательно считывает данные из файла в буфер. При этом перемещает текущую позицию на следующие по порядку данные. Если при считывании упирается в конец файла, считывает остатки, после чего чтение ничего не выдаёт — возвращается 0. Директории считываются точно таким же образом, как файлы. Приложению предстаёт голая структура директории FAT, которая, тем не менее достаточно проста в плане разбора. Именно поэтому библиотека не даёт отдельных функций для работы с директориями.

cifra/picofat.txt · Последние изменения: 2009/07/07 17:22 — vovanium
За исключением случаев, когда указано иное, содержимое этой вики предоставляется на условиях следующей лицензии: CC Attribution 3.0 Unported