2011-02-14 92 views
9

这是我写的递归导航和输出目录和常规文件的C程序。它在我的Linux机器上编译并运行良好。但在Solaris上,dit->d_type == 8检查和其他类似检查不起作用,因为没有d_type字段。我读过这个问题的一个答案是使用S_ISREG()S_ISDIR()宏,但它们目前在我的代码中并没有像我的代码那样工作。我评论了在我的Linux机器上工作的线路。如何使用S_ISREG()和S_ISDIR()POSIX宏?

#include <sys/types.h> 
#include <sys/stat.h> 
#include <stdlib.h> 
#include <dirent.h> 
#include <stdio.h> 
#include <unistd.h> 
#include <errno.h> 
#include <string.h> 

void helper(DIR *, struct dirent *, struct stat, char *, int, char **); 
void dircheck(DIR *, struct dirent *, struct stat, char *, int, char **); 

int main(int argc, char *argv[]){ 

    DIR *dip; 
    struct dirent *dit; 
    struct stat statbuf; 
    char currentPath[FILENAME_MAX]; 
    int depth = 0; /*Used to correctly space output*/ 

    /*Open Current Directory*/ 
    if((dip = opendir(".")) == NULL) 
    return errno; 

    /*Store Current Working Directory in currentPath*/ 
    if((getcwd(currentPath, FILENAME_MAX)) == NULL) 
    return errno; 

    /*Read all items in directory*/ 
    while((dit = readdir(dip)) != NULL){ 
    /*Skips . and ..*/ 
    if(strcmp(dit->d_name, ".") == 0 || strcmp(dit->d_name, "..") == 0) 
     continue; 

    if(stat(currentPath, &statbuf) == -1){ 
     perror("stat"); 
     return errno; 
    } 

    /*Checks if current item is of the type file (type 8) and no command line arguments 
     if(dit->d_type == 8 && argv[1] == NULL)*/ 
    if(S_ISREG(statbuf.st_mode) && argv[1] == NULL) 
     printf("%s (%d bytes)\n", dit->d_name, (int)statbuf.st_size); 

     /*If a command line argument is given, checks for filename match 
    if(dit->d_type == 8 && argv[1] != NULL)*/ 
    if(S_ISREG(statbuf.st_mode) && argv[1] != NULL) 
     if(strcmp(dit->d_name, argv[1]) == 0) 
     printf("%s (%d bytes)\n", dit->d_name, (int)statbuf.st_size); 

     /*Checks if current item is of the type directory (type 4) 
     if(dit->d_type == 4)*/ 
    if(S_ISDIR(statbuf.st_mode)) 
     dircheck(dip, dit, statbuf, currentPath, depth, argv); 

    } 
    closedir(dip); 
    return 0; 
} 

/*Recursively called helper function*/ 
void helper(DIR *dip, struct dirent *dit, struct stat statbuf, 
    char currentPath[FILENAME_MAX], int depth, char *argv[]){ 
    int i = 0; 

    if((dip = opendir(currentPath)) == NULL) 
    printf("Error: Failed to open Directory ==> %s\n", currentPath); 

    while((dit = readdir(dip)) != NULL){ 

    if(strcmp(dit->d_name, ".") == 0 || strcmp(dit->d_name, "..") == 0) 
     continue; 

    stat(currentPath, &statbuf); 

    /*if(dit->d_type == 8 && argv[1] == NULL){*/ 
    if(S_ISREG(statbuf.st_mode) && argv[1] == NULL){ 
     for(i = 0; i < depth; i++) 
     printf(" "); 
     printf("%s (%d bytes)\n", dit->d_name, (int)statbuf.st_size); 
    } 

    /*if(dit->d_type == 8 && argv[1] != NULL){*/ 
    if(S_ISREG(statbuf.st_mode) && argv[1] != NULL){ 
     if(strcmp(dit->d_name, argv[1]) == 0){ 
    for(i = 0; i < depth; i++) 
     printf(" "); 
    printf("%s (%d bytes)\n", dit->d_name, (int)statbuf.st_size); 
     } 
    } 

    /*if(dit->d_type == 4)*/ 
    if(S_ISDIR(statbuf.st_mode)) 
     dircheck(dip, dit, statbuf, currentPath, depth, argv); 

    } 
} 

