问题引入

判断某个目录字符串是否是根目录,咋一听很简单,只要判断字符串是否是"/"即可,但是,很多情况下使用的路径是相对路径,那么如何判断相对路径是根目录呢?

思路分析

熟悉Linux的同学应该知道,每个目录下都有.和..两个目录,分别指代当前目录和父目录,考虑从这个点下手,根目录的当前目录和父目录指向相同,也就是说这两个文件的描述符是一样的。

大体思路有了之后,来看下Linux中常用的目录操作的函数:

1 DIR *opendir(const char *)
2 struct dirent *readdir(DIR *)
3 int closedir(DIR *)

它们位于dirent.h头文件中。

再来看一下dirent的结构

1 struct dirent {
2 ino_t d_ino; /* file number of entry */
3 __uint16_t d_reclen; /* length of this record */
4 __uint8_t d_type; /* file type, see below */
5 __uint8_t d_namlen; /* length of string in d_name */
6 char d_name[__DARWIN_MAXNAMLEN + 1]; /* name must be no longer than this */
7 };

解决方案

开始动手编码,如下:

 1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <dirent.h>
5
6 bool isRoot(const char* path)
7 {
8 if (strcmp(path, "/") == 0)
9 return true;
10
11 char dp[256] = {0};
12 int l = strlen(path);
13 memcpy(dp, path, l);
14
15 if (dp[l - 1] != '/')
16 {
17 dp[l] = '/';
18 l += 1;
19 }
20
21 DIR* d = opendir(dp);
22 if (!d)
23 {
24 printf("failed to open dir\n");
25 return false;
26 }
27
28 uint64_t dino = 0, ddino = 0;
29 while (dirent* ent = readdir(d))
30 {
31 if (strcmp(ent->d_name, "..") == 0)
32 {
33 ddino = ent->d_ino;
34 }
35 if (strcmp(ent->d_name, ".") == 0)
36 {
37 dino = ent->d_ino;
38 }
39
40 if (dino > 0 && ddino > 0)
41 break;
42 }
43 return dino == ddino && dino != 0;
44 }
45
46 int main(int argc, char* argv[])
47 {
48 if (argc != 2)
49 {
50 printf("usage : app path\n");
51 return 0;
52 }
53
54 if (isRoot(argv[1]))
55 printf("this path is root\n");
56 else
57 printf("this path is not root\n");
58 return 0;
59 }

编译

g++ -o root root.cpp

下面来验证一下

# ./root /
this path is root # ./root ./
this path is not root # ./root ./../
this path is not root # ./root ./../../
this path is not root # ./root ./../../../
this path is not root # ./root ./../../../.. #注意,我的机器上这里其实已经是根目录了
this path is not root

奇怪的问题发生了,本应该通过的内容竟然不是根目录。进入代码,打印一下isRoot函数中.和..目录的name和ino。

. 2
.. 1

难道是假设错误?如果想要取得inode可以通过stat函数,那么我们该用stat函数试一下

int stat(const char *, struct stat *) 

修改代码后如下:

 1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <dirent.h>
5 #include <sys/stat.h>
6
7 bool isRoot(const char* path)
8 {
9 if (strcmp(path, "/") == 0)
10 return true;
11
12 char dp[256] = {0};
13 int l = strlen(path);
14 memcpy(dp, path, l);
15
16 if (dp[l - 1] != '/')
17 {
18 dp[l] = '/';
19 l += 1;
20 }
21
22 DIR* d = opendir(dp);
23 if (!d)
24 {
25 printf("failed to open dir\n");
26 return false;
27 }
28 uint64_t dino = 0, ddino = 0;
29 while (dirent* ent = readdir(d))
30 {
31 if (strcmp(ent->d_name, "..") == 0)
32 {
33 char pp[256] = {0};
34 memcpy(pp, dp, l);
35 pp[l] = '.';
36 pp[l + 1] = '.';
37 struct stat s;
38 stat(pp, &s);
39 //printf("ddot %s %lld\n", ent->d_name, s.st_ino);
40 ddino = s.st_ino;
41 }
42 if (strcmp(ent->d_name, ".") == 0)
43 {
44 char sp[256] = {0};
45 memcpy(sp, dp, l);
46 sp[l] = '.';
47 struct stat s;
48 stat(sp, &s);
49 //printf("dot %s %lld\n", ent->d_name, s.st_ino);
50 dino = s.st_ino;
51 }
52
53 if (dino > 0 && ddino > 0)
54 break;
55 }
56 return dino == ddino && dino != 0;
57 }
58
59 int main(int argc, char* argv[])
60 {
61 if (argc != 2)
62 {
63 printf("usage : app path\n");
64 return 0;
65 }
66
67 if (isRoot(argv[1]))
68 printf("this path is root\n");
69 else
70 printf("this path is not root\n");
71 return 0;
72 }
73

再次编译验证,发现这次的结果是正确的。经过查证后发现,在使用readdir时取得的dirent中的iNode不一定是正确的,还需要从stat中取。

总结

到此就完成了目录是否为根目录的判断,需要对Linux的API慢慢进行熟悉。

