3OS

Cвод документации по 3OS-FS

(c) 3OS-FS Team Версия от 24.12.2002

Концепция файловой системы

Любую файловую систему, в принципе, можно представить в виде некоторой базы данных, в которой каждая запись является элементарной (т.е. неделимой на данном уровне вложений) ячейкой, служащей для хранения определенного типа информации об определенного типа объекте. При этом любая из ячеек может быть связана с любыми другими ячейками различного рода связями. В свою очередь, каждую такую ячейку можно представить в виде другой базы данных с несколько другого рода связями, существующими между ячейками, и так далее. Условно эти связи можно разделить на внутренние и внешние связи, и которые могут являться линейными, иерархическими, распределенными и др.
Обычно, на данном конкретном уровне вложений, можно лишь наблюдать внешние связи ячейки (объекта). Внутренние же ее связи, которые зависят от схемы представления (кодирования) информации, т.е. формата объекта, остаются скрытыми. Для того, чтобы вскрыть эти связи, нужно спуститься на низлежащий уровень.
С этой точки зрения, любой файл можно представить в виде некоторой базы данных с линейного типа связями внутри нее. Элементарной ячейкой в этом случае будет служить 'токен', то есть 'символ'. Поскольку в файлах используется последовательный принцип записи информации, то каждый из 'токенов' в этом случае оказывается связанным только с предыдущим и последующим 'токенами', то есть - линейно. Необходимо отметить, что в качестве 'токена' может рассматриваться любой объект на определенном уровне вложенности. Т.е. такие объекты как страница, абзац, строка также являются 'токенами', но каждый для вышестоящего уровня вложенности.
В то же время, любой файл можно представить и в виде некоторой элементарной ячейки со своими (присущими только этой ячейке и скрытыми до поры) внутренними связями. Перейдя на низлежащий уровень (т.е. вскрыв эти связи), мы обнаружим, что и здесь, в принципе, информацию можно представить в виде системы "элементарных" ячеек со своими связями линейного (текстовый файл), иерархического (табличный файл, база данных) или распределенного (исполняемый файл) типов, и различного рода их комбинаций, и т.д. При этом информация о типе и параметрах внутренних (по отношению к файлу) связей хранится в самих ячейках внутри файла.
Аналогично, перейдя на вышележащий уровень, мы скроем его внутренние связи (т.е. информацию о порядке расположения 'токенов' в файле), которые до этого были открытыми. При этом его внешние связи (другого - иерархического или распределенного типа) откроются, связав воедино различные файлы между собой (группа файлов, дерево каталогов и т.д.).
Довольно часто требуется знать какого типа информация содержится в той или иной конкретной ячейке. Однако узнать схему внутренних и внешних связей объекта (при традиционном подходе к построению файловой системы) можно лишь перейдя на соответствующий уровень системы, т.е принудительно вскрыв недоступные до того связи. Этого можно было бы избежать, если бы информация об этих связях хранилась в местах хранения самих ячеек. Т.е., точно так же, как информация о внутренних (по отношению к файлу) связях хранится в элементарных ячейках файла, так и информацию о типе и параметрах внутренних (по отношению к дереву каталогов, но внешних - по отношению к файлу) связей следует хранить в его "элементарных" ячейках, т.е. вместе с самими файлами, группами файлов и т.д. При этом количество вложенных друг в друга уровней может быть неограниченным.
Применительно к файловой системе 3OS данный подход можно реализовать следующим образом:
Базовой "элементарной" ячейкой для наивысшего уровня вложенности будет являться файл (см. рисунок), который будет состоять из трех секций: данных файла, описателя контента (содержимого) файла и реестра файла. Эти секции предполагается хранить в одном месте в виде "параллельных" цепочек данных. Причем в двух последних будет содержаться вся необходимая информация о параметрах и типе внутренних и внешних связей файла.
Данные файла, в зависимости от их содержания, могут быть представлены несколькими уровнями вложенности. Так, например, текстовый файл может состоять из страниц, абзацев, строк и символов ('токенов'). Графический - из заголовка, потока данных, 'токенов', и т.д. Причем, для текстового файла в этом случае 'токеном' будут служить 2 байта Unicode, а для графического файла BMP - 3 байта RGB.
Все типы данных и внутренние связи будут содержаться в описателе контента файла. Если для файла нет описателя контента (внутренняя структура файла примитивна), то считается что файл - поток однобайтовых 'токенов' (RAW-файл). Вся информация о внешних параметрах и часть информации о внешних связях объекта будет сосредоточена в реестре файла, который, в принципе, может и отсутствовать. Предполагается описатель контента и реестр файла хранить в виде строки данных, состоящей из последовательно записанных 'токенов'. Доступ к любым объектам информации, находящимся на различных уровнях вложенности (будь то иллюстрация в файле, абзац текста, или же звуковое сопровождение), предполагается осуществлять с помощью языка высокоуровневых запросов к файловой системе DML (Data Management Language).
Спецификации в настоящий момент разрабатываются.

