文件和目录之读目录

对某个目录具有访问权限的任一用户都可读该目录,但是,为了防止文件系统产生混乱,只有内核才能写目录。一个目录的写权限位和执行权限位决定了在该目录中能否创建新文件以及删除文件,它们并不表示能否写目录本身。

#include <dirent.h>

DIR *opendir( const char *pathname );
返回值:若成功则返回指针,若出错则返回NULL

struct dirent *readdir( DIR *dp );
返回值:若成功则返回指针,若在目录结尾或出错则返回NULL

void rewinddir( DIR *dp );
int closedir( DIR *dp );
返回值:若成功则返回0,若出错则返回-1

long telldir( DIR *dp );
返回值:与dp关联的目录中的当前位置

void seekdir( DIR *dp, long loc );

 

头文件<dirent.h>中定义的dirent结构与实现有关。几种典型的UNIX实现对此结构所作的定义至少包含下列两个成员:

struct dirent {
    ino_t     d_ino;                  /* i-node number */
    char     d_name[NAME_MAX + 1];    /*null-terminated filename */
}

DIR结构是一个内部结构,上述6个函数用这个内部结构保存当前正被读的目录的有关信息。其作用类似与FILE结构。FILE结构由标准I/O库维护。

由opendir返回的指向DIR结构的指针由另外5个函数使用。opendir执行初始化操作,使第一个readdir读目录中的第一个目录项。目录中各目录项的顺序与实现有关。它们通常并不按字母顺序排序。

程序清单4-7 递归降序遍历目录层次结构,并按文件类型计数

