YAMAGUCHI::weblog

海水パンツとゴーグルで、巨万の富を築きました。カリブの怪物、フリーアルバイター瞳です。

ディレクトリの中身を再帰的に表示

最近はデータを大量に取得して、一気にバッチ処理に掛けるみたいなことをやってますが、いい加減シェルスクリプトを書くのがめんどくさくなってきたので、それ専用のクラスを作ってしまおうと昨日くらいから書き始めました。で、一応できたんでソースを載せてみます。こうした方がいいよ、という意見があれば是非コメントまで。

#include <sys/types.h>
#include <dirent.h>
#include <iostream>
using std::cerr;
using std::endl;

void show_files( const char* _cur, const char* _parent) {
    std::string path(_parent);
    if ( path.length() > 0 )
        path += "/";
    path += _cur;

    DIR* dp = opendir( path.c_str() );
    if ( dp == NULL ) {
         cerr << path << endl;
         return;
    }

    struct dirent* entp;
    while ( (entp = readdir(dp)) != NULL ) {
        std::string buff = path;
        
        if ( entp->d_name[0] != '.' )  // ドットで始まるディレクトリを回避
            dir_files( entp->d_name, buff.c_str() );
    }

    closedir(dp);
    return;
}

本当は sys/stat.h 内のstat()を使って

#include <sys/stat.h>
int is_dir (const struct dirent* _entp) {
    struct stat sb;
    stat(_entp->d_name, &sb);

    if ( S_ISDIR(sb.st_mode) )
        return 1;
    else if ( S_ISREG(sb.st_mode) )
        return 2;
    else
        return 0;
}

みたいな感じにしたかったんだけど、どうもカレントディレクトリ以外のディレクトリのファイルのモードはS_IFSOCKになってしまうみたいですね。そのおかげでだいぶはまってしまいました。コレを解消する方法はないかなぁ?
ちなみにcygwinLinuxBSDでdirent構造体の実装が違うみたいですね。dirent.d_type を使えば一発でディレクトリかどうかの判別ができたのに。

ここではd_typeは

Linux 以外では、 d_type フィールドは主に BSD 系のシステムでだけ存在する。

とあるんで、「cygwinもあるんじゃね?」と期待したけど、実際のcygwinの実装では

struct dirent
{
  long d_version;
  long d_reserved[2];
  long d_fd;
  ino_t d_ino;
  char d_name[256];
};

となってました。見事にありません。残念。