资讯动态

文件共享与保护:inode、硬链接、软链接与Linux权限机制详解

发布时间:2026/10/22 4:11:29 来源:尧图企业网站定制
最近在整理操作系统笔记我发现“文件共享和保护”这一章在课本里篇幅不算长却是最容易在实际项目里翻车的内容。明明就是一个普通的文本文件为什么别人能看见却改不了为什么我删掉软链接原文件居然还在为什么把一个目录共享出去之后别人就能把整个项目目录“顺走”这些问题的答案几乎都藏在文件系统如何实现“共享”和“保护”这两件事里。作为我这套 OS 学习笔记的第 34 篇这篇我打算换个方式写不完全按课本顺序罗列知识点而是从“一个问题是怎么引出来的”出发顺着原理讲到命令再从命令回到原理。这篇文章的目标读者很明确正在学操作系统、被绕昏头的学生以及平时要跟 Linux 服务器打交道、经常被权限搞得头大的开发同学。你可以把它当一篇独立的原理梳理也可以当作遇到实际问题时的排查手册来用。1. 先看本质共享不过是指向同一个 inode 的多个入口1.1 为什么需要共享没有“引用”就只能复制在单用户操作系统时代文件共享这个概念基本不存在。整个机器只有你一个人所有文件天然都是“我的”不存在让别人看、让别人改的问题。多用户系统出现以后事情立刻不一样了用户 A 写完一份需求文档用户 B 今天也要改如果让 B 复制一份过去后面就会冒出两个版本你说不清楚哪个才是权威版本。更要命的是系统里的可执行程序、公共库文件如果每个用户都复制一份磁盘很快就会塞满。教材在讲这一节时通常会把共享的需求提炼成三类第一多个用户协同完成同一个任务需要读写同一份文件第二系统级的公共资源希望能全局可见但同时只保存一份第三用户希望在自己的不同目录下快速访问同一个文档不用重复拷贝。这三句话翻译成一句大白话就是让多个不同路径都能访问到同一个文件实体而不是维护多个副本。这里有个很容易被忽略的细节共享省的不只是磁盘空间还有“一致性维护成本”。如果同一个数据只存在一份那么任何人改完其他人立刻就能看到最新结果不存在同步问题。副本一多你就要引入版本管理、同步机制这些都会显著增加复杂度。所以文件共享本质上是操作系统提供的一种“引用”能力让同一份数据可以被多个入口引用。1.2 目录项和文件实体是两码事要彻底理解文件共享必须先打破一个直觉我们平时说的“文件”其实包含两个完全不同的东西——目录项dentry和文件实体inode 数据块。磁盘上真正存储数据的是 inode 和数据块。inode 里记录了文件的元数据比如大小、属主、权限、时间戳以及指向数据块的指针。而目录项是什么它是我们在路径中看到的那个“名字”。目录项的核心作用是把文件名映射到对应的 inode 号。也就是说当我们访问/home/a/report.md时内核要做的事情是沿着目录层级找到report.md这个目录项读出它指向的 inode 号再通过 inode 找到真正的数据块。这个设计一旦讲清楚文件共享的定义就非常清爽了让两个或两个以上的目录项指向同一个 inode。比如/home/a/report.md和/share/report.md这两个路径表面上看起来是两个位置但如果它们内部记录的 inode 号相同它们就是同一个文件的多个入口。这时候你通过其中一个路径修改文件另一个路径看到的内容也会跟着变因为它们本来就是同一份数据。1.3 共享省了空间却让“所有权”变得模糊一提到“共享”的好处很多人第一反应是省空间这当然没错。可共享带来的麻烦也同样明显当一份文件可以被多个路径访问时就说不清楚谁是它的“主人”了。谁有权修改谁有权删除删除之后别人要不要知道这些问题不解决共享就是灾难。所以操作系统不会直接说“谁都能访问”而是设计了两套配套机制一套是共享实现机制解决“怎么让多个入口指向同一份文件”也就是硬链接和软链接另一套是保护机制解决“共享归共享每个用户到底能对这个文件做什么”也就是权限控制、加密等手段。理解了“共享会模糊所有权”这个前提后面很多看似奇怪的限制比如目录不能硬链接、权限位里有 rwx 三分组就都有了合理动机。2. 硬链接与软链接两条路径两种性格2.1 硬链接在同一个文件系统里再造一个目录项如果需要“在另一个位置访问到已有 inode”最直接的办法就是创建硬链接。系统会新建一个目录项把它指向某个已经存在的 inode同时把这个 inode 的链接计数加 1。数据块一个字节都不会复制只是多了一个“门牌”。在 Linux 里ln target link_name就是在创建硬链接。但硬链接有几个非常硬性的限制必须理解清楚。第一不能跨文件系统。这是因为 inode 号只在它所在的分区范围内有效。两个不同的磁盘分区各自都有编号为 100 的 inode这完全正常。如果允许硬链接跨分区你就没法通过 inode 号唯一定位文件所以硬链接只允许发生在同一个文件系统内部。第二不能对目录创建硬链接。我到现在还经常看到有人问“我想把整个目录链过去为什么 ln 不让我链”。答案下一节详细说这里先记住结论对目录做硬链接会导致目录树出现环破坏树形结构所以系统直接禁止。第三硬链接没有“主次之分”。有人会觉得硬链接是“复制出来的副本”这是很大的误解。实际上原文件名和硬链接名是平级的它们指向同一个 inode没有任何一个比另一个更“原始”。你删除最初创建的那个路径只要还有别的路径引用这个 inode数据就依然存在。2.2 软链接存路径字符串天生就会“断”软链接也叫符号链接的思路和硬链接完全不同。它不是给现有 inode 加目录项而是创建一个新的、独立的文件实体。这个特殊的文件里保存的是另一个文件的路径字符串。当你访问软链接时内核会读出这个路径串再去解析它指向的目标。用ln -s target link_name就可以创建软链接。软链接有它自己的特点。第一不存在引用计数问题。它不会让目标文件的链接计数加 1因为从 inode 层面看目标文件根本没多出一个入口。第二可以跨文件系统也可以指向目录。因为软链接里存的是路径路径跟文件系统编号没关系跨分区、跨设备都能用。第三天然会“断链”。如果目标文件被删除软链接并不会跟着消失它依然存在于目录里只是当你访问它时内核发现它指过去的路径已经不存在了于是报No such file or directory。很多新手第一次遇到这种情况会误以为自己把文件搞坏了其实只是链接失效了。这里我补充一个实用的认知软链接本身是一个文件它有自己的 inode、自己的大小大小等于路径字符串的长度。你用ls -l查看软链接会看到形如lrwxrwxrwx 1 user group 5 ... soft.txt - a.txt那 5 就是路径字符串a.txt的字节数。搞清楚这一点再看文件和链接之间的区别就不会再晕了。2.3 两种链接的选型标准我平时是怎么决定的硬链接和软链接不是谁替代谁的关系它们在设计目标和适用场景上完全不同。我做一个对比表方便你对照着选对比项硬链接软链接本质新增一个指向相同 inode 的目录项新增一个保存目标路径的独立文件对目标 inode 引用计数的影响加 1不加能否跨文件系统不能能能否指向目录不能能目标被删除后只要链接数不为 0数据仍可访问链接永久失效断链访问效果跟原文件完全无差别路径解析时有区分但访问内容一致移动/打包时结构复杂容易丢失共享关系可能因为相对路径变化而失效我自己的选择标准很朴素同分区内、希望多个路径平等访问同一份数据优先用硬链接。比如我在服务器上维护配置模板希望在/etc/project和/data/template两个位置都能访问同一份配置用硬链接最合理。要链接目录、要跨分区、要给程序提供一个“快捷方式”、或者希望一眼能看出这是一个链接用软链接。还有一个小坑值得提醒如果需要在项目里同时打包软链接和它指向的目标文件要注意软链接的相对路径是否还能解析。很多时候移动整个目录之后软链接会变成“指向不存在的目标”的坏链这就是所谓“移动后失效”。硬链接没有这个问题只要还在同一个文件系统内inode 不会被移走。3. 共享引发的三大经典麻烦删除、循环、一致性3.1 删除语义与引用计数为什么删了“原文件”数据还在共享之后第一个麻烦出现在删除操作上。我们平时说“删除文件”在操作系统的实现层面其实是unlink也就是“解开这个目录项与 inode 的绑定关系”。对于普通文件目录项原本是唯一入口解绑之后 inode 的链接计数变成 0系统就会回收这个 inode 和它占用的数据块。但如果有两个目录项同时指向同一个 inode链接计数是 2删除其中一个路径只是把计数从 2 变成 1数据块还在另一个路径依然能正常访问。这其实是一个非常精妙的设计系统不需要人为判断“谁是文件主人”只要保证 inode 的引用计数大于 0数据就永远保留。所以“删除原文件”这个说法只对链接数为 1 的普通文件有意义。在共享场景里你删除的只是“一个入口”而不是“文件本身”。我在实际维护服务器时遇到过这种情况一个运行中的程序 Write 一个日志文件管理员嫌日志目录太乱清理时把主路径删了但另一个硬链接还指向同一个 inode于是日志文件一直在被写磁盘空间也被占用df 却显示已删。最后排查半天发现是链路计数不为 0 导致 inode 没有释放。遇到“文件删了但空间没释放”的情况检查硬链接数应该是第一反应。3.2 目录循环为什么系统不允许对目录做硬链接硬链接不能用于目录这个限制经常被当成“规则”背但很少有人仔细想过为什么。我可以把问题描述得很具体假设我们允许对目录创建硬链接然后执行ln /data /data/self让/data目录里出现一个指向自身的入口。此时如果你递归遍历/data会进入/data/self然后再进入/data/self/self一路无限嵌套下去永远没有尽头。对目录做删除、统计、复制这类递归操作时也同样会陷入死循环。正因为如此经典操作系统在文件系统层面直接禁止对目录建硬链接用硬性规则保证目录树始终是一棵树而不是一张可能带环的图。那么想共享目录怎么办用软链接。软链接不会增加目标目录的 inode 引用计数它只是一个“路径快捷方式”。即使软链接指向一个目录访问时也只是从这个路径字符串继续往下走目录树本身不产生环。另外还有一个容易出问题的地方符号链接如果指回自己的祖先目录在递归遍历时若不加以限制同样会陷入无限循环。很多查找工具在处理符号链接时默认不跟随或者设置深度上限就是因为这个原因。3.3 多人同时修改文件系统自己解决不了的一致性共享还带出一个非常现实的业务问题两个用户同时打开同一个文件各自修改并保存最后会发生什么从文件系统层面看写入操作会被拆成多个磁盘操作最终结果很可能是“后写覆盖先写”。A 写了版本 1B 紧接着写版本 2文件里最后留下的可能是版本 2也可能因为未做同步出现半旧半新的混合内容。这叫做“丢失更新”是共享场景中最典型的数据一致性问题。关键认知是文件系统不负责解决这种业务级别的一致性。操作系统能保证的是单个写入操作要么成功要么失败以及崩溃后不会出现元数据错乱但它不知道你写的文档、代码、数据表应该以什么规则合并。于是实际项目里会用更上层的机制来处理进程间用文件锁flock、fcntl防止并发写入团队协作干脆引入版本控制系统把“共享文件”的问题从文件系统上彻底挪走。有同学会觉得这有点“推卸责任”但换一个角度想文件系统如果把业务合并规则硬编码进去那才真是灾难。它只应该提供基础同步原语把“谁先改谁后改、冲突怎么合并”的决定权留给应用去完成。4. 保护机制第一层从访问控制矩阵到 ACL4.1 保护到底在保护什么共享关心的“能不能访问到”保护关心的则是“访问到什么程度”。文件保护要面对的安全威胁主要是三类未授权读取泄露、未授权修改篡改、未授权删除或破坏破坏。一个完整的保护体系通常包含三件事身份认证确认“你是谁”授权确认“你能对文件做什么”审计记录谁在什么时候做了操作。操作系统里的文件权限系统主要负责第二件事也就是授权。它做的事情是在每次打开、读取、写入、执行文件时根据文件记录的权限信息判断当前用户是否具备相应权限。这里我特别想说一个常见的误解很多人把“保护”等同于“权限位”这其实把问题看窄了。权限位是保护的一种实现方式但不是全部。加密也是一种保护而且它在某些场景下比权限位可靠得多。后面我会专门讲口令和保护的关系。4.2 访问控制矩阵为什么没法直接落地课本在讲访问控制时会先引入一个抽象概念访问控制矩阵。这个矩阵的行是系统中的用户列是每个文件矩阵的每个格子里写着该用户对这个文件的权限比如read、write、execute的集合。逻辑上非常理想但一落到工程上就完了。假设系统有 1000 个用户、100 万 个文件那就是 10 亿个格子其中绝大多数都是空的。真要拿一个二维矩阵去存内存和磁盘都扛不住。所以实际系统永远不会直接存这个矩阵而是把它拆成两种更经济的形式。一种叫访问控制表ACL按“文件”组织每个文件带一个小列表写明“谁能用什么权限访问我”。查询时只要看当前用户在这个文件的列表里是什么权限即可。另外一种叫用户能力表按“用户”组织每个用户带一个列表写明“你能访问哪些文件、每种权限是什么”。优点是查某个用户所有权限很快缺点是搞权限回收时你必须遍历所有文件把相关条目删掉极为痛苦。4.3 Unix 的 rwx 就是 ACL 的极简版Unix 的权限位可以看作 ACL 的一种高度压缩形式。它不是针对每个用户单独记录权限而是把用户聚成三类属主owner、属组group、其他用户other。每个类别再分别指定读r、写w、执行x三种权限合起来就是九个 bit再加上特殊权限位存到 inode 里。这里有一个长期困扰新手的问题目录上的 rwx 和文件上的 rwx 含义完全不同。文件上的读表示读取文件内容写表示修改文件内容执行表示把这个文件当作程序运行。目录上的读表示可以列出目录里的文件名写表示可以在目录中创建、删除、重命名文件执行常被称为“搜索权限”表示可以“进入”这个目录并访问其中知道名字的文件。有一种很容易让人懵的现象你拥有某个目录的执行权限但没有读权限那么你用ls这个目录会提示无权限列出内容但如果你明确知道里面有个文件叫data.txt你可以直接读取它。因为你“能进入目录、能精确定位文件名”但“不能枚举目录内容”。这看起来有点别扭但只要把“目录读列出清单”和“目录执行进入”分开理解就不奇怪了。再比如用户对目录有写权限但不是文件属主用户能不能删除别人放在这个目录里的文件在许多 Unix 系统里默认是可以的因为删除操作的本质是修改目录项而不是修改文件本身只要你对该目录有写权限你就在做“改动目录内容”的操作。这也是为什么像/tmp这种共享目录要额外引入 sticky bit粘贴位来限制有 sticky 位的目录里只有文件属主、目录属主或特权用户才能删除或重命名文件避免任何人乱删别人的临时文件。5. 保护机制第二层口令、加密与集中访问控制5.1 口令保护看着简单用起来全是问题口令保护应该是最古老、最容易理解的一种文件保护方式我在访问文件之前必须先输入一个口令口令对了才允许操作。它实现起来很简单看起来也很直观但在工程实践里处处是坑。第一口令保护通常只保护“访问入口”不保护“存储内容”。口令验证通过之后文件的读写命令照常走底层的磁盘接口如果攻击者能直接把磁盘拆下来、用另一个操作系统读取数据块那文件内容依然会暴露。第二口令的传输也很容易出问题。口令在认证过程中如果走的是明文通道抓包就能看到。第三多人共享同一个口令时无法区分具体是哪个用户出了安全问题没法追责。最后口令的回收也是一团乱麻有人离职了你还得改掉所有共享文件的口令否则他就是永远的“隐形读者”。所以口令保护在现代操作系统里基本不会作为主要的文件保护机制顶多作为某些场景的辅助手段。真正负责保护的是权限系统以及下面要说的加密。5.2 加密保护把最后一道防线放进文件本身加密保护的核心思想是即使数据被人拿到了没有密钥也读不出内容。权限系统保护的是“访问路径”而加密保护的是“数据本身”。两者是不同维度的防线。在学习文件系统时我们通常把加密分为两类来理解。一类是透明文件加密/文件级加密文件系统在读写路径上自动完成加解密应用程序无感文件在磁盘上以密文形式存在但合法用户在打开文件时看到的是明文。另一类是全盘加密整个磁盘都被加密系统启动时需要输入密钥才能解锁。我的判断是如果文件只存在本机并且操作系统用户管理得还算严格权限位通常已经够用但一旦文件会进入备份介质、移动设备、云盘或者会脱离当前操作系统的管辖加密就不再是选项而是必须。很多人只把文件设为 600 权限以为安全了结果备份盘丢了之后直接泄露。本质问题是备份盘上的文件并不认识 Unix 的权限位到了别的操作系统上那些权限位就是一堆无意义的元数据数据块本身是什么内容就能被直接读出。加密也有代价。最大的代价是性能加解密会占用 CPU 和 IO文件越大越明显。另一个代价是密钥管理密钥丢了谁都解不开比误删还恐怖。所以在工程实践中通常不是让每个文件都单独拥有一个密钥而是采用“一条主密钥 多条文件密钥”的分层设计主密钥保护文件密钥文件密钥分别保护各自的数据。这样既避免了把所有文件绑在同一把钥匙上又不至于让密钥数量失控。5.3 分布式场景下的集中访问控制单机场景下ACL 和权限位已经能解决“谁可以访问”的问题。但一个人不可能只在一台机器上工作分布式文件系统和网络存储场景下“用户身份”必须跨越机器边界被识别。如果每台机器各自维护一套账号体系那权限配置会变得极其混乱同一个用户在这台机器上是 A在另一台机器上又变成 B文件到底该认谁所以现代的分布式文件系统普遍采用集中的方式管理访问控制认证环节由独立的认证中心负责用户先拿到一个可验证的凭证文件服务器根据这个凭证确定用户身份再查询该共享目录或文件配置的权限决定是否允许读写。此时的“共享”粒度已经从单个文件上升到“共享某个存储区域”在共享区域之内再按用户和组进一步划分权限。我对这类机制的学习体会是集中控制的本质是“把用户的身份判断从每个文件上剥离出来放到统一的地方处理”。单机版文件保护解决的是“文件自身”的管理分布式场景下的保护解决的是“身份如何在多机间保持一致”的问题。两者互为补充缺一不可。6. 亲手验证从命令行观察共享与保护的每个细节6.1 inode、链接数、断链一条命令全看见理论说再多不如自己跑一遍。我在学习时有一个很笨但很有效的办法把笔记里说的硬链接、软链接、删除、断链全部在 shell 里做一遍观察每个命令的输出变化。先建一个工作目录创建原始文件mkdir -p /tmp/share_demo cd /tmp/share_demo echo 这是一份共享文档 origin.txt然后分别创建硬链接和软链接用ls -li查看 inode 和链接数ln origin.txt hard.txt ln -s origin.txt soft.txt ls -li输出会显示类似这样的信息total 16 123456 -rw-r--r-- 2 user group 30 Jul 1 10:00 hard.txt 123456 -rw-r--r-- 2 user group 30 Jul 1 10:00 origin.txt 123457 lrwxrwxrwx 1 user group 9 Jul 1 10:00 soft.txt - origin.txt看到hard.txt和origin.txt的 inode 号相同、链接数为 2而soft.txt是完全不同的 inode、链接数为 1并且明显标了-指向哪怕不看任何文档也能立刻理解硬链接和软链接的本质区别。接下来通过任一入口修改文件验证共享关系echo 第二次写入 hard.txt cat origin.txtorigin.txt里会出现新写入的内容因为硬链接改变的是同一个 inode 对应的数据。如果通过soft.txt写入效果也一样因为内核解析到这个软链接后落笔的仍然是origin.txt指向的 inode。再模拟“删除原文件后的差异”rm origin.txt cat hard.txt # 仍能读到内容链接数减为 1 cat soft.txt # 报错No such file or directory链接已经断了这一套小实验跑完硬链接和软链接在“删除场景”下的区别就一目了然了。6.2 权限位组合能读不能写、能进目录看不到文件权限问题在实践中千奇百怪我挑几个最典型的现象说。现象一某用户在共享目录里能打开文件看到内容但编辑器保存时提示“Permission denied”。用ls -l一看文件属主是别人权限是-rw-r--r--也就是属主有写权限组和其他用户只有读权限。这个用户虽在 dev 组里但文件所有者不是他文件所在的组也不是 dev 组那他自然没有写权限。要修要么把文件属主改给他要么把文件组改成该用户所属组并给组加上写权限chgrp dev project.conf chmod 660 project.conf改成660之后属主和组都可以读写组内成员就能正常编辑了。现象二用户能“走进”目录但ls执行时提示权限不足。这通常是目录权限为--x只有执行权限没有读权限。执行权限让他能通过路径逐级进入但没有读权限就不能枚举目录项。如果需要“进入并列出”目录必须同时有读和执行权限通常写成r-x。现象三用户能删除目录里的文件但他的权限明明是rw-。这里最容易被忽略删除文件改的是目录项不是文件本身。只要用户对目录有写权限他就能修改目录中的条目也就意味着可以删除或重命名该目录下的文件跟他本人对这个文件的权限没有直接关系。因此共享目录如果要限制成员只能“往里放文件但不能乱删别人的文件”就必须给目录加 sticky bit比如/tmp目录的权限就是drwxrwxrwt最后的t表示粘贴位。有粘贴位的目录里删除操作只对文件属主、目录属主或特权用户开放。6.3 实操后给我的三点提醒第一不要随手chmod 777。“反正大家都要用干脆全开”这句话是权限事故的根源。共享应遵循“最小够用”原则要读就给读要写就给写执行权限只在需要时给。一个目录开了 777意味着所有用户都能在里面创建、删除、重命名任何人的文件出问题根本无法追责。第二写权限和目录写权限都要复盘。你写的代码没问题不代表配置没问题。排查权限类事故时我会按顺序确认三件事文件属主是谁、文件权限是什么、父目录权限是什么。前两个决定你能不能读写文件内容第三个决定你能不能增删目录项。很多人只查了文件本身漏掉了父目录的权限最后绕了半天才发现根源在目录上。第三加密不能靠权限位替代。如果文件最终要备份、传输、交给合作伙伴权限位保护已经失效请戴口罩。更准确地说请先加密再传输。我在实际项目中的习惯是凡是涉及敏感信息的分发文件一律在系统层面设置加密文件本身的 Linux 权限只是第二道保险。这套学习笔记写到这里其实“共享”和“保护”这两件事是唇齿相依的共享扩大了访问范围保护则在范围扩大的同时划出了边界没有保护的共享等于裸奔没有共享的保护则会让协作寸步难行。最后再分享一个我个人养成的习惯配置共享目录之前先在一张纸上写下“哪类用户对哪个目录能做什么”然后再把这条规则翻译成权限位的组合。这个简单的动作帮我避开了很多只有等到出事才会暴露的坑。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