Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Учеб.пос.СП.doc
Скачиваний:
28
Добавлен:
31.03.2015
Размер:
1.33 Mб
Скачать
    1. Системные вызовы open и creat

Системный вызов open – открывает или создает файл:

#include <sys/stat.h>

#include <fcntl.h>

int open(

const char *path, /* полное имя файла*/

int flags, /* флаги */

mode_t perms /* права доступа (если создается новый файл) */

);

/* Возвращает дескриптор файла или -1 в случае ошибки (код ошибки находится в глобальной переменной errno) */

Вызов open открывает существующий файл или создает новый, но в данном случае это может быть только обычный файл. Специальные файлы создаются вызовом mknod, а именованные каналы – вызовом mkfifo. После того, как файл будет открыт, можно использовать полученный дескриптор в вызовах read, write, lseek, close и многих других.

Рассмотрим открытие существующего файла, имя которого задается аргументом path. Если через аргумент flags передается значение O_RDONLY, то файл открывается только для чтения, O_WRONLY – только для записи, O_RDWR - как для записи, так и для чтения. Например, если эффективный идентификатор пользователя у процесса совпадает с идентификатором владельца файла, то для него должны быть установлены права доступа на чтение и/или на запись. В случае открытия существующего файла, аргумент perms игнорируется и в текстах программ, как правило, вообще опускается. Таким образом, функция open вызывается всего с двумя аргументами. Ниже приводится пример кода, который открывает существующий файл:

int fd;

fd = open(“/home/marc/oldfile”, O_RDONLY);

Вызов open присваивает файловому дескриптору наименьший из доступных номеров. Знание этого обстоятельства может порой сослужить неплохую службу. Например, когда необходимо перенаправить один из стандартных дескрипторов - 0, 1 или 2, нужно просто закрыть этот дескриптор и открыть файл, который получит номер только что закрытого дескриптора.

Рассмотрим создание нового файла. Если файл с указанным именем не существует, вызов open создаст его, при условии, что аргумент flags содержит флаг O_CREAT. Флаг O_CREAT обычно дополняется флагом O_WRONLY или O_RDWR. Кроме того, на этот раз необходимо определить права доступа к файлу, например:

fd = open(“/home/marc/newfile”, O_RDWR | O_CREAT, PERM_FILE);

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

fd = open(“/home/marc/newfile”, O_WRONLY | O_CREAT | O_TRUNC, PERM_FILE);

Использование флага O_TRUNC приводит к уничтожению всех данных в файле, поэтому его допустимо указывать только при открытии существующего файла и при условии, что процесс имеет право на запись в открываемый файл. По той же причине, флаг O_TRUNC не может использоваться совместно с флагом O_RDONLY. Чтобы создать новый файл (с флагом O_CREAT), процесс должен иметь право на запись в каталог, поскольку ссылка на файл будет записана в файл каталога. При открытии существующего файла права доступа к каталогу не имеют значения. В этом случае в расчет принимаются только права доступа к файлу. Комбинация флагов O_WRONLY | O_CREAT | O_TRUNC настолько обычна (создать файл или очистить его и открыть на запись), что для этой цели существует специальный системный вызов: creat - создает новый или очищает существующий файл и открывает его.

#include <sys/stat.h>

#include <fcntl.h>

int creat(

const char *path, /* полное имя файла*/

mode_t perms /* права доступа */

);

/* Возвращает дескриптор файла или -1 в случае ошибки (код ошибки находится в глобальной переменной errno) */

Фактически, вызов creat можно оформить в виде макроопределения:

#define creat(path, perms) open(path, O_WRONLY | O_CREAT | O_TRUNC, perms)

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

  • в качестве владельца файлу назначается эффективный идентификатор пользователя процесса;

  • в качестве группы устанавливается либо идентификатор группы каталога, в котором создается файл, либо эффективный идентификатор группы процесса.

У приложения нет возможности выбрать, какая из двух групп будет присвоена файлу, но оно может узнать это с помощью системного вызова stat. Чтобы принудительно назначить файлу нужную группу, можно воспользоваться системным вызовом chown, хотя подобные требования к приложениям предъявляются довольно редко.

Существует еще один флаг - O_EXCL, который в сочетании с O_CREAT вызывает ошибку при попытке открыть существующий файл. Системный вызов open, используемый без флага O_CREAT, означает «открыть файл, если он существует, в противном случае – завершиться с ошибкой». С комбинацией флагов O_CREAT | O_EXCL - с точностью до наоборот «создать новый файл, если он не существует, в противном случае – завершиться с ошибкой». Одно из интересных применений флага O_EXCL - работа с файлами блокировок. Другая область применений – обслуживание временных файлов, которые должны удаляться при нормальном завершении приложения.

Использование файлов блокировок. Процессы, которые требуют исключительного доступа к ресурсу, могут придерживаться следующего протокола: прежде чем получить доступ к ресурсу, они должны попытаться создать файл, используя флаг O_EXCL. Это удастся сделать только одному процессу, все остальные вызовы open будут терпеть неудачу. В случае появления ошибки, процесс может немного подождать или заняться выполнением других действий и попробовать получить доступ к ресурсу позднее. В случае успешного создания файла, процесс выполняет необходимые действия с ресурсом и затем удаляет файл. После этого другой конкурирующий процесс сможет получить доступ к ресурсу. Такой способ блокировки будет работать, только если обеспечена атомарность процесса проверки существования файла и его создания – никакой другой процесс не должен иметь возможность исполняться в промежутке между этими двумя действиями. Необходим надежный способ, гарантирующий атомарность операции, который носит название блокировка. Протокол, описанный выше, прекрасно укладывается в вызов двух функций: lock и unlock, следующим образом:

if (lock (“accounts”)) {

действия с ресурсом accounts…

unlock(“accounts”);

}

else

невозможно установить блокировку…

Если теперь два процесса попытаются выполнить этот участок программы, то блокировка предотвратит одновременное исполнение защищенной секции кода (действия с ресурсом accounts). Когда процесс не может захватить блокировку, он начинает чередовать периоды ожидания с попытками захвата, такая последовательность действий называется голосованием. Это огромная нагрузка на центральный процессор и все лишь для того, чтобы получить ответ на вопрос: Моя очередь еще не подошла? Блокировка может освободится, когда процесс еще спит, и он не узнает об этом, пока не проснется, а это тоже лишняя трата времени. К счастью, среди прочих возможностей, в Unix существует так называемая система блокировок. Она обеспечивает пробуждение процесса, когда происходит ожидаемое им событие.

Описание флагов системного вызова open. Системному вызову open можно передать большое количество флагов, представленных в табл. 2.1.

Таблица 2.1. Флаги системного вызова open

Флаг

Описание

O_RDONLY

Открыть только для чтения

O_WRONLY

Открыть только для записи

O_RDWR

Открыть для чтения и для записи

O_APPEND

Открыть для дополнения в конец файла

O_CREAT

Создать новый, если не существует

O_DSYNC

Установить режим синхронного ввода-вывода

O_EXCL

Не открывать, если существует. Используется в комбинации с O_CREAT

O_NOCTTY

Не делать устройство управляющим терминалом

O_NONBLOCK

Неблокирующий режим работы с именованными каналами и специальными файлами

O_RSYNC

Установить режим синхронного ввода-вывода

O_SYNC

Установить режим синхронного ввода-вывода

O_TRUNC

Удалить содержимое файла – усечь его размер до нуля