.

Структура файловой системы Linux и UNIX

Язык: русский
Формат: курсова
Тип документа: Word Doc
76 1642
Скачать документ

Основные понятия

Операционная система Linux разработана в соответствии с требованиями
международного стандарта на UNIX-совместимые системы IEEE POSIX, поэтому
логично будет кратко рассмотреть сначала структуру файловой системы ОС
UNIX.

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

Пользователь

С самого начала ОС UNIX замышлялась как интерактивная система. Другими
словами, UNIX предназначен для терминальной работы. Чтобы начать
работать, человек должен “войти” в систему, введя со свободного
терминала свое учетное имя (account name) и, возможно, пароль
(password). Человек, зарегистрированный в учетных файлах системы, и,
следовательно, имеющий учетное имя, называется зарегистрированным
пользователем системы. Регистрацию новых пользователей обычно выполняет
администратор системы. Пользователь не может изменить свое учетное имя,
но может установить и/или изменить свой пароль. Пароли хранятся в
отдельном файле в закодированном виде. Не стоит забывать свой пароль,
снова узнать его не поможет даже администратор!

Все пользователи ОС UNIX явно или неявно работают с файлами. Файловая
система ОС UNIX имеет древовидную структуру. Промежуточными узлами
дерева являются каталоги со ссылками на другие каталоги или файлы, а
листья дерева соответствуют файлам или пустым каталогам. Каждому
зарегистрированному пользователю соответствует некоторый каталог
файловой системы, который называется “домашним” (home) каталогом
пользователя. При входе в систему пользователь получает неограниченный
доступ к своему домашнему каталогу и всем каталогам и файлам,
содержащимся в нем. Пользователь может создавать, удалять и
модифицировать каталоги и файлы, содержащиеся в домашнем каталоге.
Потенциально возможен доступ и ко всем другим файлам, однако он может
быть ограничен, если пользователь не имеет достаточных привилегий.

Файловая система

Понятие файла является одним из наиболее важных для ОС UNIX. Все файлы,
с которыми могут манипулировать пользователи, располагаются в файловой
системе, представляющей собой дерево, промежуточные вершины которого
соответствуют каталогам, и листья – файлам и пустым каталогам. Примерная
структура файловой системы ОС UNIX показана на рисунке 2.1. Реально на
каждом логическом диске (разделе физического дискового пакета)
располагается отдельная иерархия каталогов и файлов. Для получения
общего дерева в динамике используется “монтирование” отдельных иерархий
к фиксированной корневой файловой системе.

Замечание: В мире ОС UNIX по историческим причинам термин “файловая
система” является перегруженным, обозначая одновременно иерархию
каталогов и файлов и часть ядра, которая управляет каталогами и файлами.
Видимо, было бы правильнее называть иерархию каталогов и файлов архивом
файлов, а термин “файловая система” использовать только во втором
смысле. Однако, следуя традиции ОС UNIX, мы будем использовать этот
термин в двух смыслах, различая значения по контексту.

Каждый каталог и файл файловой системы имеет уникальное полное имя (в ОС
UNIX это имя принято называть full pathname – имя, задающее полный путь,
поскольку оно действительно задает полный путь от корня файловой системы
через цепочку каталогов к соответствующему каталогу или файлу; я буду
использовать термин “полное имя”, поскольку для pathname отсутствует
благозвучный русский аналог). Каталог, являющийся корнем файловой
системы (корневой каталог), в любой файловой системе имеет
предопределенное имя “/” (слэш). Полное имя файла, например, /bin/sh
означает, что в корневом каталоге должно содержаться имя каталога bin, а
в каталоге bin должно содержаться имя файла sh. Коротким или
относительным именем файла (relative pathname) называется имя (возможно,
составное), задающее путь к файлу от текущего рабочего каталога
(существует команда и соответствующий системный вызов, позволяющие
установить текущий рабочий каталог).

В каждом каталоге содержатся два специальных имени, имя “.”, именующее
сам этот каталог, и имя “..”, именующее “родительский” каталог данного
каталога, т.е. каталог, непосредственно предшествующий данному в
иерархии каталогов.

Рис. 2.1. Структура каталогов файловой системы

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

Cp имя1 имя2 – копирование файла имя1 в файл имя2

Rm имя1 – уничтожение файла имя1

Mv имя1 имя2 – переименование файла имя1 в файл имя2

mkdir имя – создание нового каталога имя

rmdir имя – уничтожение каталога имя

ls имя – выдача содержимого каталога имя

cat имя – выдача на экран содержимого файла имя

chown имя режим – изменение режима доступа к файлу

Структура файловой системы

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

В мире UNIX существует несколько разных видов файловых систем со своей
структурой внешней памяти. Наиболее известны традиционная файловая
система UNIX System V (s5) и файловая система семейства UNIX BSD (ufs).
Файловая система s5 состоит из четырех секций (рисунок 2.2,a). В
файловой системе ufs на логическом диске (разделе реального диска)
находится последовательность секций файловой системы (рисунок 2.2,b).

Рис. 2.2. Структура внешней памяти файловых систем s5 и ufs

Кратко опишем суть и назначение каждой области диска.

Boot-блок содержит программу раскрутки, которая служит для
первоначального запуска ОС UNIX. В файловых системах s5 реально
используется boot-блок только корневой файловой системы. В
дополнительных файловых системах эта область присутствует, но не
используется.

Суперблок – это наиболее ответственная область файловой системы,
содержащая информацию, которая необходима для работы с файловой системой
в целом. Суперблок содержит список свободных блоков и свободные i-узлы
(information nodes – информационные узлы). В файловых системах ufs для
повышения устойчивости поддерживается несколько копий суперблока (как
видно из рисунка 2.2,b, по одной копии на группу цилиндров). Каждая
копия суперблока имеет размер 8196 байт, и только одна копия суперблока
используется при монтировании файловой системы (см. ниже). Однако, если
при монтировании устанавливается, что первичная копия суперблока
повреждена или не удовлетворяет критериям целостности информации,
используется резервная копия.

Блок группы цилиндров содержит число i-узлов, специфицированных в списке
i-узлов для данной группы цилиндров, и число блоков данных, которые
связаны с этими i-узлами. Размер блока группы цилиндров зависит от
размера файловой системы. Для повышения эффективности файловая система
ufs старается размещать i-узлы и блоки данных в одной и той же группе
цилиндров.

Список i-узлов (ilist) содержит список i-узлов, соответствующих файлам
данной файловой системы. Максимальное число файлов, которые могут быть
созданы в файловой системе, определяется числом доступных i-узлов. В
i-узле хранится информация, описывающая файл: режимы доступа к файлу,
время создания и последней модификации, идентификатор пользователя и
идентификатор группы создателя файла, описание блочной структуры файла и
т.д.

Блоки данных – в этой части файловой системы хранятся реальные данные
файлов. В случае файловой системы ufs все блоки данных одного файла
пытаются разместить в одной группе цилиндров. Размер блока данных
определяется при форматировании файловой системы командой mkfs и может
быть установлен в 512, 1024, 2048, 4096 или 8192 байтов.

Монтируемые файловые системы

Файлы любой файловой системы становятся доступными только после
“монтирования” этой файловой системы. Файлы “не смонтированной” файловой
системы не являются видимыми операционной системой.

Для монтирования файловой системы используется системный вызов mount.
Монтирование файловой системы означает следующее. В имеющемся к моменту
монтирования дереве каталогов и файлов должен иметься листовой узел –
пустой каталог (в терминологии UNIX такой каталог, используемый для
монтирования файловой системы, называется directory mount point – точка
монтирования). В любой файловой системе имеется корневой каталог. Во
время выполнения системного вызова mount корневой каталог монтируемой
файловой системы совмещается с каталогом – точкой монтирования, в
результате чего образуется новая иерархия с полными именами каталогов и
файлов.

