【Linux内核系列】:文件系统收尾以及软硬链接详解

🔥 本文专栏:Linux
🌸作者主页:努力努力再努力wz

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

💪 今日博客励志语录世界上只有一种个人英雄主义,那么就是面对生活的种种失败却依然热爱着生活

内容回顾

那么在之前的学习中,我们知道了操作系统是如何管理我们未打开的文件,我们知道文件的数据是存储在磁盘上的,而操作系统要管理磁盘上的所有数据,那么必然在操作系统中建立一个磁盘的逻辑映射,那么其中磁盘中的数据是保存在盘面上的一圈一圈的磁道的扇区当中,那么我们可以将该立体空间中每一个扇区按照一个线性的一维数组来进行一个排列,那么该一维数组就是磁盘的逻辑结构,其中该一维数组中的每一个元素就是一个扇区,其中为了区分不同位置的扇区,那么我们就得给扇区一个唯一的标识符,那么我们扇区在一维数组对应的数组下标便是扇区的编号从0到n分配给不同位置的扇区,而该编号也称之为LAB地址,那么当我们有了扇区的LAB地址之后,由于LAB地址是逻辑地址而不是扇区在实际的磁盘中的物理地址,而我们需要定位扇区在磁盘中真实的物理地址,而定位其在磁盘中的位置则需要该位置对应的磁头以及磁道和扇区这三个坐标,所以有了LAB地址之后,操作系统会采取特定的算法将LAB地址映射转换该位置的三个坐标即可

那么扇区是我们磁盘存储的基本单元,那么磁盘读写数据是以扇区为单位来进行读写,但是由于扇区的存储的内容量一般只有512字节,而现在的文件的大小动辄就是几十甚至上百个GB,而磁盘读取的速度取决于机器运动的次数,那么以扇区为单位读写必然io的速度就会很慢,所以不同的文件系统会采取将多个扇区给组合形成该磁盘读写的最小单元,以EXT4文件系统为例,那么它是以8个扇区为一组作为一个逻辑块,那么磁盘一次读写的数据量就是4KB,那么这样就提高了io的效率,所以在文件系统所定义的逻辑块的视角下,那么原本的一维线性数组的每一个元素便不再是一个个扇区而是逻辑块,所以给一维数组的元素个数以及每个元素的编号就会发生变化

其中由于磁盘的数据量很大,那么操作系统管理如此庞大的数据,那么采取的策略就是分区,其中将该一维线性数组分成不同的区域来进行管理,但是即使将其分区,那么每一个区的数据量依然很大,所以会进行更为细致的划分,将每一个分区在划分成不同的分组,那么其中管理好整个磁盘就是管理好该分区的每一个分组以及不同的分区,那么这就是对前置知识的回顾,如果感到陌生或者说好奇其中的细节的话,可以阅读之前的文章

★★★ 本文前置知识:

文件系统


重新理解文件

那么了解了磁盘的一个逻辑结构以及操作系统管理磁盘的一个方式之后,那么我们知道文件是由两部分所构成,分别是文件的属性以及文件的内容,那么对于文件的属性来说,操作系统则是会为其定义一个inode结构体,其中封装了该文件的各个属性字段其中就包括文件的权限以及文件的创建时间以及最近修改时间,那么inode数据则是保存在inode区域中的特定的逻辑块中,而对于文件的内容,那么保存文件内容的逻辑块则是和保存文件属性的逻辑块位于不同的区域,所以在Linux下,文件的属性以及内容是分开来管理,而其中对于inode结构体中还有一个非常重要的字段便是一个索引数组,那么该数组则是保存了该文件的内容的数据块的索引,那么意味着有了inode结构体,那么我们既能获取文件的属性也同时能够获取文件相关联的数据块
在这里插入图片描述

所以现在我们就便能理解当我们创建以及一个文件时,系统会做什么

创建文件