Устройство файла. Файл - контейнер данных

Файл в концепции 3OS является неким контейнером информации, описанной в виде классов данных. Кроме стандартных полей атрибутов файла, присущих любой файловой системе, в 3OS файл имеет еще 2 уникальных поля - описатель контента и реестр, размер которых может достигать до 4 Gb. Что же это такое?
Описатель контента - область, в которой информация о содержимом файла хранится в виде ссылок на классы данных, а также в виде индивидуального дерева классов, по которому интерпретируется содержимое файла.
Реестр файла - содержит информацию, регистрирующую файл (программу) в системе 3OS. Также, реестр файла хранит информацию о параметрах файла, которые не смогли уместиться в таблице файлов (например, в случае, когда файл имеет слишком длинное имя, оно повторяется в начале реестра).
В концепции 3OS каждая программа (файл) может иметь собственный реестр, который она регистрирует в общем (системном) реестре. Это сделано для того, что бы избежать "мусорной свалки" в главном реестре системы, что снижает ее (системы) производительность.

Описатель контента. Уникальное дерево классов файла

На основе данных взятых из описателя контента система формирует представление о содержимом файла. Описатель контента имеет вполне конкретный формат и состоит из двух секций: первая - список классов используемых при обработке файла; вторая - индивидуальное дерево классов файла. Чтобы понять, как же система работает с содержимым файла, рассмотрим пример описателя контента текстового файла, состоящего из 3-х страниц текста с иллюстрацией ко второму абзацу второй страницы:
В первой секции хранятся ссылки на классы, которые используются при интерпретации файла. Если в секции есть хотя бы одна ссылка на класс, который незарегистрирован в системе, то весь файл интерпретируется, как обычный RAW-файл (поток байт). Это связано с тем, что при отсутствии хотя бы одного класса в системе мы не сможем правильно интерпретировать содержимое файла.
Формат секции дерева классов (строения файла) полностью исключает избыточность информации, поэтому, например, мы не раскрываем содержимого первой и второй страницы, так как ясно, что они являются стандартными страницами текста. А вот во второй странице у нас есть иллюстрация. Что интересно, при разном способе записи мы получим совершенно разные результаты:

Classes.PictureClasses.BMPClass & Classes.TextClasses.Paragraph - здесь абзац текста является комментарием к рисунку и, в конечном виде, это будет выглядеть так:


Classes.TextClasses.Paragraph & Classes.PictureClasses.BMPClass - рисунок является иллюстрацией к абзацу:


А при следующем написании страница будет выглядеть так:

Правила написания дерева классов файла еще не определены, как и не ясно - как же хранить файлы (например, Word'97), ведь с описателем контента мы получаем совершенно другой формат файла. Все это нуждается в дальнейшей проработке.

Принцип общения приложения с файловой системой.
Устройство драйвера FS

Рассмотрим, каким образом приложение общается с файловой системой? Для общения с приложением предусмотрено наличие 2-х интерфейсов для работы с файлами: "стандартный" - уже привычный интерфейс, который работает с приложением посредством функций драйвера (открыть файл, прочитать блок из файла, и т.д., в общем, все как в остальных ОС), и интерфейс языка запросов DML (Data Management Language), который реализует возможность работы с данными на уровне понятий объектов информации. Для начала, давайте сначала разберем структуру драйвера файловой системы для 3OSFS (для других FS, структура практически не изменится), а потом уже разберем способы работы с информацией.
Драйвер FS описан специальным классом Driver.FS.3OSFS (здесь и далее наименования классов и методов условны, т.к. еще не выработан принцип именования классов в 3OS), в котором имеются все необходимые средства для работы с разделом 3OSFS. Следует отметить, что такие операции как дефрагментация, проверка и форматирование раздела файловой системы, проводятся самим драйвером и недоступны для пользовательских приложений. Самыми низкоуровневыми операциями, к которым у приложения может иметься доступ, являются операции непосредственной работы с файлами (открытие, закрытие, чтение, запись, установка атрибутов и др.). Посредством этого достигается безопасность хранения данных на диске: пользователь может работать только с файлами, и только с теми из них, доступ к которым ему разрешен. Доступ к секторам диска может получить только ядро системы, или другой драйвер.
Помимо методов класса драйвера, существуют еще классы-плагины, реализующие дополнительные сервисы файловой системы. Перечислим основные из них: OptimizationClass - класс, в котором собраны методы, ускоряющие работу драйвера; CryptClass - класс шифрования данных на диске; FastCompressClass - класс динамического сжатия данных на диске; MirrorClass - класс зеркалирования раздела 3OSFS. Язык DML для драйвера также является классом-плагином.
Давайте проследим порядок обращения приложения к файловой системе с помощью приведенной ниже иллюстрации:


Метод InGate сортирует сообщения поступившие драйверу FS. В случае, если это одно из системных сообщений (например "shutdown", "stop" и т.д.), то оно исполняется самим методом InGate. Если же это обращение приложения к файловой системе, то оно помещается в стек входящих сообщений (InStack).
Далее, поступившее в InStack сообщение обрабатывается методом SecureGate, который производит его проверку на допустимость исполнения. В случае некорректного обращения сообщение уничтожается, а для пославшего его приложения в OutStack помещается специальное сообщение, которое затем метод OutGate отправит по назначению. Если же обращение (запрос) удовлетворяет требованиям безопасности, оно помещается в стек WorkStack.
Метод Work (точнее это несколько методов объединенных в одну группу, однако их можно представить в виде 1-го метода), обнаруживает поступившее в WorkStack сообщение и анализирует его. Если это сигнал о проведении сервисной операции (дефрагментация, форматирование и т.д.) от ядра или консоли администратора (от остальных приложений такой сигнал отсеется методом SecureGate), он обрабатывается группой методов, которые обозначены на иллюстрации как Services. В случае же обычной операции (открытия файла, чтения/записи в файл и т.д.), ее исполнение происходит методом Work посредством обращения к классам PartitionClass (операции с заголовком раздела и отдельными кластерами), FileTableClass (операции с таблицей файлов), FileClass (операции с файлами). Результат обработки сообщения метод Work поместит в OutStack для его дальнейшей отправки приложению.
А каков порядок исполнения DML-запроса? DML через классы FileClass, FileTableClass, и др. получит доступ к затребованному объекту (фрагменту файла), обработает его с помощью классов-данных, указанных в описателе контента файла, и отправит назад либо полученную информацию, либо подтверждение о выполнении операции.

Работа классов-плагинов на примере OptimizationClass

Почему операции ускоряющие работу драйвера были выделены в отдельный класс и, более того, используются как плагин? Это было сделано потому, что методы оптимизации работы с файловой системой достаточно ресурсоемки. Если 3OS планируеся запускать на машинах с 32 Mb RAM, то оптимальнее будет снизить скорость дисковых операций, при этом увеличив область памяти, доступной для программ. Напротив, для компьютера с 128 мегабайтами RAM, потеря 1 Mb (на самом деле меньше, и зависит от конфигурации машины) на оптимизацию не так критична.
Класс оптимизации, в основном, манипулирует с таблицами и стеками, размер которых определяется в настраиваемых переменных плагина. Соответственно, чем больше размер стеков и таблиц, тем быстрее выполняются запросы приложений. Методы класса можно разделить на две категории: 1) методы операций чтения с диска; 2) Методы операций записи на диск.

