|
Программирование >> Структура ядра и системные вызовы
7.1. Общие файловые API Прототип функции open выглядит так: Как разъяснялось в предьщущей главе, файлы в UNIX- и POSIX-системах могут относиться к следующим типам: обычный файл; каталог; FIFO-файл; байт-ориентированный файл устройства; блок-ориентированный файл устройства; символическая ссылка. Для создания файлов существуют специальные API, которые будут описаны в следующих разделах. Ниже представлен набор базовых API,помощью которых можно манипулировать файлами различных типов. Назначение open Открывает файл для доступа к данным read Читает данные из файла write , Записывает данные в файл - Iseei Обеспечивает произвольную выборку данных из файла close Закрывает соединение с файлом stat, fstat Запрашивает атрибуты файла chmod Изменяет права доступа к файяу chown Изменяет UID и (или) GID файла utime Изменяет дату и время последнего изменения содержимого файла и последнего доступа к нему link Создает жесткую ссылку на файл * unlink Удаляет жесткую ссылку на файл umask Устанавливает маску Далее все перечисленные общие API описываются более детально р.: Л 7.1.1. Функция open Функция open устанавливает соединение между процессом (процесс - это прикладная программа, находящаяся в стации выполнения) и файлом. С помощью этой функции можно создавать совершенно новые файлы. Любой процесс, вызвав функцию open, может получить дескриптор для обращения к вновь созданному файлу. Дескриптор файла используется в системных вызовах read и write для получения доступа к его содержимому. #include <sys/types.h> #include <fcntl.h> int open ( const char *path name, Int access mode, mode t permission ); Первый аргумент, path name,- это имя файла. Им может быть абсолютное путевое имя (символьная строка, начинающаяся символом / ) или относительное путевое имя (символьная строка, не начинающаяся символом /). Если pathjname - символическая ссылка, то рассматриваемая функция преобразует ее (рекурсивно, если символическая ссылка обращается к другой символической ссылке) в имя файла, который упоминается в данной ссылке. Второй аргумент, accessjnode - это целое значение, которое показывает, какие виды доступа к файлу разрешены вызывающему процессу. Значение accessjnode должно быть одним из макросов, определенных в заголовке <fcntl.h>. Флаг режима доступа Использование 0 RDONLY 0 WRONLY О RDWR Открывает файл только для чтения Открывает файл только для записи Открывает файл для чтения и записи Кроме того, можно задать один или несколько из перечисленных ниже модификаторов, логически складывая их поразрядно с одним из указанных выше флагов режима доступа и изменяя таким образом механизм доступа к файлу. Флаг модификатора доступа Использование 0 APPEND 0 CREAT 0 EXCL 0 TRUNC 0 NONBLO.CK 0 ЫОСТГУ Добавляет данные в конец файла Создает файл, если он не существует Используется только с флагом 0 CREAT. Если установлены флаги 0 CREAT и 0 EXCL, а указанный файл уже существует, выполнение функции open завершается неудачей Если файл существует, отбрасывает его содержимое и устанавливает размер файла равным О Указывает на то, что все последующие операции чтения из файла и записи в файл должны выполняться без блокировки Говорит о том, что указанный файл терминального устройства нельзя использовать как управляющий терминал вызывающего процесса Проиллюстрируем использование этих флагов на примере оператора, который открывает файл /usr/xyz/textbook для чтения и записи в режиме добавления: int fdesc = open ( /usr/xyz/textbook ,0 RDWR I 0 APPEND, 0 ); Если файл необходимо открыть только для чтения, он должен уже ; существовать и никакие другие флаги модификаторов использовать нельзя. : Если файл открывается только для записи или для чтения и записи, ] можно указывать любые флаги модификаторов. При этом флаги 0 АР- \ PEND, 0 TRUNC, 0 CREAT и 0 EXCL применимы только к обычным \ файлам, 0 NONBLOCK - только к FIFO-файлам и файлам устройств, а * 0 NOCTTY - только к файлам терминальных устройств. - Флаг 0 APPEND указывает на то, что данные будут добавляться в конец файла. Если этот флаг отсутствует, данные могут записываться в любое место файла. Флаг 0 TRUNC определяет, что если заданный файл уже существует, функция open должна отбросить его содержимое. Если этот флаг отсутствует, текущие данные файла функцией open не изменяются. Флаг OCREAT говорит о том, что если заданный файл не существует, функция open должна создать его. Если же заданный файл существует, этот флаг на функцию open никак не влияет. Если заданный файл не существует и файл OCREAT не указан, выполнение функции open прерывается и возвращается код неудачного завершения. Файл OEXCL, если он используется, должен сопровождаться флагом OCREAT. Если указаны оба эти флага и заданный файл существует, то попытка выполнить функцию open завершается неудачей. Таким образом, флаг 0 EXCL гарантирует, что в результате вызова функции open будет создан новый файл. Флаг 0 NONBLOCK указывает на то, что если вызов функции open и все последующие вызовы функций read и write для заданного файла заблокируют вызывающий процесс, ядро должно немедленно прервать выполнение этих функций и возвратить управление процессу с соответствующим кодом состояния. Процесс, как правило, блокируется при попытках чтения пустого канала (функция pipe описывается в разделе 7.5) и записи в заполненный канал. С помощью этого флага можно указать, что такие операции чтения и записи не являются блокирующими. В UNIX System V.3 вместо этого флага определен флаг 0 NDELAY; по своему назначению они похожи, но работают по-разному. Более подробно эти флаги описаны в разделе 7.5. Флаг 0 N0CTTY определен в стандарте POSIX.l. Он указывает на то, что если процесс не имеет управляющего терминала и открывает файл терминального устройства, то этот терминал не будет управляющим терминалом процесса. Если названный флаг не установлен, то решение вопроса о том, будет ли этот терминал управляющим терминалом процесса, зависит от реализации ОС. Отметим, что в UNIX System V.3, где флаг 0 NOCTTY не определен, вызов функции open при отсутствии у процесса управляющего Терминала автоматически назначает управляющим терминалом первый открытый файл терминального устройства. Аргумент permission необходим только в том случае, если в аргументе accessjnode установлен флаг 0 CREAT. Он задает права доступа к файлу для его владельца, членов группы и всех остальных пользователей. В UNIX System V (V.3 и ниже) этот аргумент имеет тип int и его значение обычно задается как восьмеричный целочисленный литерал, например 764. Левая, средняя и правая цифры восьмеричного числа задают права доступа соответственно для владельца, группы и прочих пользователей. В каждой восьмеричной цифре левый, средний и правый биты определяют соответственно права на чтение, запись и выполнение. Значение каждого бита может быть равно либо 1 (право доступа предоставляется), либо О (право доступа не предоставляется). Так, число 764 означает, что у владельца нового файла есть право на чтение, запись и выполнение, у членов группы - на чтение и запись, у прочих пользователей - только на чтение. Тип данных аргумента permission определяется в POSIX.l как modet, а значение его должно строиться на основании макросов, определенных в заголовке <sys/stat.h>. Эти макросы являются псевдонимами восьмеричных целых значений, используемых в UNIX System V. Например, значение 764 должно быть задано так: S IRWXU I S IRGRP I S IWGRP 1 S IROTH Значение permission, указанное в вызове функции open, модифицируется значением umask вызывающего процесса. Значение umask задает те права доступа, которые необходимо автоматически маскировать (исключать) для всех файлов, создаваемых процессом. Значение umask наследуется процессом от его родительского процесса и может запрашиваться и изменяться системным вызовом umask. Вот прототип функции umask: mode t umask ( mode t new umask ); В качестве аргумента функция umask принимает новое значение маски. С момента начала выполнения этой функции вызывающий процесс использует заданное новое значение, а функция возвращает старое. Например, следующий оператор присваивает текущее значение маски переменной old mask и устанавливает новое значение маски как отсутствие права выполнения для группы и отсутствие права записи и выполнения для прочих пользователей : mode t old mask = umask ( S IXGRP I S IWOTH I S IXOTH ); Функция open получает значение аргумента permission и логически складывает его поразрядно со значением, равным дополнению до единицы значения umask вызывающего процесса. Таким образом, для каждого вновь создаваемого файла назначается следующее разрешение на доступ: actual j>ermission = permission & ~umask value Следовательно, биты, составляющие значение umask, показывают, что у всех вновь создаваемых файлов соответствующие права доступа будут исключаться. Например, если open вызывается в UNIX System V.3 для создания файла /usr/тагу/shoMi ex с правами доступа 0557, а значение umask вызывающего процесса - 031, то для этого файла назначаются следующие виды доступа: actual permission = 0557 & (-031) = 0546 Функция open возвращает значение -1, если данный API выполнен неудачно и переменная еггпо содержит код ошибки. Если API выполнен успешно, то возвращается дескриптор файла, по которому к файлу можно обращаться в других системных вызовах. Значение дескриптора файла должно принадлежать диапазону от О до 0PEN MAX-1 включительно. 7.1.2. Системный вызов creat Системный вызов creat служит для создания обычных файлов. Вот его приототип: #include <sys/types.h> #include <unistd.h> int creat ( const char* path name, mode t mode ); Аргумент pathname - это путевое имя создаваемого файла. Аргумент mode анологичен применяемому в API open. Поскольку к данному интерфейсу был добавлен флаг 0 CREAT, его можно использовать и для создания обычных файлов, и для их открытия. Поэтому API сгеоГустарел и сохраняется только для обратной совместимости с ранними версиями ОС UNIX. Функцию creat можно реализовать с помощью функции open: tdefine creat(path name,mode) open (path name, 0 WRONLY0 CREAT0 TRUNC, mode) 7.1.3. Функция read Функция read выбирает блок данных фиксированного размера из файла с указанным дескриптором. Прототип функции read выглядит следующим образом: #include <sys/types.h> #include <unistd.h> ssize t read ( int fdesc, void* buf, size t size ); Первый аргумент, fdesc, - это целочисленный дескриптор, обозначающий открытый файл. Второй аргумент, buf, - адрес буфера, содержащего прочитанные данные. Третий аргумент, size, задает количество байтов, которое необходимо прочитать из файла. Тип данных sizej определяется в заголовке <sys/types.h> и должен быть таким же, как и тип данных unsigned int. Следует отметить, что функция read может читать текстовые и двоичные файлы. Именно по этой причине тип данных аргумента buf - это универсальный указатель (void*). Например, приведенный ниже фрагмент кода последовательно читает одну или более записей данных типа struct sample из файла dbase: struct sample { int x; double y; char* z; ) varX; int fd = open ( dbase , 0 RDONLY); while (read(fd,SvarX,sizeof(varX))>0) /* данные процесса записаны в varX */ Функция read возвращает значение, указывающее количество байтов данных, успешно прочитанных и сохраненных в аргументе buf. Как правило, оно должно быть равно значению size. Если же файл содержит менее size байтов непрочитанных данных, то возвращаемое этой функцией значение будет меньше size. Если встречается признак конца файла, read возвращает нулевое значение. Поскольку ssize t обычно определяется в заголовке <sys/types.h> как int, пользователи не должны в вызове функции read задавать значение size, превышающее INTMAX. При соблюдении этого требования значение, возвращаемое функцией, всегда будет соответствовать числу фактически прочитанных байтов. Для случая, когда вызов функции read прерывается перехваченным сигналом (сигналы рассматриваются в главе 9) и операционная система не перезапускает этот вызов автоматически, в POSIX. 1 предусмотрено два варианта поведения функции read. Первый вариант - тот же, что в UNIX System V.3, где read возвращает значение -1, еггпо устанавливается в EINTR и все данные, прочитанные в этом вызове, отбрасываются (следовательно, процесс не может их восстановить). Второй вариант задан стандартом POSIX. 1 FIPS: функция read возвращает число байтов данных, прочитанных до прерывания. Это позволяет процессу продолжать чтение файла. В BSD UNIX, где ядро автоматически перезапускает системный вызов после его прерывания сигналом, read возвращает такое же значение, как и при нормальном выполнении. В UNIX System V.4 пользователь может для каждого сигнала указать, должно ли ядро перезапускать прерываемый системный вызов. Таким образом, с перезапускаемыми вызовами функция read может вести себя так, как в BSD UNIX, а с неперезапускаемыми - так, как в UNIX System V.3 или POSIX. 1 FIPS. Функция read может блокировать выполнение вызывающего процесса, если она читает FIFO-файл или файл устройства, а данных для удовлетворения запроса на чтение еще нет. Для запроса неблокирующих операций Чтения содержимого конкретного файла пользователь может указать с
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |