简介

文件

所有文件系统都需要进行存储检索信息, 但是内存空间受非持久性, 虚拟地址空间最大容量限制,
进程之间内存不共享等因素, 明显不能作为大型共享持久数据的存放地, 所以物理磁盘等物理存储介质
产生.
关于固态硬盘, IO 吞吐率等信息见The glossary of IO.
那么, 如何存储, 读取这些物理存储介质上的信息呢?
文件概念由此产生, 进程创建的逻辑信息单元, 一个磁盘会有成千上万文件, 每一个文件都是独立于其他
文件的. 每一个文件都是一个独立的物理地址空间.
那么, 如果对文件进行读取, 命名, 访问, 保护等操作呢?
那就是”文件系统”应该做的事情.

知识框架

关于文件系统的设计, 文件系统中的各类详细信息包含的内容实在太多, 我也不是非常了解, 这里主要
对文件系统的基本常识以及各个 OS 的常用文件系统做一些简单的介绍.
文件系统是一个分区或磁盘上的文件的逻辑集合, 其中每一个分区允许不同文件系统的逻辑来进行维护
和管理. UNIX 中一切都被认定为文件, 包括物理设备等, 万物皆文件.
关于分区命令, 见分区

根据引用的文章, 文件系统的整体知识框架(我也不是非常熟悉, 目前也没时间认真了解全部)分为 4 个部分:

  • 文件
  • 目录
  • 文件系统如何实现: 布局, 空间分配结构, inode, 目录实现, 日志文件系统, 虚拟文件系统
  • 文件系统的管理和优化: 磁盘空间管理, 备份系统, 文件系统一致性, 文件系统性能

整体知识框架如下图:框架

文件和目录

命名

在进程创建一个文件之后, 必须给文件一个命名, 当进程终止(就是我们平常创建文件保存)时, 文件仍旧
会存在, 此时其他进程就可以通过”名字”来访问该文件.
不同的文件系统, 文件的命名方式可能不同, 其中主要讲解”UNIX”和”MS-DOS”, 下图就简单介绍了在不同
文件系统下大小写是否同一个文件:
文件命名

另外, 现代操作系统除了一个特殊字符外, 都允许文件随意命名, 但是有时候还是以常规命名方式最好.

关于 MS-DOS系统, 这里进行一下简单的文件系统更换历史:

  • FAT-16: windows95/windows98 系统使用的 MS-DOS 系统.
  • FAT-32: windows98 对 FAT-16 扩展, 后续系统都支持
  • NTFS: 基于 Unicode 编码, windows7/8/10
  • ReFS: windows8/10, 但是需要额外开启

关于上述几个 windows 文件系统的优缺点, 见微软官网介绍.
另外, 大部分系统的文件命名方式都是以文件名.扩展名的方式来进行文件命名, 这种方式对于 UNIX
系统来说是不强制的, 在 OS 看来是否定义扩展名无所谓. 但是对于一些特殊程序, 例如编译器等还是
要求文件扩展名和文件本身就匹配的, 当然, 对于开发者, 使用者而言更是如此.

Windows 不同于 UNIX, 用户可以在 OS 中注册扩展名, 并指定使用哪些程序来打开此类扩展名.

关于文件查找命令, 见文件查找命令

目录结构

虽然在 UNIX 系统中万物皆文件, 但是目录本身还有一些区别的, 目录或者文件夹用于记录文件位置,
通过层次目录系统或者目录树, 将成千上万的文件分散在整个磁盘中, 系统在通过树快速的定位
所需文件, 这里就涉及到文件的绝对路径相对路径信息, 目录结构如下:
层次目录系统

关于树查找, 可以查看树查找算法.

文件属性

基本

文件包含文件属性和数据, 例如文件创建时间, 文件大小, 这些信息就是文件的属性或者metadata:

  • 创建者文件 ID
  • 文件当前所有者
  • 密码: 访问文件所需密码
  • 加锁标志: 0, 1
  • 创建时间
  • 最后一次访问时间
  • 最后一次修改时间
  • 文件大小
  • 文件最大长度
  • 其他等等

除了上面的基本属性, 下面主要讲解下文件的权限控制信息. 普通文件或者目录拥有12 个标志位,
当然这些标志位仅仅是权限信息, 并非ID 标识信息.
一般而言, 文件常见的权限表现形式为十位权限标识法: -rwxrwxrwx, 这里后 9 位分别表示:

  • 文件拥有者权限(UID): rwx
  • 文件拥有者所属组权限(GID): rwx
  • 其他用户权限(OUID): rwx