void dircheck(DIR *dip, struct dirent *dit, struct stat statbuf, 
     char currentPath[FILENAME_MAX], int depth, char *argv[]){ 
    int i = 0; 

    strcat(currentPath, "/"); 
    strcat(currentPath, dit->d_name); 

    /*If two directories exist at the same level the path 
    is built wrong and needs to be corrected*/ 
    if((chdir(currentPath)) == -1){ 
    chdir(".."); 
    getcwd(currentPath, FILENAME_MAX); 
    strcat(currentPath, "/"); 
    strcat(currentPath, dit->d_name); 

    for(i = 0; i < depth; i++) 
     printf (" "); 
    printf("%s (subdirectory)\n", dit->d_name); 
    depth++; 
    helper(dip, dit, statbuf, currentPath, depth, argv); 
    } 

    else{ 
    for(i =0; i < depth; i++) 
     printf(" "); 
    printf("%s (subdirectory)\n", dit->d_name); 
    chdir(currentPath); 
    depth++; 
    helper(dip, dit, statbuf, currentPath, depth, argv); 
    } 

} 
+2

我已将代码恢复到原始状态,因为问题没有任何意义。你提供工作代码是很好的,但这属于答案,而不是问题。如果您认为需要发布实现mu解决方案的完整代码,请将其作为答案发布。 – Gilles 2012-02-28 17:58:53

+0

这已经坐了一年多了,并且有相当数量的意见。没有理由删除正确的代码,因为来到这里的人可能会对它感兴趣(并解决了问题)。有破解的解决方案不会帮助任何人。如果您想将其更改回来,那么至少应先将解决方案粘贴为答案。 – zalberico 2012-03-27 23:41:22

+0

这与“树”相同吗? – 2015-01-17 11:39:57

回答

14

您使用S_ISREG()S_ISDIR()正确的,你只是用他们在错误的事情。

mainwhile((dit = readdir(dip)) != NULL)循环,你呼吁currentPathstat一遍又一遍,而不改变currentPath

if(stat(currentPath, &statbuf) == -1) { 
    perror("stat"); 
    return errno; 
} 

你不是应该附加一个斜线和dit->d_namecurrentPath得到充分的路径到你想要的文件stat?好像也需要对其他stat调用进行类似的更改。

3

[发表于fossuser]感谢“mu太短”我能修复这个bug。这里是我的工作代码已被编辑为那些寻找一个很好的例子(因为我无法在网上找到任何其他人)。

#include <sys/types.h> 
#include <sys/stat.h> 
#include <stdlib.h> 
#include <dirent.h> 
#include <stdio.h> 
#include <unistd.h> 
#include <errno.h> 
#include <string.h> 

void helper(DIR *, struct dirent *, struct stat, char *, int, char **); 
void dircheck(DIR *, struct dirent *, struct stat, char *, int, char **); 

