您的位置:首页 > 运维架构 > Linux

Linux程序开发中如何判断目录是否为根目录?

rengzhixin 2020-11-19 04:08 274 查看 https://www.cnblogs.com/nuofor

问题引入

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

思路分析

熟悉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慢慢进行熟悉。

标签: