先上一个linux文件系统的结构示意图
这个图说的是系统的文件是通过类似树这种数据结构来实现的。目录和文件是一个个的node,有各自的节点号,和一些基本信息(结构体方式存储),放在横条的白色部分。然后文件里面的数据是存放在后面的数据块。数据块不一定是连续的,由节点通过指针找到数据块的地址。
就好比上图里面最上面一层目录包括y、a、c三个文件(夹),这就是一个根节点。每个节点的“."代表他自身,”.."这个代表他的父亲。所以我们在linux命令中cd . . 就是进入上一层的意思.,而执行指令 ./xxx ,就代表在当前目录下执行某个文件。
a 前面的数字277代表a在277这个位置 ,而下面图中277旁边的点 “."就代表a自身 ,其他的点也是一样。
那么要实现pwd命令的功能,就分这么几步:
一、获取节点号
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;
}
这段代码中ino_t 指的是类似520,277这种数字的格式,是节点号类型 ,类似int,可以强转。
get_inode这个函数就是传入一个文件(目录)名称,返回他的节点号。函数的实现是通过系统提供的stat结构体,里面包含了st_ino成员,可以提供这个信息。
获取文件名(不是当前文件名fname,而如果是上一层以上,就是未知的,因此要给出获取方法):
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", (int)inode_to_find);
exit(1);
}
实现并不复杂,是通过目录结构体dirent获取的。
三、然后是打印路径
void printpathto(ino_t this_inode){
ino_t my_inode;
char its_name[BUFSIZ];
if( get_inode("..") != this_inode ){
chdir(".."); /* up one dir */
inum_to_name(this_inode, its_name, BUFSIZ); /* get its name*/
my_inode = get_inode("."); /* print head */
printpathto(my_inode); /* recursively */
printf("/%s", its_name); /* now print */
}
}
这里用到了递归思想。有点像前面打印二进制格式数字的方法。C Primer Plus 15 章 编程题2 打印二进制格式字符串的两种方法_自觉的数字公民杨某某的博客-CSDN博客就是说,如果当前文件夹的上一层 chdir(".."),是不一样的节点的话get_inode("..") != this_inode,那么就调用自身。否则就打印(从根节点开始打印)
四、main函数部分:
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
ino_t get_inode(char *);
void printpathto(ino_t);
void inum_to_name(ino_t, char * , int);
int main(){
printpathto(get_inode(".")); /* print path to here */
putchar('\n');
return 0;
}