stat(2) ファイルの状態を取得する

Other Alias

fstat, lstat, fstatat

書式

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>


int stat(const char *pathname, struct stat *buf);
int fstat(int fd, struct stat *buf);
int lstat(const char *pathname, struct stat *buf);

#include <fcntl.h> /* AT_* 定数の定義 */
#include <sys/stat.h>

int fstatat(int dirfd, const char *pathname, struct stat *buf,
int flags);

glibc 向けの機能検査マクロの要件 (feature_test_macros(7) 参照):

lstat():

_BSD_SOURCE || _XOPEN_SOURCE >= 500 || _XOPEN_SOURCE && _XOPEN_SOURCE_EXTENDED
|| /* glibc 2.10 以降: */ _POSIX_C_SOURCE >= 200112L

fstatat():

glibc 2.10 以降:
_XOPEN_SOURCE >= 700 || _POSIX_C_SOURCE >= 200809L
glibc 2.10 より前:
_ATFILE_SOURCE

説明

これらの関数は、ファイルについての情報を stat が指すバッファに格納して返す。 ファイルそのものに対するアクセス許可は必要としないが、 ---stat(), fstatat(), lstat() の場合には ---そのファイルへ至る pathname を構成する全てのディレクトリに対する実行 (検索) 許可が必要である。

stat() と fstatat() は pathname が指すファイルに関する情報を取得する。 fstatat() の違いについては後で説明する。

lstat() は stat() と同じであるが、 pathnames がシンボリックリンクの場合、リンクが参照しているファイルではなく、 リンク自身の状態を返す点が異なる。

fstat() は stat() と同じだが、 状態を取得するファイルをファイルディスクリプタ fd で指定する点が異なる。

これらのシステムコールはいずれも、結果を stat 構造体に入れて返す。 stat 構造体には以下のフィールドが含まれている:

struct stat {
    dev_t     st_dev;     /* ファイルがあるデバイスの ID */
    ino_t     st_ino;     /* inode 番号 */
    mode_t    st_mode;    /* アクセス保護 */
    nlink_t   st_nlink;   /* ハードリンクの数 */
    uid_t     st_uid;     /* 所有者のユーザ ID */
    gid_t     st_gid;     /* 所有者のグループ ID */
    dev_t     st_rdev;    /* デバイス ID (特殊ファイルの場合) */
    off_t     st_size;    /* 全体のサイズ (バイト単位) */
    blksize_t st_blksize; /* ファイルシステム I/O での
                             ブロックサイズ */
    blkcnt_t  st_blocks;  /* 割り当てられた 512B のブロック数 */
};
    /* Linux 2.6 以降では、カーネルは以下のタイムスタンプ
       フィールドでナノ秒の精度をサポートしている。
       Linux 2.6 より前のバージョンでの詳細は
       下記の「注意」を参照。 */
    struct timespec st_atim;  /* 最終アクセス時刻 */
    struct timespec st_mtim;  /* 最終修正時刻 */
    struct timespec st_ctim;  /* 最終状態変更時刻 */
#define st_atime st_atim.tv_sec      /* 後方互換性 */
#define st_mtime st_mtim.tv_sec
#define st_ctime st_ctim.tv_sec
};

注意: stat 構造体のフィールドの順序はアーキテクチャにより様々である。 また、上記の定義では、フィールド間に存在することがあるパディングバイトは書かれていない。このパディングバイトはアーキテクチャによっても異なる。詳細を知る必要がある場合は glibc とカーネルのソースを調べてほしい。

st_dev フィールドは、このファイルが存在するデバイスを示す (マクロ major(3), minor(3) は、このフィールドのデバイス ID を分解するのに役立つだろう)。

st_rdev フィールドは、このファイル (inode) が表すデバイスを示す。

st_size フィールドは、(通常のファイルかシンボリックリンクの場合に) ファイルの大きさをバイト単位で示す。 シンボリックリンクの大きさは、 シンボリックリンクに含まれている パス名の長さ (終端のヌルバイトは含まない) である。

st_blocks フィールドは、ファイルの大きさを 512 バイトのブロックサイズ単位で示す フィールドは、ファイルに割り当てされたブロック数を 512 バイト単位で示す。 (ファイルに穴があるような場合、この値は st_size/512 より小さくなることもある)。

