FTW(3) | Linux Programmer's Manual | FTW(3) |
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 /* feature_test_macros(7) 参照 */ #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() を呼び出す。 デフォルトでは、ディレクトリそのものが、そのディレクトリにあるファイルや サブディレクトリよりも先に処理される (行きがけ順探索; preorder traversal)。
呼び出し元プロセスが利用可能なファイルディスクリプターを使い切って しまわないようにするため、 ftw() が同時にオープンするディレクトリの最大数を nopenfd で指定することができる。 探索の深さがこの値を越えると、 一つのディレクトリを閉じてから他のディレクトリをオープンし直すこと になるので、 ftw() の動作は遅くなる。 ftw() は、ディレクトリツリーの階層 1 レベルにつき、 最大でも一つのファイルディスクリプターしか使用しない。
ディレクトリツリーで見つかったエントリー毎に、 ftw() は fpath, sb, typeflag の 3つを引き数として fn() を呼び出す。 fpath はエントリーのパス名である。 dirpath が相対パス名で指定された場合には、 fpath は ftw() が呼び出された時点の呼び出し元プロセスのカレントワーキングディレクトリ からの相対パス名となる。 dirpath が絶対パス名で指定された場合には、 fpath は絶対パス名となる。 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) を使用しないこと。
関数 nftw() は ftw() と同じだが、引き数 flags が追加される点と、 fn() の引き数に ftwbuf が追加される点が異なる。
この 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; };
これらの関数は、成功すると 0 を、エラーが発生すると -1 を返す。
fn() が 0 以外を返した場合、ディレクトリツリーの探索を終了し、 fn() が返した値を ftw() や nftw() の結果として返す。
nftw() が FTW_ACTIONRETVAL フラグ付きで呼ばれた場合、ツリーの探索を終了させるために fn() が使用できる、非 0 の値は FTW_STOP だけであり、 この値は nftw() の返り値として返される。
nftw() は バージョン 2.1 以降の glibc で利用できる。
POSIX.1-2001, SVr4, SUSv1. POSIX.1-2008 は ftw() を廃止予定としている。
POSIX.1-2001 の注記によると、 fn がカレントワーキングディレクトリを保持しなかった場合の 結果は規定されていないとされている。
nftw() 関数と、 ftw() における FTW_SL は、SUSv1 で導入された。
ftw() で FTW_SL を一切使わないシステムや、 存在しないファイルを指しているシンボリックリンクの場合にのみ FTW_SL を使うシステム、また ftw() が全てのシンボリックリンクに対して FTW_SL を使うシステムもある。 予測可能な動作をさせるためには、 nftw() を使うこと。
「stat できるがディレクトリではないオブジェクト」 (ファイル, シンボリックリンク, fifo 等) に対しては、すべて FTW_F が返される。
FTW_ACTIONRETVAL は glibc 固有である。
以下のプログラムは、一つ目のコマンドライン引き数を名前に持つパス以下の ディレクトリツリーを探索する。引き数が指定されなかった場合は、 カレントディレクトリ以下を探索する。 各々のファイルについて様々の情報が表示される。 二番目のコマンドライン引き数に文字を指定することで、 nftw() を呼び出す際に flags 引き数に渡す値を制御することができる。
#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); }
この man ページは Linux man-pages プロジェクトのリリース 3.79 の一部 である。プロジェクトの説明とバグ報告に関する情報は http://www.kernel.org/doc/man-pages/ に書かれている。
2014-12-31 | Linux |