open() - Unix,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);
|
描述
给定文件的路径名,open() 返回一个文件描述符,一个小的非负整数,用于后续的系统调用(read(2), write(2), lseek(2), fcntl(2) 等)。成功调用返回的文件描述符将是进程当前未打开的最低编号的文件描述符。
新的文件描述符设置为在 execve(2) 中保持打开(即,fcntl(2) 中描述的 FD_CLOEXEC 文件描述符标志最初被禁用)。文件偏移量设置为文件的开头(参见 lseek(2))。
调用 open() 会创建一个新的打开的文件描述,这是系统范围的打开文件表中的一个条目。此条目记录文件偏移量和文件状态标志(可通过 fcntl() F_SETFL 操作进行修改)。文件描述符是对这些条目之一的引用;如果路径名随后被删除或修改为引用不同的文件,则此引用不受影响。新的打开的文件描述最初不与任何其他进程共享,但共享可能通过 fork(2) 产生。
参数flags必须包含以下访问模式之一:O_RDONLY、O_WRONLY 或 O_RDWR。这些分别请求以只读、只写或读写方式打开文件。
此外,零个或多个文件创建标志和文件状态标志可以按位或到flags中。文件创建标志是 O_CREAT、O_EXCL、O_NOCTTY 和 O_TRUNC。文件状态标志是下面列出的所有其余标志。这两组标志之间的区别在于,可以使用 fcntl(2) 获取并(在某些情况下)修改文件状态标志。
文件创建标志和文件状态标志的完整列表如下所示
错误代码 | 描述 |
O_APPEND | 文件以追加模式打开。在每次write() 之前,文件偏移量都定位在文件的末尾,就像使用lseek() 一样。如果多个进程同时向一个文件追加数据,O_APPEND 可能会导致 NFS 文件系统上的文件损坏。这是因为 NFS 不支持向文件追加数据,因此客户端内核必须模拟它,这在没有竞争条件的情况下是无法完成的。 |
O_ASYNC | 启用信号驱动的 I/O:当此文件描述符上可能进行输入或输出时,生成一个信号(默认为 SIGIO,但这可以通过 fcntl(2) 更改)。此功能仅适用于终端、伪终端、套接字以及(自 Linux 2.6 起)管道和 FIFO。有关更多详细信息,请参见 fcntl(2)。 |
O_CREAT | 如果文件不存在,则将创建它。文件的拥有者(用户 ID)设置为进程的有效用户 ID。组所有权(组 ID)设置为进程的有效组 ID 或父目录的组 ID(取决于文件系统类型和挂载选项以及父目录的模式,例如,请参见 ext2 文件系统的挂载选项bsdgroups 和 sysvgroups,如 mount(8) 中所述)。 |
O_DIRECT | 尝试最大限度地减少与此文件进行 I/O 的缓存效应。通常,这会降低性能,但在特殊情况下很有用,例如当应用程序进行自己的缓存时。文件 I/O 直接在用户空间缓冲区之间进行。I/O 是同步的,即在read(2) 或write(2) 完成时,保证数据已传输。在 Linux 2.4 中,传输大小以及用户缓冲区和文件偏移量的对齐方式都必须是文件系统逻辑块大小的倍数。在 Linux 2.6 中,对齐方式必须适合设备的块大小。 raw(8) 中描述了块设备的语义相似(但已弃用)的接口。 |
O_DIRECTORY | 如果路径名不是目录,则导致打开失败。此标志是 Linux 特定的,是在内核版本 2.1.126 中添加的,目的是为了避免在对 FIFO 或磁带设备调用opendir(3) 时出现拒绝服务问题,但不应在opendir的实现之外使用。 |
O_EXCL | 当与O_CREAT一起使用时,如果文件已存在,则这是一个错误,并且open() 将失败。在这种情况下,符号链接存在,无论它指向哪里。O_EXCL 在 NFS 文件系统上已损坏;依赖于它来执行锁定任务的程序将包含竞争条件。使用锁文件执行原子文件锁定的解决方案是在同一个文件系统上创建一个唯一文件(例如,包含主机名和 pid),使用link(2) 创建到锁文件的链接。如果link() 返回 0,则锁定成功。否则,使用stat(2) 检查唯一文件的链接计数是否已增加到 2,在这种情况下,锁定也成功。 |
O_LARGEFILE | (LFS) 允许打开大小无法用off_t表示(但可以用off64_t表示)的文件。 |
O_NOATIME | (自 Linux 2.6.8 起) 当read(2) 文件时,不更新文件上次访问时间(inode 中的 st_atime)。此标志旨在供索引或备份程序使用,在这些程序中,它的使用可以显著减少磁盘活动量。此标志可能并非对所有文件系统都有效。一个例子是 NFS,其中服务器维护访问时间。 |
O_NOCTTY | 如果路径名引用终端设备——参见tty(4)——即使进程没有终端,它也不会成为进程的控制终端。 |
O_NOFOLLOW | 如果路径名是符号链接,则打开失败。这是 FreeBSD 扩展,在 2.1.126 版本中添加到 Linux。路径名中较早的组件中的符号链接仍将被跟踪。 |
O_NONBLOCK 或 O_NDELAY | 如果可能,则以非阻塞模式打开文件。返回的文件描述符上的open() 或任何后续操作都不会导致调用进程等待。对于 FIFO(命名管道)的处理,另请参见fifo(7)。有关O_NONBLOCK 与强制文件锁和文件租约结合使用效果的讨论,请参见fcntl(2)。
|
O_SYNC | 文件以同步 I/O 方式打开。结果文件描述符上的任何write() 都将阻塞调用进程,直到数据被物理写入底层硬件。但请参见下面的限制。 |
O_TRUNC | 如果文件已存在并且是常规文件,并且打开模式允许写入(即为 O_RDWR 或 O_WRONLY),则它将被截断为长度 0。如果文件是 FIFO 或终端设备文件,则忽略 O_TRUNC 标志。否则,O_TRUNC 的效果未指定。 |
打开文件后,可以使用fcntl() 更改其中一些可选标志。
参数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 | 00001 其他用户具有执行权限 |
当O_CREAT在flags中时,必须指定mode,否则将被忽略。
creat() 等效于flags等于O_CREAT|O_WRONLY|O_TRUNC的open()。
返回值
open() 和 creat() 返回新的文件描述符,或者如果发生错误则返回 -1(在这种情况下,errno 将被相应设置)。
备注
请注意,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字段将设置为当前时间。
错误
错误代码 | 描述 |
EACCES | 不允许请求的文件访问,或者拒绝搜索pathname路径前缀中的某个目录的权限,或者文件尚不存在且不允许对父目录进行写访问。(另见path_resolution(2)。) |
EEXIST |
pathname已存在,并且使用了O_CREAT和O_EXCL。 |
EFAULT |
pathname指向您可访问的地址空间之外。 |
EISDIR |
pathname指向一个目录,并且请求的访问涉及写入(即,设置了O_WRONLY或O_RDWR)。 |
ELOOP | 在解析pathname时遇到太多符号链接,或者指定了O_NOFOLLOW但pathname是符号链接。 |
EMFILE | 进程已打开最大数量的文件。 |
ENAMETOOLONG |
pathname太长。 |
ENFILE | 已达到系统对打开文件总数的限制。 |
ENODEV |
pathname指向一个设备特殊文件,并且不存在相应的设备。(这是一个Linux内核错误;在这种情况下,必须返回ENXIO。) |
ENOENT | 未设置O_CREAT并且指定的 文件不存在。或者,pathname中的目录组件不存在或是一个悬空符号链接。 |
ENOMEM | 内核可用内存不足。 |
ENOSPC |
要创建pathname,但包含pathname的设备没有足够空间容纳新文件。 |
ENOTDIR | pathname中用作目录的组件实际上并非目录,或者指定了O_DIRECTORY但pathname不是目录。 |
ENXIO | 设置了O_NONBLOCK | O_WRONLY,指定的文件是FIFO且没有进程打开该文件以进行读取。或者,该文件是设备特殊文件,并且不存在相应的设备。 |
EOVERFLOW |
pathname指向一个常规文件,太大而无法打开;请参见上面的O_LARGEFILE。 |
EPERM | 指定了O_NOATIME标志,但调用者的有效用户ID与文件所有者不匹配,并且调用者没有特权(CAP_FOWNER)。 |
EROFS |
pathname指向只读文件系统上的文件,并且请求了写访问。 |
ETXTBSY |
pathname指向当前正在执行的可执行映像,并且请求了写访问。 |
EWOULDBLOCK | 指定了O_NONBLOCK标志,并且在该文件上存在不兼容的租约(参见fcntl(2))。 |
注意
在Linux下,O_NONBLOCK标志表示想要打开但并不一定打算读取或写入。这通常用于打开设备以获取用于ioctl(2)的文件描述符。
符合标准
SVr4、4.3BSD、POSIX.1-2001。O_NOATIME、O_NOFOLLOW和O_DIRECTORY标志是Linux特有的。可能需要定义_GNU_SOURCE宏才能获得它们的定义。
O_RDONLY | O_TRUNC的(未定义的)效果在不同的实现中有所不同。在许多系统上,文件实际上会被截断。
O_DIRECT标志是在SGI IRIX中引入的,它具有与Linux 2.4相似的对齐限制。IRIX还有一个fcntl(2)调用来查询适当的对齐方式和大小。
FreeBSD 4.x引入了相同名称的标志,但没有对齐限制。在内核版本2.4.10中添加了对Linux的支持。较旧的Linux内核会忽略此标志。可能需要定义_GNU_SOURCE宏才能获得其定义。
错误
“O_DIRECT一直让我困扰的一件事是,整个接口都很愚蠢,可能是在某种严重的控制精神的物质作用下由一只疯猴设计的。”——Linus
当前,在调用open()时,无法通过指定O_ASYNC来启用信号驱动的I/O;使用fcntl(2)来启用此标志。
限制
底层NFS协议中存在许多不完善之处,影响到O_SYNC和O_NDELAY等。 POSIX提供了三种不同的同步I/O变体,分别对应于标志O_SYNC、O_DSYNC和O_RSYNC。目前(2.1.130)在Linux下它们都是同义词。
参见
广告
|