名前
ftw, nftw - ファイルツリーを歩きまわる
書式
#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() は、 dirpath で指定されたディレクトリ以下のディレクトリツリー全体を歩きまわり、 ツリー中でエントリが見付かるごとに、 fn() を呼び出す。 デフォルトでは、ディレクトリそのものが、そのディレクトリにあるファイルや サブディレクトリよりも先に処理される (行きがけ順探索; pre-order traversal)。
呼び出し元プロセスが利用可能なファイルディスクリプタを使い切って しまわないようにするため、 ftw() が同時にオープンするディレクトリの最大数を nopenfd で指定することができる。 探索の深さがこの値を越えると、 一つのディレクトリを閉じてから他のディレクトリをオープンし直すこと になるので、 ftw() の動作は遅くなる。 ftw() は、ディレクトリツリーの階層 1 レベルにつき、 最大でも一つのファイルディスクリプタしか使用しない。
ディレクトリツリーで見つかったエントリ毎に、 ftw() は fpath, sb, typeflag の 3つを引き数として fn() を呼び出す。 fpath はエントリの dirpath からの相対パス名である。 sb は fpath に対する stat(2) の呼び出しで返される stat 構造体へのポインタである。 typeflag は整数で、以下の値のいずれか一つである:
FTW_F | fpath が通常のファイルである |
FTW_D | fpath がディレクトリである |
FTW_DNR | |
fpath が読み込みできないディレクトリである | |
FTW_NS | シンボリックリンクではない
fpath に対する
stat(2)
呼び出しが失敗した。
fpath がシンボリックリンクで、かつ stat(2) が失敗した場合、 FTW_NS と FTW_SL (後述) のどちらが typeflag に渡されるかは未定義であると、POSIX.1-2001 には書かれている。 |
ftw() は動的なデータ構造を用いるので、ツリー探索を安全に中断する唯一の方法は 0 以外の値を fn() の返り値とすることである。割り込みを扱うには、 例えば発生した割り込みをマークしておいて、 0 以外の値を返すようにする シグナルによりメモリリークを起こさずに探索を終了できるようにするには、 シグナルハンドラで fn() がチェックするグローバルなフラグをセットするようにすればよい。 プログラムを終了させる場合以外は、 longjmp(3) を使用しないこと。
nftw()
関数 nftw() は ftw() と同じだが、引き数 flags が追加される点と、 fn() の引き数に ftwbuf が追加される点が異なる。
この flags 引き数は下記のフラグの 0 個以上の論理和を取ったものである:
FTW_ACTIONRETVAL (glibc 2.3.3 以降) | |||||||||||||||||
このフラグは glibc 固有である。
このフラグをセットすると、
nftw() の
fn() の返り値の扱いが変わる。
fn() は以下の値のいずれか一つを返す必要がある。
<ftw.h> で FTW_ACTIONRETVAL が定義されるようにするには、 機能検査マクロ _GNU_SOURCE を定義しなければならない。 | |||||||||||||||||
FTW_CHDIR | |||||||||||||||||
セットされると、ディレクトリの内容を処理する前に そのディレクトリに chdir(2) する。このフラグは、 fpath が属すディレクトリで何らかの動作を実行する必要がある場合に 便利である。 | |||||||||||||||||
FTW_DEPTH | |||||||||||||||||
セットされると、帰りがけ順探索 (post-order traversal) を行う。 つまり、ディレクトリそのものを引き数とした fn() 呼出しは、そのディレクトリに含まれるファイルとサブディレクトリに 対する処理の「後で」行われる (デフォルトでは、ディレクトリ自身の処理はディレクトリ内のエントリ より「前に」行なわれる)。 | |||||||||||||||||
FTW_MOUNT | |||||||||||||||||
セットされると、同じファイルシステムの中だけを探索対象とする (つまり、マウントポイントをまたぐことはない)。 | |||||||||||||||||
FTW_PHYS | |||||||||||||||||
セットされると、シンボリックリンクを辿らない (おそらくこちらが
通常望ましい動作だろう)。セットされていないとシンボリックリンクを
辿るが、同じファイルが二回報告されることはない。
FTW_PHYS がセットされずに FTW_DEPTH がセットされると、自分自身に対するシンボリックリンクを配下に持つ ディレクトリに対して fn() が呼び出されることは決してない。 | |||||||||||||||||
ディレクトリツリーのエントリ毎に、 nftw() は 4つの引き数で fn() を呼び出す。 fpath と sb は ftw() と同じである。 typeflag には、 ftw() で取り得る値のいずれか、または以下の値のいずれかが渡される: | |||||||||||||||||
FTW_DP | fpath がディレクトリで、かつ flags で FTW_DEPTH が指定されていた。 fpath 配下のファイルとサブディレクトリは全て処理が終わっている。 | ||||||||||||||||
FTW_SL | fpath がシンボリックリンクで、かつ FTW_PHYS が flags に セットされていた。 | ||||||||||||||||
FTW_SLN | |||||||||||||||||
fpath がシンボリックリンクで、存在しないファイルを指している (これがセットされるのは FTW_PHYS がセットされていない場合だけである)。 | |||||||||||||||||
struct FTW { int base; int level; };
base は、ファイル名 (basename 要素) の、 fpath で渡されるパス名の中でのオフセットである。 level はディレクトリツリーでの fpath の深さを示す。深さはディレクトリツリーのトップ (root) からの 相対値である (dirpath は深さ 0 である)。
返り値
これらの関数は、成功すると 0 を、エラーが発生すると -1 を返す。
fn() が 0 以外を返した場合、ディレクトリツリーの探索を終了し、 fn() が返した値を ftw() や nftw() の結果として返す。
nftw() が FTW_ACTIONRETVAL フラグ付きで呼ばれた場合、ツリーの探索を終了させるために fn() が使用できる、非 0 の値は FTW_STOP だけであり、 この値は nftw() の返り値として返される。
準拠
POSIX.1-2001, SVr4, SUSv1.
注意
nftw() 関数と、 ftw() における FTW_SL は、SUSv1 で導入された。
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 固有である。
例
以下のプログラムは、一つ目のコマンドライン引き数を名前に持つパス以下の
ディレクトリツリーを探索する。引き数が指定されなかった場合は、
カレントディレクトリ以下を探索する。
各々のファイルについて様々の情報が表示される。
二番目のコマンドライン引き数に文字を指定することで、
nftw() を呼び出す際に
flags 引き数に渡す値を制御することができる。
#define _XOPEN_SOURCE 500
#include <ftw.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static int
display_info(const char *fpath, const struct stat *sb,
int tflag, struct FTW *ftwbuf)
{
printf("%-3s %2d %7lld %-40s %d %s\n",
(tflag == FTW_D) ? "d" : (tflag == FTW_DNR) ? "dnr" :
(tflag == FTW_DP) ? "dp" : (tflag == FTW_F) ? "f" :
(tflag == FTW_DP) ? "dp" : (tflag == FTW_SL) ? "sl" :
(tflag == FTW_SLN) ? "sln" : "???",
ftwbuf->level, (long long) 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;
nftw((argc < 2) ? "." : argv[1], display_info, 20, flags);
exit(EXIT_SUCCESS);
}