Смонтированная файловая система впоследствии может быть отсоединена от
общей иерархии с использованием системного вызова umount. Для успешного
выполнения этого системного вызова требуется, чтобы отсоединяемая
файловая система к этому моменту не находилась в использовании (т.е. ни
один файл из этой файловой системы не был открыт). Корневая файловая
система всегда является смонтированной, и к ней не применим системный
вызов umount.

Как я отмечал выше, отдельная файловая система обычно располагается на
логическом диске, т.е. на разделе физического диска. Для инициализации
файловой системы не поддерживаются какие-либо специальные системные
вызовы. Новая файловая система образуется на отформатированном диске с
использованием утилиты (команды) mkfs. Вновь созданная файловая система
инициализируется в состояние, соответствующее наличию всего лишь одного
пустого корневого каталога. Команда mkfs выполняет инициализацию путем
прямой записи соответствующих данных на диск.

Интерфейс с файловой системой

Ядро ОС UNIX поддерживает для работы с файлами несколько системных
вызовов. Среди них наиболее важными являются open, creat, read, write,
lseek и close.

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

Файл в системных вызовах, обеспечивающих реальный доступ к данным,
идентифицируется своим дескриптором (целым значением). Дескриптор файла
выдается системными вызовами open (открыть файл) и creat (создать файл).
Основным параметром операций открытия и создания файла является полное
или относительное имя файла. Кроме того, при открытии файла указывается
также режим открытия (только чтение, только запись, запись и чтение и
т.д.) и характеристика, определяющая возможности доступа к файлу:

open(pathname, oflag [,mode])

Одним из признаков, которые могут участвовать в параметре oflag,
является признак O_CREAT, наличие которого указывает на необходимость
создания файла, если при выполнении системного вызова open файл с
указанным именем не существует (параметр mode имеет смысл только при
наличии этого признака). Тем не менее по историческим причинам и для
обеспечения совместимости с предыдущими версиями ОС UNIX отдельно
поддерживается системный вызов creat, выполняющий практически те же
функции.

Открытый файл может использоваться для чтения и записи
последовательностей байтов. Для этого поддерживаются два системных
вызова:

read(fd, buffer, count) и write(fd, buffer, count)

Здесь fd – дескриптор файла (полученный при ранее выполненном системном
вызове open или creat), buffer – указатель символьного массива и count –
число байтов, которые должны быть прочитаны из файла или в него
записаны. Значение функции read или write – целое число, которое
совпадает со значением count, если операция заканчивается успешно, равно
нулю при достижении конца файла и отрицательно при возникновении ошибок.

В каждом открытом файле существует текущая позиция. Сразу после открытия
файл позиционируется на первый байт. Другими словами, если сразу после
открытия файла выполняется системный вызов read (или write), то будут
прочитаны (или записаны) первые count байтов содержимого файла (конечно,
они будут успешно прочитаны только в том случае, если файл реально
содержит по крайней мере count байтов). После выполнения системного
вызова read (или write) указатель чтения/записи файла будет установлен в
позицию count+1 и т.д.

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

lseek(fd, offset, origin)

Как и раньше, здесь fd – дескриптор ранее открытого файла. Параметр
offset задает значение относительного смещения указателя чтения/записи,
а параметр origin указывает, относительно какой позиции должно
применяться смещение. Возможны три значения параметра origin. Значение 0
указывает, что значение offset должно рассматриваться как смещение
относительно начала файла. Значение 1 означает, что значение offset
является смещением относительно текущей позиции файла. Наконец, значение
2 говорит о том, что задается смещение относительно конца файла.
Заметим, что типом данных параметра offset является long int. Это
значит, что, во-первых, могут задаваться достаточно длинные смещения и,
во-вторых, смещения могут быть положительными и отрицательными.

Например, после выполнения системного вызова

lseek(fd, 0, 0)

указатель чтения/записи соответствующего файла будет установлен на
начало (на первый байт) файла. Системный вызов

lseek(fd, 0, 2)

установит указатель на конец файла. Наконец, выполнение системного
вызова

lseek(fd, 10, 1)

приведет к увеличению текущего значения указателя на 10.

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

Разновидности файлов

Как я неоднократно отмечал, в ОС UNIX понятие файла является
универсальной абстракцией, позволяющей работать с обычными файлами,
содержащимися на устройствах внешней памяти; с устройствами, вообще
говоря, отличающимися от устройств внешней памяти; с информацией,
динамически генерируемой другими процессами и т.д. Для поддержки этих
возможностей единообразным способом файловые системы ОС UNIX
поддерживают несколько типов файлов, наиболее существенные из которых мы
рассмотрим в этом разделе.

Обычные файлы

Обычные (или регулярные) файлы реально представляют собой набор блоков
(возможно, пустой) на устройстве внешней памяти, на котором
поддерживается файловая система. Такие файлы могут содержать как
текстовую информацию (обычно в формате ASCII), так и произвольную
двоичную информацию. Файловая система не предписывает обычным файлам
какую-либо структуру, обеспечивая на уровне пользователей представление
обычного файла как последовательности байтов. Используя базовые
системные вызовы , пользователи могут как угодно структурировать файлы.
В частности, многие СУБД хранят базы данных в обычных файлах ОС UNIX.

Для некоторых файлов, которые должны интерпретироваться компонентами
самой операционной системы, UNIX поддерживает фиксированную структуру.
Наиболее важным примером таких файлов являются объектные и выполняемые
файлы. Структура этих файлов поддерживается компиляторами, редакторами
связей и загрузчиком. Однако, эта структура неизвестна файловой системе.
Для нее такие файлы по-прежнему являются обычными файлами.

Файлы-каталоги

Наличие обычных файлов недостаточно для организации иерархических
файловых систем. Требуется наличие каталогов, которые сопоставляют имена
файлов или каталогов с их физическим описанием. Каталоги представляют
собой особый вид файлов, которые хранятся во внешней памяти подобно
обычным файлам, но структура которых поддерживается самой файловой
системой.

Структура файла-каталога очень проста. Фактически, каталог – это
таблица, каждый элемент которой состоит из двух полей: номера i-узла
данного файла в его файловой системе и имени файла, которое связано с
этим номером (конечно, этот файл может быть и каталогом). Если
просмотреть содержимое текущего рабочего каталога с помощью команды ls
-ai, то можно получить, например, следующий вывод:

inode File

number name

_________________________

33 .

122 ..

54 first_file

65 second_file

65 second_again

77 dir2

Этот вывод демонстрирует, что в любом каталоге содержатся два
стандартных имени – “.” и “..”. Имени “.” сопоставляется i-узел,
соответствующий самому этому каталогу, а имени “..” – i-узел,
соответствующий “родительскому” каталогу данного каталога.
“Родительским” (parent) каталогом называется каталог, в котором
содержится имя данного каталога. Файлы с именами “first_file” и
“second_file” – это разные файлы с номерами i-узлов 54 и 65
соответственно. Файл “second_again” представляет пример так называемой
жесткой ссылки: он имеет другое имя, но реально описывается тем же
i-узлом, что и файл “second_file”. Наконец, последний элемент каталога
описывает некоторый другой каталог с именем “dir2”.

Этот последний файл, как и любой обычный файл, хранится в файловой
системе как набор блоков запоминающего устройства. Однако файловая
система знает, что на самом деле это каталог со структурой,
контролируемой файловой системой. Поэтому файлам-каталогам соответствует
особый тип файла (обозначенный в их i-узлах), по отношению к которому
возможно выполнение только специального набора системных вызовов:

mkdir, производящего новый каталог,

rmdir, удаляющий пустой (незаполненный) каталог,

getdents, позволяющего прочитать содержимое указанного каталога.

Отсутствует системный вызов, позволяющий прямо писать в файл-каталог.
Какими бы правами вы не обладали по отношению к файлу-каталогу, прямая
запись информации в него запрещена – прямое следствие фиксированной (и
закрытой от пользователей) структуры файлов-каталогов. Запись в
файлы-каталоги производится неявно при создании и уничтожении файлов и
каталогов, однако читать из файла-каталога при наличии соответствующих
прав можно (пример – стандартная утилита ls, которая как раз и
пользуется системным вызовом getdents).

