16、符号链接

硬链接的局限是:

  1. 硬链接和文件必须在同一个文件系统之下。

b. 只有超级用户才能够创建目录的硬链接。

一个目录的软链接(也就是符号链接)就没有这些限制,它可以由任何人创建,可以创建目录或者文件的软链接,以及在不同文件系统上创建某个文件或者目录的软链接。软链接是不能用 rmdir 来删除的,因为软链接是一个文件,不是目录。用 rm -r 也是只删除了这个软链接本身。

当使用以名字引用一个处理文件的函数时,应当知道该函数是否能够处理符号连接。也就是这个函数是否跟随符号连接到达它所连接的文件,然后对被连接的文件进行正确地操作,而不是指向文件的链接本身。如若该函数可以处理符号连接,则传递给该函数的符号链接的路径名参数,会最终引用到由符号连接指向的文件;否则,只是引用到路径参数引用的链接本身,而不是由该链接指向的文件。这里列出了如果传递的路径是一个符号链接的时候,哪些函数会沿着符号链接跟踪到相应的文件(即对符号链接进行处理),或者不跟踪(即不处理符号链接)。

                        各种函数对符号链接的处理
+-------------------------------------------------------------------+
| Function | Does not follow symbolic link  | Follows symbolic link |
|----------+--------------------------------+-----------------------|
| access   |                                |           •           |
|----------+--------------------------------+-----------------------|
| chdir    |                                |           •           |
|----------+--------------------------------+-----------------------|
| chmod    |                                |           •           |
|----------+--------------------------------+-----------------------|
| chown    |               •                |           •           |
|----------+--------------------------------+-----------------------|
| creat    |                                |           •           |
|----------+--------------------------------+-----------------------|
| exec     |                                |           •           |
|----------+--------------------------------+-----------------------|
| lchown   |               •                |                       |
|----------+--------------------------------+-----------------------|
| link     |                                |           •           |
|----------+--------------------------------+-----------------------|
| lstat    |               •                |                       |
|----------+--------------------------------+-----------------------|
| open     |                                |           •           |
|----------+--------------------------------+-----------------------|
| opendir  |                                |           •           |
|----------+--------------------------------+-----------------------|
| pathconf |                                |           •           |
|----------+--------------------------------+-----------------------|
| readlink |               •                |                       |
|----------+--------------------------------+-----------------------|
| remove   |               •                |                       |
|----------+--------------------------------+-----------------------|
| rename   |               •                |                       |
|----------+--------------------------------+-----------------------|
| stat     |                                |           •           |
|----------+--------------------------------+-----------------------|
| truncate |                                |           •           |
|----------+--------------------------------+-----------------------|
| unlink   |               •                |                       |
+-------------------------------------------------------------------+

例如 openfollow 一个 symbolic link. 如果一个 symbolic 指向一个不存在的文件,那么 open 的时候会提示没有这样的文件,如果大家不清楚 symbolic link 的工作原理,可能会被这种现象所困惑,举例如下:

$ ln -s /no/such/file myfile            create a symbolic link
$ ls myfile
myfile                                  ls says it's there
$ cat myfile                            so we try to look at it
cat: myfile: No such file or directory
$ ls -l myfile                          try -l option
lrwxrwxrwx 1 sar        13 Jan 22 00:26 myfile -> /no/such/file

我们好像看到了一个 myfile 的文件,但是 ls 的时候却提示没有这个文件。实际上, myfile 是一个符号链接,这个符号链接所指向的文件 /no/such/file 根本就不存在。

译者注

原文参考

参考: APUE2/ch04lev1sec16.html

17、symlink和readlink函数

symlink 函数创建一个符号连接。声明如下:

#include <unistd.h>
int symlink(const char *actualpath, const char *sympath);

返回:如果成功返回0,如果错误返回1(实际值一般为-1)。

该函数创建了一个指向 actualpath 的新目录项 sympath ,在创建此符号连接时,并不要求 actualpath 已经存在。并且, actualpathsympath 不必位于同一文件系统中。

因为 open 函数跟随符号连接,所以需要有一种方法打开该连接本身,并读取该连接中的名字。 readlink 函数提供了这种功能。声明如下:

