open(2) - Linux 手册页
名称
open, creat - 打开并可能创建一个文件或设备概要
#include <sys/types.h>#include <sys/stat.h>#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);
描述
默认情况下,新的文件描述符在执行 execve(2) 后保持打开状态(即,fcntl(2) 中描述的 FD_CLOEXEC 文件描述符标志最初是禁用的;可以使用下述 O_CLOEXEC 标志来更改此默认设置)。文件偏移量被设置为文件的开头(参见 lseek(2))。
调用 open() 会创建一个新的打开文件描述(open file description),即系统范围内打开文件表中的一个条目。此条目记录了文件偏移量和文件状态标志(可通过 fcntl(2) 的 F_SETFL 操作修改)。文件描述符是对这些条目之一的引用;如果随后删除了 pathname 或将其修改为指向另一个文件,则此引用不受影响。新的打开文件描述最初不与其他任何进程共享,但通过 fork(2) 可能会产生共享。
参数 flags 必须包含以下访问模式之一:O_RDONLY、O_WRONLY 或 O_RDWR。它们分别请求以只读、只写或读写方式打开文件。
此外,零个或多个文件创建标志和文件状态标志可以与 flags 进行按位或(or)运算。文件创建标志有 O_CLOEXEC、O_CREAT、O_DIRECTORY、O_EXCL、O_NOCTTY、O_NOFOLLOW、O_TRUNC 和 O_TTY_INIT。文件状态标志是下面列出的所有其余标志。这两组标志的区别在于,文件状态标志可以使用 fcntl(2) 进行检索,并在某些情况下进行修改。文件创建标志和文件状态标志的完整列表如下:
- O_APPEND
- 以追加模式打开文件。在每次 write(2) 之前,文件偏移量会被定位到文件末尾,就像使用 lseek(2) 一样。如果在 NFS 文件系统上多个进程同时向一个文件追加数据,O_APPEND 可能会导致文件损坏。这是因为 NFS 不支持对文件的追加操作,客户端内核必须对其进行模拟,而这无法在没有竞争条件的情况下完成。
- O_ASYNC
- 启用信号驱动的 I/O:当此文件描述符上可以进行输入或输出时,生成一个信号(默认为 SIGIO,但可通过 fcntl(2) 更改)。此功能仅适用于终端、伪终端、套接字以及(自 Linux 2.6 起)管道和 FIFO。更多详细信息请参见 fcntl(2)。
- O_CLOEXEC (自 Linux 2.6.23 起)
- 为新的文件描述符启用 close-on-exec 标志。指定此标志允许程序避免额外的 fcntl(2) F_SETFD 操作来设置 FD_CLOEXEC 标志。此外,在某些多线程程序中使用此标志至关重要,因为仅使用单独的 fcntl(2) F_SETFD 操作来设置 FD_CLOEXEC 标志,不足以避免线程在打开文件描述符的同时,另一个线程执行 fork(2) 加 execve(2) 所产生的竞争条件。
- O_CREAT
- 如果文件不存在,则创建它。文件的所有者(用户 ID)被设置为进程的有效用户 ID。组所有权(组 ID)被设置为进程的有效组 ID 或父目录的组 ID(取决于文件系统类型、挂载选项以及父目录的模式,参见 mount(8) 中描述的 bsdgroups 和 sysvgroups 挂载选项)。
mode 指定在创建新文件时使用的权限。当在 flags 中指定 O_CREAT 时,必须提供此参数;如果未指定 O_CREAT,则忽略 mode。实际权限会以通常方式受进程 umask 的影响:所创建文件的权限为 (mode & ~umask)。请注意,此模式仅适用于未来对新创建文件的访问;创建只读文件的 open() 调用可能会返回一个读写文件描述符。
为 mode 提供了以下符号常量:
- S_IRWXU
- 00700 用户(文件所有者)具有读、写和执行权限
- S_IRUSR
- 00400 用户具有读权限
- S_IWUSR
- 00200 用户具有写权限
- S_IXUSR
- 00100 用户具有执行权限
- S_IRWXG
- 00070 组具有读、写和执行权限
- S_IRGRP
- 00040 组具有读权限
- S_IWGRP
- 00020 组具有写权限
- S_IXGRP
- 00010 组具有执行权限
- S_IRWXO
- 00007 其他人具有读、写和执行权限
- S_IROTH
- 00004 其他人具有读权限
- S_IWOTH
- 00002 其他人具有写权限
- S_IXOTH
- O_DIRECT (自 Linux 2.4.10 起)
- 尝试最小化此文件 I/O 带来的缓存影响。通常这会降低性能,但在特殊情况下(例如应用程序进行自己的缓存时)很有用。文件 I/O 直接在用户空间缓冲区之间进行。单独使用 O_DIRECT 标志会尝试同步传输数据,但不能提供 O_SYNC 标志所保证的数据及必要元数据已传输的保障。要保证同步 I/O,必须在 O_DIRECT 之外额外使用 O_SYNC。更详细的讨论请参见下方的“备注”。
关于块设备的语义类似(但已弃用)的接口在 raw(8) 中描述。
- O_DIRECTORY
- 如果 pathname 不是目录,则导致 open 失败。此标志是 Linux 特有的,于内核版本 2.1.126 中添加,旨在避免在 FIFO 或磁带设备上调用 opendir(3) 时产生的拒绝服务问题,但不应在 opendir(3) 的实现之外使用。
- O_EXCL
- 确保此调用创建文件:如果此标志与 O_CREAT 一起使用,并且 pathname 已经存在,则 open() 将失败。
当指定这两个标志时,不会跟随符号链接:如果 pathname 是一个符号链接,则无论该链接指向何处,open() 都会失败。
通常,如果 O_EXCL 在没有 O_CREAT 的情况下使用,其行为是未定义的。有一个例外:在 Linux 2.6 及更高版本上,如果 pathname 指向块设备,则可以在没有 O_CREAT 的情况下使用 O_EXCL。如果块设备正被系统使用(例如已挂载),open() 将失败并返回 EBUSY 错误。
在 NFS 上,O_EXCL 仅在内核 2.6 或更高版本上使用 NFSv3 或更高版本时才受支持。在不支持 O_EXCL 的 NFS 环境中,依赖它执行锁任务的程序将存在竞争条件。希望使用锁文件执行原子文件锁并需要避免依赖 NFS 对 O_EXCL 支持的可移植程序,可以在同一文件系统上创建一个唯一文件(例如包含主机名和 PID),并使用 link(2) 链接到该锁文件。如果 link(2) 返回 0,则锁定成功。否则,在唯一文件上使用 stat(2) 检查其链接数是否已增加到 2,如果是,则锁定也成功。
- O_LARGEFILE
- (LFS) 允许打开大小无法用 off_t 表示(但可以用 off64_t 表示)的文件。必须定义 _LARGEFILE64_SOURCE 宏(在包含任何头文件之前)才能获取此定义。在 32 位系统上,设置 _FILE_OFFSET_BITS 特性测试宏为 64(而不是使用 O_LARGEFILE)是访问大文件的首选方法(参见 feature_test_macros(7))。
- O_NOATIME (自 Linux 2.6.8 起)
- 当 read(2) 文件时,不要更新文件的最后访问时间(inode 中的 st_atime)。此标志旨在供索引或备份程序使用,使用它可以显著减少磁盘活动量。此标志可能并非在所有文件系统上都有效。一个例子是 NFS,其中服务器维护访问时间。
- O_NOCTTY
- 如果 pathname 指的是终端设备(参见 tty(4)),则即使进程没有控制终端,它也不会成为进程的控制终端。
- O_NOFOLLOW
- 如果 pathname 是一个符号链接,则打开失败。这是一个 FreeBSD 扩展,在 2.1.126 版本中添加到 Linux 中。路径名中较早组件里的符号链接仍会被跟随。
- O_NONBLOCK 或 O_NDELAY
- 如果可能,以非阻塞模式打开文件。open() 以及返回的文件描述符上的任何后续操作都不会导致调用进程等待。关于 FIFO(命名管道)的处理,另请参见 fifo(7)。有关 O_NONBLOCK 与强制文件锁和文件租约结合使用的影响,请参见 fcntl(2)。
- O_SYNC
- 以同步 I/O 方式打开文件。对所得文件描述符的任何 write(2) 操作都会阻塞调用进程,直到数据已被物理写入到底层硬件。*但请参见下方的“备注”。*
- O_TRUNC
- 如果文件已存在且为常规文件,并且打开模式允许写入(即为 O_RDWR 或 O_WRONLY),它将被截断为长度 0。如果文件是 FIFO 或终端设备文件,则忽略 O_TRUNC 标志。否则,O_TRUNC 的影响是未指定的。
在文件打开后,可以使用 fcntl(2) 修改其中一些可选标志。
creat() 等同于 flags 等于 O_CREAT|O_WRONLY|O_TRUNC 的 open()。
返回值
open() 和 creat() 返回新的文件描述符,如果发生错误则返回 -1(这种情况下,会相应地设置 errno)。错误
- EACCES
- 对文件的请求访问不被允许,或者路径前缀中目录之一的搜索权限被拒绝,或者文件尚未存在且父目录的写权限不被允许。(另请参见 path_resolution(7)。)
- EDQUOT
- 指定了 O_CREAT,文件不存在,且用户在文件系统上的磁盘块或 inode 配额已耗尽。
- EEXIST
- pathname 已存在,且使用了 O_CREAT 和 O_EXCL。
- EFAULT
- pathname 指向可访问地址空间之外。
- EFBIG
- 参见 EOVERFLOW。
- EINTR
- 在阻塞等待慢速设备(例如 FIFO;参见 fifo(7))的打开完成时,调用被信号处理程序中断;参见 signal(7)。
- EISDIR
- pathname 指向一个目录,且请求的访问涉及写入(即设置了 O_WRONLY 或 O_RDWR)。
- ELOOP
- 解析 pathname 时遇到过多的符号链接,或者指定了 O_NOFOLLOW 但 pathname 是一个符号链接。
- EMFILE
- 进程已达到打开文件的最大数量。
- ENAMETOOLONG
- pathname 太长。
- ENFILE
- 已达到系统打开文件总数的限制。
- ENODEV
- pathname 指向设备特殊文件,且不存在对应的设备。(这是 Linux 内核的一个 bug;在这种情况下必须返回 ENXIO。)
- ENOENT
- 未设置 O_CREAT 且指定文件不存在。或者,pathname 中的目录组件不存在或是一个悬空的符号链接。
- ENOMEM
- 内核内存不足。
- ENOSPC
- pathname 本应被创建,但包含 pathname 的设备没有空间用于新文件。
- ENOTDIR
- pathname 中用作目录的组件实际上并非目录,或者指定了 O_DIRECTORY 而 pathname 不是目录。
- ENXIO
- 设置了 O_NONBLOCK | O_WRONLY,指定文件是 FIFO,且没有进程以读取方式打开该文件。或者,该文件是设备特殊文件,且没有对应设备存在。
- EOVERFLOW
- pathname 指向一个太大而无法打开的常规文件。通常情况是在 32 位平台上未经 -D_FILE_OFFSET_BITS=64 编译的应用程序试图打开一个大小超过 (2<<31)-1 位的文件;另请参见上面的 O_LARGEFILE。这是 POSIX.1-2001 指定的错误;在 2.6.24 之前的内核中,Linux 在这种情况下给出 EFBIG 错误。
- EPERM
- 指定了 O_NOATIME 标志,但调用者的有效用户 ID 与文件所有者不匹配,且调用者不具备特权(CAP_FOWNER)。
- EROFS
- pathname 指向只读文件系统上的文件,且请求了写权限。
- ETXTBSY
- pathname 指向当前正在执行的可执行映像,且请求了写权限。
- EWOULDBLOCK
- 指定了 O_NONBLOCK 标志,且该文件上持有不兼容的租约(参见 fcntl(2))。
符合
SVr4, 4.3BSD, POSIX.1-2001。O_DIRECTORY、O_NOATIME 和 O_NOFOLLOW 标志是 Linux 特有的,可能需要定义 _GNU_SOURCE(在包含任何头文件之前)才能获取它们的定义。O_CLOEXEC 标志未在 POSIX.1-2001 中指定,但在 POSIX.1-2008 中有指定。
O_DIRECT 未在 POSIX 中指定;必须定义 _GNU_SOURCE(在包含任何头文件之前)才能获取其定义。
说明
在 Linux 下,O_NONBLOCK 标志表示想要打开但不一定有读取或写入的意图。这通常用于打开设备以获取用于 ioctl(2) 的文件描述符。与其他可以指定在 flags 中的值不同,访问模式值 O_RDONLY、O_WRONLY 和 O_RDWR 并不指定单个位。相反,它们定义了 flags 的低两位,分别定义为 0、1 和 2。换句话说,组合 O_RDONLY | O_WRONLY 是一个逻辑错误,肯定不具有与 O_RDWR 相同的含义。Linux 在 flags 中保留了特殊的非标准访问模式 3(二进制 11),含义为:检查文件的读写权限并返回一个不能用于读取或写入的描述符。此非标准访问模式被某些 Linux 驱动程序用于返回仅用于设备特定 ioctl(2) 操作的描述符。
O_RDONLY | O_TRUNC 的(未定义)效果在不同实现中有所不同。在许多系统上,文件实际上会被截断。
NFS 底层协议存在许多瑕疵,影响了 O_SYNC 和 O_NDELAY 等。
POSIX 提供了三种不同变体的同步 I/O,对应于标志 O_SYNC、O_DSYNC 和 O_RSYNC。目前(2.6.31),Linux 仅实现了 O_SYNC,但 glibc 将 O_DSYNC 和 O_RSYNC 映射为与 O_SYNC 相同的数值。大多数 Linux 文件系统实际上并未实现 POSIX O_SYNC 语义(要求写操作的所有元数据更新在返回到用户空间时都在磁盘上),而是实现了 O_DSYNC 语义(仅要求在系统调用返回时,实际文件数据和检索它所需的元数据都在磁盘上)。
注意,open() 可以打开设备特殊文件,但 creat() 不能创建它们;请改用 mknod(2)。
在启用 UID 映射的 NFS 文件系统上,open() 可能会返回一个文件描述符,但例如 read(2) 请求会被拒绝并返回 EACCES。这是因为客户端通过检查权限来执行 open(),而 UID 映射是由服务器在读写请求时执行的。
如果文件是新创建的,其 st_atime、st_ctime、st_mtime 字段(分别为最后访问时间、最后状态更改时间和最后修改时间;参见 stat(2))被设置为当前时间,父目录的 st_ctime 和 st_mtime 字段也一样。否则,如果文件因 O_TRUNC 标志而被修改,其 st_ctime 和 st_mtime 字段被设置为当前时间。
O_direct
O_DIRECT 标志可能会对用户空间缓冲区的长度和地址以及 I/O 的文件偏移量施加对齐限制。在 Linux 中,对齐限制因文件系统和内核版本而异,甚至可能完全不存在。然而,目前还没有与文件系统无关的接口供应用程序发现给定文件或文件系统的这些限制。一些文件系统提供了它们自己的执行此操作的接口,例如 xfsctl(3) 中的 XFS_IOC_DIOINFO 操作。
在 Linux 2.4 下,传输大小以及用户缓冲区和文件偏移量的对齐必须都是文件系统逻辑块大小的倍数。在 Linux 2.6 下,与 512 字节边界对齐即可。
如果内存缓冲区是私有映射(即,任何使用 mmap(2) 的 MAP_PRIVATE 标志创建的映射;这包括在堆上分配的内存和静态分配的缓冲区),则 O_DIRECT I/O 绝不应与 fork(2) 系统调用并发运行。任何此类 I/O,无论是通过异步 I/O 接口提交还是从进程中的另一个线程提交,都应在调用 fork(2) 之前完成。否则可能导致父进程和子进程中的数据损坏和未定义的行为。当使用 shmat(2) 或带 MAP_SHARED 标志的 mmap(2) 创建 O_DIRECT I/O 的内存缓冲区时,此限制不适用。当使用 madvise(2) 将内存缓冲区声明为 MADV_DONTFORK 时,此限制也不适用,这可确保它在 fork(2) 之后不会对子进程可用。
O_DIRECT 标志是在 SGI IRIX 中引入的,在那里它具有与 Linux 2.4 类似的对齐限制。IRIX 也有一个 fcntl(2) 调用来查询适当的对齐方式和大小。FreeBSD 4.x 引入了同名标志,但没有对齐限制。
O_DIRECT 支持在 Linux 内核版本 2.4.10 中添加。旧的 Linux 内核只是忽略此标志。某些文件系统可能未实现此标志,如果使用,open() 将失败并返回 EINVAL。
应用程序应避免在同一文件上混合使用 O_DIRECT 和普通 I/O,特别是对同一文件中的重叠字节区域。即使文件系统在这种情况下正确处理一致性问题,整体 I/O 吞吐量也可能比单独使用任一模式要慢。同样,应用程序应避免在同一文件上混合使用文件的 mmap(2) 和直接 I/O。
O_DIRECT 与 NFS 的行为将不同于本地文件系统。旧内核或以某种方式配置的内核可能不支持此组合。NFS 协议不支持将此标志传递给服务器,因此 O_DIRECT I/O 将仅绕过客户端上的页缓存;服务器可能仍会缓存 I/O。客户端要求服务器使 I/O 同步,以保留 O_DIRECT 的同步语义。在这些情况下,一些服务器性能会很差,特别是如果 I/O 大小很小的话。一些服务器也可能被配置为向客户端撒谎,谎称 I/O 已到达稳定存储;这避免了性能损失,但在服务器断电时对数据完整性存在一定风险。Linux NFS 客户端不对 O_DIRECT I/O 施加任何对齐限制。
总之,O_DIRECT 是一个潜在的强大工具,应谨慎使用。建议应用程序将使用 O_DIRECT 视为默认禁用的性能选项。
"关于 O_DIRECT,一直让我困扰的是整个接口简直愚蠢透顶,而且很可能是由一个吸食了某种烈性精神控制药物的疯狂猴子设计的。"——Linus