Unix 创建符号链接后,是否可以更改其指向的内容?

Unix 创建符号链接后,是否可以更改其指向的内容?,unix,symlink,Unix,Symlink,是否有操作系统提供了一种机制(系统调用-不是命令行程序)来更改符号链接(symlink)引用的路径名,而不是通过断开旧的链接并创建新的路径名 POSIX标准没有。Solaris 10没有。MacOS X 10.5(Leopard)没有。(我可以相当肯定AIX和HP-UX都没有。从这个列表中可以看出,Linux也没有这样的系统调用。) 有什么有用的吗 (我希望答案是“不”。) 既然证明否定是困难的,让我们重新组织这个问题 如果您知道尚未列出的某些(类Unix)操作系统没有系统调用来重写符号链接的

是否有操作系统提供了一种机制(系统调用-不是命令行程序)来更改符号链接(symlink)引用的路径名,而不是通过断开旧的链接并创建新的路径名

POSIX标准没有。Solaris 10没有。MacOS X 10.5(Leopard)没有。(我可以相当肯定AIX和HP-UX都没有。从这个列表中可以看出,Linux也没有这样的系统调用。)

有什么有用的吗

(我希望答案是“不”。)


既然证明否定是困难的,让我们重新组织这个问题

如果您知道尚未列出的某些(类Unix)操作系统没有系统调用来重写符号链接的值(由
readlink()
返回的字符串),而不删除旧的符号链接并创建新的符号链接,请在回答中添加它或它们。

好的,不,您不能。您必须删除它并重新创建它。实际上,您可以覆盖符号链接,从而更新其引用的路径名:

$ ln -s .bashrc test
$ ls -al test
lrwxrwxrwx 1 pascal pascal 7 2009-09-23 17:12 test -> .bashrc
$ ln -s .profile test
ln: creating symbolic link `test': File exists
$ ln -s -f .profile test
$ ls -al test
lrwxrwxrwx 1 pascal pascal 8 2009-09-23 17:12 test -> .profile
EDIT:正如OP在评论中指出的那样,使用
--force
选项将使
ln
symlink()
之前执行系统调用
unlink()
。下面是我的linux机器上的
strace
的输出,证明了这一点:

$ strace -o /tmp/output.txt ln -s -f .bash_aliases test
$ grep -C3 ^unlink /tmp/output.txt 
lstat64("test", {st_mode=S_IFLNK|0777, st_size=7, ...}) = 0
stat64(".bash_aliases", {st_mode=S_IFREG|0644, st_size=2043, ...}) = 0
symlink(".bash_aliases", "test")        = -1 EEXIST (File exists)
unlink("test")                          = 0
symlink(".bash_aliases", "test")        = 0
close(0)                                = 0
close(1)                                = 0
所以我猜最后的答案是“不”

编辑:以下是从unix.stackexchange.com上复制的,大约在2016年

通过使用
重命名(2)
,首先在临时名称下创建新的符号链接,然后一次性完全覆盖旧的符号链接,这确实可以原子化地完成。作为缔约国:

如果newpath引用符号链接,则该链接将被覆盖

在shell中,您可以使用
mv-T
执行此操作,如下所示:

$ mkdir a b
$ ln -s a z
$ ln -s b z.new
$ mv -T z.new z
您可以
strace
最后一个命令,以确保它确实在发动机罩下使用
rename(2)

$ strace mv -T z.new z
lstat64("z.new", {st_mode=S_IFLNK|0777, st_size=1, ...}) = 0
lstat64("z", {st_mode=S_IFLNK|0777, st_size=1, ...}) = 0
rename("z.new", "z")                    = 0
请注意,在上面的示例中,
mv-T
strace
都是特定于Linux的

在FreeBSD上,交替使用
mv-h


编者按:这是Capistrano多年来一直在做的事情,从~2.15开始。请参阅。

取消链接并创建新符号链接最终不会做同样的事情吗?

没有必要显式取消链接旧符号链接。您可以这样做:

ln -s newtarget temp
mv temp mylink
(或使用等效的符号链接和重命名调用)。这比显式取消链接要好,因为重命名是原子的,所以可以确保链接始终指向旧的或新的目标。但是,这不会重用原始inode

在某些文件系统上,如果符号链接的目标足够短,则将其存储在inode本身(代替块列表)中;这是在创建时确定的

关于实际所有者和组无关紧要的说法,on Linux表示,有一种情况非常重要:

可以使用更改现有符号链接的所有者和组 立法会(二)。符号链接的所有权唯一重要的时候是 在具有粘性的目录中删除或重命名链接时 位集(见stat(2))

符号链接的最后访问和最后修改时间戳可以是 使用utimensat(2)或lutimes(3)进行更改

在Linux上,符号链接的权限不用于任何操作; 所有用户的权限始终为0777(读、写和执行) 类别),并且无法更改

是的,你可以

$ ln -sfn source_file_or_directory_name softlink_name

以上正确答案只是一个警告:

如果混淆了源和目标,则使用-f/--force方法会有丢失文件的风险:

mbucher@server2:~/test$ ls -la
total 11448
drwxr-xr-x  2 mbucher www-data    4096 May 25 15:27 .
drwxr-xr-x 18 mbucher www-data    4096 May 25 15:13 ..
-rw-r--r--  1 mbucher www-data 4109466 May 25 15:26 data.tar.gz
-rw-r--r--  1 mbucher www-data 7582480 May 25 15:27 otherdata.tar.gz
lrwxrwxrwx  1 mbucher www-data      11 May 25 15:26 thesymlink -> data.tar.gz
mbucher@server2:~/test$ 
mbucher@server2:~/test$ ln -s -f thesymlink otherdata.tar.gz 
mbucher@server2:~/test$ 
mbucher@server2:~/test$ ls -la
total 4028
drwxr-xr-x  2 mbucher www-data    4096 May 25 15:28 .
drwxr-xr-x 18 mbucher www-data    4096 May 25 15:13 ..
-rw-r--r--  1 mbucher www-data 4109466 May 25 15:26 data.tar.gz
lrwxrwxrwx  1 mbucher www-data      10 May 25 15:28 otherdata.tar.gz -> thesymlink
lrwxrwxrwx  1 mbucher www-data      11 May 25 15:26 thesymlink -> data.tar.gz
当然这是有意的,但通常会出现错误。因此,删除和重建符号链接需要更多的工作,但也节省了一点时间:

mbucher@server2:~/test$ rm thesymlink && ln -s thesymlink otherdata.tar.gz 
ln: creating symbolic link `otherdata.tar.gz': File exists