#include <unistd.h>
ssize_t readlink(const char* restrict pathname, char *restrict buf, size_t bufsize);

返回:如果成功返回读取的字节数目;错误返回1(实际值一般为-1)。

此函数组合了 open , readclose 的所有操作。如果成功,则返回读入 buf 的字节数。在 buf 中返回的符号连接的内容不以 null 字符终止。

译者注

原文参考

参考: APUE2/ch04lev1sec17.html

18、文件的三种时间

文件有三种和时间相关的属性:

  1. atime :访问时间。记录最后一次,例如执行 exec ,或者 read ,或者创建文件(非截断创建)的时候的时间。
  2. mtime :内容改变时间。记录最后一次文件内容改变的时间。
  3. ctime :状态改变时间。记录最后一次文件索引信息改变的时间,例如:文件名称,大小,链接数目,等一般在 stat 中的信息的改变。

这里,内容改变时间( st_mtime )和状态改变时间( st_ctime )是不同的:内容改变时间是文件内容最后一次被修改的时间;状态改变时间是该文件的 i 节点最后一次被修改的时间。

因为有很多操作,它们只影响到i节点,但并没有更改文件的实际内容:文件的存取许可权、用户 ID 、连接数等等。而i节点中的所有信息都是与文件的实际内容分开存放的,所以,除了文件数据改变时间以外,还需要状态改变时间。

另外,注意,系统并不保存对一个 i节点的最后一次存取时间,所以 accessstat 函数并不更改这三个时间中的任一个。下表给出之前讲过的各种函数对这三个时间的作用。

                        各种函数对access,modification,以及changed-status时间的影响
+--------------------------------------------------------------------------------------------------------------------------------------+
|                    |     Referenced file or    |                                                 |        |                          |
|      Function      |          directory        | Parent directory of referenced file or directory| Section|           Note           |
|                    |---------------------------+-------------------------------------------------|        |                          |
|                    |    a    |    m    |    c  |       a        |       m        |       c       |        |                          |
|--------------------+---------+---------+-------+----------------+----------------+---------------+--------+--------------------------|
| chmod, fchmod      |         |         |    •  |                |                |               |   4.9  |                          |
|--------------------+---------+---------+-------+----------------+----------------+---------------+--------+--------------------------|
| chown, fchown      |         |         |    •  |                |                |               |  4.11  |                          |
|--------------------+---------+---------+-------+----------------+----------------+---------------+--------+--------------------------|
| creat              |    •    |    •    |    •  |                |       •        |       •       |   3.4  | O_CREAT new file         |
|--------------------+---------+---------+-------+----------------+----------------+---------------+--------+--------------------------|
| creat              |         |    •    |    •  |                |                |               |   3.4  | O_TRUNC existing file    |
|--------------------+---------+---------+-------+----------------+----------------+---------------+--------+--------------------------|
| exec               |    •    |         |       |                |                |               |  8.10  |                          |
|--------------------+---------+---------+-------+----------------+----------------+---------------+--------+--------------------------|
| lchown             |         |         |    •  |                |                |               |  4.11  |                          |
|--------------------+---------+---------+-------+----------------+----------------+---------------+--------+--------------------------|
| link               |         |         |    •  |                |       •        |       •       |  4.15  | parent of second argument|
|--------------------+---------+---------+-------+----------------+----------------+---------------+--------+--------------------------|
| mkdir              |    •    |    •    |    •  |                |       •        |       •       |  4.20  |                          |
|--------------------+---------+---------+-------+----------------+----------------+---------------+--------+--------------------------|
| mkfifo             |    •    |    •    |    •  |                |       •        |       •       |  15.5  |                          |
|--------------------+---------+---------+-------+----------------+----------------+---------------+--------+--------------------------|
| open               |    •    |    •    |    •  |                |       •        |       •       |   3.3  | O_CREAT new file         |
|--------------------+---------+---------+-------+----------------+----------------+---------------+--------+--------------------------|
| open               |         |    •    |    •  |                |                |               |   3.3  | O_TRUNC existing file    |
|--------------------+---------+---------+-------+----------------+----------------+---------------+--------+--------------------------|
| pipe               |    •    |    •    |    •  |                |                |               |  15.2  |                          |
|--------------------+---------+---------+-------+----------------+----------------+---------------+--------+--------------------------|
| read               |    •    |         |       |                |                |               |   3.7  |                          |
|--------------------+---------+---------+-------+----------------+----------------+---------------+--------+--------------------------|
| remove             |         |         |    •  |                |       •        |       •       |  4.15  | remove file = unlink     |
|--------------------+---------+---------+-------+----------------+----------------+---------------+--------+--------------------------|
| remove             |         |         |       |                |       •        |       •       |  4.15  | remove directory = rmdir |
|--------------------+---------+---------+-------+----------------+----------------+---------------+--------+--------------------------|
| rename             |         |         |    •  |                |       •        |       •       |  4.15  | for both arguments       |
|--------------------+---------+---------+-------+----------------+----------------+---------------+--------+--------------------------|
| rmdir              |         |         |       |                |       •        |       •       |  4.20  |                          |
|--------------------+---------+---------+-------+----------------+----------------+---------------+--------+--------------------------|
| truncate, ftruncate|         |    •    |    •  |                |                |               |  4.13  |                          |
|--------------------+---------+---------+-------+----------------+----------------+---------------+--------+--------------------------|
| unlink             |         |         |    •  |                |       •        |       •       |  4.15  |                          |
|--------------------+---------+---------+-------+----------------+----------------+---------------+--------+--------------------------|
| utime              |    •    |    •    |    •  |                |                |               |  4.19  |                          |
|--------------------+---------+---------+-------+----------------+----------------+---------------+--------+--------------------------|
| write              |         |    •    |    •  |                |                |               |   3.8  |                          |
+--------------------------------------------------------------------------------------------------------------------------------------+

译者注

原文参考

参考: APUE2/ch04lev1sec18.html

19、 utime 函数

我们可以使用 utime 函数来修改文件的访问时间和内容修改时间。其声明如下:

#include <utime.h>
int utime(const char *pathname, const struct utimbuf *times);

返回:如果成功返回0,如果错误返回1(其值一般为-1)。

这里, utimbuf 结构定义如下:

struct utimbuf {
        time_t actime;   /*access time*/
        time_t modtime;  /*modification time*/
};

此结构中的两个时间值是日历时间(即1970年1月1日,00:00:00至今的秒数)。此函数的操作以及执行它所要求的优先权取决于参数 times 是否为 NULL

  1. 如果 times 是空指针,则存取时间和修改时间两者都设置为当前时间。此操作必须满足下列两条件之一:进程的有效用户 ID 必须等于该文件的所有者 ID ;进程对该文件必须具有写许可权。
  2. 如果 times 非空,则存取时间和修改时间被设置为 times 所指向的结构中的值。此时,进程的有效用户 ID 必须等于该文件的所有者 ID ,或者进程必须是一个超级用户进程。对文件只具有写许可权是不够的。

注意,我们不能对更改状态时间 st_ctime 指定一个值,当调用 utime 函数时,此字段被自动更新。

译者注

原文参考

参考: APUE2/ch04lev1sec19.html

20、 mkdirrmdir 函数

mkdir 函数可以创建一个目录,其声明如下:

#include <sys/stat.h>
int mkdir(const char *pathname, mode_t mode);

返回:如果成功返回0,如果错误返回1(其值一般为-1)。

空目录通过函数 rmdir 被删除。这里空目录表示目录里面只有 ... 目录项。这个函数声明如下:

#include <unistd.h>
int rmdir(const char *pathname);

返回:如果成功返回0,如果错误返回1(其值一般为-1)。

如果此调用使目录的连接计数变成0,并且也没有其他进程打开此目录,则释放此目录所占空间。如果在连接计数达到0时,有一个或几个进程打开了此目录,则在此函数返回前删除最后一个连接及 ... 项,另外,在此目录中不能再创建新文件。在最后一个进程关闭它之前并不释放此目录(即使某些进程打开该目录,这些进程在此目录下也不能执行其他操作,因为为使rmdir函数成功执行,该目录必须为空)。

译者注

原文参考

参考: APUE2/ch04lev1sec20.html