Unix/Linux编程:Unix文件系统回顾

基本定义

从用户的观点来看,Unix定义一个文件包含一个字节序列。理论上,Unix文件可以任意长;在实际中,一个文件的长度是收到物理存储设备空间限制的。Unix文件可以动态的增长,文件系统不能对文件大小进行预定义或者对文件的空间进行预分配。而且,只要应用程序向文件中写入任何数据,文件都会自动增长。

从概念上来说,Unix从零开始对文件中的字节进行计数。在任何时候,文件的大小(size)都被定义成它所包含的字节数。Unix文件系统允许用字节数作为基准对文件进行随机存取,它允许应用程序移到文件中的任何位置并对该位置上的数据进行存取

无记录界限的字节序列

每个Unix文件都是一个字节序列;除了数据本身之外,系统并不提供任何其他的结构。具体来讲,Unix没有记录界限、记录分块、索引文件、类型文件的概念。当然,有可能某个应用程序会创建记录文件并在后来对它进行存取。关键是文件系统本身并不理解文件的内容,使用某文件的应用程序必须认同该格式

文件拥有者和组标识符

Unix为多用户提供账号,并为每个用户分配一个数值型的用户标识符,该标识符用于系统中的记账与鉴别。每个Unix文件都有一个文件owner,它用创建该文件的用户标识符来表示。所有权信息是于文件存储在一起的。

除了用户标识符之外,Unix通过系统管理员为用户组分配一个数值型的组标识符,以便在用户组之间能提供文件共享。在任何时候,某用户可以属于一个或者多个Unix组。当用户运行一个应用程序时,运行的程序继承了用户的文件拥有者标识符和组标识符。每个Unix文件都属于一个组,并在它内部存在组的数值标识符。系统把存储在文件中的文件拥有者标识符以及组标识符与特定进程的用户以及组标识符进行比较,以此来决定该进行对这个文件进行何种操作。

保护和存取

Unix存取保护机制允许文件拥有者分别控制文件拥有者、文件组成员以及所有其他用户对文件的存取。保护机制允许文件拥有者指明每个集合中的用户所允许的读、写或执行文件的权限。下图显示把Unix’文件存取权限看成一个保护比特矩阵
在这里插入图片描述
在内部,Unix系统把文件存取保护矩阵编码在一个二进制整数的低位比特中,在使用这个对保护位编码的整数时,Unix使用了名词文件模式(file mode)和文件存取模式(file access mode)。下图说明了Unix是如何把文件保护位编码在一个文件模式整数的9个低位比特中。

在这里插入图片描述
当保护整数的值写成八进制时,最右边三个数字给出了文件拥有者、文件组成员和其他用户的保护位。比如,0700指定文件拥有者可以读、写、执行文件,但其他用户不能对它进行访问

打开-读-写-关闭范例

在Unix中,应用程序使用打开-读-写-关闭(open-read-write-close)方法对文件进行存取。为了对某个文件进行存取,应用程序必须调用函数open,传给它文件的名和一个参数,该参数模式所要进行的存取:

fd = open("filename", O_CREATR | O_RDWR, 0644);

数据传送

应用程序用read把数据从文件传输到内存中,用write把数据从内存传输到文件。比如下面代码要求系统从文件描述符fd中读取24字节的数据到buff中

n = read(fd, buff, 24);

read和write从文件当前位置开始传送,当这两种操作结束时它们都会修改文件当前位置。比如,如果一个应用程序打开一个文件,文件当前位置为0,应用程序从文件中读出10字节数据,那么read结束之后,文件当前位置将变为0

如果程序要读取的字节数比文件所要包含的多,那么read把文件所有数据全部读出然后返回读取的个数;如果调用read时文件当前位置在文件的末尾,那么read将返回0表示文件end-of-file的情况

搜索目录权限

Unix用目录把文件按一种层次结构进行组织,目录中有文件和其他目录。系统用同样的9为保护模式来描述目录,与一般的数据文件一样,read权限位决定一个应用程序能否得到某个目录的所有文件列表,write权限位决定一个应用程序能发向该目录中插入或删除文件。每个文件都有各自的权限比特集合,用以决定对文件的内容可进行何种操作。目录权限仅指定了对目录本身可进行的操作

