文件链接函数

    根据 文件系统基本结构中的介绍,任何一个文件都可以有多个目录项指向其 i 节点。创建一个指向现有文件的链接的方法是使用 link 函数或 linkat 函数(创建新目录项和增加链接计数是一个原子操作)。
#include <unistd.h>

int link(const char *existingpath, const char *newpath);
int linkat(int efd, const *existingpath, int nfd, const char *newpath, int flag);
                      /* 返回值:若成功,都返回 0;否则,都返回 -1 */

    两个函数都创建一个新目录项 newpath,它引用现有文件 existingpath。如果 newpath 已经存在,则返回出错。
    对于 linkat 函数,现有文件是通过 efd 和 existingpath 参数指定的,新的路径名是通过  nfd 和 newpath 参数指定的。默认情况下,如果两个路径名中的任一个是相对路径,那么它需要通过相对于对应的文件描述符进行计算。如果两个文件描述符中的任一个设置为 AT_FDCWD,那么相应的路径名(如果它是相对路径)就通过相对于当前目录进行计算。如果任一路径名是绝对路径,相应的文件描述符参数就会被忽略。当现有文件是符号链接时,由flag 参数来控制 linkat 函数是创建指向现有符号链接的链接还是指向其所指向的文件的链接。如果 flag 参数中设置了 AT_SYMLINK_FOLLOW 标志,就创建指向符号链接目标的链接。否则就创建一个指向符号链接本身的链接。
    注意,很多文件系统实现不允许创建对于目录的硬链接,以免在文件系统中形成循环。
    为删除一个现有的目录项,可以调用 unlink 或 unlinkat 函数。
#include <unistd.h>

int unlink(const char *pathname);
int unlinkat(int fd, const char *pathname, int flag);
                      /* 返回值:若成功,都返回 0;否则,都返回 -1 */

    这两个函数删除目录项,并将由 pathname 所引用的文件的链接计数减 1。如果对该文件还有其他链接,则仍可通过其他链接访问该文件。如果出错,则不对该文件做任何更改。
    如果 pathname 参数是相对路径名,那么 unlinkat 函数计算相对于由 fd 文件描述符参数代表的路径名。如果 fd 设置为 AT_FDCWD,那么通过相当于调用进程的当前工作目录来计算路径名(除非 pathname 是绝对路径名)。当 flag 参数设置为 AT_REMOVEDIR 标志时,unlinkat 函数可类似于 rmdir 一样删除目录。否则执行与 unlink 同样的操作。
    为了解除对文件的链接,必须对包含该目录项的目录具有写和执行权限。如果对该目录设置了粘着位,则对该目录具有写权限,并且还要具备下面三个条件之一:
    1、拥有该文件。
    2、拥有该目录。
    3、具有超级用户权限。
    只有当链接计数变为 0 时,该文件的内容才可被删除。此外,当有进程打开了该文件时,其内容也不能删除。关闭一个文件时,内核首先检查打开该文件的进程个数,如果这个计数为 0,内核再去检查其链接计数,如果也是 0,那么就删除该文件的内容。
    下面这个程序打开一个文件,之后立刻解除它的链接,然后执行该程序的进程睡眠 15 秒,接着终止。
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>

int main(void){
	if(open("tempfile", O_RDWR) < 0){
		printf("open error\n");
		exit(1);
	}
	if(unlink("tempfile") < 0){
		printf("unlink error\n");
		exit(1);
	}
	printf("*** file unlinked\n");
	sleep(15);
	printf("done\n");
	exit(0);
}

    运行结果:
$ ls -l tempfile
-rw-r----- 1 sar      413265408  Jan 21 07:14  tempfile
$ df /home                         # 检查可用磁盘空间
Filesystem    1K-blocks       Used     Available     Used      Mounted on
/dev/hda4      11021440      1956332    9065108       18%        /home
$ ./unlinkDemo.out &               # 在后台运行程序
1364                               # 进程 ID
*** file unlinked                # 解除了文件链接
$ ls -l tempfile
ls:tempfile: No such file or directory             # 目录项已被删除
$ df /home                         # 检查可用磁盘空间的变化
Filesystem    1K-blocks       Used     Available     Used      Mounted on
/dev/hda4      11021440      1956332    9065108       18%        /home
$
done                             # 程序执行结束,关闭所有打开文件
$ df /home                         # 现在应当有更多可用的磁盘空间
Filesystem    1K-blocks       Used     Available     Used      Mounted on
/dev/hda4      11021440      1552352    9469088       15%        /home

    unlink 的这种特性经常被用来确保即使是在程序崩溃时,它所创建的临时文件也不会遗留下来。进程用 open 或 creat 创建一个文件,然后立即调用 unlink,因为该文件仍旧是打开的,所以不会被立即删除,只有当进程关闭该文件或终止时(此时内核会关闭该进程所打开的全部文件),该文件的内容才被删除。
    如果 pathname 是符号链接,那么 unlink 删除该符号链接,而不是所引用的文件。给出符号链接名的情况下,没有一个函数能删除由该链接所引用的文件。
    另外,也可用 remove 函数解除对一个文件或目录的链接。对于文件,remove 的功能与 unlink 相同;对于目录,remove 的功能同 rmdir。
#include <stdio.h>

int remove(const char *pathname);
                  /* 返回值:若成功,返回 0;否则,返回 -1 */

猜你喜欢

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