open(2) | System Calls Manual | open(2) |
open, openat, creat - открывает и, возможно, создаёт файл
Standard C library (libc, -lc)
#include <fcntl.h>
int open(const char *pathname, int flags); int open(const char *pathname, int flags, mode_t mode);
int creat(const char *pathname, mode_t mode);
int openat(int dirfd, const char *pathname, int flags); int openat(int dirfd, const char *pathname, int flags, mode_t mode);
/* Documented separately, in openat2(2): */ int openat2(int dirfd, const char *pathname, const struct open_how *how, size_t size);
openat():
Since glibc 2.10:
_POSIX_C_SOURCE >= 200809L
Before glibc 2.10:
_ATFILE_SOURCE
Системный вызов open() открывает файл, на который указывает pathname. Если заданный файл не существует, то он может быть создан open() (если в flags задан O_CREAT).
The return value of open() is a file descriptor, a small, nonnegative integer that is an index to an entry in the process's table of open file descriptors. The file descriptor is used in subsequent system calls (read(2), write(2), lseek(2), fcntl(2), etc.) to refer to the open file. The file descriptor returned by a successful call will be the lowest-numbered file descriptor not currently open for the process.
По умолчанию, новый файловый дескриптор остаётся открытым при вызове execve(2) (т. е., флаг FD_CLOEXEC файлового дескриптора, описанный в fcntl(2), изначально сброшен; для изменения поведения по умолчанию можно использовать флаг O_CLOEXEC, он описан далее). Файловое смещение устанавливается на начало файла (см. lseek(2)).
Вызов open() создаёт новое открытое файловое описание — запись в системной таблице открытых файлов. В этой записи хранится смещение и флаги состояния файла (смотрите ниже). Файловый дескриптор — это ссылка на открытое файловое описание; с этой ссылкой ничего не происходит при последующем удалении pathname или переуказании имени на другой файл. Дополнительную информацию об открытых файловых описаниях смотрите в разделе ЗАМЕЧАНИЯ.
Параметр flags должен содержать один из следующих режимов доступа: O_RDONLY (только для чтения), O_WRONLY (только для записи) или O_RDWR (для чтения и записи).
Также в flags можно указывать флаги создания и состояния файла, объединяя их битовой операцией ИЛИ. Флаги создания файла: O_CLOEXEC, O_CREAT, O_DIRECTORY, O_EXCL, O_NOCTTY, O_NOFOLLOW, O_TMPFILE и O_TRUNC. Флаги состояния файла — все оставшиеся, перечислены ниже. Различие между двумя этими группами в том, что флаги создания влияют на работу самой операции открытия, а флаги состояния влияют на работу последующих операций ввода-вывода. Флаги состояния можно запросить и (в некоторых случаях) изменить; смотрите fcntl(2).
Полный список флагов создания и флагов состояния файла:
char buf[PATH_MAX]; fd = open("some_prog", O_PATH); snprintf(buf, PATH_MAX, "/proc/self/fd/%d", fd); execl(buf, "some_prog", (char *) NULL);
char path[PATH_MAX]; fd = open("/path/to/dir", O_TMPFILE | O_RDWR,
S_IRUSR | S_IWUSR); /* File I/O on 'fd'... */ linkat(fd, "", AT_FDCWD, "/path/for/file", AT_EMPTY_PATH); /* If the caller doesn't have the CAP_DAC_READ_SEARCH
capability (needed to use AT_EMPTY_PATH with linkat(2)),
and there is a proc(5) filesystem mounted, then the
linkat(2) call above can be replaced with: snprintf(path, PATH_MAX, "/proc/self/fd/%d", fd); linkat(AT_FDCWD, path, AT_FDCWD, "/path/for/file",
AT_SYMLINK_FOLLOW); */
Вызов creat() эквивалентен вызову open() с значением flags O_CREAT|O_WRONLY|O_TRUNC.
Системный вызов openat() работает также как системный вызов open(), за исключением случаев, описанных здесь.
The dirfd argument is used in conjunction with the pathname argument as follows:
If the pathname given in pathname is relative, and dirfd is not a valid file descriptor, an error (EBADF) results. (Specifying an invalid file descriptor number in dirfd can be used as a means to ensure that pathname is absolute.)
The openat2(2) system call is an extension of openat(), and provides a superset of the features of openat(). It is documented separately, in openat2(2).
On success, open(), openat(), and creat() return the new file descriptor (a nonnegative integer). On error, -1 is returned and errno is set to indicate the error.
Вызовы open(), openat() и creat() могут завершаться со следующими ошибками:
openat() was added in Linux 2.6.16; library support was added in glibc 2.4.
open(), creat() SVr4, 4.3BSD, POSIX.1-2001, POSIX.1-2008.
openat(): POSIX.1-2008.
openat2(2) is Linux-specific.
Флаги O_DIRECT, O_NOATIME, O_PATH и O_TMPFILE есть только в Linux. Для их определения может потребоваться задать _GNU_SOURCE.
Флаги O_CLOEXEC, O_DIRECTORY и O_NOFOLLOW не указаны в POSIX.1-2001, но есть в POSIX.1-2008. Начиная с glibc 2.12, их определения можно получить определив или _POSIX_C_SOURCE со значением большим и равным 200809L, или _XOPEN_SOURCE со значением большим и равным 700. В glibc 2.11 и старее их определения можно получить определив _GNU_SOURCE.
Как было отмечено в feature_test_macros(7), такие макросы тестирования свойств как _POSIX_C_SOURCE, _XOPEN_SOURCE и _GNU_SOURCE, должны быть определены до включения любых заголовочных файлов.
В Linux флаг O_NONBLOCK иногда используется в случаях, когда файл только открыть, и не обязательно будет производиться чтение или запись. Например, он может использоваться для открытия устройства, чтобы получить его файловый дескриптор для использования в ioctl(2).
Результат работы комбинации флагов O_RDONLY | O_TRUNC в разных реализациях разный (нигде не определён). Во многих системах файл усекается.
Заметим, что open() может открывать специальные файлы устройств, но creat() не может их создавать; вместо этого используйте mknod(2).
Если файл только что был создан, его поля st_atime, st_ctime, st_mtime (время последнего доступа, последней смены состояния и последнего изменения, соответственно; см. stat(2)) устанавливаются в значение текущего времени, и оно совпадает с полями st_ctime и st_mtime родительского каталога. Или же, если файл изменяется из-за установленного флага O_TRUNC, то его поля st_ctime и st_mtime устанавливаются в значение текущего времени.
Файлы в каталоге /proc/[pid]/fd представляют открытые файловые дескрипторы процесса с PID равным pid. Файлы в каталоге /proc/[pid]/fdinfo представляют дополнительную информацию об этих файловых дескрипторах. Подробное описание данных каталогов можно найти в proc(5).
В заголовочном файле Linux <asm/fcntl.h> не определён O_ASYNC; вместо него определён синоним FASYNC (как в BSD).
The term open file description is the one used by POSIX to refer to the entries in the system-wide table of open files. In other contexts, this object is variously also called an "open file object", a "file handle", an "open file table entry", or—in kernel-developer parlance—a struct file.
При создании копии файлового дескриптора (с помощью dup(2) или подобного вызова), копия ссылается на то же открытое файловое описание что и изначальный файловый дескриптор, и, следовательно, два файловых дескриптора имеют общее файловое смещение и флаги состояния файла. Такая общность может также быть у двух процессов: процесс-потомок, создаваемый fork(2), наследует копии файловых дескрипторов своего родителя и эти копии ссылаются на те же открытые файловые описания.
При каждом open() файла создаётся новое файловое описание; таким образом, может быть несколько открытых файловых описаний, соответствующих inode файла.
Для проверки того, что два файловых дескриптора (одного процесса или разных) ссылаются на одно файловое описание, в Linux можно использовать вызов kcmp(2) с операцией KCMP_FILE.
В POSIX.1-2008 способность «синхронизированного ввода-вывода» описана в виде различных вариантов синхронизированного ввода-вывода и для open() определяет флаги управления поведением O_SYNC, O_DSYNC и O_RSYNC. Независимо от того, имеется ли в реализации данная способность, она должна, как минимум, поддерживать использование флага O_SYNC для обычных файлов.
В Linux реализованы O_RSYNC и O_DSYNC, но не O_RSYNC. Несколько некорректно в glibc определён O_RSYNC со значением как у O_SYNC (O_RSYNC определён в заголовочном файле Linux <asm/fcntl.h> для HP PA-RISC, но не используется).
Флаг O_SYNC предоставляет выполнение целостного синхронизованного ввод-вывода file, то есть операции записи передают данные и все связанные метаданные в задействованное аппаратное обеспечение. Флаг O_DSYNC предоставляет выполнение целостного синхронизованного ввод-вывода data, то есть операции записи передают данные в задействованное аппаратное обеспечение, но обновляются только те метаданные, которые требуются для выполнения последующего чтения. Полнота целостности данных может сократить количество дисковых операций, которые требуются приложениям, не требующим гарантий целостности файлов.
Чтобы понять разницу между двумя типами обеспечения целостности рассмотрим две части метаданных файла: метка времени последнего изменения файла (st_mtime) и длину файла. Все операции записи обновляют метку времени последнего изменения файла, но только при записи, которая добавляет данные в конец файла, будет изменена длина файла. Метка времени последнего изменения файла не требуется для корректного чтения файла, чего не скажешь о длине. Таким образом, O_DSYNC гарантирует только запись обновлений о метаданных длины файла (в то время как O_SYNC также всегда записывает метаданные о метки времени последнего изменения файла).
До Linux версии 2.6.33 в Linux реализован только флаг O_SYNC для open(). Однако, когда этот флаг указан, большинство файловых систем в действительности предоставляют эквивалент выполнения целостности синхронизированного ввода-вывода data (т. е., на самом деле O_SYNC был реализован как эквивалент O_DSYNC).
Since Linux 2.6.33, proper O_SYNC support is provided. However, to ensure backward binary compatibility, O_DSYNC was defined with the same value as the historical O_SYNC, and O_SYNC was defined as a new (two-bit) flag value that includes the O_DSYNC flag value. This ensures that applications compiled against new headers get at least O_DSYNC semantics before Linux 2.6.33.
Since glibc 2.26, the glibc wrapper function for open() employs the openat() system call, rather than the kernel's open() system call. For certain architectures, this is also true before glibc 2.26.
В протоколе, по которому работает NFS, существует множество недоработок, оказывающих влияние на многое, в том числе на работу с O_SYNC и O_NDELAY.
В файловых системах NFS с включённым проецированием UID, open() может вернуть файловый дескриптор, но, например, запросы read(2) будут отклонены с ошибкой EACCES. Это происходит из-за того, что клиент выполняет open() проверяя одни права, но сервер выполняет проецирование UID только при запросах чтения и записи.
Открытие на чтение или запись конца FIFO приводит к блокировке то тех пор, пока другой конец не также не будет открыт (другим процессом или нитью). Подробности смотрите в fifo(7).
В отличие от других значений, указываемых в flags, значения режима доступа O_RDONLY, O_WRONLY и O_RDWR, не определяются отдельными битами. Точнее, они задаются двумя первыми битами flags, и имеют значения 0, 1 и 2, соответственно. Другими словами, комбинация O_RDONLY | O_WRONLY приводит к логической ошибке и точно не работает как O_RDWR.
В Linux зарезервирован специальный нестандартный режим доступа 3 (11 двоичное) в flags, при котором: проверяются права на чтение и запись к файлу и возвращается файловый дескриптор, который не может использоваться для чтения или записи. Данный нестандартный режим доступа используется некоторыми драйверами Linux для получения файлового дескриптора, который будет использоваться в ioctl(2) только для специальных операций с устройством.
openat() and the other system calls and library functions that take a directory file descriptor argument (i.e., execveat(2), faccessat(2), fanotify_mark(2), fchmodat(2), fchownat(2), fspick(2), fstatat(2), futimesat(2), linkat(2), mkdirat(2), mknodat(2), mount_setattr(2), move_mount(2), name_to_handle_at(2), open_tree(2), openat2(2), readlinkat(2), renameat(2), renameat2(2), statx(2), symlinkat(2), unlinkat(2), utimensat(2), mkfifoat(3), and scandirat(3)) address two problems with the older interfaces that preceded them. Here, the explanation is in terms of the openat() call, but the rationale is analogous for the other interfaces.
Во-первых, openat() позволяет приложению избежать условий состязательности, которые могут возникнуть, когда open() открывает файлы в каталогах, отличных от текущего рабочего каталога. Состязательность возникает из-за того, что один из компонентов префикса каталога, указанного open(), может измениться одновременно с вызовом open(). Например, предположим, что мы хотим создать файл dir1/dir2/xxx.dep и существует файл dir1/dir2/xxx. Проблема находится между шагами проверки существования и созданием файла, указываемые dir1 или dir2 (которые могут быть символическими ссылками) места могут измениться. Этой состязательности можно избежать открыв файловый дескриптор каталога назначения, и затем указав этот файловый дескриптор в аргументе dirfd вызова (скажем) fstatat(2) и openat(). Также, использование файлового дескриптора dirfd имеет другие преимущества:
Во-вторых, openat() позволяет реализовать отдельный «текущий рабочий каталог» для каждой нити посредством файлового дескриптора, сопровождаемого приложением. Эта возможность также может быть получена с использованием /proc/self/fd/dirfd, но менее эффективно.
The dirfd argument for these APIs can be obtained by using open() or openat() to open a directory (with either the O_RDONLY or the O_PATH flag). Alternatively, such a file descriptor can be obtained by applying dirfd(3) to a directory stream created using opendir(3).
When these APIs are given a dirfd argument of AT_FDCWD or the specified pathname is absolute, then they handle their pathname argument in the same way as the corresponding conventional APIs. However, in this case, several of the APIs have a flags argument that provides access to functionality that is not available with the corresponding conventional APIs.
The O_DIRECT flag may impose alignment restrictions on the length and address of user-space buffers and the file offset of I/Os. In Linux alignment restrictions vary by filesystem and kernel version and might be absent entirely. The handling of misaligned O_DIRECT I/Os also varies; they can either fail with EINVAL or fall back to buffered I/O.
Since Linux 6.1, O_DIRECT support and alignment restrictions for a file can be queried using statx(2), using the STATX_DIOALIGN flag. Support for STATX_DIOALIGN varies by filesystem; see statx(2).
Some filesystems provide their own interfaces for querying O_DIRECT alignment restrictions, for example the XFS_IOC_DIOINFO operation in xfsctl(3). STATX_DIOALIGN should be used instead when it is available.
If none of the above is available, then direct I/O support and alignment restrictions can only be assumed from known characteristics of the filesystem, the individual file, the underlying storage device(s), and the kernel version. In Linux 2.4, most filesystems based on block devices require that the file offset and the length and memory address of all I/O segments be multiples of the filesystem block size (typically 4096 bytes). In Linux 2.6.0, this was relaxed to the logical block size of the block device (typically 512 bytes). A block device's logical block size can be determined using the ioctl(2) BLKSSZGET operation or from the shell using the command:
blockdev --getss
Ввод-вывод с O_DIRECT никогда не должен запускаться одновременно с системным вызовом fork(2), если буфер памяти является закрытым отображением (т. е., любым отображениям, созданным с помощью mmap(2) с флагом MAP_PRIVATE; к ним относится память, выделенная под кучу и статически выделенные буферы). Любой подобный ввод-вывод, предоставленный через асинхронный интерфейс или из другой нити процесса, должен выполниться полностью до вызова fork(2). В противном случае, может произойти повреждение данных и непредсказуемое поведение в процессе родителя и потомка.Данное ограничение не действует, если буфер памяти для ввода-вывода с O_DIRECT был создан с помощью shmat(2) или mmap(2) с флагом MAP_SHARED. И при этом это ограничение не действует, когда буфер памяти был помечен (advised) как MADV_DONTFORK с помощью madvise(2), если точно известно, что он не будет доступен потомку после fork(2).
Флаг O_DIRECT появился в SGI IRIX, где ограничения на выравнивание подобны Linux 2.4. В IRIX также есть вызов fcntl(2) для запроса значений соответствующего выравнивания и размеров. В FreeBSD 4.x появился флаг с таким же именем, но без ограничений на выравнивание.
O_DIRECT support was added in Linux 2.4.10. Older Linux kernels simply ignore this flag. Some filesystems may not implement the flag, in which case open() fails with the error EINVAL if it is used.
Приложения должны избегать смешивания O_DIRECT и обычных операций ввода-вывода в один файл и особенно перекрывать байтовые области. Даже когда файловая система правильно обрабатывает проблемы с когерентностью в такой ситуации, общая пропускная способность ввода-вывода, вероятно, будет медленнее чем при использовании какого-то одного из этих режимов отдельно. Аналогично приложения должны избегать смешивания mmap(2) и прямого ввода-вывода для одинаковых файлов.
Поведение O_DIRECT на NFS отличается от локальных файловых систем. Старые ядра и ядра, настроенные определёнными способами, могут не поддерживать такую комбинацию. Протокол NFS не поддерживает передачу флага на сервер, поэтому ввод-вывод с O_DIRECT будет пропускать кэширование страниц только на клиенте; сервер всё равно может выполнить кэширование ввода-вывода. Клиент просит сервер выполнять операции ввода-вывода синхронно для сохранения синхронной семантики O_DIRECT. Некоторые серверы будут выполнять это плохо при определённых условиях, особенно если размер данных ввода-вывода невелик. Некоторые серверы также могут быть настроены на отправку ложного ответа клиентам о том, что ввод-вывод произведён на носитель; это позволяет избежать потери производительности, но есть риск потери целостности данных в случае проблем с электропитанием сервера. В Linux клиент NFS не устанавливает ограничений по выравниванию при вводе-выводе с O_DIRECT.
Флаг O_DIRECT является потенциально мощным инструментом, который нужно использовать с осторожностью. Рекомендуется, чтобы приложения считали использование O_DIRECT как параметр производительности, который по умолчанию выключен.
На данный момент невозможно включить сигнальное управление вводом-выводом, указав O_ASYNC при вызове open(); чтобы установить этот флаг используйте fcntl(2).
Для определения поддержки ядром O_TMPFILE нужно проверять два различных кода ошибок — EISDIR и ENOENT.
При указании флагов O_CREAT и O_DIRECTORY в flags, и при этом указанный в pathname файл не существует, open() создаст обычный файл (то есть флаг O_DIRECTORY будет проигнорирован).
chmod(2), chown(2), close(2), dup(2), fcntl(2), link(2), lseek(2), mknod(2), mmap(2), mount(2), open_by_handle_at(2), openat2(2), read(2), socket(2), stat(2), umask(2), unlink(2), write(2), fopen(3), acl(5), fifo(7), inode(7), path_resolution(7), symlink(7)
Русский перевод этой страницы руководства был сделан Azamat Hackimov <azamat.hackimov@gmail.com>, Konstantin Shvaykovskiy <kot.shv@gmail.com>, Yuri Kozlov <yuray@komyakino.ru> и Иван Павлов <pavia00@gmail.com>
Этот перевод является бесплатной документацией; прочитайте Стандартную общественную лицензию GNU версии 3 или более позднюю, чтобы узнать об условиях авторского права. Мы не несем НИКАКОЙ ОТВЕТСТВЕННОСТИ.
Если вы обнаружите ошибки в переводе этой страницы руководства, пожалуйста, отправьте электронное письмо на man-pages-ru-talks@lists.sourceforge.net.
5 февраля 2023 г. | Linux man-pages 6.03 |