Материал: 6262

Внимание! Если размещение файла нарушает Ваши авторские права, то обязательно сообщите нам

46

1.6 Дублирование дескрипторов файлов

Известно, что:

интерпретатор shell, запуская процесс, передает ему три дескриптора файлов: 0 — для чтения; 1 и 2 — для записи;

функция open(...), в случае нормального завершения, возвращает наименьший доступный номер дескриптора;

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

программа обработки алгоритма пищется и отлаживается при условии, что

ввод осущесвляется из дескриптора с номером 0, а вывод осуществляется в файл с дескриптором 1;

серверная программа, для обработки запроса, создает дочерний процесс, ко-

торый: открывает файл ввода информации, закрывает дескриптор 0 и дублирует дескриптор открытого файла, обеспечивая ввод данных по дескриптору 0; аналогичные действия проводятся с вескриптором файла вывода; после этого, посредством одного из системных вызовов exec(…), осуществляется запуск программы обработки алгоритма.

Стандарт POSIX предоставляет два системных вызова дублирования дескрипторов файлов:

#include <unistd.h>

int dup (int oldfd);

int dup2(int oldfd, int newfd);

где oldfd — старый дескриптор файла; newfd — новый дескриптор файла.

Обе функции, в случае нормального завершения вызова:

возвращают новый дескриптор файла;

функция dup2(…), если требуется, предварительно закрывает старый деск-

риптор oldfd.

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

Если произошла ошибка, то возвращается значение -1 и переменная errno устанавливается должным образом:

EBADF oldfd не является открытым файловым дескриптором, или же newfd находится вне допустимого диапазона файловых дескрипторов;

47

EMFILE — процесс уже открыл максимальное количество файлов и пытается открыть еще один;

EINTR — Вызов dup2(...) был прерван каким-либо сигналом;

EBUSY — может случиться только в Linux, при вызове dup2(...) во время состязательных вызовов open(...) и dup(...).

1.7 Монтирование и демонтирование ФС

Все ОС имеют системные вызовы, предназначенные для подключения и отключения внешних файловых систем к корневой файловой системе.

Стандарт POSIX определяет эти функции как:

#include <sys/mount.h>

int mount(const char *source, const char *target, unsigned mountflags);

int umount(const char *special);

где source — раздел блочного устройства или файл, содержащий файловую систему, известную ядру ОС;

target — директория, присутствующая в файловой системе, к которой монтируется внешняя файловая система;

mountflags — опции, с которыми монтируется файловая система;

special — это source или target, которые специфицируют точку монтирования.

При удачном завершении вызова возращаемое значение равно нулю.

При ошибке возвращается -1, а переменной errno присваивается номер ошибки.

Замечание

В предыдущих темах были подробно изучены утилиты mount и umount, предназначенные для аналогичных целей.

Программисту, без большой необходимости, не следует не следует использовать эти системные вызовы, потому что:

основные привилегии создания структуры ФС и защита такой структуры обеспе-

чивается администратором ОС, что исключает необходимость оперативного монтирования и демонтирования из программы;

синтаксис и реализация этих системных вызовов всегда специфичен для конкретной ОС, можно убедится при изучении man 2 mount и man 2 umount;

в крайнем случае, можно с помощью дочернего процесса вызвать «родные» утилиты ОС, что повысит переносимость разработанного ПО.

48

1.8 Ссылки на имена файлов

Данный подраздел является завершающим в теоретической части темы №7 «Подсистема управления вводом-выводом».

Здесь мы изучим материал касающийся вопросов формирования и использования имен файлов.

Программисту и обычному пользователю, любая отдельная файловая система ОС представляется в виде иерархии имен файлов, в которой особое место занимают

файлы типа директорий (каталогов):

именно с корневого каталога начинается каждая файловая система, разме-

щенная на внешних носителях информации; например, в файловой системе EXT2FS, изученной в теме 4 [6, подраздел 1.5], за корневым каталогом закреплен индексный дескриптор (i-узел, i-node) с номером 2;

именно к каталогам монтируются разные файловые системы, образуя еди-

ное дерево файловой системы ОС, вершина которой (корневой каталог VFS) формируется в ядре ОС;

именно в записях каталогов имя файла (name) связано с i-узлом (inode).

Встандарте POSIX для создания и удаления каталогов определяет два системных вызова: mkdir(...) и rmdir(...).

Системный вызов mkdir(...) имеет синтаксис:

#include <sys/stat.h>

#include <sys/types.h>

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

где pathname — имя создаваемой каталога;

mode — задает права доступа, которые получит зданный каталог; эти права стандартным образом модифицируются с помощью umask: права доступа оказываются равны mode & ~umask.

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

