Bisakah Anda mengubah poin symlink setelah dibuat?

122

Apakah ada sistem operasi yang menyediakan mekanisme (panggilan sistem - bukan program baris perintah) untuk mengubah nama jalur yang direferensikan oleh tautan simbolis (symlink) - selain dengan memutuskan tautan yang lama dan membuat yang baru?

Standar POSIX tidak. Solaris 10 tidak. MacOS X 10.5 (Leopard) tidak. (Saya cukup yakin baik AIX maupun HP-UX tidak melakukannya. Dilihat dari daftar panggilan sistem Linux ini , Linux juga tidak memiliki panggilan sistem seperti itu.)

Apakah ada yang bisa?

(Saya mengharapkan jawabannya adalah "Tidak".)


Karena sulit membuktikan negatif, mari susun ulang pertanyaannya.

Jika Anda mengetahui bahwa beberapa sistem operasi (mirip-Unix) yang belum terdaftar tidak memiliki pemanggilan sistem untuk menulis ulang nilai symlink (string yang dikembalikan oleh readlink()) tanpa menghapus symlink lama dan membuat yang baru, tambahkan - atau mereka - dalam sebuah jawaban.

Jonathan Leffler
sumber
Apa salahnya menautkan kembali? Mengapa tidak mengeluarkan lnperintah (atau API yang setara) menimpa tautan lama? Masalah apa yang Anda hadapi?
S. Lott
9
Lucu - Saya bertanya apakah ada panggilan sistem untuk melakukan pekerjaan pemrograman, dan pertanyaannya ditandai 'milik situs lain'.
Jonathan Leffler
3
Lucu- Sama sekali tidak jelas Anda mencari panggilan sistem dan Anda baru saja mengedit pertanyaan untuk menambahkan detail ini. Jadi bagaimana Anda bisa mengharapkan orang untuk mengurangi sesuatu bahkan sebelum Anda menulisnya?
Pascal Thivent
2
@ S. Lott: Saya sedang menulis makalah tentang keamanan dan tautan simbolik. Pada satu titik saya membuat pernyataan "pemilik sebenarnya, grup, izin pada symlink itu sendiri tidak penting" dan alasannya adalah bahwa pemilik symlink hanya dapat menghapusnya dan tidak mengubah nilainya. Saya memeriksa ulang bahwa tidak ada cara lain selain dengan menghapus symlink untuk mencapai efek 'menulis ulang nilai symlink'. Saya mengabaikan akses langsung ke disk mentah dan meretas FS dengan cara itu - ini membutuhkan hak akses root dan kekhawatiran saya adalah dengan pengguna non-root, bukan dengan apa yang dapat dilakukan root.
Jonathan Leffler
4
@Pascal: Maaf - saya tidak menyadari bahwa tidak jelas bahwa saya berbicara tentang panggilan sistem sampai orang-orang menyimpang dari apa yang saya maksudkan (yang ternyata berbeda dari apa yang saya katakan). Saya menyesal telah menyesatkan; itu tidak disengaja.
Jonathan Leffler

Jawaban:

106

AFAIK, tidak, Anda tidak bisa. Anda harus menghapusnya dan membuatnya kembali. Sebenarnya, Anda dapat menimpa sebuah symlink dan dengan demikian memperbarui nama jalur yang dirujuk olehnya:

$ 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 : Seperti yang ditunjukkan OP dalam komentar, menggunakan --forceopsi ini akan membuat lnpanggilan sistem ke unlink()sebelumnya symlink(). Di bawah ini, output stracedi kotak linux saya membuktikannya:

$ 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

Jadi saya kira jawaban akhirnya adalah "tidak".

EDIT : Berikut ini disalin dari jawaban Arto Bendiken di unix.stackexchange.com, sekitar tahun 2016.

Ini dapat memang dilakukan atom dengan rename(2), dengan terlebih dahulu menciptakan symlink baru di bawah nama sementara dan kemudian bersih Timpa symlink lama dalam satu pergi. Seperti yang dinyatakan halaman manual :

Jika jalur baru mengacu pada tautan simbolis, tautan tersebut akan ditimpa.

Di shell, Anda akan melakukan ini dengan mv -Tsebagai berikut:

$ mkdir a b
$ ln -s a z
$ ln -s b z.new
$ mv -T z.new z

Anda dapat melakukan straceperintah terakhir itu untuk memastikannya memang menggunakan di rename(2)bawah tenda:

$ 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

Perhatikan bahwa di atas, keduanya mv -Tdan stracekhusus untuk Linux.

Di FreeBSD, gunakan secara mv -hbergantian.

Catatan editor: Beginilah cara Capistrano melakukannya selama bertahun-tahun sekarang, sejak ~ 2.15. Lihat permintaan tarik ini .

