ftw4.c (4023B)
1 #include <sys/types.h> 2 #include <sys/stat.h> 3 #include <dirent.h> 4 #include <limits.h> 5 #include "ourhdr.h" 6 7 typedef int Myfunc(const char *, const struct stat *, int); 8 /* function type that's called for each filename */ 9 10 static Myfunc myfunc; 11 static int myftw(char *, Myfunc *); 12 static int dopath(Myfunc *); 13 14 static long nreg, ndir, nblk, nchr, nfifo, nslink, nsock, ntot; 15 16 int 17 main(int argc, char *argv[]) 18 { 19 int ret; 20 21 if (argc != 2) 22 err_quit("usage: ftw <starting-pathname>"); 23 24 ret = myftw(argv[1], myfunc); /* does it all */ 25 26 if ( (ntot = nreg + ndir + nblk + nchr + nfifo + nslink + nsock) == 0) 27 ntot = 1; /* avoid divide by 0; print 0 for all counts */ 28 printf("regular files = %7ld, %5.2f %%\n", nreg, nreg*100.0/ntot); 29 printf("directories = %7ld, %5.2f %%\n", ndir, ndir*100.0/ntot); 30 printf("block special = %7ld, %5.2f %%\n", nblk, nblk*100.0/ntot); 31 printf("char special = %7ld, %5.2f %%\n", nchr, nchr*100.0/ntot); 32 printf("FIFOs = %7ld, %5.2f %%\n", nfifo, nfifo*100.0/ntot); 33 printf("symbolic links = %7ld, %5.2f %%\n", nslink,nslink*100.0/ntot); 34 printf("sockets = %7ld, %5.2f %%\n", nsock, nsock*100.0/ntot); 35 36 exit(ret); 37 } 38 39 /* 40 * Descend through the hierarchy, starting at "pathname". 41 * The caller's func() is called for every file. 42 */ 43 44 #define FTW_F 1 /* file other than directory */ 45 #define FTW_D 2 /* directory */ 46 #define FTW_DNR 3 /* directory that can't be read */ 47 #define FTW_NS 4 /* file that we can't stat */ 48 49 static char *fullpath; /* contains full pathname for every file */ 50 51 static int /* we return whatever func() returns */ 52 myftw(char *pathname, Myfunc *func) 53 { 54 fullpath = path_alloc(NULL); /* malloc's for PATH_MAX+1 bytes */ 55 /* ({Prog pathalloc}) */ 56 strcpy(fullpath, pathname); /* initialize fullpath */ 57 58 return(dopath(func)); 59 } 60 /* 61 * Descend through the hierarchy, starting at "fullpath". 62 * If "fullpath" is anything other than a directory, we lstat() it, 63 * call func(), and return. For a directory, we call ourself 64 * recursively for each name in the directory. 65 */ 66 static int /* we return whatever func() returns */ 67 dopath(Myfunc* func) 68 { 69 struct stat statbuf; 70 struct dirent *dirp; 71 DIR *dp; 72 int ret; 73 char *ptr; 74 75 if (lstat(fullpath, &statbuf) < 0) 76 return(func(fullpath, &statbuf, FTW_NS)); /* stat error */ 77 78 if (S_ISDIR(statbuf.st_mode) == 0) 79 return(func(fullpath, &statbuf, FTW_F)); /* not a directory */ 80 81 /* 82 * It's a directory. First call func() for the directory, 83 * then process each filename in the directory. 84 */ 85 86 if ( (ret = func(fullpath, &statbuf, FTW_D)) != 0) 87 return(ret); 88 89 ptr = fullpath + strlen(fullpath); /* point to end of fullpath */ 90 *ptr++ = '/'; 91 *ptr = 0; 92 93 if ( (dp = opendir(fullpath)) == NULL) 94 return(func(fullpath, &statbuf, FTW_DNR)); 95 /* can't read directory */ 96 97 while ( (dirp = readdir(dp)) != NULL) { 98 if (strcmp(dirp->d_name, ".") == 0 || 99 strcmp(dirp->d_name, "..") == 0) 100 continue; /* ignore dot and dot-dot */ 101 102 strcpy(ptr, dirp->d_name); /* append name after slash */ 103 104 if ( (ret = dopath(func)) != 0) /* recursive */ 105 break; /* time to leave */ 106 } 107 ptr[-1] = 0; /* erase everything from slash onwards */ 108 109 if (closedir(dp) < 0) 110 err_ret("can't close directory %s", fullpath); 111 112 return(ret); 113 } 114 static int 115 myfunc(const char *pathname, const struct stat *statptr, int type) 116 { 117 switch (type) { 118 case FTW_F: 119 switch (statptr->st_mode & S_IFMT) { 120 case S_IFREG: nreg++; break; 121 case S_IFBLK: nblk++; break; 122 case S_IFCHR: nchr++; break; 123 case S_IFIFO: nfifo++; break; 124 case S_IFLNK: nslink++; break; 125 case S_IFSOCK: nsock++; break; 126 case S_IFDIR: 127 err_dump("for S_IFDIR for %s", pathname); 128 /* directories should have type = FTW_D */ 129 } 130 break; 131 132 case FTW_D: 133 ndir++; 134 break; 135 136 case FTW_DNR: 137 err_ret("can't read directory %s", pathname); 138 break; 139 140 case FTW_NS: 141 err_ret("stat error for %s", pathname); 142 break; 143 144 default: 145 err_dump("unknown type %d for pathname %s", type, pathname); 146 } 147 148 return(0); 149 }