Linux程序开发中如何判断目录是否为根目录?的更多相关文章

  1. IOS开发中如何判断程序第一次启动(根据判断结果决定是否显示新手操作引导)

    IOS开发中如何判断程序第一次启动 在软件下载安装完成后,第一次启动往往需要显示一个新手操作引导,来告诉用户怎么操作这个app,这就需要在程序一开始运行就判断程序是否第一次启动,如果是,则显示新手操作 ...

  2. 在C#/.NET应用程序开发中创建一个基于Topshelf的应用程序守护进程(服务)

    本文首发于:码友网--一个专注.NET/.NET Core开发的编程爱好者社区. 文章目录 C#/.NET基于Topshelf创建Windows服务的系列文章目录: C#/.NET基于Topshelf ...

  3. 微信小程序开发教程 #043 - 在小程序开发中使用 npm

    本文介绍了如何在微信小程序开发中使用 npm 中包的功能,大大提高微信小程序的开发效率,同时也是微信小程序系列教程的视频版更新. 微信小程序在发布之初没有对 npm 的支持功能,这也是目前很多前端开发 ...

  4. 总结微信小程序开发中遇到的坑

    总结微信小程序开发中遇到的坑,一些坑你得一个一个的跳啊,/(ㄒoㄒ)/~~ 1,页面跳转和参数传递实例 首先说一下我遇到的需求有一个我的消息页面,里面的数据都是后端返回的,返回的数据大致如下,有一个是 ...

  5. IOS程序开发中-跳转到 发送短信界面 实现发短信

    前言:我发现我标题取的不好,谁帮我取个承接上下文的标题?评论一下,我改 项目需求:在程序开发中,我们需要在某个程序里面发送一些短信验证(不是接收短信验证,关于短信验证,传送门:http://www.c ...

  6. AOP称为面向切面编程,在程序开发中主要用来解决一些系统层面上的问题

    AOP称为面向切面编程,在程序开发中主要用来解决一些系统层面上的问题,比如日志,事务,权限等待,Struts2的拦截器设计就是基于AOP的思想,是个比较经典的例子. 一 AOP的基本概念 (1)Asp ...

  7. Delphi 10.2 Linux 程序开发环境部署的基本步骤(网络连接方式要选择桥接或者是Host Only)

    Delphi 10.2 Linux 程序开发环境部署的基本步骤 http://blog.qdac.cc/?p=4477 升級到 Delphi 10.2 Tokyo 笔记http://www.cnblo ...

  8. 解决微信小程序开发中wxss中不能用本地图片

    微信小程序开发中wxss中不能用本地图片,我们可以用将我们的图片传到服务器上,然后直接引用在线地址.但是当我们没有服务器时,我们可以用"图床",这个具体可以百度.这里我们用第二种方 ...

  9. 程序开发中的术语,如IDE,OOP等等

    我们在开发程序过程中,会用到一些与编译有关的术语,比如:[编辑器.编译器.调试器.连接器,链接器.解释器,集成开发环境(Integrated Development Environment,IDE). ...

随机推荐

  1. 【UR #2】猪猪侠再战括号序列

    UOJ小清新题表 题目摘要 UOJ链接 有一个由 \(n\) 个左括号 "(" 和 \(n\) 个右括号 ")" 组成的序列.每次操作时可以选定两个数 \(l, ...

  2. hdu6376 度度熊剪纸条-----01背包

    题目:度度熊有一张纸条和一把剪刀.   纸条上依次写着 N 个数字,数字只可能是 0 或者 1.     度度熊想在纸条上剪 K 刀(每一刀只能剪在数字和数字之间),这样就形成了 K+1 段.   他 ...

  3. centos7 shell 安装docker redis mongodb 等

    脚本下载: 百度网盘 提取码: wc4r 下载后上传到 服务器 chmod +x docker.sh sh docker.sh

  4. centos8平台redis cluster集群添加/删除node节点(redis5.0.7)

    一,当前redis cluster的node情况: 我们的添加删除等操作都是以这个cluster作为demo cluster采用六台redis,3主3从 redis1 : ip: 172.17.0.2 ...

  5. 圆形进度条的模仿1-DrawArc,DrawCircle,DrawText讲解

    1:画弧 canvas.drawArc(oval,startAngle,sweepAngle,useCenter,paint) 第一个参数:绘制的区域,oval可以是被定好了的一个区域,也可以将ova ...

  6. 【应用服务 App Service】App Service中抓取网络日志

    问题描述 众所周知,Azure App Service是一种PaaS服务,也就是说,IaaS层面的所有内容都由平台维护,所以使用App Service的我们根本无法触碰到远行程序的虚拟机(VM), 所 ...

  7. 【Azure Redis 缓存 Azure Cache For Redis】在创建高级层Redis(P1)集成虚拟网络(VNET)后,如何测试VNET中资源如何成功访问及配置白名单的效果

    当使用Azure Redis高级版时候,为了能更好的保护Redis的安全,启用了虚拟网路,把Redis集成在Azure中的虚拟网络,只能通过虚拟网络VENT中的资源进行访问,而公网是不可以访问的.但是 ...

  8. 第12天 | 12天搞定Python,让excel飞起来

    学了10多天Python基础知识了,是时候来点硬货了,看过<第1天 | 12天搞定Python,告诉你有什么用?>的老铁都知道,Python可用的领域挺多的.只是我长期待在企业,所以只能说 ...

  9. The path "" is not a valid path to the 3.10.0-957.el7.x86_64 kernel headers.

    安装 kernel-devel yum install kernel-devel-$(uname -r)

  10. jumpserver部署使用

    一.简介 前面我们聊到了openvpn的部署和使用,它能够实现从互联网通过openvpn连接到公司内网服务器,从而进行远程管理:但openvpn有一个缺点它不能记录哪些用户在内网服务器上操作了什么,拥 ...