355 500 произведений, 25 200 авторов.

Электронная библиотека книг » Арнольд Роббинс » Linux программирование в примерах » Текст книги (страница 10)
Linux программирование в примерах
  • Текст добавлен: 6 мая 2017, 11:00

Текст книги "Linux программирование в примерах"


Автор книги: Арнольд Роббинс



сообщить о нарушении

Текущая страница: 10 (всего у книги 55 страниц)

4.4.4. Пример: Unix cat

Как и было обещано, вот версия cat V7[47]47
  См. /usr/src/cmd/cat.c в дистрибутиве V7. Программа без изменений компилируется для GNU/Linux. – Примеч. автора.


[Закрыть]
. Она начинается с проверки опций, cat V7 принимает единственную опцию, -u, для осуществления небуферированного вывода.

Общая структура сходна с той, которую мы видели ранее; программа перечисляет файлы, указанные в аргументах командной строки и читает каждый файл, по одному символу за раз, посылая этот символ в стандартный вывод. В отличие от нашей версии, она использует возможности . Во многих случаях код, использующий стандартную библиотеку ввода/вывода, проще читать и писать, поскольку все проблемы с буферами скрыты библиотекой.

1  /*

2   * Объединение файлов.

3   */

4

5  #include

6  #include

7  #include

8

9  char stdbuf[BUFSIZ];

10

11 main(argc, argv) /* int main(int argc, char **argv) */

12 char **argv;

13 {

14  int fflg = 0;

15  register FILE *fi;

16  register c;

17  int dev, ino = -1;

18  struct stat statb;

19

20  setbuf(stdout, stdbuf);

21  for( ; argc>1 && argv[1][0] == '-'; argc–, argv++) {

22   switch(argv[1][1]) { /* Обработка опций */

23   case 0:

24    break;

25   case 'u':

26    setbuf(stdout, (char*)NULL);

27    continue;

28   }

29   break;

30  }

31  fstat(fileno(stdout), &statb); /* Строки 31-36 объясняются в главе 5 */

32  statb.st_mode &= S_IFMT;

33  if (statb.st_mode != S_IFCHR && statb.st_mode != S_IPBLK) {

34   dev = statb.st_dev;

35   ino = statb.st_ino;

36  }

37  if (argc < 2) {

38   argc = 2;

39   fflg++;

40  }

41  while (–argc > 0) { // Loop over files

42   if (fflg || (*++argv)[0] == '-' && (*argv)[1] == '')

43    fi = stdin;

44   else {

45    if ((fi = fopen(*argv, "r")) == NULL) {

46     fprintf(stderr, "cat: can't open %sn", *argv);

47    continue;

48   }

49  }

50  fstat(fileno(fi), &statb); /* Строки 50-56 объясняются в главе 5 */

51  if (statb.st_dev == dev && statb.st_ino == ino) {

52   fprintf(stderr, "cat: input %s is outputn",

53    fflg ? "-" : *argv);

54   fclose(fi);

55   continue;

56  }

57  while ((c=getc(fi)) != EOF) /* Копировать содержимое в stdout */

58   putchar(с);

59  if (fi != stdin)

60   fclose(fi);

61  }

62  return(0);

63 }

Следует заметить, что программа всегда завершается успешно (строка 62); можно было написать ее так, чтобы отмечать ошибки и указывать их в возвращаемом значении main(). (Механизм завершения процесса и значение различных кодов завершения обсуждаются в разделе 9.1.5.1 «Определение статуса завершения процесса».)

Код, работающий с struct stat и функцией fstat() (строки 31–36 и 50–56), без сомнения, непрозрачен, поскольку мы еще не рассматривали эти функции и не будем рассматривать до следующей главы (Но обратите внимание на использование fileno() в строке 50 для получения нижележащего дескриптора файла, связанного с переменными FILE*.) Идея в основе этого кода заключается в том, чтобы убедиться, что входной и выходной файлы не совпадают. Это предназначено для предотвращения бесконечного роста файла, в случае подобной команды:

$ cat myfile >> myfile /* Добавить копию myfile к себе? */