它至少保存了我的文件。

以防万一:有一种方法可以使用midnight commander(mc)编辑符号链接。 菜单命令为(在我的mc界面上为法语):

可翻译为:

File / Edit symbolic link
快捷方式是C-x C-s

也许它在内部使用了
ln--force
命令,我不知道


现在,我正试图找到一种方法,一次编辑大量符号链接(我就是这样来到这里的)。

从技术上讲,没有内置命令来编辑现有的符号链接。只需几个简短的命令即可轻松实现

这里有一个小的bash/zsh函数我写这个函数是为了更新现有的符号链接:

# -----------------------------------------
# Edit an existing symbolic link
#
# @1 = Name of symbolic link to edit
# @2 = Full destination path to update existing symlink with 
# -----------------------------------------
function edit-symlink () {
    if [ -z "$1" ]; then
        echo "Name of symbolic link you would like to edit:"
        read LINK
    else
        LINK="$1"
    fi
    LINKTMP="$LINK-tmp"
    if [ -z "$2" ]; then
        echo "Full destination path to update existing symlink with:"
        read DEST
    else
        DEST="$2"
    fi
    ln -s $DEST $LINKTMP
    rm $LINK
    mv $LINKTMP $LINK
    printf "Updated $LINK to point to new destination -> $DEST"
}

简单地重新链接有什么问题?为什么不发出
ln
命令(或API Equivalent)覆盖旧链接?你有什么问题?有趣-我在问是否有系统调用来执行编程工作,并且问题被标记为“属于其他站点”。有趣的是-根本不清楚你在寻找系统调用,你只是编辑了问题以添加此细节。那么,你怎么能指望人们在你写东西之前就把它删掉呢?@S.Lott:我正在写一篇关于安全和符号链接的论文。我曾断言“符号链接本身的实际所有者、组和权限是无关紧要的”,理由是符号链接的所有者只能删除它,而不能更改值。我反复检查,除了删除符号链接之外,没有其他方法可以达到“重写符号链接值”的效果。我忽略了对原始磁盘的直接访问,并以这种方式攻击FS-这需要root权限,我关心的是非root用户,而不是root用户可以做什么。@Pascal:对不起-直到人们偏离了我的意图,我才意识到我说的是系统调用(这显然与我所说的不同)。很抱歉我误导了你,这是无意的。为什么首先要取消链接?为什么不
# -----------------------------------------
# Edit an existing symbolic link
#
# @1 = Name of symbolic link to edit
# @2 = Full destination path to update existing symlink with 
# -----------------------------------------
function edit-symlink () {
    if [ -z "$1" ]; then
        echo "Name of symbolic link you would like to edit:"
        read LINK
    else
        LINK="$1"
    fi
    LINKTMP="$LINK-tmp"
    if [ -z "$2" ]; then
        echo "Full destination path to update existing symlink with:"
        read DEST
    else
        DEST="$2"
    fi
    ln -s $DEST $LINKTMP
    rm $LINK
    mv $LINKTMP $LINK
    printf "Updated $LINK to point to new destination -> $DEST"
}