文件重命名和符号链接

    文件或目录可以用 rename 函数或者 renameat 函数进行重命名。
#include <stdio.h>

int rename(const char *oldname, const char *newname);
int renameat(int oldfd, const char *oldname, int newfd, const char *newname);
                  /* 返回值:若成功,都返回 0;否则,都返回 -1 */

    除了当 oldname 或 newname 指向相对路径时,这两个函数功能相同。如果 oldname 指向相对路径,就相对于 oldfd 引用的目录来计算 oldname。类似地,如果 newname 指向相对路径,就相对于 newfd 引用的目录来计算 newname。oldfd 或 newfd 都能设置成 AT_FDCWD,此时相对于当前目录来计算相应的路径名。
    根据 oldname 是指文件、目录还是符号链接,有几种情况需要讨论。
    1、如果 oldname 指的是一个文件而不是目录,那么为该文件或符号链接重命名。在这种情况下,如果 newname 已存在,则它不能引用一个目录。如果 newname 存在而且不是一个目录,则先将该目录项删除,然后将 oldname 重命名为为 newname。对包含 oldname 的目录以及包含 newname 的目录,调用进程必须具有写权限,因为将更改这两个目录。
    2、若 oldname 指的是一个目录,那么为该目录重命名。如果 newname 已存在,则它必须引用一个空目录(即只能有“.”和“..”项)。如果 newname 存在且是空目录,则先将其删除,然后将 oldname 重命名为 newname。另外,newname 不能包含 oldname 作为其路径前缀。
    3、若 oldname 或 newname 引用符号链接,则处理的是符号链接本身。
    4、不能对“.”和“..”重命名。
    5、当 oldname 和 newname 引用同一文件时,函数不做任何更改。

    符号链接是对一个文件的间接指针,而硬链接直接指向文件的 i 节点。引入符号链接是为了避开硬链接的一些限制:
    1、硬链接通常要求链接和文件位于同一文件系统。
    2、只有超级用户才能创建指向目录的硬链接(底层文件系统支持的话)。
    对符号链接以及它指向何种对象并无任何文件系统限制,任何用户都可以创建指向目录的符号链接。符号链接一般用于将一个文件或目录结构移到系统中另一个位置。
    当使用以名字引用文件的函数时,应当了解该函数是否处理符号链接,也就是是否跟随符号链接到达它所链接的文件。因为符号链接可能在文件系统中引入循环,大多数查找路径名的函数在这种情况下都将出错返回,并把 errno 值设置为 ELOOP。如下示例:
$ mkdir foo
$ touch foo/a
$ ln -s ../foo foo/testdir      # 创建一个符号链接

    此时如用类似于 Solaris 的标准函数 ftw 以降序遍历该文件结构,打印每个遇到的路径,则将输出:
foo
foo/a
foo/testdir
foo/testdir/a
foo/testdir/testdir
......                  # 更多行,直到 ftw 出错,此时 errno 值为 ELOOP

    另外,当用 open 打开文件时,如果传递的参数指定了一个符号链接,那么 open 会跟随此链接到达所指定的文件。若引用文件不存在,open 将出错返回。这有时会让不熟悉符号链接的人感到迷惑,例如:
$ ln -s /no/such/file myfile  # 创建一个指向不存在的文件的符号链接
$ ls -l myfile                # 使用 ls 命令能看到该符号链接
lrwxrwxrwx 1 sar     13 Jan 22 00:26  myfile -> /no/such/file
$ cat myfile                     # 试图查看该文件,结果报错
cat:myfile: No such file or directory

    可以用 symlink 或 symlinkat 函数创建一个符号链接。
#include <unistd.h>
int symlink(const char *actualpath, const char *sympath);
int symlinkat(const char *actualpath, int fd, const char *sympath);
                    /* 返回值:若成功,都返回 0;否则,都返回 -1 */

    函数创建了一个指向 actualpath 的新目录项 sympath,这里并不要求 actualpath 必须存在(如上面的例子所示),而且,actualpath 和 sympath 也并不需要一定位于同一文件系统中。
    symlinkat 函数类似于 symlink 函数,但 sympath 参数根据相对于打开文件描述符引用的目录(由 fd 参数指定)进行计算。如果 sympath 指定的是绝对路径或 fd 设置为 AT_FDCWD 值,那么 symlinkat 就等同于 symlink 函数。
    由于 open 函数会跟随符号链接,所以需要有一种方法打开该链接本身,并读取该链接中的名字。readlink 和 readlinkat 函数提供了这种功能。
#include <unistd.h>
ssize_t readlink(const char *restrict pathname, char *restrict buf, size_t bufsize);
ssize_t readlink(int fd, const char *restrict pathname, char *restrict buf, size_t bufsize);
                    /* 返回值:若成功,都返回读取的字节数;否则,都返回 -1 */

    如果函数执行成功,则返回读入 buf 的字节数,buf 中返回的符号链接的内容不以 null 字节终止。
    当 pathname 指定的是绝对路径或 fd 设置为 AT_FDCWD 值,那么 readlinkat 就等同于 readlink 函数。但是,如果 fd 是一个打开目录的有效文件描述符并且 pathname 是相对路径名,则 readlinkat 计算相对于由 fd 代表的打开目录的路径名。

猜你喜欢

转载自aisxyz.iteye.com/blog/2384261