EPERM - файловая система, содержащая pathname, не поддерживает создание каталогов;

EEXIST pathname уже существует: это не обязательно каталог, а например, символической ссылка;

EFAULT pathname указывает за пределы доступного адресного пространства;

EACCES — родительский каталог не позволяет запись, или же один из каталогов, перечисленных в pathname, не позволяет поиск (выполнение);

ENAMETOOLONG pathname слишком длинно;

49

ENOENT — компонент пути pathname не существует или является висячей символической ссылкой;

ENOTDIR — компонент пути, использованный как каталог в pathname, в действительности таковым не является;

ENOMEM — ядру не хватило памяти;

EROFS — файл находится на файловой системе, смонтированной только для чтения;

ELOOP pathname является зацикленной символической ссылкой, то есть при подстановке возникает ссылка на неё саму;

ENOSPC — на устройстве, содержащем pathname, нет места для создания

новой записи в каталоге; это может произойти также, если исчерпана квота дискового пространства пользователя.

Замечание

Создать файл каталог можно и спомощью системного вызова open(...) или, например, mknod(...), но такой каталог будет «неполноценным», поскольку в нем будут отсутствовать файлы «.» и «..».

Системный вызов rmdir(...) имеет синтаксис:

#include <unistd.h>

int rmdir(const char *pathname);

где pathname — имя удаляемого каталога, который должен быть пустым, кроме файлы «.» и «..».

В случае успеха возвращается ноль. При ошибке возвращается -1, а errno устанавливается следующим образом:

EPERM — файловая система, содержащая pathname, не поддерживает удаление каталогов;

EFAULT pathname указывает за пределы доступного адресного пространства;

EACCES — доступ на запись в каталоге, содержащем pathname, не разрешен

для текущего эффективного идентификатора пользователя, или же один из каталогов в pathname не разрешает поиск (выполнение);

EPERM — в правах доступа к каталогу, содержащему pathname, включен бит "липкости" (S_ISVTX), а эффективный идентификатор пользователя не совпадает ни с владельцем удаляемого файла, ни с владельцем каталога, который его содержит, или же pathname является каталогом;

ENAMETOOLONG pathname слишком длинно;

ENOENT — одна из частей пути pathname не существует или является висячей символической ссылкой;

ENOTDIR — компонент пути, использованный как каталог в pathname, в действительности таковым не является;

ENOTEMPTY pathname содержит какие-либо еще, кроме записей . или .. ;

50

EBUSY pathname является текущим рабочим или корневым каталогом какого-либо процесса;

ENOMEM — ядру не хватило памяти;

EROFS — файл находится на файловой системе, смонтированной только для чтения;

ELOOP pathname является зацикленной символической ссылкой, то есть при подстановке возникает ссылка на неё саму.

Для удаления имен файлов, в стандарте POSIX, предусмотрен системный вызов unlink(...), имеющий следующий синтаксис:

#include <unistd.h>

int unlink(const char *pathname);

где pathname — имя удаляемого файла.

В случае успеха возвращается ноль. При ошибке возвращается -1, а errno устанавливается следующим образом:

EACCES — доступ на запись в каталог, содержащий pathname не разрешён

для эффективного идентифкатора пользователя текущего процесса или права на один из каталогов в pathname не позволяют поиск (выполнение);

EPERM или EACCES — каталог, содержащий pathname имеет установленный sticky-бит (S_ISVTX) и эффективный идентификатор пользователя текущего процесса не совпадает и с идентификатором пользователя удаляемого файла и с идентификатором пользователя каталога, в котором содержится этот файл;

EPERM (только в Linux) — файловая система не разрешает удаление файлов;

EPERM — система не разраешает удаление каталогов или удаление каталогов

требует превилегий, которыми не обладает текущий процесс: этот код ошибки появился в POSIX;

EISDIR pathname указывает на каталог: это не-POSIX значение, возвращаемое в Linux начиная с 2.1.132;

EBUSY (нет в Linux) — файл pathname не может быть удалён, потому что он

используется системой или другим процессом и текущая реализация вызова считает, что это ошибка;

EFAULT pathname указывает за пределы доступного вам адресного пространства;

ENAMETOOLONG pathname имеет слишком большую длину;

ENOENT — какой-либо компонент в pathname не существует или является битой ссылкой или в pathname пусто;

ENOTDIR — какой-либо компонент, используемый как каталог в pathname, на самом деле не является каталогом;

ENOMEM — не хватает памяти;

EROFS pathname указывает на файл в файловой системе доступной только для чтения;

ELOOP — слишком много символьных ссылок было обнаружено при транс-

Источник: https://studfile.net/preview/16438530/