Pascal Thivent
sumber
2
Bukankah opsi '-f' memaksa 'ln' untuk melakukan pemanggilan sistem unlink () lalu symlink ()?
Jonathan Leffler
1
Memang. Tapi pertanyaannya mungkin dianggap sebagai "bagaimana saya melakukannya dalam satu langkah" dan kemudian bermuara pada definisi "langkah" - baris perintah? syscall?
Michael Krelin - hacker
1
Saya baru saja memperhatikan bahwa Anda menambahkan kata-kata syscall ke pertanyaan Anda ;-)
Michael Krelin - hacker
2
@Pascal: memang. Pada Solaris, output dari 'truss ln -spx' dan 'truss ln -s -fpx' menunjukkan panggilan unlink () sebelum panggilan symlink () pada kasus kedua (dan panggilan symlink () yang gagal pada kasus pertama). Saya berharap itu berlaku untuk sebagian besar, jika tidak semua varian Unix.
Jonathan Leffler
12
+1 untuk komentar @Taai - jika berurusan dengan symlink yang dereferensi (menunjuk ke) direktori, Anda perlu menentukan "-n" untuk memastikan trik ini berhasil.
wally
161

Ya kamu bisa!

$ ln -sfn source_file_or_directory_name softlink_name
Taai
sumber
9
Terima kasih telah menanggapi. The -fberarti opsi 'menghapus tujuan yang ada' sebelum membuat yang baru. Jadi, perintah ini mencapai hasil, tetapi dengan melakukan unlink(2)diikuti oleh symlink(2). Ini bukanlah tentang pertanyaan aslinya. Juga perhatikan bahwa jawaban yang diterima dan jawaban yang paling banyak dipilih berikutnya keduanya digunakan ln -sfuntuk melakukan pekerjaan itu, tetapi seperti yang straceditunjukkan oleh output, itu dilakukan unlink()dan symlink()karena tidak ada panggilan sistem untuk mengubah symlink.
Jonathan Leffler
17
-N tampaknya diperlukan saat tautan asli masuk ke direktori, bukan ke file.
steampowered
11
Tombol 'n' penting. Saya berjuang dengan masalah bahwa symlink tidak diperbarui tetapi perintah membuat tautan lain di dalam yang sudah ada karena opsi 'tidak ada derefencing' tidak diatur.
Jonathan Gruber
14

Tidak perlu memutuskan tautan symlink lama secara eksplisit. Kamu bisa melakukan ini:

ln -s newtarget temp
mv temp mylink

(atau gunakan symlink yang setara dan ganti nama panggilan). Ini lebih baik daripada membatalkan tautan secara eksplisit karena penggantian nama bersifat atomik, sehingga Anda dapat yakin bahwa tautan akan selalu mengarah ke target lama atau baru. Namun ini tidak akan menggunakan kembali inode asli.

Pada beberapa sistem file, target dari symlink disimpan dalam inode itu sendiri (menggantikan daftar blokir) jika cukup pendek; ini ditentukan pada saat dibuat.

Mengenai pernyataan bahwa pemilik dan grup sebenarnya tidak material, symlink (7) di Linux mengatakan bahwa ada kasus di mana itu signifikan:

Pemilik dan grup dari tautan simbolik yang ada dapat diubah menggunakan lchown (2). Kepemilikan tautan simbolik hanya penting ketika tautan sedang dihapus atau diganti namanya dalam direktori yang memiliki kumpulan bit lengket (lihat stat (2)).

Akses terakhir dan cap waktu modifikasi terakhir dari tautan simbolik dapat diubah menggunakan utimensat (2) atau lutimes (3).

Di Linux, izin tautan simbolik tidak digunakan dalam operasi apa pun; izinnya selalu 0777 (baca, tulis, dan jalankan untuk semua kategori pengguna), dan tidak dapat diubah.

mark4o
sumber
@ mark4o: The Good - Referensi ke lchown () dan kepemilikan dalam direktori sticky-it berguna - terima kasih. Saya mengetahui lchown () dan itu bukan material untuk tesis saya. Saya juga mengetahui direktori sticky-bit; Saya pikir kepemilikan hampir merupakan konsekuensi standar dari aturan - perbedaan, dan mungkin mengapa ini dipanggil, adalah bahwa biasanya Anda dapat menghapus file jika Anda dapat menulisnya, dan secara nominal, siapa pun dapat menulis ke symlink karena dari 777 izin, tetapi dalam kasus ini, aturannya sedikit berbeda.
Jonathan Leffler
1
@ mark4o: The Not So Good - urutan perintah yang ditampilkan tidak melakukan apa yang menurut Anda dilakukannya (setidaknya, dalam skenario:) 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. Jika Anda membuat file oldfile dan newfile alih-alih direktori dan menjalankan skrip yang setara (terutama mengubah olddir ke oldfile, newdir ke newfile), maka Anda mendapatkan efek yang Anda harapkan. Hanya satu kerumitan ekstra! Terima kasih atas tanggapannya.
Jonathan Leffler
2