st_blksize フィールドは、効率的にファイルシステム I/O ができる「好ましい」 ブロックサイズを示す (もっと小さい単位でファイルに書き込みを行うと、 読み出し--修正--再書き込みといった非効率な動作になってしまうかもしれない)。

全ての Linux のファイルシステムが全ての時間フィールドを 実装しているわけではない。 ファイルやディレクトリのアクセスが st_atime フィールドを更新しないようなかたちでマウントできるファイルシステムもある。 (mount(8) の noatime, nodiratime, relatimemount(2) の関連する情報を参照)。 また、ファイルが O_NOATIME 付きでオープンされている場合には st_atime は更新されない。 open(2) 参照。

st_atime フィールドはファイルアクセスがあった場合に変更される (例えば、 execve(2), mknod(2), pipe(2), utime(2) を使用した場合や read(2) で 1 バイト以上読み込んだ場合など)。 mmap(2) などの他のルーチンでは、 st_atime は更新されることもあれば、そうでない場合もある。

st_mtime フィールドは、ファイルが修正された場合に変更される (例えば、 mknod(2), truncate(2), utime(2) を使用した場合や write(2) で 1 バイト以上書き込みをした場合など)。 さらに、ディレクトリの st_mtime は、そのディレクトリで ファイルが作成されたり削除されたりすると変更される。 st_mtime フィールドは 所有者やグループやハード・リンク数やモードの変更では変更 されない。

st_ctime フィールドは書き込みや inode 情報 (所有者、グループ、リンク数、モードなど) の 設定によって変更される。

以下の POSIX マクロは、 st_mode フィールド で使用されるファイル種別のチェックのために定義されている :

S_ISREG(m)
通常のファイルか?
S_ISDIR(m)
ディレクトリか?
S_ISCHR(m)
キャラクター・デバイスか?
S_ISBLK(m)
ブロック・デバイスか?
S_ISFIFO(m)
FIFO (名前付きパイプ) か?
S_ISLNK(m)
シンボリックリンクか? (POSIX.1-1996 にはない)
S_ISSOCK(m)
ソケットか? (POSIX.1-1996 にはない)

以下のフラグが st_mode フィールド用に定義されている:

S_IFMT0170000ファイル種別を示すビット領域を表すビットマスク
S_IFSOCK0140000ソケット
S_IFLNK0120000シンボリックリンク
S_IFREG0100000通常のファイル
S_IFBLK0060000ブロック・デバイス
S_IFDIR0040000ディレクトリ
S_IFCHR0020000キャラクター・デバイス
S_IFIFO0010000FIFO
S_ISUID0004000set-user-ID bit
S_ISGID0002000set-group-ID bit (下記参照)
S_ISVTX0001000スティッキー・ビット (下記参照)
S_IRWXU00700ファイル所有者のアクセス許可用のビットマスク
S_IRUSR00400所有者の読み込み許可
S_IWUSR00200所有者の書き込み許可
S_IXUSR00100所有者の実行許可
S_IRWXG00070グループのアクセス許可用のビットマスク
S_IRGRP00040グループの読み込み許可
S_IWGRP00020グループの書き込み許可
S_IXGRP00010グループの実行許可
S_IRWXO00007 他人 (others) のアクセス許可用のビットマスク
S_IROTH00004他人の読み込み許可
S_IWOTH00002他人の書き込み許可
S_IXOTH00001他人の実行許可

set-group-ID bit (S_ISGID) にはいくつかの特殊な使用法がある: ディレクトリに設定した場合には、そのディレクトリが BSD 方式で使用される ことを示す。つまり、そのディレクトリに作成されたファイルのグループID は 作成したプロセスの実効 (effective) グループID ではなく、ディレクトリの グループID を継承する。また、そのディレクトリに作成されたディレクトリにも S_ISGID ビットが設定される。グループ実行ビット (S_IXGRP) が設定されていないファイルに設定された場合は、 set-group-ID ビットはファイル/レコードの 強制的な (mandatory) ロックを表す。

ディレクトリにスティッキービット (S_ISVTX) が設定された場合は、 そのディレクトリのファイルの名前を変更したり、削除したりできるのは、 そのファイルの所有者か、そのディレクトリの所有者か、特権プロセス だけとなる。

fstatat()

