Основы операционных систем
Изучение теорий операционных систем. Исследование принципов построения и особенностей проектирования современных ОС. Сущность виртуальной памяти и алгоритма синхронизации. Рассмотрение операционной и файловой системы, система управления вводом-выводом.
Рубрика | Программирование, компьютеры и кибернетика |
Вид | книга |
Язык | русский |
Дата добавления | 12.01.2010 |
Размер файла | 2,6 M |
Отправить свою хорошую работу в базу знаний просто. Используйте форму, расположенную ниже
Студенты, аспиранты, молодые ученые, использующие базу знаний в своей учебе и работе, будут вам очень благодарны.
Понятие суперблока
Мы уже коснулись содержимого заголовка раздела, когда говорили о массиве индексных узлов файловой системы. Оставшуюся часть заголовка в s5fs принято называть суперблоком. Суперблок хранит информацию, необходимую для правильного функционирования файловой системы в целом. В нем содержатся, в частности, следующие данные:
Тип файловой системы.
Флаги состояния файловой системы.
Размер логического блока в байтах (обычно кратен 512 байтам).
Размер файловой системы в логических блоках (включая сам суперблок и массив inode).
Размер массива индексных узлов (т. е. сколько файлов может быть размещено в файловой системе).
Число свободных индексных узлов (сколько файлов еще можно создать).
Число свободных блоков для размещения данных.
Часть списка свободных индексных узлов.
Часть списка свободных блоков для размещения данных.
В некоторых модификациях файловой системы s5fs последние два списка выносятся за пределы суперблока, но остаются в заголовке раздела. При первом же обращении к файловой системе суперблок обычно целиком считывается в адресное пространство ядра для ускорения последующих обращений. Поскольку количество логических блоков и индексных узлов в файловой системе может быть весьма большим, нецелесообразно хранить списки свободных блоков и узлов в суперблоке полностью. При работе с индексными узлами часть списка свободных узлов, находящаяся в суперблоке, постепенно убывает. Когда список почти исчерпан, операционная система сканирует массив индексных узлов и заново заполняет список. Часть списка свободных логических блоков, лежащая в суперблоке, содержит ссылку на продолжение списка, расположенное где-либо в блоках данных. Когда эта часть оказывается использованной, операционная система загружает на освободившееся место продолжение списка, а блок, применявшийся для его хранения, переводится в разряд свободных.
Операции над файлами и директориями
Хотя с точки зрения пользователя рассмотрение операций над файлами и директориями представляется достаточно простым и сводится к перечислению ряда системных вызовов и команд операционной системы, попытка систематического подхода к набору операций вызывает определенные затруднения. Далее речь пойдет в основном о регулярных файлах и файлах типа «директория».
В лекции (лекция 11, раздел «Организация файлов и доступ к ним») речь шла о том, что существует два основных вида файлов, различающихся по методу доступа: файлы последовательного доступа и файлы прямого доступа. Если рассматривать файлы прямого и последовательного доступа как абстрактные типы данных, то они представляются как нечто, содержащее информацию, над которой можно совершать следующие операции:
* Для последовательного доступа: чтение очередной порции данных (read), запись очередной порции данных (write) и позиционирование на начале файла (rewind).
* Для прямого доступа: чтение очередной порции данных (read), запись очередной порции данных (write) и позиционирование на требуемой части данных (seek).
Работа с объектами этих абстрактных типов подразумевает наличие еще двух необходимых операций: создание нового объекта (new) и уничтожение существующего объекта (free).
Расширение математической модели файла за счет добавления к хранимой информации атрибутов, присущих файлу (права доступа, учетные данные), влечет за собой появление еще двух операций: прочитать атрибуты (get attribute) и установить их значения (set attribute).
Наделение файлов какой-либо внутренней структурой (как у файла типа «директория») или наложение на набор файлов внешней логической структуры (объединение в ациклический направленный граф) приводит к появлению других наборов операций, составляющих интерфейс работы с файлами, которые, тем не менее, будут являться комбинациями перечисленных выше базовых операций.
Для директории, например, такой набор операций, определяемый ее внутренним строением, может выглядеть так: операции new, free, set attribute и get attribute остаются без изменений, а операции read, write и rewind (seek) заменяются более высокоуровневыми:
прочитать запись, соответствующую имени файла, -- get record;
добавить новую запись -- add record;
* удалить запись, соответствующую имени файла, -- delete record. Неполный набор операций над файлами, связанный с их логическим объединением в структуру директорий, будет выглядеть следующим образом:
Операции для работы с атрибутами файлов - get attribute, set attribute.
Операции для работы с содержимым файлов -- read, write, rewind (seek) для регулярных файлов и get record, add record, delete record для директорий.
Операция создания регулярного файла в некоторой директории (создание нового узла графа и добавление в граф нового именованного ребра, ведущего в этот узел из некоторого узла, соответствующего директории) -- create. Эту операцию можно рассматривать как суперпозицию двух операций: базовой операции new для регулярного файла и add record для соответствующей директории.
Операция создания поддиректории в некоторой директории -- make directory. Эта операция отличается от предыдущей операции create занесением в файл новой директории информации о файлах с именами «.» и «. .», т. е. по сути дела она есть суперпозиция операции create и двух операций add record.
Операция создания файла типа «связь» -- symbolic link.
Операция создания файла типа «FIFO» -- make FIFO.
Операция добавления к графу нового именованного ребра, ведущего от узла, соответствующего директории, к узлу, соответствующему любому другому типу файла, -- link. Это просто add record с некоторыми ограничениями.
Операция удаления файла, не являющегося директорией или «связью» (удаление именованного ребра из графа, ведущего к терминальной вершине с одновременным удалением этой вершины, если к ней не ведут другие именованные ребра), -- unlink.
Операция удаления файла типа «связь» (удаление именованного ребра, ведущего к узлу, соответствующему файлу типа «связь», с одновременным удалением этого узла и выходящего из него неименованного ребра, если к этому узлу не ведут другие именованные ребра), -- unlink link.
Операция рекурсивного удаления директории со всеми входящими в нее файлами и поддиректориями -- remove directory.
Операция переименования файла (ребра графа) -- rename.
Операция перемещения файла из одной директории в другую (перемещается точка выхода именованного ребра, которое ведет к узлу, соответствующему данному файлу) -- move.
Возможны и другие подобные операции.
Способ реализации файловой системы в реальной операционной системе также может добавлять новые операции. Если часть информации файловой системы или отдельного файла кэшируется в адресном пространстве ядра, то появляются операции синхронизации данных в кэше и на диске для всей системы в целом (sync) и для отдельного файла (sync file).
Естественно, что все перечисленные операции могут быть выполнены процессом только при наличии у него определенных полномочий (прав доступа и т. д.). Для выполнения операций над файлами и директориями операционная система предоставляет процессам интерфейс в виде системных вызовов, библиотечных функций и команд операционной системы. Часть этих системных вызовов, функций и команд мы рассмотрим в следующих разделах.
Системные вызовы и команды для выполнения операций над файлами и директориями
В материалах предыдущих семинаров уже говорилось о некоторых командах и системных вызовах, позволяющих выполнять операции над файлами в операционной системе UNIX.
В семинарах 1-2 рассматривался ряд команд, позволяющих изменять атрибуты файла -- chmod, chown, chgrp, команду копирования файлов и директорий -- ср, команду удаления файлов и директорий -- rm, команду переименования и перемещения файлов и директорий -- mv, команду просмотра содержимого директорий -- Is.
В материалах семинара 5, посвященного потокам ввода-вывода, рассказывалось о хранении информации о файлах внутри адресного пространства процесса с помощью таблицы открытых файлов, о понятии файлового дескриптора, о необходимости введения операций открытия и закрытия файлов (системные вызовы open () и close ()) и об операциях чтения и записи (системные вызовы read () и write ()). Мы обещали вернуться к более подробному рассмотрению затронутых вопросов в текущих семинарах. Пора выполнять обещанное. Далее в этом разделе, если не будет оговорено особо, под словом «файл» будет подразумеваться регулярный файл.
Вся информация об атрибутах файла и его расположении на физическом носителе содержится в соответствующем файлу индексном узле и, возможно, в нескольких связанных с ним логических блоках. Для того чтобы при каждой операции над файлом не считывать эту информацию с физического носителя заново, представляется логичным, считав информацию один раз при первом обращении к файлу, хранить ее в адресном пространстве процесса или в части адресного пространства ядра, характеризующей данный процесс. Именно поэтому в лекции 2 данные о файлах, используемых процессом, были отнесены к составу системного контекста процесса, содержащегося в его PC В.
С точки зрения пользовательского процесса каждый файл представляет собой линейный набор байт, снабженный указателем текущей позиции процесса в этом наборе. Все операции чтения из файла и записи в файл производятся в этом наборе с того места, на которое показывает указатель текущей позиции. По завершении операции чтения или записи указатель текущей позиции помещается после конца прочитанного или записанного участка файла. Значение этого указателя является динамической характеристикой файла для использующего его процесса и также должно храниться в РСВ.
На самом деле организация информации, описывающей открытые файлы в адресном пространстве ядра операционной системы UNIX, является более сложной.
Некоторые файлы могут использоваться одновременно несколькими процессами независимо друг от друга или совместно. Для того чтобы не хранить дублирующуюся информацию об атрибутах файлов и их расположении на внешнем носителе для каждого процесса отдельно, такие данные обычно размещаются в адресном пространстве ядра операционной системы в единственном экземпляре, а доступ к ним процессы получают только при выполнении соответствующих системных вызовов для операций над файлами.
Независимое использование одного и того же файла несколькими процессами в операционной системе UNIX предполагает возможность для каждого процесса совершать операции чтения и записи в файл по своему усмотрению. При этом для корректной работы с информацией необходимо организовывать взаимоисключения для операций ввода-вывода. Совместное использование одного и того же файла в операционной системе UNIX возможно для близко родственных процессов, т. е. процессов, один из которых является потомком другого или которые имеют общего родителя. При совместном использовании файла процессы разделяют некоторые данные, необходимые для работы с файлом, в частности, указатель текущей позиции. Операции чтения или записи, выполненные в одном процессе, изменяют значение указателя текущей позиции во всех близко родственных процессах, одновременно использующих этот файл.
Как мы видим, вся информация о файле, необходимая процессу для работы с ним, может быть разбита на три части:
данные, специфичные для этого процесса;
данные, общие для близко родственных процессов, совместно использующих файл, например, указатель текущей позиции;
данные, являющиеся общими для всех процессов, использующих файл, -- атрибуты и расположение файла.
Естественно, что для хранения этой информации применяются три различные связанные структуры данных, лежащие, как правило, в адресном пространстве ядра операционной системы, -- таблица открытых файлов процесса, системная таблица открытых файлов и таблица индексных узлов открытых файлов. Для доступа к этой информации в управляющем блоке процесса заводится таблица открытых файлов, каждый непустой элемент которой содержит ссылку на соответствующий элемент системной таблицы открытых файлов, содержащей данные, необходимые для совместного использования файла близко родственными процессами. Из системной таблицы открытых файлов мы, в свою очередь, можем по ссылке добраться до общих данных о файле, содержащихся в таблице индексных узлов открытых файлов (см. рис. 10-11.2). Только таблица открытых файлов процесса входит в состав его РСВ и, соответственно, наследуется при рождении нового процесса. Индекс элемента в этой таблице (небольшое целое неотрицательное число) или файловый дескриптор является той величиной, характеризующей файл, которой может оперировать процесс при работе на уровне пользователя. В эту же таблицу открытых файлов помещаются и ссылки на данные, описывающие другие потоки ввода-вывода, такие как pipe и FIFO (об этом уже упоминалось в семинаре 5). Как мы увидим позже (в материалах семинаров 15--16, посвященных сетевому программированию), эта же таблица будет использоваться и для размещения ссылок на структуры данных, необходимых для передачи информации от процесса к процессу по сети.
Рис. 10-11.2. Взаимосвязи между таблицами, содержащими данные об открытых файлах в системе
Системный вызов ореп (). Для выполнения большинства операций над файлами через системные вызовы пользовательский процесс обычно должен указать в качестве одного из параметров системного вызова дескриптор файла, над которым нужно совершить операцию. Поэтому, прежде чем совершать операции, мы должны поместить информацию о файле в наши таблицы файлов и определить соответствующий файловый дескриптор. Для этого, как уже говорилось в семинаре 5, применяется процедура открытия файла, осуществляемая системным вызовом open (). При открытии файла операционная система проверяет, соответствуют ли права, которые запросил процесс для операций над файлом, правам доступа, установленным для этого файла. В случае соответствия она помещает необходимую информацию в системную таблицу файлов и, если этот файл не был ранее открыт другим процессом, в таблицу индексных дескрипторов открытых файлов. Далее операционная система находит пустой элемент в таблице открытых файлов процесса, устанавливает необходимую связь между всеми тремя таблицами и возвращает на пользовательский уровень дескриптор этого файла.
По сути дела, с помощью операции открытия файла операционная система осуществляет отображение из пространства имен файлов в дисковое пространство файловой системы, подготавливая почву для выполнения других операций.
Системный вызов close (). Обратным системным вызовом по отношению к системному вызову open () является системный вызов close (), с которым мы уже познакомились. После завершения работы с файлом процесс освобождает выделенные ресурсы операционной системы и, возможно, синхронизирует информацию о файле, содержащуюся в таблице индексных узлов открытых файлов, с информацией на диске, используя этот системный вызов. Надо отметить, что место в таблице индексных узлов открытых файлов не освобождается по системному вызову close () до тех пор, пока в системе существует хотя бы один процесс, использующий этот файл. Для обеспечения такого поведения в ней для каждого индексного узла заводится счетчик числа открытий, увеличивающийся на 1 при каждом системном вызове ореп() для данного файла и уменьшающийся на 1 при каждом его закрытии. Очищение элемента таблицы индексных узлов открытых файлов с окончательной синхронизацией данных в памяти и на диске происходит только в том случае, если при очередном закрытии файла этот счетчик становится равным 0.
Поведение таблицы открытых файлов процесса и связанных с ней таблиц при системных вызовах exit (), exec () и fork () рассматривалось в материалах семинара 5.
Операция создания файла. Системный вызов creat (). При обсуждении системного вызова open () подробно рассказывалось о его использовании для создания нового файла. Для этих же целей можно использовать системный вызов creat (), являющийся, по существу, урезанным вариантом вызова open () (о значении флага 0_TRUNC для системного вызова open () будет сказано чуть ниже).
Системный вызов creat() Прототип системного вызова
#include <fcntl.h>
int creatichar *path, int mode);
Описание системного вызова
Системный вызов creat эквивалентен системному вызову open () с параметром flags, установленным в значение 0_CREAT I 0_WR0NLY I 0_TRUNC.
Параметр path является указателем на строку, содержащую полное или относительное имя файла.
Если файла с указанным именем не существовало к моменту системного вызова, он будет создан и открыт только для выполнения операций записи. Если файл уже существовал, то он открывается также только для операции записи, при этом его длина уменьшается до 0 с одновременным сохранением всех других атрибутов файла.
Параметр mode устанавливает атрибуты прав доступа различных категорий пользователей к новому файлу при его создании. Этот параметр задается как сумма следующих восьмеричных значений:
0400 - разрешено чтение для пользователя, создавшего файл;
0200 - разрешена запись для пользователя, создавшего файл;
0100 - разрешено исполнение для пользователя, создавшего файл;
0040 - разрешено чтение для группы пользователя, создавшего файл;
0020 - разрешена запись для группы пользователя, создавшего файл;
0010 - разрешено исполнение для группы пользователя, создавшего файл;
0004 - разрешено чтение для всех остальных пользователей;
0002 - разрешена запись для всех остальных пользователей;
0001 - разрешено исполнение для всех остальных пользователей.
При создании файла реально устанавливаемые права доступа получаются из стандартной комбинации параметра mode и маски создания файлов текущего процесса umask, а именно -они равны mode & ~ umask.
Возвращаемое значение
Системный вызов возвращает значение файлового дескриптора для открытого файла при нормальном завершении и значение -1 при возникновении ошибки.
Операция чтения атрибутов файла. Системные вызовы stat (), fstat() и 1вь.^(). Для чтения всех атрибутов файла в специальную структуру могут применяться системные вызовы stat(), fstat() и lstat (). Разъяснение понятий жесткой и мягкой (символической) связи, встречающихся в описании системных вызовов, будет дано позже при рассмотрении операций связывания файлов.
Системные вызовы для чтения атрибутов файла
Прототипы системных вызовов
#include <sys/stat.h> #include <unistd.h>
int stat(char *filename, struct stat *buf);
int fstat(int fd, struct stat *buf);
int lstatjchar *filename, struct stat *buf);
Описание системных вызовов
Настоящее описание не является полным описанием этих системных вызовов, а приспособлено для целей данного курса. Для получения полного описания обращайтесь в UNIX Manual.
Системные вызовы stat, f stat и lstat служат для получения информации об атрибутах файла.
Системный вызов stat читает информацию об атрибутах файла, на имя которого указывает параметр filename, и заполняет ими структуру, расположенную по адресу buf. Заметим, что имя файла должно быть полным, либо должно строиться относительно той директории, которая является текущей для процесса, совершившего вызов. Если имя файла относится к файлу типа «связь», то читается информация (рекурсивно!) об атрибутах файла, на который указывает символическая связь.
Системный вызов lstat идентичен системному вызову stat за одним исключением: если имя файла относится к файлу типа «связь», то читается информация о самом файле типа «связь».
Системный вызов fstat идентичен системному вызову stat, только файл задается не именем, а своим файловым дескриптором (естественно, файл к этому моменту должен быть открыт).
Для системных вызовов stat и lstat процессу не нужны никакие права доступа к указанному файлу, но могут понадобиться права для поиска во всех директориях, входящих в специфицированное имя файла.
Структура stat в различных версиях UNIX может быть описана по-разному. В Linux она содержит следующие поля:
struct stat {
dev_t st_dev; /* устройство, на котором расположен файл */
ino_t st_ino; /* номер индексного узла для файла */
mode_t st_mode; /* тип файла и права доступа к нему */
nlink_t st_nlink; /* счетчик числа жестких связей */
uid_t st_uid; /* идентификатор пользователя владельца */
gid_t st_gid; /* идентификатор группы владельца */
dev_t st_rdev; /* тип устройства для специальных файлов устройств */
off_t st_size; /* размер файла в байтах (если определен для данного
типа файлов) */
unsigbed long st_blksize; /* размер блока для файловой системы */
unsigned long st_blocks; /* число выделенных блоков */
time_t st_atime; /* время последнего доступа к файлу */
time_t st_mtime; /* время последней модификации файла */
time_t st_ctime; /* время создания файла */
}
Для определения типа файла можно использовать следующие логические макросы, применяя их к значению поля st_mode:
S_ISLNK (m) - файл типа «связь»? S_ISREG (m) - регулярный файл? S_ISDIR (m) - директория?
S_ISCHR (m) - специальный файл символьного устройства? S_ISBLK (m) - специальный файл блочного устройства? S_ISFIF0 (m) - файл типа FIFO? S_ISS0CK (m) - файл типа «socket»?
Младшие 9 бит поля s t_mode определяют права доступа к файлу подобно тому, как это делается в маске создания файлов текущего процесса.
Возвращаемое значение
Системные вызовы возвращают значение 0 при нормальном завершении и значение -1 при возникновении ошибки.
Операции изменения атрибутов файла. Большинство операций изменения атрибутов файла обычно выполняется пользователем в интерактивном режиме с помощью команд операционной системы. О них уже шла речь в материалах семинаров 1--2, и мы не будем возвращаться к ним вновь. Отметим только операцию изменения размеров файла, а точнее операцию его обрезания, без изменения всех других атрибутов, кроме, быть может, времени последнего доступа к файлу и его последней модификации. Для того чтобы уменьшить размеры существующего файла до О, не затрагивая остальных его характеристик (прав доступа, даты создания, учетной информации и т. д.), можно при открытии файла использовать в комбинации флагов системного вызова open () флаг 0_TRUNC. Для изменения размеров файла до любой желаемой величины (даже для его увеличения во многих вариантах UNIX, хотя изначально этого не предусматривалось!) может использоваться системный вызов f truncate (). При этом, если размер файла мы уменьшаем, то вся информация в конце файла, не влезающая в новый размер, будет потеряна. Если же размер файла мы увеличиваем, то это будет выглядеть так, как будто мы дополнили его до недостающего размера нулевыми байтами.
Системный вызов ftruncate() Прототип системного вызова
((include <sys/types.h>
#include <unistd.h>
int ftruncate(int fd, size_t length);
Описание системного вызова
Системный вызов f truncate предназначен для изменения длины открытого регулярного файла.
Параметр fd является дескриптором соответствующего файла, т. е. значением, которое вернул системный вызов open ().
Параметр length - значение новой длины для этого файла. Если параметр length меньше, чем текущая длина файла, то вся информация в конце файла, не влезающая в новый размер, будет потеряна. Если же он' больше, чем текущая длина, то файл будет выглядеть так, как будто мы дополнили его до недостающего размера нулевыми байтами.
Возвращаемое значение
Системный вызов возвращает значение 0 при нормальном завершении и значение -1 при возникновении ошибки.
Операции чтения из файла и записи в файл. Для операций чтения из файла и записи в файл применяются системные вызовы read() и write (), которые мы уже обсуждали ранее (семинар 5, раздел «Системные вызовы read ( ), write ( ), close ( ) »).
Надо отметить, что их поведение при работе с файлами имеет определенные особенности, связанные с понятием указателя текущей позиции в файле.
При работе с файлами информация записывается в файл или читается из него, начиная с места, определяемого указателем текущей позиции в файле. Значение указателя увеличивается на количество реально прочитанных или записанных байт. При чтении информации из файла она не пропадает из него. Если системный вызов read возвращает значение 0, то это означает, что достигнут конец файла.
Операция изменения указателя текущей позиции. Системный вызов lseek (). С точки зрения процесса все регулярные файлы являются файлами прямого доступа. В любой момент процесс может изменить положение указателя текущей позиции в открытом файле с помощью системного вызова lseek ().
Особенностью этого системного вызова является возможность помещения указателя текущей позиции в файле за конец файла (т. е. возможность установления значения указателя большего, чем длина файла).
При любой последующей операции записи в таком положении указателя файл будет выглядеть так, как будто возникший промежуток от конца файла до текущей позиции, где начинается запись, был заполнен нулевыми байтами. Если операции записи в таком положении указателя не производится, то никакого изменения файла, связанного с необычным значением указателя, не произойдет (например, операция чтения будет возвращать нулевое значение для количества прочитанных байтов).
Системный вызов lseek() Прототип системного вызова
#include <sys/types.h> #include <unistd.h>
off_t lseekfint fd, off_t offset, int whence); Описание системного вызова
Системный вызов lseek предназначен для изменения положения указателя текущей позиции в открытом регулярном файле.
Параметр fd является дескриптором соответствующего файла, т. е. значением, которое вернул системный вызов open ().
Параметр offset совместно с параметром whence определяют новое положение указателя текущей позиции следующим образом:
Если значение параметра whence равно SEEKSET, то новое значение указателя будет составлять offset байт от начала файла. Естественно, что значение offset в этом случае должно быть не отрицательным.
значение параметра whence равно SEEK_CUR, то новое значение указателя будет составлять старое значение указателя + offset байт. При этом новое значение указателя не должно стать отрицательным.
Если значение параметра whence равно SEEK_END, то новое значение указателя будет составлять длина файла + offset байт. При этом новое значение указателя не должно стать отрицательным.
Системный вызов lseek позволяет выставить текущее значение указателя за конец файла (т. е. сделать его превышающим размер файла). При любой последующей операции записи в этом положении указателя файл будет выглядеть так, как будто возникший промежуток был заполнен нулевыми битами.
Тип данных of f_t обычно является синонимом типа long.
Возвращаемое значение
Системный вызов возвращает новое положение указателя текущей позиции в байтах от начала файла при нормальном завершении и значение -1 при возникновении ошибки.
Операция добавления информации в файл. Флаг 0_APPEND. Хотя эта операция по сути дела является комбинацией двух уже рассмотренных операций, мы считаем нужным упомянуть ее особо. Если открытие файла системным вызовом open () производилось с установленным флагом 0_APPEND, то любая операция записи в файл будет всегда добавлять новые данные в конец файла, независимо от предыдущего положения указателя текущей позиции (как если бы непосредственно перед записью был выполнен вызов lseek () для установки указателя на конец файла).
Операции создания связей. Команда In, системные вызовы link() и symlink(). С операциями, позволяющими изменять логическую структуру файловой системы, такими как создание файла, мы уже сталкивались в этом разделе. Однако операции создания связи служат для проведения новых именованных ребер в уже существующей структуре без добавления новых узлов или для опосредованного проведения именованного ребра к уже существующему узлу через файл типа «связь» и неименованное ребро. Такие операции мы до сих пор не рассматривали, поэтому давайте остановимся на них подробнее.
Допустим, что несколько программистов совместно ведут работу над одним и тем же проектом. Файлы, относящиеся к этому проекту, вполне естественно могут быть выделены в отдельную директорию так, чтобы не смешиваться с файлами других пользователей и другими файлами программистов, участвующих в проекте. Для удобства каждый из разработчиков, конечно, хотел бы, чтобы эти файлы находились в его собственной директории. Этого можно было бы добиться, копируя по мере изменения новые версии соответствующих файлов из директории одного исполнителя в директорию другого исполнителя. Однако тогда, во-первых, возникнет ненужное дублирование информации на диске. Во-вторых, появится необходимость решения тяжелой задачи: синхронизации обновления замены всех копий этих файлов новыми версиями.
Существует другое решение проблемы. Достаточно разрешить файлам иметь несколько имен. Тогда одному физическому экземпляру данных на диске могут соответствовать различные имена файла, находящиеся в одной или в разных директориях. Подобная операция присвоения нового имени файлу (без уничтожения ранее существовавшего имени) получила название операции создания связи.
В операционной системе UN IX связь может быть создана двумя различными способами.
Первый способ, наиболее точно следующий описанной выше процедуре, получил название способа создания жесткой связи (hard link). С точки зрения логической структуры файловой системы этому способу соответствует проведение нового именованного ребра из узла, соответствующего некоторой директории, к узлу, соответствующему файлу любого типа, получающему дополнительное имя. Сточки зрения структур данных, описывающих строение файловой системы, в эту директорию добавляется запись, содержащая дополнительное имя файла и номер его индексного узла (уже существующий!). При таком подходе и новое имя файла, и его старое имя или имена абсолютно равноправны для операционной системы и могут взаимозаменяемо использоваться для осуществления всех операций.
Использование жестких связей приводит к возникновению двух проблем.
Первая проблема связана с операцией удаления файла. Если мы хотим удалить файл из некоторой директории, то после удаления из ее содержимого записи, соответствующей этому файлу, мы не можем освободить логические блоки, занимаемые файлом, и его индексный узел, не убедившись, что у файла нет дополнительных имен (к его индексному узлу не ведут ссылки из других директорий), иначе мы нарушим целостность файловой системы. Для решения этой проблемы файлы получают дополнительный атрибут -- счетчик жестких связей (или именованных ребер), ведущих к ним, который, как и другие атрибуты, располагается в их индексных узлах. При создании файла этот счетчик получает значение 1. При создании каждой новой жесткой связи, ведущей к файлу, он увеличивается на 1. Когда мы удаляем файл из некоторой директории, то из ее содержимого удаляется запись об этом файле, и счетчик жестких связей уменьшается на 1. Если его значение становится равным 0, происходит освобождение логических блоков и индексного узла, выделенных этому файлу.
Вторая проблема связана с опасностью превращения логической структуры файловой системы из ациклического графа в циклический и с возможной неопределенностью толкования записи с именем «. .» в содержимом директорий. Для их предотвращения во всех существующих вариантах операционной системы UNIX запрещено создание жестких связей, ведущих к уже существующим директориям (несмотря на то, что POSIX-стандарт для операционной системы UNIX разрешает подобную операцию для пользователя root). Поэтому мы и говорили о том, что в узел, соответствующий файлу типа «директория», не может вести более одного именованного ребра. (В операционной системе Linux по непонятной причине дополнительно запрещено создание жестких связей, ведущих к специальным файлам устройств.)
Команда In |
||
Синтаксис команды |
||
In [options] source |
[dest] |
|
In [options] source |
... directory |
Описание команды
Настоящее описание не является полным описанием команды In, а описывает только ее опции, используемые в данном курсе. Для получения полного описания обращайтесь к UNIX Manual.
Команда In предназначена для реализации операции создания связи в файловой системе. В нашем курсе мы будем использовать две формы этой команды.
Первая форма команды, когда в качестве параметра source задается имя только одного файла, а параметр dest отсутствует, или когда в качестве параметра dest задается имя файла, не существующего в файловой системе, создает связь к файлу, указанному в качестве параметра source, в текущей директории с его именем (если параметр dest отсутствует) или с именем dest (полным или относительным) в случае наличия параметра dest.
Вторая форма команды, когда в качестве параметра source задаются имена одного или нескольких файлов, разделенные между собой пробелами, а в качестве параметра directory задается имя уже существующей в файловой системе директории, создает связи к каждому из файлов, перечисленных в параметре source, в директории directory с именами, совпадающими с именами перечисленных файлов.
Команда 1п без опций служит для создания жестких связей (hard link), а команда In с опцией -s - для создания мягких (soft link) или символических (symbolic) связей.
Примечание: во всех существующих версиях UNIX (несмотря на стандарт P0SIX) запрещено создание жестких связей к директориям. Операционная система Linux запрещает также, по непонятным причинам, создание жестких связей к специальным файлам устройств.
Для создания жестких связей применяются команда операционной системы In без опций и системный вызов 1 ink ().
Надо отметить, что системный вызов link() является одним из немногих системных вызовов, совершающих операции над файлами, которые не требуют предварительного открытия файла, поскольку он подразумевает выполнение единичного действия только над содержимым индексного узла, выделенного связываемому файлу.
Системный вызов link() Прототип системного вызова
#include <unistd.h>
int link(char *pathname, char *linkpathname); Описание системного вызова
Системный вызов link служит для создания жесткой связи к файлу с именем, на которое указывает параметр pathname. Указатель на имя создаваемой связи задается параметром linkpathname (полное или относительное имя связи). Во всех существующих реализациях операционной системы UNIX запрещено создавать жесткие связи к директориям. В операционной системе Linux (по непонятной причине) дополнительно запрещено создавать жесткие связи к специальным файлам устройств.
Возвращаемое значение
Системный вызов возвращает значение 0 при нормальном завершении и значение -1 при возникновении ошибки.
Второй способ создания связи получил название способа создания мягкой (soft) или символической (symbolic) связи (link). В то время как жесткая связь файлов является аналогом использования прямых ссылок (указателей) в современных языках программирования, символическая связь, до некоторой степени, напоминает косвенные ссылки (указатель на указатель). При создании мягкой связи с именем symlink из некоторой директории к файлу, заданному полным или относительным именем linkpath, в этой директории действительно создается новый файл типа «связь» с именем syml ink со своими собственными индексным узлом и логическими блоками. При тщательном рассмотрении можно обнаружить, что все его содержимое составляет только символьная запись имени linkpath. Операция открытия файла типа «связь» устроена таким образом, что в действительности открывается не сам этот файл, а тот файл, чье имя содержится в нем (при необходимости рекурсивно!). Поэтому операции над файлами, требующие предварительного открытия файла (как, впрочем, и большинство команд операционной системы, совершающих действия над файлами, где операция открытия файла присутствует, но скрыта от пользователя), в реальности будут совершаться не над файлом типа «связь», а над тем файлом, имя которого содержится в нем (или над тем файлом, который, в конце концов, откроется при рекурсивных ссылках). Отсюда, в частности, следует, что попытки прочитать реальное содержимое файлов типа «связь» с помощью системного вызова read () обречены на неудачу. Как видно, создание мягкой связи, с точки зрения изменения логической структуры файловой системы, эквивалентно опосредованному проведению именованного ребра к уже существующему узлу через файл типа «связь» и неименованное ребро.
Создание символической связи не приводит к проблеме, связанной с удалением файлов. Если файл, на который ссылается мягкая связь, удаляется с физического носителя, то попытка открытия файла мягкой связи (а, следовательно, и удаленного файла) приведет к ошибке «Файла с таким именем не существует», которая может быть аккуратно обработана приложением. Таким образом, удаление связанного объекта, как упоминалось ранее, лишь отчасти и не фатально нарушит целостность файловой системы.
Неаккуратное применение символических связей пользователями операционной системы может привести к превращению логической структуры файловой системы из ациклического графа в циклический граф. Это, конечно, нежелательно, но не носит столь разрушительного характера, как циклы, которые могли бы быть созданы жесткой связью, если бы не был введен запрет на организацию жестких связей к директориям. Поскольку мягкие связи принципиально отличаются от жестких связей и связей, возникающих между директорией и файлом при его создании, мягкая связь легко может быть идентифицирована операционной системой или программой пользователя. Для предотвращения зацикливания программ, выполняющих операции над файлами, обычно ограничивается глубина рекурсии по прохождению мягких связей. Превышение этой глубины приводит к возникновению ошибки «Слишком много мягких связей», которая может быть легко обработана приложением. Поэтому ограничения на тип файлов, к которым может вести мягкая связь, в операционной системе UNIX не вводятся.
Для создания мягких связей применяются уже знакомая нам команда операционной системы In с опцией - ей системный вызов symlink (). Надо отметить, что системный вызов symlink () также не требует предварительного открытия связываемого файла, поскольку он вообще не рассматривает его содержимое.
Системный вызов symlink() Прототип системного вызова
#include <unistd.h>
int symlink(char *pathname, char *linkpathname);
Описание системного вызова
Системный вызов symlink служит для создания символической (мягкой) связи к файлу с именем, на которое указывает параметр pathname. Указатель на имя создаваемой связи задается параметром linkpathname (полное или относительное имя связи).
Никакой проверки реального существования файла с именем pathname системный вызов не производит.
Возвращаемое значение
Системный вызов возвращает значение 0 при нормальном завершении и значение -1 при возникновении ошибки.
Операция удаления связей и файлов. Системный вызов unlink (). При рассмотрении операции связывания файлов мы уже почти полностью рассмотрели, как производится операция удаления жестких связей и файлов.
При удалении мягкой связи, т. е. фактически файла типа «связь», все происходит как и для обычных файлов. Единственным изменением, с точки зрения логической структуры файловой системы, является то, что при действительном удалении узла, соответствующего файлу типа «связь», вместе с ним удаляется и выходящее из него неименованное ребро.
Дополнительно необходимо отметить, что условием реального удаления регулярного файла с диска является не только равенство 0 значения его счетчика жестких связей, но и отсутствие процессов, которые держат этот файл открытым. Если такие процессы есть, то удаление регулярного файла будет выполнено при его полном закрытии последним использующим файл процессом.
Для осуществления операции удаления жестких связей и/или файлов можно задействовать уже известную вам из семинаров 1--2 команду операционной системы rm или системный вызов unlink ().
Заметим, что системный вызов unlink () также не требует предварительного открытия удаляемого файла, поскольку после его удаления совершать над ним операции бессмысленно.
Системный вызов unlinkO Прототип системного вызова
#include <unistd.h>
int unlink(char *pathname);
Описание системного вызова
Системный вызов unlink служит для удаления имени, на которое указывает параметр pathname, из файловой системы.
Если после удаления имени счетчик числа жестких связей у данного файла стал равным О, то возможны следующие ситуации:
Если в операционной системе нет процессов, которые держат данный файл открытым, то файл полностью удаляется с физического носителя.
Если удаляемое имя было последней жесткой связью для регулярного файла, но какой-либо процесс держит его открытым, то файл продолжает существовать до тех пор, пока не будет закрыт последний файловый дескриптор, ссылающийся на данный файл.
Если имя относится к файлу типа socket, FIFO или к специальному файлу устройства, то файл удаляется независимо от наличия процессов, держащих его открытым, но процессы, открывшие данный объект, могут продолжать пользоваться им.
* Если имя относится к файлу типа «связь», то он удаляется, и мягкая связь оказывается разорванной.
Возвращаемое значение
Системный вызов возвращает значение 0 при нормальном завершении и значение -1 при возникновении ошибки.
Практическое применение команд и системных вызовов для операций над файлами
Практическое использование изученных вызовов и команд обычно проводится по усмотрению преподавателя или собственному вашему усмотрению. Создайте жесткие и символические связи из вашей директории к другим файлам. Просмотрите содержимое директорий со связями с помощью команды Is -al. Обратите внимание на отличие мягких и жестких связей в листинге этой команды. Определите допустимую глубину рекурсии символических связей для вашей операционной системы.
Специальные функции для работы с содержимым директорий
Стандартные системные вызовы open (), read () и close () не могут помочь программисту изучить содержимое файла типа «директория». Для анализа содержимого директорий используется набор функций из стандартной библиотеки языка С.
Функция opendir()
Прототип функции
ttinclude <sys/types.h>
#include <dirent.h>
DIR *opendir(char *name);
Описание функции
Функция opendir служит для открытия потока информации для директории, имя которой расположено по указателю name. Тип данных DIR представляет собой некоторую структуру данных, описывающую такой поток. Функция opendir подготавливает почву для функционирования других функций, выполняющих операции над директорией, и позиционирует поток на первой записи директории.
Возвращаемое значение
При удачном завершении функция возвращает указатель на открытый поток директории, который будет в дальнейшем передаваться в качестве параметра всем другим функциям, работающим с этой директорией. При неудачном завершении возвращается значение NULL.
С точки зрения программиста в этом интерфейсе директория представляется как файл последовательного доступа, над которым можно совершать операции чтения очередной записи и позиционирования на начале файла. Перед выполнением этих операций директорию необходимо открыть, а после окончания -- закрыть. Для открытия директории используется функция орепсИг (), которая подготавливает почву для совершения операций и позиционирует нас на начале файла. Чтение очередной записи из директории осуществляет функция геас1с11г (), одновременно позиционируя нас на начале следующей записи (если она, конечно, существует). Для операции нового позиционирования на начале директории (если вдруг понадобится) применяется функция гею±пс1-сНг (). После окончания работы с директорией ее необходимо закрыть с помощью функции СХОБесИг ().
Функция readdir()
Прототип функции
tinclude <sys/types.h>
tinclude <dirent.h>
struct dirent *readdir(DIR *dir);
Описание функции
(рункция readdir служит для чтения очередной записи из потока информации для директории.
Параметр dir представляет собой указатель на структуру, описывающую поток директории, который вернула функция opendir ().
Тип данных struct dirent представляет собой некоторую структуру данных, описывающую одну запись в директории. Поля этой записи сильно варьируются от одной файловой системы к другой, но одно из полей, которое собственно и будет нас интересовать, всегда присутствует в ней. Это поле char d_name [ ] неопределенной длины, не превышающей значения NAMEL.MAX+1, которое содержит символьное имя файла, завершающееся символом конца строки. Данные, возвращаемые функцией readdir, переписываются при очередном вызове этой функции для того же самого потока директории.
Возвращаемое значение
При удачном завершении функция возвращает указатель на структуру, содержащую очередную запись директории. При неудачном завершении или при достижении конца директории возвращается значение NULL.
Функция rewinddir()
Прототип функции
#include <sys/types.h> . #include <dirent:h> void rewinddir(DIR *dir);
Описание функции
Функция rewinddir служит для позиционирования потока информации для директории, ассоциированного с указателем dir (т. е. с тем, который вернула функция opendir ()), на первой записи (или на начале) директории.
Функция closedir()
Прототип функции
#include <sys/types.h> #include <dirent.h> int closedir(DIR *dir);
Описание функции
Функция closedir служит для закрытия потока информации для директории, ассоциированного с указателем dir (т. е. с тем, который вернула функция opendir ()). После закрытия поток директории становится недоступным для дальнейшего использования.
Возвращаемое значение
При успешном завершении функция возвращает значение 0, при неудачном завершении -значение -1.
Написание, прогон и компиляция программы, анализирующей содержимое директории
Напишите, откомпилируйте и прогоните программу, распечатывающую список файлов, входящих в директорию, с указанием их типов. Имя директории задается как параметр командной строки. Если оно отсутствует, то выбирается текущая директория.
Задача повышенной сложности: напишите программу, распечатывающую содержимое заданной директории в формате, аналогичном формату выдачи команды 1э -а1. Для этого вам дополнительно понадобится самостоятельно изучить в UNIX Manual функцию ctime (3) и системные вызовы time (2 ), readlink (2 )'. Цифры после имен функций и системных вызовов -- это номера соответствующих разделов для UNIX Manual.
Понятие о файлах, отображаемых в память (memory mapped файлах). Системные вызовы mmapO, munmap()
Как уже говорилось, с помощью системного вызова open () операционная система отображает файл из пространства имен в дисковое пространство файловой системы, подготавливая почву для осуществления других операций. С появлением концепции виртуальной памяти, которая рассматривалась в лекции 9, когда физические размеры памяти перестали играть роль сдерживающего фактора в развитии вычислительных систем, стало возможным отображать файлы непосредственно в адресное пространство процессов. Иными словами, появилась возможность работать с файлами как с обычной памятью, заменив выполнение базовых операций над ними с помощью системных вызовов на использование операций обычных языков программирования. Файлы, чье содержимое отображается непосредственно в адресное пространство процессов, получили название файлов, отображаемых в память, или, по-английски, memory mapped файлов (см. лекцию 10). Надо отметить, что такое отображение может быть осуществлено не только для всего файла в целом, но и для его части.
С точки зрения программиста работа с такими файлами выглядит следующим образом:
Подобные документы
Основные понятия об операционных системах. Виды современных операционных систем. История развития операционных систем семейства Windows. Характеристики операционных систем семейства Windows. Новые функциональные возможности операционной системы Windows 7.
курсовая работа [60,1 K], добавлен 18.02.2012Понятие виртуальной памяти, ее реализация. Особенности страничной организации по требованию. Этапы обработки ситуации отсутствия страницы в памяти. Стратегии (алгоритмы) замещения страниц. Особенности некоторых операционных систем: Windows NT и Solaris.
презентация [2,2 M], добавлен 24.01.2014Изучение особенностей операционной системы, набора программ, контролирующих работу прикладных программ и системных приложений. Описания архитектуры и программного обеспечения современных операционных систем. Достоинства языка программирования Ассемблер.
презентация [1,3 M], добавлен 22.04.2014Общая характеристика преимуществ взаимодействующих процессов: модульность, ускорение вычислений. Знакомство с основами современных операционных систем. Анализ особенностей использования общего почтового ящика, рассмотрение способов создания и удаления.
презентация [1,6 M], добавлен 24.01.2014Характеристика сущности, назначения, функций операционных систем. Отличительные черты их эволюции. Особенности алгоритмов управления ресурсами. Современные концепции и технологии проектирования операционных систем, требования, предъявляемые к ОС XXI века.
курсовая работа [36,4 K], добавлен 08.01.2011Операционная система - программа, которая загружается при включении компьютера. Способы реализации интерфейса и классификация операционных систем. Организация файловой системы, типы файлов и их наименования. Понятие каталога, атрибуты файловой системы.
реферат [16,6 K], добавлен 25.02.2011Важность операционной системы для мобильных устройств. Популярность операционных систем. Доля LINUX на рынке операционных систем. История OS Symbian, BlackBerry OS, Palm OS. Отличия смартфона от обычного мобильного телефона. Учет ограничений по памяти.
презентация [477,3 K], добавлен 01.12.2015Основные понятия операционных систем. Современное оборудование компьютера. Преимущества и недостатки операционной системы Linux. Функциональные возможности операционной системы Knoppix. Сравнительная характеристика операционных систем Linux и Knoppix.
реферат [1,5 M], добавлен 17.12.2014Основные понятия операционных систем. Синхронизация и критические области. Сигналы и взаимодействие между процессами. Управление памятью. Драйверы устройств. Особенности современных операционных систем. Центральный процессор, микросхемы часов и таймеров.
учебное пособие [1,2 M], добавлен 24.01.2014Использование операционных систем Microsoft Windows. Разработка операционной системы Windows 1.0. Возможности и характеристика последующих версий. Выпуск пользовательских операционных систем компании, доработки и нововведения, версии Windows XP и Vista.
реферат [23,3 K], добавлен 10.01.2012