И конечно же, проверка работает:

$ echo hi > myfile /* Создать файл */

$ v7cat myfile >> myfile /* Попытка добавить файл к себе */

cat: input myfile is output

Если вы попробуете это с ch04-cat, программа продолжит работу, и myfile будет расти до тех пор, пока вы не прервете ее. GNU версия cat осуществляет эту проверку. Обратите внимание, что что-то вроде этого выходит за рамки контроля cat:

$ v7cat < myfile > myfile

cat: input – is output

$ ls -l myfile

-rw-r–r– 1 arnold devel 0 Mar 24 14:17 myfile

В данном случае это слишком поздно, поскольку оболочка урезала файл myfile (посредством оператора >) еще до того, как cat получила возможность исследовать файл! В разделе 5.4.4.2 «Возвращаясь к V7 cat» мы объясним код с struct stat.

4.5. Произвольный доступ: перемещения внутри файла

До сих пор мы обсуждали последовательный ввод/вывод, при котором данные читаются или записываются с начала файла и продолжаются до его конца. Часто это все, что требуется программе. Однако, возможно осуществление произвольного ввода/вывода; т.е. читать данные из произвольного положения в файле без необходимости предварительного чтения всего, что находится перед этим местом.

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

#include /* для off_t; POSIX */

#include /* объявления lseek() и значений whence */

off_t lseek(int fd, off_t offset, int whence);

Тип off_t (тип смещения) является знаковым целым, представляющим позиции байтов (смещений от начала) внутри файла. На 32-разрядных системах тип представлен обычно как long. Однако, многие современные системы допускают очень большие файлы, в этом случае off_t может быть более необычным типом, таким, как C99 int64_t или какой-нибудь другой расширенный тип. lseek() принимает три следующих аргумента.

int fd

Дескриптор открытого файла.

off_t offset

Позиция, в которую нужно переместиться. Интерпретация этого значения зависит от параметра whence. offset может быть положительным или отрицательным; отрицательные значения перемещают к началу файла; положительные значения перемещают к концу файла.

int whence

Описывает положение в файле, относительно которого отсчитывается offset. См. табл. 4.4.

Таблица 4.4. Значения whence для lseek()


SEEK_SET 0offset абсолютно, т.е. относительно начала файла
SEEK_CUR 1offset относительно текущей позиции в файле
SEEK_END 2offset относительно конца файла.

Большое количество старого кода использует числовые значения, приведенные в табл. 4.4. Однако, любой новый код, который вы пишете, должен использовать символические имена, значение которых более ясно.

Смысл значений и их действие на положение в файле показаны на рис. 4.1. При условии, что файл содержит 3000 байтов и что перед каждым вызовом lseek() текущим является смещение 2000 байтов, новое положение после каждого вызова будет следующим.

Рис. 4.1. Смещения для lseek()

Отрицательные смещения относительно начала файла бессмысленны; они вызывают ошибку «недействительный параметр».

Возвращаемое значение является новым положением в файле. Поэтому, чтобы получить ваше текущее местоположение в файле, используйте

off_t curpos;

...

curpos = lseek(fd, (off_t)0, SEEK_CUR);

Буква l в lseek() означает long. lseek() был введен в V7 Unix, когда размеры файлов были увеличены; в V6 был простой системный вызов seek(). В результате большое количество старой документации (и кода) рассматривает параметр offset как имеющий тип long, и вместо приведения к типу off_t довольно часто можно видеть суффикс L в константных значениях смешений:

curpos = lseek(fd, 0L, SEEK_CUR);

На системах с компилятором стандартного С, где lseek() объявлена с прототипом, такой старый код продолжает работать, поскольку компилятор автоматически преобразует 0L из long в off_t, если это различные типы.

Одной интересной и важной особенностью lseek() является то, что она способна устанавливать смещение за концом файла. Любые данные, которые впоследствии записываются в это место, попадают в файл, но с образованием «интервала» или «дыры» между концом предыдущих данных файла и началом новых данных. Данные в промежутке читаются, как если бы они содержали все нули.

