1.创建符号链接
#include<unistd.h>
定义函数 int symlink( const char * oldpath,const char * newpath);
函数说明 symlink()以参数newpath指定的名称来建立一个新的连接(符号连接)到参数oldpath所指定的已存在文件。参数oldpath指定的文件不一定要存在 (如果不存在,符号链接也可建立,只是利用该符号链接读或写文件时会出粗),如果参数newpath指定的名称为一已存在的文件则不会建立连接。
返回值 成功则返回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.读写符号链接的目的文件
用户可以像操作普通文件一样操作链接文件,这时实际操作的是符号链接所指向的文件。
3.读写多重符号链接的目的文件
当创建了一个符号连接时,read和write函数会一直跟踪符号链接,知道遇到实际目的文件为止。因此即使存在多重符号链接,也可随便操作该链接链上的任意一个,实现对实际文件的读写。
范例:
//mul_link.c
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#define MAX 1024
int main(void)
{
int fd;
char buf[MAX];
int n;
if(symlink("test.txt", "sl") == -1){ /* 创建一个符号链接,指向test.txt文件 */
perror("fail to create symbol link");
exit(1);
}
/* 再次创建一个符号链接,指向sl。就此形成了一个符号链接链:sl2->sl->test.txt
* test.txt文件是目的文件,也是该符号链接链的重点
*/
if(symlink("sl", "sl2") == -1){
perror("fail to create symbol link");
exit(1);
}
if((fd = open("sl2", O_RDWR)) == -1){ /* 打开的实际上是目的文件test.txt */
perror("fail to open");
exit(1);
}
printf("already create symbol-links/n");
if((n = read(fd, buf, MAX)) == -1){ /* 读文件的内容 */
perror("fail to read");
exit(1);
}
buf[n] = '/0';
printf("file content is : %s/n", buf); /* 输出结果*/
strcat(buf, ", admin");
if(write(fd, buf, strlen(buf)) == -1){ /* 向该文件写内容 */
perror("fail to write");
exit(1);
}
printf("done/n"); /* 输出提示信息 */
close(fd);
return 0;
}
4.读写符号链接
符号链接是文件的一种,这种文件也哟自己保存的内容。符号链接中保存的是目的文件的路径,其是一个字符串。
若要读取一个符号链接本身的内容,可用如下 函数:
#include<unistd.h>
定义函数 int 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路径中的目录存在但却非真正的目录。
buf缓冲区中的字符串不以'/0'结束,必要时自己添 。
范例:
//readlink.c
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#define MAX 1024
int main()
{
char buf[MAX];
int fd;
if(syslink("root/alei/linux/code/test.txt","s1")==-1){
perror("fail to create symbol-link");
exit(1);
}
if(syslink("s1","s2")==-1){
perror("fail to create symbol-link");
exit(1);
}
if(readlink("s1",buf,MAX)==-1){
perror("fail to read link");
exit(1);
}
printf("%s/n",buf);
if(readlink("s1",buf,MAX)==-1){
perror("fail to read link");
exit(1);
}
printf("%s/n",buf);
return 0;
}
如果使用一个不存在的文件作为符号链接的目的文件,readlink函数也可以成功读取符号链接的内容,因为readlink函数在符号链接的数据库爱上读取内容,该内容是一个路径名,只是该路径端点上的文件不存在而已。
5.获得符号链接的状态
符号链接是一种特殊文件,这文件也有自己的状态。
//sys_stat.c
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
int main(void)
{
struct stat buf; /* 存储文件状态信息 */
if(stat("sl", &buf) == -1){
perror("fail to stat");
exit(1);
}
printf("permission : %d/n", buf.st_mode); /* 打印文件权限字 */
printf("inode number : %d/n", buf.st_ino); /* 打印i节点号 */
printf("device number : %d/n", buf.st_dev); /* 打印文件系统设备号 */
printf("r-device number : %d/n", buf.st_rdev); /* 打印硬件设备设备号 */
printf("link : %d/n", buf.st_nlink); /* 打印硬链接数 */
printf("uid : %d/n", buf.st_uid); /* 打印所有者用户ID */
printf("gid : %d/n", buf.st_gid); /* 打印所有者组ID */
printf("file size : %d/n", buf.st_size); /* 打印文件的大小 */
printf("access time : %d/n", buf.st_atime); /* 打印最近一次的访问时间*/
printf("motify time : %d/n", buf.st_mtime); /* 打印最近一次修改文件内容的时间 */
printf("change time : %d/n", buf.st_ctime); /* 打印最近一次修改文件属性的时间 */
printf("buf size : %d/n", buf.st_blksize); /* 打印最适的缓冲区大小 */
printf("block size : %d/n", buf.st_blocks); /* 打印文件在外存上占用的盘块数 */
if(stat("test.txt", &buf) == -1){
perror("fail to stat");
exit(1);
}
printf("permission : %d/n", buf.st_mode); /* 打印文件权限字 */
printf("inode number : %d/n", buf.st_ino); /* 打印i节点号 */
printf("device number : %d/n", buf.st_dev); /* 打印文件系统设备号 */
printf("r-device number : %d/n", buf.st_rdev); /* 打印硬件设备设备号 */
printf("link : %d/n", buf.st_nlink); /* 打印硬链接数 */
printf("uid : %d/n", buf.st_uid); /* 打印所有者用户ID */
printf("gid : %d/n", buf.st_gid); /* 打印所有者组ID */
printf("file size : %d/n", buf.st_size); /* 打印文件的大小 */
printf("access time : %d/n", buf.st_atime); /* 打印最近一次的访问时间*/
printf("motify time : %d/n", buf.st_mtime); /* 打印最近一次修改文件内容的时间 */
printf("change time : %d/n", buf.st_ctime); /* 打印最近一次修改文件属性的时间 */
printf("buf size : %d/n", buf.st_blksize); /* 打印最适的缓冲区大小 */
printf("block size : %d/n", buf.st_blocks); /* 打印文件在外存上占用的盘块数 */
return 0;
}
这两次输出的内容是一样的,因为使用stat函数时,实际得到的是目的文件的状态信息。
如果要知道符号链接文件本身的文件状态信息。可用:
#include<sys/stat.h>
#include<unistd.h>
定义函数 int lstat (const char * file_name.struct stat * buf);
函数说明 lstat()与stat()作用完全相同,都是取得参数file_name所指的文件状态,其差别在于,当文件为符号连接时,lstat()会返回该link本身的状态。详细内容请参考stat()。
返回值 执行成功则返回0,失败返回-1,错误代码存于errno。
范例:
//sym_lstat.c
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
int main(void)
{
struct stat buf; /* 存储文件状态信息 */
if(lstat("sl", &buf) == -1){
perror("fail to stat");
exit(1);
}
printf("permission : %d/n", buf.st_mode); /* 打印文件权限字 */
printf("inode number : %d/n", buf.st_ino); /* 打印i节点号 */
printf("device number : %d/n", buf.st_dev); /* 打印文件系统设备号 */
printf("r-device number : %d/n", buf.st_rdev); /* 打印硬件设备设备号 */
printf("link : %d/n", buf.st_nlink); /* 打印硬链接数 */
printf("uid : %d/n", buf.st_uid); /* 打印所有者用户ID */
printf("gid : %d/n", buf.st_gid); /* 打印所有者组ID */
printf("file size : %d/n", buf.st_size); /* 打印文件的大小 */
printf("access time : %d/n", buf.st_atime); /* 打印最近一次的访问时间*/
printf("motify time : %d/n", buf.st_mtime); /* 打印最近一次修改文件内容的时间 */
printf("change time : %d/n", buf.st_ctime); /* 打印最近一次修改文件属性的时间 */
printf("buf size : %d/n", buf.st_blksize); /* 打印最适的缓冲区大小 */
printf("block size : %d/n", buf.st_blocks); /* 打印文件在外存上占用的盘块数 */
if(stat("test.txt", &buf) == -1){
perror("fail to stat");
exit(1);
}
printf("permission : %d/n", buf.st_mode); /* 打印文件权限字 */
printf("inode number : %d/n", buf.st_ino); /* 打印i节点号 */
printf("device number : %d/n", buf.st_dev); /* 打印文件系统设备号 */
printf("r-device number : %d/n", buf.st_rdev); /* 打印硬件设备设备号 */
printf("link : %d/n", buf.st_nlink); /* 打印硬链接数 */
printf("uid : %d/n", buf.st_uid); /* 打印所有者用户ID */
printf("gid : %d/n", buf.st_gid); /* 打印所有者组ID */
printf("file size : %d/n", buf.st_size); /* 打印文件的大小 */
printf("access time : %d/n", buf.st_atime); /* 打印最近一次的访问时间*/
printf("motify time : %d/n", buf.st_mtime); /* 打印最近一次修改文件内容的时间 */
printf("change time : %d/n", buf.st_ctime); /* 打印最近一次修改文件属性的时间 */
printf("buf size : %d/n", buf.st_blksize); /* 打印最适的缓冲区大小 */
printf("block size : %d/n", buf.st_blocks); /* 打印文件在外存上占用的盘块数 */
return 0;
}
这一次输出的内容是不一样的。
6.更改符号链接的所有者
chown函数用于符号链接时,会改变符号链接所指向的文件的所有者的用户ID,而不是链接文件本身的用户ID。
若要改变符号链接本身的所有者ID,用如下函数:
#include <unistd.h>
int lchown(const char * pathname,uid_t owner,gid_t group);
owner的值为-1时,符号链接的所有者ID不发生变化,同理对于组ID也是一样的。
//sym_chown.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include <string.h>
int main(void)
{
struct stat statbuf;
char buf[1024];
printf("before changing/n/n"); /* 输出提示信息 */
if(stat("test.txt", &statbuf) == -1){ /* 得到目的文件的状态信息 */
perror("fail to get status");
exit(1);
}
printf("the owner of test.txt is : %d/n", (unsigned int)statbuf.st_uid);
printf("the group of test.txt is : %d/n", (unsigned int)statbuf.st_gid);
if(lstat("sl", &statbuf) == -1){ /* 使用lstat函数得到符号链接的状态信息 */
perror("fail to get status");
exit(1);
}
printf("the owner of sl is : %d/n", (unsigned int)statbuf.st_uid);
printf("the group of sl is : %d/n", (unsigned int)statbuf.st_gid);
if(chown("sl", 0, -1) == -1){ /* 改变目的文件的所有者 */
perror("fail to change owner");
exit(1);
}
printf("after changing/n"); /* 输出提示信息 */
if(stat("test.txt", &statbuf) == -1){ /* 再次得到目的文件的文件状态信息 */
perror("fail to get status");
exit(1);
}
printf("the owner of test.txt is : %d/n", (unsigned int)statbuf.st_uid);
printf("the group of test.txt is : %d/n", (unsigned int)statbuf.st_gid);
if(lstat("sl", &statbuf) == -1){ /* 使用lstat函数得到符号链接本身的文件状态信息 */
perror("fail to get status");
exit(1);
}
printf("the owner of sl is : %d/n", (unsigned int)statbuf.st_uid);
printf("the group of sl is : %d/n", (unsigned int)statbuf.st_gid);
return 0;
}