Sekadar peringatan untuk jawaban yang benar di atas:

Menggunakan Metode -f / --force memberikan risiko kehilangan file jika Anda mencampuradukkan sumber dan target:

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

Tentu saja ini memang disengaja, tetapi biasanya kesalahan terjadi. Jadi, menghapus dan membangun kembali symlink sedikit lebih banyak pekerjaan tetapi juga sedikit hemat:

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

yang setidaknya menyimpan file saya.

Markus Bucher
sumber
Menggunakan opsi -fatau --forceselalu sedikit berbahaya; itu menganggap pengguna tahu tentang apa mereka. Ini sangat mematikan jika Anda menggunakannya secara biasa ( rm -fr …setiap saat berbahaya).
Jonathan Leffler
1

Bukankah membatalkan tautannya dan membuat yang baru pada akhirnya akan melakukan hal yang sama?

matt b
sumber
2
Mengapa membatalkan tautan di tempat pertama? Mengapa tidak menimpanya dengan sederhana?
S. Lott
5
Hasil bersihnya kira-kira sama - tetapi pemilik dan grup serta waktu modifikasi terakhir (dan mungkin nomor inode) semuanya akan berbeda, secara umum.
Jonathan Leffler
2
@ S. Lott: pemanggilan sistem apa yang 'ditimpa'? Di POSIX, tidak ada panggilan seperti itu. Di Solaris dan MacOS X, tidak ada panggilan seperti itu. Apakah ada panggilan untuk melakukan itu di ... Linux, AIX, HP-UX, apa pun yang terlihat seperti Unix? Windows tidak benar-benar memiliki symlink dengan cara yang sama, AFAICT, jadi ini tidak penting untuk analisis saya - tetapi informasi tentang API Windows yang setara akan berguna.
Jonathan Leffler
@Jonathan Leffler: Ummm .... ln --forceperintah ini benar-benar akan menimpa tautan yang ada.
S. Lott
Teman-teman, saya pikir Anda berbicara dengan tujuan yang berlawanan. S. Lott sedang mendiskusikan eksekusi ln (1), sementara matt b. membahas fakta bahwa symlink (2)tidak tidak mendukung Timpa. Anda berdua benar, dan saya akan menyarankan bahwa melihat implementasi ln (1)akan memberikan cara paling idomatis untuk menyelesaikan prosedur unlink-relink.
dmckee --- mantan moderator kucing
0

Untuk berjaga-jaga jika itu membantu: ada cara untuk mengedit symlink dengan midnight commander (mc). Perintah menu adalah (dalam bahasa Prancis di antarmuka mc saya):

Fichier / Éditer le lien symbolique

yang dapat diterjemahkan ke:

File / Edit symbolic link

Pintasannya adalah Cx Cs

Mungkin secara internal menggunakan ln --forceperintah, saya tidak tahu.

Sekarang, saya mencoba menemukan cara untuk mengedit banyak symlink sekaligus (begitulah cara saya sampai di sini).

Pierre
sumber
1
Sudahkah Anda memverifikasi apa yang dilakukan MC di balik layar? Saya akan memperkirakan bahwa sebenarnya itu unlink()diikuti oleh a symlink(), hanya karena itulah yang disediakan oleh sistem mirip Unix.
Jonathan Leffler
Tidak, saya belum memeriksanya. Dan ya, sangat mungkin memang seperti yang Anda katakan. Fakta bahwa saya mengedit kotak teks memberi perasaan bahwa saya sebenarnya mengedit target symlink, tetapi saya mungkin telah tertipu ...
Pierre
0

Secara teknis, tidak ada perintah bawaan untuk mengedit tautan simbolik yang ada. Ini dapat dengan mudah dicapai dengan beberapa perintah singkat.

Ini sedikit fungsi bash / zsh yang saya tulis untuk memperbarui tautan simbolik yang ada:

# -----------------------------------------
# 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"
}
blizzrdof77
sumber
2
Terima kasih atas usahanya. Ini tidak memenuhi persyaratan saya untuk menjadi panggilan sistem bahasa C. Ada banyak cara untuk mengubah tautan selama Anda memiliki izin menulis pada direktori yang menyimpan tautan (yang diperlukan). Tidak ada cara yang saya ketahui, bahkan sekarang, untuk mengubah nilai symlink tanpa melakukan unlink()dan symlink()dengan nilai baru, yang terjadi di balik layar dengan kode Anda. Secara pribadi, saya akan meminta fungsi tersebut menuntut tepat dua (atau mungkin kelipatan dari dua) argumen dan jaminan jika pemanggilan tidak benar. Itu perspektif khusus.
Jonathan Leffler