#include <ftw.h> int ftw(const char *dirpath, int (*fn) (const char *fpath, const struct stat *sb, int typeflag), int nopenfd); #define _XOPEN_SOURCE 500 #include <ftw.h> int nftw(const char *dirpath, int (*fn) (const char *fpath, const struct stat *sb, int typeflag, struct FTW *ftwbuf), int nopenfd, int flags);
呼び出し元プロセスが利用可能なファイルディスクリプタを使い切って しまわないようにするため、 ftw() が同時にオープンするディレクトリの最大数を nopenfd で指定することができる。 探索の深さがこの値を越えると、 一つのディレクトリを閉じてから他のディレクトリをオープンし直すこと になるので、 ftw() の動作は遅くなる。 ftw() は、ディレクトリツリーの階層 1 レベルにつき、 最大でも一つのファイルディスクリプタしか使用しない。
ディレクトリツリーで見つかったエントリ毎に、 ftw() は fpath, sb, typeflag の 3つを引き数として fn() を呼び出す。 fpath はエントリの dirpath からの相対パス名である。 sb は fpath に対する stat(2) の呼び出しで返される stat 構造体へのポインタである。 typeflag は整数で、以下の値のいずれか一つである:
fpath がシンボリックリンクで、かつ stat(2) が失敗した場合、 FTW_NS と FTW_SL (後述) のどちらが typeflag に渡されるかは未定義であると、POSIX.1-2001 には書かれている。
ツリーの探索を止めたい場合は、 fn() が 0 以外の値を返せば良い (この値は ftw() 自身の戻り値となる)。 それ以外の場合は ftw() はツリー全体の探索を続け、すべてのツリーを探索し終えたところで 0 を返す。探索中に (malloc(3) の失敗などの) エラーが起こると -1 を返す。
ftw() は動的なデータ構造を用いるので、ツリー探索を安全に中断する唯一の方法は 0 以外の値を fn() の返り値とすることである。割り込みを扱うには、 例えば発生した割り込みをマークしておいて、 0 以外の値を返すようにする シグナルによりメモリリークを起こさずに探索を終了できるようにするには、 シグナルハンドラで fn() がチェックするグローバルなフラグをセットするようにすればよい。 プログラムを終了させる場合以外は、 longjmp(3) を使用しないこと。
この flags 引き数は下記のフラグの 0 個以上の論理和を取ったものである:
他の返り値は将来新しい動作に対応付けられる可能性がある。 fn() は上記のリストにある値以外を返さないようにすべきである。
<ftw.h> で FTW_ACTIONRETVAL が定義されるようにするには、 機能検査マクロ _GNU_SOURCE を定義しなければならない。
FTW_PHYS がセットされずに FTW_DEPTH がセットされると、自分自身に対するシンボリックリンクを配下に持つ ディレクトリに対して fn() が呼び出されることは決してない。
ディレクトリツリーのエントリ毎に、 nftw() は 4つの引き数で fn() を呼び出す。 fpath と sb は ftw() と同じである。 typeflag には、 ftw() で取り得る値のいずれか、または以下の値のいずれかが渡される:
nftw() が fn() を呼び出す際に渡す 4つめの引き数は FTW 型の構造体である。
struct FTW { int base; int level; };base は、ファイル名 (basename 要素) の、 fpath で渡されるパス名の中でのオフセットである。 level はディレクトリツリーでの fpath の深さを示す。深さはディレクトリツリーのトップ (root) からの 相対値である (dirpath は深さ 0 である)。
fn() が 0 以外を返した場合、ディレクトリツリーの探索を終了し、 fn() が返した値を ftw() や nftw() の結果として返す。
nftw() が FTW_ACTIONRETVAL フラグ付きで呼ばれた場合、ツリーの探索を終了させるために fn() が使用できる、非 0 の値は FTW_STOP だけであり、 この値は nftw() の返り値として返される。
ftw() で FTW_SL を一切使わないシステムや、 存在しないファイルを指しているシンボリックリンクの場合にのみ FTW_SL を使うシステム、また ftw() が全てのシンボリックリンクに対して FTW_SL を使うシステムもある。 予測可能な動作をさせるためには、 nftw() を使うこと。
Linux では、 libc4, libc5, glibc 2.0.6 は 「stat できるがディレクトリではないオブジェクト」 (ファイル, シンボリックリンク, fifo 等) に対してはすべて FTW_F を使う。
nftw() 関数は glibc 2.1 以降で利用できる。
FTW_ACTIONRETVAL は glibc 固有である。
#define _XOPEN_SOURCE 500 #include <ftw.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdint.h> static int display_info(const char *fpath, const struct stat *sb, int tflag, struct FTW *ftwbuf) { printf("%-3s %2d %7jd %-40s %d %s\n", (tflag == FTW_D) ? "d" : (tflag == FTW_DNR) ? "dnr" : (tflag == FTW_DP) ? "dp" : (tflag == FTW_F) ? "f" : (tflag == FTW_NS) ? "ns" : (tflag == FTW_SL) ? "sl" : (tflag == FTW_SLN) ? "sln" : "???", ftwbuf->level, (intmax_t) sb->st_size, fpath, ftwbuf->base, fpath + ftwbuf->base); return 0; /* To tell nftw() to continue */ } int main(int argc, char *argv[]) { int flags = 0; if (argc > 2 && strchr(argv[2], 'd') != NULL) flags |= FTW_DEPTH; if (argc > 2 && strchr(argv[2], 'p') != NULL) flags |= FTW_PHYS; if (nftw((argc < 2) ? "." : argv[1], display_info, 20, flags) == -1) { perror("nftw"); exit(EXIT_FAILURE); } exit(EXIT_SUCCESS); }