1. ホーム
  2. c

[解決済み】S_ISREG() と S_ISDIR() POSIX マクロを使用するには?

2022-02-22 23:51:27

質問

これは、ディレクトリと通常のファイルを再帰的にナビゲートして出力するために書いたC言語プログラムです。 私のLinuxマシンでは問題なくコンパイルして実行できます。しかし、Solaris上では dit->d_type == 8 がないため、チェックやその他類似のものが機能しない。 d_type のフィールドがあります。 この問題に対する私が読んだ回答は S_ISREG()S_ISDIR() というマクロがあるのですが、現在私のコードにある方法では全く動作しません。 私のLinuxマシンで動作する行をコメントアウトしました。

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

}

解決方法は?

を使用しています。 S_ISREG()S_ISDIR() を正しく使うことで、間違ったものに使っているだけなのです。

あなたの while((dit = readdir(dip)) != NULL) のループは main を呼び出しているのであれば、あなたは stat について currentPath を何度も何度も変更することなく currentPath :

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

スラッシュと dit->d_namecurrentPath にしたいファイルへのフルパスを取得します。 stat ? あなたの他の stat の呼び出しも必要です。