Блокнот: размещение файлов в памяти.

Если проект выдаёт что-либо наружу сложнее нескольких светодиодов, то надо это как-то хранить. И для этого придумали понятие файл: это именованная область данных на носителе информации. Самый простой способ — разместить в памяти. Но даже тут возможны варианты. Оставим за кадром файловые системы вроде FatFs, SPIFF, UBIFS, JFFS и прочих, ограничившись внутренней памятью устройства. Благо, контроллеры в отношении её со временем становятся всё жирнее. Самый простой способ — запихать всё в массив или связанный список. Можно догадаться, что кто-то уже наверняка делал подобное, и если поискать, то можно найти несколько способов. Из простых сравню romfs, cpio-архив, cramfs и обычный массив (да, он с определённым допущением тоже является «именованной областью данных».
Какие тонкости и отличия я накопал?

  • простота:
    1. массив — самое простое, что можно придумать. Требуется только bin2c от SEGGER или *nix-утилита xxd. Длина задаётся константой.
    2. romfs — напоминает связанный список; есть имя, длина, CRC контрольная сумма.
    3. cpio — последовательно размещённые файлы с именами, правами доступа и другой информацией.
    4. cramfs — почти файловая система. Полноценный архиватор же.
  • потери:
    1. массив — нет ни дополнительного расхода памяти как ROM так и RAM, ни обработок.
    2. romfs — 16 байт на заголовок файловой системы + 16 байт на файл, выравнивание на 16-битную границу размера и имени файла.
    3. cpio — по умолчанию 26 байт на заголовок каждого файла, выравнивание имени файла и длинны файла по границе слова; в конце специальный файл (36 байт)
    4. cramfs — блоки по 4096 байт. Мда...
  • ограничения размера:
    1. масив — нет как таковых; всё зависит от компилятора.
    2. romfs — весь образ 32 бита = 4 GiB, размер файла 24 бита = 16 MiB 4 GiB — минус длинна общего заголовка и минус длина заголовка файла.
    3. cpio — непонятно с длиной архива (зависит от системы и компилятора?), размер файла 32 бита = 4 GiB
    4. cramfs — размер образа 272 MiB, длина файла 16 MiB
  • надёжность:
    1. масив — без проверок, можно дополнить CRC.
    2. romfs — CRC контрольная сумма на заголовок первые 512 байт; CRC контрольная сумма для каждого файла.
    3. cpio — без проверок кроме корректного заголовка по 'magic number'; есть опция CRC контрольной суммы, но используется только при хранении заголовка в символьном виде, что увеличивает его длину до ~110 байт.
    4. cramfs — забил из-за уже имеющихся недостатков.
  • основная особенность:
    1. масив — нужен только компилятор и утилита; при отсутствии последней пишется на любом языке.
    2. romfs — наличие CRC проверки целостности 'искаропки'; при наличии зарезервированной области можно дописать файл в конец(при использовании небольшого трюка). Применяется в прошивках роутеров, есть инструментарий под *nix.
    3. cpio — хранение прав доступа, времени создания, владельца и т.п. Применяется при загрузке Linux-ядра, есть инструментарий (даже устанавливать не пришлось).
  • функции доступа:
    1. масив — встроено в компилятор
    2. romfs — автор уверяет что всё поместится в 4 кбайта. Можно очень сильно уменьшить
    3. cpio — почти то же самое, что и для romfs.
  • +1
  • 18 августа 2016, 13:46
  • Hoksmur

Комментарии (16)

RSS свернуть / развернуть
неплохая шпаргалочка получилась (;
0
Ага, так и задумывалось. Самому чтобы не забыть, ну и другим вдруг полезно будет.
0
romfs — весь образ 32 бита = 4 GiB, размер файла 24 бита = 16 MiB
Где это? По линнку указано 32 бита на размер файла.
romfs — наличие CRC 'искаропки'
Контрольной суммы. CRC — это вполне конкретный алгоритм, и в ROMFS используется не он.

Есть еще вариант «сделать свою FS», реализовав только то, что нужно.
+1
  • avatar
  • Vga
  • 18 августа 2016, 15:00
Где это? По линнку указано 32 бита на размер файла.
Since the file headers begin always at a 16 byte boundary, the lowest
4 bits would be always zero in the next filehdr pointer. These four
bits are used for the mode information.
Контрольной суммы. CRC — это вполне конкретный алгоритм, и в ROMFS используется не он.
Согласен, что тут присутствует неоднозначность с термином. Но согласно текущей wiki CRC это
Циклический избыточный код (англ. Cyclic redundancy check, CRC[1]) — алгоритм нахождения контрольной суммы, предназначенный для проверки целостности данных[2].
Если бы подразумевался конкретный алгоритм, то было бы что-то вроде CRC+циферка. У автора так реализовано:
int romfs_checksum(void *data, int size)
{
        int32_t sum, word, *ptr;

        sum = 0; ptr = data;
        size>>=2;
        while (size>0) {
                word = *ptr++;
                sum += ntohl(word);
                size--;
        }
        return sum;
}

Есть еще вариант «сделать свою FS», реализовав только то, что нужно.
Самый разумный, в общем-то. Но есть такой момент: по функционалу очень быстро можно придти к romfs, а получить ещё один стандарт. Как на картинке.
0
Since the file headers begin always at a 16 byte boundary, the lowest
4 bits would be always zero in the next filehdr pointer. These four
bits are used for the mode information.
Это даже не про размер написано. Перечитай еще раз, но внимательнее.
Если бы подразумевался конкретный алгоритм, то было бы что-то вроде CRC+циферка. У автора так реализовано:
CRC — семейство алгоритмов, различающихся полиномом. У автора же обычная проверочная сумма, AFAIK к CRC отношения не имеющая. Обрати внимание, он и сам называет ее checksum, а не CRC.
Но есть такой момент: по функционалу очень быстро можно придти к romfs, а получить ещё один стандарт.
Врядли тебе понадобятся linux-specific возможности, заложенные в FS. Зато вполне вероятно потребуется что-то другое. Если не стоит задача взаимодействия с чем-то другим, либо задействования готовых инструментов, нужды использовать стандартное решение нет.
+2
Это даже не про размер написано. Перечитай еще раз, но внимательнее.
Не горячитесь. Формально вы правы, а по факту — размер файла не может быть больше, чем смещение до следующего заголовка, то есть приходим к тем же 24 битам.

Врядли тебе понадобятся linux-specific возможности, заложенные в FS.
Если мы говорим о romfs — то их там нет. Имя и размер. Всё. В cpio — да, есть.

Зато вполне вероятно потребуется что-то другое. Если не стоит задача взаимодействия с чем-то другим, либо задействования готовых инструментов, нужды использовать стандартное решение нет.
Всё верно. Вам "Блокнот:" в заголовке и публикация в личном разделе ни о чём не говорит?
0
Формально вы правы, а по факту — размер файла не может быть больше, чем смещение до следующего заголовка, то есть приходим к тем же 24 битам.
Срезаются 4 младших бита. Диапазон адресации при этом не меняется, меняется гранулярность адресации.
Ну и эта… 32 — 4 — несколько больше, чем 24. Хотя в данном случае это несущественно.
Если мы говорим о romfs — то их там нет. Имя и размер.
Есть, внимательнее почитай, что именно кодируется в 4 младших битах смещения следующего чанка и spec.info. Заголовок раздела, кстати, тоже в эмбед-применениях не нужен.
Да и вообще там довольно много избыточных данных. Самый простой из моих форматов имеет 5+namelen байт заголовка на файл и не использует заголовок архива вообще.
Всё верно. Вам «Блокнот:» в заголовке и публикация в личном разделе ни о чём не говорит?
И что? Это не повод не излагать свои мысли по вопросу.
0
Про 24 бита вы правы, там шаг 16 байт. Но не думаю, что это актуально. В конце концов, никто не мешает ни мне, ни вам создать образ и поковыряться в нём шестнадцатиричным редактором.
0
придумали понятие файл: это именованная область данных
другие подумали и придумали понятие «Блок данных»
Блоки данных бывают сумбурными или логичными :)
не/типизированные не/структурированные не/экземплярные… это всё разнооборазие давно применяется в промышленных контроллерах…
главное — чтобы места в памяти под них было достаточно… а общая память программ/данных в ПЛК от 16 килобайт…
0
Не очень понял, что имеет автор под словом массив? Маппинг файлов на пямять — Your text to link...?
0
Просто uint8_t myfile[] = {0x4d, 0x5a, 0x90, 0x00, ...}.
0
Vga , вы верно ответили. А как делали у себя? размер+имя(строка со счётчиком?)+тело? Или как? Я про это:
Самый простой из моих форматов имеет 5+namelen байт заголовка на файл и не использует заголовок архива вообще.
0
[File1][File2]..[FileN]
File:
[FileNameSize:uint8][FileSize:uint32][FileName:FileNameSize][FileData:FileSize]
0
Код: раз, два, три.
0
Хорошо, спасибо. К.м.к., лучше поменять на
[FileSize:uint32][FileNameSize:uint8][FileName:FileNameSize][FileData:FileSize]
или же
[FileNameSize:uint8][FileName:FileNameSize][FileSize:uint32][FileData:FileSize]
и выровнять на границу long-а. Тогда доступ на 32-х разрядной платформе будет проще. А 8-мибитникам без разницы. Согласны с аргументами?
0
Я оптимизировал по размеру, поэтому выравнивания файлов нет, а без него нет смысла и структуру выравнивать. Да и производительность доступа к файлам в этом проекте роли не играет.
Но если играет — то можно и оптимизировать, конечно.
0
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.