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