Provided by: manpages-ja-dev_0.5.0.0.20140515+dfsg-2_all
名前
open, openat, creat - ファイルのオープン、作成を行う
書式
#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> int open(const char *pathname, int flags); int open(const char *pathname, int flags, mode_t mode); int creat(const char *pathname, mode_t mode); int openat(int dirfd, const char *pathname, int flags); int openat(int dirfd, const char *pathname, int flags, mode_t mode); glibc 向けの機能検査マクロの要件 (feature_test_macros(7) 参照): openat(): glibc 2.10 以降: _XOPEN_SOURCE >= 700 || _POSIX_C_SOURCE >= 200809L glibc 2.10 より前: _ATFILE_SOURCE
説明
ファイルの pathname を与えると、 open() はファイルディスクリプタを返す。 ファイルディスク リプタは、この後に続くシステムコール (read(2), write(2), lseek(2), fcntl(2) など) で使用 される小さな非負の整数である。 このシステムコールが成功した場合に返されるファイルディスク リプタは そのプロセスがその時点でオープンしていないファイルディスクリプタの うち最小の数字 のものとなる。 デフォルトでは、新しいファイルディスクリプタは execve(2) を実行した後も オープンされたまま となる (つまり、 fcntl(2) に説明がある FD_CLOEXEC ファイルディスクリプタフラグは最初は無効 である; 後述の O_CLOEXEC フラグ を使うとこのデフォルトを変更することができる)。 ファイルオ フセット (file offset) はファイルの先頭に設定される (lseek(2) 参照)。 open() を呼び出すと、「オープンファイル記述」 (open file description) が作成される。ファ イル記述とは、システム全体の オープン中のファイルのテーブルのエントリである。 このエントリ は、ファイルオフセットとファイル状態フラグ (fcntl(2) F_SETFL 操作により変更可能) が保持す る。 ファイルディスクリプタはこれらのエントリの一つへの参照である。 この後で pathname が削 除されたり、他のファイルを参照するように変更されたりしても、 この参照は影響を受けない。 新 しいオープンファイル記述は最初は他のどのプロセスとも 共有されていないが、 fork(2) で共有 が起こる場合がある。 引き数 flags には、アクセスモード O_RDONLY, O_WRONLY, O_RDWR のどれかひとつが入っていなけ ればならない。 これらはそれぞれ読み込み専用、書き込み専用、読み書き用に ファイルをオープン することを要求するものである。 さらに、 flags には、ファイル作成フラグ (file creation flag) とファイル状態フラグ (file status flag) を 0 個以上「ビット単位の OR (bitwise-or)」で 指定することができる。 ファイル 作成フラグ は O_CLOEXEC, O_CREAT, O_DIRECTORY, O_EXCL, O_NOCTTY, O_NOFOLLOW, O_TMPFILE, O_TRUNC, O_TTY_INIT である。 ファイル状態フラグ は以下のリストのうち上記以外の残りのもので ある。 二種類のフラグの違いは、ファイル状態フラグの方はその内容を取得したり (場合によって は) 変更したりできる点にある。詳細は fcntl(2) を参照。 すべてのファイル作成フラグとファイル状態フラグを以下のリストに示す。 O_APPEND ファイルを追加 (append) モードでオープンする。 毎回の write(2) の前に lseek(2) を 行ったかのように、ファイルポインタをファイルの最後に移動する。 NFS ファイルシステム で、 O_APPEND を使用すると、複数のプロセスがひとつのファイルに同時にデータを追加し た場合、 ファイルが壊れてしまうことがある。 これは NFS が追加モードをサポートしてい ないため、 クライアントのカーネル (kernel) がそれをシミュレートしなければならないの だが、 競合状態を避けることはできないからである。 O_ASYNC シグナル駆動 I/O (signal-driven I/O) を有効にする: このファイルディスクリプタへの 入力または出力が可能になった場合に、シグナルを生成する (デフォルトは SIGIO である が、 fcntl(2) によって変更可能である)。 この機能が使用可能なのは端末、疑似端末、ソ ケットのみであり、 (Linux 2.6 以降では) パイプと FIFO に対しても使用できる。 さらに 詳しい説明は fcntl(2) を参照すること。 下記の「バグ」も参照。 O_CLOEXEC (Linux 2.6.23 以降) 新しいファイルディスクリプタに対して close-on-exec フラグを有効にする。 このフラグ を指定することで、 プログラムは FD_CLOEXEC フラグをセットするために fcntl(2) F_SETFD 操作を別途呼び出す必要がなくなる。 ある種のマルチスレッドのプログラムはこのフラグの使用は不可欠である点に注意するこ と。 なぜなら、個別に FD_CLOEXEC フラグを設定する fcntl(2) F_SETFD 操作を呼び出した としても、あるスレッドがファイルディスクリプタを オープンするのと同時に別のスレッド が fork(2) と execve(2) を実行するという競合条件を避けるのには十分ではないからであ る。 実行の順序に依存して、この競合条件の結果、 open() が返したファイルディスクリプ タが fork(2) で作成された子プロセスにより実行されるプログラムに意図せず見えてしまう 可能性がある。 (この種の競合は、 本質的に、 close-on-exec フラグをセットすべきファ イルディスクリプタを作成するどのシステムコールでも起こり得るものであり、 他のいろい ろな Linux システムコールでこの問題に対処するために O_CLOEXEC と同等の機能が提供さ れている。) O_CREAT ファイルが存在しなかった場合は作成 (create) する。 ファイルの所有者 (ユーザー ID) は、プロセスの実効ユーザー ID に設定される。 グループ所有権 (グループ ID) は、プロ セスの実効グループ ID または親ディレクトリのグループ ID に設定される (これは、ファ イルシステムタイプ、マウントオプション、 親ディレクトリのモードに依存する。 mount(8) で説明されているマウントオプション bsdgroups と sysvgroups を参照)。 mode は新しいファイルを作成する場合に使用するアクセス許可 (permission) を指定する。 flags に O_CREAT か O_TMPFILE が指定されている場合、 mode を指定しなければならな い。 O_CREAT も O_TMPFILE も指定されていない場合、 mode は無視される。 有効なアクセ ス許可は、普段と同じようにプロセスの umask によって修正され、作成されたファイルの許 可は (mode & ~umask) となる。 このモードは、新しく作成されたファイルに対するそれ以 降のアクセス にのみ適用される点に注意すること。 読み取り専用のファイルを作成する open() コールであっても、 読み書き可能なファイルディスクリプタを返すことがありう る。 mode のために以下のシンボル定数が提供されている : S_IRWXU 00700 ユーザー (ファイルの所有者) に読み込み、書き込み、 実行の許可があ る。 S_IRUSR 00400 ユーザーに読み込みの許可がある。 S_IWUSR 00200 ユーザーに書き込みの許可がある。 S_IXUSR 00100 ユーザーに実行の許可がある。 S_IRWXG 00070 グループに読み込み、書き込み、実行の許可がある。 S_IRGRP 00040 グループに読み込みの許可がある。 S_IWGRP 00020 グループに書き込みの許可がある。 S_IXGRP 00010 グループに実行の許可がある。 S_IRWXO 00007 他人 (others) に読み込み、書き込み、実行の許可がある。 S_IROTH 00004 他人に読み込みの許可がある。 S_IWOTH 00002 他人に書き込みの許可がある。 S_IXOTH 00001 他人に実行の許可がある。 O_DIRECT (Linux 2.4.10 以降) このファイルに対する I/O のキャッシュの効果を最小化しようとする。このフラグを使う と、一般的に性能が低下する。 しかしアプリケーションが独自にキャッシングを行っている ような 特別な場合には役に立つ。 ファイルの I/O はユーザー空間バッファに対して直接行 われる。 O_DIRECT フラグ自身はデータを同期で転送しようとはするが、 O_SYNC フラグの ようにデータと必要なメタデータの転送が保証されるわけではない。同期 I/O を保証するた めには、 O_DIRECT に加えて O_SYNC を使用しなければならない。下記の「注意」の節の議 論も参照。 ブロックデバイスに対する似通った意味のインターフェースが raw(8) で説明されている (但し、このインタフェースは非推奨である)。 O_DIRECTORY pathname がディレクトリでなければオープンは失敗する。 このフラグは、 opendir(3) が FIFO やテープデバイスに対してコールされた場合の サービス不能 (denial-of-service) 攻 撃を避けるために カーネル 2.1.126 で追加された。 O_DSYNC ファイルに対する書き込み操作は、同期 I/O のデータ完全性完了の要件に基づいて行われ る。 write(2) (や同様のコール) が返るまでに、 書き込まれたデータおよびデータを取得するの に必要なファイルメタデータが裏で利用されているハードウェアに転送される (つま り、write(2) の後に fdatasync(2) を呼び出したのと同じようになる)。 下記の「注意」も 参照のこと。 O_EXCL この呼び出しでファイルが作成されることを保証する。このフラグが O_CREAT と 一緒に指 定され、 pathname のファイルが既に存在した場合、 open() は失敗 する。 これら二つのフラグが指定された際、シンボリックリンクは辿られない。 pathname がシン ボリックリンクの場合、 シンボリックリンクがどこを指しているかに関わらず open() は 失敗する。 一般的には、 O_CREAT を指定せずに O_EXCL を使用した場合の O_EXCL の動作は規定されて いない。 これには一つ例外があり、Linux 2.6 以降では、 pathname がブロックデバイスを 参照している場合、 O_CREAT なしで O_EXCL を使用することができる。 システムがそのブ ロックデバイスを使用中の場合 (例えば、 マウントされているなど)、 open() はエラー EBUSY で失敗する。 NFS では、 O_EXCL は、Linux 2.6 以降で NFSv3 以降を使っている場合でのみサポートされ る。 O_EXCL サポートが提供されていない NFS 環境では、このフラグに頼って ロック処理 を実行するプログラムは競合状態 (race condition) に出会う 可能性がある。 ロックファ イルを使用して不可分 (atomic) なファイルロックを実現し、 NFS が O_EXCL をサポートし ているかに依存しないようにしたい場合、 移植性のある方法は、同じファイルシステム上に 他と名前の重ならない ファイル (例えばホスト名と PID を組み合わせた名前) を作成し、 link(2) を使用してそのロックファイルへのリンクを作成することである。 link(2) コー ルの返り値が 0 ならばロックに成功している。 あるいは、そのファイルに stat(2) を使 用してリンク数 (link count) が 2 になっているかをチェックする。 そうなっていれ ば、同じくロックに成功しているということである。 O_LARGEFILE (LFS) off_t ではサイズを表せない (だだし off64_t ではサイズを表せる)ファ イルをオー プン可能にする。この定義を有効にするためには、(どのヘッダファイ ルをインクルードす るよりも前に) _LARGEFILE64_SOURCE マクロを定義しなければ ならない。 32 ビットシステ ムにおいて大きなファイルにアクセスしたい場合、 (O_LARGEFILE を使うよりも) _FILE_OFFSET_BITS 機能検査マクロを 64 に セットする方が望ましい方法である (feature_test_macros(7) を参照)。 O_NOATIME (Linux 2.6.8 以降) ファイルに対して read(2) が実行されたときに、最終アクセス時刻 (inode の st_atime) を更新しない。 このフラグはインデックス作成やバックアッププログラムで使うことを意図 している。 これを使うとディスクに対する操作を大幅に減らすことができる。 このフラグ は全てのファイルシステムに対して有効であるわけではない。 その一例が NFS であ り、サーバがアクセス時刻を管理している。 O_NOCTTY pathname が端末 (terminal) デバイス — tty(4) 参照 — を指している 場合に、たとえその プロセスが制御端末を持っていなくても、オープンしたファイル は制御端末にはならない。 O_NOFOLLOW pathname がシンボリックリンクだった場合、オープンは失敗する。 これは FreeBSD の拡張 で、Linux には バージョン 2.1.126 で追加された。 このフラグが指定された場合でも pathname の前の方の要素 (最後のディレクトリセパレータより前の部分) にあるシンボリッ クリンクについてはリンクが辿られる。 下記の O_PATH も参照のこと。 O_NONBLOCK または O_NDELAY 可能ならば、ファイルは非停止 (nonblocking) モードでオープンされる。 open() も、返し たファイルディスクリプタに対する以後のすべての操作も呼び出 したプロセスを待たせるこ とはない。 FIFO (名前付きパイプ) を扱う場合には fifo(7) も参照すること。 強制ファイ ルロック (mandatory file lock) やファイ ルリース (file lease) と組み合わせた場合 の、 O_NONBLOCK の効果についての 議論は、 fcntl(2) を参照すること。 O_PATH (Linux 2.6.39 以降) このフラグを指定して取得したファイルディスクリプタは、 ファイルシステムツリー内での 場所を示すため、 純粋にファイルディスクリプタレベルでの作用する操作を実行するため、 の二つの目的で使用することができる。 ファイル自身はオープンされず、 他のファイル操 作 (例えば read(2), write(2), fchmod(2), fchown(2), fgetxattr(2), mmap(2)) はエラー EBADF で失敗する。 取得したファイルディスクリプタに対して以下の操作を行うことが「できる」。 * close(2); fchdir(2) (Linux 3.5 以降); fstat(2) (Linux 3.6 以降) * ファイルディスクリプタの複製 (dup(2), fcntl(2) F_DUPFD など) * ファイルディスクリプタフラグの取得と設定 (fcntl(2) の F_GETFD と F_SETFD) * fcntl(2) の F_GETFL 操作を使ったオープンされたファイルの状態フラグの取得。 返さ れるフラグには O_PATH ビットが含まれる。 * openat(2) や他の "*at()" 系のシステムコールの dirfd 引数としてそのファイルディス クリプタを渡す。 * そのファイルディスクリプタを別のプロセスに UNIX ドメインソケット経由で渡す。 (unix(7) の SCM_RIGHTS を参照) flags に O_PATH が指定された場合、 O_DIRECTORY と O_NOFOLLOW 以外のフラグビットは無 視される。 pathname がシンボリックリンクで O_NOFOLLOW フラグも合わせて指定された場合、 この呼 び出しではシンボリックリンクを参照するファイルディスクリプタを返す。 このファイル ディスクリプタは、 空のパス名を指定した fchownat(2), fstatat(2), linkat(2), readlinkat(2) の呼び出しで dirfd 引数として使うことで、 そのシンボリックリンクに対 して操作を行うことができる。 O_SYNC ファイルに対する書き込み操作は、同期 I/O のファイル完全性完了の要件に基づいて行われ る (これに対し O_DSYNC では同期 I/O のデータ完全性完了が提供される)。 write(2) (や同様のコール) が返るまでに、 書き込まれたデータと関連するファイルメタ データが裏で利用されているハードウェアに転送される (つまり、write(2) の後に fsync(2) を呼び出したのと同じようになる)。 下記の「注意」も参照のこと。 O_TMPFILE (Linux 3.11 以降) 名前なしの一時ファイルを作成する。 pathname 引き数はディレクトリを指定する。 名前な しの inode がそのディレクトリが存在するファイルシステムに作成される。 そのファイル に名前を付与しない限り、 作成されたファイルに書き込まれた内容は、 最後のファイル ディスクリプタがクローズされる際に失われる。 O_TMPFILE は必ず O_RDWR か O_WRONLY のいずれかと一緒に使わなければならない。 O_EXCL も指定することができる。 O_EXCL が指定されなかった場合、 linkat(2) を使って、その ファイルシステムにこの一時ファイルへのリンクを作成し、ファイルを永続化することがで きる。 以下のコードのようにすればよい。 char path[PATH_MAX]; fd = open("/path/to/dir", O_TMPFILE | O_RDWR, S_IRUSR | S_IWUSR); /* 'fd' に対するファイル I/O ... */ snprintf(path, PATH_MAX, "/proc/self/fd/%d", fd); linkat(AT_FDCWD, path, AT_FDCWD, "/path/for/file", AT_SYMLINK_FOLLOW); この場合、 open() の mode 引き数は O_CREAT と同様にファイルのアクセス許可モードの決 定に使われる。 O_TMPFILE とともに O_EXCL を指定すると、 一時ファイルに対して上記の方法でファイルシ ステムへのリンクを行うことができなくなる (この場合の O_EXCL の意味は他の場合の O_EXCL の意味とは異なる点に注意)。 O_TMPFILE には主に二つの用途がある。 * 改善された tmpfile(3) の機能: (1) クローズ時に自動的に削除される、 (2) パス名で は決して参照できない、 (3) シンボリックリンク攻撃ができない、 (4) 呼び出し元が一 意な名前を考える必要がない、 という特長を持つ競合のない一時ファイルの作成。 * 最初は見えないファイルを作成し、 それからデータを書き込んだり、適切なファイルシ ステム属性を持つように調整したり (chown(2), chmod(2), fsetxattr(2) など) した 後、 準備が全て整った状態で (上述の linkat(2) を使って) ファイルシステム内にアト ミックにリンクを行う。 O_TMPFILE は、 裏で利用されるファイルシステムによるサポートが必要である。 一部の Linux ファイルシステムだけがこの機能をサポートしている。 最初の実装では、 ext2, ext3, ext4, UDF, Minix, shmem ファイルシステムがサポートしていた。 XFS でのサポート が Linux 3.15 で追加された。 O_TRUNC ファイルが既に存在し、通常ファイルであり、 アクセスモードで書き込みが許可されている (つまり、 O_RDWR または O_WRONLY の) 場合、長さ 0 に切り詰め (truncate) られる。 ファイルが FIFO または端末デバイスファイルの場合、 O_TRUNC フラグは無視される。 そ れ以外の場合、 O_TRUNC の効果は未定義である。 creat() creat() は flags に O_CREAT|O_WRONLY|O_TRUNC を指定して open() を行うのと等価である。 openat() openat() システムコールは open() と全く同様に動作するが、以下で説明する点が異なる。 pathname で指定されたパス名が相対パスの場合、このパス名はファイルディスクリプター dirfd が 参照するディレクトリに対する相対パスと解釈される (open() に相対パス名を渡した場合のよう に、呼び出したプロセスのカレントワーキングディレクトリに対する相対パスではない)。 pathname で指定されたパス名が相対パスで、 dirfd が特別な値 AT_FDCWD の場合、 (open() と同 様に) pathname は呼び出したプロセスのカレントワーキングディレクトリに対する相対パスと解釈 される。 pathname で指定されたパス名が絶対パスの場合、 dirfd は無視される。
返り値
open(), openat(), creat() は新しいファイルディスクリプタを返す。 エラーが発生した場合は -1 を返す (その場合は errno が適切に設定される)。
エラー
open(), openat(), creat() は以下のエラーで失敗する。 EACCES ファイルに対する要求されたアクセスが許されていないか、 pathname のディレクトリ部分 の何れかのディレクトリに検索許可がなかった。 またはファイルが存在せず、親ディレクト リへの書き込み許可がなかった。 (path_resolution(7) も参照すること。) EDQUOT O_CREAT が指定された場合で、そのファイルが存在せず、ディスクブロックか inode がその ファイルシステムのユーザクォータに達していた。 EEXIST pathname は既に存在し、 O_CREAT と O_EXCL が使用された。 EFAULT pathname がアクセス可能なアドレス空間の外を指している。 EFBIG EOVERFLOW 参照。 EINTR 遅いデバイス (例えば FIFO、 fifo(7) 参照) のオープンが完了するのを待って停止してい る間に システムコールがシグナルハンドラにより割り込まれた。 signal(7) 参照。 EINVAL ファイルシステムが O_DIRECT フラグをサポートしていない。 詳細は注意を参照。 EINVAL flags に無効な値が入っている。 EINVAL flags に O_TMPFILE が指定されたが、 O_WRONLY も O_RDWR も指定されていなかった。 EISDIR pathname はディレクトリを参照しており、書き込み要求が含まれていた (つまり O_WRONLY または O_RDWR が設定されている)。 EISDIR pathname が存在するディレクトリを参照していて、 O_TMPFILE および O_WRONLY と O_RDWR の一方が flags に指定されていたが、 このカーネルバージョンでは O_TMPFILE 機能が提供 されていない。 ELOOP pathname を解決する際に遭遇したシンボリックリンクが多過ぎる。 ELOOP pathname がシンボリックリンクで、 flags に O_NOFOLLOW が指定されたが、 O_PATH が指 定されていなかった。 EMFILE プロセスがオープンしているファイル数がすでに最大数に達している。 ENAMETOOLONG pathname が長過ぎる。 ENFILE オープンされているファイルの総数がシステムの制限に達している。 ENODEV pathname がデバイススペシャルファイルを参照しており、対応するデバイスが存在しない。 (これは Linux カーネルのバグであり、この場合には ENXIO が返されるべきである) ENOENT O_CREAT が設定されておらず、かつ指定されたファイルが存在しない。 または、 pathname のディレクトリ部分が存在しないか壊れた (dangling) シンボリックリンクである。 ENOENT pathname が存在しないディレクトリを参照していて、 O_TMPFILE および O_WRONLY と O_RDWR の一方が flags に指定されていたが、 このカーネルバージョンでは O_TMPFILE 機 能が提供されていない。 ENOMEM 十分なカーネルメモリーがない。 ENOSPC pathname を作成する必要があるが、 pathname を含んでいるデバイスに新しいファイルのた めの空き容量がない。 ENOTDIR pathname に含まれるディレクトリ部分のどれかが実際にはディレクトリでない。 または O_DIRECTORY が指定されており、 pathname がディレクトリでない。 ENXIO O_NONBLOCK | O_WRONLY が設定されており、指定したファイルが FIFO で そのファイルを読 み込みのためにオープンしているプロセスが存在しない。 または、ファイルがデバイススペ シャルファイルで 対応するデバイスが存在しない。 EOPNOTSUPP pathname を含んでいるファイルシステムが O_TMPFILE をサポートしていない。 EOVERFLOW pathname が参照しているのが、大き過ぎてオープンできない通常のファイルである。 通 常、このエラーが発生するは、32 ビットプラットフォーム上で -D_FILE_OFFSET_BITS=64 を 指定せずにコンパイルされたアプリケーションが、ファイルサイズが (2<31)-1 ビットを超 えるファイルを開こうとした場合である。 上記の O_LARGEFILE も参照。 これは POSIX.1-2001 で規定されているエラーである。 2.6.24 より前のカーネルでは、Linux はこ の場合にエラー EFBIG を返していた。 EPERM O_NOATIME フラグが指定されたが、呼び出し元の実効ユーザー ID が ファイルの所有者と一 致せず、かつ呼び出し元に特権 (CAP_FOWNER) がない。 EROFS pathname が読み込み専用のファイルシステム上のファイルを参照しており、 書き込みアク セスが要求された。 ETXTBSY pathname が現在実行中の実行イメージを参照しており、書き込みが要求された。 EWOULDBLOCK O_NONBLOCK フラグが指定されたが、そのファイルには矛盾するリースが設定されていた (fcntl(2) 参照)。 openat() では以下のエラーも発生する。 EBADF dirfd が有効なファイルディスクリプタではない。 ENOTDIR pathname が相対パスで、 dirfd がディレクトリ以外のファイルを参照しているファイル ディスクリプタである。
バージョン
openat() はカーネル 2.6.16 で Linux に追加された。 ライブラリによるサポートはバージョン 2.4 で glibc に追加された。
準拠
open(), creat() SVr4, 4.3BSD, POSIX.1-2001, POSIX.1-2008. openat(): POSIX.1-2008. フラグ O_DIRECT, O_NOATIME, O_PATH, O_TMPFILE は Linux 特有のものである。 これらのフラグの 定義を得るためには _GNU_SOURCE を定義しなければならない。 フラグ O_CLOEXEC, O_DIRECTORY, O_NOFOLLOW は POSIX.1-2001 では規定されていないが、 POSIX.1-2008 では規定されている。 glibc 2.12 以降では、これらの定義を得るには、 _POSIX_C_SOURCE を 200809L 以上の値で定義するか、 _XOPEN_SOURCE を 700 以上の値で定義す る。 glibc 2.11 以前では、 これらの定義を得るには _GNU_SOURCE を定義する。 feature_test_macros(7) に注意書きがあるように、 _POSIX_C_SOURCE, _XOPEN_SOURCE, _GNU_SOURCE などの機能検査マクロはどのヘッダーファイルをインクルードするより前に定義しなけ ればならない。
注意
Linux では、 O_NONBLOCK フラグは、 open を実行したいが read または write を実行する意図は 必ずしもないことを意味する。 これは ioctl(2) のためのファイルディスクリプタを取得するため に、 デバイスをオープンするときによく用いられる。 O_RDONLY | O_TRUNC の影響は未定義であり、その動作は実装によって異なる。 多くのシステムでは ファイルは実際に切り詰められる。 open() はスペシャルファイルをオープンすることができるが、 creat() でスペシャルファイルを 作成できない点に注意すること。 代わりに mknod(2) を使用する。 ファイルが新しく作成されると、 ファイルの st_atime, st_ctime, st_mtime フィールド (それぞ れ最終アクセス時刻、最終状態変更時刻、最終修正時刻である。 stat(2) 参照) が現在時刻に設定 される。 さらに親ディレクトリの st_ctime と st_mtime も現在時刻に設定される。 それ以外の場 合で、O_TRUNC フラグでファイルが修正されたときは、 ファイルの st_ctime と st_mtime フィー ルドが現在時刻に設定される。 同期 I/O POSIX.1-2008 の「同期 I/O」の選択肢として複数種類が規定されており、 動作を制御するために open() フラグとして O_SYNC, O_DSYNC, O_RSYNC が規定されている。 この選択肢を実装がサポート しているかに関わらず、 各実装では少なくとも通常のファイルに対して O_SYNC が利用できなけれ ばならない。 Linux は O_SYNC と O_DSYNC を実装しているが、 O_RSYNC は実装していない (少し間違っているの だが、 glibc では O_RSYNC が O_SYNC と同じ値で定義されている)。 O_SYNC は、 同期 I/O でのファイル完全性完了を提供する。 つまり、 書き込み操作はデータとす べての関連メタデータを裏で利用されているハードウェアにフラッシュすることを意味する。 O_DSYNC は、 同期 I/O でのデータ完全性完了を提供する。 つまり、 書き込み操作はデータを裏で 利用されているハードウェアにフラッシュするが、 それ以降の読み出し操作が正常に完了するのに 必要なメタデータの更新のみをフラッシュする。 データ完全性完了は、 ファイル完全性完了を必要 としないアプリケーションで、 ディスク操作の数を減らすことができる。 2 種類の完了の違いを理解するために、 ファイルメタデータの 2 つの要素、 ファイルの最終修正 時刻 (st_mtime) とファイル長、を考える。 すべての書き込み操作は最終修正時刻を更新するが、 ファイルの末尾にデータを追加する書き込み操作のみがファイル長を変更する。 最終修正時刻は、 読み出しが正常に完了するのに必要ではないが、 ファイル長は必要である。 したがって、 O_DSYNC はファイル長のメタデータの更新がフラッシュされることだけを保証する (これに対して O_SYNC で は最終修正時刻のメタデータも常にフラッシュされる)。 Linux 2.6.33 より前では、 Linux は open() では O_SYNC フラグのみを実装していた。 しかしな がら、 このフラグが指定された場合、 ほとんどのファイルシステムで提供されていたのは実際には 同期 I/O でのデータ完全性完了と等価なものであった (つまり、 O_SYNC は実際には O_DSYNC と等 価なものとして実装されていた)。 Linux 2.6.33 行こう では、 正しい O_SYNC のサポートが提供されている。 しかしながら、 バイ ナリレベルの後方互換性を保証するため、 O_DSYNC は以前の O_SYNC と同じ値で定義されており、 O_SYNC は O_DSYNC フラグの値を含む新しい (2 ビットの) フラグ値として定義されている。 これ により、 新しいヘッダを使ってコンパイルされたアプリケーションで、 2.6.33 より前のカーネル で少なくとも O_DSYNC の動作は同じになることが保証される。 NFS NFS を実現しているプロトコルには多くの不備があり、特に O_SYNC と O_NDELAY に影響する。 UID マッピングを使用している NFS ファイルシステムでは、 open() がファイルディスクリプタを 返した場合でも read(2) が EACCES で拒否される場合がある。 これはクライアントがアクセス許可 のチェックを行って open() を実行するが、読み込みや書き込みの際には サーバーで UID マッピン グが行われるためである。 ファイルアクセスモード 「アクセスモード」の値 O_RDONLY, O_WRONLY, O_RDWR は、 flags に指定できる他の値と違 い、個々のビットを指定するものではなく、 これらの値は flags の下位 2 ビットを定義する。 O_RDONLY, O_WRONLY, O_RDWR はそれぞれ 0, 1, 2 に定義されている。 言い換えると、 O_RDONLY | O_WRONLY の組み合わせは論理的に間違いであり、確かに O_RDWR と同じ意味ではない。 Linux では、特別な、非標準なアクセスモードとして 3 (バイナリでは 11) が 予約されており flags に指定できる。 このアクセスモードを指定すると、ファイルの読み出し/書き込み許可を チェックし、 読み出しにも書き込みにも使用できないディスクリプタを返す。 この非標準のアクセ スモードはいくつかの Linux ドライバで、デバイス固有の ioctl(2) 操作にのみ使用されるディス クリプタを返すために使われている。 openat() や他のディレクトリファイルディスクリプタ API の基本原理 openat() やディレクトリファイルディスクリプタを引き数を取る他のシステムコールやライブラリ 関数 (faccessat(2), fanotify_mark(2), fchmodat(2), fchownat(2), fstatat(2), futimesat(2), linkat(2), mkdirat(2), mknodat(2), name_to_handle_at(2), readlinkat(2), renameat(2), symlinkat(2), unlinkat(2), utimensat(2) mkfifoat(3), scandirat(3)) は二つの理由から用意さ れている。 ここでは、 openat コールに関して説明するが、この基本原理は他のインターフェース でも同じである。 最初の理由として、 openat() を使うと、 アプリケーションは、 カレントワーキングディレクトリ 以外のディレクトリで open() を使ってファイルをオープンする際に起こり得る競合条件を避けるこ とができる。 これらの競合条件は、 open() に渡されたディレクトリプレフィックスの構成要素が open() の呼び出しと並行して変化する可能性があるという点に由来している。 このような競合条件 は、 対象のディレクトリに対するファイルディスクリプタをオープンし、 それから openat() の dirfd 引き数としてそのファイルディスクリプタを指定することで、 避けることができる。 二つ目として、 openat() を使うと、アプリケーションが管理するファイルディスクリプタにより、 スレッド単位の「カレントワーキングディレクトリ」を実装することができる (この機能は、 /proc/self/fd/dirfd を使った方法でも実現することができるが、 効率の面で落とる)。 O_DIRECT O_DIRECT フラグを使用する場合、ユーザ空間バッファの長さやアドレス、 I/O のファイルオフセッ トに関してアラインメントの制限が課されることがある。 Linux では、アラインメントの制限は ファイルシステムやカーネルのバージョンに よって異なり、全く制限が存在しない場合もある。 し かしながら、現在のところ、指定されたファイルやファイルシステムに対して こうした制限がある かを見つけるための、アプリケーション向けのインタフェースで ファイルシステム非依存のものは 存在しない。 いくつかのファイルシステムでは、制限を確認するための独自のインタフェースが 提 供されている。例えば、 xfsctl(3) の XFS_IOC_DIOINFO 命令である。 Linux 2.4 では、転送サイズ、 ユーザーバッファのアラインメント、ファイルオフセットは、 ファ イルシステムの論理ブロックサイズの倍数でなければならない。 Linux 2.6 では、512 バイトごと の境界に配置されていれば充分である。 メモリバッファがプライベートマッピング (mmap(2) の MAP_PRIVATE フラグで作成されたマッピン グ) の場合には、O_DIRECT I/O は fork(2) システムコールと同時に決して実行すべきではない (プ ライベートマッピングには、ヒープ領域に割り当てられたメモリや静的に 割り当てたバッファも含 まれる)。非同期 I/O インターフェース (AIO) 経由 やプロセス内の他のスレッドから発行され た、このような I/O は、 fork(2) が呼び出される前に完了されるべきである。 そうしなかった場 合、データ破壊や、親プロセスや子プロセスでの予期しない 動作が起こる可能性がある。 O_DIRECT I/O 用のメモリバッファが shmat(2) やMAP_SHARED フラグ 付きの mmap(2) で作成された場合に は、この制限はあてはまらない。 madvise(2) でメモリバッファにアドバイス MADV_DONTFORK が設 定され ている場合にも、この制限はあてはまらない(MADV_DONTFORK はそのメモリ バッファが fork(2) 後に子プロセスからは利用できないことを保証するも のである)。 O_DIRECT フラグは SGI IRIX で導入された。SGI IRIX にも Linux 2.4 と同様の (ユーザーバッ ファの) アラインメントの制限がある。 また、IRIX には適切な配置とサイズを取得するための fcntl(2) コールがある。 FreeBSD 4.x も同じ名前のフラグを導入したが、アラインメントの制限 はない。 O_DIRECT が Linux でサポートされたのは、カーネルバージョン 2.4.10 である。 古い Linux カー ネルは、このフラグを単に無視する。 O_DIRECT フラグをサポートしていないファイルシステムもあ り、その場合は、 O_DIRECT を使用すると open() は EINVAL で失敗する。 アプリケーションは、同じファイル、 特に同じファイルの重複するバイト領域に対して、 O_DIRECT と通常の I/O を混ぜて使うのは避けるべきである。 ファイルシステムがこのような状況において一 貫性の問題を正しく 扱うことができる場合であっても、全体の I/O スループットは どちらか一方 を使用するときと比べて低速になるであろう。 同様に、アプリケーションは、同じファイルに対し て mmap(2) と直接 I/O (O_DIRECT) を混ぜて使うのも避けるべきである。 NFS で O_DIRECT を使った場合の動作はローカルのファイルシステムの場合と違う。 古いカーネル や、ある種の設定でコンパイルされたカーネルは、 O_DIRECT と NFS の組み合わせをサポートして いないかもしれない。 NFS プロトコル自体はサーバにフラグを渡す機能は持っていないので、 O_DIRECT I/O はクライアント上のページキャッシュをバイパスするだけになり、 サーバは I/O を キャッシュしているかもしれない。 クライアントは、 O_DIRECT の同期機構を保持するため、サー バに対して I/O を同期して行うように依頼する。 サーバによっては、こうした状況下、特に I/O サイズが小さい場合に 性能が大きく劣化する。 また、サーバによっては、I/O が安定したストレー ジにまで行われたと、 クライアントに対して嘘をつくものもある。 これは、サーバの電源故障が起 こった際にデータの完全性が保たれない 危険は少しあるが、性能面での不利な条件を回避するため に行われている。 Linux の NFS クライアントでは O_DIRECT I/O でのアラインメントの制限はな い。 まとめると、 O_DIRECT は、注意して使うべきであるが、強力なツールとなる可能性を持っている。 アプリケーションは O_DIRECT をデフォルトでは無効になっている性能向上のためのオプションと 考えておくのがよいであろう。 「O_DIRECT でいつも困るのは、インタフェース全部が本当にお馬鹿な点だ。 たぶん危ない マインドコントロール剤で 頭がおかしくなったサルが設計したんじゃないかな」 — Linus
バグ
現在のところ、 open() の呼び出し時に O_ASYNC を指定してシグナル駆動 I/O を有効にすること はできない。 このフラグを有効にするには fcntl(2) を使用すること。 カーネルが O_TMPFILE 機能をサポートしているかを判定する際に、 EISDIR と ENOENT の 2 つのエ ラーコードをチェックしなければならない。
関連項目
chmod(2), chown(2), close(2), dup(2), fcntl(2), link(2), lseek(2), mknod(2), mmap(2), mount(2), open_by_name_at(2), read(2), socket(2), stat(2), umask(2), unlink(2), write(2), fopen(3), fifo(7), path_resolution(7), symlink(7)
この文書について
この man ページは Linux man-pages プロジェクトのリリース 3.65 の一部 である。プロジェクト の説明とバグ報告に関する情報は http://www.kernel.org/doc/man-pages/ に書かれている。