シンボリックリンクが作成された後、それが指すものを変更できますか?


122

古いシンボリックリンクを解除して新しいシンボリックリンクを作成する以外の方法で、シンボリックリンク(symlink)によって参照されるパス名を変更するメカニズム(システムコール-コマンドラインプログラムではない)を提供するオペレーティングシステムはありますか?

POSIX標準ではサポートされていません。Solaris 10ではサポートされていません。MacOS X 10.5(Leopard)ではサポートされていません。(私は、AIXもHP-UXもどちらも実行しないことを確信しています。このLinuxシステムコールのリストから判断する、Linuxにもそのようなシステムコールはありません。)

何かすることはありますか?

(答えは「いいえ」であると期待しています。)


ネガを証明するのは難しいので、質問を整理してみましょう。

まだリストされていない(Unixのような)オペレーティングシステムにreadlink()、古いシンボリックリンクを削除して新しいシンボリックリンクを作成せずにシンボリックリンクの値(によって返される文字列)を書き換えるシステムコールがないことがわかっている場合は、追加してください—またはそれら—答えで。


単に再リンクすることの何が問題になっていますか?lnコマンド(または同等のAPI)を発行して古いリンクを上書きしないのはなぜですか?どんな問題がありますか
S.Lott

9
おかしい-プログラミングジョブを実行するためのシステムコールがあるかどうかを尋ねているところ、その質問は「他のサイトに属している」とマークされています。
ジョナサンレフラー、

3
おもしろい-システムコールを探していて、この詳細を追加するために質問を編集しただけなのは明らかではありません。それで、あなたがそれを書く前に、人々が何かを差し引くことをどのように期待できますか?
Pascal Thivent

2
@ S.Lott:セキュリティとシンボリックリンクに関する論文を書いています。ある時点で、「実際の所有者、グループ、シンボリックリンク自体に対する権限は重要ではない」と主張し、シンボリックリンクの所有者はそれを削除することしかできず、値を変更することはできないと考えています。「シンボリックリンクの値を書き換える」という効果を達成するためにシンボリックリンクを削除する以外に方法がないことを再確認しています。私はrawディスクへの直接アクセスを無視し、FSをそのようにハッキングしています。ルート権限が必要であり、私の懸念は非rootユーザーに関するものであり、rootができることではありません。
ジョナサンレフラー、

4
@Pascal:すみません-私がシステムコールについて話していることは、人々が私が意図したもの(私が言ったものとは明らかに異なっていた)から正直に離れるまで話をしていたことがはっきりしないことに気づきませんでした。誤解して申し訳ありません。それは意図的ではありませんでした。
ジョナサンレフラー、

回答:


106

私の知る限り、できません。削除して再作成する必要があります。実際には、シンボリックリンクを上書きして、それによって参照されるパス名を更新できます。

$ 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

編集:OPがコメントで指摘したように、この--forceオプションを使用するlnと、unlink()before へのシステムコールが実行されますsymlink()。以下は、strace私のLinuxボックスの出力です。

$ 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

最終的な答えは「いいえ」だと思います。

編集:以下は、2016年頃のunix.stackexchange.comのArto Bendikenの回答からコピーされたものです。

これ確かrename(2)に、最初に一時的な名前で新しいシンボリックリンクを作成し、次に古いシンボリックリンクを一度に完全に上書きすることにより、アトミックに行うことができます。同様にmanページの状態:

newpathがシンボリックリンクを参照している場合、リンクは上書きされます。

シェルでは、これを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 -TstraceはLinux固有のものであることに注意してください。

FreeBSDでは、mv -h交互に使用します。

編集者注:これは、カピストラーノが〜2.15以降、何年にもわたって行ってきた方法です。このプルリクエストをご覧ください。


2
'-f'オプションは、 'ln'にunlink()を実行させ、次にsymlink()システムコールを実行させませんか?
ジョナサンレフラー

1
します。しかし、質問は「1つのステップでそれを行う方法」として認識された可能性があり、結局、「ステップ」の定義(コマンドライン)に要約されますか?syscall?
マイケルクレリン-ハッカー、

1
私はあなたがあなたの質問にシステムコールの文言を追加したことに気づきました;-)
マイケル・クレリン-ハッカー

2
@Pascal:あります。Solarisでは、「truss ln -spx」および「truss ln -s -fpx」からの出力は、2番目のケースではsymlink()呼び出しの前にunlink()呼び出しを示します(最初のケースでは失敗したsymlink()呼び出し)。私はそれがすべてではないにしてもほとんどのUnixの変種に当てはまると期待しています。
ジョナサンレフラー

12
+1から@Taaiへのコメント-ディレクトリを逆参照する(ポイントする)シンボリックリンクを処理する場合は、このトリックが確実に機能するように「-n」を指定する必要があります。
ウォリー

161

はい、できます!

$ ln -sfn source_file_or_directory_name softlink_name

9
お返事ありがとうございます。この-fオプションは、新しい宛先を作成する前に「既存の宛先を削除する」ことを意味します。したがって、このコマンドは結果を実現しますが、をunlink(2)続けて実行しsymlink(2)ます。これは、元の質問についてのことではありません。また、受け入れ答え、次のほとんどが両方使用答える投票ことに注意してln -sf仕事をするために、しかしとしてstrace出力を示し、それがないunlink()symlink()シンボリックリンクを変更するためのシステムコールはありませんので。
ジョナサンレフラー

17
元のリンクがファイルではなくディレクトリに移動する場合、-nが必要なようです。
2014年

11
「n」スイッチは重要です。シンボリックリンクが更新されなかったが、「再参照なし」オプションが設定されていなかったため、コマンドが既存のリンク内に別のリンクを作成するという問題に苦しみました。
Jonathan Gruber 2014

14

古いシンボリックリンクを明示的にリンク解除する必要はありません。あなたはこれを行うことができます:

ln -s newtarget temp
mv temp mylink

(または同等のsymlinkとrename呼び出しを使用します)。名前の変更はアトミックであるため、明示的にリンクを解除するよりも、リンクが常に古いターゲットまたは新しいターゲットのいずれかを指すことが保証されます。ただし、これは元のiノードを再利用しません。

一部のファイルシステムでは、シンボリックリンクのターゲットが十分に短い場合、シンボリックリンクのターゲットは(ブロックリストの代わりに)iノード自体に格納されます。これは、作成時に決定されます。

Linuxのsymlink(7)は、実際の所有者とグループは重要ではないという主張に関して、それが重要である場合があると言っています:

既存のシンボリックリンクの所有者とグループは、lchown(2)を使用して変更できます。シンボリックリンクの所有権が重要になるのは、スティッキービットが設定されているディレクトリでリンクが削除または名前変更されている場合のみです(stat(2)を参照)。

シンボリックリンクの最終アクセスおよび最終変更のタイムスタンプは、utimensat(2)またはlutimes(3)を使用して変更できます。

Linuxでは、シンボリックリンクの権限はどの操作でも使用されません。アクセス許可は常に0777(すべてのユーザーカテゴリの読み取り、書き込み、実行)であり、変更できません。


@ mark4o:良い-lchown()への参照と、sticky-itディレクトリでの所有権は役に立ちます-ありがとう。私はlchown()を知っていて、それは私の論文にとって重要ではありませんでした。スティッキービットのディレクトリも知っていました。所有権はルールのほぼ標準的な結果だと思います-違い、そしておそらくそれが呼び出される理由は、通常、ファイルに書き込むことができればファイルを削除できることです。通常、誰でもシンボリックリンクに書き込むことができます。 777の権限の1つですが、この場合、ルールは少し異なります。
ジョナサンレフラー