那么文件是有内容+属性这两部分构成,当我们创建一个文件时,那么意味着首先就得定义该文件对应的inode结构体,而既然要创建inode结构体,那么我们就得为该文件分配一个空闲的逻辑块来保存该inode结构体的数据,所以系统会到分区的各个分组中,首先会查看该分组的gbt字段,因为gbt字段保存了该分组的整体的逻辑块的使用情况,其中记录了该文件的多少inode逻辑块被使用,多少inode逻辑块是剩余空闲,那么接着再去查看inode表,那么inode表是一个位图结构,其中每一个比特位对应特定位置编号的逻辑块,那么该比特位的值就表示该逻辑块是否被使用,那么为inode分配好一个逻辑块之后后,接下来就是对inode结构体的相关属性进行一个初始化,那么这就是系统创建文件的一个过程

删除文件

那么文件是由属性和内容两部分构成,那么删除一个文件必然就是要删除这两部分数据,而我们知道文件本质就是由保存属性的inode结构体以及保存文件的内容的数据块所构成,而我们的inode结构体中内部有一个索引数组能够找到该文件关联的数据块,那么也就是意味着删除一个文件,我们只需要找到该文件的inode结构体,那么即可获取该文件的全部内容,而获取文件的inode结构体的方式那么就是得需要知道保存该inode结构体的数据的逻辑块的编号,所以一旦获取到inode编号之后,那么我们根据该编号确定该inode对应的逻辑块是在哪一个分组中,然后该分组的块表则记录那些逻辑块被使用哪些逻辑块未被使用,而inode表则是记录了哪些inode结构体被使用哪些未被使用,所以我们获取到inode结构体的编号之后,那么意味着也能同时获取到数据块的编号,接着就只需要将块表以及inode表中对应位置的比特位设置为0即可,无需要覆盖inode块以及数据块的内容,然后更新gbt,这样就逻辑上完成了对文件的删除

所以删除一个文件,意味着会更新相应的块表以及inode表等属性,而不会直接采取覆盖数据块以及对应的inode块,那么也就意味着其实删除一个文件本质上是可以恢复的,但是恢复的过程其实比较复杂还要涉及到专业的工具,并且文件系统的格式化其实也就是在重新初始化对应的分区的每个分组的块表以及inode表等属性,也不会覆盖所谓的数据块以及inode块


那么对于其中的文件的删除,过程道理想必大家都懂,那么关键是我怎么获取目标文件的inode编号呢,我们在Linux上删除文件,我们知道是输入rm指令,而其中我们输入rm指令删除目标文件都是后面直接输入的是删除目标文件的文件名,而不是输入的是其inode编号,但是系统也确实成功删除了目标文件,那么这又是怎么回事呢?

那么我们删除一个文件核心肯定是需要文件的inode编号,那么既然我们只需要输入文件名就可以达到删除的效果,那么只能说明一点,那么就是系统有我们该文件名到inode编号的映射,那么要说清楚这点,那么就得重新来认识一下我们的目录了

目录文件

那么我们之前在Linux的学习中,我们知道可以输入mkdir指令来创建一个目录,那么我们也知道目录本质上其实也是一个文件,有着自己的属性,那么既然是一个文件,那么不用说,它肯定也有一个inode结构体在其中的一个特定的分组当中,那么它的inode结构体肯定也记录其相应的属性比如权限以及创建时间等,那么同理它也一定有一个索引数组指向其关联的数据块,那么我们对于普通文件来说,其inode关联的数据块就是其文件内容,那么对于我们目录文件来说,它也有自己所属的数据块,那么对于目录文件来说,它的数据块保存的是什么内容呢?

答案就是它的数据块保存的就是其目录当中子目录以及子文件的文件名到inode编号的映射,那么每一个数据块也就是目录项保存的都是这个key-value模型的一个映射关系的内容,那么也就是说,我们查找一个目标文件的inode编号,那么就需要到目标文件所处的目录中的目录项中去匹配找到对应的映射关系,获取到其对应的inode编号,所以这就是我们为什么同一个目录下,不能有重名文件的文件的原因

