lseek(2) ファイルの読み書きオフセットの位置を変える

書式

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

off_t lseek(int fd, off_t offset, int whence);

説明

lseek() 関数は、ファイルディスクリプタ (descriptor) fd に対応するオープンされたファイルのオフセットを、 whence に基づき offset 引き数の位置へ以下のように変更する:
SEEK_SET
オフセットは offset バイトに設定される。
SEEK_CUR
オフセットは現在位置に offset バイトを足した位置になる。
SEEK_END
オフセットはファイルのサイズに offset バイトを足した位置になる。

lseek() 関数は、オフセットをファイルの末尾を越えた位置に設定できる (但し、これによりファイルのサイズが変わらない)。 もしデータがこのオフセット位置以降に書き込まれた場合、 間の空隙の部分 ("穴 (hole)") の読み出しがあると、 実際にそこにデータを書き込まれるまではヌルバイト ('\0') の列が返される。

ファイルのデータとホールの探索

Linux バージョン 3.1 以降では、 whence に以下の値も指定することができる。
SEEK_DATA
ファイルオフセットを offset 以上で次にデータがある位置に設定する。 offset がデータを指している場合には、 ファイルオフセットは offset に設定される。
SEEK_HOLE
ファイルオフセットを、 位置が offset 以上の次のホール (hole) に設定する。 offset がホールの内部にある場合は、ファイルシステムは offset に設定される。 offset 以降にホールがない場合は、 ファイルオフセットはファイル末尾に設定される (つまり、 どのファイルの末尾にも暗黙のホールが存在するということだ)。

上記のどちらの場合も、 offset がファイル末尾よりも先を指している場合には lseek() は失敗する。

これらの操作を使うことで、 アプリケーションが、 まばら (sparse ) にページが割り当てられたファイルでホールをマップすることができる。 この機能はファイルバックアップツールなどのアプリケーションで有用である。 ホールを見つける仕組みがあれば、 ファイルバックアップツールで、 バックアップを作成する際に保存領域を節約し、ホールを保持することができる。

これらの操作の目的としては、 ホールは (通常は) バックエンドのファイルストレージには割り当てられていない連続する 0 の列である。 しかし、ファイルシステムにはホールを報告する義務はなく、 そのため、 これらの操作は、 ファイルに実際に割り当てられたストレージ領域をマッピングする方法としては確実性のある仕組みではない。 (また、バックエンドのストレージに実際に書き込まれた連続する 0 の列はホールとして報告されないこともある。) 最も単純な実装としては、 SEEK_HOLE は常にファイル末尾のオフセットを返すようにし、 SEEK_DATA は常に offset を返すようにすることで、 ファイルシステムはこれらの操作をサポートすることができる (SEEK_DATA は常に offset を返すというのは、 offset が参照する場所がホールであったとしても、 連続する 0 の列のデータで構成されているとみなすということである)。

<unistd.h> から SEEK_DATASEEK_HOLE の定義を得るには、 機能検査マクロ _GNU_SOURCE を定義しなければならない。

SEEK_HOLE, SEEK_DATA 操作に対応しているのは以下のファイルシステムである。

*
Btrfs (Linux 3.1 以降)
*
OCFS (Linux 3.2 以降)
*
XFS (Linux 3.5 以降)
*
ext4 (Linux 3.8 以降)
*
tmpfs (Linux 3.8 以降)

返り値

成功した場合、 lseek() は結果のファイル位置をファイルの先頭からのバイト数で返す。 エラーの場合、値 (off_t) -1 が返され、 errno にエラーが指示される。

エラー

EBADF
fd がオープンされたファイルディスクリプタでない。
EINVAL
whence が有効な値ではない。または、seek の結果、ファイルオフセットが負に なってしまうか、 seek 可能なデバイスの末尾を越えてしまう。
EOVERFLOW
結果のファイルオフセットを off_t 型で表現することができない。
ESPIPE
fd がパイプ、ソケット、FIFO を参照している。
ENXIO
whenceSEEK_DATASEEK_HOLE で、 現在のファイルオフセットがファイルの末尾を超えた位置である。

準拠

SVr4, 4.3BSD, POSIX.1-2001.

SEEK_DATASEEK_HOLE は非標準の拡張で、 Solaris, FreeBSD, DragonFly BSD にも存在する。 これらは POSIX の次の版 (Issue 8) に入れるよう提案されている。

注意

いくつかのデバイスでは seek ができない。 POSIX はどのデバイスが lseek() に対応すべきかは規定していない。

Linux では、端末 (terminal) デバイスに lseek() を使用すると ESPIPE が返る。

古いコードを変換する時は whence の値を以下のマクロに置き換えること:

old new
0SEEK_SET
1SEEK_CUR
2SEEK_END
L_SETSEEK_SET
L_INCRSEEK_CUR
L_XTNDSEEK_END

dup(2) や fork(2) で作成されたファイルディスクリプタは、現在のファイル位置ポインタ (current file position pointer) を共有しているので、 このようなファイルで移動を行うと競合状態を引き起こす可能性がある。

この文書について

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