|
Программирование >> Структура ядра и системные вызовы
6.5. Интерфейсы прикладного программирования для файлов в UNIX и в POSIX API для работы с файлами имеют ряд общих черт: Файлы идентифицируются путевыми именами. Прежде чем файлы можно будет использовать, их нужно создать. Ниже перечислены UNIX-команды и соответствующие им системные вызовы, предназначенные для создания различных типов файлов. Тип файла Команда UNIX Системный вызов UNIX и P0SIX.1 Обычные файлы Каталоги FIFO-файлы Файлы устройств Символические ссылки VI, ех и т.д. mkdir mkfifo mknod In -s open, creat mkdir, mknod mkfifo, mknod mknod symlink Прежде чем прикладные программы смогут получить доступ к файлам, последние необходимо открыть. В UNIX и POSIX. I определен API open, который может быть использован для открытия любого файла. Функция open возвращает дескриптор, который представляет собой идентификатор файла, предназначенный для использования в других системных вызовах, манипулирующих открытым файлом. Процесс может одновременно открыть максимум OPEN MAX файлов любых типов. Значение OPEN MAX и значение POSIX OPEN MAX, определенные в POSIX. 1, задаются в заголовке <limits.h>. Системные вызовы read и write могут использоваться для чтения данных из открытых файлов и записи данных в открытые файлы. Атрибуты файла можно запрашивать с помощью системного вызова stat или fstat. Атрибуты файла можно изменять посредством системных вызовов chmod, chown, и time, link. Жесткие ссылки на файл можно удалять с использованием системного вызова unlink. Для облегчения запроса атрибутов файла прикладными программами в UNIX и POSIX. 1 определен тип данных struct stat в заголовке <sys/stat.h>. Запись struct stat содержит все доступные для пользователя атрибуты любого запрашиваемого файла. Она инициализируется и возвращается функцией stat или fstat. Объявление struct stat согласно POSIX. 1 выглядит так: struct stat { dev t ino t mode t nlink t uid t gid t dev t st dev; st ino; st mode; st nlink; st uid; st gid; st rdev; off t st size; time t st atime; time t st mtime; time t St ctime; /* идентификатор файловой системы */ /* номер индексного дескриптора файла /* тип файла и флаги доступа */ /* счетчик жестких ссылок */ /* UID владельца файла */ /* GID владельца файла */ /* содержит старший и младший номера устройства*/ /* размер файла в байтах */ /* время последнего доступа */ /* время последней модификации */ /* время последнего изменения статуса Если путевое имя (или дескриптор файла) символической ссылки передается как аргумент в системный вызов stat (или fstat), то эта функция произведет разыменование ссылки и покажет атрибуты реального файла, на который указывает ссылка. Для запроса атрибутов самой символической ссылки можно использовать системный вызов Istat. Поскольку символические ссылки стандартом POSIX. 1 еще не поддерживаются, системный вызов Istat также не является для POSIX. 1 стандартным. 6.6. Поддержка файлов ядром UNIX В UNIX System V.3 ядро ведет таблицу файлов, в которой отслеживаются все открытые в системе файлы. Имеется также таблица индексных дескрипторов, содержащая копию индексных дескрипторов файлов, выбиравшихся последними. Чтобы пользователь мог выполнить команду, ядро создает определенный процесс. Процесс имеет собственную структуру данных и, в частности, содержит таблицу дескрипторов файлов. В таблице дескрипторов имеется OPEN MAX элементов, и в ней регистрируются все файлы, открытые процессом. Когда процесс вызывает функцию open с тем, чтобы открыть файл для чтения и (или) записи, ядро преобразует путевое имя в индексный дескриптор файла. Если индексный дескриптор файла не найден или если у процесса нет необходимых прав доступа к индексному дескриптору, вызов функции open завершается с кодом возврата -1, свидетельствующем об ошибке. Если индексный дескриптор файла доступен процессу, ядро продолжит организацию связи между записью в таблице дескрипторов файлов процесса (с помощью таблицы файлов ядра) и индексным дескриптором открываемого файла. Эта процедура выполняется в последовательности, описанной ниже: 1- Ядро ищет в таблице дескрипторов файлов процесса первую незадейст-вованную позицию. Если такая позиция есть, она будет использована для обращения к файлу. Номер (индекс) этой позиции будет возвращен процессу (через значение, возвращаемое функцией open) как дескриптор открытого файла. 2. Ядро просматривает таблицу файлов в своем пространстве и ищет неза-действованную позицию, которую можно использовать для обращения к файлу. Если неиспользуемая позиция найдена, происходит следующее: а) в записи таблицы дескрипторов файлов процесса делается ссылка на найденную позицию в таблице файлов; б) в записи таблицы файлов производится ссылка на ту запись таблицы индексных дескрипторов файловой системы, в которой хранится индексный дескриптор этого файла; в) в записи таблицы файлов формируется указатель текущей позиции в открытом файле. Этот указатель представляет собой смещение относительно начала файла позиции, где будет происходить следующая операция чтения или записи; г) в запись таблицы файлов заносится информация о том, в каком режиме открыт файл: только для чтения, только для записи, для чтения и записи и т.д. Режим открытия задается вызывающим процессом как аргумент функции open; д) значение счетчика ссылок в записи таблицы файлов устанавливается равным 1. Этот базовый счетчик следит за тем, сколько дескрипторов файлов из процесса обращаются к данной записи; ж) значение счетчика ссылок индексного дескриптора файла в оперативной памяти увеличивается на 1. Счетчик определяет, сколько записей таблицы файлов указывает на этот индексный дескриптор. Если условие (1) или (2) не выполнено, функция open возвратит значение -1 и ни одна запись таблицы дескрипторов файлов или таблицы файлов не будет предоставлена для нового файла. На рис. 6.2 показаны таблица дескрипторов файлов процесса, таблица файлов ядра и таблица индексных дескрипторов файловой системы после того, как процесс открыл три файла: xyz - только для чтения, abc - для чтения и записи и вновь abc - только для записи. Обратите внимание на то, что значение счетчика ссылок предоставленной записи таблицы файлов обычно равно 1, но процесс может с помощью функции dup (или dup2) сделать так, чтобы на одну запись таблицы файлой создавались ссылки из нескольких записей таблицы дескрипторов файлов. Как вариант, процесс может вызвать функцию fork и создать порожденный процесс, чтобы записи таблицы дескрипторов файлов порожденного и родительского процессов одновременно указывали на соответствующие записи таблицы файлов. Все это приводит к тому, что значение счетчика ссылок записи таблицы файлов превышает 1. Функции dup, dup2, fork и методы их использования будут объяснены более детально в главе 8. Счетчик ссылок в записи индексного дескриптора файла показывает, сколько сделано ссылок из таблицы файлов на эту запись. Если значение счетчика не равно нулю, это значит, что один или более процессов в текущий момент открывают файл для доступа. Таблица дескрипторов файлов Таблица файлов Таблица индексных дескрипторов гс = счетчик ссылок г = только для чтения rw= для чтения и записи W = только для записи гс=1 rw гс=2 гс=1 Пространство ядра гс=1 гс=2 Рис. 6.2. Структура таблиц, предназначенных для манипулирования файлами Если вызов функции open выполнен успешно, процесс может использовать возвращенный дескриптор файла для последующих обращений. В частности, когда процесс пытается читать данные из файла (или записывать их в файл), он использует дескриптор файла как первый аргумент системного вызова read (или write). Ядро будет использовать этот дескриптор файла как индекс в таблице дескрипторов файлов процесса для поиска элемента таблицы файлов, соответствующего открытому файлу. Затем ядро проверяет данные записи в таблице файлов, дабы убедиться в том, что файл открыт в соответствующем режиме, позволяющем выполнить необходимую операцию чтения или записи. Если выяснилось, что операция чтения (или записи) совместима с режимом открытия файла, ядро использует указатель из записи в таблице файлов для доступа к записи индексного дескриптора файла (хранящегося в таблице индексных дескрипторов). Кроме того, оно использует указатель позиции в файле, хранящийся в записи таблицы файлов, чтобы определить, где должно происходить чтение или запись. Наконец, ядро проверяет тип файла в записи индексного дескриптора и вызывает соответствующий драйвер для того, чтобы начать фактический обмен данными с физическим устройством. Если процесс производит системный вызов Iseek и изменяет указатель позиции в файле, задавая другое смещение для следующей операции чтения (или записи), ядро использует дескриптор файла как индекс в таблице дескрипторов файлов процесса при поиске соответствующей записи в таблице файлов. Затем ядро по записи в таблице файлов получает указатель на запись индексного дескриптора файла. Потом оно проверяет, не является ли этот файл байт-ориентированным файлом устройства, FIFO-файлом или символической ссылкой, так как такие файлы позволяют выполнять только последовательные операции чтения и записи. Если тип файла совместим с Iseek, ядро изменит указатель позиции в файле, хранящийся в записи таблицы файлов, в соответствии со значением, указанным в аргументах функции Iseek. Когда процесс вызывает функцию close, чтобы закрыть открытый файл, выполняются следующие операции: 1. Ядро отмечает соответствующую позицию в таблице дескрипторов файлов данного процесса как незадействованную. 2. Ядро уменьшает значение счетчика ссылок соответствующей записи таблицы файлов на 1. Если значение счетчика ссылок все еще отлично от О, выполняется операция, указанная в пункте 6. 3. Позиция таблицы файлов отмечается как незадействованная. 4. Значение счетчика ссылок в соответствующей записи таблицы индексных дескрипторов файла уменьшается на 1. Если значение счетчика ссылок все еще отлично от О, выполняется операция, указанная в пункте 6. 5. Если значение счетчика жестких ссылок индексного дескриптора отлично от О, ядро передает управление вызывающему процессу и возвращает код успешного выполнения. В противном случае ядро отмечает данную позицию таблицы индексных дескрипторов как незадействованную и f освобождает всю физическую память, выделенную для хранения файла на диске, поскольку все путевые имена файла какой-то процесс удалил. 6. Ядро передает управление процессу и возвращает код успешного выполнения (0). 6.7. Взаимосвязь указателей потоков С и дескрипторов файлов Указатели потоков С (FILE*) инициализируются путем вызова С-функ-ции fopen. Указатель потока более эффективен при использовании в приложениях, осуществляющих крупномасштабные операции последовательного чтения из файлов и записи в файлы, поскольку библиотечные функции С при вводе-выводе в поток производят буферизацию. С другой стороны, дескриптор файла, выделенный системным вызовом open, является более эффективным для приложений, часто выполняющих произвольную выборку данных из файлов, для осуществления которой буферизация ввода-вывода не желательна. Еще одно различие между этими функциями состоит в том, что указатели потоков поддерживаются всеми операционными системами, использующими компиляторы С и, в частности, VMS, CMS, DOS и UNIX. Дескрипторы файлов применяются только в системах, совместимых с UNIX и POSIX. 1. Таким образом, программы, использующие указатели потоков, более мобильны, чем те, которые применяют дескрипторы файлов. Для поддержки указателей потоков каждый процесс в UNIX имеет таблицу потоков фиксированного размера с OPENMAX количеством записей. Каждая запись имеет тип FILE и содержит рабочие данные для открытого файла. Данные, находящиеся в записи FILE, содержат информацию о буфере, выделенном для буферизации данных ввода-вывода, о состоянии флага ошибки ввода-вывода в файл, флаг конца файла и т.д. Функция fopen просматривает таблицу потоков вызывающего процесса, с тем чтобы найти неиспользованную позицию. Обнаруженная позиция служит для обозначения данного файла, а ее адрес (FILE*) является указателем потока. Кроме того, в UNIX функция fopen вызывает функцию open для фактического открытия файла, а запись FILE содержит дескриптор открытого файла. Дескриптор файла, связанный с указателем потока, можно извлечь с помощью макроса fileno, который объявляется в заголовке <stdio.h>: int fileno (FILE* stream pointer); Таким образом, если процесс, чтобы открыть файл, вызывает функцию fopen, то возможность обращения к этому файлу реализуется путем выделения позиций в таблице потоков процесса и таблице дескрипторов файлов процесса. Если же для открытия файла вызывается функция open, то для обозначения файла назначается только позиция таблицы дескрипторов файлов процесса. Можно, однако, преобразовать дескриптор файла в указатель потока, воспользовавшись библиотечной функцией С fdopen: FILE* fdopen (int file descriptor, char* open mode); Действие функции fdopen подобно действию функции fopen, а именно: для обозначения файла она назначает позицию в таблице потоков процесса, регистрирует значение дескриптора в этой записи и возвращает адрес записи вызывающему процессу. После вызова fdeno или вызова fdopen процесс может обращаться к файлу как через указатель потока, так и через дескриптор файла. Другие библиотечные функции С при выполнении фактических операций с системными ресурсами тоже используют API операционной системы. Далее следует
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |