十三、文件和目录——软链接和硬链接
13.1 软链接和硬链接介绍
13.1.1 软硬链接的创建
通过 ln 命令可以对文件创建软硬链接
创建硬链接
2 表示链接数
创建软链接
通过 ls -l 命令显示的文件类型为 l,表示文件类型为符号链接
- 若删除原始文件,对硬链接来说依然可以查看到文件内容,只不过链接数会减1,对软链接来说,则链接依然存在,但是查看不到文件内容了,用 cat 和 more 命令的时候,会提示没有哪个文件或目录。
13.1.2 软硬链接在Linux系统中的存放
创建硬链接的时候,只是多创建了一个目录项,并不会创建一个 i 节点和数据块,然后链接数 +1。只有直到硬链接数为0的时候,才会释放这个文件,即真正的删除。
创建硬链接,数据块存放的是源文件的路径,所以当源文件删除后,就找不到软链接的内容了。但是 i 节点和数据块还存在。软链接的链接数永远都是1。
13.2 硬链接函数
- 硬链接创建条件
- 针对文件创建链接,无法对目录进行创建,除非是 root 用户
- 必须是同一个分区
- 只有超级用户才能对目录建立连接
- 文件删除条件
- 链接计数为0
- 无其他进程打开该文件
13.2.1 创建链接-link 函数
link(建立文件连接)
相关函数 symlink,unlink
1 #include <unistd.h> 2 int link (const char * oldpath, const char * newpath);
- 函数说明
- link()以参数 newpath 指定的名称来建立一个新的连接(硬连接)到参数 oldpath 所指定的已存在文件。
- 如果参数 newpath 指定的名称为一已存在的文件则不会建立连接。
- 函数功能:
- 创建一个指向现存文件的连接(硬链接)
- 附加说明
- link()所建立的硬连接无法跨越不同文件系统,如果需要请改用 symlink()。
- 返回值
- 成功则返回0,失败返回-1,错误原因存于errno。
- 附加说明
- link()所建立的硬连接无法跨越不同文件系统,如果需要请改用 symlink()。
- 错误代码
- EXDEV 参数 oldpath 与 newpath 不是建立在同一文件系统。
- EPERM 参数 oldpath 与 newpath 所指的文件系统不支持硬连接
- EROFS 文件存在于只读文件系统内
- EFAULT 参数 oldpath 或 newpath 指针超出可存取内存空间。
- ENAMETOLLONG 参数 oldpath 或 newpath 太长
- ENOMEM 核心内存不足
- EEXIST 参数 newpath 所指的文件名已存在。
- EMLINK 参数 oldpath 所指的文件已达最大连接数目。
- ELOOP 参数 pathname 有过多符号连接问题
- ENOSPC 文件系统的剩余空间不足。
- EIO I/O 存取错误。
13.2.2 删除链接
unlink(删除文件)
相关函数 link,rename,remove
1 #include <unistd.h> 2 int unlink(const char * pathname);
- 函数说明
- unlink()会删除参数 pathname 指定的文件。
- 如果该文件名为最后连接点,但有其他进程打开了此文件,则在所有关于此文件的文件描述词皆关闭后才会删除。
- 如果参数 pathname 为一符号连接,则此连接会被删除。
- 函数功能:
- 删除 pathname 指定的硬链接(源文件和指定的硬链接文件都可以),并将由 pathname 所引用的文件链接计数减1
- 返回值
- 成功则返回0,失败返回-1,错误原因存于errno
- 错误代码
- EROFS 文件存在于只读文件系统内
- EFAULT 参数 pathname 指针超出可存取内存空间
- ENAMETOOLONG 参数 pathname 太长
- ENOMEM 核心内存不足
- ELOOP 参数 pathname 有过多符号连接问题
- EIO I/O 存取错误
13.2.3 remove 函数
remove(删除文件)
相关函数 link,rename,unlink
1 #include <stdio.h> 2 int remove(const char * pathname);
- 函数说明
- remove()会删除参数 pathname 指定的文件。
- 如果参数 pathname 为一文件,则调用 unlink() 处理,若参数 pathname 为一目录,则调用 rmdir() 来处理。请参考 unlink() 与 rmdir()。
- 对于文件,remove 的功能与 unlink 相同
- 对于目录,remove 的功能与 rmdir 相同
- 函数功能:
- 解除一个文件或目录的链接
- 返回值
- 成功则返回0,失败则返回-1,错误原因存于errno。
- 错误代码
- EROFS 欲写入的文件存在于只读文件系统内
- EFAULT 参数 pathname 指针超出可存取内存空间
- ENAMETOOLONG 参数 pathname 太长
- ENOMEM 核心内存不足
- ELOOP 参数 pathname 有过多符号连接问题
-
- EIO I/O 存取错误
13.2.4 rename 函数
rename(更改文件名称或位置)
相关函数 link,unlink,symlink
1 #include <stdio.h> 2 int rename(const char * oldpath, const char * newpath);
- 函数说明
- rename() 会将参数 oldpath 所指定的文件名称改为参数 newpath 所指的文件名称。若 newpath 所指定的文件已存在,则会被删除。
- 函数功能:
- 文件或目录更名
- 返回值
- 执行成功则返回0,失败返回-1,错误原因存于errno
13.2.5 例子
(1)硬链接的创建
file_hardlink.c
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <unistd.h> 4 #include <fcntl.h> 5 #include <string.h> 6 7 int main(int argc, char *argv[]) 8 { 9 if(argc < 0) { 10 fprintf(stderr, "usage:%s srcfile files\n", argv[0]); 11 exit(1); 12 } 13 14 int i; 15 16 for(i = 2; i < argc; i++){ 17 if(link(argv[1], argv[i]) < 0) { 18 perror("link error"); 19 continue; 20 } 21 } 22 23 printf("create success\n"); 24 return 0; 25 }
编译执行如下:
13.3 软链接(即符号链接)
13.3.1 创建软链接
(1)创建软链接
symlink(建立文件符号连接)
相关函数 link,unlink
1 #include <unistd.h> 2 int symlink( const char * oldpath, const char * newpath);
- 函数说明
- symlink() 以参数 newpath 指定的名称来建立一个新的连接(符号连接)到参数 oldpath 所指定的已存在文件。
- 参数 oldpath 指定的文件不一定要存在,如果参数 newpath 指定的名称为一已存在的文件则不会建立连接。
- 创建符号链接并不要求 oldpath 的存在
- 可以跨文件系统建立符号链接
- 软链接可以针对目录进行创建
- 函数功能
- 创建一个符号链接(软链接)
- 返回值
- 成功则返回0,失败返回-1,错误原因存于errno。
- 错误代码
- EPERM 参数 oldpath 与 newpath 所指的文件系统不支持符号连接
- EROFS 欲测试写入权限的文件存在于只读文件系统内
- EFAULT 参数 oldpath 或 newpath 指针超出可存取内存空间。
- ENAMETOOLONG 参数 oldpath 或 newpath 太长
- ENOMEM 核心内存不足
- EEXIST 参数 newpath 所指的文件名已存在。
- EMLINK 参数 oldpath 所指的文件已达到最大连接数目
- ELOOP 参数 pathname 有过多符号连接问题
- ENOSPC 文件系统的剩余空间不足
- EIO I/O 存取错误
(2)读取软链接
readlink(取得符号连接所指的文件)
相关函数 stat,lstat,symlink
1 #include <unistd.h> 2 ssize_t readlink(const char * path ,char * buf,size_t bufsiz);
- 函数说明
- readlink()会将参数 path 的符号连接内容存到参数 buf 所指的内存空间,返回的内容不是以 NULL 作字符串结尾,但会将字符串的字符数返回。若参数 bufsiz 小于符号连接的内容长度,过长的内容会被截断。
- 函数功能
- 打开该链接本身,并读该链接中的名字(源文件的路径)
- 返回值
- 成功则返回读到的字节数,失败则返回-1,错误代码存于errno。
- 错误代码
- EACCESS 取文件时被拒绝,权限不够
- EINVAL 参数 bufsiz 为负数
- EIO I/O 存取错误。
- ELOOP 欲打开的文件有过多符号连接问题。
- ENAMETOOLONG 参数 path 的路径名称太长
- ENOENT 参数 path 所指定的文件不存在
- ENOMEM 核心内存不足
- ENOTDIR 参数 path 路径中的目录存在但却非真正的目录。
13.3.2 例子
file_link.c
1 #include <stdio.h> 2 #include <string.h> 3 #include <fcntl.h> 4 #include <stdlib.h> 5 #include <errno.h> 6 #include <unistd.h> 7 8 int main(int argc, char *argv[]) 9 { 10 if(argc < 3) { 11 fprintf(stderr, "usage:%s srcfile linkfiles\n", argv[0]); 12 exit(1); 13 } 14 15 //对源文件创建符号链接(软链接) 16 if(symlink(argv[1], argv[2]) < 0) { 17 perror("symlink error"); 18 exit(1); 19 } 20 21 //读取软链接引用的源文件的内容 22 char buff[4096]; 23 ssize_t size; 24 memset(buff, 0, sizeof(buff)); 25 int fd = open(argv[2], O_RDONLY); 26 if(fd < 0) { 27 perror("open error"); 28 exit(1); 29 } 30 31 if((size = read(fd, buff, sizeof(buff))) < 0) { 32 perror("read error"); 33 exit(1); 34 } else { 35 write(STDOUT_FILENO, buff, size); 36 } 37 38 printf("\n"); 39 40 //读取软链接本身的内容 41 memset(buff, 0, sizeof(buff)); 42 if((size = readlink(argv[2], buff, sizeof(buff))) < 0) { 43 perror("readlink error"); 44 exit(1); 45 } else { 46 write(STDOUT_FILENO, buff, size); 47 } 48 49 printf("\n"); 50 51 return 0; 52 }
编译执行