操作系统:文件系统

本文探讨了硬链接和符号链接在Linux文件系统中的区别,包括硬链接数的增减原理、硬链接与符号链接的创建与删除,以及目录操作函数如getcwd、chdir、mkdir和rmdir的用法。同时揭示了文件在磁盘上的存储结构和文件链接的工作机制。
摘要由CSDN通过智能技术生成

在这里插入图片描述

文件在块设备上存储时,磁盘大致被分为三部分:

  1. 超级区
    负责"块设备"空间的分配和回收,记录块设备空间哪里用了哪里没用。

  2. inode节点区

    • 被划分为了一个个相连的,空间大小相同的inode节点空间。
    • 每个节点空间被用于存放某个文件的属性信息,每个节点空间大小是固定的比如一般的是512字节
    • 每个节点都有一个节点编号,通过节点编号就可以索引找到inode节点空间。
      使用stat读取文件属性时,struct stat结构体中的st_dev成员,就是用来存储inode节点编号的。
  3. 数据区
    数据区专门用于存放文件的数据。

    存储数据时,实际上并不是数据有多少个字节,就分配对应多少的字节空间给你,为了便于助理空间高效管理,往往都是按块分配空间的,一块往往为4k字节(4*1024) 。
    文件中的数据小于一块时,还是给你分配一块,当数据超过一块时,会给你再分配一块,当这一块又满了时,再给你分配一块。

    不同的数据块之间不一定是连续的,块之间使用地址进行相互链接,也即是说每一块都有存放前后块的地址,通过地址就可以找到前后块空间。

    • 目录文件
      目录文件的数据量小,所以一般就只有一块数据。目录文件里面放的内容,并不是目录所包含文件的数据,放的只是所包含文件的基本信息,其中两个信息最重要。文件名和文件的inode节点号
    • 链接文件
      存放的数据很简单,就是所指向文件的文件名。

硬链接

每创建一个硬链接,文件就多一个文件名,硬件链接数+1
创建硬链接后所得到的多个文件名,指向的同一个inode节点,只有inode节点代表了文件的真实存在,inode节点只有一个,因此多个文件名指向的是同一个文件,不管使用的是哪一个文件名,都能操作这个文件。

硬链接数

记录了有多少个文件名指向这个inode节点,通过创建硬链接,每增加一个文件名,就多一个硬链接数。
同理,每删除一个一个硬链接,也就是删除一个文件名,就少一个硬链接数,当然硬链接数被减为0时,也就代表着文件名被删除完了,这个文件也就被删除了。
不过这里需要主要一点,当硬链接数被减为了0时,如果还有进程在操作这个文件的话,这个文件还会一直存在,直到进程结束后,这个文件才被删除。

删除文件后,文件数据还在,因为删除文件时,只是将文件的inode节点空间释放了,如果这个文件的数据没有被覆盖的话,只要将文件的inode节点空间恢复,即可还原该文件。

  • 为什么新建的目录一开始的文件链接数就是2?
    因为新创建的目录,一开始就有两个名字指向了目录的inode节点,分别是目录的本名和.

  • 为什么在该目录下,每多创建一个目录,当前目录就会多一个硬链数?
    新创建目录的..名字,也指向了当前目录。

  • Linux不允许用户自己给目录创建硬链接,只能由Linux系统自己给目录创建硬链接。用户只能给目录以外的,其它类型的文件创建硬链接。

link与unlink

#include <unistd.h>
int link(const char *oldpath,const char *newplath);//原有路径名->新路径名
int unlink (const char *pathname) ;//pathname 删除硬链接的路径名

可以使用unlink创建临时文件,先用open创建一个文件,然后使用unlink删除文件的硬链接,在进程结束前还可以使用这个文件,进程结束后文件就删除了。

remove

#include <stdio.h>
int remove (const char *pathname) ;

功能:可以用于删除任何文件(既可以删除目录文件,也可以删除非目录文件)。删除非目录文件时,功能与unlink一样。

remove是一个库函数。它封装了unlink和rmdir这两个系统函数。remove会自动检测文件类型,如果是目录就调用rmdir删除,如果其它文件,就调用unlink删除。

rename

#include <stdio.h>
int rename(const char *oldpath,const char *newpath);

功能:修改文件路径名,将旧的路径名oldpath,改为新的路径名newpath。

mv就是调用rename函数实现的,看起来功能有三个(改名、移动、移动+改名),其实功能就一个,修改文件的路径名。

符号链接

符号链接文件也被称为软链接文件。
使用ln -s就可以创建符号链接文件。

符号链接与硬链接的对比
  • 创建硬连接
    同一个文件有多个不同的名字,它们指向是同一个inode节点。
  • 创建符号链接文件
    符号链接文件与它所指向的文件,是两个完全不同的独立的文件,拥有自己独立的inode节点。符号链接文件的数据就是指向文件的文件名,文件大小就是名字的字符个数。
  • 不能给目录创建硬链接,但是可以给目录创建符号链接

