书上的说法是:
lstat与stat相同,除非是符号链接,统计链接本身,而不是链接所引用文件。所以,stat和lstat的区别是:stat遵循链接,但lstat不是
当初看这段话并没有真正理解,下面详细解释下:
首先,无论是stat
还是lstat
,对于硬链接文件,都将其视为regular文件,不同点只在于符号链接(symlink)文件。
对于stat(file, &mystat)
这个系统调用,无论是读取regular文件还是symlink文件,通过mystat.st_mode
获取到的文件类型都必然是regular文件,即S_ISREG(mystat.st_mode) == 1
。
对于lstat(file, &mystat)
这个系统调用,当file是symlink文件时,通过mystat.st_mode
获取到的文件类型是link文件,即S_ISLNK(mystat.st_mode) == 1
。
所以,当我们想要识别符号链接文件的时候,只能使用lstat
;当我们关注的是符号链接指向的文件时,就应该使用stat
。
下面展示mycp程序的一部分,file1是待复制的文件,file2是复制得到的文件。对于符号链接文件会创建对应的新符号链接,而不是简单的复制文件。对于reguler文件,会复制文件。
struct stat mystat;
if(lstat(file1, &mystat) < 0){//must be lstat, not stat
printf("stat %s fail\n", file1);
exit(-1);
}
printf("%s st_mode is %x\n", file1, mystat.st_mode);
if(S_ISLNK(mystat.st_mode)){
char linkName[FILE_NAME_LEN], fullLinkName[FILE_NAME_LEN];
strcpy(fullLinkName,file2);
readlink(file1, linkName, FILE_NAME_LEN);
for(int i=strlen(fullLinkName)-1;i>=0;i--){
if(fullLinkName[i] == '/'){
fullLinkName[i+1] = 0;
break;
}
}
strcat(fullLinkName, linkName);
symlink(fullLinkName, file2);
printf("link file %s to file %s\n", fullLinkName, file2);
}
else if(S_ISREG(mystat.st_mode)){
int oldFd = open(file1, O_RDONLY);
int newFd = open(file2, O_RDWR | O_CREAT | O_TRUNC, 0664);
int n=0;
char buf[4096];
while(n = read(oldFd, buf, 4096)){
write(newFd, buf, n);
}
close(oldFd);
close(newFd);
printf("copy file %s to file %s\n", file1, file2);
}