我们可以把一个磁盘分成一个或多个分区。每个分区可以包含一个文件系统。i节点是固定长度的记录项m它包含有关文件的信息。
如果我们忽视自举块和超级块的情况,那么可以得到下面这张更清晰的图。
在图中有两个目录项指向同一个i节点,每个i节点都有一个连接计数,他的值是指向这个i节点的目录项数。只有当连接计数为0的时候,才可以删除该文件(也就是可以释放该文件占用的数据块)。这就是为什么”解除一个文件的连接”的操作并不总是意味这”释放该文件占用的磁盘块”的原因。这也是为什么删除一个目录项的函数被称之为unlink而不是delete的原因。
另一种连接类型称之为符号连接(symbolic link)。对于这种连接,该文件的实际内容(在数据块中)包含了该符号连接所指向的文件的名字。该i节点中的文件类型是S_INLNK,于是系统知道这是一个符号连接。
i节点包含了所有与文件有关的信息:文件类型,文件存取许可权位,文件长度和指向该文件所占用的数据块的指针等等。stat结构中大多数信息都取自i节点。只有两项数据存放在目录项中:文件名和i节点编号数。i节点编号数的数据类型是ino_t。
因为目录项中的i节点编号数指向同一文件系统中的i节点,所以不能使一个目录项指向另一个文件系统的i节点。
当不更改文件系统的情况下为一个文件更名时,该文件的实际内容并未移动,只需构造一个指向现存i节点的新目录项,并删除老的目录项。例如:将文件 /usr/lib/foo 更名为 /usr/foo ,如果目录/usr/lib和/usr处于同一文件系统上,则文件foo的内容无需移动。这就是mv命令的通常操作。
现在来说明这个连接计数是怎么算的。
创建一个向现存文件连接的方法是使用link函数
link函数原型
int link(const char *existingpath,const char* newpath);
此函数创建一个新目录newpath,他引用现存文件existingpath
创建新目录项以及增加连接计数应当是一个原子操作
只有超级用户进程可以创建指向一个目录的新连接。其理由是这样做可能在文件系统形成循环,大多数处理文件系统的公用程序都不能处理这种情况。
为了删除一个现存的目录项,可以调用unlinkhanshu1
unlink函数原型
int unlink(const char *pathname);
此函数删除目录项,并将有pathname所引用的文件连接计数减1.如果该文件还有其他连接,则仍可通过其他链接存取该文件的数据。
只有当连接计数达到0时,该文件的内容才可被删除。另一个条件也阻止删除文件的内容——只要有进程打开该文件,其内容也不能删除。关闭一个文件时,内核首先检查使该文件打开的进程计数。如果该计数到达0,然后内核检查其连接计数,如果这也是0,那么就删除该文件的内容。
#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
int main()
{
int fd;
char buf[32];
struct stat buff;
if((fd=open("temp.txt",O_RDWR|O_CREAT|O_TRUNC,S_IRWXU))<0){
printf("create file error!\n");
}
stat("temp.txt",&buff);
printf("temp.link=%d\n",buff.st_nlink);
link("temp.txt","test.txt");
stat("test.txt",&buff);
printf("after link the temp.link=%d\n",buff.st_nlink);
if(unlink("temp.txt")<0){
printf("write error!\n");
}
if((lseek(fd,0,SEEK_SET))==-1){
printf("lseek error!\n");
}
if((read(fd,buf,5))<0){
printf("read error!\n");
}
return 0;
}
//temp.link=1
//after link the temp.link=1
符号连接
符号连接是对一个文件的间接指针,他与硬连接不同。硬连接直接指向文件的i节点。引进符号连接的原因是为了避免硬连接的一些限制:
1. 硬连接通常要求连接文件位于同一文件系统中
2. 只有超级用户才能创建到目录的硬连接,对符号连接以及他指向什么没有文件系统限制,任何用户都可创建指向目录的符号连接
符号连接一般用于将一个文件或整个目录结构移到其他某一个地址。
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<string.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<unistd.h>
#include<dirent.h>
int main(int argc,char *argv[])
{
if(argc!=4){
printf("param too few\n");
exit(0);
}
char buf[1000];
ssize_t sz;
DIR *dp;
int fd;
if((dp=opendir(argv[2]))==NULL) {
perror("opendir\n");
exit(0);
}
if((fd=dirfd(dp))<0){
perror("dirfd\n");
exit(0);
}
if(symlinkat(argv[1],fd,argv[3])<0){
perror("symlinkat\n");
exit(0);
}
memset(buf,0,sizeof(buf));
if((sz=readlinkat(fd,argv[3],buf,sizeof(buf)))<0){
perror("readlinkat\n");
exit(0);
}
printf("buf:%s,length:%u\n",buf,(unsigned int)sz);
close(fd);
return 0;
// ./a.out ./p1_symlink.c ./foo ./mysymlinl
//输出 ./p1_symlink.c,length 14
}
进入当前目录下的foo目录就能看到刚创建的符号连接mysymlink
(symlink程序 参考自飞鹰51 老哥http://blog.csdn.net/eagle51/article/details/52704156)