实现mypwd(选做)
任务清单
1 学习pwd命令
2 研究pwd实现需要的系统调用(man -k; grep),写出伪代码
3 实现mypwd
4 测试mypwd
(一)pwd命令的学习
1、pwd的功能
通过查询man手册可知,pwd用于打印当前目录的整个路径名,即目录的绝对地址;
- 扩展:
- 绝对路径:目录下的绝对位置,直接到达目标位置,通常是从盘符开始的路径。完整的描述文件位置的路径就是绝对路径;
- 相对路径:相对于当前文件的路径;
- LINUX系统中:
- 绝对路径:以“/”为起始。例:/home/user1/abc.txt
- 相对路径为: home/user1/abc.txt
- 扩展:
2、pwd使用示例
(二)pwd需要的系统调用
- 由于pwd与目录、路径有关,输入
man -k directory |grep 2
,查询与目录有关的系统调用;
由查询结果可知有三个系统调用是可能符合结果的,分别进入对应man手册页进行查看:
chdir:改变当前所处目录
- getcwd:获得当前所在目录路径
- readdir:获得目录条目
- 其中,很明显getcwd完美符合pwd的需求,一个获取,一个打印,由此可以轻松写出以下代码:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
char dir[1000];
char *cwd=getcwd(dir, sizeof(dir));
if (cwd==NULL)
{
perror("Can't get directory!\n");
return -1;
}
else
{
printf("%s\n", cwd);
}
return 0;
}
最终效果
但是这种实现方式是取巧的,所以接下来还是要继续深入学习一下:
- 通过另两个查询出的系统调用,可以联想出另一个思路:先通过readdir获取当前目录名称,然后通过chdir向上搜寻父目录,之后不断循环此流程直至根目录;
- 但这又引出了另一个问题,readdir读的是什么呢?
- 重新打开readdir的手册页,可以看到这一行:
- 再使用
man inode
查询一下inode是干什么的:
- 由此可见,inode是文件系统中的meta data,文件索引节点,是文件基本信息的存放地和数据块指针存放地。且每一个文件都有一个独一无二的inode number。linux文件系统通过inode表进行文件的管理。
- 综上,可以写出一个基于inode的pwd伪代码,其基本思想是递归:
while(未到根目录)
{
读取当前目录名称;
打开父目录;
}
printf(目录);
(三)实现pwd
#include<stdio.h>
#include<sys/stat.h>
#include<sys/types.h>
#include<dirent.h>
#include<stdlib.h>
#include<string.h>
#define SIZE 128
ino_t get_inode(char *dirname);
void get_work_dir(ino_t inode_num);
void inode_to_dirname(ino_t inode_num, char *buf, int buflen);
int main(void)
{
get_work_dir(get_inode("."));
printf("\n");
return 0;
}
ino_t get_inode(char *dirname)
{
struct stat info;
if (stat(dirname, &info) == -1)
{
perror("dirname");
exit(1);
}
return info.st_ino;
}
void get_work_dir(ino_t inode_num)
{
ino_t parent_inode;
char buf[SIZE];
if (get_inode("..") != inode_num)
{
chdir("..");
inode_to_dirname(inode_num, buf, SIZE);
parent_inode = get_inode(".");
get_work_dir(parent_inode);
printf("/%s", buf);
}
}
void inode_to_dirname(ino_t inode_num, char *buf,int buflen)
{
DIR *dir_ptr;
struct dirent *dire;
if ((dir_ptr = opendir(".")) == NULL)
{
perror(".");
exit(1);
}
while ((dire = readdir(dir_ptr)) != NULL)
{
if (dire->d_ino == inode_num)
{
strncpy(buf, dire->d_name, buflen);
buf[strlen(buf)] = '\0';
closedir(dir_ptr);
return ;
}
}
fprintf(stderr, "error looking for inode number %d\n", (int)inode_num);
exit(1);
}