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

  • 相关阅读:
    1.4.2.3. SETUP(Core Data 应用程序实践指南)
    1.4.2.2. PATHS(Core Data 应用程序实践指南)
    1.4.2.1. FILES(Core Data 应用程序实践指南)
    1.4.2. 实现 Core Data Helper 类(Core Data 应用程序实践指南)
    1.4.1. Core Data Helper 简介(Core Data 应用程序实践指南)
    1.4. 为现有的应用程序添加 Core Data 支持(Core Data 应用程序实践指南)
    1.3.2. App Icon 和 Launch Image(Core Data 应用程序实践指南)
    1.3.1. 新建Xcode项目并设置故事板(Core Data 应用程序实践指南)
    php验证邮箱是否合法
    如何使js函数异步执行
  • 原文地址:https://www.cnblogs.com/nuoforever/p/14002659.html
Copyright © 2011-2022 走看看