Методы операций чтения:
Методы операций записи:
Для реализации кэша записей файлов (файловой таблицы) выработан свой собственный формат записей файлов. Т.е. прокэшированные записи храняться совершенно в другом виде, чем на диске. С чем это связано? На диске в записи хранятся только имена файлов < 32 символов, все остальные имена хранятся в реестре файла. Т.е. длинну полной информации о файле мы предсказать не можем, т.к. не знаем четкой длинны имени файла. Поэтому был выработан свой язык управляющих символов для форматирования полей прокэшированных записей в памяти. Т.е. необходимо понимать, что в кэше записи не имеют четкой длинны и проиндексированны в индексной таблице кэша.
Кроме того, что кэшируется запись файла + полное имя файла, запись в кэше может содержать еще и реестр и описатель контента, если они имеют достаточно маленькитй размер (порядка 200байт). Все это учитывается в динамической разметке полей записи с помощью управляющих символов.

Новый язык DML (Data Managment Language)

DML - новый язык для работы с объектами данных, интегрированный в драйвер файловой системы. В принципе, язык запросов можно реализовать и вне драйвера FS, тогда нам будет без разницы на какой FS у нас хранится информация, в этом случае придется реализоввывать DML-как отдельный драйвер. Язык DML будет использоваться не только в обращениях приложений к драйверу FS, но и в других областях, например команды DML можно будет исполнять прямо из командной строки. Опираясь на иллюстрацию приведенную в концепции файловой системы, приведем простой пример исполняемого файла, написанного в шелкодах (пример условен):
Такой подход приятен тем, что теперь программисту, например для добавления иллюстрации к абзацу текста, вообще не нужно работать непостредственно с файлом, он посылает драйверу последовательность высокоуровневых DML-команд.
Язык DML сможет оперировать со всеми классами данных зареистрированных в системе. Оцените ситуацию, когда для выбора кадра из фильма, мы просто делаем выборку DivX-файлов, находим нужный из них (по имени), и даем команду сохранить кадр в отдельный файл в любом графическом формате (класс которого так же зарегистророван в системе). Вместо написания длинной программы и предварительного изучения формата DivX, мы все делаем за три команды, которые можно ввести прямо с консоли!
А как вам идея файлового менеджера, который умеет оперировать не только файлами, но и их содержимом? Который раскрывает связи данных файла, встает например на лист (или кусок звукового потока, например :-) и копирует его в нужное место другого файла по клавише F5!
По своей сути язык DML - это огромный шаг вперед в обработке информации. В дальнейшем развитии операционных систем с использованием DML сотрется понятье файла - остануться лишь абстрактные контейнеры данных в виде таблиц СУБД. Это дело далекого будущего, а пока нам предстоит лишь сделать первый шаг, который сделает 3OS исключительно легкой системой для оперирования объектами.

А почему так? Обоснование формата раздела 3OSFS.
Маленький FAQ по возможным вопросам

