apue 4.22 读目录代码解析Reading Directories

整体思路就是先读入文件名,然后再文件名中调用myftw处理文件名,myftw中调用dopath处理文件名路径中各种文件,主要分为目录和非目录文件。
非目录文件调用myfunc直接用宏测试语句测试出来类型,
目录文件就需要采用递归的思想进行处理,dopath-》func-》func递归处理每一层目录。

#include "apue.h" 
#include <dirent.h> 
#include <limits.h> 

/* function type that is called for each filename */ 
typedef int Myfunc(const char *, const struct stat *, int); 
//Myfunc就等价于int(const char *, const struct stat *, int)  
static Myfunc myfunc; 
//static函数---静态函数的定义和声明默认情况下是extern的,但静态函数只是在声明他的文件当中可见,不能被其他文件所用
static int myftw(char *, Myfunc *);
//第二个形参Myfunc *是一个指针函数返回的指针变量,等价于int *(const char *, const struct stat *, int)这个函数返回的指针
static int dopath(Myfunc *); 
static long nreg, ndir, nblk, nchr, nfifo, nslink, nsock, ntot; 
        //普通文件,目录,块特殊,字符特殊,FIFO,符号链接,套接字,tot
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.2f %%\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("FIFOs = %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 that can't be read */ 
#define FTW_NS 4 /* file that we can't stat */ 

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

static int /* we return whatever func() returns */ 
myftw(char *pathname, Myfunc *func) 
{ 
        fullpath = path_alloc(&pathlen);
                      /* 动态分配路径名malloc PATH_MAX+1 bytes */                                                                       
                      /* ({Flgure 图2.16}) */ 
        if (pathlen <= strlen(pathname)) { 
                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 call ourself 
* recursively for each name in the directory. 
*/ 

static int /* we return whatever func() returns */ 
dopath(Myfunc* func) //这句话就定义了一个Myfunc类型的函数func
{ 
        struct stat statbuf; //stat函数
        struct dirent *dirp; //readdir函数
        DIR *dp;             //opendir函数
        int ret, n; 
        //之前define的4中文件,这里先分辨出来,然后调用func
        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 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; //添加“0”,后面会把这个0覆盖掉,所以无所谓
         /* 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 after "/" */ 

                if ((ret = dopath(func)) != 0) /* 说明是define中1.2.3这几种文件,在myfunc中return不是0,是报错退出了,所以不需要进行处理了,就break。 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: 
                switch (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 have 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("unknown type %d for pathname %s", type, pathname); 
        } 
        return(0); 
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值