1
@ mark4o:Not So Good-表示されたコマンドシーケンスは、あなたが思っていることを実行しません(少なくとも、シナリオでは:)set -x -e; mkdir junk; ( cd junk; mkdir olddir newdir; ln -s olddir mylink; ls -ilR; ln -s newdir temp; ls -ilR; mv temp mylink; ls -ilR; ); rm -fr junk。ディレクトリの代わりにファイルoldfileとnewfileを作成し、同等のスクリプト(主にolddirをoldfileに、newdirをnewfileに変更)を実行すると、期待した効果が得られます。あと1つだけ複雑です!ご回答ありがとうございます。
ジョナサンレフラー、

2

上記の正解に対する警告です。

-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

少なくとも私のファイルを保持します。


-for --forceオプションの使用は常に少し危険です。それは、ユーザーが自分が何であるかを知っていると仮定しています。常習的に使用すると二重の致命的です(rm -fr …毎回危険です)。
ジョナサンレフラー2014年

1

リンクを解除して新しいものを作成しても、結局同じことをしませんか?


2
なぜ最初にリンクを解除するのですか?単純にそれを上書きしないのはなぜですか?
S.Lott

5
最終的な結果はほぼ同じですが、所有者とグループ、および最終変更時刻(およびおそらくiノード番号)は、一般にすべて異なります。
ジョナサンレフラー、

2
@ S.Lott:「上書き」するシステムコールは何ですか?POSIXでは、そのような呼び出しはありません。SolarisおよびMacOS Xでは、そのような呼び出しはありません。Linux、AIX、HP-UX、Unixのように見えるものでそれを行うための呼び出しはありますか?WindowsにはAFAICTと同じように実際にはシンボリックリンクがないので、私の分析にとって重要ではありませんが、同等のWindows APIに関する情報が役立つでしょう。
ジョナサンレフラー

@ジョナサンレフラー:うーん.... ln --forceコマンドは既存のリンクを完全に上書きします。
S.Lott

皆さん、私はあなたがクロス目的で話していると思います。S.Lottは実行可能ファイルについて議論し、ln (1)マットはbです。上書きをサポートしてsymlink (2)ないという事実について議論しています。どちらも正しいので、の実装を見るとln (1)、リンク解除と再リンクの手順を実行する最も理想的な方法が得られると思います。
dmckee ---元モデレーターの子猫

0

念のため:真夜中の司令官(mc)でシンボリックリンクを編集する方法があります。メニューコマンドは(私のmcインターフェースではフランス語です):

Fichier / Éditer le lien symbolique

これは次のように翻訳されます:

File / Edit symbolic link

ショートカットはCx Csです

多分それは内部でln --forceコマンドを使用しています、私は知りません。

今、私は多くのシンボリックリンクを一度に編集する方法を見つけようとしています(それが私がここに到着した方法です)。


1
MCが裏で行うことを確認しましたか?Unixライクなシステムが提供するものだからとunlink()いって、実際にはの後にが続くとは思えませんsymlink()
Jonathan Leffler、2014

いいえ、チェックしていません。そして、はい、実際、あなたが言うとおりに実行される可能性は非常に高いです。テキストボックスを編集したという事実は、実際にシンボリックリンクのターゲットを編集しているような気がしますが、だまされた可能性があります...
Pierre

0

技術的には、既存のシンボリックリンクを編集するための組み込みコマンドはありません。これは、いくつかの短いコマンドで簡単に実現できます。

これが、既存のシンボリックリンクを更新するために私が書いた小さな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"
}

2
努力をありがとう。これは、C言語のシステムコールであるという私の要件を満たしていません。リンクを保持するディレクトリへの書き込み権限(これが必要)を持っている限り、リンクを変更する方法は多数あります。そこで私は、今でも、知っているの実行せずにシンボリックリンクの値を変更することがない方法unlink()symlink()あなたのコードとの舞台裏で何が起こっている新しい値とを。個人的には、関数に正確に2つ(またはおそらく2の倍数)の引数を要求し、呼び出しが正しくなかった場合は保釈します。しかし、それは特定の視点です。
ジョナサンレフラー
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.