4.1 文件系统简述

linux系统将所有设备都看作文件。
按名存取:系统必须首先利用用户提供的文件名,对文件目录进行查询,找出该文件的文件控制块FCB,对UNIX/linux系统即要找出该文件的索引节点,然后根据找到的FCB中所记录的文件物理地址,并根据文件物理组织方式,找出文件的盘块号,进而换算出文件在磁盘上的物理位置,最后启动磁盘驱动程序,将文件读入内存,再返回给用户。
操作系统的一个重要任务就是管理文件,要将大量文件存储进存储设备中,还要了解存储设备中都有哪些文件,这些文件的属性以及存放位置。而文件系统就是操作系统中管理文件的那部分系统软件以及管理文件所需的各种数据结构。
不同的操作系统管理文件的方法各不相同,使用一个新设备时,需要“格式化”,其实就是操作系统按照自己的方式在设备上建立文件系统,操作系统对存储设备的空间进行划分,并在其上建立初始的数据结构。文件系统建立好了,OS就可以在上面存取并管理文件了。
文件系统的类型:Dos、windows采用的FAT、NTFS,Linux采用的ext2、ext3,Unix采用的UFS。
利用VFS虚拟文件系统,在支持自己的文件系统类型的同时也可以支持其他不同类型的文件系统,这方便了用户在不同系统之间共享文件。VFS是建立在各种具体文件系统之上的一个抽象层,其目的是让用户以统一形式访问不同的操作系统。VFS定义了一组统一的接口来访问具体文件系统的文件,如open,read,write,close,lseek等。

4.1.1 UNIX/Linux文件系统概述