fstatat() システムコールは stat() と全く同様に動作するが、以下で説明する点が異なる。

指定された pathname が相対パスの場合、 ファイルディスクリプタ dirfd が参照するディレクトリに対する相対パスと解釈される (stat() に相対パスを渡した場合のように、呼び出したプロセスのカレントワーキングディレクトリに対する相対パスではない)。

pathname が相対パスで、 dirfd が特別な値 AT_FDCWD の場合、 (stat(2) と同様に) pathname は呼び出したプロセスのカレントワーキングディレクトリに対する相対パスと解釈される。

pathname で指定されたパス名が絶対パスの場合、 dirfd は無視される。

この flags 引き数は下記のフラグの 0 個以上の論理和を取ったものである:

AT_EMPTY_PATH (Linux 2.6.39 以降)
pathname が空文字列の場合、 dirfd が参照するファイルに対して操作を行う (dirfdopen(2) の O_PATH フラグを使って取得できる)。 dirfdAT_FDCWD の場合、呼び出しはカレントワーキングディレクトリに対して操作を行う。 この場合、 dirfd は、ディレクトリだけでなく、任意のタイプのファイルを参照することができる。 このフラグは Linux 固有であり、その定義を得るには _GNU_SOURCE を定義すること。
AT_NO_AUTOMOUNT (Linux 2.6.38 以降)
pathname がオートマウントポイントとなっているディレクトリの場合、 pathname の最終 ("basename") 要素のオートマウントを行わない。 これにより (マウントされるはずの場所ではなく) オートマウントポイントの属性を取得することができる。 このフラグを使うと、 ディレクトリをスキャンするツールがオートマウントポイントのディレクトリを大量にオートマウントしてしまうのを防ぐことができる。 マウントポイントがすでにマウントされている場合 AT_NO_AUTOMOUNT フラグは何の効果もない。 このフラグは Linux 固有であり、その定義を得るには _GNU_SOURCE を定義すること。
AT_SYMLINK_NOFOLLOW
(lstat() 同様) pathname がシンボリックリンクの場合リンクの展開を行わず、 リンク自身の情報を返す (デフォルトでは、 fstatat() は、 stat() と同様に、シンボリックリンクの展開を行う)。

fstatat() の必要性についての説明については openat(2) を参照。

返り値

成功した場合、0 が返される。 失敗した場合、 -1 が返され、 errno に適切な値がセットされる。

エラー

EACCES
pathname が所属するディレクトリとその上位のディレクトリのいずれかに 対する検索許可がなかった (path_resolution(7) も参照のこと)。
EBADF
fd が不正である。
EFAULT
アドレスが間違っている。
ELOOP
パスを辿る際に解決すべきシンボリックリンクが多過ぎた。
ENAMETOOLONG
pathname が長過ぎる。
ENOENT
pathname の構成要素が存在しないか、 pathname が空文字列である。
ENOMEM
カーネルのメモリが足りない。
ENOTDIR
pathname の前半部分 (prefix) の構成要素がディレクトリではない。
EOVERFLOW
pathname または fd が、ファイルサイズ、inode 番号、ブロック数が それぞれ off_t 型、 ino_t 型、 blkcnt_t 型で表現できないファイルを 参照している。このエラーが起こるのは、例えば、32 ビットプラットフォーム上で -D_FILE_OFFSET_BITS=64 を指定せずにコンパイルされたアプリケーションが、 ファイルサイズが (1<<31)-1 バイトを超えるファイルに対して stat() を呼び出した場合である。

fstatat() では以下のエラーも発生することがある。

EBADF
dirfd が有効なファイルディスクリプタでない。
EINVAL
flags に無効なフラグが指定された。
ENOTDIR
pathname が相対パスで、 dirfd がディレクトリ以外のファイルを参照しているファイルディスクリプタである。

バージョン

fstatat() はカーネル 2.6.16 で Linux に追加された。 ライブラリによるサポートはバージョン 2.4 で glibc に追加された。

準拠

stat(), fstat(), lstat(): SVr4, 4.3BSD, POSIX.1-2001, POSIX.1.2008.

fstatat(): POSIX.1-2008.

