Литмир - Электронная Библиотека
Содержание  
A
A

Иллюстрацией изложенного может служить упрощенная версия

cp
. Ее главный недостаток состоит в том, что она копирует только один файл и не разрешает использовать в качестве второго аргумента каталог. Кроме того, наша версия не сохраняет права доступа файла-источника; в дальнейшем мы покажем, как это исправить.

/* cp: minimal version */

#include <stdio.h>

#define PERMS 0644 /* RW for owner, R for group, others */

char *progname;

main(argc, argv) /* cp: copy f1 to f2 */

 int argc;

 char *argv[];

{

 int f1, f2, n;

 char buf[BUFSIZ];

 progname = argv[0];

 if (argc != 3)

  error("Usage: %s from to", progname);

 if ((f1 = open(argv[1], 0)) == -1)

  error("can't open %s", argv[1]);

 if ((f2 = creat(argv[2], PERMS)) == -1)

  error("can't create %s", argv[2]);

 while ((n = read(f1, buf, BUFSIZ)) > 0)

  if (write(f2, buf, n) != n)

 error("write error", (char*)0);

 exit(0);

}

error
мы обсудим ниже.

Число файлов, которые одновременно могут быть открыты программой, ограничено (обычно порядка 20; см.

NOFILE
в
<SYS/param.h>
). Поэтому любая программа, которой предстоит обрабатывать много файлов, должна быть готова неоднократно использовать одни и те же дескрипторы файлов. Системный вызов
close
разрывает связь между именем и дескриптором файла, освобождая дескриптор для использования с некоторым другим файлом. Завершение программы посредством
exit
и возврат из основной программы закрывают все открытые файлы. Вызов системы unlink удаляет файл из файловой системы.

Обработка ошибок:
errno

Обсуждаемые здесь системные вызовы, а по сути все системные вызовы, могут вызывать ошибки. Обычно они сигнализируют об ошибке, возвращая значение -1. Иногда полезно знать, какая именно ошибка произошла, поэтому системные вызовы, когда это приемлемо, оставляют номер ошибки во внешней целой переменной, называемой

errno
. (Значение различных номеров ошибок объясняется во введении к разд. 2 справочного руководства по UNIX.) С помощью
errno
ваша программа может определить, например, чем вызвана неудача при открытии файла — тем, что он не существует, или тем, что у вас нет разрешения на его чтение. Кроме того, есть массив символьных строк
sys_errlist
, индексируемый
errno
, который переводит число в строку, передающую смысл ошибки. Наша версия error использует эти структуры данных:

error(s1, s2) /* print error message and die */

 char *s1, *s2;

{

 extern int errno, sys_nerr;

 extern char *sys_errlist[], *progname;

 if (progname)

  fprintf(stderr, "%s: ", progname);

 fprintf(stderr, s1, s2);

 if (errno > 0 && errno < sys_nerr)

  fprintf (stderr, " (%s)", sys_errlist[errno]);

 fprintf(stderr, "\n");

 exit(1);

}

Errno
первоначально равна нулю и всегда должна быть меньше, чем
sys_herr.
Она не становится нулевой вновь при нормальной работе, поэтому вы должны обнулять ее после каждой ошибки, если ваша программа будет продолжать выполняться. Сообщения об ошибках в нашей версии
cp
появляются следующим образом:

$ cp foo bar

cp: can't open foo      
(Нет такого файла или каталога)

$ date >foo; chmod 0 foo
Создать нечитаемый файл

$ cp too bar

cp: can't open foo      
(В разрешении отказано)

$

Произвольный доступ:
lseek

Файл ввода-вывода обычно последовательный: каждый

read
или
write
занимает место в файле непосредственно после использованного при предыдущем вызове. Однако при необходимости файл может быть прочитан или записан в произвольном порядке. Системный вызов
lseek
позволяет перемещаться по файлу, не осуществляя ни чтения, ни записи:

int fd, origin;

long offset, pos, lseek();

pos = lseek(fd, offset, origin);

Текущая позиция в файле с дескриптором

fd
перемещается к позиции
offset
, которая отсчитывается относительно места, определяемого
origin
. Последующие процессы чтения или записи будут начинаться с этой позиции.
Origin
может иметь значения 0, 1, 2, задавая тем самым начало отсчета значения
offset
 — от начала, от текущей позиции или от конца файла соответственно.

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

lseek(fd, 0L, 2);

Чтобы вернуться обратно к началу ("перемотать"), необходимо вызвать

lseek(fd, 0L, 0);

Для определения текущей позиции следует выполнить

pos = lseek(fd, 0L, 1);

Обратите внимание на аргумент

0L
: смещение есть длинное целое. ('l' в lseek означает 'long' — длинный, чтобы отличить его от системного вызова
seek
в шестой версии, где используются короткие целые.)

89
{"b":"248117","o":1}