文件的三个表

内核用三个相关的数据结构来表示打开的文件:

  1. 描述符表(descriptor table)。每个进程都有它独立的描述附表,他的表项是由进程打开文件的文件描述符来索引的。
  2. 每个打开的描述符表项指向文件表中的一个表项。
  3. 文件表(file table)。打开文件的集合是有一张文件表来表示的,所有的进程共享这张表。
  4. 每个文件表的表项组成(针对我们的目的)包括当前文件位置、引用计数(reference count)(即当前指向该表项的描述表项数),以及一个指向v-node表中对应表项的指针。
  5. 关闭一个描述符会减少相应的文件表表项中的引用计数。内核不会删除这个文件表象,直到他的引用计数为零。
  6. v-node表(v-node table)。同文件表一样,所有进程共享这张V-NODE表。每个表项包含stat结构中的大多数信息(包括st_modest_size成员)

多个描述符也可以通过不同的文件表项来引用同一个文件。

一个实验:

  1. #include <unistd.h>
  2. #include <sys/stat.h>
  3. #include <stdio.h>
  4. #include <fcntl.h>
  5. int main(){
  6. int fd1,fd2;
  7. char c;
  8. fd1=open("flag.txt",O_RDONLY,0);
  9. fd2=open("flag.txt",O_RDONLY,0);
  10. read(fd1,&c,1);
  11. read(fd2,&c,1);
  12. printf("c=%c\n",c);
  13. }

这段程序是两个描述符引用同一个文件,fd1读取一个字的时候fd2文件位置并没有改变,因为每个描述符对于flag.txt都有他自己的文件位置,所以从fd2的读操作会读取flag.txt文件的第一个字节并输出
图片.png

另一个实验:

  1. #include <unistd.h>
  2. #include <sys/stat.h>
  3. #include <stdio.h>
  4. #include <sys/wait.h>
  5. #include <stdlib.h>
  6. #include <fcntl.h>
  7. int main(){
  8. int fd1;
  9. char c;
  10. fd1=open("flag.txt",O_RDONLY,0);
  11. if(fork()==0){
  12. read(fd1,&c,1);
  13. exit(0);
  14. }
  15. wait(NULL);
  16. read(fd1,&c,1);
  17. printf("c = %c\n",c);
  18. }

子进程会继承父进程的描述符表,以及所有进程共享的同一个打开文件表。因此,描述符fd在父子进程中都指向同一个打开文件表表项。当子进程读取文件的第一个字节时,文件位置加1.因此,父进程会读取第二个字节.
图片.png