Системный вызов open linux
Вызов open() используется, чтобы преобразовать путь к файлу в описатель файла (небольшое неотрицательно целое число, которое используется с вызовами read , write и т.п. при последующем вводе-выводе). Если системный вызов завершается успешно, возвращенный файловый описатель является наименьшим описателем, который еще не открыт процессом. В результате этого вызова появляется новый открытый файл, не разделяемый никакими процессами (разделяемые открытые файлы могут возникнуть, когда посылается системный вызов fork (2)). Новый описатель файла будет оставаться открытым при выполнении функции exec (2) (смотри описание fcntl (2)). Указатель устанавливается в начале файла. Параметр flags — это флаги O_RDONLY , O_WRONLY или O_RDWR , открывающие файлы «только для чтения», «только для записи» и для чтения и записи соответственно, которые собрираются с помощью побитовой операции OR из таких значений, как: O_CREAT (если файл не существует, то он будет создан. Владелец (идентификатор пользователя) файла устанавливается в значение эффективного идентификатора пользователя процесса. Группа (идентификатор группы) устанавливается либо в значение эффективного идентификатора группы процесса, либо в значение идентификатора группы родительского каталога (зависит от типа файловой системы, параметров подсоединения (mount) и режима родительского каталога, см. например, параметры подсоединения bsdgroups и sysvgroups файловой системы ext2, как описано в руководстве mount (8)).); O_EXCL (Если он используется совместно с O_CREAT , то при наличии уже созданного файла вызов open завершится с ошибкой. В этом состоянии, при существующей символьной ссылке не обращается внимание, на что она указывает.); O_EXCL (Оно не работает в файловых системах NFS, а в программах, использующих этот флаг для блокировки, возникнет «race condition». Решение для атомарной блокировки файла: создать файл с уникальным именем в той же самой файловой системе (это имя может содержать, например, имя машины и идентификатор процесса), используя link (2), чтобы создать ссылку на файл блокировки. Если link() возвращает значение 0, значит, блокировка была успешной. В противном случае используйте stat (2), чтобы убедиться, что количество ссылок на уникальный файл возросло до двух. Это также означает, что блокировка была успешной); O_NOCTTY (если pathname указывает на терминальное устройство — см. tty (4) —, то оно не станет терминалом управления процесса, даже если процесс такового не имеет); O_TRUNC (если файл уже существует, он является обычным файлом и режим позволяет записывать в этот файл (т.е. установлено O_RDWR или O_WRONLY), то его длина будет урезана до нуля. Если файл является каналом FIFO или терминальным устройством, то этот флаг игнорируется. Иначе действие флага O_TRUNC не определено. O_APPEND (Файл открывается в режиме добавления. Перед каждой операцией write файловый указатель будет устанавливаться в конце файла, как если бы использовался lseek ); O_APPEND (может привести к повреждению файлов в системе NFS, если несколько процессов одновременно добавляют данные в один файл. Это происходит из-за того, что NFS не поддерживает добавление в файл данных, поэтому ядро на машине-клиенте должно эмулировать эту поддержку); O_NONBLOCK или O_NDELAY (если возможно, то файл открывается в режиме non-blocking. Ни open , ни другие последующие операции над возвращаемым описателем файла не заставляют вызывающий процесс ждать. Для работы с каналами FIFO см. fifo (4). Этот режим не оказывает никакого действия на не-FIFO файлы.); O_SYNC (Файл открывается в режиме синхронного ввода-вывода. Все вызовы write для соответствующего описателя файла блокируют вызывающий процесс до тех пор, пока данные не будут физически записаны. Однако, Вам необходимо прочитать раздел ОГРАНИЧЕНИЯ); O_NOFOLLOW (если pathname — это символьная ссылка, то open содержит код ошибки. Это расширение FreeBSD, которое было добавлено в Linux версии 2.1.126. Все прочие символьные ссылки в имени будут обработаны как обычно. Заголовочные файлы из glibc версии 2.0.100 (и более поздних) содержат определение этого флага; ядра версий, более ранних, чем 2.1.126, игнорируют этот флаг ); O_DIRECTORY (Если pathname не является каталогом, то open укажет на ошибку. Этот флаг используется только в Linux и был добавлен к ядру 2.1.126, чтобы избежать проблем с «отказом от обслуживания», если opendir (2) был вызван для канала FIFO или ленточного устройства. Этот флаг не следует использовать вне реализации opendir ); O_LARGEFILE (На 32-битных системах, поддерживающих файловые системы (Large), этот флаг позволяет открывать файлы, длина которых больше 31-ого бита.
Некоторые из вышеописанных флагов могут быть изменены с помощью fctnl после открытия файла. Аргумент mode задает права доступа, которые используются в случае создания нового файла. Они модифицируются обычным способом, с помощью umask процесса; права доступа созданного файла равны (mode & ~umask) . Обратите внимание, что этот режим применяется только к правам создаваемого файла; open создает файл только для чтения, но может вернуть дескриптор с установленными флагами для чтения и записи.
Следующие символьные константы можно использовать в mode : S_IRWXU (00700 пользователь (владелец файла) имеет права на чтение, запись и выполнение
файла); S_IRUSR (S_IREAD) (00400 пользователь имеет права на чтение файла); S_IWUSR (S_IWRITE) (00200 пользователь имеет права на запись информации в файл); S_IXUSR (S_IEXEC) (00100 пользователь имеет права на выполнение файла); S_IRWXG (00070 группа имеет права на чтение, выполнение файла и запись в него информации); S_IRGRP (00040 группа имеет права на чтение файла); S_IWGRP (00020 группа имеет права на запись информации в файл); S_IXGRP (00010 группа имеет права на выполнение
файла); S_IRWXO (00007 все остальные имеют права на чтение, выполнение файла и запись в него информации); S_IROTH (00004 все остальные имеют права на чтение файла); S_IWOTH (00002 все остальные имеют права на запись информации в файл); S_IXOTH (00001 все остальные имеют права на выполнение
файла).
mode всегда должен быть указан при использовании O_CREAT ; во всех остальных случаях этот параметр игнорируется. creat эквивалентен open с flags , которые равны O_CREAT | O_WRONLY | O_TRUNC .
ВОЗВРАЩАЕМЫЕ ЗНАЧЕНИЯ
open и creat возвращают новый описатель файла или -1 в случае ошибки (в этом случае
значение переменной errno устанавливается должным образом). Заметьте, что open может открывать файлы устройств, но creat не может создавать их, поэтому используйте для создания функцию mknod (2).
В файловых системах NFS, в которых идентификаторы пользователей могут быть преобразованы, open может вернуть файловый описатель, но, например, read (2) вернет ошибку EACCES из-за того, что клиент выполняет команду open , проверяя права доступа (а преобразование идентификаторов производится сервером при запросах на чтение и запись).
Если создается файл, то его время последнего доступа, создания и модификации устанавливаются в значение текущего времени, а также устанавливаются поля времени модификации и создания родительского каталога. Иначе, если файл изменяется с флагом O_TRUNC, то его время создания и время изменения устанавливаются в значение текущего времени.
НАЙДЕННЫЕ ОШИБКИ
EEXIST pathname уже существует, но были использованы O_CREAT и O_EXCL . EISDIR Тип доступа подразумевает запись, а pathname указывает на каталог, (то есть установлены O_WRONLY или O_RDWR ). EACCES Запрошенный доступ к файлу не разрешен, или один из каталогов в pathname не позволяет поиск (выполнение) файла, файл еще не существует, или доступ для записи в родительский каталог не разрешен. ENAMETOOLONG pathname является слишком длинным. ENOENT O_CREAT не установлен, а указанный файл не существует. Или не существует каталог в пути pathname , или он является неверной символьной ссылкой. ENOTDIR Компонент, который обозначен как каталог в pathname , таковым не является, или был указан флаг O_DIRECTORY , а pathname не является каталогом. ENXIO Установлены O_NONBLOCK | O_WRONLY, файл является каналом FIFO, но нет процессов, которые открыли этот канал для чтения. Возможно также, что файл является файлом устройства, но соответствующее устройство не установлено. ENODEV pathname ссылается на файл устройства, но соответствующего устройства не существует. (Это ошибка в ядре Linux: должен возвращаться параметр ENXIO). EROFS Был запрошен доступ к записи, а pathname ссылается на файл, находящийся в системе, предназначенной только для чтения. ETXTBSY pathname ссылается на файл, который в настоящее время исполняется, и был запрошен доступ к записи. EFAULT pathname указывает на каталог за пределами доступного адресного пространства. ELOOP Слишком много символьных ссылок составляют pathname , или был указан флаг O_NOFOLLOW , а pathname является символьной ссылкой. ENOSPC pathname должен был указать на устройство, в котором отсутствует место для нового файла. ENOMEM Недостаточно памяти в системе. EMFILE Процесс уже открыл максимально допустимое количество файлов. ENFILE Достигнут предел общего количества файлов, открытых в системе.
СООТВЕТСТВИЕ СТАНДАРТАМ
SVr4, SVID, POSIX, X/OPEN, BSD 4.3. Флаги O_NOFOLLOW и O_DIRECTORY являются специфичными для системы Linux. Они могут опреляться макросом _GNU_SOURCE .
Эффект (неопределенный изначально) от O_RDONLY | O_TRUNC отличается в разных реализациях. Во многих системах файл в действительности обрезается.
Флаг O_DIRECT был представлен в SGI IRIX, где он имеет похожие ограничения по принаджености, как и в Linux. IRIX также имеет вызов fcntl(2) для очередей с выравниванием и размерами. FreeBSD 4.x имеет флаг с таким же именем, но без ограничений на выравнивание. В Linux была добавлена поддержка с ядра версии 2.4.10. Старые ядра Linux просто игнорируют этот флаг.
НАЙДЕННЫЕ ОШИБКИ
«Меня всего беспокоило кое-что относительно O_DIRECT — то, что вообще в целом этот интерфейс просто идиотичен. Создается впечатление, что он как-бы был создан сумасшедшей обезьяной для работы с высокими материями, управляющими разумом.» — Linus
НАЙДЕННЫЕ ОШИБКИ И ОГРАНИЧЕНИЯ
В протоколе, по которому работает NFS, существует множество недоработок, оказывающих влияние на O_SYNC и O_NDELAY . POSIX предоставляет три разных варианта синхронного ввода-вывода, соответствующего флагам O_SYNC , O_DSYNC и O_RSYNC . В настоящее время (версия 2.1.130) все флаги являются похожими на флаги Linux.