This program uses a number of functions to manipulate the directory to write a program to traverse the file hierarchy, and finally the various types of file count. This program has only one parameter, which shows the starting path name, from which the recursive their oaths sequence traverses the file hierarchy. It also uses a function path_alloc that dynamically allocates the store for the path name.
ftw.c//2015-08-18 Lucifer zhang//recursively descend a directory hierarchy, counting file Types#include "Apue.h" #i Nclude "pathalloc.h" #include <dirent.h> #include <limits.h>//function type that's called for each filenamety pedef int Myfunc (const char *, const struct STAT *, int); static Myfunc myfunc;static int myftw (char *, Myfunc *); static in T Dopath (Myfunc *); static long Nreg, Ndir, Nblk, NCHR, Nfifo, Nslink, Nsock, ntot;int main (int argc, char *argv[]) {int Ret if (argc! = 2) {err_quit ("usage:ftw <starting-pathname>"); } ret = MYFTW (argv[1], myfunc); Does it all Ntot = Nreg + ndir + nblk + nchr + nfifo + nslink + nsock; if (Ntot = = 0) {Ntot = 1;//avoid divide by 0; Print 0 for all counts} printf ("Regular files =%7ld,%5.2 F%%\n ", Nreg, Nreg * 100.0/ntot); printf ("directories =%7ld,%5.2f%%\n", Ndir, Ndir * 100.0/ntot); printf ("Block special =%7ld,%5.2f%%\n", nblk, nblk * 100.0/ntot);printf ("Char special =%7ld,%5.2f%%\n", NCHR, NCHR * 100.0/ntot); printf ("Fifls =%7ld,%5.2f%%\n", Nfifo, Nfifo * 100.0/ntot); printf ("Symbolic links =%7ld,%5.2f%%\n", Nslink, Nslink * 100.0/ntot); printf ("sockets =%7ld,%5.2f%%\n", Nsock, Nsock * 100.0/ntot); Exit (ret);} /* * Descend through the hierarchy starting at "pathname". * The caller ' s func () is called for every file. * */#define FTW_F 1//file other than Directory#define Ftw_d 2//Directory#define FTW_DNR 3//directory Thar can ' t is read#define ftw_ns 4//file that we can ' t statstatic char *fullpath; Contains full pathname for every filestatic size_t pathlen;static int myftw (char *pathname, Myfunc *func)//We return Whatever func () returns{FullPath = Path_alloc (&pathlen);//malloc path_max+1 bytes if (pathlen <= strlen (PA Thname)) {Pathlen = strlen (pathname) * 2; if ((FullPath = ReAlloc (FullPath, pathlen)) = = = NULL) {Err_sys("ReAlloc failed"); }} strcpy (FullPath, pathname); Return (Dopath (func));} /* * Descend through the hierarchy, starting at "FullPath". * If "FullPath" is anything other than a directory, we Lstat () it * call Func (), and return. For a directory, we are ourself * recursively for each name in the directory. * */static int Dopath (Myfunc *func)//We return whatever func () returns{struct stat statbuf; struct Dirent *dirp; DIR * DP; int ret, n; if (Lstat (FullPath, &statbuf) < 0) {//STAT error return (func (FullPath, &statbuf, Ftw_ns)); } if (S_isdir (statbuf.st_mode) = = 0) {//Not a directory return (func (FullPath, &statbuf, Ftw_f)); }/* * It ' s a directory. First call Func () for the directory, * then process each of the filename in the directory. * */if (ret = func (FullPath, &statbuf, ftw_d))! = 0) {return ret; } n = strlen (FullPath); if (n + name_max +2 > Pathlen) {//expand path BUffer Pathlen *= 2; if (FullPath = ReAlloc (FullPath, pathlen)) = = NULL) {Err_sys ("ReAlloc failed"); }} fullpath[n++] = '/'; Fullpath[n] = 0; if (DP = Opendir (fullpath)) = = NULL) {//can ' t read directory return func (FullPath, &statbuf, FTW_DNR); } while ((DIRP = Readdir (DP)) = NULL) {if (strcmp (Dirp->d_name, ".") = = 0 | | strcmp (Dirp->d_name, "..") = = 0) {continue;//Ignore dot and Dot-dot} strcpy (&fullpath[ N], dirp->d_name); Append name Agter "/" if (ret = Dopath (func))! = 0) {//recursive break;//Time to leave} } fullpath[n-1] = 0; Erase everything from slash onward if (Closedir (DP) < 0) {Err_ret ("can ' t close directory%s", FullPath); } return ret;} static int myfunc (const char *pathname, const struct STAT *statptr, int type) {switch (type) {case FTW_F:SW Itch (Statptr->st_mode & S_IFMT) {case S_ifreg: ++nreg; Break Case S_IFBLK: ++nblk; Break Case S_IFCHR: ++NCHR; Break Case S_IFIFO: ++nfifo; Break Case S_iflnk: ++nslink; Break Case S_ifsock: ++nsock; Break Case S_IFDIR://directories should has type = Ftw_d err_dump ("For S_ifdir for%s", pathname); } break; Case Ftw_d: ++ndir; Break Case Ftw_dnr:err_ret ("can ' t read directory%s", pathname); Break Case Ftw_ns:err_ret ("Stat error for%s", pathname); Break Default:err_dump ("Unknow type%d for pathname%s", type, pathname); } return 0;}
pathalloc.h//2015-08-18 Lucifer zhang//Dynamically allocate space for a pathname#include "apue.h" #include <errn o.h> #include <limits.h> #ifdef path_maxstatic long pathmax = Path_max; #elsestatic long pathmax = 0; #endifstatic l Ong posix_version = 0;static Long xsi_version = 0;//If Path_max is indeterminate, no guarantee the is Adequate#define PA Th_max_guess 1024char* Path_alloc (size_t *sizep) {//also return allocated size, if nonnull char *ptr; size_t size; if (posix_version = = 0) {posix_version = sysconf (_sc_version); } if (xsi_version = = 0) {xsi_version = sysconf (_sc_xopen_version); } if (Pathmax = = 0) {//first time through errno = 0; if (Pathmax = pathconf ("/", _pc_path_max)) < 0) {if (errno = = 0) {Pathmax = Path_max_guess ; It ' s indeterminate} else {Err_sys ("pathconf error for _pc_path_max"); }} else {++pathmax;//And One since it s relative to root}}/* * Before posix.1-2001, we aren ' t guaranteed that Phat_max include S * the terminating null byte. Same goes for XPG3. */if ((Posix_version < 200112L) && (Xsi_version < 4)) {size = Pathmax + 1; } else {size = Pathmax; } if (ptr = malloc (size) = = NULL) {err_sys ("malloc error for pathname"); } if (Sizep! = NULL) {*sizep = size; } return ptr;}
Test results on the Centos6.7:
Copyright NOTICE: This article for Bo Master original article, without Bo Master permission not reproduced.
Recursive their oaths traversal of directory hierarchies and counting by file type