Специальные файлы

Специальные файлы не хранят данные. Они обеспечивают механизм
отображения физических внешних устройств в имена файлов файловой
системы. Каждому устройству, поддерживаемому системой, соответствует, по
меньшей мере, один специальный файл. Специальные файлы создаются при
выполнении системного вызова mknod, каждому специальному файлу
соответствует порция программного обеспечения, называемая драйвером
соответствующего устройства. При выполнении чтения или записи по
отношению к специальному файлу, производится прямой вызов
соответствующего драйвера, программный код которого отвечает за передачу
данных между процессом пользователя и соответствующим физическим
устройством.

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

cp myfile /tmp/kuz

перепишет файл с именем myfile в подкаталог kuz рабочего каталога. В то
же время, команда

cp myfile /dev/console

выдаст содержимое файла myfile на системную консоль вашей установки.

Различаются два типа специальных файлов – блочные и символьные. Блочные
специальные файлы ассоциируются с такими внешними устройствами, обмен с
которыми производится блоками байтов данных, размером 512, 1024, 4096
или 8192 байтов. Типичным примером подобных устройств являются магнитные
диски. Файловые системы всегда находятся на блочных устройствах, так что
в команде mount обязательно указывается некоторое блочное устройство.

Символьные специальные файлы ассоциируются с внешними устройствами,
которые не обязательно требуют обмена блоками данных равного размера.
Примерами таких устройств являются терминалы (в том числе, системная
консоль), последовательные устройства, некоторые виды магнитных лент.
Иногда символьные специальные файлы ассоциируются с магнитными дисками.

При обмене данными с блочным устройством система буферизует данные во
внутреннем системном кеше. Через определенные интервалы времени система
“выталкивает” буфера, при которых содержится метка “измененный”. Кроме
того, существуют системные вызовы sync и fsync, которые могут
использоваться в пользовательских программах, и выполнение которых
приводит к выталкиванию измененных буферов из общесистемного пула.
Основная проблема состоит в том, что при аварийной остановке компьютера
(например, при внезапном выключении электрического питания) содержимое
системного кеша может быть утрачено. Тогда внешние блочные файлы могут
оказаться в рассогласованном состоянии. Например, может быть не
вытолкнут супер-блок файловой системы, хотя файловая система
соответствует его вытолкнутому состоянию. Заметим, что в любом случае
согласованное состояние файловой системы может быть восстановлено
(конечно, не всегда без потерь пользовательской информации).

Обмены с символьными специальными файлами производятся напрямую, без
использования системной буферизации.

Связывание файлов с разными именами

Файловая система ОС UNIX обеспечивает возможность связывания одного и
того же файла с разными именами. Часто имеет смысл хранить под разными
именами одну и ту же команду (выполняемый файл) командного
интерпретатора. Например, выполняемый файл традиционного текстового
редактора ОС UNIX vi обычно может вызываться под именами ex, edit, vi,
view и vedit.

Можно узнать имена всех связей данного файла с помощью команды ncheck,
если указать в числе ее параметров номер i-узла интересующего файла.
Например, чтобы узнать все имена, под которыми возможен вызов редактора
vi, можно выполнить следующую последовательность команд (третий аргумент
команды ncheck представляет собой имя специального файла,
ассоциированного с файловой системой /usr):

$ ls -i /usr/bin/vi

372 /usr/bin/vi

$ ncheck -i 372 /dev/dsk/sc0d0s5

/dev/dsk/sc0d0s5:

372 /usr/bin/edit

372 /usr/bin/ex

372 /usr/bin/vedit

372 /usr/bin/vi

372 /usr/bin/view

Ранее в большинстве версий ОС UNIX поддерживались только так называемые
“жесткие” связи, означающие, что в соответствующем каталоге имени связи
сопоставлялось имя i-узла соответствующего файла. Новые жесткие связи
могут создаваться с помощью системного вызова link. При выполнении этого
системного вызова создается новый элемент каталога с тем же номером
i-узла, что и ранее существовавший файл.

Начиная с “быстрой файловой системы” университета Беркли, в мире UNIX
появились “символические связи”. Символическая связь создается с помощью
системного вызова symblink. При выполнении этого системного вызова в
соответствующем каталоге создается элемент, в котором имени связи
сопоставляется некоторое имя файла (этот файл даже не обязан
существовать к моменту создания символической связи). Для символической
связи создается отдельный i-узел и даже заводится отдельный блок данных
для хранения потенциально длинного имени файла.

Для работы с символьными связями поддерживаются три специальных
системных вызова:

readlink – читает имя файла, связанного с именуемой символической связью
(это имя может соответствовать реальному файлу, специальному файлу,
жесткой ссылке или вообще ничему); имя хранится в блоке данных,
связанном с данной символической ссылкой;

lstat – аналогичен системному вызову stat (получить информацию о файле),
но относится к символической ссылке;

lchowm – аналогичен системному вызову chown, но используется для смены
пользователя и группы самой символической ссылки.

Именованные программные каналы

Программный канал (pipe) – это одно из наиболее традиционных средств
межпроцессных взаимодействий в ОС UNIX. В русской терминологии
использовались различные переводы слова pipe (начиная от “трубки” и
заканчивая замечательным русским словом “пайп”). Я считаю, что термин
“программный канал” наиболее точно отражает смысл термина “pipe”.

Основной принцип работы программного канала состоит в буферизации
байтового вывода одного процесса и обеспечении возможности чтения
содержимого программного канала другим процессом в режиме FIFO (т.е.
первым будет прочитан байт, который раньше всего записан). В любом
случае интерфейс программного канала совпадает с интерфейсом файла (т.е.
используются те же самые системные вызовы read и write).

Однако различаются два подвида программных каналов – неименованные и
именованные. Неименованные программные каналы появились на самой заре ОС
UNIX . Неименованный программный канал создается процессом-предком,
наследуется процессами-потомками, и обеспечивает тем самым возможность
связи в иерархии порожденных процессов. Интерфейс неименованного
программного канала совпадает с интерфейсом файла. Однако, поскольку
такие каналы не имеют имени, им не соответствует какой-либо элемент
каталога в файловой системе.

Именованному программному каналу обязательно соответствует элемент
некоторого каталога и даже собственный i-узел. Другими словами,
именованный программный канал выглядит как обычный файл, но не
содержащий никаких данных до тех пор, пока некоторый процесс не выполнит
в него запись. После того, как некоторый другой процесс прочитает
записанные в канал байты, этот файл снова становится пустым. В отличие
от неименованных программных каналов, именованные программные каналы
могут использоваться для связи любых процессов (т.е. не обязательно
процессов, входящих в одну иерархию родства). Интерфейс именованного
программного канала практически полностью совпадает с интерфейсом
обычного файла (включая системные вызовы open и close), хотя, конечно,
необходимо учитывать, что поведение канала отличается от поведения
файла.

Файлы, отображаемые в виртуальную память

В современных версиях ОС UNIX (например, в UNIX System V.4) появилась
возможность отображать обычные файлы в виртуальную память процесса с
последующей работой с содержимым файла не с помощью системных вызовов
read, write и lseek, а с помощью обычных операций чтения из памяти и
записи в память. Заметим, что этот прием был базовым в историческом
предшественнике ОС UNIX – операционной системе Multics.

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

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

Синхронизация при параллельном доступе к файлам

Исторически в ОС UNIX всегда применялся очень простой подход к
обеспечению параллельного (от нескольких процессов) доступа к файлам:
система позволяла любому числу процессов одновременно открывать один и
тот же файл в любом режиме (чтения, записи или обновления) и не
предпринимала никаких синхронизационных действий. Вся ответственность за
корректность совместной обработки файла ложилась на использующие его
процессы, и система даже не предоставляла каких-либо особых средств для
синхронизации доступа процессов к файлу.

