问题引入
判断某个目录字符串是否是根目录,咋一听很简单,只要判断字符串是否是"/"即可,但是,很多情况下使用的路径是相对路径,那么如何判断相对路径是根目录呢?
思路分析
熟悉Linux的同学应该知道,每个目录下都有.和..两个目录,分别指代当前目录和父目录,考虑从这个点下手,根目录的当前目录和父目录指向相同,也就是说这两个文件的描述符是一样的。
大体思路有了之后,来看下Linux中常用的目录操作的函数:
1 DIR *opendir(const char *)2 struct dirent *readdir(DIR *)3 int closedir(DIR *)
它们位于dirent.h头文件中。
再来看一下dirent的结构
struct dirent { ino_t d_ino; /* file number of entry */ __uint16_t d_reclen; /* length of this record */ __uint8_t d_type; /* file type, see below */ __uint8_t d_namlen; /* length of string in d_name */ char d_name[__DARWIN_MAXNAMLEN + 1]; /* name must be no longer than this */ };
解决方案
开始动手编码,如下:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <dirent.h> bool isRoot(const char* path) { if (strcmp(path, "/") == 0) return true; char dp[256] = {0}; int l = strlen(path); memcpy(dp, path, l); if (dp[l - 1] != '/') { dp[l] = '/'; l += 1; } DIR* d = opendir(dp); if (!d) { printf("failed to open dir\n"); return false; } uint64_t dino = 0, ddino = 0; while (dirent* ent = readdir(d)) { if (strcmp(ent->d_name, "..") == 0) { ddino = ent->d_ino; } if (strcmp(ent->d_name, ".") == 0) { dino = ent->d_ino; } if (dino > 0 && ddino > 0) break; } return dino == ddino && dino != 0; } int main(int argc, char* argv[]) { if (argc != 2) { printf("usage : app path\n"); return 0; } if (isRoot(argv[1])) printf("this path is root\n"); else printf("this path is not root\n"); return 0; }
编译
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 *)
修改代码后如下:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <dirent.h> #include <sys/stat.h> bool isRoot(const char* path) { if (strcmp(path, "/") == 0) return true; char dp[256] = {0}; int l = strlen(path); memcpy(dp, path, l); if (dp[l - 1] != '/') { dp[l] = '/'; l += 1; } DIR* d = opendir(dp); if (!d) { printf("failed to open dir\n"); return false; } uint64_t dino = 0, ddino = 0; while (dirent* ent = readdir(d)) { if (strcmp(ent->d_name, "..") == 0) { char pp[256] = {0}; memcpy(pp, dp, l); pp[l] = '.'; pp[l + 1] = '.'; struct stat s; stat(pp, &s); //printf("ddot %s %lld\n", ent->d_name, s.st_ino); ddino = s.st_ino; } if (strcmp(ent->d_name, ".") == 0) { char sp[256] = {0}; memcpy(sp, dp, l); sp[l] = '.'; struct stat s; stat(sp, &s); //printf("dot %s %lld\n", ent->d_name, s.st_ino); dino = s.st_ino; } if (dino > 0 && ddino > 0) break; } return dino == ddino && dino != 0; } int main(int argc, char* argv[]) { if (argc != 2) { printf("usage : app path\n"); return 0; } if (isRoot(argv[1])) printf("this path is root\n"); else printf("this path is not root\n"); return 0; }
再次编译验证,发现这次的结果是正确的。经过查证后发现,在使用readdir时取得的dirent中的iNode不一定是正确的,还需要从stat中取。其实在isRoot中没有必要使用dir相关的操作,只需要组织出输入路径的当前路径和父目录,再使用stat判断即可。
总结
到此就完成了目录是否为根目录的判断,需要对Linux的API慢慢进行熟悉。
发表评论 取消回复