Unix/Linux编程实践读书笔记2
第四章 文件系统:编写pwd
文件系统的内部结构
Unix文件系统由三个部分组成:
(1)超级块,存放文件系统本身的结构信息。
(2)inode表,每个文件都有一个inode,用来保存文件的属性,inode的位置被称为文件的inode号,inode号是文件的唯一标识。
(3)数据区,存放文件的内容。
创建一个文件的过程
我们现在知道文件的内容和属性是分开存放的,那么又是如何管理它们的呢?现在我们以创建一个文件为例来讲解。在命令行输入命令:
$ who > userlist
当完成这个命令时。文件系统中增加了一个存放命令who输出内容的新文件,那么这整个过程到底是怎么回事呢?
文件的属性和内容:内核将文件内容存放在数据区,文件属性存放在i-节点,文件名存放在目录。下图显示了创建一个文件的例子,假如这个新文件要3 个存储块来存放内容。
包括如下四个步骤:
- 存储属性 也就是文件属性的存储,内核先找到一块空的i-节点。图中,内核找到i-节点号47。内核把文件的信息记录其中。如文件的大小、文件所有者、和创建时间等
- 存储数据 即文件内容的存储,由于该文件需要3个数据块。因此内核从自由块的列表中找到3个自由块。图中分别为627、200、992,内核缓冲区的第一块数据复制到块627,第二和第三分别复制到200和992.
- 记录分配情况,数据保存到了三个数据块中。分配情况记录在文件的i-节点中的磁盘分配区。磁盘分配区是一个磁盘块序号的列表,这3个编号分别放在最开始的3个位置。
- 添加文件名到目录,新文件的名字是userlist, 内核将文件的入口(47,userlist)添加到目录文件里。文件名和i-节点号之间的对应关系将文件名和文件和文件的内容属性连接起来,找到文件名就找到文件的i-节点号,通过i-节点号就能找到文件的属性和内容。
cat命令的工作原理
- 在目录中寻找文件名
- 定位i-节点并读取内容
- 访问存储内容的数据块
所有从文件读取数据的命令,如cat,cp,more,who等,都是将文件名传给open来访问文件内容。对open的每次调用,都是现在目录中查找文件名,然后根据目录中的i-节点编号获得文件属性,最终找到文件内容。在i-节点中,内核可以查看文件的权限位和拥有者的用户ID。
unix文件系统的改进(未详述)
文件在目录中的真正含义
文件存放在目录中,目录中存放的只是文件在i-节点表中的入口,文件的内容则存储在数据区。目录包含的是文件的应用,每个引用称为链接,文件的内容存储在数据块,文件的属性记录在被称为i-节点的结构中,i-节点的编号和文件名存储在目录中。
编写pwd
- 得到“.”(当前目录)的i-节点号,称其为n(使用stat);
- chdir .. (使用chdir,进入父目录);
- 找到i-节点号n链接的名字(使用opendir, readdir, closedir);
- 回到1,直到到达树的顶端(当“.”和”..”的i-节点号相同时)。
pwd版本
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 /* spwd.c: a simplified version of pwd 2 * 3 * starts in current directory and recursively 4 * climbs up to root of filesystem, prints top part 5 * then prints current part 6 * 7 * uses readdir() to get info about each thing 8 * 9 * bug: prints an empty string if run from "/" 10 **/ 11 #include <stdio.h> 12 #include <sys/types.h> 13 #include <sys/stat.h> 14 #include <dirent.h> 15 16 ino_t get_inode(char *); 17 void printpathto(ino_t); 18 void inum_to_name(ino_t , char *, int ); 19 20 int main() 21 { 22 printpathto( get_inode( "." ) ); /* print path to here */ 23 putchar('\n'); /* then add newline */ 24 return 0; 25 } 26 27 void printpathto( ino_t this_inode ) 28 /* 29 * prints path leading down to an object with this inode 30 * kindof recursive 31 */ 32 { 33 ino_t my_inode ; 34 char its_name[BUFSIZ]; 35 36 if ( get_inode("..") != this_inode ) 37 { 38 chdir( ".." ); /* up one dir */ 39 40 inum_to_name(this_inode,its_name,BUFSIZ);/* get its name*/ 41 42 my_inode = get_inode( "." ); /* print head */ 43 printpathto( my_inode ); /* recursively */ 44 printf("/%s", its_name ); /* now print */ 45 /* name of this */ 46 } 47 } 48 49 void inum_to_name(ino_t inode_to_find , char *namebuf, int buflen) 50 /* 51 * looks through current directory for a file with this inode 52 * number and copies its name into namebuf 53 */ 54 { 55 DIR *dir_ptr; /* the directory */ 56 struct dirent *direntp; /* each entry */ 57 58 dir_ptr = opendir( "." ); 59 if ( dir_ptr == NULL ){ 60 perror( "." ); 61 exit(1); 62 } 63 64 /* 65 * search directory for a file with specified inum 66 */ 67 68 while ( ( direntp = readdir( dir_ptr ) ) != NULL ) 69 if ( direntp->d_ino == inode_to_find ) 70 { 71 strncpy( namebuf, direntp->d_name, buflen); 72 namebuf[buflen-1] = '\0'; /* just in case */ 73 closedir( dir_ptr ); 74 return; 75 } 76 fprintf(stderr, "error looking for inum %d\n", inode_to_find); 77 exit(1); 78 } 79 80 ino_t get_inode( char *fname ) 81 /* 82 * returns inode number of the file 83 */ 84 { 85 struct stat info; 86 87 if ( stat( fname , &info ) == -1 ){ 88 fprintf(stderr, "Cannot stat "); 89 perror(fname); 90 exit(1); 91 } 92 return info.st_ino; 93 }
上述版本显示的文件系统的根目录不是计算机上整颗文件树的根目录。unix系统允许将磁盘组织成一棵由多棵树相互连接的树,每个磁盘或磁盘上的每个分区都包含一棵目录树。这些独立的树被连接成一棵单一的无缝的树。