POSIX.1-2001 では、シンボリックリンクに対する lstat() で 有効な情報を返すように求められていたのは、 stat 構造体の st_sizest_mode のファイル種別要素だけであった。 POSIX.1-2008 では規定が厳しくなり、 lstat() は st_mode の アクセス許可ビット以外の全てのフィールドに有効な情報を返すことが 求められるようになっている。

st_blocksst_blksize フィールドの使用はあまり移植性がない (これらのフィールドは BSD によって導入された。 システムごとに解釈が 異なっており、 NFS マウントの場合には同じシステムでも異なる可能性がある)。 <sys/stat.h> から blkcnt_tblksize_t 型定義を 読み込みたい場合は、(どのヘッダファイルをインクルードするよりも前に) _XOPEN_SOURCE を 500 以上の値で定義すること。

POSIX.1-1990 には S_IFMT, S_IFSOCK, S_IFLNK, S_IFREG, S_IFBLK, S_IFDIR, S_IFCHR, S_IFIFO, S_ISVTX 定数に関する 記述はなかったが、代わりに S_ISDIR() のようなマクロを使用するように 要求していた。 S_IF* 定数は POSIX.1-2001 以降には存在する。

マクロ S_ISLNK() と S_ISSOCK() は POSIX.1-1996 にはないが、 POSIX.1-2001 には両方とも存在する。 前者は SVID 4 に、後者は SUSv2 に 由来している。

UNIX V7 (とその後のシステム) は S_IREAD, S_IWRITE, S_IEXEC を持っており、 POSIX はその同義語として S_IRUSR, S_IWUSR, S_IXUSR を規定している。

他のシステム

各種システムで使用されていた(いる)値:
16進名前ls8進数説明
f000S_IFMT170000ファイル種別フィールドのビットマスク
0000000000 SCO では 使用不能 inode; BSD では不明なファイル種別; SVID-v2 と XPG2 では 0 と 0100000 の両方が通常のファイル
1000S_IFIFOp|010000FIFO (名前付きパイプ)
2000S_IFCHRc020000キャラクタ特殊ファイル (V7)
3000S_IFMPC030000多重化されたキャラクタ特殊ファイル (V7)
4000S_IFDIRd/040000ディレクトリ (V7)
5000S_IFNAM050000 XENIX の二つの副型を持つ名前付きの特殊ファイル 副型は st_rdev の値 1, 2 で区別される
0001S_INSEMs000001XENIX の IFNAM セマフォ副型
0002S_INSHDm000002XENIX の IFNAM 共有データ副型
6000S_IFBLKb060000ブロック特殊ファイル (V7)
7000S_IFMPB070000多重化されたブロック特殊ファイル (V7)
8000S_IFREG-100000通常ファイル (V7)
9000S_IFCMP110000VxFS 圧縮ファイル
9000S_IFNWKn110000ネットワーク特殊ファイル (HP-UX)
a000S_IFLNKl@120000シンボリックリンク (BSD)
b000S_IFSHAD130000 Solaris の ACL 用の隠し inode (ユーザ空間からは見えない)
c000S_IFSOCKs=140000ソケット (BSD; VxFS の "S_IFSOC")
d000S_IFDOORD>150000Solaris の door ファイル
e000S_IFWHTw%160000BSD の空白ファイル (inode を使用しない)
0200S_ISVTX001000 スティッキービット: 使用後もスワップに残す (V7)
予約 (SVID-v2)
ディレクトリ以外: ファイルをキャッシュしない (SunOS)
ディレクトリの場合: 削除制限フラグ (SVID-v4.2)
0400S_ISGID002000 実行時の set-group-ID (V7)
ディレクトリの場合: GID の伝搬に BSD 方式を使用する
0400S_ENFMT002000 System V ファイルロックを強制する (S_ISGID と共有)
0800S_ISUID004000実行時の set-user-ID (V7)
0800S_CDF004000 ディレクトリがコンテキスト依存ファイル (HP-UX)

スティッキー コマンドは Version 32V AT&T UNIX で登場した。

注意

Linux では、 lstat() は一般には自動マウント動作 (automounter action) の きっかけとならないが、 stat() はきっかけとなる (fstatat(2) を参照)。

/proc ディレクトリ以下にあるファイルのほとんどでは、 stat() を呼び出した際に、 st_size フィールドにファイルサイズが返されない。 代わりに st_size フィールドには 0 が返される。

