2017-2018-1 20155330 《信息安全系统设计基础》加分项目--实现mypwd
pwd命令
- 命令功能:查看”当前工作目录“的完整路径。
- 通过man命令查看pwd的相关信息
mypwd的实现
研究pwd实现需要的系统调用(man -k; grep),写出伪代码
- 通过
man -k directory | grep 2
查看相关系统调用。可以发现getcwd()函数是实现该功能的相关函数。
- 通过
man 2 getcwd
查看函数结构。
- 利用
getcwd()
函数简单实现的伪代码
设置一个char型数组(或指针)用于保存当前绝对路径内容;
调用系统函数`getcwd()`获取当前路径并保存在之前的数组中;
if(返回指针==NULL)
错误;
else
打印当前路径;
- 代码
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#define MAX 2048
int main()
{
char buf[MAX],*a=getcwd(buf,sizeof(buf));
if(a==NULL)
printf("Error!");
else
printf("%s
",a);
return 0;
}
运行结果:
- 通过
man -k directory | grep 3
查看相关库函数。
- 通过之前查看的getcwd函数可知getcwd函数与getwd函数基本相同。现在查看
opendir()
函数和readdir()
函数。opendir()
函数
readdir()
函数
- 由
readdir()
函数中的结构体
struct dirent {
ino_t d_ino; /* inode number */
off_t d_off; /* not an offset; see NOTES */
unsigned short d_reclen; /* length of this record */
unsigned char d_type; /* type of file; not supported
by all filesystem types */
char d_name[256]; /* filename */
};
可以知道显示文件名需要与之对应的i-node
。
- 获得i-node可用stat函数,需要注意的是,在使用帮助文档查看stat函数时,应使用命令
man 2 stat
。 - 代码实现查看inode功能
#include <sys/types.h>
#include <sys/stat.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
struct stat sb;
if (argc != 2) {
fprintf(stderr, "Usage: %s <pathname>
", argv[0]);
exit(EXIT_FAILURE);
}
if (stat(argv[1], &sb) == -1) {
perror("stat");
exit(EXIT_FAILURE);
}
printf("File type: ");
switch (sb.st_mode & S_IFMT) {
case S_IFBLK: printf("block device
"); break;
case S_IFCHR: printf("character device
"); break;
case S_IFDIR: printf("directory
"); break;
case S_IFIFO: printf("FIFO/pipe
"); break;
case S_IFLNK: printf("symlink
"); break;
case S_IFREG: printf("regular file
"); break;
case S_IFSOCK: printf("socket
"); break;
default: printf("unknown?
"); break;
}
printf("I-node number: %ld
", (long) sb.st_ino);
printf("Mode: %lo (octal)
",
(unsigned long) sb.st_mode);
printf("Link count: %ld
", (long) sb.st_nlink);
printf("Ownership: UID=%ld GID=%ld
",
(long) sb.st_uid, (long) sb.st_gid);
printf("Preferred I/O block size: %ld bytes
",
(long) sb.st_blksize);
printf("File size: %lld bytes
",
(long long) sb.st_size);
printf("Blocks allocated: %lld
",
(long long) sb.st_blocks);
printf("Last status change: %s", ctime(&sb.st_ctime));
printf("Last file access: %s", ctime(&sb.st_atime));
printf("Last file modification: %s", ctime(&sb.st_mtime));
exit(EXIT_SUCCESS);
}
- 运行结果
- 综合以上信息得到伪代码
设置一个char型数组(或指针)用于保存当前绝对路径内容,无符号数用于记录绝对路径的深度;
while(1)
{
分别获取"."(当前目录)和".."(当前目录的上一级目录)i-node;
if("."i-node==".."i-noode)
输出目录信息;
else
{
切换至父级目录获取i-node
在父级目录中搜索对应的文件名并记录下来
}
}
- 完整代码
#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <unistd.h>
//获取文件的inode-number
ino_t get_ino_byname(char *filename)
{
struct stat file_stat;
if(0 != stat(filename, &file_stat)) //stat()通过文件名filename获取文件信息,并保存在buf所指的结构体stat中
{
perror("stat");
exit(-1);
}
return file_stat.st_ino;
}
//根据inode-number, 在当前目录中查找对应文件名
char *find_name_byino(ino_t ino)
{
DIR *dp = NULL;
struct dirent *dptr = NULL;
char *filename = NULL;
if(NULL == (dp = opendir("."))) //opendir()打开一个目录,在失败的时候返回一个空的指针,成返回DIR结构体
{
fprintf(stderr, "Can not open Current Directory
");
exit(-1);
}
else
{
while(NULL != (dptr = readdir(dp))) //readdir()用来读取目录。返回是dirent结构体指针
{
if(dptr->d_ino == ino)
{
filename = strdup(dptr->d_name); //strdup()将串拷贝到新建的位置处,返回一个指针,指向为复制字符串分配的空间;如果分配空间失败,则返回NULL值.
break;
}
}
closedir(dp);
}
return filename;
}
int main(int argc, char *argv[])
{
//记录目名的栈
char *dir_stack[256];
unsigned current_depth = 0;
while(1)
{
ino_t current_ino = get_ino_byname("."); //通过"."获取当期目录inode
ino_t parent_ino = get_ino_byname(".."); //通过".."获取当前目录的父目录的inode
if(current_ino == parent_ino)
break; //达到根目录,推出循环
/*若两个inode不一样*/
chdir(".."); //更改当前工作目录,变为当前目录的父目录
dir_stack[current_depth++] = find_name_byino(current_ino); //"文件名"地址存放
}
int i = current_depth - 1;
for(i = current_depth - 1; i >= 0; i--) //打印路径
{
fprintf(stdout, "/%s", dir_stack[i]);
}
fprintf(stdout, "%s
", current_depth == 0 ? "/" : "");
return 0;
}
运行结果: