Linux的open(2)手册首先把返回值说明为一个小的非负整数:它是进程打开文件描述符表中某个条目的索引,供后续文件相关调用指代已打开文件。成功返回的号码是该进程当前尚未打开的最低号码。因此,看到两个不同整数,首先知道的是存在两个描述符入口,还没有知道它们各自引用哪一份打开状态。[1]
手册随即引入open file description。这里的description并非一段文件介绍文字,而是系统级打开文件表中的条目;它记录文件偏移量和file status flags。文件描述符是对这个条目的引用。进程内的号码与被引用的打开状态有了两层位置:前者提供入口,后者保存多个入口可能共同面对的状态。[1]
每次open都会创建一个新的打开文件描述。同一文件的inode可以因此对应多个这样的对象。文件身份相同,并没有取消各次打开形成的状态身份;如果两项资料都指向同一文件,却分别来自两次open,不能只凭相同文件名便把它们的偏移量归到同一份记录中。这里依据的是手册对每次创建新对象的说明。[1]
复制描述符的dup走的是另一种关系。dup(2)说,新分配的文件描述符引用与原描述符相同的打开文件描述,并且同样选择当前未用的最低号码。号码确实新增,底下的状态对象却没有由此重新创建。两个入口共享偏移量和文件状态标志;原文以一边改变偏移量、另一边随之改变为例,解释共享究竟发生在哪里。[2]
共享还有明确的终点。dup文档紧接着指出,两个描述符不共享file descriptor flags,即描述符自身的标志;复制所得描述符的close-on-exec标志为关闭状态。它与前段的file status flags不是同一组词。若资料把二者都压成“文件标志”,就会同时抹掉共享对象上的状态和每个入口自身属性的区别。[2]
open的说明又将这层引用扩展到进程之间:fork创建的子进程继承父进程描述符的副本,副本仍指向相同的打开文件描述。由此能看出,打开状态的共享不一定只发生在一个进程里。需要保留的是这条继承关系,而不能仅凭存在两个进程,就认定它们必然各有一份独立文件偏移。[1]
可以用一个纸面关系说明三层对象:入口甲与由它复制出的乙指向状态对象一;同一文件另一次打开得到的丙指向状态对象二。文件所对应的inode可以相同,一和二仍是不同的打开对象;甲、乙号码不同,却共享同一个状态对象。这个示意解释的是文档中的引用关系,不是本文读取了某个进程的描述符表。[1][2]
采用范围为Linux man-pages 6.19的上述定义。首次发表日未知;本文没有执行文件调用、重定向或权限修改。
信息来源
- Linux man-pages / man7.org:open(2) — Linux manual page
- Linux man-pages / man7.org:dup(2) — Linux manual page
本文基于上述公开资料整理,未使用来源页面的图片、视频或嵌入媒体。