Unix的UFS文件系统由四个部分组成:引导块,超级块,索引节点表,数据块区。
image.png
unix系统对UFS文件系统的使用大致上是这样的:当用户需要将一个文件保存到该文件系统上时,unix系统需要为这个文件分配相应的空闲磁盘空间和一个空闲索引节点。unix系统根据超级块中关于空闲块的参数从数据块区找出足够的空闲磁盘块来存放文件具体内容,并根据超级块中关于空闲索引节点的参数找出一个空闲索引节点来存储该文件的属性信息,属性信息中包括文件类型、存取类型、存取时间、文件长度及存放的磁盘块位置等。
image.png
索引节点表中,每一个保存在该文件系统中的文件,在表中都对应有一个索引节点保存该文件的信息。
unix/Linux系统中,每个保存在磁盘的文件包括两部分:索引节点inode数据块索引节点也叫i节点,用来记录文件属性信息(ls –i或 stat)。文件的属性包括:文件类型,访问权限,文件主人,组,长度,访问日期等等。但不包括文件名。也就是说,除了文件名以外,文件的主要属性信息都存放在inode节点中。
inode内容:

  • 文件字节数
  • 文件权限
  • 所属者
  • 所属组
  • rwx权限
  • 时间戳:ctime:文件inode上次变动时间;mtime:内容上次变动时间;atime:文件上次打开时间
  • 硬链接数
  • 文件数据block位置

    1. ![image.png](https://cdn.nlark.com/yuque/0/2021/png/1054933/1633489861280-dc8529cd-6531-44b3-a182-7dafe8465d50.png#clientId=u998088ab-7b01-4&from=paste&height=242&id=u4e1237c9&margin=%5Bobject%20Object%5D&name=image.png&originHeight=484&originWidth=422&originalType=binary&ratio=1&size=36285&status=done&style=none&taskId=u862c24e3-470f-4df4-9b4c-c3054953c4b&width=211)<br />![image.png](https://cdn.nlark.com/yuque/0/2021/png/1054933/1633490095586-6f409565-f04f-4dbc-b2ca-73e7d6b41ceb.png#clientId=u998088ab-7b01-4&from=paste&id=u762aff47&margin=%5Bobject%20Object%5D&name=image.png&originHeight=247&originWidth=513&originalType=binary&ratio=1&size=75410&status=done&style=none&taskId=u0ff87900-617d-4dcc-9df6-f1b097d1275)<br />![image.png](https://cdn.nlark.com/yuque/0/2021/png/1054933/1633490176915-cea391f5-3f2e-4c4d-bd20-8b55f45097d6.png#clientId=u998088ab-7b01-4&from=paste&height=62&id=u531c7738&margin=%5Bobject%20Object%5D&name=image.png&originHeight=83&originWidth=765&originalType=binary&ratio=1&size=50555&status=done&style=none&taskId=u8dd18d67-be4e-427a-861d-939ef42124e&width=574)<br />![image.png](https://cdn.nlark.com/yuque/0/2021/png/1054933/1633490147698-58185901-9eab-43ba-9abb-ee045428a42a.png#clientId=u998088ab-7b01-4&from=paste&height=164&id=u5afbfe28&margin=%5Bobject%20Object%5D&name=image.png&originHeight=327&originWidth=868&originalType=binary&ratio=1&size=51928&status=done&style=none&taskId=u07b20a32-d707-4a8e-b2ff-8db8ad72b93&width=434)

而目录文件中保存着文件名和索引节点的对应关系。可以用ls -i命令查看。这也是同级目录下文件名不能重名的原因。
数据块里面存放文件具体内容,占据文件系统的绝大部分空间。

linux引入拓展文件系统即Ext FS,性能不令人满意,后来引入Ext2第二拓展文件系统。
image.png

4.1.2 文件的类型

在linux的文件系统中,文件的inode里面st_node成员共有16位,其中高4位代表文件类型,低12位表示文件权限。

普通文件(rugular file)
image.png
目录文件(directory)
image.png
字符设备文件(character device)与块设备文件(block device)
image.png
符号链接文件(symbolic link)
image.png
image.png
FIFO文件(fifo)
image.png

socket套接字文件(socket)
image.png

4.1.3 文件的访问权限

用户分为3类:文件所有者(owner),文件所属组成员(group),其他用户(other)。
权限的表示方法通常有三种:字母,数字,符号常量。
三种方式都能表示权限,但只有8进制数字和符号常量形式(作为参数只能用数字或宏定义)可以用于编程代码中。
image.png
image.png

新建文件的权限=666-umsak值;
新建目录的权限=777-umask值;
umask定义对象是用户,不受操作系统的统一定义。
image.png

4.2 访问文件的内核数据结构

要访问一个文件时,系统需要在内存中建立相应的数据结构来记录访问文件所需要的各种信息,包括内存inode表,文件表,用户文件描述符表。

image.png
image.png
用户通过文件名向系统发出访问文件的请求,系统根据文件名在磁盘文件系统的inode表中查找到该文件的inode,同时将该inode复制到内存的inode表中,以便提高访问inode的速度。内存inode表是用户用到的文件inode在内存的拷贝。内存中inode会比磁盘inode多一些信息,比如内存inode是否被修改过的标记、内存inode引用计数等。
image.png

系统还要建立一个文件表,用于记录系统中所有打开的文件。当用户打开一个文件时,都要在该表中登记一个表项,如果两次open都是打开同一个文件,就在文件表中登记两个表项。
对于每一个进程,系统也要建立一个用户打开文件描述符表来记录每个用户当前打开的所有文件。

4.3 文件基本I/O操作

文件系统处理文件所需要的信息都包含在一个名为索引节点(inode)的数据结构中。
几个进程能打开同一个文件,文件系统就会给每个进程分配一个独立的打开文件对象和文件描述符。

4.3.1 打开/创建文件

image.png
image.png
需要注意的是,系统调用open总是得到一个最小可用的文件描述符。该文件描述符指向一个新的打开文件表项。
打开方式flags必须取只读方式(O_RDONLY)、只写方式(O_WRONLY)、读写方式(O_RDWR)、追加方式(O_APPEND)。

4.3.2 读文件

image.png
image.png
对于文件的读写,每个文件都有一个读写指针,指向该文件下一次读写的位置。当打开一个文件时,读写指针为0,即指向该文件的开始位置;每次执行读写操作后,如果执行成功,则读写指针会自动移动。

4.3.3 写文件

image.png
image.png

4.3.4 文件偏移量

image.png
image.png
image.png

4.3.5 文件定位函数

改变读写指针位置,可以使用lseek
image.png
image.png
image.png
对于读写指针已经超过文件长度时执行写操作,linux系统会先将文件的长度延长到当前位置,然后再写入,延长的部分用ASCII码0填充,成为空洞。而空洞是否占据磁盘存储空间由文件系统决定。
当父进程通过folk创建子进程后,子进程从父进程那里继承了用户文件描述符表,也就是说父子进程此时拥有内容一样的用户文件描述符表。

4.3.6 关闭文件

image.png
image.png
image.png

4.4 文件访问的同步

  • ANSI C:这一标准是 ANSI(美国国家标准局)于 1989 年制定的 C 语言标准。 后来被 ISO(国际标准化组织)接受为标准,因此也称为 ISO C。
    ANSI C 的目标是为各种操作系统上的 C 程序提供可移植性保证,而不仅仅限于 UNIX。 该标准不仅定义了 C 编程语言的语发和语义,而且还定义了一个标准库。这个库可以根据 头文件划分为 15 个部分,其中包括:字符类型 ()、错误码 ()、 浮点常数 ()、数学常数 ()、标准定义 ()、 标准 I/O ()、工具函数 ()、字符串操作 ()、 时间和日期 ()、可变参数表 ()、信号 ()、 非局部跳转 ()、本地信息 ()、程序断言 () 等等。
  • POSIX:该标准最初由 IEEE 开发的标准族,部分已经被 ISO 接受为国际标准。该标准的具体内容 见 1.1.3。POSIX.1 和 POSIX.2 分别定义了 POSIX 兼容操作系统的 C 语言系统接口 以及 shell 和工具标准。这两个标准是通常提到的标准。POSIX 表示可移植操作系统接口(Portable Operating System Interface ,缩写为 POSIX 是为了读音更 像 UNIX)。电气和电子工程师协会(Institute of Electrical and Electronics Engineers,IEEE) 最初开发 POSIX 标准,是为了提高 UNIX 环境下应用程序的可移植性。然而,POSIX 并不局限于 UNIX。 许多其它的操作系统,例如 DEC OpenVMS 和 Microsoft Windows NT,都支持 POSIX 标准,尤其是 IEEE Std. 1003.1-1990(1995 年修订)或 POSIX.1,POSIX.1 提供了源代码级别的 C 语言应用编程 接口(API)给操作系统的服务程序,例如读写文件。POSIX.1 已经被国际标准化组织(International Standards Organization,ISO)所接受,被命名为 ISO/IEC 9945-1:1990 标准。

image.png
image.png
当用户调用write向文件中写数据时,操作系统并不是立即将数据真正写入磁盘中,而是先将数据写入磁盘缓冲区中,事后再将磁盘缓冲区中的内容更新到磁盘中。这样做提高了读写磁盘的效率,但是会出现磁盘文件和缓冲区暂时不一致的情况。如果用户程序执行了write但数据还没有更新到磁盘上时系统崩溃,就会造成数据丢失。
image.png

补充:
image.png
image.png