int main(int argc, char *argv[]){ 

    DIR *dip; 
    struct dirent *dit; 
    struct stat statbuf; 
    char currentPath[FILENAME_MAX]; 
    int depth = 0; /*Used to correctly space output*/ 

    /*Open Current Directory*/ 
    if((dip = opendir(".")) == NULL) 
    return errno; 

    /*Store Current Working Directory in currentPath*/ 
    if((getcwd(currentPath, FILENAME_MAX)) == NULL) 
    return errno; 

    /*Read all items in directory*/ 
    while((dit = readdir(dip)) != NULL){ 

    /*Skips . and ..*/ 
    if(strcmp(dit->d_name, ".") == 0 || strcmp(dit->d_name, "..") == 0) 
     continue; 

    /*Correctly forms the path for stat and then resets it for rest of algorithm*/ 
    getcwd(currentPath, FILENAME_MAX); 
    strcat(currentPath, "/"); 
    strcat(currentPath, dit->d_name); 
    if(stat(currentPath, &statbuf) == -1){ 
     perror("stat"); 
     return errno; 
    } 
    getcwd(currentPath, FILENAME_MAX); 


    /*Checks if current item is of the type file (type 8) and no command line arguments*/ 
    if(S_ISREG(statbuf.st_mode) && argv[1] == NULL) 
     printf("%s (%d bytes)\n", dit->d_name, (int)statbuf.st_size); 

    /*If a command line argument is given, checks for filename match*/ 
    if(S_ISREG(statbuf.st_mode) && argv[1] != NULL) 
     if(strcmp(dit->d_name, argv[1]) == 0) 
     printf("%s (%d bytes)\n", dit->d_name, (int)statbuf.st_size); 

    /*Checks if current item is of the type directory (type 4)*/ 
    if(S_ISDIR(statbuf.st_mode)) 
     dircheck(dip, dit, statbuf, currentPath, depth, argv); 

    } 
    closedir(dip); 
    return 0; 
} 

/*Recursively called helper function*/ 
void helper(DIR *dip, struct dirent *dit, struct stat statbuf, 
     char currentPath[FILENAME_MAX], int depth, char *argv[]){ 
    int i = 0; 

    if((dip = opendir(currentPath)) == NULL) 
    printf("Error: Failed to open Directory ==> %s\n", currentPath); 

    while((dit = readdir(dip)) != NULL){ 

    if(strcmp(dit->d_name, ".") == 0 || strcmp(dit->d_name, "..") == 0) 
     continue; 

    strcat(currentPath, "/"); 
    strcat(currentPath, dit->d_name); 
    stat(currentPath, &statbuf); 
    getcwd(currentPath, FILENAME_MAX); 

    if(S_ISREG(statbuf.st_mode) && argv[1] == NULL){ 
     for(i = 0; i < depth; i++) 
    printf(" "); 
     printf("%s (%d bytes)\n", dit->d_name, (int)statbuf.st_size); 
    } 

    if(S_ISREG(statbuf.st_mode) && argv[1] != NULL){ 
     if(strcmp(dit->d_name, argv[1]) == 0){ 
    for(i = 0; i < depth; i++) 
     printf(" "); 
    printf("%s (%d bytes)\n", dit->d_name, (int)statbuf.st_size); 
     } 
    } 

    if(S_ISDIR(statbuf.st_mode)) 
     dircheck(dip, dit, statbuf, currentPath, depth, argv); 
    } 
    /*Changing back here is necessary because of how stat is done*/ 
    chdir(".."); 
    closedir(dip); 
} 

void dircheck(DIR *dip, struct dirent *dit, struct stat statbuf, 
      char currentPath[FILENAME_MAX], int depth, char *argv[]){ 
    int i = 0; 

    strcat(currentPath, "/"); 
    strcat(currentPath, dit->d_name); 

    /*If two directories exist at the same level the path 
    is built wrong and needs to be corrected*/ 
    if((chdir(currentPath)) == -1){ 
    chdir(".."); 
    getcwd(currentPath, FILENAME_MAX); 
    strcat(currentPath, "/"); 
    strcat(currentPath, dit->d_name); 

    for(i = 0; i < depth; i++) 
     printf (" "); 
    printf("%s (subdirectory)\n", dit->d_name); 
    depth++; 
    helper(dip, dit, statbuf, currentPath, depth, argv); 
    } 

    else{ 
    for(i =0; i < depth; i++) 
     printf(" "); 
    printf("%s (subdirectory)\n", dit->d_name); 
    chdir(currentPath); 
    depth++; 
    helper(dip, dit, statbuf, currentPath, depth, argv); 
    } 
}