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实现:

2017-2018-1 20155339 第十一周加分项Linux下Mypwd的实现的更多相关文章

  1. 2017-2018-1 20155338 《信息安全系统设计基础》第5周加分项Mybash的实现

    2017-2018-1 20155338 <信息安全系统设计基础>第5周加分项Mybash的实现 使用fork,exec,wait实现mybash 一.fork函数 定义和理解:fork( ...

  2. 20155322 2017-2018-1《信息安全系统设计》第二周 课堂测试 Linux下C语言实现MYOD

    20155322 2017-2018-1<信息安全系统设计>第二周 课堂测试 Linux下C语言实现MYOD [博客目录] 静态库测试 实现方法 相关资料 操作 动态库测试 实现方法 相关 ...

  3. 2017-2018-1 20155215 第九周 加分项 PWD命令的实现

    1 学习pwd命令 Linux中用 pwd 命令来查看"当前工作目录"的完整路径. 简单得说,每当你在终端进行操作时,你都会有一个当前工作目录. 在不太确定当前位置时,就会使用pw ...

  4. “2017面向对象程序设计(Java)第十一周学习总结”存在问题的反馈及教学安排

    “2017面向对象程序设计(Java)第十一周学习总结”存在问题的反馈及教学安排1.“提出表扬的同学:姜依萍,王雪玲,徐楠,相文君,赵晓未提交作业的同学:任红强,王瑞强,宗鹏新,扎西才让,布旦刀杰,范 ...

  5. 2017面向对象程序设计(Java)第十一周学习总结

    首先,由于前几周同学们普遍反映知识点比较难,并且累积较多,难以掌握,所以老师在上周对教学方案进行了如下调整: (1)周四下午理论课第一学时,将结合实验八与实验九的编程题,通过范例演示同学们存在问题的解 ...

  6. 201521123061 《Java程序设计》第十一周学习总结

    201521123061 <Java程序设计>第十一周学习总结 1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结多线程相关内容. 本周学习的是如何解决多线程访问中的互斥 ...

  7. 201521123038 《Java程序设计》 第十一周学习总结

    201521123038 <Java程序设计> 第十一周学习总结 1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结多线程相关内容. 2. 书面作业 本次PTA作业题集多 ...

  8. 2017-2018-2 1723《程序设计与数据结构》第十一周作业 & 实验三 & (总体)第三周结对编程 总结

    作业地址 第十一次作业:https://edu.cnblogs.com/campus/besti/CS-IMIS-1723/homework/1933 (作业界面已评分,可随时查看,如果对自己的评分有 ...

  9. C语言程序设计I—第十一周教学

    第十一周教学总结(12/11-17/11) 教学内容 第4章 循环结构-break continue嵌套循环 4.3 判断素数,4.4求1! + 2! + -. + 100! 课前准备 在蓝墨云班课发 ...

随机推荐

  1. python正则二

    在python中,我们可以使用re模块来使用正则表达式. 正则表达式使用\对特殊字符进行转义,因为python本身也是用\作为转义,所以在使用正则的时候会出现这样的情况,'python\\.org', ...

  2. JavaScript学习记录总结(八)——全选、反选

    <!DOCTYPE html><html><head><title>checkboxs.html</title> <meta name ...

  3. InputStream TO byte

    public class ByteToInputStream { public static final InputStream byte2Input(byte[] buf) { return new ...

  4. BZOJ1042:[HAOI2008]硬币购物(DP,容斥)

    Description 硬币购物一共有4种硬币.面值分别为c1,c2,c3,c4.某人去商店买东西,去了tot次.每次带di枚ci硬币,买si的价值的东西.请问每次有多少种付款方法. Input 第一 ...

  5. 【bootstrap】.container与.container_fluid

    .container与.container_fluid是bootstrap中的两种不同类型的外层容器,区别是: .container 类用于固定宽度并支持响应式布局的容器.不用你自己设宽度,通过< ...

  6. 搞懂JVM类加载机制

    有这样一道面试题: class Singleton{ private static Singleton singleton = new Singleton(); public static int v ...

  7. .NET Core中基类可以反射子类的成员

    我们定义一个类DemoA,再定义一个类DemoB继承DemoA.当构造一个DemoB类对象后,我们可以通过其调用基类DemoA中的方法来反射子类DemoB的成员. 新建一个.NET Core控制台项目 ...

  8. nodejs运行的时候报错:Error: write EIO以及乱码解决方式

    在运行node.js的过程中报如下错误: events.js:72 throw er; // Unhandled 'error' event ^ Error: write EIO at errnoEx ...

  9. 使用XWAF框架(5)——XML解析器:CXDP

    XWAF推出了自己的组合式XML文档解析器,英文名叫:“CXDP”,是“Combined XML Document Parser”的缩写.核心代码属XWAF原创,注释.日志和帮助文档采用全中文描述,特 ...

  10. Java上机试题1

    1. 有一串字符串String s = "ababab", 这个字符串可以看做由3个"ab"构成,即n=3, L = "ab", s = n ...