[root@localhost apue]# cat -b prog4-7.c
     1  #include "apue.h"
     2  #include <dirent.h>
     3  #include <limits.h>
     4  #include <errno.h>

     5  #ifdef PATH_MAX
     6  static int pathmax = PATH_MAX;
     7  #else
     8  static int pathmax = 0;
     9  #endif

    10  #define SUSV3 200112L

    11  static long posix_version = 0;

    12  /* If PATH_MAX is indeterminate, no guarantee  this is adequate */
    13  #define PATH_MAX_GUESS 1024

    14  char *
    15  path_alloc(int *sizep) /* also return allocated size, if nonull */
    16  {
    17          char *ptr;
    18          int size;

    19          if(posix_version == 0)
    20                  posix_version = sysconf(_SC_VERSION);
    21
    22          if(pathmax == 0) {   /* first time trough */
    23                  errno = 0;
    24                  if((pathmax = pathconf("/", _PC_PATH_MAX)) < 0) {
    25                          if(errno == 0)
    26                                  pathmax = PATH_MAX_GUESS;  /* it's indeterminate */
    27                          else
    28                                  err_sys("pathconf error for _PC_PATH_MAX");
    29                  } else {
    30                          pathmax++;    /* add one since it's relative to root */
    31                  }
    32          }
    33          if(posix_version < SUSV3)
    34                  size = pathmax + 1;
    35          else
    36                  size = pathmax;
    37
    38          if((ptr = malloc(size)) == NULL)
    39                  err_sys("malloc error for pathname");

    40          if(sizep != NULL)
    41                  *sizep = size;
    42          return(ptr);
    43  }

    44  /* function type that is called for each filename */
    45  typedef int Myfunc( const char *, const struct stat *, int );

    46  static Myfunc   myfunc;
    47  static int      myftw( char *, Myfunc * );
    48  static int      dopath( Myfunc * );

    49  static long nreg, ndir, nblk, nchr, nfifo, nslink, nsock, ntot;

    50  int
    51  main( int argc, char *argv[] )
    52  {
    53          int ret;
    54
    55          if( argc != 2 )
    56                  err_quit( "usage: ftw <starting-pathname>" );
    57
    58          ret = myftw( argv[1], myfunc );         /* does it all */

    59          ntot = nreg + ndir + nblk + nchr + nfifo + nslink + nsock;
    60          if( ntot == 0 )
    61                  ntot = 1;       /* avoid divide by 0; print 0 for all counts */
    62          printf( "regular files  = %7ld, %5.2f %%\n", nreg, nreg*100.0/ntot );
    63          printf( "directories    = %7ld, %5.2f %%\n", ndir, ndir*100.0/ntot );
    64          printf( "block special  = %7ld, %5.2f %%\n", nblk, nblk*100.0/ntot );
    65          printf( "char special   = %7ld, %5.2f %%\n", nchr, nchr*100.0/ntot );
    66          printf( "FIFOs          = %7ld, %5.2f %%\n", nfifo, nfifo*100.0/ntot );
    67          printf( "symbolic links = %7ld, %5.2f %%\n", nslink, nslink*100.0/ntot );
    68          printf( "sockets                = %7ld, %5.2f %%\n", nsock, nsock*100.0/ntot );

    69          exit( ret );
    70  }

    71  /*
    72  * Descend throuth the hierarchy, starting at "pathname".
    73  * The caller's func() is called for every file.
    74  */
    75  #define FTW_F   1       /* file other than directory */
    76  #define FTW_D   2       /* directory */
    77  #define FTW_DNR 3       /* directory that can't be read */
    78  #define FTW_NS  4       /* file that we can't stat */

    79  static char * fullpath; /*contains full pathname for every file */

    80  static int
    81  myftw( char *pathname, Myfunc *func )
    82  {
    83          int len;
    84          fullpath = path_alloc( &len );  /* malloc's for PATH_MAX + 1 bytes */
    85                                          /* program_list 2-3 */
    86          strncpy( fullpath, pathname, len );     /* protect against */
    87          fullpath[len - 1] = 0;

    88          return(dopath(func));
    89  }

    90  /*
    91  * Descend through the hierarchy, starting at "fullpath".
    92  * If "fullpath" is anything other than a directory, we lstat() it,
    93  * call func(), and return. For a directory, we call ourself 
    94  * recursively for each name in the directory.
    95  */
    96  static int
    97  dopath( Myfunc *func )
    98  {
    99          struct stat     statbuf;
   100          struct dirent   *dirp;
   101          DIR             *dp;
   102          int             ret;
   103          char            *ptr;

   104          if( lstat( fullpath, &statbuf ) < 0 )   /* stat error */
   105                  return( func(fullpath, &statbuf, FTW_NS) );
   106          if( S_ISDIR(statbuf.st_mode) == 0)      /* not a directory */
   107                  return( func(fullpath, &statbuf, FTW_F) );

   108          /*
   109          * It's a directory. First call func() for the directory,
   110          * then process each filename in the directory.
   111          */
   112          if((ret = func(fullpath, &statbuf, FTW_D)) != 0)
   113                  return(ret);

   114          ptr = fullpath + strlen(fullpath);      /* point to end of fullpath */
   115          *ptr++ = '/';
   116          *ptr = 0;

   117          if((dp = opendir(fullpath)) == NULL)    /* can't read directory */
   118                  return(func(fullpath, &statbuf, FTW_DNR));

   119          while((dirp = readdir(dp)) != NULL)
   120          {
   121                  if(strcmp(dirp->d_name, ".") == 0 ||
   122                     strcmp(dirp->d_name, "..") == 0)
   123                          continue;       /* ignore dot and dot-dot */
   124
   125                  strcpy(ptr, dirp->d_name);      /*append name after slash */

   126          //      if((ret = dopath(func)) != 0)   /* recursive */
   127          //              break;                  /* time to leave */
   128                  dopath(func);
   129          }
   130          ptr[-1] = 0;    /* erase everything from slash onwards */
   131          if(closedir(dp) < 0)
   132                  err_ret("can't close directory %s", fullpath);
   133          return(ret);
   134  }

   135  static int
   136  myfunc(const char *pathname, const struct stat *statptr, int type)
   137  {
   138          switch(type)
   139          {
   140                  case FTW_F:
   141                          switch(statptr->st_mode & S_IFMT)
   142                          {
   143                                  case S_IFREG:   nreg++;         break;
   144                                  case S_IFBLK:   nblk++;         break;
   145                                  case S_IFCHR:   nchr++;         break;
   146                                  case S_IFIFO:   nfifo++;        break;
   147                                  case S_IFLNK:   nslink++;       break;
   148                                  case S_IFSOCK:  nsock++;        break;
   149                                  case S_IFDIR:
   150                                          err_dump("for S_IFDIR for %s", pathname);
   151                                          /* directories should have type = FTW_D */
   152                          }
   153                          break;
   154                  case FTW_D:
   155                          ndir++;
   156                          break;
   157                  case FTW_DNR:
   158                          err_ret("can't read directory %s", pathname);
   159                          break;
   160                  case FTW_NS:
   161                          err_ret("stat error for %s", pathname);
   162                          break;
   163                  default:
   164                          err_dump("unknown type %d for pathname %s", type, pathname);
   165          }
   166          return( 0 );
   167  }

程序运行结果:

[root@localhost apue]# ./prog4-7 /home/zhu/test
regular files   =       3, 60.00 %
directories     =       2, 40.00 %
block special   =       0,  0.00 %
char special    =       0,  0.00 %
FIFOs           =       0,  0.00 %
symbolic links  =       0,  0.00 %
sockets         =       0,  0.00 %

上面的源程序代码中有一个不理解的地方,第126-127行(这是APUE书中原来的代码)。希望路过的有缘人可以指点一二,小弟不胜感激。将这两行替换为128行,这样能够理解,而且程序正确执行。

本篇博文内容摘自《UNIX环境高级编程》(第二版),仅作个人学习记录所用。关于本书可参考:http://www.apuebook.com/

posted @ 2014-01-04 15:18  ITtecman  阅读(364)  评论(0编辑  收藏  举报