Следующая программа демонстрирует создание дыр. Она записывает три экземпляра struct в начало, середину и дальний конец файла. Выбранные смешения (строки 16–18, третий элемент каждой структуры) произвольны, но достаточно большие для демонстрации особенности:

1  /* ch04-holes.c – Демонстрация lseek() и дыр в файлах. */

2

3  #include /* для fprintf(), stderr, BUFSIZ */

4  #include /* объявление errno */

5  #include /* для flags для open() */

6  #include /* объявление strerror() */

7  #include /* для ssize_t */

8  #include /* для off_t, etc. */

9  #include   /* для mode_t */

10

11 struct person {

12  char name[10]; /* имя */

13  char id[10]; /* идентификатор */

14  off_t pos; /* положение в файле для демонстрации */

15 } people[] = {

16  { "arnold", "123456789", 0 },

17  { "miriam", "987654321", 10240 },

18  { "joe", "192837465", 81920 },

19 };

20

21 int

22 main(int argc, char **argv)

23 {

24  int fd;

25  int i, j;

26

27  if (argc < 2) {

28   fprintf(stderr, "usage: %s filen", argv[0]);

29   return 1;

30  }

31

32  fd = open(argv[1], O_RDWR | O_CREAT | O_TRUNC, 0666);

33  if (fd < 0) {

34   fprintf(stderr, "%s: %s: cannot open for read/write: %sn",

35    argv[0], argv[1], strerror(errno));

36   return 1;

37  }

38

39  j = sizeof(people) / sizeof(people[0]); /* число элементов */

Строки 27–30 гарантируют, что программа была вызвана правильно. Строки 32–37 открывают именованный файл и проверяют успешность открытия.

Вычисление числа элементов j массива в строке 39 использует отличный переносимый трюк число элементов является размером всего массива, поделенного на размер первого элемента. Красота этого способа в том, что он всегда верен: неважно, сколько элементов вы добавляете в массив или удаляете из него, компилятор это выяснит. Он не требует также завершающей сигнальной метки; т.е. элемента, в котором все поля содержат нули, NULL или т.п.

Работа осуществляется в цикле (строки 41–55), который отыскивает смещение байтов, приведенное в каждой структуре (строка 42), а затем записывает всю структуру (строка 49):

41  for (i = 0; i < j; i++) {

42   if (lseek(fd, people[i].pos, SEEK_SET) < 0) {

43    fprintf(stderr, "%s: %s: seek error: %sn",

44     argv[0], argv[1], strerror(errno));

45    (void)close(fd);

46    return 1;

47   }

48

49   if (write(fd, &people[i], sizeof(people[i])) != sizeof(people[i])) {

50    fprintf(stderr, "%s: %s: write error: %sn",

51     argv[0], argv[1], strerror(errno));

52    (void)close(fd);

53    return 1;

54   }

55  }

56

57  /* здесь все нормально */

58  (void)close(fd);

59  return 0;

60 }

Вот результаты запуска программы:

$ ch04-holes peoplelist /* Запустить программу */

$ ls -ls peoplelist /* Показать использованные размеры и блоки */

16 -rw-r–r– 1 arnold devel 81944 Mar 23 17:43 peoplelist

$ echo 81944 / 4096 | bc -l /* Показать блоки, если нет дыр */

20.00585937500000000000

Случайно мы знаем, что каждый дисковый блок файла использует 4096 байтов. (Откуда мы это знаем, обсуждается в разделе 5 4.2 «Получение информации о файле». Пока примите это как данное.) Финальная команда bc указывает, что файлу размером 81944 байтов нужен 21 дисковый блок. Однако, опция -s команды ls, которая сообщает нам, сколько блоков использует файл на самом деле, показывает, что файл использует лишь 16 блоков![48]48
  По крайней мере, три из этих блоков содержат данные, которые мы записали, другие для использования операционной системой при отслеживании размещения этих данных – Примеч. автора.


[Закрыть]
Отсутствующие блоки в файле являются дырами. Это показано на рис. 4.2.

Рис. 4.2. Дыры в файле

