zoukankan      html  css  js  c++  java
  • Linux程序开发中如何判断目录是否为根目录?

    问题引入

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

    思路分析

    熟悉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
    ");
    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
    ");
    51         return 0;
    52     }
    53 
    54     if (isRoot(argv[1]))
    55         printf("this path is root
    ");
    56     else
    57         printf("this path is not root
    ");
    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
    ");
    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
    ", 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
    ", 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
    ");
    64         return 0;
    65     }
    66 
    67     if (isRoot(argv[1]))
    68         printf("this path is root
    ");
    69     else
    70         printf("this path is not root
    ");
    71     return 0;
    72 }
    73                                  

    再次编译验证,发现这次的结果是正确的。经过查证后发现,在使用readdir时取得的dirent中的iNode不一定是正确的,还需要从stat中取。其实在isRoot中没有必要使用dir相关的操作,只需要组织出输入路径的当前路径和父目录,再使用stat判断即可。

    完整的isRoot代码如下:

     1 bool isRoot(const char* path)
     2 {
     3     if (strcmp(path, "/") == 0)
     4         return true;
     5 
     6     char pp[256] = {0};
     7 
     8     int l = strlen(pp);
     9     strcpy(pp, path);
    10 
    11     if (pp[l - 1] != '/')
    12     {
    13         pp[l] = '/';
    14         l += 1;
    15     }
    16 
    17     strcat(pp, "..");
    18 
    19     struct stat ps;
    20     stat(pp, &ps);
    21 
    22     struct stat cs;
    23     stat(path, &cs);
    24 
    25     return ps.st_ino   ==  cs.st_ino &&
    26            ps.st_nlink ==  cs.st_nlink &&
    27            ps.st_mtime ==  cs.st_mtime;
    28 }

    总结

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

  • 相关阅读:
    MySQL语法
    Linux常用命令大全
    触发器使用UTL_SMTP包发送邮件
    MySQL——触发器的创建和使用总结
    MySQL数据库备份
    Nginx配置文件(nginx.conf)配置详解
    JS弹出框,打开文件,保存文件,另存为。。。。
    java excel两种操作方式
    Zookeeper的优缺点
    activemq linux安装
  • 原文地址:https://www.cnblogs.com/nuoforever/p/14002659.html
Copyright © 2011-2022 走看看