所以我们有了目录文件的概念之后,那么我们就得对之前上文所说的创建文件以及删除文件的过程进行一个完善,那么对于其中创建文件,我们知道会为该文件定义一个inode结构体,然后为在分组中为其分配一个未被使用的逻辑块来保存inode的数据,而其中对于其所处的目录文件中,那么目录文件的数据块也就是目录项中也会添加该文件关于文件名到其文件编号的映射

同理对于删除文件来说,那么首先我们得获取该文件的inode编号,那么我们就得从其所处的目录中的目录项中找到其对应的inode编号,也就是要获得其所处目录的目录项里面的内容,那么我们也得递归的去该目录的上一级目录中得到该目录的inode编号,而我们的文件是以树状的数据结构来组织的,那么其中整个文件系统的根节点便是根目录,而其inode编号是已知的,例如在EXT4文件系统中它对应的inode编号是2,那么我们要得到目标文件的文件编号,我们只需要得到该目录的绝对路径,也就是从根目录到该目标文件的路径,那么系统就会从根目录往下逐层解析,从根目录开始,扫描其目录项中寻找下一级目录的映射关系获取到其inode编号,那么再同理递归到下一级的目录当中扫描其目录项获取其下一级的目录或者文件的inode编号直到达到目标文件

那么由此便能解释之前的问题,为什么我们rm指令输入目标文件的文件名而不是inode编号,也能够删除目标文件

那么如果我们输入删除的目标文件带有绝对路径,那么就是按照上述过程,解析该绝对路径找到目标文件的inode编号然后删除

但是如果是相对路径的话,那么系统会获取到该进程的内核的环境变量中的CWD字段,那么该字段保存了所处的工作目录的inode编号,那么从该目录文件的目录项找到目标文件的inode编号从而删除

而至于进程的内核的环境变量中的CWD字段为什么能够直接获取到所处的目录的inode编号,那么则和dentry缓存有关,因为我们知道从根目录开始解析到目标文件,这其中的过程要涉及扫描每一个目录的目录项的映射关系,那么时间代价就很大,所以dentry就是一个数据结构记录了每一级目录的inode编号,那么我们进程切换目录的时候会利用缓存来得到当前目录的inode编号从而更新CWD,而无需解析整个路径

软链接

那么有了目录以及目录项的概念之后,那么我们其中便可以引入软链接

那么第一个问题:

软链接是什么

那么我们在解释其原理之前,我们先来看看软链接长什么样子,那么我们可以输入该指令来创建软链接一个指向test.c文件的名为soft的软链接

ln -s [目标文件或目录] [软链接名称]

那么创建完之后软链接之后,我们再来使用ls -l 指令来查看一下当前目录下的所有子目录以及文件的属性,

在这里插入图片描述

我们发现创建的软链接本质上其实也就是一个文件,那么既然它是一个文件,那么它肯定就由文件的内容和属性所构成,也就意味着其一定有对应的inode结构体,那么我们可以输入ls -li查询inode编号
在这里插入图片描述

根据结果我们发现其软链接以及该软链接指向的目标文件test.c的inode编号是不同的,那么说明其有自己独立的inode结构体以及其相关联的数据块,那么其独立的inode结构体肯定存储其相关的属性,那么其相关联的数据块那么存储的是什么内容呢?

那么我们可以输入cat指令来打印器软链接的文件内容到终端上
test.c文件内容:
在这里插入图片描述

cat内容:
在这里插入图片描述

那么我们发现软链接打印的内容竟然就是其指向的目标文件的内容

软链接怎么做到的

那么我们软连接本身有一个独立的inode结构体以及相关联的数据块,软连接本身的数据块存储的内容便是目标文件的路径,所以当我们输入cat指令来访问到软链接的时候,那么首先会得到软链接的inode编号并且识别到该文件的类型,然后从inode编号中获取其关联的数据块,而其数据块存储的内容便是其目标文件的路径,那么接着系统会解析这个路径得到目标文件的inode结构体从而间接访问到目标文件的数据块,然后打印的是指向的文件的文件内容,所以我们的软链接和我们c语言的指针其实非常的像,那么指针的本质其实就是一个变量,只不过该变量的内容就是指向的目标数据的地址,而同理我们的软链接,也是一个文件,只不过内容保存的是指向的目标文件的路径