其中第一位表示文件类型, 可以使用ls -l来查看各个文件信息, 下面简单介绍常见的文件类型

  • -: 普通文件
  • d: 目录
  • s: socket 文件
  • p: pipe 管道文件
  • l: symbolic link 符号链接文件
  • b: block-oriented device file 面向块设备文件
  • c: character-oriented device file 面向字符设置文件

SET 位

除了上面的 9 位权限位之外, Linux 还设置了除正常读写之外的附加权限位

  • SET 位权限: suid, sgid
  • 粘滞位权限: sticky

suid/sgid 是为了使”没有取得特权用户要完成一项必须要有特权才可以执行的任务”而产生的.

  • SUID: 对文件属主用户增加 SET 位权限
  • SGID: 对文件属组用户增加 SET 位权限

实现原理就是, 用户 A 进程在执行设置了用户 B(或其组) 的文件 file 之时, 进程中会临时更改文件
file 的UID信息, 从而使用户 A 进程有权限进行后续操作, 当然这种方式非常危险.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 1. 创建一个不可执行文件, 其文件输出为:-rw-r--r--
touch unexec.txt
ls -l

# 2. 设置suid, 此时终端显示该文件变红, 属性输出为: -rwSr--r--, 注意这是大写的 S
chmod u+s unexec.txt
ls -l

# 3. 创建可执行文件, 属性输出为: -rwxr-xr-x
touch exec.sh
chmod +x exec.sh
ls -l

# 4. 设置suid, 属性输出: -rwsr-xr-x, 注意是小写s
chmod u+s exec.sh
ls -l

UNIX 系统中设置了 SUID 的文件有:

  • /bin/su
  • /bin/mount
  • /bin/ping

SET 位常用于协同办公

Sticky 位

Sticky 用于为目录设置特殊的附加权限, 目录被设置了粘滞位权限后, 即便用户对该目录有写的权限,
也不能删除该目录中其他用户的文件数据.

1
chmod +t dir

其输出:

1
2
-rwsr-xr-t 表示设置了粘滞位且其他用户组有可执行权限
-rwSr--r-T 表示设置了粘滞位但其他用户组没有可执行权限

文件系统

分类信息

从上面可知:文件系统是一个分区或磁盘上的文件的逻辑集合, 其中一个分区是一个信息的容器, 每个分区
允许不同的文件系统进行逻辑维护和管理. 那么, 都有哪些文件系统呢?

我们先介绍一下日志系统, 日志系统是干嘛的? 比如, 我们需要移除一个文件, 其步骤如下:

  • 在目录中删除文件
  • 释放 inode 到空闲 inode 池
  • 释放磁盘块到空闲磁盘池

在正常情况下, 这些操作都是没有任何问题的, 但是如果在这之间系统崩溃了呢? 比如突然断电啥的.
日志系统保留磁盘写入期间对文件系统所做的更改的日志或日志, 该日志可用于快速重建可能由于
系统崩溃或断电等事件而发生的损坏.

日志系统的进化:

  • 日志文件结构系统: 减少磁盘的寻道时间以匹配内存容量的增加
  • 日志文件系统: 上着衍射出的日志系统, 记录系统下一步将要做什么的日志, NTFS/EXT3/OSX 都使用该系统

上文中提及到每一个分区都有自己所属的文件系统, 比如 Windows 的不同磁盘就可以指定不同的系统. UNIX
系统则不同于 Windows, 其使用一个统一的结构来将多种文件系统整合, 比如ext2作为根系统, ext3
装载在/usr下等等. 这个统一的结构就被称为虚拟文件系统:

虚拟文件系统

开发者都了解, 在计算机的时间里, 分层或者代理在很多地方被使用到, 比如 TCP/IP 协议等, 分层或者
代理解决所有因为性能, 不统一等等问题. 虚拟文件系统就相当于底层文件系统的一层代理, 从而确保
系统能够正常使用.

在 2.1 节我们简单介绍过 windows 的文件系统, 现在我们简单介绍下 Linux 文件系统信息, OSX 就不介绍

  • MINIX 文件系统: Linux 早起的一个极小的类 UNIX 系统
  • ext: 在 Linux 内核中的新虚拟文件系统(VFS)抽象层, 解决了前辈存储空间问题, 达到 2GB
  • ext2: ext 提出 1 年后提出, 提供了 GB 级别的最大文件大小和 TB 级别的文件系统大小
  • ext3: ext2 提出 2 年后提出, 解决不一致状态等问题, 增加日志系统等信息
  • ext4: 2006 年发表, 一个显著扩展 ext3 但仍然依赖于旧技术的临时技术

系统性能

关于内存, 物理介质的 IO 读写性能, 请看下图:

性能

参考:

彻底理解文件系统