目录即文件-Ext文件系统收尾篇

目录即文件:Ext 文件系统的最后一块拼图(附 cd 命令的实现原理)

我的github:(https://github.com/xcx55/ubuntu-linux-project)

感谢各位大佬参观我的github!!

这是 Ext 系列笔记的收尾篇。前面几篇把磁盘硬件、块、分区、inode、位图、路径缓存都过了一遍,

剩下的最后一个疙瘩是:目录,到底是不是文件? 以及我们天天敲的 cd ..,内核到底做了什么?


一、目录就是文件,只是「解读方式」不同

先给出结论,然后逐条验证:

文件和目录,在磁盘和文件系统的视角下完全平等。它们都是「文件项」,都由 inode(属性)+ data blocks(数据)构成。

数据块里存什么,才是二者唯一的分野:

普通文件 目录
inode 属性(权限、大小、时间...) 属性(多一个「我是目录」的标志位)
data blocks 内容 文件正文 「文件名 → inode number」映射表
谁负责解读 文件系统 + 应用 内核(系统调用层用 if/else 分流)

那我们在 ls 时看到的「目录带颜色、带 / 尾缀」是怎么回事?

  • 颜色和 / 是 shell 为了人眼友好故意打印的,不是磁盘上的事实;
  • 内核判断「这是目录」靠的是 inode 里的标志位,而不是内容长相。

换句话说:「是不是目录」这个身份,是从 inode 读出来的;「目录里有什么」,是从数据块里读出来的。 前者是属性,后者是映射关系。


二、路径背后站着的,是那棵 dentry 树

前面我们讲过:路径解析的产物是 struct dentry 组成的全局多叉树(外加 hash 加速)。

所以「路径」这个东西,本质上只是给用户看的一串字符串,它背后真正的对应物是:

复制代码
"/home/user/a.txt"  ──解析──▶  dentry 树上的一个节点  ──▶  struct inode(+inode number)

PCB 里的 pwd 指针,就是这棵树上的一个「当前位置坐标」 (注意区分:shell 里的 PWD 只是个字符串环境变量,内核的 pwd 是指针)。


三、cd .. 的一瞬间,内核做了哪些事

把一个命令拆开看,逻辑非常清爽:

  1. shell 解析命令行参数 ,识别出 cd 和参数 ..
  2. 因为 ..父目录这一硬链接的映射 ,内核到当前目录 inode 的数据块里,查「.. 对应的 inode number」;
  3. 顺着该 inode number 拿到父目录 inode(可能触发一次磁盘 IO,构建/命中 dentry 缓存);
  4. 在 dentry 多叉树中移动位置,修改 PCB 的 pwd 指针,指向父目录的 dentry;
  5. shell 把新目录的字符串结果写进 1 号文件(stdout),于是你在屏幕上看到提示符变了。

cd .cd -cd /abs/path 同理,只是走的树路径不同。所谓「切换目录」,就是换个指针指向,加一次 stdout 写入------没有复制、没有搬移数据。


四、顺带说清:指令从哪来,参数又从哪来

这一条经常把人绕晕,其实是两条独立的路:

  • 命令本身 :shell 拿着你敲的命令名,去 PATH 环境变量列出的目录里逐个查找可执行文件;
  • 命令要用到的文件和参数 :它不走 PATH ,直接用自己进程 PCB 里继承来的 pwd 指针(以及相对路径解析)就能定位。

这也是为什么 ./a.outa.out 行为不同:

  • a.out → 去 PATH 里的目录找(当前目录通常不在 PATH 里,所以常报 command not found);
  • ./a.out → 明确以「当前工作目录」为起点解析,也就是显式使用那个 pwd 指针。

这就是 . 存在的意义:把「当前目录」和「PATH 搜索」彻底分开。


五、Ext 系列小结

层次 核心结论
硬件 磁盘是黑盒,只认 LBA;机械访问慢,要少碰
抽象 扇区 → 块(4KB)→ 块号即「文件系统的指针」
组织 分区 → 块组 → Super Block / GDT / 双位图 / Inode Table / Data Blocks
索引 文件 = inode(属性)+ Data Blocks(内容),靠 i_block[] 关联,大文件用多级间接
命名 目录 = 「名字 → inode number」映射表;硬链接复用 inode,软链接存路径
加速 dentry 多叉树 + hash 路径缓存,一切性能优化都是空间换时间
统一 目录与文件同构,路径机制先于分区机制,挂载把文件系统接进目录树

到这里,从磁头下的一块扇区你敲下 cd .. 时指针的一次移动,整条链路就闭合了。


本文基于 2026-07-18 的学习笔记整理。下一篇进入「库文件」系列:从 .o 到静态库、动态库,再到 ELF 与进程地址空间。

相关推荐
牵猫散步的鱼儿2 小时前
重载、重写(覆盖)、重定义区别
c语言
phltxy3 小时前
C 语言指针:从内存地址到灵活的数据访问
c语言
_艾伦 耶格尔.3 小时前
进程间通信
linux
phltxy4 小时前
C 语言中的数据存储:从类型到二进制位
c语言
Liuqy-054 小时前
Linux IO编程——静态库、动态库
linux
彧azz4 小时前
Linux 环境下 Redis 学习总结:数据类型、持久化、锁、事务、主从与缓存问题
linux·redis·笔记·学习·面试
-梅5 小时前
linux(8) 软硬链接
linux·运维·服务器
AIgorithmGEEK5 小时前
[Linux]线程三部曲(上):一个执行流的诞生——从操作系统一路拆到 pthread_create
linux·线程·pid
琥珀色糖6 小时前
SimlpeHttp
linux·服务器