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