Прежде чем начать чтение описания формата раздела 3OSFS, не поленитесь прочитать эту часть документации. Я уверен что большинство вопросов, которые возникнут у вас по формату раздела уже описаны в этой части документа.
Файловая система 3OSFS была построена на следующих предпосылках:
Для обеспечения быстрого доступа к данным, все необходимые сведения о файлах сводятся в единую файловую таблицу, на основе которой уже потом строятся индивидуальные файловые таблицы пользователей. Единая файловая таблица хранится в начале диска. Для увеличения быстродействия работы с файловой таблицей в плагине OptimizationClass создан кэш записей таблицы к которым система обращалась в последний раз (не менее 400 записей), который размещен в памяти.
Обеспечение быстрого доступа так же подразумевает борьбу с фрагментацией файлов. Для этого раздел имеет структуру, при которой фрагментация файлов размером <8Mb (размер блока раздела) минимальна. Весь раздел поделен на блоки (8Mb). Каждый блок может вмещать в себя множество записей (до 4000 файлов, реестров, описателей контента). Ключевым моментом для минимизации фрагментации является алгоритм работы с блоками. При записи файла на диск: Если файл <8Mb и не помещается в уже занятые блоки целиком, он пишется в новый блок. Если файл <8Mb умещается в уже занятый блок целиком, он пишется туда. Если файл >=8Mb, то он всегда пишеться начиная с нового блока, и имеет продолжение в других чистых блоках, единственое исключение делается для "конца" файла, он может быть дописан в уже занятый блок (если он в нем умещается). Дозапись в блок файлов размер которых <8Mb, поисходит только целиком, одним куском.
Надежность хранения обеспечивается возможностью восстановления таблицы файлов при ее крахе. Записи о файлах могут быть восстановлены по записям которые храняться вначале блока. Единственное что мы теряем оригинальные имена файлов и некотрые атрибуты. По информации лежащей в начале блока мы можем установить: длинну файла, цепочки кластеров данных файла (реестра, описателя контента), его положение в таблице файлов (идентификационный номер). Это уже не мало. Если файл имеет имя длиннее 38-ми символов, то мы восстановим и его имя (из реестра). Так же для повышения надежности мы можем использовать зеркалирование FS.
Специально для того что бы пользователь смог восстановить свои удаленные файлы, драйвер может работать в 3-режимах удаления: 1) Запись помечается как свободная. 2) Запись помечается как удаленный файл, но запись и ее кластеры не затираются до тех пор, пока не будет заканчиваться свободное пространство на диске (2% от емкости диска, но не менее 500Mb). 3) Запись и ее кластеры физически вытираются с диска (самый медленный режим).
Разграничение доступа к файлам организуется не только на уровне ОС (учетные записи пользователей), но и на уровне файловой системы. Пользователь может сам назначить права доступа на свои собственные файлы.
Файловая система обеспечивает хранение реестра и описателя контента в паралельных цепочках кластеров, котрые в идеале должны хранится в одном блоке с файлом, но могут и храниться отдельно от файла. Под параллельностью здесь понимается то, что одной записи соответствуют 3 цепочки кластеров (данные, реестр, описатель контента). Любая из этих цепочек может отсутствовать.

Формат раздела 3OSFS

Для понимания формата раздела 3OSFS, необходимо знать следующее: Весь раздел побит на блоки по 8Mb. Первый блок - системный, далее идет несколько “сырых блоков”, и после них идут блоки с данными. Первый (системный) блок начинается прямо от начала раздела, т.е. boot-запись это уже первый сектор первого блока. “Сырые блоки” - это свободные блоки, которые еще никак не размечены. Если у нас заканчивается место отведенное под таблицу файлов, то мы “откусываем” из “сырой области” следующий блок для таблицы. Если у нас закончилось свободное место в разделе, то последний “сырой блок” размечается, как свободный блок данных. Блоки данных разбиты на кластеры, размером по 2kb, и имеют собственную таблицу размещения данных в блоке. Все атрибуты файла, кроме реестра и описателя контента, для увеличения быстродействия сведены в единую таблицу.
Раздел 3OSFS можно представить в следующем виде:

Заголовок раздела занимает 512 байт:

  Содержание Размер (байт) Примечания