注:软链接指向的目标文件一定要存在,如果不存在,那么我们软连接保存的内容是无效的,那么此时该软链接的状态就是悬浮的就类似于我们指针不能为空,不然解引用就会出错

软链接的应用场景

那么在我们Windows下我们的一个可执行文件的成功执行需要编译各种配置的源文件,那么可执行文件和其源文件会封装到一个文件夹在特定的盘的特定路径下保存,那么我们运行这个可执行文件,那么我们就得知道其路径,但是我们用户通常不需要记住每一个可执行文件它保存的路径在哪里,而是通过桌面的快捷方式点开即可运行,那么其实这个快捷方式本质上就是一个软链接,那么它内部记录了可执行文件的路径,那么打开该快捷方式其实本质上就是解析其路径然后运行目标的可执行文件即可

所以学习了Linux之前,相信大家都有过这么的经历,那么就是删除一个文件,很多人以为我将快捷方式放到回收站删除即可那么现在我们知道了,你删除的快捷方式其实本质上是删除了一个软链接,那么该程序的可执行文件以及源文件其实没有任何影响

硬链接

那么有软连接,我们Linux还有硬链接的存在,那么它的作用其实和软连接是差不多的

那么我们先来看看在Linux下我们是如何创建我们的硬链接:

     ln 目标文件 硬链接

硬链接是什么

我们在认识硬链接是什么之前,我们还是先来看一下硬链接长什么样子吧,那么我们假设在当前目录下创建一个test.c文件,然后创建一个名为hard的硬链接来指向该test.c文件,然后首先我们还是输入ls -l指令来查看我们当前目录下的子目录以及文件属性,我们发现当前目录下有我们的硬链接文件以及指向的目标文件test.c
在这里插入图片描述

然后我们再来输入ls -li来查看该该目录下的文件的inode编号,我们发现硬链接文件以及指向的目标文件的inode编号是相同的
在这里插入图片描述

下一步我们再来输入cat指令来打印我们的硬链接的文件的内容时
test.c内容:
在这里插入图片描述
cat 硬链接:
在这里插入图片描述
我们发现其硬链接打印的内容竟然还是指向的目标文件test.c的文件内容

硬链接怎么做到的

那么我们知道硬链接文件是和其指向的目标文件的inode编号相同,那么说明其共享一个inode结构体,并其硬链接和指向的目标文件是共享inode结构体和其关联的数据块,那么当我们创建一个硬链接的时候,那么会在该硬链接所处的目录中添加一个新的映射,也就是该硬链接的文件名到inode编号的映射,所以当我们访问该硬链接的时候,那么其实本质上就是直接访问了其指向的目标文件的inode结构体,所以打印的内容就是目标文件的内容

并且有了硬链接的概念之后,那么我们输入ls -l指令所展示的文件的属性中,其中拥有者以及所属组和其他后面那个数字便是该文件的硬链接数,而我们创建一个普通文件,那么该文件的硬链接数初始化是1,因为它所处的目录文件的目录项会指向它,而对于目录文件来说,则是2,是因为它所处的目录文件会有一个指向其子目录的目录项,并且对于该目录的目录项来说,那么它也有一个目录项,也就是文件名为".“指向自己的inode的映射,同时还有一个文件名为”…“指向其上级目录的映射,而对于根目录来说,其”.“与”…"都指向自己
在这里插入图片描述

注:一般不建议创建指向目录的硬链接,因为我们知道了目录的目录项中有自己以及所处子目录的引用,而如果你在当前所处的目录下创建一个比如其上级目录的应用,那么我们在解析路径的时候就会陷入循环导致崩溃,所以硬链接使用的很少,一般都选择软链接