ЗАМЕЧАНИЕch04-holes.c не осуществляет непосредственный двоичный ввод/вывод. Это хорошо демонстрирует красоту ввода/вывода с произвольным доступом: вы можете рассматривать дисковый файл, как если бы он был очень большим массивом двоичных структур данных.

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

4.6. Создание файлов

Как было описано ранее, open(), очевидно, открывает лишь существующие файлы. Данный раздел описывает, как создавать новые файлы. Есть две возможности: creat() и open() с дополнительными файлами. Первоначально creat() был единственным способом создания файла, но затем эта возможность была добавлена также и к open(). Оба механизма требуют указания начальных прав доступа к файлу.

4.6.1. Определение начальных прав доступа к файлу

Как пользователь GNU/Linux, вы знакомы с правами доступа к файлу, выдаваемыми командой 'ls -l': на чтение, запись и исполнение для каждого из владельца файла, группы и остальных. Различные сочетания часто выражаются в восьмеричной форме, в частности, для команд chmod и chmask. Например, права доступа к файлу -rw-r–r– эквивалентны восьмеричному 0644, a -rwxr-xr-x эквивалентно восьмеричному 0755. (Ведущий 0 в нотации С означает восьмеричные значения.)

Когда вы создаете файл, вы должны знать, какую защиту необходимо назначить новому файлу. Вы можете сделать это с помощью простого восьмеричного числа, если захотите, и такие числа довольно обычно можно увидеть в старом коде. Однако, лучше использовать побитовую операцию OR для одной или более символических имен из , описанных в табл. 4.5.

Таблица 4.5. Символические имена POSIX для режимов доступа к файлу


S_IRWXU 00700Разрешение на чтение, запись и исполнение для владельца
S_IRUSR 00400Разрешение на чтение для владельца
S_IREAD Аналогично S_IRUSR
S_IWUSR 00200Разрешение на запись для владельца
S_IWRITE Аналогично S_IWUSR
S_IXUSR 00100Разрешение на исполнение для владельца.
S_IEXEC Аналогично S_IXUSR
S_IRWXG 00070Разрешение на чтение, запись и исполнение для группы
S_IRGRP 00040Разрешение на чтение для группы
S_IWGRP 00020Разрешение на запись для группы.
S_IXGRP 00010Разрешение на исполнение для группы
S_IRWXO 00007Разрешение на чтение, запись и исполнение для остальных.
S_IROTH 00004Разрешение на чтение для остальных.
S_IWOTH 00002Разрешение на запись для остальных
S_IXOTH 00001Разрешение на исполнение для остальных

Следующий фрагмент показывает, как создать переменные, представляющие разрешения -rw-r–r– и -rwxr-xr-x (0644 и 0755 соответственно):

mode_t rw_mode, rwx_mode;

rw_mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; /* 0644 */

rwx_mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH; /* 0755 */

Более старый код использовал S_IREAD, S_IWRITE и S_IEXEC вместе со сдвигом битов для получения того же результата:

mode_t rw_mode, rwx_mode;

rw_mode = (S_IREAD|S_IWRITE) | (S_IREAD >> 3) | (S_IREAD >> 6); /* 0644 */

rwx_mode = (S_IREAD|S_IWRITE|S_IEXEC) |

 ((S_IREAD|S_IEXEC) >> 3) | ((S_IREAD|S_IEXEC) >> 6); /* 0755 */

К сожалению, ни одна из записей не является очень удобной. Современные версии предпочтительнее, поскольку у каждого бита доступа есть собственное имя и меньше вероятность неправильного выполнения побитовых операций.

При изменении прав доступа к файлу для использования доступны биты дополнительных разрешений, показанные в табл. 4.6, но они не должны использоваться при первоначальном создании файла. Возможность включения этих битов широко варьирует между операционными системами. Лучше всего не пробовать; вместо этого следует изменить права доступа к файлу явным образом после его создания. (Изменение прав доступа описано в разделе 5.5.2 «Изменение прав доступа: chmod() и fchmod()». Значения этих битов обсуждаются в главе 11 «Права доступа и идентификаторы пользователя и группы».)

Таблица 4.6. Дополнительные символические имена POSIX для режимов доступа к файлам


