В настоящее время актуальный стандарт - это POSIX 2008 и его дополнение POSIX 1003.13 |
Организация файловой системы
Создание, удаление, копирование и перемещение файлов
Стандарт POSIX-2001 не требует наличия утилиты для создания обычных файлов. Они появляются по мере необходимости как побочный продукт многочисленных служебных программ (например, утилиты копирования), поэтому сама постановка задачи - создать файл "просто так" - является отчасти надуманной. В то же время, если новый файл все-таки нужен, полезно иметь в виду возможность перенаправления вывода пустой команды, которая имеется в языке shell.
При программировании на языке C для создания обычных файлов можно воспользоваться функцией creat() (см. листинг 4.30).
#include <fcntl.h> int creat (const char *path, mode_t mode);Листинг 4.30. Описание функции creat().
Функция creat() имеет два аргумента: маршрутное имя вновь образуемого файла и устанавливаемый режим доступа (идентификаторы владельца и владеющей группы наследуются у текущего пользователя). Результатом служит файловый дескриптор (который, напомним, представляется неотрицательным целым числом), т. е. функция creat() не только создает файл, но и открывает его.
Если файл, который пытаются создать при помощи creat(), уже существует, он опустошается (размер становится равным 0), а режим доступа и владелец не изменяются.
В случае неудачи результат creat() равен -1, а внешней переменной errno присваивается код ошибки, позволяющий определить причину ее (ошибки) возникновения. Переменная errno, а также мнемоники для кодов ошибок определены в заголовочном файле <errno.h>. Для формирования системного сообщения об ошибке можно воспользоваться функцией perror() (см. листинг 4.31), которая, опираясь на значение errno, помещает в стандартный протокол описание последней ошибки.
#include <stdio.h> void perror (const char *s);Листинг 4.31. Описание функции perror().
Например, при первом выполнении программы, приведенной в листинге 4.32, в стандартный протокол может быть выдан соответствующий результат (см. листинг 4.33).
#include <fcntl.h> #include <errno.h> #include <stdio.h> #include <limits.h> /* Программа пытается создавать в текущем */ /* каталоге файлы с именами g1, g2, ..., */ /* пока эти попытки не закончатся неудачей */ int main (void) { int n = 0; char name [PATH_MAX]; do sprintf (name, "g%d", ++n); while (creat (name, (mode_t) 0) >= 0); perror ("CREAT failed"); fprintf (stderr, "errno = %d\n", errno); fprintf (stderr, "Неудача на файле номер %d\n", n); return 0; }Листинг 4.32. Пример программы, использующей функции creat() и perror().
CREAT failed: Too many open files errno = 24 Неудача на файле номер 1022Листинг 4.33. Возможный результат первого выполнения программы, использующей функции creat() и perror().
Результат второго запуска той же программы показан в листинге 4.34.
CREAT failed: Permission denied errno = 22 Неудача на файле номер 1Листинг 4.34. Результат повторного выполнения программы, использующей функции creat() и perror().
При первом запуске причина неудачи - превышение максимально допустимого числа одновременно открытых файлов (с учетом стандартных ввода, вывода и протокола), при повторном - попытка создать существующий файл вопреки отсутствию права на запись в него ( файлы создавались с нулевым режимом доступа ).
Перечислим несколько других условий, способных привести к неудачному завершению вызова creat(): компонент маршрутного имени не существует или не является каталогом ; у компонента маршрута отсутствует право на поиск ; создание файла требует записи в каталог, права на запись в который нет; файл существует и является каталогом.
Рассмотренный в примере стиль уведомления о неудачном завершении общий для большинства функций. Неудача определяется возвращением результата, невозможного в другом случае (почти всегда это -1 или пустой указатель NULL ); код ошибки заносится в переменную errno. Разумеется, в реальных программах errno не выводят, а анализируют. В данном случае уместно было бы сравнивать errno с константами EACCES, EINVAL, EMFILE и т.д. (см. <errno.h> ).
файл не обязательно создавать в текущем каталоге ; в качестве аргумента creat() может быть передано составное имя. Пример, когда устанавливаются все биты режима доступа, приведен в листинге 4.35.
df = creat ("/tmp/sample", S_IRWXU | S_IRWXG | S_IRWXO);Листинг 4.35. Пример вызова функции creat().
Для создания (пустых) каталогов служит утилита
mkdir [-p] [-m режим_доступа] каталог ...
#include <sys/stat.h> int mkdir (const char *path, mode_t mode);
С помощью одной команды mkdir можно сформировать несколько каталогов. В каждом из них появятся ссылки . и .., которые другими способами создать нельзя. По умолчанию устанавливаются все биты режима доступа; режим можно задать и явно с помощью опции -m.
Если нужен не один, а целая цепочка каталогов, следует воспользоваться опцией -p. Соответствующий пример приведен в листинге 4.36.
mkdir -p work/tmp/saveЛистинг 4.36. Пример использования служебной программы mkdir для создания цепочки каталогов.
По этой команде в текущем каталоге появится подкаталог work, в нем - каталог tmp, а уже в нем - каталог save.
Смысл аргументов функции mkdir() тот же, что и для creat(), в случае неудачи возвращается -1, но при нормальном завершении результат равен 0 ( mkdir() не оставляет новый каталог открытым). Перечисленные выше условия неудачного завершения creat() (кроме превышения максимального числа одновременно открытых файлов ) применимы и к mkdir().
Интерфейс, сходный с mkdir, имеют утилита mkfifo для создания каналов:
mkfifo [-m режим_доступа] канал ...
Заметим, что здесь отсутствует опция -p ) и одноименная функция (см. листинг 4.37).
#include <sys/stat.h> int mkfifo (const char *path, mode_t mode);Листинг 4.37. Описание функции mkfifo().