文件系统和pwd命令实现

112 阅读4分钟

文件系统

磁盘存储数据:盘面、磁道、扇区,盘面由多个磁道组成、磁道由多个扇区组成,扇区编号从0开始
文件系统:文件内容、文件属性(文件所有者、日期)、目录
文件系统将磁盘块分为3个部分:超级块、inode节点表、数据区
超级块:存储文件系统本身的结构信息,每个区域的大小、未被使用的磁盘块信息
inode节点表:inode节点的列表,表重每个inode节点都通过位置来标识,inode节点记录文件大小、所有者、最近修改时间,所有inode节点大小相同
数据区:文件的内容,磁盘上所有块大小相同

创建文件的流程

1.存储属性:在inode节点列表中找空闲节点,内核将文件信息记录在这个节点中
2.存储数据:将文件内容存储在数据区,假设需要2个磁盘块,内核从自由块列表中找2个自由块(200、201),内核缓冲区将第一块复制到200、第二块缓冲区复制到201
3.记录分配情况:将数据区的磁盘块号顺序的记录在inode节点的磁盘分布区
4.添加目录:将新文件名和对应的inode节点号记录到目录文件

读取文件的流程

1.在目录中查找文件名
2.通过文件名找到inode节点号
3.通过inode节点找到数据块列表
4.内核知道数据块后,使用read函数,将磁盘上的字节复制到内核缓冲区,然后到用户空间

操作没有读写权限的文件

1.根据文件名找到inode节点
2.读取inode节点的信息,文件的权限位、UID
如果用户ID对文件没有访问权限,open返回-1,将全局变量设为EPERM

存储大文件

使用多级指针,inode节点的磁盘分布区只有13个空间,前10个空间用来存储具体的磁盘块号,第11个空间用来存储一级指针(指针指向磁盘块号的数组),第12个空间用来存储二级指针,第13个空间用来存储三级指针

// 一级指针 p_disk
int disk_num[] = {200,201,202}; // 占用200 201 202号磁盘块
int *p_disk = disk_num;
// 二级指针 pp_disk
int disk_num_1[] = {200,201}; // 占用200 201号磁盘块
int disk_num_2[] = {202,203}; // 占用202 203号磁盘块
int *p_disk1 = disk_num_1; // 一级指针
int *p_disk2 = disk_num_2; // 一级指针
int *p_arr[] = {p_disk1,p_disk2};
int **pp_disk = p_arr;

目录

目录包含子目录和文件,每个子目录都有一个父目录
文件在目录中的含义:文件都有一个对应的inode节点,在目录中有指向inode节点的链接

多个文件系统组合

1.每个分区都有自己的文件系统树,当计算机有超过一个文件系统时,系统将这些树整合成一颗更大的数
2.一个文件系统是根文件系统,这棵树的顶端是整颗树真正的根,另一个文件系统被加载到根文件系统的某个子目录上
3.内核在跟文件系统将一个目录作为指针,指向另一个文件系统的根,将两个文件系统联系起来

装载点

子树的根目录被嵌入到根文件系统的一个目录中,子树所在的目录是第二个系统的挂载点
mount命令 列出当前所装载的文件系统以及挂载点

/dev/sda1 on / type ext4 /dev/sda1上的分区1装载在树的根目录上,这个分区时根文件系统
/dev/sr0 on /media/helisi/Ubuntu /dev/sr0上的文件系统被装载在根文件系统的/media/helisi/ubuntu目录上
当用户使用chdir从/进入/media/helisi/ubuntu时,实际上是从一个文件系统进入另一个文件系统

硬链接和符号链接

硬链接是将目录链接到树的指针,同时也是将文件名和文件本身链接起来的指针,不能指向其他系统的inode节点

pwd命令

实现思路: 1.stat函数得到当前目录的节点号
2.chdir到父目录
3.找到i节点号对应的文件名
4.判断是否到达树的顶端(当前目录与父目录的inode节点号相同)

#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <string.h>
#include <dirent.h>
#include <unistd.h>

ino_t get_inode(char *filename) {
    struct stat info;
    if(stat(filename, &info) == -1) {
        fprintf(stderr, "cannot stat ");
        perror(filename);
        exit(1);
    }
    return info.st_ino;
}

void inode_to_name(ino_t inode_num, char *namebuf, int buflen) {
    DIR *p_dir;
    struct dirent *p_dirent;
    p_dir = opendir(".");
    if(p_dir == NULL) {
        perror(".");
        exit(1);
    }
    while((p_dirent = readdir(p_dir)) != NULL) {
        if(p_dirent -> d_ino == inode_num) {
            strncpy(namebuf, p_dirent -> d_name, buflen);
            namebuf[buflen - 1] = '\0';
            closedir(p_dir);
            return;
        }
    }
}

void printpathto(ino_t this_inode) {
    ino_t my_inode;
    char filename[BUFSIZ];
    if(get_inode("..") != this_inode) {
        chdir("..");
        inode_to_name(this_inode, filename, BUFSIZ);
        my_inode = get_inode(".");
        printpathto(my_inode);
        printf("/%s", filename);
    }
}

int main(void) {
    printpathto(get_inode("."));
    putchar('\n');
    exit(0);
}