タイムスタンプフィールド

古いカーネルや古い標準では、ナノ秒精度のタイムスタンプフィールドはサポートされていなかった。 代わりに 3 つの time_t 型のタイムスタンプフィールド st_atime, st_mtime, and st_ctime があった。これらのフィールドには 1 秒単位のタイムスタンプが記録されていた。

カーネル 2.5.48 以降では、 stat 構造体は 3 つのファイルのタイムスタンプ関連のフィールドでナノ秒単位の精度に対応している。 機能検査マクロ _BSD_SOURCE_SVID_SOURCE が定義された場合に、各タイムスタンプのナノ秒の情報は st_atim.tv_nsec という形式の名前で参照できる。 ナノ秒のタイムスタンプは現在では標準化されており、 POSIX.1-2008 からである。 バージョン 2.12 以降の glibc では、 _POSIX_C_SOURCE が 200809L 以上の値で定義されるか、 _XOPEN_SOURCE が 700 以上の値で定義された場合にも、 このナノ秒のタイムスタンプが公開される。 上記のマクロのいずれも定義されていない場合、ナノ秒の値は st_atimensec という形式の名前で公開される。

ナノ秒のタイムスタンプは XFS, JFS, Btrfs, ext4 でサポートされている (Linux 2.6.23 以降)。 ナノ秒のタイムスタンプは ext2, ext3, Resierfs ではサポートされていない。 サブ秒のタイムスタンプをサポートしていないファイルシステムでは、 ナノ秒のフィールドには値 0 が入る。

背後のカーネル・インタフェース

時間の経過とともに、 stat 構造体のサイズが大きくなり、この影響で stat() には 3つのバージョンが存在する: sys_stat() (スロットは __NR_oldstat)、 sys_newstat() (スロットは __NR_stat)、 sys_stat64() (カーネル 2.4 で導入; スロットは __NR_stat64). glibc の stat() ラッパー関数はこれらの詳細をアプリケーションから隠蔽してくれる。 具体的には、カーネルが提供しているシステムコールのうち最新のバージョンを 起動し、古いバイナリの場合には必要に応じて返された情報を再構成 (repack) する。 fstat() と lstat() についても同様である。

glibc の fstatat() ラッパー関数が内部で利用するシステムコールは、実際には fstatat64() である。

以下のプログラムは stat() を呼び出し、返ってきた stat 構造体のフィールドのいくつかを表示する。
#include <sys/types.h>
#include <sys/stat.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
int
main(int argc, char *argv[])
{
    struct stat sb;
    if (argc != 2) {
        fprintf(stderr, "Usage: %s <pathname>\n", argv[0]);
        exit(EXIT_FAILURE);
    }
    if (stat(argv[1], &sb) == -1) {
        perror("stat");
        exit(EXIT_FAILURE);
    }
    printf("File type:                ");
    switch (sb.st_mode & S_IFMT) {
    case S_IFBLK:  printf("block device\n");            break;
    case S_IFCHR:  printf("character device\n");        break;
    case S_IFDIR:  printf("directory\n");               break;
    case S_IFIFO:  printf("FIFO/pipe\n");               break;
    case S_IFLNK:  printf("symlink\n");                 break;
    case S_IFREG:  printf("regular file\n");            break;
    case S_IFSOCK: printf("socket\n");                  break;
    default:       printf("unknown?\n");                break;
    }
    printf("I-node number:            %ld\n", (long) sb.st_ino);
    printf("Mode:                     %lo (octal)\n",
            (unsigned long) sb.st_mode);
    printf("Link count:               %ld\n", (long) sb.st_nlink);
    printf("Ownership:                UID=%ld   GID=%ld\n",
            (long) sb.st_uid, (long) sb.st_gid);
    printf("Preferred I/O block size: %ld bytes\n",
            (long) sb.st_blksize);
    printf("File size:                %lld bytes\n",
            (long long) sb.st_size);
    printf("Blocks allocated:         %lld\n",
            (long long) sb.st_blocks);
    printf("Last status change:       %s", ctime(&sb.st_ctime));
    printf("Last file access:         %s", ctime(&sb.st_atime));
    printf("Last file modification:   %s", ctime(&sb.st_mtime));
    exit(EXIT_SUCCESS);
}

この文書について

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