В System V.4 появились средства, позволяющие процессам синхронизировать
параллельный доступ к файлам. В принципе, было бы логично связать
синхронизацию доступа к файлу как к единому целому с системным вызовом
open (т.е., например, открытие файла в режиме записи или обновления
могло бы означать его монопольную блокировку соответствующим процессом,
а открытие в режиме чтения – совместную блокировку). Так поступают во
многих операционных системах (начиная с ОС Multics). Однако, по
отношению к ОС UNIX такое решение принимать было слишком поздно,
поскольку многочисленные созданные за время существования системы
прикладные программы опирались на свойство отсутствия автоматической
синхронизации.

Поэтому разработчикам пришлось пойти “обходным путем”. Ядро ОС UNIX
поддерживает дополнительный системный вызов fcntl, обеспечивающий такие
вспомогательные функции, относящиеся к файловой системе, как получение
информации о текущем режиме открытия файла, изменение текущего режима
открытия и т.д. В System V.4 именно на системный вызов fcntl нагружены
функции синхронизации.

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

Установленные блокировки относятся только к тому процессу, который их
установил, и не наследуются процессами-потомками этого процесса. Более
того, даже если некоторый процесс пользуется синхронизационными
возможностями системного вызова fcntl, другие процессы по-прежнему могут
работать с тем файлом без всякой синхронизации. Другими словами, это
дело группы процессов, совместно использующих файл, – договориться о
способе синхронизации параллельного доступа.

Распределенные файловые системы

Основная идея распределенной файловой системы состоит в том, чтобы
обеспечить совместный доступ к файлам локальной файловой системы для
процессов, которые, вообще говоря, выполняются на других компьютерах.
Эта идея может быть реализована многими разными способами, однако в
среде ОС UNIX все известные подходы основываются на монтировании
удаленной файловой системы к одному из каталогов локальной файловой
системы. После выполнения этой процедуры файлы, хранимые в удаленной
файловой системе, доступны процессам локального компьютера точно таким
же образом, как если бы они хранились на локальном дисковом устройстве.

На рисунке 2.3 приведен пример, в котором два подкаталога удаленной
файловой системы-сервера (share и X11) монтируются к двум (пустым)
каталогам файловой системы-клиента.

Рис. 2.3. Схема монтирования удаленной файловой системы

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

Теперь перейдем собственно к файловой системе Linjx/

Структура файловой системы LINUX

Человеку, ранее работавшему с DOS или Windows, при общении с Linux
прежде всего бросаются в глаза использование символа `/’ вместо ‘\’,
отсутствие имен дисков (A:, B:, C: и т. д.) и то, что в именах файлов
различаются большие и маленькие буквы. Однако другие особенности, не
столь заметные с первого взгляда, более существенны. Давайте посмотрим,
как устроена в Linux работа с файлами.

Прежде чем переходить к основному изложению, заметим, что выражение
“файловая система” имеет два значения. Так называют, во-первых,
определенный способ организации файлов, каталогов и т. д., а во-вторых,
конкретное множество файлов, каталогов и т. д., организованное по этому
способу.

Хотя Linux поддерживает более десятка самых разных файловых систем, все
“иностранные” (foreign) системы так или иначе маскируются под стандартно
используемую в этой ОС ext2fs. Давайте с нее и начнем.

Узлы и каталоги

Во времена юности Unix, когда автор Linux еще не ходил в школу, работа с
файлами в этой ОС была организована весьма просто: все файлы на диске
нумеровались и для каждого создавалась специальная запись – узел (inode;
к сожалению, устоявшегося русского перевода этого термина пока нет), где
содержалась служебная информация о файле. Имя в состав этой информации
не включалось, а связывалось с узлом с помощью ссылки (link). Ссылки
оформлялись как пары вида “имя файла – номер узла” и хранились в
каталогах. Каталог можно было читать, как обычный файл, однако для его
модификации уже тогда требовалось использовать специальные команды.

Найдя по ссылке в каталоге узел, ядро ОС дальше оперировало с файлом, не
обращая никакого внимания на его исходное имя, поскольку все необходимые
данные (размер файла, права доступа к нему и т. д.) извлекались уже из
узла. С тех пор многое изменилось, однако в файловой системе Linux узлы
по-прежнему играют важную роль, а вся информация о файле по-прежнему
хранится отдельно от его имени.

Далее, в Unix-системах (включая Linux) нет операции удаления файла в
смысле DOS/Windows: есть только удаление ссылки на узел – unlink – и
ссылки на пустой каталог – rmdir (в некоторых Unix-системах unlink
позволяет удалить ссылку на пустой каталог, но в Linux это не так). Сам
же файл удаляется автоматически тогда, когда делается недоступным для
системы. Это означает, что не должно остаться, во-первых, ни одной
ссылки на него, а во-вторых, ни одной работающей с ним активной
программы.

Именно поэтому, кстати, в Linux можно обойтись без перезагрузки
практически при любом изменении системы (за исключением замены ядра).
Чтобы обновить системную библиотеку, вы стираете ее прежнюю версию (т.
е. освобождаете соответствующую ссылку) и записываете под тем же именем
новую. Ядро откладывает момент удаления библиотеки до тех пор, пока не
закончит работу последняя из программ, ее использующих (что может
произойти много месяцев спустя). Это весьма удобно, но если не знать о
таком поведении системы, можно попасть в неприятную ситуацию.

Монтирование

Однако если ядро ОС учитывает не только состояние файловой системы на
диске, но и состояние программ, работающих с файлами, то как быть со
сменными носителями? Ведь если просто вынуть из дисковода дискету с
файлом, уже не имеющим имени, но еще не удаленным, файловая система
будет разрушена; степень повреждения зависит от разных обстоятельств и
варьирует от небольших неполадок до полного превращения в руины. Здесь
как нельзя лучше подтверждается мысль о том, что наши недостатки – это
продолжение наших достоинств.

Чтобы избежать подобных эффектов, любую файловую систему необходимо
перед началом работы с ней в явной форме подключить к ОС (смонтировать –
mount), а по окончании отключить (размонтировать – unmount). Для этой
цели служат команды mount и umount (без n, хотя соответствующее действие
называется unmount). Команда mount имеет множество опций, но
обязательных аргументов у ее стандартного варианта два: имя файла
блочного устройства и имя каталога. В результате выполнения этой команды
файловая система, расположенная на указанном устройстве, подключается к
системе таким образом, что ее содержимое заменяет собой содержимое
заданного каталога (поэтому для монтирования обычно используют пустой
каталог). Команда umount выполняет обратную операцию – отсоединяет
файловую систему, после чего накопитель можно извлечь и положить на
полку (на самом деле проблемы возникают почти исключительно с дискетами:
CD-ROM, магнитно-оптический диск или Zip-диск, который забыли
размонтировать, просто не удастся вытащить без помощи скрепки – он
блокируется).

Такие разные файлы

Осталось выяснить, что такое файл блочного устройства. Для этого следует
рассказать о том, какие вообще “звери” встречаются в файловой системе.
Очевидно, там есть обычные файлы и каталоги, но это далеко не все.
Файлами с точки зрения Linux являются также:

символьные устройства;

блочные устройства;

именованные каналы (named pipes);

гнезда (sockets);

символьные ссылки (symlinks).

Все эти “звери” в чем-то похожи на обычные файлы, а в чем-то отличаются
от них (во всяком случае, все они могут быть удалены системным вызовом
unlink, что сближает их с обычными файлами и отдаляет от каталогов).
Рассмотрим их по порядку.

Символьные и блочные устройства

Файлы символьных и блочных устройств создаются с помощью программы mknod
и соответствуют внешним устройствам, а также псевдоустройствам, таким
как знаменитое пустое устройство /dev/null (такое, при попытке чтения из
которого сразу же сообщается о достижении конца файла и при записи в
которое никогда не происходит переполнения – точный аналог NUL в
DOS/Windows).

Устройства нумеруются двумя целыми числами – старшим (major number) и
младшим (minor number). Первое из них соответствует типу устройства
(например, для устройств, подключенных к первому IDE-контроллеру, оно
равно 3, для подключенных ко второму – 22 и т. д.), а второе –
конкретному устройству (например, для мастер-диска, подключенного к
первому IDE-контроллеру, оно равно 0, для первого раздела на этом диске
– 1 и т. д.). При этом символьные и блочные устройства нумеруются
независимо.

Различие между файлами символьных и блочных устройств заключается в том,
что к первым разрешен только последовательный доступ, а вторые допускают
обращение (для чтения или записи) к произвольному месту устройства.

Многие устройства имеют дополнительные характеристики: скажем, на
консоли (виртуальной) IBM PC есть три лампочки – Num Lock, Caps Lock и
Scroll Lock, – а последовательный порт может передавать данные с
различной скоростью. Как правило, программы в Linux работают просто с
файлами, никак или почти никак не учитывая особенности того или иного
конкретного устройства. Если же программа должна их учитывать, она
осуществляет управление соответствующими параметрами через системный
вызов ioctl, позволяющий, например, зажечь Num Lock или изменить
громкость звука. В основном использование ioctl сводится к управлению
конфигурацией (отсюда и название – I/O ConTroL, т. е. управление
вводом-выводом).

Основной недостаток описанной схемы в том, что она плохо масштабируется:
различных устройств существует великое множество, и поскольку всякое
устройство, потенциально подключаемое к компьютеру, должно получить
номер (а многие – несколько номеров), этих самых номеров явно не
хватает. Кроме того, хотя в каталоге /dev, где традиционно хранятся
файлы устройств, представлен, разумеется, далеко не весь спектр
аппаратуры (только для SCSI-устройств потребовалось бы завести не одну
тысячу файлов), он все-таки обычно содержит более тысячи файлов, и лишь
очень малая их часть соответствует устройствам (или псевдоустройствам),
реально присутствующим в системе.

Эта проблема была осознана достаточно давно, и уже предложено несколько
вариантов ее решения. Однако самым распространенным остается пока
стандартный подход, когда все файлы устройств создаются вручную
программой mknod. Мне представляется наиболее удачным вариант с
использованием специальной файловой системы devfs, монтируемой в каталог
/dev, в которой специальные файлы устройств создаются и уничтожаются
автоматически по мере надобности.

Именованные каналы

Канал – это простейшее, но очень удобное и широко применяемое средство
обмена информацией между процессами. Все, что один процесс помещает в
канал (буквально – в “трубу”), другой может оттуда прочитать. Если два
процесса, обменивающиеся информацией, порождены одним и тем же
родительским процессом (а так чаще всего и происходит), канал может быть
неименованным. В противном случае требуется создать именованный канал,
что можно сделать с помощью программы mkfifo. При этом собственно файл
именованного канала участвует только в инициации обмена данными.

Гнезда

Вообще гнезда (и взаимодействие программ при помощи гнезд) играют очень
важную роль во всех Unix-системах, включая и Linux: они являются
ключевым понятием TCP/IP и соответственно на них целиком строится
Internet. Однако c точки зрения файловой системы гнезда практически
неотличимы от именованных каналов: это просто метки, позволяющие связать
несколько программ. После того как связь установлена, общение программ
происходит без участия файла гнезда: данные передаются ядром ОС
непосредственно от одной программы к другой HYPERLINK
“http://www.citforum.nnov.ru/operating_systems/articles/” \l “1” *.

Символические ссылки

Символическая ссылка – относительно новое понятие в Unix. Это особый
файл с информацией о том, что требуемый файл в действительности
находится в другом месте, и о том, где именно его искать. Например, файл
/usr/bin/gzip представляет собой символическую ссылку, указывающую на
файл /bin/gzip; благодаря ей можно использовать /bin/gzip, обращаясь к
нему как к /usr/bin/gzip. Близким аналогом символических ссылок являются
ярлыки Windows 9X и NT 4.0, но ярлыки интерпретируются Проводником
Windows, а символические ссылки – непосредственно ядром ОС.

В отличие от обычной, или, как еще говорят во избежание путаницы,
жесткой ссылки, символическая ссылка может указывать на файл из другой
файловой системы (например, находящийся на другом диске). Замечу, что
при создании жесткой ссылки мы получаем два равноправных объекта (при
удалении файла /usr/bin/unzip файл /usr/bin/zipinfo будет работать
по-прежнему), а вот символическая ссылка при удалении (или
переименовании/перемещении) объекта, на который она указывает,
“провисает” и становится неработоспособной.

Во второй части я рассмотрю права доступа к файлам и работу Linux с
другими файловыми системами.

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

Монтирование.

Как уже было сказано, монтирование файловых систем выполняется командой
mount, а их размонтирование – командой umount. Исключение составляет
корневая файловая система HYPERLINK
“http://www.citforum.nnov.ru/operating_systems/articles/” \l “2” * ,
которая обслуживается отдельно и до всех остальных систем.
Действительно, только при ее наличии становятся доступными и сама
команда mount, и каталог /dev, где находятся файлы устройств, и
подкаталоги для монтирования. Чтобы файловые системы можно было
монтировать при запуске ОС и размонтировать при ее остановке,
используются два файла, которые традиционно размещаются в подкаталоге
/etc: /etc/fstab и /etc/mtab.

Файл /etc/fstab содержит список файловых систем, которые могут быть
смонтированы. Конечно, необходимые параметры всегда можно указать при
вызове команды mount, но гораздо удобнее, когда они извлекаются из
файла.

Каждой точке монтирования в нем соответствует одна строка, состоящая из
шести полей: название устройства, на котором расположена файловая
система, точка монтирования, тип файловой системы, параметры
монтирования, “уровень дампа” и порядковый номер файловой системы для
программы fsck. Рассмотрим эти поля по порядку.

Название устройства

Чаще всего в этом поле задается имя блочного устройства, на котором
размещена файловая система, но так бывает не всегда: для файловой
системы procfs, дающей доступ к внутренним структурам ядра, здесь может
находиться любой текст (в примере – слово none), для сетевой файловой
системы указывается имя сервера и подкаталога на нем и т.д. Даже для
обычных файловых систем данное поле иногда содержит нечто отличное от
имени устройства: скажем, в трех последних строках моего файла
/etc/fstab это имена файлов с образами дисков CD-ROM. Кроме того,
разрешается указать вместо имени устройства метку диска или его серийный
номер.

Эта возможность редко применяется на машинах с обычной конфигурацией
аппаратуры, но очень полезна в случае, когда к компьютеру подключены
десятки дисков через ряд SCSI-контроллеров или интерфейс Firewire, либо
когда на нем происходит работа со множеством сменных накопителей и
имеется несколько устройств для их чтения.

Точка монтирования

Поле со вполне, казалось бы, очевидным значением, но пара маленьких
подвохов все-таки имеется. Во-первых, при автоматическом монтировании
файловые системы монтируются в том порядке, в каком они перечислены в
/etc/fstab, и если, например, файловая система /home у вас находится на
отдельном диске, а /home/ftp – еще на одном диске, то строка с описанием
/home должна стоять в /etc/fstab до строки с описанием /home/ftp.
Во-вторых, для раздела (или файла) подкачки данное поле никак не
используется, и его содержимое может быть любым – лишь бы оно вообще
присутствовало (этого требует формат файла).

Тип файловой системы

Уж здесь-то какие могут быть подвохи? Их и нет. Почти. Можно задать в
этом поле значение auto, и тогда команда mount попытается сама
определить тип файловой системы. Это не так уж замечательно, как может
показаться: тип файловой системы определяется путем проверки так
называемого “магического числа”, которая срабатывает далеко не всегда, а
кроме того, перебираются только файловые системы, которые поддерживаются
ядром в данный момент (они перечислены в файле /proc/filesystems). Иначе
говоря, если у вас имеется дискета с файловой системой minix, а ни
одного раздела с этой системой не смонтировано, то при явном задании
типа в память будет загружен модуль с файловой системой minix и дискета
смонтируется, а при указании типа auto этого, скорее всего, не
произойдет и смонтировать дискету не удастся.

Параметры монтирования

Это поле обладает одной весьма неприятной особенностью: часть задаваемых
в нем параметров интерпретируется командой mount, а часть – ядром
системы. Параметры, интерпретируемые ядром, различны в зависимости от
файловой системы и версии ядра, а команда mount интерпретирует следующие
параметры:

async – весь ввод-вывод осуществляется асинхронно;

atime – изменять параметр “время доступа” при обращении к файлам (по
умолчанию);

auto – система может быть смонтирована при автоматическом монтировании;

defaults – установки по умолчанию: rw + suid + dev + exec + auto +
nouser + async;

dev – система может содержать файлы блочных и символьных устройств;

exec – она может содержать исполняемые файлы;

loop – для размещения системы можно использовать обычный файл
(стандартно файловые системы размещаются на устройствах, к каковым
обычные файлы не относятся, но если указать параметр loop, программа
mount находит свободное loop-устройство, “связывает” с ним с помощью
программы losetup заданный файл и передает имя этого устройства
системному вызову mount; именно так монтируются образы CD-ROM в трех
последних строках моего файла fstab);

noatime, noauto, nodev, noexec, nosuid, nouser – параметры,
противоположные по значению соответствующим параметрам без “no-“;

remount – повторно смонтировать уже смонтированную файловую систему
(например, чтобы сменить параметры монтирования);

ro – смонтировать файловую систему только для чтения;

rw – смонтировать файловую систему для чтения и записи (установка по
умолчанию);

suid – разрешить интерпретацию битов SUID и SGID (подробнее мы
рассмотрим их в разделе, посвященном правам доступа);

sync – весь ввод-вывод осуществляется синхронно;

user – обычный пользователь (не суперпользователь) наделяется правом
монтировать и размонтировать данную файловую систему; этот параметр
влечет за собой noexec, nosuid и nodev, если после него явно не указано
exec, dev или suid.

“Уровень дампа”

Это поле – самое мистическое в /etc/fstab. Оно используется программой
dump, предназначенной для создания резервных копий. Если файловая
система должна участвовать в процессе резервного копирования, то здесь
должно стоять число 1, если нет – 0 (в действительности возможны и
другие значения, но чтобы объяснить их смысл, пришлось бы вникать в
тонкости работы программы dump).

Порядковый номер файловой системы для программы fsck

Перед автоматическим монтированием во время загрузки ОС файловая система
тестируется программой fsck, которая проверяет ее целостность и, если
необходимо, исправляет простейшие ошибки. Чтобы ускорить этот процесс,
можно запустить fsck параллельно для нескольких файловых систем. Однако
параллельно обрабатываемые системы должны находиться на разных дисках,
иначе вместо ускорения обработки мы получим замедление, ибо диск будет
непрерывно получать запросы на чтение разных его участков. Значение,
установленное в данном поле, позволяет влиять на последовательность
проверки: если присвоить файловым системам одинаковые номера, они будут
проверяться одновременно. Системы, для которых этот параметр установлен
в 0, не проверяются вообще. Для корневой файловой системы его значение
несущественно.

Если в файле /etc/fstab имеется строка, относящаяся к данной файловой
системе, то при вызове для нее программы mount можно опустить параметры
монтирования, название устройства или точку монтирования. Этот файл
используется также в графических оболочках, таких как KDE, где
монтирование файловой системы сводится к щелчку мышью.

Программа amd и особая файловая система autofs позволяют сделать так,
чтобы файловая система автоматически монтировалась при “заходе” в
специальный каталог и размонтировалась через некоторое время после того,
как последняя программа перестанет использовать файлы из нее. Однако это
достаточно рискованно при работе с обычными дисководами гибких дисков:
если по ошибке вынуть дискету из дисковода в тот момент, когда она
смонтирована, можно серъезно разрушить файловую систему на ней.

В файле /etc/mtab хранится информация о том, какие файловые системы
сейчас смонтированы и с какими параметрами монтирования это было
сделано. Данные о смонтированных файловых системах содержатся также в
файле /proc/mounts (и там они точнее, поскольку отображают
соответствующую внутреннюю таблицу ядра), но параметров, с которыми эти
системы были смонтированы, в нем нет, поскольку они в ядре не хранятся
(а те из них, которые интерпретируются программой mount, вообще не
доходят до ядра), поэтому /etc/mtab также находит применение.

Права доступа

Теперь, когда мы выяснили, какие объекты встречаются в файловой системе,
полезно вспомнить, что Linux, подобно другим Unix-системам, является
многопользовательской ОС, а значит, доступ к файлам должен
ограничиваться.

Пользователи и группы

Стандартная система прав доступа в Linux, пришедшая все из тех же
далеких 70-х, весьма проста и логична, хотя и не всегда удобна
HYPERLINK “http://www.osp.ru/pcworld/2000/03/” \l “1” * . Ее базовые
понятия — пользователь и группа. Каждый зарегистрированный в системе
пользователь получает уникальный номер-идентификатор. Кроме того, он
должен входить хотя бы в одну группу, которая является для него
«главной», и может входить в другие — «дополнительные» (supplementary
groups). Все группы также перенумерованы. Файл всегда связан с
определенным пользователем — своим владельцем — и с определенной
группой, т. е. у него есть UID (User ID, идентификатор пользователя) и
GID (Group ID, идентификатор группы). Изменять права доступа к файлу
разрешено только его владельцу. Изменить владельца файла может
суперпользователь, группу — суперпользователь или владелец файла.

Программа, выполняющаяся в системе, всегда запускается от имени
какого-то пользователя и какой-то группы (обычно — основной группы этого
пользователя), но связь процессов с пользователями и группами
организована сложнее: здесь различаются идентификатор для доступа к
файловой системе (FSUID — File System access User ID, FSGID — File
System access Group ID) и эффективный идентификатор (EUID — Effective
User ID, EGID — Effective Group ID), а при доступе к файлам учитываются
еще и полномочия (capabilities), присвоенные самому процессу.
Соответствующие механизмы мы разберем, когда будем рассматривать
управление процессами.

При создании файл получает UID, совпадающий с FSUID процесса, который
его создает, и, как правило, GID, совпадающий с FSGID этого процесса; об
исключении будет сказано чуть ниже.

Атрибуты доступа

Права доступа приписываются узлу файла. Каждому файлу сопоставлены три
набора атрибутов доступа: для владельца, для группы и для всех
остальных.

Атрибуты определяют, что разрешено делать с данным файлом данной
категории пользователей. Каков же набор возможных операций в Linux (и —
шире — в Unix)? Оказывается, их всего три: чтение, запись и выполнение.
Как же, спросите вы, быть, например, с созданием и удалением файлов? И
как можно выполнить каталог?

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

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

Помимо трех названных основных атрибутов доступа существуют
дополнительные, используемые в особых случаях. Наиболее важные из них —
SUID, SGID и SVTX.

Атрибуты SUID и SGID существенны при запуске программы на выполнение:
они требуют, чтобы программа выполнялась не от имени запустившего ее
пользователя (группы), а от имени владельца (группы) того файла, в
котором она находится. Выражаясь более формально, если файл программы
имеет атрибут SUID (SGID), то FSUID и EUID (FSGID и EGID)
соответствующего процесса не наследуются от процесса, запустившего его,
а совпадают с UID (GID) файла. Благодаря этому «рядовые» пользователи
получают, например, возможность запустить системную программу, которая
создает свои рабочие файлы в закрытых для них каталогах.

Кроме того, если процесс создает файл в каталоге, имеющем атрибут SGID,
то файл получает GID не по FSGID процесса, а по GID каталога. Это удобно
для коллективной работы: все файлы и подкаталоги в каталоге
автоматически оказываются принадлежащими одной и той же группе, хотя
создавать их могут разные пользователи.

Атрибут SVTX (называемый также sticky bit, т. е. бит-липучка) в эпоху
молодости Unix определял, нужно ли выгружать программу из памяти по
окончании ее выполнения, однако сейчас от ручного управления выгрузкой
отказались. Зато SVTX приобрел новое значение применительно к каталогам:
из каталога, имеющего этот атрибут, ссылку на файл может удалить только
владелец файла. SVTX применяется в первую очередь в каталоге /tmp, где
хранятся временные файлы: создать там файл может любой пользователь
системы, а удалить — только тот, кто его создал (и, разумеется,
суперпользователь).

Запись прав доступа

Существуют две стандартных формы записи прав доступа — символьная и
восьмеричная. Символьная представляет собой цепочку из десяти знаков,
первый из которых не относится собственно к правам, а обозначает тип
файла (‘-’ — обычный файл, ‘d’ — каталог, ‘c’ — символьное устройство,
‘b’ — блочное устройство, ‘p’ — именованный канал, ‘s’ — «гнездо», ‘l’ —
символическая ссылка). Далее следуют три последовательности, каждая из
трех символов, соответствующие правам пользователя, группы и всех
остальных. Наличие права на чтение обозначается буквой ‘r’, на запись —
‘w’ на выполнение — ‘x’, отсутствие какого-либо права — знаком ‘-’ в
соответствующей позиции. Наличие атрибута SUID (SGID) обозначается
буквой ‘S’ в позиции права на выполнение для владельца (группы), если
выполнение не разрешено, и буквой ‘s’, если разрешено. SVTX записывается
соответственно буквой ‘T’ или ‘t’ в позиции права на выполнение для
«посторонней публики».

Восьмеричная запись — шестизначное число, первые два знака которого
обозначают тип файла и довольно часто опускаются, третий — атрибуты GUID
(4), SGID (2) и SVTX (1), а оставшиеся три — соответственно права
владельца, группы и всех остальных: чтение — 4, запись — 2, выполнение —
1.

Например, стандартный набор прав доступа для каталога /tmp в символьной
форме выглядит как drwxrwxrwt, а в восьмеричной как 041777 (это каталог;
чтение, запись и поиск разрешены всем; установлен атрибут SVTX). А набор
прав -r-S—xw—, или 102412, будет означать, что это обычный файл,
владельцу разрешается читать его, но не выполнять и не изменять,
пользователям из группы файла (за исключением владельца) — выполнять
(причем во время работы программа получит права владельца файла), но не
читать и не изменять, а всем остальным — изменять, но не читать и не
выполнять. Пример, конечно, условный: трудно вообразить себе ситуацию, в
которой действительно потребовалось бы назначить файлу подобные права
доступа.

А вот несколько более реалистичный пример. Вообразим себе, что среди
пользователей некой машины имеется группа «писателей», которые сочиняют
коллективную монографию, и группа «читателей», которые по ходу написания
читают ее и высказывают свои замечания. Пользователям, не входящим ни в
одну из этих групп, материалы должны быть недоступны. На первый взгляд
кажется, что здесь мы натыкаемся на ограниченность системы прав Linux: у
файла (или каталога) может быть только один GID.

Однако выход достаточно прост: если сформировать группы так, чтобы
список «писателей» был включен в список группы «читателей» , то нужного
результата можно добиться с помощью иерархии из двух каталогов:

d—-r-x—- /readers UID=0,

GID=

d—-rwsr-x /readers/writers

UID=0, GID=

Все файлы размещаются в каталоге /readers/writers. Модифицировать их
разрешено «писателям», а читать всем, но реально добраться до этого
каталога смогут только те, у кого есть право на выполнение каталога
/readers, т. е. «читатели».

Большинство программ создают файлы с разрешением на чтение и запись для
всех пользователей, а каталоги — с разрешением на чтение, запись и поиск
для всех пользователей. Этот исходный набор атрибутов логически
складывается с «пользовательской маской» — user file-creation mask,
сокращенно umask, которая обычно ограничивает доступ. Так, для
описанного только что примера значение umask должно быть
u=rwx,g=rwx,o=rx, т. е. у владельца и группы остается полный набор прав,
а всем остальным запрещается запись. В восьмеричном виде оно запишется
как 002 (первый знак — ограничения для владельца, второй — для группы,
третий — для остальных, запрещение чтения — 4, записи — 2, выполнения —
1).

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

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

Об именах

Вернемся теперь к именам файлов. Как уже говорилось, они не очень важны
с точки зрения Linux и вообще Unix: например, существует функция
системной библиотеки, которая создает и сразу же «удаляет» файл со
случайным именем, после чего возвращает ссылку на него. Ставший
безымянным файл продолжает существовать до окончания использования, так
что программа получает в свое распоряжение файл, к которому нельзя
обычным образом обратиться извне. Однако с точки зрения пользователя имя
все-таки представляет собой довольно существенный параметр файла.

Какие же ограничения накладываются на имена файлов? Их немного —
поразительно немного для людей, работавших ранее с другими ОС:

имя файла не должно содержать символов ‘\0’ (символ с кодом 0) и ‘/’;

имя файла не должно быть длиннее 255 символов;

полный путь к файлу должен быть не длиннее 4096 символов.

Это все. Причем есть способ добраться и до файла, путь к которому
оказался слишком длинным; я расскажу о нем в связи с процессами.

Имена файлов считаются одинаковыми, если они совпадают побитно, т. е.
разница между большими и маленькими буквами существенна. Тем самым,
проблема поддержки разных кодировок отпадает: ядру системы неважно,
какой набор символов использовался для записи имени — Latin 1, koi8-u,
UTF-8 или Big5, лишь бы в нем не встречались два «запрещенных» символа.
Иногда это приводит к курьезам. Например, в результате загрузки с
помощью программы Minicom файла C:\WINDOWS\ COMMAND\EDIT.COM вполне
может образоваться файл с именем из 27 символов — «C:\WINDOWS\
COMMAND\EDIT.COM» (первый символ — ‘C’, второй — ‘:’, третий – ‘\\’ и т.
д).

К сожалению, допустимость имени с точки зрения ядра системы еще не
гарантирует того, что с ним смогут работать прикладные программы. Среди
последних немало даже таких, которые вообще не признают символов с
ненулевым старшим битом (а значит, «не понимают» русских букв). В этом
смысле русификация Linux является противоположностью русификации DOS: в
DOS основной проблемой было «научить» систему вводить и отображать
русские буквы (особенно в именах файлов); когда это было сделано,
большинство программ начали совершенно свободно работать с кириллицей. В
Linux же поддержка русских букв имелась в ядре системы «с самого начала»
(их ввод и вывод на системной консоли был обеспечен хотя и не «с самого
начала», но также очень и очень давно), а все необходимое для
русификации (за исключением, пожалуй, масштабируемых шрифтов) входит в
комплект любого современного дистрибутива. Однако программы зачастую
отказываются работать с русскими буквами, и их нужно либо специально
настраивать , либо обманывать с помощью «шаманских» приемов.

«Чужие» файловые системы

Поговорим теперь немного о поддерживаемых в Linux «чужих» файловых
системах. В действительности общих правил работы с ними не существует —
слишком уж они разнообразны, — поэтому я ограничусь тем, что рассмотрю
по отдельности несколько наиболее важных.

Файловые системы Unix

Начать удобнее с систем, которые нельзя считать в полном смысле слова
«чужими», поскольку они также применяются в ОС семейства Unix и
обслуживаются ядром Linux наравне со стандартной Ext2 fs. Это Minix fs
(Minix, Xenix), System V/Coherent fs (System V, Xenix) и UFS (FreeBSD,
NetBSD, OpenBSD, SunOS/Solaris, NextStep, OpenStep).

Во всех названных системах (включая, естественно, и Ext2 fs)
пользователи и группы представлены только идентификаторами (UID, GID);
фактически ядро ОС ничего не знает об их именах. Следовательно, человек,
сумевший подключить ваш диск к машине, на которой он является
суперпользователем, получит возможность читать и модифицировать любую
информацию на диске, не зная пароля суперпользователя вашей системы. (В
ряде случаев для этого достаточно быть суперпользователем одной из
установленных на машине ОС, причем не обязательно Linux — подойдет даже
Windows 95, если только злоумышленнику удастся получить из нее доступ к
вашему диску.)

Поэтому обычно не имеет смысла ограничивать права доступа к файлам на
сменных носителях информации. Чтобы защитить хранящиеся там данные,
лучше их зашифровать.. В дальнейшем поддержка шифрования, видимо, будет
встроена в ядро Linux (в связи с изменением законодательства США,
касающегося экспорта криптотехнологий, такая возможность теперь
появилась), однако неясно, произойдет ли это уже в версии 2.4.

FAT

Наиболее распространенная файловая система — это, конечно же, FAT (в
Linux она называется msdos). Множество пророков множество раз
предсказывали ей смерть, и все же ее модификации (VFAT, FAT32) до сих
пор служат основной файловой системой в Windows 9x, а для дискет даже
Windows NT не предлагает ничего другого. Оригинальная версия FAT,
сохранявшаяся практически неизменной от MS-DOS 2.0 до MS-DOS 6.22,
крайне проста: вся информация о файле хранится в каталоге, и для доступа
к ней используется имя файла, построенное по так называемой «формуле
8+3», т. е. состоящее из собственно имени длиной до 8 символов и
расширения длиной до 3 символов, разделенных точкой.

Большие и маленькие буквы в именах файлов не различаются: при всех
операциях с файлами используются большие буквы (именно это свойство
породило известные проблемы с русскими буквами в именах файлов,
продержавшиеся вплоть до появления русифицированной версии Windows 3.1).
У каждого файла хранится время последней модификации (с точностью до 2
с) и могут быть установлены атрибуты Read Only (только для чтения),
Archive (архивный), Hidden (скрытый) и System (системный).

При монтировании диска с FAT атрибут Read Only отображается в
соответствующий атрибут файловой системы Linux, остальные же
игнорируются, поскольку не имеют аналога. В результате файлы с атрибутом
Read Only получают набор прав доступа r-xr-xr-x, а все прочие —
rwxrwxrwx. Чтобы как-то еще ограничить права доступа, следует задать
среди параметров монтирования нужное значение umask, а чтобы при этом
предоставить привилегии определенным пользователям, — указать
соответствующие UID и GID. Можно также просто разрешить пользователям
самим монтировать разделы, но это не очень удобно, поскольку нельзя
смонтировать один и тот же раздел дважды.

NTFS

О работе с NTFS, к сожалению, можно сказать мало утешительного. Это
исключительно сложная и гибкая файловая система, а открытая документация
по ней практически отсутствует. Два названных свойства и определяют
границы поддержки NTFS в Linux. Обеспечивается работа с версиями вплоть
до NTFS4 (Windows NT 4.0). Версия же NTFS5 (Windows 2000 Pro) не
поддерживается, и неизвестно, когда появится ее поддержка (если появится
вообще).

Даже для тех версий, с которыми Linux работает, доступ предоставляется
только к основной секции файла: в NTFS файл может иметь произвольное
число секций, аналогичных «вилкам» (forks) MacOS (но в MacOS у каждого
файла ровно две секции — «вилка данных» и «вилка ресурсов»). А запись в
раздел NTFS возможна только в особом экспериментальном режиме, перед
включением которого рекомендуется подготовиться к восстановлению диска
после полной потери данных, — и это не просто громкое предупреждение.

Вся система прав доступа NTFS в Linux игнорируется, и доступ к файлам
регулируется так же, как для FAT. Правда, если указать параметр
posix=yes, можно будет увидеть все имена файлов — и короткие, и длинные.
Заодно это позволит увидеть файлы с именами, отличающимися только
регистром символов. Откуда они берутся? Дело в том, что в Windows NT
есть подсистема POSIX, внутри которой различаются большие и маленькие
буквы, есть возможность создавать жесткие ссылки и т. д. Она иногда
используется при переносе программ из Unix в Windows NT.

В Linux поддерживается еще много файловых систем (HFS, HPFS и др.), но
они реже встречаются на практике. Сетевые файловые системы — coda,
smbfs, nсpfs и nfs.

Ниже приведены характеристики и особенности некоторых современных
файловых систем, поддерживаемых Linux.

Таблица 1. Некоторые современные файловые системы

Название Максимальный размер файловой системы Размеры блоков
Максимальный размер файла

XFS 18 тыс. Пбайт от 512 байт до 64 Кбайт 9 тыс. Пбайт

JFS блок на 512 байт/4 Пбайт 512/1024/ 2048/4096 байт 512 Тбайт

блок на 4 Кбайт32 Пбайт 4 Пбайт

ReiserFS 4 гигаблоков До 64 Кбайт (сейчас фиксированы 4 Кбайт) 4 Гбайт

ext3fs 4 Тбайт 1 Кбайт – 4 Кбайт 2 Гбайт

Таблица 2. Особенности современных файловых систем

Метод/ Файловая система Управление свободными блоками Экстенты для
свободного пространства B-деревья для элементов каталогов B-деревья для
адресации блоков файлов Экстенты для адресации блоков файлов Данные
внутри inode (небольшие файлы) Данные симво-льных ссылок внутри inode
Элементы каталогов внутри inode (неболь-шие каталоги)

XFS B-деревья, индексированные по смещению и по размеру Да Да Да Да Да
Да Да

JFS Дерево+ Binary Buddy (1) Нет Да Да Да Нет Да До 8

ReiserFS (2) На основе битовой карты Пока не поддерживается Как
поддерево основного дерева файловой системы Внутри основного дерева
файловой системы Будет реализовано в версии 4 (3) (3) (3)

ext3fs ext3fs не является файловой системой, созданной с нуля; она
базируется на ext2fs, поэтому не поддерживает ни один из перечисленных
выше методов; ext3fs предоставляет ext2fs поддержку журналирования, в то
же время сохраняя обратную совместимость.

Примечания

JFS использует иной подход к организации дерева блоков. Структура
представляет собой дерево, где концевые узлы являются фрагментами
битовой карты, а не непрерывными областями. Binary Buddy – это метод,
используемый для управления и объединения вместе последовательных групп
свободных логических блоков с целью формирования группы большего
размера. Как уже было отмечено при обсуждении метода битовой карты,
каждый бит в карте соответствует логическому блоку на диске. Значение
бита “1” означает, что блок занят, “0” – свободен. Фрагменты битовой
карты, каждый из которых содержит 32 бита, могут быть интерпретированы
как шестнадцатеричные числа. Так, значение “FFFFFFFF” указывает, что
блоки, соответствующие битам этого фрагмента битовой карты, все заняты.
Наконец, за счет использования этого числа резервирования и другой
информации JFS создает дерево, в котором можно быстро найти группу
последовательных блоков определенного размера.

Эта файловая система базируется на B*деревьях (усовершенствованная
версия B+дерева). Основное различие сводится к тому, что каждый объект
файловой системы размещается внутри общего B*дерева. Это значит, что для
каждого каталога не создается своего дерева, но каждый каталог имеет
поддерево в основном дереве файловой системы. Такой подход предполагает,
что в ReiserFS применяются более сложные методы индексирования. Еще одно
важное отличие состоит в том, что ReiserFS не использует экстенты, хотя
в перспективе они будут поддерживаться.

ReiserFS помещает каждый объект файловой системы внутри B*дерева. Эти
объекты, каталоги, блоки файлов, атрибуты файлов, ссылки и так далее –
все поддерживаются внутри одного и того же дерева. Для получения
значения ключевого поля, необходимого для организации элементов внутри
B-дерева, используются методы хеширования. Их несомненным достоинством
является тот факт, что за счет изменения применяемого метода хеширования
можно изменить способ, каким файловая система организует элементы и их
относительное положение внутри дерева.

PAGE

PAGE 26

Нашли опечатку? Выделите и нажмите CTRL+Enter

Похожие документы
Обсуждение

Ответить

Курсовые, Дипломы, Рефераты на заказ в кратчайшие сроки
Заказать реферат!
UkrReferat.com. Всі права захищені. 2000-2020