示例脚本:
#!/bin/sh -e
sudo useradd -m user_a
sudo useradd -m user_b -g user_a
sudo chmod g+w /home/user_a
set +e
sudo su user_a <<EOF
cd
umask 027
>> file_a
>> file_b
>> file_c
ls -l file_*
EOF
sudo su user_b <<EOF
cd
umask 000
rm -f file_*
ls -l ~user_a/
set -x
mv ~user_a/file_a .
cp ~user_a/file_b .
ln ~user_a/file_c .
set +x
ls -l ~/
EOF
sudo userdel -r user_b
sudo userdel -r user_a
输出:
-rw-r----- 1 user_a user_a 0 Jul 11 12:26 file_a
-rw-r----- 1 user_a user_a 0 Jul 11 12:26 file_b
-rw-r----- 1 user_a user_a 0 Jul 11 12:26 file_c
total 0
-rw-r----- 1 user_a user_a 0 Jul 11 12:26 file_a
-rw-r----- 1 user_a user_a 0 Jul 11 12:26 file_b
-rw-r----- 1 user_a user_a 0 Jul 11 12:26 file_c
+ mv /home/user_a/file_a .
+ cp /home/user_a/file_b .
+ ln /home/user_a/file_c .
ln: failed to create hard link ‘./file_c’ => ‘/home/user_a/file_c’: Operation not permitted
+ set +x
total 0
-rw-r----- 1 user_a user_a 0 Jul 11 12:26 file_a
-rw-r----- 1 user_b user_a 0 Jul 11 12:26 file_b
userdel: user_b mail spool (/var/mail/user_b) not found
userdel: user_a mail spool (/var/mail/user_a) not found
答案1
您运行的是哪个系统?在 Linux 上,该行为是可通过/proc/sys/fs/protected_hardlinks
(或sysctl fs.protected_hardlinks
) 配置的。
该行为描述于proc(5)
:
/proc/sys/fs/protected_hardlinks
(自Linux 3.6起)
当该文件中的值为0时,对硬链接的创建没有限制(即,这是Linux 3.6之前的历史行为)。当该文件中的值为 1 时,只有满足以下条件之一才能创建到目标文件的硬链接:
- 调用进程具有 CAP_FOWNER 能力...
- 创建链接的进程的文件系统 UID 与目标文件的所有者 (UID) 匹配...
- 以下所有条件均成立:
- 目标是一个常规文件;
- 目标文件未启用其设置用户 ID 模式位;
- 目标文件没有同时启用其设置组 ID 和组可执行模式位;和
- 调用者有权读取和写入目标文件(通过文件的权限掩码或因为它具有合适的功能)。
这样做的理由应该很清楚:
该文件中的默认值为 0。将该值设置为 1 可防止由基于硬链接的检查时间、使用时间竞争引起的一类长期存在的安全问题,这些问题最常见于全局可写目录中,例如作为/tmp。
在 Debian 系统protected_hardlinks
和类似的protected_symlinks
默认系统上,因此在没有对文件的写访问权限的情况下建立链接是行不通的:
$ ls -ld . ./foo
drwxrwxr-x 2 root itvirta 4096 Jul 11 16:43 ./
-rw-r--r-- 1 root root 4 Jul 11 16:43 ./foo
$ mv foo bar
$ ln bar bar2
ln: failed to create hard link 'bar2' => 'bar': Operation not permitted
设置protected_hardlinks
为零会解除限制:
# echo 0 > /proc/sys/fs/protected_hardlinks
$ ln bar bar2
$ ls -l bar bar2
-rw-r--r-- 2 root root 4 Jul 11 16:43 bar
-rw-r--r-- 2 root root 4 Jul 11 16:43 bar2
答案2
通常,每个文件都有一个目录项(也有例外,但无需赘述)。
目录项本质上是一个姓名+号码一对;文件的名称和一个称为 i 编号的数字。这是一个名为“我的列表,其中包含每个文件的所有真实详细信息,结构称为i节点。
i 节点包含文件所有者的详细信息等。它实际上由文件所有者“拥有”。其中的字段之一是使用次数,通常设置为 1。
当建立硬链接时,它只是另一个名称+数字对,与第一个没有区别。此时使用计数增加 1;当硬链接(或原始目录项,因为它们具有相同的地位)被删除时,使用计数减1。当它变为零时,文件消失。您可以从中看到,创建硬链接意味着您必须能够在不是其所有者时更改 i 节点。
这是 UNIX 上多年来的一个问题,也是符号链接(或符号链接,有时称为软链接) 被引入。这是一个姓名+姓名对,基本上只是为原始文件提供一个别名。 i 节点中没有任何变化;这只是一个重定向。缺点是可以删除原始文件而符号链接不会消失,并且最终指向一个不存在的文件。
答案3
从man 2 link
:“...两个名称都引用同一个文件(因此具有相同的权限和所有权)”
即使您有权读取/复制/移动文件,也不能使用不同的权限创建指向同一文件的两个链接或者所有权,作为模式,uid和吉德存储在您要从两个不同目录创建链接的索引节点中,而不是存储在目录条目本身中。
考虑:
$ touch file_a
$ touch file_b
$ ln file_a file_A
$ ls -iln
total 0
1310731 -rw-rw-r-- 2 1000 1000 0 Jul 11 08:45 file_a
1310731 -rw-rw-r-- 2 1000 1000 0 Jul 11 08:45 file_A
1320710 -rw-rw-r-- 1 1000 1000 0 Jul 11 08:45 file_b
======= ===================================== ======
^ ^ ^
| | \-- names, stored in directory
| \-- file metadata, stored in inode
\-- inode number, stored in directory and pointing to inode
在这个例子中,file_a
并且file_A
有相同的inode号,所以一定将所有相同的属性存储在 inode 中。