05 pwd——mkdir、rmdir、unlink、rename、chdir

1、pwd能做什么

命令pwd用来显示到达当前目录的路径。

2、pwd是如何实现的

(1)创建一个文件的过程

文件有内容和属性,内核将文件内容存放在数据区,文件属性存放在i-节点,文件名存放在目录。创建一个文件的4个主要操作:

  • 存储属性:内核先找到一个空的i-节点,内核将文件的属性信息记录其中。
  • 存储数据:内核从自由块的列表中找出相应文件大小个数的自由块。内核缓冲区的数据一块一块复制到自由块。
  • 记录分配情况:内核在i-节点的磁盘分布区记录了上述的块序列,磁盘分布区是一个磁盘块序号列表。
  • 添加文件名到目录:内核将入口(i-节点号,文件名)添加到目录文件,文件名和i-节点号之间的对应关系将文件名和文件的内容及属性连接了起来。

(2)cat命令的工作原理

cat命令的工作原理就是从目录文件一步一步找到数据的过程。

  • 在目录中寻找文件名:内核会去目录文件中包含该文件名的记录,通过遍历目录中每个条目dirent结构,这样就可以找到该文件及对应的i-节点号。
  • 定位i-节点号并读取其内容:内核在文件系统中的i-节点区域找到该i-节点号。
  • 访问存储文件内容的数据块:内核通过访问该i-节点中的记录磁盘块序号的磁盘分布区就知道文件内容存放在哪些数据块上以及它们的顺序,cat不断调用read函数,使得内核不断将字节从磁盘复制到内核缓冲区,进而到达用户空间。

总结:所有从文件读取数据的命令,例如cat、cp、more、who等,都是将文件名传给open来访问文件内容。对open的每次调用都是先在目录中寻找文件名,然后根据目录中的i-节点号获得文件的属性,最终找到文件的内容。

(3)i-节点和大文件

i-节点中存放有磁盘块分配列表只包含一个含有13个项的分配链表,当一个大文件需要很多磁盘块的时候,将分配列表的大部分存储在数据块,在i-节点中存放指向那些块的指针。比如存放一个文件需要14个数据块存储它的内容,将分配链表的前10个编号放在i-节点中,其它4个编号放入数据块中,而i-节点分配列表块11存储该数据块的编号,该数据块称为间接块,块12存储着包含更多间接块的那个数据块的编号,这个块称为二级间接块,块13存储包含更多二级间接块的那个块的编号,称为三级间接块。

(4)与目录树相关的命令和系统调用

与目录树相关的命令有mkdir、rmdir、mv、ln、rm、cd等。

  • mkdir:result=mkdir(char *pathname,mode_t mode),用于创建目录,mkdir创建一个新的目录节点并把它链接至文件系统树。mkdir创建了这个目录的i-节点;分配了一个磁盘块用以存储它的内容;在目录中设置两个入口:“.”和“..”,并正确配置了它们的i-节点号;在它的父目录中增加一个该节点的链接。
  • rmdir:result=rmdir(const char *path),用于删除一个目录且此目录必须为空。rmdir从目录树中删除一个目录节点。这个目录必须是空的。同时在父目录中删除这个目录的链接。如果这个目录本身并未被其他进程占用,它的i-节点和数据块将被释放。
  • rm:rm使用unlink系统调用,result=unlink(const char *path),用于删除一个链接,unlink用来删除目录文件中的一个记录,减少相应i-节点的链接数。如果该i-节点的链接数减为0,数据块和i-节点将被释放。unlink不能被用来删除目录。
  • ln:In用来创建一个文件的链接(硬链接),使用系统调用link,result=link(const char *orig,const char *new),创建一个文件的新链接,link生成一个i-节点的链接。新链接包含原始链接的i-节点号并且具有特定的名字。link不能用来生成目录的新链接。
  • mv:mv使用系统调用rename,reslut=rename(const char *from,const char* to),重命名或删除一个链接,rename用来改变文件或者目录的名字或位置。目录不存放文件,仅存放文件的链接,rename将一个文件移动的另一个目录,其实就是将链接从一个目录移动到另一个目录。第一步复制链接至新的名字/位置,第二步删除原来链接。
  • cd:用来改变进程的当前目录,cd使用系统调用chdir,result=chdir(const char* path),用于改变所调用进程的当前目录,。每个运行程序都有一个当前目录,chdir改变进程的当前目录,在系统内部,进程有一个存放当前目录i-节点号的变量,从一个目录进入另一个目录只是改变那个变量的值。

(5)pwd是如何实现的:

追踪链接,读取目录,一个目录接着一个目录沿着树向上追踪,每步查看当前目录“.”的文件信息stat,可以通过stat找到当前目录文件的i-节点号,然后进入父目录,通过读取父目录中每个条目dirent结构找到对应的i-节点号,这样就可以返回该i-节点号的文件名,然后更新父目录为当前i-节点号继续向上查找文件名,直到根目录,根目录的当前目录文件i-节点号和父目录文件i-节点号相同,递归终止。

3、自己编写一个pwd

spwd.c

#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<dirent.h>
ino_t get_inode(char *fname)
{
    struct stat info;
    if(stat(fname,&info)==-1)
    {
        fprintf(stderr,"Cannot stat");
        perror(fname);
        exit(1);
    }
    return info.st_ino;
}
void printpathto(ino_t this_inode)
{
    ino_t my_inode;
    char its_name[BUFSIZ];
    if(get_inode("..")!=this_inode)
    {
        chdir("..");
        inum_to_name(this_inode,its_name,BUFSIZ);
        my_inode=get_inode(".");
        printpathto(my_inode);
        printf("/%s",its_name);
    }
}
void inum_to_name(ino_t inode_to_find,char *namebuf,int buflen)
{
    DIR *dir_ptr;
    struct dirent *direntp;
    dir_ptr=opendir(".");
    if(dir_ptr==NULL)
    {
        perror(".");
        exit(1);
    }
    while((direntp=readdir(dir_ptr))!=NULL)
    {
        if(direntp->d_ino==inode_to_find)
        {
            strncpy(namebuf,direntp->d_name,buflen);
            namebuf[buflen-1]='\0';
            closedir(dir_ptr);
            return;
        }
    }
    fprintf(stderr,"error looking for inum %d\n",inode_to_find);
    exit(1);
}
int main()
{
    printpathto(get_inode("."));
    putchar('\n');
    return 0;
}

 

 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值