最近Linux课要考试了,在复习文件系统。顺便就尝试实现一下pwd命令
这个命令的功能很简单,就是显示当前目录的绝对路径
key point:
由于在Linux/Unix文件系统中,每个文件对应的inode值都是唯一的。这个就是我们要寻找的突破点。
算法核心:
1. 拿到当前目录中"."这个目录的st_ino值,记为inode。
2. 转到父目录中,遍历父目录,找到第一个st_ino值与inode相同的那个目录,并保存名字。
3. 再拿当前目录中"."目录的st_ino值作为inode,向前递归(此时的"."目录已经不是1中的"."了,而是1中的"..")
4. 输出 “/" + 2中保存的名字
由于3与4之间的次序关系,保证了输出的字符串中,子目录总是在父目录后面的。
递归出口:
由于在根目录下,"." 和 ".." 的inode值是一样的,所以当递归到某一层,若父目录的inode值与当前的inode值(作为递归函数的参数传入) 相同,那么就可以结束递归了。
注意:
需要注意的就是,步骤2 要把遍历父目录的那个函数的当前路径跳转到父目录中去,chdir("..")。如果不这样子做的话,你匹配到的那个字符串始终是 ".",且你的目标的st_ino和inode不一样 !!! 结果,程序的输出就变成这样了:/./././. .... 读者可以自行尝试。下面是我在/Users/user下的一个测试程序的输出:
程序分别输出:
1. 当前目录下,"."的st_ino值
2. 父目录下所有文件的st_ino值,(其中"user" 是正确的目标目录名)
(如果"."和"user"的inode值相同,那么才算正确)
1. 没有加chdir,仅以opendir("..")代替,出错!!!
2. 加上chdir(".."),转换到父目录后,应该 opendir(".") 而不是 opendir("..")了,正确!!!
看,当前目录中,"."的inode值是603090,父目录中,"user"的inode值也是603090
源代码:
#include <dirent.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
int flag = 0;
unsigned long get_inode(char *name) {
struct stat e;
if (lstat(name,&e) == -1) {
printf("lstat error\n");
return 0;
}
return e.st_ino;
}
void pwd(unsigned long inode) {
struct dirent *dp;
struct stat e;
DIR* dir;
if(get_inode("..") == inode)
return;
chdir("..");
if((dir = opendir(".")) == NULL) {
printf("opendir error\n");
return;
}
while ( (dp = readdir(dir)) != NULL) {
if (lstat(dp->d_name,&e) == -1) {
printf("lstat error\n");
break;
}
if (e.st_ino == inode) {
flag = 1;
pwd(get_inode("."));
printf("/%s",dp->d_name);
break;
}
}
closedir(dir);
}
int main(int args , char * argv[]) {
pwd(get_inode("."));
if(!flag) printf("/");
printf("\n");
return 0;
}