1. Идентификатор раздела 20 Строка ‘3OS filesystem vN.NN’
2. Имя раздела 200 100 символов unicode
3. Указатель на таблицу файлов 4 Сектор с которого начинаются записи файлов
4. Размер кластера в блоке 4 Измеряется в байтах, кратен физическому сектору диска. Стандартно равен 2kb.
5. Размер блока 4 Измеряется в кластерах. Стандартно=4000 (8Mb в кластерах по 2kb).
6. Адрес первого блока 4 Первый сектор, с которого начинается деление диска на блоки.
7. Дата форматирования 4 -
8. Дата последней дефрагментации 4 -
9. Дата последней проверки FS 4 -
10. Флаг необходимости проверки FS 1 Устанавливается в 1, если при следующем запуске требуется произвести проверку раздела.
11. Зарезервировано 263 -


Таблица файлов состоит из записей, размер которых составляет 128 байт. Пример такой записи:

  Содержание Размер (байт) Примечания
1. Тип записи 1 0 - чистая запись.
1 - Файл
2 - Файл помеченный как удаленный.
2. Тип хранения файла в FS. 1 0 - Обычное хранение
1 - Файл заархивирован
2 - Файл зашифрован
3 - Файл заархивирован и зашифрован
3. Имя файла 64 32 символа unicode. Вообще, имя файла может достигать до 255 символов. Если имя превышает 32 символа, то оно размещается в начале реестра файла, а в этом поле помещается индикатор переполнения - строка "00 in reg"
4. Размер файла 8 В байтах. Max. размер 2^64 байт (примерно 16000 пентабайт).
5. Размер реестра 4 В байтах. Max. размер 4Gb.
6. Размер описателя контента 4 В байтах. Max. размер 4Gb.
7. Дата создания 4 Формат: 1-й (младший) байт - день
2-ой байт - месяц
3-й и 4-й байты - год.
8. Время создания 4 Формат: 1-й (младший) байт - час
2-ой байт - минуты
3-й - секунды
4-й - зарезервирован..
9. Дата последнего изменения 4 -
10. Время последнего изменения 4 -
11. ID владельца файла 4 0 - система 1 - root и т.д.
12. Маска доступа к файлу 8 Определяется самим пользователем. Пока недокументирована, т.к. формат будет зависить от того в какую сторону будет развиваться 3OS
13. Указатель на блок в котором хранятся данные реестра. 4 Если = 0, то файл без реестра.
14. Номер записи реестра в таблице блока. 2 -
15. Указатель на блок в котором хранятся данные описателя контента 4 Если = 0, то это raw-файл.
16. Номер записи описателя контента в таблице блока. 2 -
17. Указатель на блок в котором хранятся данные файла 4 Для файла нулевой длинны, это поле = 0, т.е. данные нигде не хранятся.
18. Номер записи данных файла в таблице блока. 2 -


Блок размеченный для хранения данных имеет свою таблицу размещения информации, c записями размером в 16 байт:

  Содержание Размер (байт) Примечания
1. Идентификатор файла к которому принадлежит запись. 4 № файла в общей таблице.
2. Адрес данных в блоке. 2 Смещение в кластерах от начала блока. Максимальное смещение составляет 64536 кластеров, что при минимальном размере кластера 512байт, составит 32Mb, т.е. не стоит задавать размер блока более 32Mb.
3. Количество кластеров занятых под запись в блоке 2 -
4. Указатель на след. блок. 2 Если = 0, то значит запись помещается в блоке целиком, если нет, то содержит адрес следующего блока в котором лежит продолжение записи.
5. Указатель замись в следующем блоке принадлежащей записи (файлу, реестру, описателю контента). 2 Если = 0, то значит файл помещается в блоке целиком, если нет, то содержит адрес следующего блока в котором лежит продолжение записи.
6. Тип записи. 2 0 - Данные Файла, 1 - реестр, 2 - описатель контента.
7. Зарезервировано. 2 -



Стандартное API драйвера файловой системы

API драйвера файловой системы базируются на методах предоставляемым классами PartitionClass, FileTableClass и FileClass. Для доступа к этим методам мы обязательно должны воспользоваться драйвером FS, использовать эти классы на прямую нельзя (и попросту не получится). Рассмотрим каждый из них:
PartitionClass:
FileTableClass:
FileClass:

Не описан! Требует проработки!