APUE 学习记录 20200622~20200623

3.2 文件描述符

对于内核而言,所有打开的文件都通过文件描述符引用。文件描述符是一个非负整数。当打开一个现有文件或创建一个新文件时,内核向进程返回一个文件描述符。当读写一个文件时,使用open或creat返回的文件描述符,将其作为参数传送给read和write。

UNIX系统shell将文件描述符0与进程的标准输入关联,文件描述符1与标准输出关联,文件描述符2与标准错误关联。在符合POSIX
.1的应用程序,应当将0,1,2替换成符号STDIN_FILENO、STDOUT_FILENO和STDERR_FILENO来提高可读性。这些常量在头文件中定义。文件描述符的变化范围是0~OPEN_MAX-1。

3.3 函数open和openat

调用open或openat函数可以打开或创建一个文件。

#include 
int open(const char *path, int pflag, .../*mode_t mode */);
int openat(int fd, const char *path, int oflag, ... /* mode_t mode */);

...表示余下的参数的数量及其类型是可变的。对于open函数而言,仅当创建新文件时才使用最后一个参数。

path参数是要打开或创建文件的名字。oflag参数可用来说明此函数的多个选项,用下列一个或多个常量进行或运算构成oflag参数。

O_RDONLY 只读打开
O_WRONLY 只写打开
O_EDWR 读写打开
O_EXEC 只执行打开
O_SEARCH 只搜索打开

以上五个常量中必须指定一个且只能指定一个。

以下常量为可选:
O_APPEND 追加
O_CLOEXEC 把FD_CLOEXEC常量设置为文件描述符标志
O_CREAT 若此文件不存在则创建它。open函数需同时说明mode参数
O_DIRECTORY 如果path引用不是目录,则出错。
O_EXCL 如果同时指定了O_CREAT,而文件已经存在,则出错。可以用来测试一个文件是否存在,如果不存在,则创建此文件。这使测试和创建成为一个原子操作。
O_NOCTTY 如果path引用的是终端设备,则不将该设备分配作为此进程的控制终端。
O_NOFOLLOW 如果path引用的是一个符号链接,则出错。
O_NONBLOCK 如果path引用的是一个FIFO,一个块特殊文件或一个字符特殊文件,则此选项为文件的本次打开操作和后续的I/O操作设置为非阻塞方式。
O_SYNC 是每次write等待物理I/O操作完成,包括由该write操作引起的文件属性更新所需的I/O。
O_TRUNC 如果此文件存在,且为只写或读写成功打开,则将其长度截断为0.
O_TTY_INIT 如果打开一个还未打开的终端设备,设置非标准termios参数值,时器符合single UNIX Specification。
O_DSYNC 使每次write要等待物理I/O操作完成,但是如果该写操作并不影响读取刚写入的数据,则不需要等待文件属性被更新。
O_RSYNC 使每一个以文件描述符作为参数进行的read操作等待,直至所有对文件同一部分挂起的写操作都完成。

由open和openat函数返回的文件描述符一定是最小的未用描述符数值。fd把参数open和openat函数区分开,共有3种可能性:

  1. path参数指定的是绝对路径名,在这种情况下,fd参数被忽略,openat函数就相当于open函数。
  2. path参数指定的是相对路径名,fd参数指出了相对路径名在文件系统中的开始地址。fd参数是通过打开相对路径名所在的目录凯获取。
  3. path参数指定了相对路径名,fd参数具有特殊值AT_FDCWD。在这种情况下,路径名在当前目录中获取,openat函数在操作上与open函数类似。

openat函数是POSIX.1最新版本中新增的函数。希望解决两个问题:

  1. 让线程可以使用相对路径名打开目录中的文件,而不再只能打开当先工作目录。
  2. 可以避免time-ofcheck-to-time-of-use(TOCTTOU)错误。

TOCTTOU错误的基本思想是:如果有两个基于文件的函数调用,其中第二个调用依赖于第一个调用的结果,那么程序是脆弱的。因为两个调用并不是原子操作。

文件名和路径截断
如果NAME_MAX是14,而视图在当前目录中创建一个包含15个字符的新文件。在POSIX.1中,常量_POSIX_NO_TRUNC决定是要截断过长的文件名或路径名,还是返回一个出错。

你可能感兴趣的:(linux编程)