目录中可以由应用程序。但是它们不包含已编译的代码本身。因此,它们不能像一个应用程序一样执行,所以对目录来说,执行权限是没有意义的。Unix把目录的执行权限比特解释成搜索权限。如果某个应用权限具有搜索权限,它就能引用该目录中的文件;否则,系统不允许对该文件的任何引用。搜索权限可以用来隐藏或打开文件分层结构中的某一整个分支,同时不对该分支中任何一个文件的权限加以修改。

随机存取

当打开一个文件时,可以吧文件位置设置到文件的开始或者末尾。打开一个文件后,通过lseek可以改变问的当前位置。比如,下面代码把当前文件位置的描述符fd移到100字节处(绝对位置)

lseek(fd, 100, L_SET);

搜索超过文件的结束

Unix文件系统允许程序移到文件的任何位置,即使所指定的位置超过当前文件结束的地方。如果应用程序定位到一个确实存在的字节位置并写入新的数据,则新的数据覆盖该文件上的旧数据。如果程序定位超过文件结束的地方并写入新的数据,则文件系统扩展文件的长度。从用户的观点来看,系统将用空字节(值为0的字节)来填补已有数据和空数据之间的所有间隙。如果程序试图从填补空隙的字节处开始读数据,那么文件系统将返回内容值为0的字节。
在这里插入图片描述
尽管文件系统看起来用空字节填补了空隙,但是存储结构可以模拟空字节而不在物理媒体上表现出来。因此,文件大小记录了数据被写入的最高字节的位置,而不是已经写入的字节的总数

文件位置和并发读取

Unix文件系统允许多个应用程序并发的读取同一文件。每个打开的文件的描述符引用一个记录文件当前位置的数据结构。当一个进程调用fork创建一个新进程时,子进程继承了父进程在调用fork时已经打开的所有文件的描述符的副本。这些描述符指向一个统一的用来存取文件的数据结构。因此,如果这两个进程中的任何一个改变了文件的位置,而另一个进程中的文件描述符位置也要发生改变

每次调用open都生成一个新的描述符,它的文件位置独立于前面调用open时所生成的描述符。因此,如果两个应用程序对同一个文件都调用了open,那么它们都维护一个各自独立的文件位置

每次调用open都将产生一个新的文件存取点,它存储了文件偏移量。把当前文件位置从文件本身独立出来,可以运行多个应用程序互不干扰地对同一文件进行并发存取。它还允许由lseek操作在不改变文件本身的情况下修改某个程序的文件位置。

在并发存取时"write"语义

当两个程序对某个文件并发写入时,它们可能会产生冲突。

Unix没有互斥机制,也没有定义并发存取的语义,它只是指出一个文件总是含有一个最近写入的数据,这样,保证正确性的责任就落在了程序员身上。(在Linux中提供了一种锁机制flock)

索引节点inode:存储在文件中的信息

除了数据本身外,Unix还在稳定存储设备上存放了有关每个文件的信息。这些信息保存在一个称为文件索引节点(inode)的结构中。索引节点中包含了很多域,包括:文件owner、组标识符、模式整数、最近一次修改时间、文件长度、文件所驻留的磁盘设备和文件系统、文件的目录页数、文件当前所用的磁盘块数以及文件类型(普通文件?目录?…)

索引节点的概念有助于解释几个Unix文件系统的特色,这些特色在NFS中也使用了。首先,Unix把文件所有者关系和文件保护比特等信息从文件的目录项分离出来。这样就使两个目录项可以指向同一文件。Unix用术语链接(link)或者硬链接(hand link)来指某个文件的一个目录项。

stat操作

Unix系统函数stat从它的索引节点中提取文件信息并把它返回给调用者。该调用者拥有两个参数:文件路径名和存放结构的结构地址

stat(pathname, &result_struct);

任何用户都可以调用stat来得到文件信息,即使该文件是不可读的。但是调用者必须允许搜索在指定文件的路径上的所有目录,否则stat返回一个错误

文件命名机制

尽管用户想象所有文件和目录但是某个文件分层的一部分,但是分层是通过一种文件命名机制获得的。命名机制允许系统管理员把几个小的分层综合成一个概念性的层次结构。用户对下层的文件系统结构和多个组件如何形成的Unix的分层结构知之甚少,因为命名机制完全隐藏了这个结构。当NFS在某个Unix中运行时,它从这个命名机制中大为获益,它把远程文件和本地文件集成到一起

