2017-2018-1 20155339 第十一周加分项Linux下Mypwd的实现

学习pwd命令

  • 通过man命令查看pwd命令的功能

  • 由图可知pwd命令的用途是显示工作目录的路径名称。pwd 命令将当前目录的全路径名称(从根目录)写入标准输出。全部目录使用 /(斜线)分隔。第一个 / 表示根目录,最后一个目录是当前目录。

  • pwd [-L]如果 PWD 环境变量包含了不包含文件名 .(点)或 ..(点点)的当前目录的绝对路径名,则显示 PWD 环境变量的值。否则,-L 标志与 -P 标志一样运行。

  • pwd [-p]显示当前目录的绝对路径名。与 -P 标志一起显示的绝对路径不包含在路径名的绝对路径中涉及到符号链接类型的文件的名称。

  • 运行结果

研究pwd实现需要的系统调用(man -k; grep),写出伪代码

  • 分析:由图可知,getcwd具备这个功能,除此之外```readdir``也可以实现该功能。
  • getcwd:通过查看帮助文档,可以知道该函数用途:取得当前的工作目录,头文件为#include <unistd.h>,使用方法:char *getcwd(char *buf, size_t size);getcwd()会将当前的工作目录绝对路径复制到参数buf 所指的内存空间,参数size 为buf 的空间大小。
  • getcwd伪代码:
char buf[256];
getcwd(buf,sizeof(buf));
输出buf;
  • readdir:通过查看readdir的帮助文档可知此处调用readdir的c函数库函数比较合适,查看其帮助文档,如下图,其用途为读取目录,头文件为#include <dirent.h>函数使用方法:struct dirent *readdir(DIR *dirp); 返回dirent结构体指针,dirent结构体成员如下,
 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 */
};

  • 查看readdir的相关函数可以看到opendir,借鉴之前的经验,在read一个文件之前肯定需要先将这个文件打开,因此我们查看opendir的帮助文档,该函数用途为:打开目录文件,头文件为:
#include <sys/types.h>
#include <dirent.h>

函数原型:DIR *opendir(const char *name);

返回值:成功则返回DIR* 型态的目录流, 打开失败则返回NULL。

  • 文件是通过i节点对其内容进行一个索引,因此一个文件一个i节点,因此此处我们要实现pwd命令,必须要知道文件的i节点,并且通过实践可知(可以在根目录下查看i结点值可知,根节点与其父结点的i节点值一样,因此可以通过这一点来设定循环条件,通过man帮助文档进行查找,得到如下信息:

  • 选择stat函数:用途:获取文件信息,头文件:#include <sys/stat.h> #include <unistd.h>函数原型:int stat(const char *file_name, struct stat *buf);

    函数说明: 通过文件名filename获取文件信息,并保存在buf所指的结构体stat中

    返回值: 执行成功则返回0,失败返回-1,错误代码存于errno,结构体stat:

struct stat {
dev_t st_dev; //文件的设备编号
ino_t st_ino; //节点
mode_t st_mode; //文件的类型和存取的权限
nlink_t st_nlink; //连到该文件的硬连接数目,刚建立的文件值为1
uid_t st_uid; //用户ID
gid_t st_gid; //组ID
dev_t st_rdev; //(设备类型)若此文件为设备文件,则为其设备编号
off_t st_size; //文件字节数(文件大小)
unsigned long st_blksize; //块大小(文件系统的I/O 缓冲区大小)
unsigned long st_blocks; //块数
time_t st_atime; //最后一次访问时间
time_t st_mtime; //最后一次修改时间
time_t st_ctime; //最后一次改变时间(指属性)
};

此处我们需要的是其结构体中的ino_t,来获取文件的节点。

  • 在此过程中,我们还需要改变当前工作的目录,通过man来查找,发现chdir()函数符合要求:函数功能:改变当前工作目录,

    头文件:#include<unistd.h>,

    函数定义:int chdir(const char *path),

    函数说明:将当前的工作目录改变成以参数path所指的目录。

    返回值:执行成功则返回0,失败返回-1,errno为错误代码。

  • readdir伪代码:


while(1)
{
通过文件名“.”获取当前目录的i节点;
通过文件名“..”获取当前目录的父级目录的i节点;
判断当前目录和上级目录的inode-number是否一样;
if(两个节点一样,则说明到达根目录 )
跳出循环;
else
切换至父级目录,获取inode-number,在父级目录中搜索对应的文件名并记录下来;
搜索文件名并存入文件名到数组中;
}
输出文件名;

实现mypwd

  • 通过getcwd实现:

#include "stdio.h"
#include "unistd.h"
int main(void)
{
char buf[256];
getcwd(buf,sizeof(buf));
printf("当前路径为:%s\n",buf);
return 0;
}
  • 通过readdir实现:
#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)) {
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("."))) {
fprintf(stderr, "Can not open Current Directory\n");
exit(-1);
} else {
while (NULL != (dptr = readdir(dp))) {
if (dptr->d_ino == ino) {
filename = strdup(dptr->d_name);
break;
}
}
closedir(dp);
}
return filename;
} #define MAX_DIR_DEPTH (256) int main(int argc, char *argv[])
{ char *dir_stack[MAX_DIR_DEPTH];
unsigned current_depth = 0; while(1){
/*1.通过特殊的文件名“.”获取当前目录的inode-number*/
ino_t c_ino = get_ino_byname(".");
/*2.通过特殊的文件名“..”获取当前目录的父级目录的inode-number*/
ino_t p_ino = get_ino_byname(".."); /*3.判断当前目录和上级目录的inode-number是否一样*/
if (c_ino == p_ino)
break; /*4.如果两个inode-number一样说明到达根目录*/ /*5.如果两个inode-number不一样*/ /*切换至父级目录,根据步骤1获取的inode-number,在父级目录中搜索对应的文件名并记录下来, 重新回到步骤1*/
chdir("..");
dir_stack[current_depth++] = find_name_byino(c_ino);
if (current_depth>=MAX_DIR_DEPTH) { /*路径名太深*/
fprintf(stderr, "Directory tree is too deep.\n");
exit(-1);
}
} /*输出完整路径名*/
//int i = current_depth-1;
int i;
for (i = current_depth-1; i>=0; i--) {
fprintf(stdout, "/%s", dir_stack[i]);
}
fprintf(stdout, "%s\n", current_depth==0?"/":""); return 0;
}

测试mypwd

  • getced实现:

  • readdir实现:

最新文章

  1. 数据库(Database)
  2. 如何用最简单的方法将PCweb改成适合各种设备的web
  3. Win环境下的文件读写
  4. git不是内部命令和可执行程序解决方法
  5. 2016年7月1日 星期五 --出埃及记 Exodus 14:28
  6. 故事板(Storyboard) 、 iPad编程 、 App和VC的生命周期
  7. [cmd]linux 常用命令
  8. Reveal 破解
  9. Linux上安装使用boost入门指导
  10. xml复习
  11. CI源码引用使用--php引用demo,静态变量和引用关系
  12. Codeforces Round #363 (Div. 2) 698B Fix a Tree
  13. iBatis 的条件查询
  14. mysql 修复表和优化表
  15. resumable.js —— 基于 HTML 5 File API 的文件上传组件 支持续传后台c#实现
  16. java中this关键字解析
  17. 【Unity Shaders】Using Textures for Effects——打包和混合textures
  18. mysql 查看当前使用的配置文件my.cnf的方法
  19. zabbix 自动发现端口并添加监控设置
  20. 回顾HashMap

热门文章

  1. 1001.A+B Format (20)解题描述
  2. python时间模块和random模块
  3. Linux学习总结(十八)几个简单的文本处理工具cut sort tr split
  4. [Java123] Java中的System.exit
  5. 关于ie8下监听input事件的不兼容问题。
  6. 跳转到AppStore下载app
  7. Boost noncopyable实现禁止拷贝的类
  8. myeclipse安装SVN插件方法
  9. mina 通讯框架
  10. 【Linux】Linux中VIM编辑器的使用