Scroll to navigation

GETDENTS(2) Linux Programmer's Manual GETDENTS(2)

名前

getdents, getdents64 - ディレクトリエントリーを取得する

書式

long getdents(unsigned int fd, struct linux_dirent *dirp,
             unsigned int count);
#define _GNU_SOURCE        /* feature_test_macros(7) 参照 */
#include <dirent.h>
ssize_t getdents64(int fd, void *dirp, size_t count);

: getdents() の glibc のラッパー関数は存在しない。「注意」の節を参照。

説明

これらはあなたの関心を引くようなインターフェースではないだろう。 POSIX 準拠の C ライブラリインターフェースについては readdir(3) を参照のこと。このページは、カーネルシステムコールの生のインターフェースについて記載したものである。

getdents()

getdents() システムコールは、オープン済みのファイルディスクリプター fd で参照されるディレクトリから linux_dirent 構造体をいくつか読み出し、 dirp が指しているバッファーに格納する。 count 引数はそのバッファーのサイズを示す。

linux_dirent 構造体は以下のように宣言されている。


struct linux_dirent {

unsigned long d_ino; /* inode 番号 */
unsigned long d_off; /* 次の linux_dirent へのオフセット */
unsigned short d_reclen; /* この linux_dirent の長さ */
char d_name[]; /* (ヌル終端された) ファイル名 */
/* 実際の長さは (d_reclen - 2 -
offsetof(struct linux_dirent, d_name)) */
/*
char pad; // 値 0 のパディングバイト
char d_type; // ファイル種別 (Linux 2.6.4 以降のみ);
// オフセットは (d_reclen - 1)
*/ }

d_ino は inode 番号である。 d_off はディレクトリの先頭から次の linux_dirent の先頭までの距離である。 d_reclen はこの linux_dirent 全体のサイズである。 d_name はヌル文字で終わるファイル名である。

d_type は、構造体の最後のバイトであり、ファイルタイプを示す。 d_type は以下の値のいずれか一つを取る (<dirent.h> で定義されている)。

ブロックデバイスである。
キャラクターデバイスである。
ディレクトリである。
名前付きパイプ (FIFO) である。
シンボリックリンクである。
通常のファイルである。
UNIX ドメインソケットである。
ファイルタイプが不明。

d_type フィールドは Linux 2.6.4 以降で実装されている。 このフィールドは、 linux_dirent 構造体の中で以前はゼロで埋められていた空間に配置されている。 したがって、2.6.3 以前のカーネルでは、このフィールドにアクセスしようとすると 常に値 0 (DT_UNKNOWN) が返される。

現在のところ、 d_type でファイルタイプを返す機能が完全にサポートされているのは、 いくつかのファイルシステムにおいてのみである (Btrfs, ext2, ext3, ext4 はサポートしている)。 どのアプリケーションも DT_UNKNOWN が返された際に適切に処理できなければならない。

getdents64()

元々の Linux の getdents() システムコールは、大きなファイルシステムと大きなファイルオフセットを扱うことができなかった。そのため、Linux 2.4 で getdents64() が追加された。 getdents64() では、 d_inod_off でビット幅の大きなデータ型が使われている。また、 getdents64() では d_type フィールドが明示的にサポートされている。

getdents64() システムコールは getdents() と似ているが、 2 番目の引数が以下の構造体が入ったバッファへのポインターである点が異なる。


struct linux_dirent64 {

ino64_t d_ino; /* 64 ビットの inode 番号 */
off64_t d_off; /* 次の構造体への 64 ビットのオフセット */
unsigned short d_reclen; /* この dirent の大きさ */
unsigned char d_type; /* ファイル種別 */
char d_name[]; /* (ヌル終端された) ファイル名 */ };

返り値

成功した場合は、読み込んだバイト数が返される。 ディレクトリの終わりならば 0 が返される。 エラーの場合は -1 が返され、 errno に適切な値が設定される。

エラー

ファイルディスクリプター fd が不正である。
引数が呼び出し元プロセスのアドレス空間外を指している。
結果用のバッファーが小さすぎる。
そのようなディレクトリは存在しない。
ファイルディスクリプターがディレクトリを参照していない。

準拠

SVr4.

注意

getdents64() に対応するライブラリのサポートは glibc 2.30 で追加された。 getdents() に対する glibc ラッパー関数は存在しない。 getdents() (もしくは glibc の古いバージョンでの getdents64()) を呼び出すには、 syscall(2) を使う必要がある。その場合、構造体 linux_direntlinux_dirent64 を自分で定義する必要があるだろう。

おそらく、あなたが使いたいのは、これらのシステムコールではなく readdir(3) の方であろう。

これらのシステムコールは readdir(2) を置き換えるものである。

下記のプログラムは getdents() の使用例を示したものである。 以下は、このプログラムを ext2 ディレクトリで実行した際に得られる 出力の例である。


$ ./a.out /testfs/
--------------- nread=120 ---------------
inode#    file type  d_reclen  d_off   d_name

2 directory 16 12 .
2 directory 16 24 ..
11 directory 24 44 lost+found
12 regular 16 56 a
228929 directory 16 68 sub
16353 directory 16 80 sub2
130817 directory 16 4096 sub3

プログラムのソース

#define _GNU_SOURCE
#include <dirent.h>     /* DT_* 定数の定義 */
#include <fcntl.h>
#include <stdint.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#define handle_error(msg) \

do { perror(msg); exit(EXIT_FAILURE); } while (0) struct linux_dirent {
unsigned long d_ino;
off_t d_off;
unsigned short d_reclen;
char d_name[]; }; #define BUF_SIZE 1024 int main(int argc, char *argv[]) {
int fd;
long nread;
char buf[BUF_SIZE];
struct linux_dirent *d;
char d_type;
fd = open(argc > 1 ? argv[1] : ".", O_RDONLY | O_DIRECTORY);
if (fd == -1)
handle_error("open");
for (;;) {
nread = syscall(SYS_getdents, fd, buf, BUF_SIZE);
if (nread == -1)
handle_error("getdents");
if (nread == 0)
break;
printf("--------------- nread=%d ---------------\n", nread);
printf("inode# file type d_reclen d_off d_name\n");
for (long bpos = 0; bpos < nread;) {
d = (struct linux_dirent *) (buf + bpos);
printf("%8ld ", d->d_ino);
d_type = *(buf + bpos + d->d_reclen - 1);
printf("%-10s ", (d_type == DT_REG) ? "regular" :
(d_type == DT_DIR) ? "directory" :
(d_type == DT_FIFO) ? "FIFO" :
(d_type == DT_SOCK) ? "socket" :
(d_type == DT_LNK) ? "symlink" :
(d_type == DT_BLK) ? "block dev" :
(d_type == DT_CHR) ? "char dev" : "???");
printf("%4d %10jd %s\n", d->d_reclen,
(intmax_t) d->d_off, d->d_name);
bpos += d->d_reclen;
}
}
exit(EXIT_SUCCESS); }

関連項目

readdir(2), readdir(3), inode(7)

この文書について

この man ページは Linux man-pages プロジェクトのリリース 5.10 の一部である。プロジェクトの説明とバグ報告に関する情報は https://www.kernel.org/doc/man-pages/ に書かれている。

2020-11-01 Linux