Выбрать главу

fd = open("/dev/fd/1", O_WRONLY);

fd = dup(1); /* Дублирование стандартного вывода */

Аргумент flags вызова open() интерпретируется, поэтому следует позаботиться об указании точно такого же режима доступа, который был использован исходным дескриптором. Указывать другие флаги, такие как O_CREAT, в данном контексте не имеет смысла (они просто игнорируются).

В Linux открытие одного из файлов в /dev/fd эквивалентно повторному открытию исходного файла. Иначе говоря, новый файловый дескриптор связан с новым описанием открытого файла (и, следовательно, имеет различные флаги состояния файла и смещение файла).

Фактически /dev/fd является символьной ссылкой на характерный для Linux каталог /proc/self/fd. Он представляет собой частный случай свойственных для Linux каталогов /proc/PID/fd, в каждом из которых хранятся символьные ссылки, соответствующие всем файлам, содержащимся процессом в открытом состоянии.

В программах файлы в каталоге /dev/fd редко используются. Наиболее часто они применяются в оболочке. Многие из доступных пользователю команд принимают в качестве аргументов имена файлов, и иногда удобно соединить эти команды с помощью конвейера, чтобы использовать стандартный ввод или вывод в качестве такого аргумента. Для этой цели некоторые программы (например, diff, ed, tar и comm) задействуют аргумент, состоящий из одиночного дефиса (-), означающего: «в качестве файла, имя которого должно быть указано в аргументах, использовать стандартный ввод или вывод (что больше соответствует)». Так, для сравнения списка файлов из ls с ранее созданным списком файлов можно набрать такую команду:

$ ls | diff — oldfilelist

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

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

$ ls | diff /dev/fd/0 oldfilelist

Для удобства в качестве символьных ссылок на /dev/fd/0, /dev/fd/1 и /dev/fd/2 соответственно предоставляются имена /dev/stdin, /dev/stdout и /dev/stderr.

5.12. Создание временных файлов

Некоторые программы нуждаются в создании временных файлов, используемых только при выполнении программы, а при завершении программы такие файлы должны быть удалены. Например, временные файлы создаются в ходе компиляции многими компиляторами. Для этих целей в GNU-библиотеке языка C предоставляется несколько библиотечных функций. Здесь будут рассмотрены две такие функции: mkstemp() и tmpfile().

Функция mkstemp() создает уникальные имена файлов на основе шаблона, предоставляемого вызывающим процессом, и открывает файл, возвращая файловый дескриптор, который может быть использован с системными вызовами ввода-вывода.

#include <stdlib.h>

int mkstemp(char *template);

При успешном завершении возвращает новый файловый дескриптор, а при ошибке выдает –1

Аргумент template принимает форму путевого имени, последними шестью символами которого должны быть XXXXXX. Эти шесть символов заменяются строкой, придающей имени уникальность, и измененная строка возвращается через аргумент template. Поскольку template изменен, он должен указываться как массив символов, а не как строковая константа.

Функция mkstemp() создает файл с правами на чтение и запись для владельца файла (и без прав для других пользователей) и открывает его с флагом O_EXCL, гарантируя вызывающему процессу эксклюзивный доступ к файлу.

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

int fd;

char template[] = "/tmp/somestringXXXXXX";

fd = mkstemp(template);

if (fd == -1)

errExit("mkstemp");

printf("Generated filename was: %s\n", template);

unlink(template); /* Имя тут же исчезает, но файл удаляется только после close() */

/* Использование системных вызовов ввода-вывода — read(), write() и т. д. */

if (close(fd) == -1)

errExit("close");

Для создания уникальных имен файлов могут также применяться функции tmpnam(), tempnam() и mktemp(). Но их использования следует избегать, поскольку они могут создавать в приложении бреши в системе безопасности. Дополнительные подробности об этих функциях можно найти на страницах руководства.

Функция tmpfile() создает временный файл с уникальным именем, открытый для чтения и записи. (Файл открыт с флагом O_EXCL, чтобы защититься от маловероятной возможности, что файл с таким же именем уже был создан другим процессом.)

#include <stdio.h>