问题引入
判断某个目录字符串是否是根目录,咋一听很简单,只要判断字符串是否是\”/\”即可,但是,很多情况下使用的路径是相对路径,那么如何判断相对路径是根目录呢?
思路分析
熟悉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>56 bool isRoot(const char* path)7 {8 if (strcmp(path, \"/\") == 0)9 return true;1011 char dp[256] = {0};12 int l = strlen(path);13 memcpy(dp, path, l);1415 if (dp[l - 1] != \'/\')16 {17 dp[l] = \'/\';18 l += 1;19 }2021 DIR* d = opendir(dp);22 if (!d)23 {24 printf(\"failed to open dir\\n\");25 return false;26 }2728 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 }3940 if (dino > 0 && ddino > 0)41 break;42 }43 return dino == ddino && dino != 0;44 }4546 int main(int argc, char* argv[])47 {48 if (argc != 2)49 {50 printf(\"usage : app path\\n\");51 return 0;52 }5354 if (isRoot(argv[1]))55 printf(\"this path is root\\n\");56 else57 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>67 bool isRoot(const char* path)8 {9 if (strcmp(path, \"/\") == 0)10 return true;1112 char dp[256] = {0};13 int l = strlen(path);14 memcpy(dp, path, l);1516 if (dp[l - 1] != \'/\')17 {18 dp[l] = \'/\';19 l += 1;20 }2122 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 }5253 if (dino > 0 && ddino > 0)54 break;55 }56 return dino == ddino && dino != 0;57 }5859 int main(int argc, char* argv[])60 {61 if (argc != 2)62 {63 printf(\"usage : app path\\n\");64 return 0;65 }6667 if (isRoot(argv[1]))68 printf(\"this path is root\\n\");69 else70 printf(\"this path is not root\\n\");71 return 0;72 }73
再次编译验证,发现这次的结果是正确的。经过查证后发现,在使用readdir时取得的dirent中的iNode不一定是正确的,还需要从stat中取。
总结
到此就完成了目录是否为根目录的判断,需要对Linux的API慢慢进行熟悉。