if (argc!= 3 || strcmp(argv[1], "-help") == 0)

usageErr("%s old-file new-file\n", argv[0]);

/* Открытие файлов ввода и вывода */

inputFd = open(argv[1], O_RDONLY);

if (inputFd == -1)

errExit("opening file %s", argv[1]);

openFlags = O_CREAT | O_WRONLY | O_TRUNC;

filePerms = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP |

S_IROTH | S_IWOTH; /* rw-rw-rw- */

outputFd = open(argv[2], openFlags, filePerms);

if (outputFd == -1)

errExit("opening file %s", argv[2]);

/* Перемещение данных до достижения конца файла ввода или возникновения ошибки */

while ((numRead = read(inputFd, buf, BUF_SIZE)) > 0)

if (write(outputFd, buf, numRead)!= numRead)

fatal("couldn't write whole buffer");

if (numRead == -1)

errExit("read");

if (close(inputFd) == -1)

errExit("close input");

if (close(outputFd) == -1)

errExit("close output");

exit(EXIT_SUCCESS);

}

fileio/copy.c

4.2. Универсальность ввода-вывода

Одна из отличительных особенностей модели ввода-вывода UNIX состоит в универсальности ввода-вывода. Это означает, что одни и те же четыре системных вызова — open(), read(), write() и close() — применяются для выполнения ввода-вывода во всех типах файлов, включая устройства, например терминалы. Следовательно, если программа написана с использованием лишь этих системных вызовов, она будет работать с любым типом файла. Например, следующие примеры показывают вполне допустимое использование программы, чей код приведен в листинге 4.1:

$ ./copy test test.old Копирование обычного файла

$ ./copy a.txt /dev/tty Копирование обычного файла в этот терминал

$ ./copy /dev/tty b.txt Копирование ввода с этого терминала в обычный файл

$ ./copy /dev/pts/16 /dev/tty Копирование ввода с другого терминала

Универсальность ввода-вывода достигается обеспечением того, что в каждой файловой системе и в каждом драйвере устройства реализуется один и тот же набор системных вызовов ввода-вывода. Поскольку детали реализации конкретной файловой системы или устройства обрабатываются внутри ядра, при написании прикладных программ мы можем вообще игнорировать факторы, относящиеся к устройству. Когда требуется получить доступ к конкретным свойствам файловой системы или устройства, в программе можно использовать всеобъемлющий системный вызов ioctl() (см. раздел 4.8). Он предоставляет интерфейс для доступа к свойствам, которые выходят за пределы универсальной модели ввода-вывода.

4.3. Открытие файла: open()

Системный вызов open() либо открывает существующий файл, либо создает и открывает новый файл.

#include

#include

int open(const char *pathname, int flags… /* mode_t mode */);

Возвращает дескриптор при успешном завершении или –1 при ошибке

Чтобы файл открылся, он должен пройти идентификацию по аргументу pathname. Если в этом аргументе находится символьная ссылка, она разыменовывается. В случае успеха open() возвращает дескриптор файла, который используется для ссылки на файл в последующих системных вызовах. В случае ошибки open() возвращает –1, а для errno устанавливается соответствующее значение.

Аргумент flags является битовой маской, указывающей режим доступа к файлу с использованием одной из констант, перечисленных в табл. 4.2.

В ранних версиях UNIX вместо имен, приведенных в табл. 4.2, использовались числа 0, 1 и 2. В более современных реализациях UNIX эти константы определяются с указанными в таблице значениями. Из нее видно, что O_RWDW (10 в двоичном представлении) не совпадает с результатом операции O_RDONLY | O_WRONLY (0 | 1 = 1); последняя комбинация прав доступа является логической ошибкой.

Когда open() применяется для создания нового файла, аргумент битовой маски режима (mode) указывает на права доступа, которые должны быть присвоены файлу. (Используемый тип данных mode_t является целочисленным типом, определенным в SUSv3.) Если при вызове open() не указывается флаг O_CREAT, то аргумент mode может быть опущен.

Таблица 4.2. Режимы доступа к файлам

Режим доступа

Описание

O_RDONLY

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

O_WRONLY

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

O_RDWR

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

Подробное описание прав доступа дается в разделе 15.4. Позже будет показано, что права доступа, фактически присваиваемые новому файлу, зависят не только от аргумента mode, но и от значения umask процесса (см. подраздел 15.4.6) и от (дополнительно имеющегося) списка контроля доступа по умолчанию (access control list) (см. раздел 17.6) родительского каталога. А пока просто отметим для себя, что аргумент mode может быть указан в виде числа (обычно восьмеричного) или, что более предпочтительно, путем применения операции логического ИЛИ (|) к нескольким константам битовой маски, перечисленным в табл. 15.4.

Перейти на страницу:

Похожие книги