The design of the unix operating system by Maurice J
Вид материала | Реферат |
5.7 Создание файла 5.8 Создание специальных файлов 5.9 Смена текущего и корневого каталога |
- Лекция 10. Файловые системы Unix, 116.79kb.
- Уровни рассмотрения, 314.07kb.
- Курс по операционным системам (на примере ос windows) Основан на учебном курсе Windows, 29.21kb.
- Выполнил ученик 11 «А» класса, 443.51kb.
- Ос лекция 1 (2-й семестр – временно), 101.4kb.
- Operating System, 7686.97kb.
- Unix-подобные операционные системы, характеристики, особенности, разновидности, 40.63kb.
- 1. ms sql server. Общие сведения, 66.03kb.
- Shanti ananda maurice, 89.84kb.
- Методические материалы, 3002.45kb.
пользовать вызов системной функции lseek для указания места в
файле, где будет производиться ввод-вывод, и осуществления произ-
вольного доступа к файлу. Синтаксис вызова системной функции:
position = lseek(fd,offset,reference);
где fd - дескриптор файла, идентифицирующий файл, offset - смеще-
ние в байтах, а reference указывает, является ли значение offset
смещением от начала файла, смещением от текущей позиции ввода-вы-
вода или смещением от конца файла. Возвращаемое значение,
position, является смещением в байтах до места, где будет начи-
наться следующая операция чтения или записи. Например, в програм-
ме, приведенной на Рисунке 5.10, процесс открывает файл, считыва-
ет байт, а затем вызывает функцию lseek, чтобы заменить значение
поля смещения в таблице файлов величиной, равной 1023 (с перемен-
ной reference, имеющей значение 1), и выполняет цикл. Таким обра-
зом, программа считывает каждый 1024-й байт файла. Если reference
имеет значение 0, ядро осуществляет поиск от начала файла, а если
2, ядро ведет поиск от конца файла. Функция lseek ничего не долж-
на делать, кроме операции поиска, которая позиционирует головку
чтения-записи на указанный дисковый сектор. Для того, чтобы вы-
полнить функцию lseek, ядро просто выбирает значение смещения из
таблицы файлов; в последующих вызовах функций read и write смеще-
ние из таблицы файлов используется в качестве начального смеще-
ния.
5.6 CLOSE
Процесс закрывает открытый файл, когда процессу больше не
нужно обращаться к нему. Синтаксис вызова системной функции close
(закрыть):
---------------------------------------------------------┐
│ #include
│ main(argc,argv) │
│ int argc; │
│ char *argv[]; │
│ { │
│ int fd,skval; │
│ char c; │
│ │
│ if(argc != 2) │
│ exit(); │
│ fd = open(argv[1],O_RDONLY); │
│ if (fd == -1) │
│ exit(); │
│ while ((skval = read(fd,&c,1)) == 1) │
│ { │
│ printf("char %c\n",c); │
│ skval = lseek(fd,1023L,1); │
│ printf("new seek val %d\n",skval); │
│ } │
│ } │
L---------------------------------------------------------
Рисунок 5.10. Программа, содержащая вызов системной функции
lseek
close(fd);
где fd - дескриптор открытого файла. Ядро выполняет операцию зак-
рытия, используя дескриптор файла и информацию из соответствующих
записей в таблице файлов и таблице индексов. Если счетчик ссылок
в записи таблицы файлов имеет значение, большее, чем 1, в связи с
тем, что были обращения к функциям dup или fork, то это означает,
что на запись в таблице файлов делают ссылку другие пользователь-
ские дескрипторы, что мы увидим далее; ядро уменьшает значение
счетчика и операция закрытия завершается. Если счетчик ссылок в
таблице файлов имеет значение, равное 1, ядро освобождает запись
в таблице и индекс в памяти, ранее выделенный системной функцией
open (алгоритм iput). Если другие процессы все еще ссылаются на
индекс, ядро уменьшает значение счетчика ссылок на индекс, но ос-
тавляет индекс процессам; в противном случае индекс освобождается
для переназначения, так как его счетчик ссылок содержит 0. Когда
выполнение системной функции close завершается, запись в таблице
пользовательских дескрипторов файла становится пустой. Попытки
процесса использовать данный дескриптор заканчиваются ошибкой до
тех пор, пока дескриптор не будет переназначен другому файлу в
результате выполнения другой системной функции. Когда процесс за-
вершается, ядро проверяет наличие активных пользовательских деск-
рипторов файла, принадлежавших процессу, и закрывает каждый из
них. Таким образом, ни один процесс не может оставить файл откры-
тым после своего завершения.
На Рисунке 5.11, например, показаны записи из таблиц,
приведенных на Рисунке 5.4, после того, как второй процесс закры-
вает соответствующие им файлы. Записи, соответствующие дескрипто-
рам 3 и 4 в таблице пользовательских дескрипторов файлов, пусты.
Счетчики в записях таблицы файлов теперь имеют значение 0, а сами
записи пусты. Счетчики ссылок на файлы "/etc/passwd" и "private"
в индексах также уменьшились. Индекс для файла "private" находит-
ся в списке свободных индексов, поскольку счетчик ссылок на него
равен 0, но запись о нем не пуста. Если еще какой-нибудь процесс
пользовательские дескрип-
торы файла таблица файлов таблица индексов
----------┐ -------------┐ ---------------┐
0│ │ │ │ │ │
+---------+ │ │ │ │
1│ │ │ │ │ │
+---------+ +------------+ │ │
2│ │ │ │ │ │
+---------+ │ │ │ │
3│ ----+----┐ │ │ │ │
+---------+ │ │ │ +--------------+
4│ ----+---┐│ │ │ ----->│ счет- │
+---------+ ││ │ │ │ │ чик (/etc/ │
5│ ----+--┐││ +------------+ │ --->│ 2 passwd)│
+---------+ │││ │ счет- │ │ │ +--------------+
│ │ ││L-->│ чик +--- │ │ │
│ │ ││ │ 1 │ │ │ │
│ │ ││ +------------+ │ │ │
L---------- ││ │ │ │ │ │
││ │ │ │ │ │
----------┐ ││ │ │ │ │ │
0│ │ ││ +------------+ │ │ │
+---------+ ││ │ счет- │ │ │ │
1│ │ │L--->│ чик +----│┐ │ │
+---------+ │ │ 1 │ ││ │ │
2│ │ │ +------------+ ││ │ │
+---------+ │ │ │ ││ +--------------+
3│ NULL │ │ │ │ ││ │ счет- │
+---------+ │ │ │ │L->│ чик (local)│
4│ NULL │ │ │ │ │ │ 1 │
+---------+ │ │ │ │ +--------------+
5│ │ │ │ │ │ │ │
+---------+ │ +------------+ │ │ │
│ │ │ │ счет- │ │ │ │
│ │ │ │ чик │ │ │ │
│ │ │ │ 0 │ │ │ │
L---------- │ +------------+ │ │ │
│ │ │ │ │ │
│ │ │ │ +--------------+
│ │ │ │ │ счет- │
│ +------------+ │ │ чик (private)│
│ │ счет- │ │ │ 0 │
L---->│ чик +----- +--------------+
│ 1 │ │ │
+------------+ │ │
│ │ │ │
│ │ L---------------
│ │
+------------+
│ счет- │
│ чик │
│ 0 │
L-------------
Рисунок 5.11. Таблицы после закрытия файла
обратится к файлу "private", пока индекс еще находится в списке
свободных индексов, ядро востребует индекс обратно, как показано
в разделе 4.1.2.
5.7 СОЗДАНИЕ ФАЙЛА
Системная функция open дает процессу доступ к существующему
файлу, а системная функция creat создает в системе новый файл.
Синтаксис вызова системной функции creat:
fd = creat(pathname,modes);
где переменные pathname, modes и fd имеют тот же смысл, что и в
системной функции open. Если прежде такого файла не существовало,
ядро создает новый файл с указанным именем и указанными правами
доступа к нему; если же такой файл уже существовал, ядро усекает
файл (освобождает все существующие блоки данных и устанавливает
размер файла равным 0) при наличии соответствующих прав доступа к
нему (***). На Рисунке 5.12 приведен алгоритм создания файла.
-------------------------------------------------------------┐
│ алгоритм creat │
│ входная информация: имя файла │
│ установки прав доступа к файлу │
│ выходная информация: дескриптор файла │
│ { │
│ получить индекс для данного имени файла (алгоритм namei);│
│ если (файл уже существует) │
│ { │
│ если (доступ не разрешен) │
│ { │
│ освободить индекс (алгоритм iput); │
│ возвратить (ошибку); │
│ } │
│ } │
│ в противном случае /* файл еще не существует */ │
│ { │
│ назначить свободный индекс из файловой системы (алго- │
│ ритм ialloc); │
│ создать новую точку входа в родительском каталоге: │
│ включить имя нового файла и номер вновь назначенного │
│ индекса; │
│ } │
│ выделить для индекса запись в таблице файлов, инициализи-│
│ ровать счетчик; │
│ если (файл существовал к моменту создания) │
│ освободить все блоки файла (алгоритм free); │
│ снять блокировку (с индекса); │
│ возвратить (пользовательский дескриптор файла); │
│ } │
L-------------------------------------------------------------
Рисунок 5.12. Алгоритм создания файла
Ядро проводит синтаксический анализ имени пути поиска, ис-
пользуя алгоритм namei и следуя этому алгоритму буквально, когда
речь идет о разборе имен каталогов. Однако, когда дело касается
последней компоненты имени пути поиска, а именно идентификатора
создаваемого файла, namei отмечает смещение в байтах до первой
---------------------------------------
(***) Системная функция open имеет два флага, O_CREAT (создание)
и O_TRUNC (усечение). Если процесс устанавливает в вызове
функции флаг O_CREAT и файл не существует, ядро создаст
файл. Если файл уже существует, он не будет усечен, если
только не установлен флаг O_TRUNC.
пустой позиции в каталоге и запоминает это смещение в пространс-
тве процесса. Если ядро не обнаружило в каталоге компоненту имени
пути поиска, оно в конечном счете впишет имя компоненты в только
что найденную пустую позицию. Если в каталоге нет пустых позиций,
ядро запоминает смещение до конца каталога и создает новую пози-
цию там. Оно также запоминает в пространстве процесса индекс
просматриваемого каталога и держит индекс заблокированным; ката-
лог становится по отношению к новому файлу родительским катало-
гом. Ядро не записывает пока имя нового файла в каталог, так что
в случае возникновения ошибок ядру приходится меньше переделы-
вать. Оно проверяет наличие у процесса разрешения на запись в ка-
талог. Поскольку процесс будет производить запись в каталог в ре-
зультате выполнения функции creat, наличие разрешения на запись в
каталог означает, что процессам дозволяется создавать файлы в ка-
талоге.
Предположив, что под данным именем ранее не существовало фай-
ла, ядро назначает новому файлу индекс, используя алгоритм ialloc
(раздел 4.6). Затем оно записывает имя нового файла и номер вновь
выделенного индекса в родительский каталог, а смещение в байтах
сохраняет в пространстве процесса. Впоследствии ядро освобождает
индекс родительского каталога, удерживаемый с того времени, когда
в каталоге производился поиск имени файла. Родительский каталог
теперь содержит имя нового файла и его индекс. Ядро записывает
вновь выделенный индекс на диск (алгоритм bwrite), прежде чем за-
писать на диск каталог с новым именем. Если между операциями за-
писи индекса и каталога произойдет сбой системы, в итоге окажет-
ся, что выделен индекс, на который не ссылается ни одно из имен
путей поиска в системе, однако система будет функционировать нор-
мально. Если, с другой стороны, каталог был записан раньше вновь
выделенного индекса и сбой системы произошел между ними, файловая
система будет содержать имя пути поиска, ссылающееся на неверный
индекс (более подробно об этом см. в разделе 5.16.1).
Если данный файл уже существовал до вызова функции creat, яд-
ро обнаруживает его индекс во время поиска имени файла. Старый
файл должен позволять процессу производить запись в него, чтобы
можно было создать "новый" файл с тем же самым именем, так как
ядро изменяет содержимое файла при выполнении функции creat: оно
усекает файл, освобождая все информационные блоки по алгоритму
free, так что файл будет выглядеть как вновь созданный. Тем не
менее, владелец и права доступа к файлу остаются прежними: ядро
не передает право собственности на файл владельцу процесса и иг-
норирует права доступа, указанные процессом в вызове функции. На-
конец, ядро не проверяет наличие разрешения на запись в каталог,
являющийся родительским для существующего файла, поскольку оно не
меняет содержимого каталога.
Функция creat продолжает работу, выполняя тот же алгоритм,
что и функция open. Ядро выделяет созданному файлу запись в таб-
лице файлов, чтобы процесс мог читать из файла, а также запись в
таблице пользовательских дескрипторов файла, и в конце концов
возвращает указатель на последнюю запись в виде пользовательского
дескриптора файла.
5.8 СОЗДАНИЕ СПЕЦИАЛЬНЫХ ФАЙЛОВ
Системная функция mknod создает в системе специальные файлы,
в число которых включаются поименованные каналы, файлы устройств
и каталоги. Она похожа на функцию creat в том, что ядро выделяет
для файла индекс. Синтаксис вызова системной функции mknod:
mknod(pathname,type and permissions,dev)
где pathname - имя создаваемой вершины в иерархической структуре
файловой системы, type and permissions - тип вершины (например,
каталог) и права доступа к создаваемому файлу, а dev указывает
старший и младший номера устройства для блочных и символьных спе-
циальных файлов (глава 10). На Рисунке 5.13 приведен алгоритм,
реализуемый функцией mknod при создании новой вершины.
-------------------------------------------------------------┐
│ алгоритм создания новой вершины │
│ входная информация: вершина (имя файла) │
│ тип файла │
│ права доступа │
│ старший, младший номера устройства │
│ (для блочных и символьных специальных │
│ файлов) │
│ выходная информация: отсутствует │
│ { │
│ если (новая вершина не является поименованным каналом │
│ и пользователь не является суперпользователем) │
│ возвратить (ошибку); │
│ получить индекс вершины, являющейся родительской для │
│ новой вершины (алгоритм namei); │
│ если (новая вершина уже существует) │
│ { │
│ освободить родительский индекс (алгоритм iput); │
│ возвратить (ошибку); │
│ } │
│ назначить для новой вершины свободный индекс из файловой│
│ системы (алгоритм ialloc); │
│ создать новую запись в родительском каталоге: включить │
│ имя новой вершины и номер вновь назначенного индекса; │
│ освободить индекс родительского каталога (алгоритм │
│ iput); │
│ если (новая вершина является блочным или символьным спе-│
│ циальным файлом) │
│ записать старший и младший номера в структуру индек-│
│ са; │
│ освободить индекс новой вершины (алгоритм iput); │
│ } │
L-------------------------------------------------------------
Рисунок 5.13. Алгоритм создания новой вершины
Ядро просматривает файловую систему в поисках имени файла,
который оно собирается создать. Если файл еще пока не существует,
ядро назначает ему новый индекс на диске и записывает имя нового
файла и номер индекса в родительский каталог. Оно устанавливает
значение поля типа файла в индексе, указывая, что файл является
каналом, каталогом или специальным файлом. Наконец, если файл яв-
ляется специальным файлом устройства блочного или символьного ти-
па, ядро записывает в индекс старший и младший номера устройства.
Если функция mknod создает каталог, он будет существовать по за-
вершении выполнения функции, но его содержимое будет иметь невер-
ный формат (в каталоге будут отсутствовать записи с именами "." и
".."). В упражнении 5.33 рассматриваются шаги, необходимые для
преобразования содержимого каталога в правильный формат.
-------------------------------------------------------------┐
│ алгоритм смены каталога │
│ входная информация: имя нового каталога │
│ выходная информация: отсутствует │
│ { │
│ получить индекс для каталога с новым именем (алгоритм │
│ namei); │
│ если (индекс не является индексом каталога или же про- │
│ цессу не разрешен доступ к файлу) │
│ { │
│ освободить индекс (алгоритм iput); │
│ возвратить (ошибку); │
│ } │
│ снять блокировку с индекса; │
│ освободить индекс прежнего текущего каталога (алгоритм │
│ iput); │
│ поместить новый индекс в позицию для текущего каталога │
│ в пространстве процесса; │
│ } │
L-------------------------------------------------------------
Рисунок 5.14. Алгоритм смены текущего каталога
5.9 СМЕНА ТЕКУЩЕГО И КОРНЕВОГО КАТАЛОГА
Когда система загружается впервые, нулевой процесс делает
корневой каталог файловой системы текущим на время инициализации.
Для индекса корневого каталога нулевой процесс выполняет алгоритм
iget, сохраняет этот индекс в пространстве процесса в качестве
индекса текущего каталога и снимает с индекса блокировку. Когда
с помощью функции fork создается новый процесс, он наследует те-
кущий каталог старого процесса в своем адресном пространстве, а
ядро, соответственно, увеличивает значение счетчика ссылок в ин-
дексе.
Алгоритм chdir (Рисунок 5.14) изменяет имя текущего каталога
для процесса. Синтаксис вызова системной функции chdir:
chdir(pathname);
где pathname - каталог, который становится текущим для процесса.
Ядро анализирует имя каталога, используя алгоритм namei, и прове-
ряет, является ли данный файл каталогом и имеет ли владелец про-
цесса право доступа к каталога. Ядро снимает с нового индекса
блокировку, но удерживает индекс в качестве выделенного и остав-
ляет счетчик ссылок без изменений, освобождает индекс прежнего
текущего каталога (алгоритм iput), хранящийся в пространстве
процесса, и запоминает в этом пространстве новый индекс. После
смены процессом текущего каталога алгоритм namei использует ин-
декс в качестве начального каталога при анализе всех имен путей,
которые не берут начало от корня. По окончании выполнения систем-
ной функции chdir счетчик ссылок на индекс нового каталога имеет
значение, как минимум, 1, а счетчик ссылок на индекс прежнего те-
кущего каталога может стать равным 0. В этом отношении функция
chdir похожа на функцию open, поскольку обе функции обращаются к
файлу и оставляют его индекс в качестве выделенного. Индекс, вы-
деленный во время выполнения функции chdir, освобождается только
тогда, когда процесс меняет текущий каталог еще раз или когда
процесс завершается.
Процессы обычно используют глобальный корневой каталог файло-
вой системы для всех имен путей поиска, начинающихся с "/". Ядро
хранит глобальную переменную, которая указывает на индекс гло-
бального корня, выделяемый по алгоритму iget при загрузке систе-
мы. Процессы могут менять свое представление о корневом каталоге
файловой системы с помощью системной функции chroot. Это бывает
полезно, если пользователю нужно создать модель обычной иерархи-
ческой структуры файловой системы и запустить процессы там. Син-
таксис вызова функции:
chroot(pathname);
где pathname - каталог, который впоследствии будет рассматривать-
ся ядром в качестве корневого каталога для процесса. Выполняя
функцию chroot, ядро следует тому же алгоритму, что и при смене
текущего каталога. Оно запоминает индекс нового корня в прост-
ранстве процесса, снимая с индекса блокировку по завершении вы-
полнения функции. Тем не менее, так как умолчание на корень для
ядра хранится в глобальной переменной, ядро освобождает индекс
прежнего корня не автоматически, а только после того, как оно са-
мо или процесс-предок исполнят вызов функции chroot. Новый индекс
становится логическим корнем файловой системы для процесса (и