unlink与close关系
UNIX文件系统包括引导块、超级块、i节点区、文件存储区、进程对换区等几部分。
引导块占用第0号物理块,不属于文件系统管辖,如果系统中有多个文件系统,只有根文件系统才有引导程序放在引导块中,其余文件系统都不使用引导块。
超级块占用第1号物理块,是文件系统的控制块,超级块包括:文件系统的大小、空闲块数目、空闲块索引表、空闲i节点数目、空闲i节点索引表、封锁标记等。超级块是文件系统为文件分配存储空间、回收存储空间的依据。
i节点区存放i节点,i节点是对文件进行控制和管理的一种数据结构。
文件存储区是存放文件内容的区域,文件存储区中各数据块的使用情况在超级中有记录,系统利用超级块中的记录完成对数据块的分配和回收。
unix文件系统中很重要的概念之一就是i节点,下面就开始说说这个重要的概念。
每一个文件都由自己的i节点,每个i节点都有唯一的i节点号。
i节点的结构如下(参考/usr/include/sys/ino.h)
struct dinode
{
ushort di_mode;//文件类型与权限
short di_nlink;
ushort di_uid;
ushort di_gid;
off_t di_size;
char di_addr[40];
time_t di_atime;
time_t di_mtime;
time_t di_ctime;
}
从上面的结构中可以看出:
1、i节点保存了文件的属性和类型、存放文件内容的物理块地址、最近一次的存取时间、最后一次修改时间、创建此文件的时间。
2、i节点中没有记录文件名字,那么文件的名字是怎么关联到i节点的呢?这么设计又有什么好处呢?
在linux系统中,文件的查找不是通过文件名称来查找的。实际上是通过i节点来实现文件的查找定位的。我们可以形象的将i节点看作是一个指针。当文件存储到磁盘上去的时候,文件肯定会存放到一个磁盘位置上,可以这样想象,既然文件数据是存放在磁盘上的,如果我们知道这个文件数据的地址,当我们想读写文件的时候,我们是不是直接使用这个地址去找到文件就可以了呢?
是的,在linux下,i节点其实就是可以这么认为,把i节点看作是一个指向磁盘上该文件存储区的地址。只不过这个地址我们一般没办法直接使用,而是通过文件名来间接使用的。事实上,i节点不仅包含了文件数据存储区的地址,上面也提到过,它还包含了很多其他信息(文件的属性和类型,存放文件内容的物理块地址,最近一次的存取时间,最近一次的修改时间,创建文件的时间)。但是i节点是不保存文件名的。文件名保存在一个目录项中。每个目录项中都包含了文件名和i节点。回到正题,i节点中没有记录文件爱你名字,那么文件按名是怎么关联到i节点的呢。这里就关系到了硬链接与符号链接的区别。
如下图:
对于硬链接来说,如果删掉源文件helloA.c,那么磁盘上数据文件按是不会被删除的。因为i节点上记录了该文件的硬链接数。只有硬链接数为0的时候,删除文件名的时候,该数据在磁盘上才会删除。
所谓的符号链接,其实是指文件索引的索引。当源文件helloB.c删除之后,其实磁盘数据文件还在,helloC.c也无法使用。符号链接包含了一个文件名的路径,如果这个文件名被删除,这个符号链接自然就不能正常工作了。
3、di_mode这个是怎么保存文件类型+用户权限的呢?
比如:
drwxr-xr-x 7 root sys 512 dec 15 2012 var
-rw-r--r--- 1 root sys 4003 Ju1 4 23 : 37 1
红色字体部分说明是文件类型标记和文件权限,这个字符串跟ushort di_mode怎么关联的?
ushort di_mode是16位2进制数,保存的就是文件类型及用户权限信息,具体结构如下:
4 8 12 16
第1-4位:文件类型
第5位:suid位
第6位:sgid位
第7位:sticky位
第8-10位:文件属主权限位
第11-13位:文件属组权限位
第14-16位:其他用户权限位
1)文件类型分类:
d--目录文件、f--普通文件、b--块设备文件、c--字符设备文件、l--链接文件
2)文件类型位算法
从系统的头文件/usr/include/sys/stat.h中可以知道:
a、#define S_IFMT 0170000 -- 文件类型掩码宏,0170000以0开头,表示这是一个8进制数,转换成2进制,正好是 1 111 000 000 000 000 ,高4位全置1;
b、#define S_IFREG 0100000 -- 普通文件类型掩码,0100000,转换成2进制,1 000 000 000 000 000,最高位置1;
c、#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) -- 判断文件是否普通文件的宏函数
举例说明:m值即为我们取到ushort di_mode,假设其2进制值为 0 011 000 000 000 000,对应的8进制为 060000 。S_ISREG(0060000) 即 (((0060000) & 0170000 ) == 0100000) ,该值返回False,则代表该文件不是普通文件。
说明:stat结构中的大多数信息都取自i节点。只有两项数据存放在目录项中:文件名和i节点编号。i节点编号的数据类型是ino_t。
注意:每个文件系统各自对它们的i节点进行编号,因此目录项中的i节点编号数指向同一文件系统中相应的i节点,不能使一个目录项指向另一个文件系统的i节点。
讨论linux中link,unlink,close,fclose函数对st_nlink的影响
linux中每一个文件,都可以通过一个struct stat的结构体来获得文件信息,其中一个成员st_nlink代表文件的链接数。
当通过shell的touch命令或者在程序中open一个带有O_CREAT的不存在的文件时,文件的链接数为1。
通常open一个已存在的文件不会影响文件的链接数。open的作用只是使调用进程与文件之间建立一种访问关系,即open之后返回fd,调用进程可以通过fd来read 、write 、 ftruncate等等一系列对文件的操作。
close()就是消除这种调用进程与文件之间的访问关系。自然,不会影响文件的链接数。在调用close时,内核会检查打开该文件的进程数,如果此数为0,进一步检查文件的链接数,如果这个数也为0,那么就删除文件内容。
link函数创建一个新目录项,并且增加一个链接数。
unlink函数删除目录项,并且减少一个链接数。如果链接数达到0并且没有任何进程打开该文件,该文件内容才被真正删除。如果在unlilnk之前没有close,那么依旧可以访问文件内容。
综上所诉,真正影响链接数的操作是link、unlink以及open的创建。
删除文件内容的真正含义是文件的链接数为0,而这个操作的本质完成者是unlink。close能够实施删除文件内容的操作,必定是因为在close之前有一个unlink操作。
举个例子简单说明:通过shell touch test.txt
1 #include <stdio.h>
2 #include <unistd.h>
3 #include <sys/stat.h>
4 #include <sys/types.h>
5 #include <fcntl.h>
6
7 int main(int argc,char *argv[])
8 {
9 struct stat buf;
10 stat("test.txt",&buf);
11 printf("1.link=%d\n",buf.st_nlink);
12
13 int fd;
14 fd = open("test.txt",O_RDONLY);
15 stat("test.txt",&buf);
16 printf("2.link=%d\n",buf.st_nlink);
17
18 close(fd);
19 stat("test.txt",&buf);
20 printf("3.link=%d\n",buf.st_nlink);
21 link("test.txt","test2.txt");
22 stat("test.txt",&buf);
23 printf("4.link=%d\n",buf.st_nlink);
24 unlink("test2.txt");
25 stat("test.txt",&buf);
26 printf("5.link=%d\n",buf.st_nlink);
27 fd = open("test.txt",O_RDONLY);
28 stat("test.txt",&buf);
29 printf("6.link=%d\n",buf.st_nlink);
30 unlink("test.txt");
31 fstat(fd,&buf);
32 printf("7.link=%d\n",buf.st_nlink);
33
34 return 0;
35
36 }
顺次执行以上8个步骤,结果如下:
1.link=1
2.link=1 //open不影响链接数
3.link=1 //close不影响链接数
4.link=2 //link之后链接数加1
5.link=1 //unlink后链接数减1
6.link=1 //重新打开 链接数不变
7.link=0 //unlink之后再减1,此处我们改用fstat函数而非stat,因为unlilnk已经删除文件名,所以不可以通过 文件名访问,但是fd仍然是打开着的,文件内容还没有被真正删除,依旧可以使用fd获得文件信息。
执行步骤8,文件内容被删除....
注意:在第步骤6中,文件test.txt此时已经打开并没有将其关闭,而步骤七中直接将其释放,此时,文件的内容没有真正的被删除。进程任然可以继续读文件中的内容。直到关闭该文件或进程结束自动关闭后,内核首先会先检查打开文件的进程数,如果为0,然后内核检查其链接数,由于在第七步中已经释放了最后一个,所以其链接数为0,那么就删除该文件的内容。
下图是抄之apue的精典例子:
unlink的这种性质经常被程序用来确保即使是在该程序崩溃时,它所创建的临时文件也不会被遗留下来。进程用open或creat创建一个文件,然后立即调用unlink。因为该文件仍旧是打开的,所以不会将其内容删除。只有当进程关闭该文件或终止时(这种情况下,内核会关闭该进程打开的全部文件),该文件的内容才会被删除。
unlink删除该符号链接,而不是删除由该链接所引用的文件。给出符号链接名的情况下,没有一个函数能删除由该链接所引用的文件。
unlink与close关系的更多相关文章
- unlink和close关系
今天看到nginx用文件锁实现互斥的实现方案时,发现,unlink文件后还可需用fd,很是纳闷!于是搜索到此文,并自测了下,涨姿势了~分享给大家~ 原理: 每一个文件,都可以通过一个struct st ...
- 《图解HTTP》阅读笔记
HTTP基础的简单理解 在了解HTTP协议之前,我们先了解下TCP/IP的参考模型,TCP/IP参考模型分为四层:应用层.传输层.网络层.链路层(数据链路层). 应用层:为不同的网络应用提供所需的服务 ...
- HTTP请求方法对照表
根据HTTP标准,HTTP请求可以使用多种请求方法. HTTP1.0定义了三种请求方法: GET, POST 和 HEAD方法. HTTP1.1新增了五种请求方法:OPTIONS, PUT, DELE ...
- HTTP笔记(一)
最近在看<图解HTTP>.全书以图解的形式生动形象的讲解了HTTP协议.本文是根据该书整理的笔记,方便以后回顾. HTTP的诞生 HTTP又称超文本传输协议(HTTP,HyperText ...
- 【http】http的方法,状态码和组成部分
Http(Hypertext Transfer Protocol) HTTP协议(HyperText Transfer Protocol,超文本传输协议)是用于从WWW服务器传输超文本到本地浏览器的传 ...
- ResfulApi规范
序号 方法 描述 1 GET 请求指定的页面信息,并返回实体主体. 2 HEAD 类似于get请求,只不过返回的响应中没有具体的内容,用于获取报头 3 POST 向指定资源提交数据进行处理请求(例如提 ...
- 【HTTP】267- HTTP 的15个常见知识点复习
前言 自从入职新公司到现在,我们前端团队内部一直在做 ?每周一练 的知识复习计划,我之前整理了一个 [每周一练 之 数据结构与算法] (https://juejin.im/post/5ce2a20e6 ...
- 【HTTP】HTTP 的15个常见知识点复习
前言 自从入职新公司到现在,我们前端团队内部一直在做 ?每周一练 的知识复习计划,我之前整理了一个 每周一练 之 数据结构与算法 学习内容,大家也快去看看~~ 最近三周,主要复习 网络基础 相关的知识 ...
- 图解 HTTP 笔记(二)——简单的 HTTP 协议
本章主要以 HTTP 1.0 为例,讲解 HTTP 协议的基本结构. 在两台计算机之间使用 HTTP 协议进行通讯时,在一条通讯线路上必定有一端是客户端,另一端则是服务器端. 请求访问文本或图像等资源 ...
随机推荐
- CSS通过设置position定位的三种常用定位
CSS中可以通过设置为元素设置一个position属性值,从而达到将不同的元素显示在不同的位置,或者固定显示在某一个位置,或者显示在某一层页面之上. position的值可以设为relative,ab ...
- 在已配置成功的opencv3.2.0下配置opencv_contrib模块
简介: 之前在Ubuntu下配置OpenCV时,因为对opencv3..0不是特别了解,没有把opencv_contrib进行安装,这里提醒大家尽量要一次性安装完毕,减少不必要的麻烦. .0文件夹 ( ...
- 关于 eval 的报错 Uncaught ReferenceError: False is not defined
var obj ={'id': 16, 'name': '管理员', 'delflag': False, 'grade': 1000000.0}VM3614:1 Uncaught ReferenceE ...
- 封装一个 TopBarBaseActivity
什么是快速开发嘞,看这个效果 然而我只用了这么几行代码: activity_main.xml 里面什么也没有! 其实说白了哈,就是我把 TopBar 封装在 TopBarBaseActivity 里面 ...
- Attack Top Chunk之 bcloud
前言 这是 bctf 2016 的题,链接 https://github.com/ctfs/write-ups-2016/tree/master/bctf-2016/exploit/bcloud-20 ...
- gitlab 启用HTTPS
NGINX设置 启用HTTPS 警告 Nginx配置会告诉浏览器和客户端,只需在未来24个月通过安全连接与您的GitLab实例进行通信.通过启用HTTPS,您需要至少在24个月内为您的实例提供安全连接 ...
- d3js path generator vs layouts
我们知道d3的一般套路就是d3.selectAll('path.mypath').data(yourDataset).enter().append('path').attr('class','mypa ...
- [翻译] EAIntroView
EAIntroView https://github.com/ealeksandrov/EAIntroView This is highly customizable drop-in soluti ...
- sonarQube环境搭建--常见问题及解决
环境配置:MySQL Server 5.7 Jdk1.8 1.安装mysql数据库(默认安装一路默认到底,注意不要先新建用户账号) a) Mysql 环境变量配置: b)新增my.ini文件: ...
- Linux dumpe2fs命令详解
dumpe2fs: 查看格式化之后的文件系统信息. dumpe2fs使用 [root@localhost omc]# dumpe2fs --help<BR>dumpe2fs 1.41.12 ...