symlink

#include <unistd.h>
int symlink(const char *oldpath,const char *newpath);

功能:为oldpath,创建符号连接文件newpath。
使用ln创建硬链接时,调用的是link函数。
使用ln -s创建符号链接时,调用的是symlink,sym就是符号的意思。

readlink

#include <unistd.h>
ssize_t readlink(const char *path,char *buf,size_t bufsiz);
  • 功能:读符号链接文件的数据(指向文件的名字)。readlink命令,就是调用这个函数实现的。
  • 参数
    • const char *path:符号连接文件的路径名。
    • char *buf:存放名字的缓存。
    • size t bufsiz:缓存的大小
  • 返回值:调用成功,返回读到的字节数,失败返回-1,errno被设置

目录操作函数

getcwd

include <unistd.h>
char *getcwd(char *buf, size_t size) ;
char *getwd(char *buf); 
  • 功能:获取进程的当前工作目录
  • 参数
    • buf:存放获取到的当前路径的缓存
    • size:缓存的大小
  • 返回值:成功返回指向字符串的指针,字符串存放当前工作目录,失败返回NULL,erno被设置。

chdir

#include <unistd.h>
int chdir(const char *path);
int fchdir(int fd) ;

切换进程当前工作目录到path或文件描述符fd指向的路径

mkdir

#include <sys/stat.h>
#include <sys/types.h>
int mkdir(const char *pathname,mode_t mode);
  • 功能:创建新目录。
  • 参数
    • pathname:需创建目录的路径名
    • mode:指定目录的原始权限,一般给0775
      给目录指定原始权限时,一定要有x权限,否者无法进入这个目录。
  • 返回值:调用成功返回0,失败返回-1,errno被设置

rmdir

#include <unistd.h>
int rmdir(const char *pathname) ;
  • 函数功能:删除路径名为pathname的这个目录,必须是空目录,如果目录不空,则需递归删除。
    不管是我们讲那个函数,在指定路径名时,可以是相对路径,也可以是绝对路径。
    删除时,Linux系统会调用相关函数,将目录硬链数全部减位0,然后目录就被删除了。
  • 函数返回值:调用成功返回0,失败返回-1,errno被设置

opendir

#include <sys/types.h>                                                               
#include <dirent.h>                                                                 
DIR *opendir(const char *name);                                                     
DIR *fdopendir(int fd);
  • 功能:打开目录,不能使用open函数打开目录,只能使用opendir打开。

  • 参数:

    name:需打开目录的路径名
    fd:文件描述符

  • 返回值
    调用成功:返回一个DIR *的指针,这个指针指向了被打开的目录,readir通过这个指针就可以读取目录的目录项。
    调用失败:返回NULL,errno被设置。

readdir

#include <dirent.h>
struct dirent *readdir(DIR *dirp) ;
  • 功能:读取目录里的目录项。每调用一次,就读取出一条目录项。

  • 参数
    dirp: opendir打开目录时,得到的指针。

  • 返回值:调用成功,返回指针指向struct dirent结构体的指针。这个结构体其实是定义在了<dirent.h>头文件中。

    这个结构体就是用来存放一条目录项的,调用readdir读取到目录项后,会自动开辟一个struct dirent变量来存放目录项,然后将变量的指针返回,应用程序通过这个指针,就可以访问结构体中的目录项信息(文件基本信息)。

    struct dirent
    {
    	ino_t d_ino;/*i节点编号*/
    	off_t d_off;/*地址偏移*/
    	unsigned short d_reclen;/*本条目录项的大小*/
    	unsigned chard_type;/*文件类型,不是所有系统都支持*/
    	char d_name [256]; /*文件名字*/
    };
    

    返回NULL的话有如下两种情况:
    1)读到目录的末尾时,返回NULL。
    2)函数调用失败时,也返回NULL,不过errno被设置。
    怎么判断函数是否调用失败了呢,如果ernno==0,表示没有设置错误号,返回NULL是因为读到了文件的末尾。如果errno!=0,表示是因为函数调用出错而返回的NULL。

int main(void){
	DIR *dirp = NULL;
    dirp = opendir(".");
    if(NULL == dirp)
    {
		perror("opendir fail");
        exit(-1);
	}
    while(1){
        struct dirent *direntp = NULL;
        direntp = readdir(dirp);
        if(direntp == NULL && errno!=0)//调用失败
        {
        	perror( "readdir fail");
            exit(-i);
        }
        printf("inodeID=%d,fnane=%s\n",direntp->d_ino,direntp->d_name);
        if(direntp == NULL && errno == 0) break;//读到目录末尾
	}
}

chmod

#include <sys/stat.h>                                                               
int chmod(const char *pathname, mode_t mode);                                    
int fchmod(int fd, mode_t mode);     
  • 功能:修改文件权限,比如将权限指定为0664等。
    chmod命令就是调用这两个函数来实现的。
    chmod:使用路径名操作
    fchmod:使用文件描述符操作
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Shilong Wang

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值