如何使用S_ISREG()和S_ISDIR()POSIX宏?

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

 #include  #include  #include  #include  #include  #include  #include  #include  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 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 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 d_name); depth++; helper(dip, dit, statbuf, currentPath, depth, argv); } else{ for(i =0; i d_name); chdir(currentPath); depth++; helper(dip, dit, statbuf, currentPath, depth, argv); } } 

你正确使用S_ISREG()S_ISDIR() ,你只是在错误的东西上使用它们。

在你的while((dit = readdir(dip)) != NULL)循环中,你在一次又一次地调用currentPath上的stat而不改变currentPath

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

您是否应该将斜杠和dit->d_name附加到currentPath以获取要进行stat的文件的完整路径? 还需要对您的其他stat调用进行类似更改。

[代表fossuser发表]由于“mu太短”,我能够解决这个问题。 这是我的工作代码已被编辑为那些寻找一个很好的例子(因为我在网上找不到任何其他人)。

 #include  #include  #include  #include  #include  #include  #include  #include  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); } }