在一台 Linux 机器(实际上是一个计算集群)上,我从另一个用户那里复制了一个文件夹(他授予我使用适当的 chmod 执行此操作的权限)。
该文件夹包含我无法访问的文件的符号链接。我想更新它们,以便它们指向我拥有的相同文件的副本。
但是,当我尝试使用 这样做时ln -sf
,我得到了Permission denied
。
为什么会这样?
这就是链接:
$ ls -l 50ATC_Rep2.fastq
lrwxrwxrwx 1 bli cifs-BioIT 55 21 nov. 13:45 50ATC_Rep2.fastq -> /pasteur/homes/mmazzuol/Raw_data/CHIP_TEST/BM50.2.fastq
我无权访问其目标,但我有它的副本。这就是我想要的新目标:
$ ls -l ../../../raw_data/CHIP_TEST/BM50.2.fastq
-rwxr-xr-x 1 bli cifs-BioIT 4872660831 21 nov. 14:00 ../../../raw_data/CHIP_TEST/BM50.2.fastq
这就是我尝试时发生的情况ln -sf
:
$ ln -sf ../../../raw_data/CHIP_TEST/BM50.2.fastq 50ATC_Rep2.fastq
ln: accessing `50ATC_Rep2.fastq': Permission denied
看来当前目标的权限才是重要的,而不是链接本身的权限。
我可以通过先删除链接然后重新创建它来规避该问题:
$ rm 50ATC_Rep2.fastq
rm: remove symbolic link `50ATC_Rep2.fastq'? y
$ ln -s ../../../raw_data/CHIP_TEST/BM50.2.fastq 50ATC_Rep2.fastq
$ ls -l 50ATC_Rep2.fastq
lrwxrwxrwx 1 bli cifs-BioIT 40 21 nov. 18:57 50ATC_Rep2.fastq -> ../../../raw_data/CHIP_TEST/BM50.2.fastq
为什么我可以删除链接,但无法更新?
答案1
看起来好像ln
Linux 上的 GNU 实现使用了stat()
函数判断目标是否存在。该函数需要解析符号链接,因此当无法访问预先存在的链接的目标时,该函数将返回EACCESS
(“权限被拒绝”)并且实用程序失败。这已strace
在 Ubuntu Linux 系统上得到验证。
让 GNUln
使用lstat()
相反,它不解析符号链接,您应该使用其(非标准)-n
选项来调用它(GNU 另外用作 的--no-dereference
别名-n
)。
ln -s -n -f ../../../raw_data/CHIP_TEST/BM50.2.fastq 50ATC_Rep2.fastq
正在阅读POSIX 规范ln
,我真的无法弄清楚 GNU 是否ln
对规范中某些未定义或未指定的行为这样做,但它可能利用了这样一个事实……
如果目标路径存在并且是由上一步创建的,未指定是否
ln
应将诊断消息写入标准错误,对当前源文件不执行任何操作,并继续处理任何剩余的源文件;或将继续处理当前的source_file。
这里的“未指定”位可能会给予 GNUln
其行为的许可,至少如果我们允许自己将“前一步”解释为“目标路径是符号链接”。
该选项的 GNU 文档-n
主要关注目标是指向某个对象的符号链接的情况。目录:
'-n'
'--no-dereference'
Do not treat the last operand specially when it is a symbolic link
to a directory. Instead, treat it as if it were a normal file.
When the destination is an actual directory (not a symlink to one),
there is no ambiguity. The link is created in that directory. But
when the specified destination is a symlink to a directory, there
are two ways to treat the user's request. 'ln' can treat the
destination just as it would a normal directory and create the link
in it. On the other hand, the destination can be viewed as a
non-directory--as the symlink itself. In that case, 'ln' must
delete or backup that symlink before creating the new link. The
default is to treat a destination that is a symlink to a directory
just like a directory.
This option is weaker than the '--no-target-directory' ('-T')
option, so it has no effect if both options are given.
当目标是目录的符号链接时, GNU 的默认行为ln
是将新的符号链接放入该目录中(即,取消引用该目录的链接)。当预先存在的链接的目标不可访问时,它会选择发出诊断消息并失败(标准文本允许)。
另一方面,当目标是指向某个对象的符号链接时,OpenBSD ln
(可能还有其他 BSD 系统)的行为将类似于 GNU。ln
ln
无障碍目录,但如果预先存在的链接的目标是,则将根据请求取消链接并重新创建符号链接不是无障碍。即,它选择继续操作(标准文本允许)。
另外,ln
OpenBSD 上的 GNU 的行为类似于 OpenBSD 的本机ln
,这有点有趣。
删除预先存在的符号链接rm
不是任何问题,因为您似乎对其所在目录具有写入和可执行权限。