所以当我们删除一个文件的时候,我们要确定是否彻底删除清理该文件的属性以及内容的数据的时候,我们系统其实首先会得到其文件的硬链接数,然后减一,如果该硬链接数不为0的话,那么意味着还有其指向该文件的inode结构体,所以不会清空该文件的inode结构体以及内容数据,但是如果为0,那么该文件不再被需要,那么则会删除该文件的inode结构体以及其相关联的数据块
在这里插入图片描述

结语

那么这就是本篇文章关于文件系统以及软硬件链接的全部内容了,那么这篇文章也就是我们Linux文件系统的收官了,那么文件系统也就此完结撒花告一段落啦,那么恭喜你看到这里,成功的翻阅了文件系统这道大山🎆🎆,当然,对于我这几篇文章来说,肯定是不可能全部覆盖到所有的Linux文件系统的知识,只是覆盖了大部分并且其中最高频的知识,那么其中文件系统跟Linux其他的内容比如进程之间的联系,那么又是说来又是话长,那么我也考虑要不要出一期文章来解析,总之感谢你的耐心观看!

那么我下一期的文章便是动静态库的实现,那么我会持续更新,希望你能够多多关注支出,如果本篇文章有帮组到你的话,那么还请你多多三连加关注哦,你的支持就是我创作的最大的动力!
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/34265.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【eNSP实战】三层交换机使用ACL实现网络安全

拓图 要求: vlan1可以访问Internetvlan2和vlan3不能访问Internet和vlan1vlan2和vlan3之间可以互相访问PC配置如图所示,这里不展示 LSW1接口vlan配置 vlan batch 10 20 30 # interface Vlanif1ip address 192.168.40.2 255.255.255.0 # interface Vla…

Trae与Builder模式初体验

说明 下载的国际版:https://www.trae.ai/ 建议 要选新模型 效果 还是挺不错的,遇到问题反馈一下,AI就帮忙解决了,真是动动嘴(打打字就行了),做些小的原型效果或演示Demo很方便呀&#xff…

Canoe Panel常用控件

文章目录 一、Panel 中控件分类1. 指示类控件2. 功能类控件3. 信号值交互类控件4. 其他类控件 二、控件使用方法1. Group Box 控件2. Input/Output Box控件3. Static Text控件4. Button控件5. Switch/Indicator 控件 提示:Button 和 Switch 的区别参考 一、Panel 中…

睡不着运动锻炼贴士

在快节奏的现代生活中,失眠似乎已成为许多人的“夜间伴侣”。夜晚辗转反侧,白天精神不振,这样的恶性循环让许多人苦不堪言。其实,除了调整作息和饮食习惯,适当的运动也是改善睡眠的一剂良药。今天,就让我们…

java数据结构(复杂度)

一.时间复杂度和空间复杂度 1.时间复杂度 衡量一个程序好坏的标准,除了能处理各种异常,还有就是时间效率,当然,对于一些配置好的电脑数据处理起来就是比配置低的高,但从后期发展来看,当数据量足够庞大时&…

NAT和NAPT的介绍

一、NAT的介绍以及作用 二、NAPT的介绍以及作用 三、NAT vs NAPT 一、NAT的介绍以及作用 1.1 NAT的介绍 NAT(Network Address Translation)是一种广泛应用于互联网的技术,主要用于解决IPv4地址耗尽问题,同时提供网络安全和网络…

VSCode通过SSH免密远程登录Windows服务器

系列 1.1 VSCode通过SSH远程登录Windows服务器 1.2 VSCode通过SSH免密远程登录Windows服务器 文章目录 系列1 准备工作2 本地电脑配置2.1 生成密钥2.2 VS Code配置密钥 3. 服务端配置3.1 配置SSH服务器sshd_config3.2 复制公钥3.3 配置权限(常见问题)3.…

大模型训练全流程深度解析

前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站。https://www.captainbed.cn/north 文章目录 1. 大模型训练概览1.1 训练流程总览1.2 关键技术指标 2. 数据准备2.1 数据收集与清洗2.2 数据…

export、export default 和 module.exports 深度解析

