Ulrich Drepper が自身のブログで、効率的なディレクトリ読み込みについてエントリを書いている。
しかし、改善案が思いっきり linux+glibc 依存なのでこれを実践できる人は少ないだろうな。と苦笑
元記事: http://udrepper.livejournal.com/18555.html
以下、抜粋
ダメなコード
オススメ
ポイント
追記: 元エントリへのリンクを忘れていたので貼る
追記2: 識者から、個々のファイル名という表現は誤解を招くというご指摘をいただいた。その通りなので修正
しかし、改善案が思いっきり linux+glibc 依存なのでこれを実践できる人は少ないだろうな。と苦笑
元記事: http://udrepper.livejournal.com/18555.html
以下、抜粋
ダメなコード
DIR *dir = opendir(some_path);
struct dirent *d;
struct dirent d_mem;
while (readdir_r(d, &d_mem, &d) == 0) {
char path[PATH_MAX];
snprintf(path, sizeof(path), "%s/%s/somefile", some_path, d->d_name);
int fd = open(path, O_RDONLY);
if (fd != -1) {
... do something ...
close (fd);
}
}
closedir(dir);
オススメ
DIR *dir = opendir(some_path);
int dfd = dirfd(dir);
struct dirent64 *d;
while ((d = readdir64(dir)) != NULL) {
if (d->d_type != DT_DIR && d->d_type != DT_UNKNOWN)
continue;
char path[PATH_MAX];
snprintf(path, sizeof(path), "%s/somefile", d->d_name);
int fd = openat(dfd, path, O_RDONLY);
if (fd != -1) {
... do something ...
close (fd);
}
}
closedir(dir);
ポイント
- readdir_r() は意味ないよ。これは複数のスレッドが同じディレクトリストリームを読むことを可能にする関数だが、dirがローカル変数になってるから絶対他スレッドと競合しない
- readdir()ではなく、readdir64()を使え。2GB越えのファイルで泣きたくなければ
- Linuxは、名前長制限は
個々のファイル名open()等の引数文字列長にかかるのであって、絶対パスにはかからない(まあリンクとか有るからカーネルでチェックできんしね)。だからPATH_MAXを安易に使うな。some_pathがPATH_MAXに非常に近い文字列長だったら、どうなる?openat()を使うべし
- そもそも some_pathを足してopenする事自体がracyでダメ。パスをたぐってる間に別プロセスがリンクを張り直したりできるよ。セキュリティーホールになるよ。openat()を使うべし
- dirent64はd_typeフィールドがあるから、openしなくてもディレクトリかどうか分かるよ
追記: 元エントリへのリンクを忘れていたので貼る
追記2: 識者から、個々のファイル名という表現は誤解を招くというご指摘をいただいた。その通りなので修正
コメント
コメント一覧 (1)