分类: 系统运维
2012-03-28 13:47:14
正如我们在前一节看到的,任何文件可以有多个目录项指向它的i-node。我们创建一个已存在的文件的链接的方法是使用link函数。
这个函数创建一个新的目录项newpath,指向已存在文件exsitingpath。如果newpath已存在,则返回一人错误。只有newpath的最后一个部分被创建。路径的其余部分必须已经存在。
新目录项的创建和链接接的增加必须是一个原子操作。(回想下3.11节关于原子操作的讨论。)
多数实现需要两个路径名在同一个文件系统,尽管POSIX.1允许一个实现支持跨越文件系统的链接。如果一个实现支持目录硬链接的创建,它只能由超级用户
完成。原因是这样做可能会引起文件系统的回路,多数处理文件系统的工具没有能力处理。(我们在4.16节展示由一个符号链接引起回路的一个例子。)许多文
件系统实现因为这个原因不允许目录的硬链接。
为了删除一个已存在的目录项,我们调用unlink函数。
函数删除目录项并减少pathname引用的文件的链接数。如果文件有其它链接,文件的数据仍可以通过别的链接访问。如果错误发生,文件不会改变。
我们已经提过在解链接文件之前,我们必须有包含该目录项的目录的写权限和执行权限,因为这是我们正删除的目录项。同样,我们在4.10节也提过如果目录设置了粘滞位,我们必须有这个目录的写权限和以下三者之一:拥有该文件、拥有该目录、有超级用户权限。
只有当链接数减为0时文件的内容才能删除。另一个阻止文件内容被删除的条件是:只要有一些进程正打开该文件,它的内容不能被删除。
当一个文件被关闭后,内核首先检查打开该文件的进程数量。如果进程数为0,内核检查链接数,如果链接数为0,文件内容被删除。
看下面的代码:
再看看可用的剩余空间
tommy@tommy-zheng-ThinkPad-T61:~/code/c/unix$ df /home
文件系统 1K-块 已用 可用 已用% 挂载点
/dev/sda1 73843936 9101884 60990936 13% /
后台方式执行程序
$ ./a.out &
[1] 4991
$ file unlinked
查看文件被unlinked后文件是否存在
ls -l tempfile
ls: 无法访问tempfile: 没有那个文件或目录
查看unlink后可用的空间(没有变化)
$ df /home
文件系统 1K-块 已用 可用 已用% 挂载点
/dev/sda1 73843936 9101884 60990936 13% /
程序运行完毕,查看文件关闭后可用的空间(已释放文件内容)
$ done
df /home
文件系统 1K-块 已用 可用 已用% 挂载点
/dev/sda1 73843936 9101816 60991004 13% /
unlink的属性通常被程序用来确保当崩溃的,它创建的临时文件不会留在那里。进程用open或creat创建一个文件然后立即调用unlink。尽管
如此,文件并没有被删除,因为它仍被打开。只有当进程关闭这个文件或终止时(导致内核关闭它的所有的打开文件),文件才会被删除。
如果路径名是一个符号链接,unlink删除这个符号链接,而不是链接指向的文件。没有给定链接名删除其指向的文件的函数。
超级用户可以用目录的路径名调用unlink,但是函数rmdir函数应该被用来解链接一个目录,而不是unlink。我们在4.20节讲述rmdir函数。
我们还可以用remove函数解链接一个文件或目录。对于一个文件,remove与unlink相同。对于一个目录,remove和rmidir相同。
ISO C规定了remove函数来删除一个文件。名字从历史上的UNIX名字unlink改变是因为那时实现C标准的多数非UNIX系统都不支持文件链接的概念。
一个文件或目录可以用rename函数来重命名。
这个函数被ISO C为文件定义。(C标准没有处理目录。)POSIX.1扩展了这个定义,包含了目录和符号链接。
根据oldname是指向一个文件、目录还是符号链接,我们有几种条件来讲述下。我们必须说下如果newname已经存在时会发生什么:
1、如果oldname指定一个不是目录的文件,那我们就是重命名一个文件或符号链接。在这种情况下,如果newname已经存在,它不能是一个目录。如
果newname已存在且不是一个目录,那么它会被删除,而且oldname会重命名为newname。我们必须有包含oldname的目录和包含
newname的目录的写权限,因为我们改变了两个目录。
2、如果oldname指向一个目录,那么我们正在重命名一个目录。如果newname存在的话,它必须是一个目录,而且它必须为空。(当我们说目录为空
时,我们指这个目录里的项只有点和点点。)如果newname存在且为空时,它被删除,oldname被重命名为newname。额外地,当我们重命名一
个目录时,newname不能包含以oldname为前缀的路径。比如,我们不能重命名/usr/foo为/usr/foo/testdir,因为旧名字
(/usr/foo)是新名字的路径前缀,且不能被删除。
3、如果oldname或newname指向一个符号链接,链接本身被处理,而不是它解析的文件。
4、作为一个特殊例子,如果oldname和newname是同一个文件,那么函数成功返回但不改变任何东西。
如果newname已经存在,我们需要有删除它的权限。同样,因为我们正在删除oldname的目录项而且可能创建newname的目录项,我们需要包含旧文件所在目录和新文件所在目录的写权限和执行权限。