文章目录 1. 模块系统概述1.1 模块系统对比1.2 模块加载流程 2. ES Modules2.1 export 使用2.2 export default 使用2.3 混合使用 3. CommonJS3.1 module.exports 使用3.2 exports 使用 4. 对比分析4.1 语法对比4.2 使用场景 5. 互操作性5.1 ES Modules 中使用 CommonJS5.2 Com…

AI芯片设计

目的:未来的时代,一定会是AI的时代,那么,AI时代的三个重要组成部分,我要参与其中之一! 参考视频:AI芯片设计第一讲_哔哩哔哩_bilibili 端处理 云端

动手学深度学习:CNN和LeNet

前言 该篇文章记述从零如何实现CNN,以及LeNet对于之前数据集分类的提升效果。 从零实现卷积核 import torch def conv2d(X,k):h,wk.shapeYtorch.zeros((X.shape[0]-h1,X.shape[1]-w1))for i in range(Y.shape[0]):for j in range(Y.shape[1]):Y[i,j](X[i:ih,j:jw…

【开源代码解读】AI检索系统R1-Searcher通过强化学习RL激励大模型LLM的搜索能力

关于R1-Searcher的报告: 第一章:引言 - AI检索系统的技术演进与R1-Searcher的创新定位 1.1 信息检索技术的范式转移 在数字化时代爆发式增长的数据洪流中,信息检索系统正经历从传统关键词匹配到语义理解驱动的根本性变革。根据IDC的统计…

使用Node的http模块创建web服务,给客户端返回html页面时,css失效的根本原因(有助于理解http)

最近正在尝试使用node写后端,使用node创建http服务的时候,碰到了这样的一个问题: 这是我的源代码: import { createServer } from http import { join, dirname, extname } from path import { fileURLToPath } from url import…

JVM 2015/3/15

定义:Java Virtual Machine -java程序的运行环境(java二进制字节码的运行环境) 好处: 一次编写,到处运行 自动内存管理,垃圾回收 数组下标越界检测 多态 比较:jvm/jre/jdk 常见的JVM&…

IP风险度自检,互联网的安全“指南针”

IP地址就像我们的网络“身份证”,而IP风险度则是衡量这个“身份证”安全性的重要指标。它关乎着我们的隐私保护、账号安全以及网络体验,今天就让我们一起深入了解一下IP风险度。 什么是IP风险度 IP风险度是指一个IP地址可能暴露用户真实身份或被网络平台…

【鸿蒙】封装日志工具类 ohos.hilog打印日志

封装一个ohos.hilog打印日志 首先要了解hilog四大日志类型: info、debug、warm、error 方法中四个参数的作用 domain: number tag: string format: string ...args: any[ ] 实例: //普通的info日志,使用info方法来打印 //第一个参数 : 0x0…

走路碎步营养补充贴士

走路碎步,这种步伐不稳的现象,在日常生活中并不罕见,特别是对于一些老年人或身体较为虚弱的人来说,更是一种常见的行走状态。然而,这种现象可能不仅仅是肌肉或骨骼的问题,它还可能是身体在向我们发出营养缺…

Python软件和搭建运行环境

目录 一、Python安装全流程(Windows/Mac/Linux) 1. 下载官方安装包 2. 详细安装步骤(以Windows为例) 3. 环境变量配置(Mac/Linux) 二、虚拟环境管理(关键!) 为什么需…

【蓝桥杯】省赛:神奇闹钟

思路 python做这题很简单,灵活用datetime库即可 code import os import sys# 请在此输入您的代码 import datetimestart datetime.datetime(1970,1,1,0,0,0) for _ in range(int(input())):ls input().split()end datetime.datetime.strptime(ls[0]ls[1],&quo…

RabbitMQ (Java)学习笔记

目录 一、概述 ①核心组件 ②工作原理 ③优势 ④应用场景 二、入门 1、docker 安装 MQ 2、Spring AMQP 3、代码实现 pom 依赖 配置RabbitMQ服务端信息 发送消息 接收消息 三、基础 work Queue 案例 消费者消息推送限制(解决消息堆积方案之一&#…