05-更改文件名_rename()
18.4 更改文件名:rename()
借助于rename()系统调用,既可以重命名文件,又可以将文件移至同一文件系统中的另一目录。
调用会将现有的一个路径名oldpath重命名为newpath参数所指定的路径名。
rename()调用仅操作目录条目,而不移动文件数据。改名既不影响指向该文件的其他硬链接,也不影响持有该文件打开描述符的任何进程,因为这些文件描述符指向的是打开文件描述,(在调用open()之后)与文件名并无瓜葛。
以下规则适用与对rename()的调用。
- 若newpath已经存在,则将其覆盖。
- 若newpath与oldpath指向同一文件,则不发生变化(且调用成功)。这很不合常理。顺着上一条规则的思路,通常的推断是:如果两个文件名x和y都存在,那么调用rename("x","y")时应当把x移除才是。但如果x和y链接的是同一文件,事实却并非如此。
此规则源于早期的BSD实现,其动机可能是出于这样的考虑:要保障诸如rename("x","x")、rename("x","./x")以及rename("x", "somedir/../x")之类的调用不会移除文件,内核必须进行检查。而这种设计则有助于简化这一检查。
- rename()系统调用对其两个参数中的符号链接均不进行解引用。如果oldpath是一符号链接,那么将重命名该符号链接。如果newpath是一符号链接,那么会将其视为由oldpath重命名而成的普通路径名(即移除已有的符号链接newpath)。
- 如果oldpath指代文件,而非目录,那么就不能将newpath指定为一个目录的路径名(否则将errno置为EISDIR)。要想重命名一个文件到某一目录中(亦即将文件移到另一目录),newpath必须包含新的文件名。如下调用既将一个文件移动到另一目录中,同时又将其改名:
-
- 若将oldpath指定为目录名,则意在重命名该目录。这种情况下,必须保证newpth要么不存在,要么是一个空目录的名称。无论newpath是一个已有文件还是一个非空目录,调用都将出错(分别将errno置为ENOTDIR和ENOTEMPTY)。
- 若oldpath是一目录,则newpath不能包含oldpath作为其目录前缀。例如,不能将 /home/mtk重命名为/home/mtk/bin(错误为EINVAL)。
- oldpath和newpath所指代的文件必须位于同一文件系统。之所以如此,是因为目录内容由硬链接列表组成,且硬链接所指向的i-node与目录位于同一文件系统。如前所述,rename()仅限于操作目录列表的内容。试图将一文件重命名至不同的文件系统将返回错误EXDEV。(非要如此,必须从一个文件系统中将其文件内容复制到另一文件系统,然后再删除老文件。这正是mv命令的功能所在。)