S_ISUID 04000Установить ID пользователя
S_ISGID 02000Установить ID группы
S_ISVTX 01000Сохранить текст

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

действительные_права = (затребованные_права & (~umask));

umask обычно устанавливается с помощью команды umask в $НОМЕ/.profile, когда вы входите в систему. Из программы С она устанавливается с помощью системного вызова umask().

#include /* POSIX */

#include mode_t umask(mode_t mask);

Возвращается старое значение umask. Поэтому для определения текущей маски нужно установить новое значение, а затем восстановить старое (или изменить его при необходимости):

mode_t mask = umask(0); /* получить текущую маску */

(void)umask(mask); /* восстановить ее */

Вот пример работы umask на уровне оболочки:

$ umask /* Показать текущую маску */

0022

$ touch newfile /* Создать файл */

$ ls -l newfile /* Показать права доступа нового файла */

-rw-r–r– 1 arnold devel 0 Mar 24 15:43 newfile

$ umask 0 /* Установить пустую маску */

$ touch newfile2 /* Создать второй файл */

$ ls -l newfile2 /* Показать права доступа нового файла */

-rw-rw-rw– 1 arnold devel 0 Mar 24 15:44 newfile2

4.6.2. Создание файлов с помощью creat()

Системный вызов creat()[49]49
  Да, это пишется так. Кена Томпсона (Ken Thompson), одного из двух «отцов» Unix, однажды спросили, что бы он сделал по-другому, если бы ему пришлось переделать Unix. Он ответил, что написал бы creat() с «e» на конце. И в самом деле, именно это он сделал для операционной системы Plan 9 From Bell LabsПримеч. автора.


[Закрыть]
создает новые файлы. Он объявлен следующим образом:

#include /* POSIX */

#include

#include

int creat(const char *pathname, mode_t mode);

Аргумент mode представляет права доступа к новому файлу (как обсуждалось в предыдущем разделе). Создается файл с именем pathname.с данными правами доступа, модифицированными с использованием umask. Он открыт (только) для чтения, а возвращаемое значение является дескриптором нового файла или -1, если была проблема. В последнем случае errno указывает ошибку. Если файл уже существует, он будет при открытии урезан.

Во всех остальных отношениях дескрипторы файлов, возвращаемые creat(), являются теми же самыми, которые возвращаются open(); они используются для записи и позиционирования и должны закрываться при помощи close():

int fd, count;

/* Проверка ошибок для краткости опущена */

fd = creat("/some/new/file", 0666);

count = write(fd, "some datan", 10);

(void)close(fd);

4.6.3. Возвращаясь к open()

Вы можете вспомнить объявление для open():

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

Ранее мы сказали, что при открытии файла для простого ввода/вывода мы можем игнорировать аргумент mode. Хотя, посмотрев на creat(), вы, возможно, догадались, что open() также может использоваться для создания файлов и что в этом случае используется аргумент mode. Это в самом деле так.

Помимо флагов O_RDONLY, O_WRONLY и O_RDWR, при вызове open() могут добавляться с использованием поразрядного OR дополнительные флаги. Стандарт POSIX предоставляет ряд этих дополнительных флагов. В табл. 4.7 представлены флаги, которые используются для большинства обычных приложений.

Таблица 4.7. Дополнительные флаги POSIX для open()


O_APPEND Принудительно осуществляет все записи в конец файла
O_CREAT Создает новый файл, если он не существует.
O_EXCL При использовании вместе с O_CREAT возвращает ошибку, если файл уже существует
O_TRUNC Урезает файл (устанавливает его длину в 0), если он существует.

Если даны O_APPEND и O_TRUNC, можно представить, как оболочка могла бы открывать или создавать файлы, соответствующие операторам > и >>. Например:

int fd;

extern char *filename;

mode_t mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH; /* 0666 */

fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, mode); /* для > */

fd = open(filename, O_CREAT | O_WRONLY | O_APPEND, mode); /* для >> */

Обратите внимание, что флаг O_EXCL здесь не используется, поскольку как для >, так и для >> не является ошибкой существование файла. Запомните также, что система применяет к запрошенным правам доступа umask.

