Linux系统中为了解决文件共享问题,引入了软链接和硬链接的概念,软链接又称符号链接,即 soft link 或 symbolic link ,硬链接即为 hard link 。 同时它们还带来了隐藏文件路径、增加权限安全及节省存储等好处。
soft link
symbolic link
hard link
若一个文件指向另一个文件,该文件的内容仅仅是另一个文件的 path ,则其为软链接。 若一个 inode号 对应多个文件名,则称这些文件为硬链接。换言之,硬链接就是同一个文件使用了多个别名。 软链接可由命令 ln 创建,硬链接可由命令 link或ln 创建。
path
inode号
ln
link或ln
由于硬链接的文件是有着相同 inode号 ,仅文件名不同,因此硬链接存在以下几点特性:
inode 和 data blocks
12345678910111213141516171819202122232425262728
$ lltotal 4-rw-r--r-- 1 root root 928 Nov 11 08:37 tstfile$ ln tstfile hlink$ lltotal 8-rw-r--r-- 2 root root 928 Nov 11 08:37 hlink-rw-r--r-- 2 root root 928 Nov 11 08:37 tstfile$ stat tstfile File: ‘tstfile’ Size: 928 Blocks: 8 IO Block: 4096 regular fileDevice: 803h/2051d Inode: 4851726 Links: 2Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root)Access: 2017-11-11 08:37:07.554081068 +0800Modify: 2017-11-11 08:37:07.554081068 +0800Change: 2017-11-11 08:37:42.216988088 +0800 Birth: -$ stat hlink File: ‘hlink’ Size: 928 Blocks: 8 IO Block: 4096 regular fileDevice: 803h/2051d Inode: 4851726 Links: 2Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root)Access: 2017-11-11 08:37:07.554081068 +0800Modify: 2017-11-11 08:37:07.554081068 +0800Change: 2017-11-11 08:37:42.216988088 +0800 Birth: -
因为硬链接文件具有相同的地位,并没有谁指向谁之说,所以想要查找一个 inode号 对应的所有硬链接文件并不容易,通常需要遍历目录下所有的文件,系统里可通过 find 命令查找一个文件相关的所有硬链接文件。
find
1234567891011121314
$ mkdir dir$ ln tstfile dir/hlink$ find ./ -samefile tstfile./dir/hlink./hlink./tstfile$ ls -i tstfile4851726 tstfile$ find ./ -inum 4851726./dir/hlink./hlink./tstfile
可以通过命令 strace find ./ -samefile tstfile 查看具体执行的系统调用,发现该命令会在输入的目录下查询所有的文件,输出与参数文件 inode num 一致的文件,所以在目录里文件非常多时,该命令会非常耗时的。
strace find ./ -samefile tstfile
inode num
软链接与硬链接不同,若一个文件的数据块中存放的内容是另一文件的路径名时,则该文件就是软链接。 软链接就是一个普通文件,只是数据块内容有点特殊。 软链接有着自己的 inode 号以及数据块,因此软链接的创建与使用没有类似硬链接的诸多限制。
inode
软链接的特性如下:
i_nlink
$ ln -s tstfile slink$ lltotal 4lrwxrwxrwx 1 root root 7 Nov 11 08:39 slink -> tstfile-rw-r--r-- 1 root root 928 Nov 11 08:37 tstfile$ stat tstfile File: ‘tstfile’ Size: 928 Blocks: 8 IO Block: 4096 regular fileDevice: 803h/2051d Inode: 4851726 Links: 1Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root)Access: 2017-11-11 08:37:07.554081068 +0800Modify: 2017-11-11 08:37:07.554081068 +0800Change: 2017-11-11 08:39:04.749766771 +0800 Birth: - $ stat slink File: ‘slink’ -> ‘tstfile’ Size: 7 Blocks: 0 IO Block: 4096 symbolic linkDevice: 803h/2051d Inode: 4851778 Links: 1Access: (0777/lrwxrwxrwx) Uid: ( 0/ root) Gid: ( 0/ root)Access: 2017-11-11 08:39:24.730713312 +0800Modify: 2017-11-11 08:39:22.901718205 +0800Change: 2017-11-11 08:39:22.901718205 +0800 Birth: -$ readlink slinktstfile
Linux里由命令 stat 来获取一个文件的状态,文件状态保持在数据结构 struct stat 里,定义如下:
stat
struct stat
123456789101112131415
struct stat { dev_t st_dev; /* ID of device containing file */ ino_t st_ino; /* inode number */ mode_t st_mode; /* protection */ nlink_t st_nlink; /* number of hard links */ uid_t st_uid; /* user ID of owner */ gid_t st_gid; /* group ID of owner */ dev_t st_rdev; /* device ID (if special file) */ off_t st_size; /* total size, in bytes */ blksize_t st_blksize; /* blocksize for file system I/O */ blkcnt_t st_blocks; /* number of 512B blocks allocated */ time_t st_atime; /* time of last access */ time_t st_mtime; /* time of last modification */ time_t st_ctime; /* time of last status change */};
其中 st_mode 变量用来表示文件类型的,特征位的定义如下:
st_mode
1234567891011121314151617181920212223
S_IFMT 0170000 bit mask for the file type bit fieldsS_IFSOCK 0140000 socketS_IFLNK 0120000 symbolic linkS_IFREG 0100000 regular fileS_IFBLK 0060000 block deviceS_IFDIR 0040000 directoryS_IFCHR 0020000 character deviceS_IFIFO 0010000 FIFOS_ISUID 0004000 set-user-ID bitS_ISGID 0002000 set-group-ID bit (see below)S_ISVTX 0001000 sticky bit (see below)S_IRWXU 00700 mask for file owner permissionsS_IRUSR 00400 owner has read permissionS_IWUSR 00200 owner has write permissionS_IXUSR 00100 owner has execute permissionS_IRWXG 00070 mask for group permissionsS_IRGRP 00040 group has read permissionS_IWGRP 00020 group has write permissionS_IXGRP 00010 group has execute permissionS_IRWXO 00007 mask for permissions for others (not in group)S_IROTH 00004 others have read permissionS_IWOTH 00002 others have write permissionS_IXOTH 00001 others have execute permission
POSIX标准里定义了如下的宏来检查文件类型:
1234567
S_ISREG(m) is it a regular file?S_ISDIR(m) directory?S_ISCHR(m) character device?S_ISBLK(m) block device?S_ISFIFO(m) FIFO (named pipe)?S_ISLNK(m) symbolic link? (Not in POSIX.1-1996.)S_ISSOCK(m) socket? (Not in POSIX.1-1996.)
结合上面的描述,我们可以写如下测试代码:
12345678910111213141516171819202122232425262728293031323334353637
$ cat file_stat.cc#include <iostream>#include <string>#include <sys/stat.h>#include <unistd.h>using namespace std;int main(int argc, char* argv[]){ struct stat fstat; string file_path = argv[1]; # use lstat instead of stat as lstat handle symbolic link itself # when input path is a symbolic, not the file it refers to. int ret = lstat(file_path.c_str(), &fstat); cout << "file path: " << file_path << endl; cout << "file size: " << fstat.st_size << endl; cout << "file ino: " << fstat.st_ino << endl; cout << "file mode: " << fstat.st_mode << endl; cout << "file nlink: " << fstat.st_nlink << endl; if (S_ISREG(fstat.st_mode)) { cout << "regular file: " << file_path << endl; } else if (S_ISLNK(fstat.st_mode)) { cout << "link file: " << file_path << endl; char buf[256]; ret = readlink(file_path.c_str(), buf, 255); buf[ret] = '\0'; cout << "readlink return " << ret << endl; cout << "link file real path: " << buf << endl; } return 0;}//g++ -std=c++11 -ofile_stat file_stat.cc
命令行输出
1234567891011121314151617
$ ./file_stat hlinkfile path: hlinkfile size: 928file ino: 4851726file mode: 33188file nlink: 3regular file: hlink$ ./file_stat slinkfile path: slinkfile size: 7file ino: 4851778file mode: 41471file nlink: 1link file: slinkreadlink return 7link file real path: tstfile
https://www.ibm.com/developerworks/cn/linux/l-cn-hardandsymb-links/index.html http://www.giannistsakiris.com/2011/04/15/counting-and-listing-hard-links-on-linux/