名前
rename, renameat, renameat2 -
ファイルの名前や位置を変更する
書式
#include <stdio.h>
int rename(const char *oldpath, const char *newpath);
#include <fcntl.h> /* AT_* 定数の定義 */
#include <stdio.h>
int renameat(int olddirfd, const char *oldpath,
int newdirfd, const char *newpath);
int renameat2(int olddirfd, const char *oldpath,
int newdirfd, const char *newpath, unsigned int flags);
renameat():
renameat2():
説明
rename()
はファイルの名前を変更し、必要ならばディレクトリ間の移動を行なう。
そのファイルに対する
(link(2)
を使用して作られた)
他のハードリンク (hard link)
には影響はない。
オープン済の oldpath
に対するファイルディスクリプターにも影響はない。
Various restrictions determine whether or not the rename operation
succeeds: see ERRORS below.
If newpath already exists, it will be atomically replaced,
so that there is no point at which another process attempting to access
newpath will find it missing. However, there will probably be a
window in which both oldpath and newpath refer to the file
being renamed.
oldpath と newpath
がどちらも既存のハードリンクで、同じファイルを参照している場合、
rename()
は何も行わず、ステータスとして成功を返す。
newpath
が存在し、何らかの理由で操作が失敗した場合、
rename() は newpath
の実体を元のまま残すことを保証する。
oldpath
にはディレクトリを指定することもできる。
この場合、 newpath
は存在しないか、空のディレクトリでなければならない。
oldpath
がシンボリックリンク
(symbolic link)
を参照している場合は、
リンクの名前が変更される。
また、 newpath
がシンボリックリンクを参照している場合は、リンクが上書きされる。
renameat()
システムコールは
rename()
と全く同様に動作するが、以下で説明する点が異なる。
oldpath
で指定されたパス名が相対パスの場合、このパス名はファイルディスクリプター
olddirfd
が参照するディレクトリに対する相対パスと解釈される
(rename(2)
に相対パス名を渡した場合のように、呼び出したプロセスのカレントワーキングディレクトリに対する相対パスではない)。
oldpath
で指定されたパス名が相対パスで、
olddirfd が特別な値 AT_FDCWD
の場合、 (rename(2)
と同様に) oldpath
は呼び出したプロセスのカレントワーキングディレクトリに対する相対パスと解釈される。
oldpath
で指定されたパス名が絶対パスの場合、
olddirfd は無視される。
newpath の解釈は oldpath
と同じである。
相対パスのパス名がファイルディスクリプター
newdirfd
が参照するディレクトリと解釈される点だけが異なる。
renameat()
の必要性についての説明については
openat(2) を参照。
renameat2() には追加の
flags 引数がある。 flags
引数が 0 の renameat2()
の呼び出しは renameat()
と等価である。
flags
引数は、以下のフラグの
0
個以上のビットマスクである。
- RENAME_EXCHANGE
- oldpath と newpath
をアトミックに入れ換える。
両方のパス名が存在しなければならないが、
ファイル種別は異なっていてもよい
(例えば、一方は空でないディレクトリで、もう一方はシンボリックリンクであるなど)。
- RENAME_NOREPLACE
- rename の newpath
を上書きしない。
newpath
がすでに存在する場合エラーを返す。
- RENAME_NOREPLACE can't be employed together with
RENAME_EXCHANGE.
- RENAME_NOREPLACE requires support from the underlying filesystem.
Support for various filesystems was added as follows:
-
ext4 (Linux 3.15);
-
btrfs, shmem, cifs (Linux 3.17);
-
xfs (Linux 4.0);
- Support for many other filesystems was added in Linux 4.9, including ext2,
minix, reiserfs, jfs, vfat, and bpf.
- RENAME_WHITEOUT
(Linux 3.18 以降)
- This operation makes sense only for overlay/union filesystem
implementations.
- Specifying RENAME_WHITEOUT creates a "whiteout" object at
the source of the rename at the same time as performing the rename. The
whole operation is atomic, so that if the rename succeeds then the
whiteout will also have been created.
- A "whiteout" is an object that has special meaning in
union/overlay filesystem constructs. In these constructs, multiple layers
exist and only the top one is ever modified. A whiteout on an upper layer
will effectively hide a matching file in the lower layer, making it appear
as if the file didn't exist.
- When a file that exists on the lower layer is renamed, the file is first
copied up (if not already on the upper layer) and then renamed on the
upper, read-write layer. At the same time, the source file needs to be
"whiteouted" (so that the version of the source file in the
lower layer is rendered invisible). The whole operation needs to be done
atomically.
- When not part of a union/overlay, the whiteout appears as a character
device with a {0,0} device number. (Note that other union/overlay
implementations may employ different methods for storing whiteout entries;
specifically, BSD union mount employs a separate inode type,
DT_WHT, which, while supported by some filesystems available in
Linux, such as CODA and XFS, is ignored by the kernel's whiteout support
code, as of Linux 4.19, at least.)
- RENAME_WHITEOUT requires the same privileges as creating a device
node (i.e., the CAP_MKNOD capability).
- RENAME_WHITEOUT can't be employed together with
RENAME_EXCHANGE.
- RENAME_WHITEOUT requires support from the underlying filesystem.
Among the filesystems that provide that support are tmpfs (since Linux
3.18), ext4 (since Linux 3.18), XFS (since Linux 4.1), f2fs (since Linux
4.2), btrfs (since Linux 4.7), and ubifs (since Linux 4.9).
返り値
成功した場合は 0
が返される。エラーの場合は
-1 が返され、 errno
が適切に設定される。
エラー
- EACCES
- oldpath または newpath
を含んでいるディレクトリの書き込み許可がない。
または、 oldpath または
newpath
のディレクトリ部分のどれかに検索許可がない。
または、 oldpath
がディレクトリで
(..
エントリーを更新するのに必要な)
書き込み許可がない
(path_resolution(7) も参照)。
- EBUSY
- oldpath または newpath
がディレクトリで、何らかのプロセスが使用中
(多分、カレントワーキングディレクトリか、ルートディレクトリか、
読み込みのためにオープンされているかでろう)
もしくは、システムが使用中
(例えばマウントポイントである)
であり、システムがこれをエラーであると判断したために
rename が失敗した。
(このような場合に
EBUSY
を返すことは規格では要求されていない点に注意すること。
このような場合に、rename
をとにかく実行してみるのは何の問題もない。
ただし、そのような状況で、システムが他に返すエラーがない場合には
EBUSY
を返すことが許されている。)
- EDQUOT
- ディスクブロックか
inode
がそのファイルシステムのユーザークォータに達していた。
- EFAULT
- oldpath や newpath
がアクセス可能なアドレス空間の外を指している。
- EINVAL
- newpath が oldpath
のパス部分を含んでいる。ディレクトリを自分自身のサブディレクトリに
変更しようとした場合がほとんどである。
- EISDIR
- newpath
は存在しているディレクトリであるが、
oldpath
はディレクトリでない。
- ELOOP
- oldpath または newpath
を解決する際に遭遇したシンボリックリンクが多過ぎる。
- EMLINK
- oldpath
は既に最大数までのリンクを持っているか、それがディレクトリで
newpath
を含んでいるディレクトリが最大数までのリンクを持っている。
- ENAMETOOLONG
- oldpath または newpath
が長過ぎる。
- ENOENT
- oldpath
という名前のリンクが存在しない。
または、 newpath
というディレクトリが存在しない。
または、 oldpath か newpath
が空の文字列である。
- ENOMEM
- 十分なカーネルメモリーがない。
- ENOSPC
- そのファイルを含んでいるデバイスに新しいディレクトリエントリーを
作成するための空きがない。
- ENOTDIR
- oldpath か newpath
に含まれているディレクトリ部分が
実際にはディレクトリでない。
または oldpath
がディレクトリで、
newpath
が存在してディレクトリでない。
- ENOTEMPTY
または EEXIST
- newpath
が空でないディレクトリである。すなわち
"." と ".."
以外を含んでいる。
- EPERM
または EACCES
- oldpath
のあるディレクトリにスティッキービット
(sticky bit) (S_ISVTX)
が設定されており、
プロセスの実効ユーザー
ID が
削除しようとするファイルのユーザー
ID と
そのファイルを含むディレクトリのユーザー
ID
のいずれとも一致せず、かつ
プロセスに特権がない
(Linux では CAP_FOWNER
ケーパビリティ (capability)
がない)。 または、
newpath
がすでに存在するファイルで、親ディレクトリにスティッキービットが設定されており、
プロセスの実効ユーザー
ID が
置き換えようとするファイルのユーザー
ID と
そのファイルを含むディレクトリのユーザー
ID
のいずれとも一致せず、かつ
プロセスに特権がない
(Linux では CAP_FOWNER
ケーパビリティがない)。
または oldpath と newpath
が存在するファイルシステムが、要求された種類の名前の変更を
サポートしていない。
- EROFS
- ファイルが読み込み専用のファイルシステムに存在する。
- EXDEV
- oldpath と newpath
が同じマウントされたファイルシステムに存在しない。
(Linux は 1
つのファイルシステムを複数のマウント位置に
マウントすることを許可している。
しかし rename()
は、たとえ同じファイルシステムであっても、
別々のマウント位置を跨いでは動作しない。)
renameat() と renameat2()
では以下のエラーも発生する。
- EBADF
- olddirfd か newdirfd
が有効なファイルディスクリプターでない。
- ENOTDIR
- oldpath が相対パスで、
olddirfd
がディレクトリ以外のファイルを参照している。または
newpath と newdirfd
に関して同じ状況である。
renameat2()
では以下のエラーも発生する。
- EEXIST
- flags に RENAME_NOREPLACE
が指定されているが、
newpath
がすでに存在する。
- EINVAL
- 無効なフラグ値が
flags に指定された。
- EINVAL
- RENAME_NOREPLACE と RENAME_EXCHANGE
の両方が flags
に指定された。
- EINVAL
- Both RENAME_WHITEOUT and RENAME_EXCHANGE were specified in
flags.
- EINVAL
- flags
にファイルシステムでサポートされていないフラグが指定された。
- ENOENT
- flags に RENAME_EXCHANGE
が指定されたが、
newpath
が存在しない。
- EPERM
- RENAME_WHITEOUT が flags
に指定されたが、呼び出し元が
CAP_MKNOD
ケーパビリティを持っていない。
バージョン
renameat() はカーネル 2.6.16
で Linux に追加された。
ライブラリによるサポートはバージョン
2.4 で glibc
に追加された。
renameat2() はカーネル 3.15
で Linux に追加された。
ライブラリによるサポートは
glibc 2.28 で追加された。
準拠
rename(): 4.3BSD, C89, C99, POSIX.1-2001, POSIX.1-2008.
renameat(): POSIX.1-2008.
renameat2() は Linux
固有である。
注意
renameat()
が利用できない古いカーネルでは、
glibc ラッパー関数は
rename()
を使用するモードにフォールバックする。
oldpath と newpath
が相対パスの場合、
glibc は olddirfd と newdirfd
引数に対応する
/proc/self/fd
のシンボリックリンクに基づいてそれぞれパス名を構成する。
バグ
NFS
ファイルシステムでは、操作が失敗したからといって、
ファイルの名前が変更できなかったと決めてかかることはできない。
サーバが rename
操作を終えてからクラッシュした場合、
サーバが再び立ち上がったときに、
再送信された RPC
が処理されるが、これは失敗となる。
アプリケーションはこの問題を正しく取り扱うことが期待されている。
同様の問題について
link(2)
にも書かれている。
この文書について
この man ページは Linux
man-pages
プロジェクトのリリース
5.10
の一部である。プロジェクトの説明とバグ報告に関する情報は
https://www.kernel.org/doc/man-pages/
に書かれている。