文件系统
文件存储相关的概念
文件描述主要有两个inode和dentry
inode
是一个结构体, 里面有这一个文件的权限, 类型, 大小, 时间, 用户, 盘块位置之类的信息, 这一个是文件属性的管理结构
文件名是单独存储的, 可以使用inode的编号找到这一个结构体
创建一个硬链接的时候实际这两个文件的inode是一样的, 不一样的是dentry
dentry 目录项
这一个结构体里面有两个主要的变量(经常使用), 分别是文件名以及inode的编号, 可以使用这一个获取文件的信息
文件操作
stat函数:获取文件属性
实际上是从文件的inode结构体里面获取
int stat(const char *pathname, struct stat *statbuf);
参数1: 是一个文件的路径
参数2: 这一个实际返回值
int fstat(int fd, struct stat *statbuf);
使用的参数是一个文件的描述符
int lstat(const char *pathname, struct stat *statbuf);
这一个函数的目标是一个软链接的时候返回的是这一个软链接的信息, 之前的几个函数返回的是软连接指向的文件
可以使用这几个宏定义进行文件的格式的获取, 这一个实际是使用一个16位的数据保存了这一个文件的数据类型, 这几个宏定义是判断这一个数字的高几位是什么, 这一个数据里面还有这一个文件的权限
其他位
特殊权限位:
包含三个二进制位。依次是:设置组ID位setGID;设置用户ID位setID;黏住位sticky
黏住位
早起计算机内存紧,只有精要的常用的程序可以常驻物理内存,剩下的要暂存磁盘中。当内存不够用的时候会将该部分程序存回磁盘,腾出内存空间。若文件设置了黏住位,那么即使在内存比较吃紧的情况下,也不会将该文件回存到磁盘上。由于现阶段操作系统的虚拟内存管理分页算法完善。该功能已经被废弃。
但我们仍然可以对目录设置黏住位。被设置了该位的目录,其内部文件只有:
①超级管理员
②该目录所有者
③该文件的所有者
以上三种用户有权限做删除、修改操作。其他用户可以读、创建但不能随意删除。
setUID位
进程有两个ID:EID(有效用户ID),表示进程履行哪个用户的权限。
UID(实际用户ID),表示进程实际属于哪个用户。
多数情况下,EID和UID相同。但是,当文件的setID被设置后两个ID则有可能不一样。
例如:当进程执行一个root用户的文件,若该文件的setID位被设置为1, 那么执行该文件时,进程的UID不变。EID变为root,表示进程开始履行root用户权限。
access检测文件权限
int access(const char *pathname, int mode);
F_OK , R_OK, W_OK, and X_OK. F_OK tests for the existence of the file. R_OK, W_OK, and X_OK test whether the file exists and grants read, write, and execute permissions, respectively.
成功的时候返回0, 这一个文件不存在或者这一个文件的某一个查询的文件不存在, 这个时候返回-1
chmod改变一个文件的权限
int chmod(const char *pathname, mode_t mode);
可以设置权限以及几个特殊位
- 权限位
- 特殊位
4.4 S_ISUID、S_ISGID位与文件访问权限检查-CSDN博客
大致意思是前面两个位设置的时候其他用户使用这一个文件的时候会使用这一个用户的拥有者的ID
后面是黏住位, 前面有
link创建一个硬链接
int link(const char *oldpath, const char *newpath);
这一个文件的路径, 以及硬链接的路径, 实际是为一个文件创建一个新的dentry
返回0表示成功
unlink删除一个文件
int unlink(const char *pathname);
删除一个文件的目录项, 这一个文件的目录项为0的时候这一个文件会被删除, 这一个文件不是立刻被删除的, 实际的删除是操作系统处理的, 如果有一个其他的进程使用这一个文件, 这一个文件会在打开这一个文件的进程结束以后再释放这一个文件
可以使用这两个函数实现一个mv命令, 先为这一个文件创建一个dentry, 再把旧的dentry移除
隐式回收
一个进程结束以后, 这一个进程打开的资源会被回收, 包括打开的文件, 申请的空间
symlink软连接
int symlink(const char *target, const char *linkpath);
为文件创建一个软连接, 实际是一个记录文件路径的字符串
readlink从一个链接获取文件路径
ssize_t readlink(const char *pathname, char *buf, size_t bufsiz);
把这一个文件的路径放在这一个buf里面, 如果这一个buf很小, 这一个路径会被截断
rename给一个文件重命名
int rename(const char *oldpath, const char *newpath);
如果这一个新的文件已经存在, 这一个文件会被替代
目录操作
getcwd获取位置
获取进程当前工作目录 (卷3,标库函数)
char *getcwd(char *buf, size_t size);
成功:buf中保存当前进程工作目录位置。失败返回NULL。
chdir变换路径
改变当前进程的作目录, 相当于cd
int chdir(const char *path);
成功:0;失败:-1设置errno为相应值
文件目录权限
如果使用vi打开一个目录, 可以获取这一个目录里面的文件名(目录项)
r | w | x | |
---|---|---|---|
文件 | 文件的内容可以被查看 | 内容可以被修改 | 可以运行产生一个进程 |
cat、more、less… | vi、> … | ./文件名 | |
目录 | 目录可以被浏览 ls tree | 创建、删除、修改文件 touch rm mkdir | 可以被打开、进入 cd |
目录设置黏住位:若有w权限,创建不变,删除、修改只能由root、目录所有者、文件所有者操作。
opdir打开一个目录
DIR *opendir(const char *name);
成功的时候返回描述符, 失败的话会返回NULL
closedir关闭这一个文件
int closedir(DIR *dirp);
0: 成功, -1失败
readdir返回目录里面一个目录的描述符
struct dirent *readdir(DIR *dirp);
这一个是获取这一个文件夹里面的文件的目录项
注 :使用这一个函数的时候需要注意这一个函数可以获取到. 和 … 目录, 遍历的时候要注意不要死循环
rewinddir返回文件夹的开头
void rewinddir(DIR *dirp);
这一个函数主要用于遍历文件的时候, 从头再开始
telldir/seekdir函数
获取目录读写位置
long telldir(DIR *dirp); 成功:与dirp相关的目录当前读写位置。失败-1,设置errno
修改目录读写位置
void seekdir(DIR *dirp, long loc); 返回值:无
参数loc一般由telldir函数的返回值来决定。
dup/dup2重定向文件
这一个在命令行里面的形式的>(把输出的信息添加到文件)或者>>(追加)
int dup(int oldfd);
int dup2(int oldfd, int newfd);
dup2实际是把后面的那一个文件指向前一个文件, 使用的时候如果newfd这一个描述符被使用了, 会把这一个描述符覆盖
还可以使用fcntl的F_DUPFD实现同样的功能, 但是如果new放到位置的文件被使用的时候这一个文件不会被覆盖, 而是使用比他大的第一个可以使用的描述符
可以使用这两个函数配合exec系列函数实现比如 ls -l > wc的功能