4.文件系统

目录

正如文件描述符一章说过,在Unix/Linux中万事万物都是文件,目录也是文件。

“目录”本质上与一本书的目录没有差别。一个目录实为一个文件,其内容为一系列条目。每一个条目为文件名与“页码”的对应,“页码”即为文件存储的位置。

目录入口(dirent)结构

Linux中的目录同图书的目录十分相似,一个目录是一个特殊的文件,其内容为一系列条目。每个条目,即每个目录入口结构,中最为重要的是文件名(d_name)和其“页码”(d_ino)——在Linux中是一个称为i-node number(i节点号)的整数。完整的条目结构如下:

struct dirent {
	ino_t			d_ino;       /* inode number */
	off_t			d_off;       /* not an offset; see NOTES */
	unsigned short 	d_reclen;    /* length of this record */
	unsigned char  	d_type;      /* type of file; not supported
									by all file system types */
 	char			d_name[256]; /* filename */
 };

编写ls命令

ls命令的目的,就是打开一个目录文件,并将其每一个目录入口结构中的文件名打印出来。由于不同的Unix/Linux的版本或不同的文件系统在目录文件结构上有所出入,不建议使用系统调用open/read/close来处理目录文件。我们可以通过

man -k directory|grep open

来查找一下如何打开一个目录。

image-20211201214802321

其中,opendir (3p)就是我们需要的,而且它是POSIX标准。当然opendir (3)也没问题。

man 3p opendir
基本的ls
#include <sys/types.h>
#include <dirent.h>
#include <stdlib.h>
#include <stdio.h>

main(int ac, char *av[]){
	DIR *dp;
	struct dirent *p;
	if(1==ac){
		dp=opendir(".");
	}
	else{
		if((dp=opendir(av[1]))==NULL){
			perror("cannot open");
			exit(1);
		}
	}

	while((p=readdir(dp))!=NULL){
		if(p->d_name[0]!='.'){
			printf("%s\n", p->d_name);
		}
	}

	closedir(dp);
}
ls -l

运行该命令,结果如下

image-20211201220838837

每一条目从左到右分别为:文件模式(mode)、链接数、用户(在Linux下user即所有者)、组用户、文件大小、最后修改时间、文件名。其中ls -l展示的mode共包含10个字母,首位是文件类型,-代表一般文件,d代表目录,c代表字符设备,b代表块设备。剩下9位表示文件权限。共分为三组,每一组3位,第一组对应的是用户的权限,第二组对应的是同组用户的权限,第三组对一个的是其他用户的权限。每一组的三位对应的含义是:

  • r(Read,读权限):对文件而言,具有读取文件内容的权限;对目录来说,具有浏览目录的权限。
  • w(Write,写权限):对文件而言,具有新增、修改文件内容的权限;对目录来说,具有创建、删除、移动目录内文件的权限。
  • x(eXecute,可执行权限):对文件而言,具有执行文件的权限;对目录来说,该用户具有进入目录的权限。

想要编写ls -l,文件名我们已经通过读取目录获得了,我们还需获得其他信息。

文件状态(status)(文件属性)

通过man手册搜索如何获取文件状态(status)。

man -k file|grep status
image-20211203190609238

我们选择使用系统调用stat (2),man 2 stat可以看到stat的手册页

文件mode

st_mode是一个16 bit的整数,其中最高4位代表文件类型(理论上可以表示16种文件类型,但实际只用到了7种),后面12位每三位分为一组,共分为三组。第一组(最高的三位)对应的是setuidsetgid,和sticky;第二组对应的是用户的权限,第三组对应的是同组用户的权限,第四组对一个的是其他用户的权限。

setuid

setuid位被设置为1之后, 当文件被执行(该程序被运行时)时, 操作系统会赋予文件用户(即文件所有者)的权限。

我们以修改密码为例,我们在“用户”一章已经学习过,每个用户都可以使用passwd命令修改自己的密码。同样在“用户”一章也学习过,用户的真正密码,一般都存储于/etc/shadow里。

shadow条目中的第一项为用户名,第二项为加密后的密码。

这里面的关键问题是,很显然,/etc/shadow没有写权限。当然root有至高无上的权利,他不会收到mode的限制而具有任何权限。但是为何每个用户都可以用passwd命令修改/etc/shadow——这个只有root有修改权限的文件呢?

原因在于passwdsetuid位被设置为1了。

第四个字符“s”的意思等于"x+setuid",/bin/passwdmode对应的二进制数值为1000 100 111 101 101。1000代表的是一般的文件。

setgid

setgid位与setuid相似,当setgid位被设置为1之后, 当文件被执行(该程序被运行时)时, 操作系统会赋予文件组用户的权限。

该mode对应的二进制数值为1000 010 111 101 101。

sticky

如果对文件设置sticky位,则要求当该文件执行时,必须使其常驻内存而不要将其临时存储于硬盘上的交换空间上(swap space)。当然,由于现在都是采用基于分页的虚拟内存技术,Linux内核已经忽略普通文件的sticky位了。

如果对目录设置sticky位,则表示该目录中的文件,只能被其用户(所有者)和root删除。最有代表性的就是/tmp目录。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值