Также легко видеть, что, по крайней мере концептуально, creat() можно было бы легко написать следующим образом:

int creat(const char *path, mode_t mode) {

 return open(path, O_CREAT | O_WRONLY | O_TRUNC, mode);

}

ЗАМЕЧАНИЕ. Если файл открыт с флагом O_APPEND, все данные будут записаны в конец файла, даже если текущее смещение было восстановлено с помощью lseek().

Современные системы предоставляют дополнительные флаги с более специализированным назначением. Они кратко описаны в табл. 4.8.

Таблица 4.8. Дополнительные расширенные флаги POSIX для open()


O_APPEND Принудительно осуществляет все записи в конец файла
O_CREAT Создает новый файл, если он не существует.
O_EXCL При использовании вместе с O_CREAT возвращает ошибку, если файл уже существует
O_TRUNC Урезает файл (устанавливает его длину в 0), если он существует.

Флаги O_DSYNC, O_RSYNC и O_SYNC требуют некоторых пояснений. Системы Unix (включая Linux) содержат внутренний кэш дисковых блоков, который называется буферным кэшем (buffer cache). Когда возвращается системный вызов write(), данные, переданные операционной системе, были скопированы в буфер в буферном кэше. Они необязательно были записаны на диск.

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

Системы Unix осуществляют также опережающее чтение; поскольку чтение в большинстве случаев последовательное, операционная система после прочтения одного блока осуществляет чтение нескольких дополнительных последовательных блоков таким образом, что эта информация будет уже находиться в кэше, когда программа ее запросит. Если один и тот же файл читают несколько программ, они все получают преимущество, поскольку все получают свои данные из одной копии дисковых блоков файла в буферном кэше.

Все это кэширование, конечно, замечательно, но бесплатного обеда не бывает. В то время, пока данные находятся в буферном кэше и до того, как они будут записаны на диск, есть небольшое, но вполне реальное окно, в котором может случиться катастрофа; например, если выключат питание. Современные дисковые приводы обостряют эту проблему: у многих из них есть собственные внутренние буферы, поэтому при записи данных на диск они могут оказаться не записанными на носитель при выключении питания! Это может быть значительной проблемой для небольших систем, которые не находятся в информационном центре с контролируемым энергоснабжением или не имеют источников бесперебойного питания (UPS).[50]50
  Если у вас нет UPS и вы используете систему для критической работы, мы настоятельно рекомендуем вам обзавестись им. Следует также регулярно делать резервные копии. – Примеч. автора.


[Закрыть]

Для большинства приложений вероятность того, что данные в буферном кэше могут быть нечаянно потеряны, довольно низка. Однако, для некоторых приложений любой такой шанс неприемлем. Поэтому в системе Unix было введено понятие синхронного ввода/вывода, при котором программе гарантируется, что по возвращении из системного вызова данные безопасно записаны на физическое устройство хранения.

Флаг O_DSYNC гарантирует целостность данных; данные и любая другая информация, которую операционная система должна найти, записываются на диск до возвращения write(). Однако, вспомогательные данные, такие, как время модификации или доступа к файлу, могут быть не записаны на диск. Флаг O_SYNC требует, чтобы эти данные также были записаны на диск до возвращения write(). (Здесь тоже нет бесплатного обеда; синхронные записи могут серьезно повлиять на производительность программы, заметно ее снизив.)

Флаг O_RSYNC предназначен для чтения данных: если read() находит данные в буферном кэше, которые были назначены для записи на диск, функция не вернет эти данные до тех пор, пока они не будут записаны. Два других флага влияют на это: в частности, O_SYNC заставит read() ждать, пока не будут также записаны и вспомогательные данные.

ЗАМЕЧАНИЕ. Что касается ядра версии 2.4, Linux рассматривает все три флага одинаково со значением флага O_SYNC. Более того, Linux определяет дополнительные флаги, которые специфичны для Linux и предназначены для специального использования. Дополнительные подробности см. в справочной странице GNU/Linux для open(2).


    Ваша оценка произведения:

Популярные книги за неделю