Unix命名机制的最初动机产生于计算机系统有多个物理存储设备。为了让用户免于既要识别文件又要识别磁盘,Unix:允许系统管理员把一个磁盘上的层次结构连到另一个磁盘的层次结构上。其结果是一个统一的文件名空间,它允许用户在不知道文件位置的情况下工作。命名机制是这样运行的:

  • 由管理员指定某个磁盘上的分层结构为跟
  • 管理员在根的分层上创建一个空目录,空目录的全路径可有/a给出
  • 管理员指定命名机制在/a目录上覆盖了一个新的分层结构(通常是从其他磁盘上)

一旦管理员连接了新的分层结构,命名机制自动的把新连接的分层结构中的具有路径b的文件或者子目录映射到形式为/a/b的名字上。即:

Unix命名机制提供给用户和应用程序一个统一的文件分层结构,即使底层的文件跨越了多个物理磁盘

文件系统mount

上面说明了把整个磁盘作为分层结构的一部分而连接到系统上,事实上,Unix系统比这更具有通用性。它允许系统管理员把一个物理磁盘划分成一个或者多个文件系统。每个文件系统都是一个独立的分层,它包含文件和目录。一个文件系统可以在任何一点上连接的统一的分层结构上去

Unix命名机制依赖于mount系统调用来构造统一的分层结构。系统管理员用mount指明在一个磁盘上的文件系统如何连接到分层结构上。通常,由管理员来安排在系统启动时自动执行必要的安装。下图一个文件系统已经安装成为一个统一的分层结构

在这里插入图片描述
上图:

  • 硬盘1上的文件系统0作为分层结构的根目录。
  • 硬盘1上的文件系统1已安装为目录/a
  • 磁盘2上的文件系统0已安装为目录/c

mount用一个新的文件系统完全覆盖了最初的目录。通常,系统管理员创建一个用来进行安装的目录。但是,如果将被某个文件系统安装的目录在安装之前已经有文件了,则它们将被完全隐藏起来(也就是说,即使对某个系统管理员来说也是不可存取的),直到文件系统的安装被撤销位置。

除了一些例外以外,对用户来说,安装完成不可见:

  • 如果ls列出根目录/下的所有内容,将显示:a、h、c
  • 如果ls列出/a下的所有内容,将显示:g、h
  • 如果ls列出/c/s中的所有内容,将显示:u、v

注意:用户不能跨文件系统创建硬链接

一旦用mount系统函数生成了一个Unix文件系统分层结构,那么各文件系统之间的连接就称为透明的了。有的文件和目录可以驻留在一个硬盘上,而另一些文件和目录可以驻留在其他硬盘上,用户无法区分它们,因为这种安装在一种同一的命名机制下隐藏了所有的界限。

优点:

  • 允许管理员选择文件的存储位置,减少存取争用
  • 在偶然丢失的情况下使目录保持孤立
  • 提供了一个简便的方法把远程文件引入到Unix分层结构中

Unix文件名解析

当给出一个全路径名时,Unix文件系统机制沿着概念性的分层结构来解析文件名。在Unix中,名字解析意味着找到标识一个文件的索引节点。为了把一个全路径名解析出来,文件系统从分层结构的根开始,每次跟踪一个目录。比如/a/b/c/d,文件系统打开根目录并在其中搜索子目录a,一旦发现/a,它就打开该目录,并搜索子目录b。同样,它在目录b中搜索目录c,搜索c中是否有一个文件或者目录d。名字解析软件可以每次从全路径名中提取出其中的一部分,因为斜杠把各个部分分隔开了

Unix一次解析一个全路径名的一部分。它从分层结构的根以及路径的开始出发,重复的从路径中提取出下一部分,并找到具有该名字的文件或者子目录。

符号链接

符号链接是一个特殊的文本文件,它包含了另一个文件的名

符号链接的主要好处在于它的通用性:因为一个符号链接可以包含任意一个字符串,它可以对任意文件或者目录命名。比如,文件系统禁止创建到某个木兰山更得硬链接但是允许用户创建一个到该目录的符号链接

符号链接的主要缺点在于它们缺乏一致性和可靠性。比如,我们可以创建一个到某个文件的符号链接,然后把该文件移走,使符号链接指向一个不存在的对象。事实上,我们也可以创建到一个不存在文件的链接,因为系统在创建符号链接时并不检查它的内容。我们还可以创建一个形成回路的符号链接,或者两个符号链接相互指向对方(此时open会产生一个运行时错误)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值