Czy możesz zmienić to, na co wskazuje dowiązanie symboliczne po jego utworzeniu?

122

Czy jakikolwiek system operacyjny zapewnia mechanizm (wywołanie systemowe - nie program wiersza poleceń) do zmiany ścieżki, do której odwołuje się dowiązanie symboliczne (dowiązanie symboliczne) - inne niż przez odłączenie starego i utworzenie nowego?

Standard POSIX tego nie robi. Solaris 10 nie. MacOS X 10.5 (Leopard) nie. (Jestem całkiem pewien, że ani AIX, ani HP-UX też nie. Sądząc po liście wywołań systemowych Linuksa, Linux również nie ma takiego wywołania systemowego).

Czy jest coś, co robi?

(Oczekuję, że odpowiedź brzmi „Nie”).


Ponieważ udowodnienie czegoś negatywnego jest trudne, przeorganizujmy pytanie.

Jeśli wiesz, że jakiś (podobny do systemu Unix) system operacyjny, którego nie ma jeszcze na liście, nie ma żadnego wywołania systemowego do przepisywania wartości dowiązania symbolicznego (ciąg zwracany przez readlink()) bez usuwania starego dowiązania symbolicznego i tworzenia nowego, dodaj go - lub je - w odpowiedzi.

Jonathan Leffler
źródło
Co jest złego w zwykłym ponownym łączeniu? Dlaczego po prostu nie wydać lnpolecenia (lub równoważnika API) nadpisującego stare łącze? Jaki masz problem?
S.Lott,
9
Zabawne - pytam, czy jest wywołanie systemowe do wykonania pracy programistycznej, a pytanie jest oznaczone jako „należy do innej witryny”.
Jonathan Leffler
3
Zabawne - nie było absolutnie jasne, że szukasz wywołania systemowego i właśnie zredagowałeś pytanie, dodając ten szczegół. Jak więc możesz oczekiwać, że ludzie będą coś odliczać, zanim jeszcze to napiszesz?
Pascal Thivent
2
@ S.Lott: Piszę artykuł na temat bezpieczeństwa i dowiązań symbolicznych. W pewnym momencie stwierdzam, że „rzeczywisty właściciel, grupa, uprawnienia do samego łącza symbolicznego są nieistotne”, a rozumowanie jest takie, że właściciel łącza symbolicznego może je tylko usunąć, a nie zmienić jego wartości. Dokładnie sprawdzam, czy nie ma innego sposobu niż usunięcie łącza symbolicznego w celu osiągnięcia efektu „przepisania wartości łącza symbolicznego”. Ignoruję bezpośredni dostęp do surowego dysku i hakowanie FS w ten sposób - wymaga to uprawnień roota, a moje obawy dotyczą użytkowników innych niż root, a nie tego, co może zrobić root.
Jonathan Leffler
4
@Pascal: Przepraszam - nie zdawałem sobie sprawy, że nie było jasne, że mówię o wywołaniach systemowych, dopóki ludzie nie wyszli na styczną od tego, co zamierzałem (co było ewidentnie inne niż to, co powiedziałem). Przepraszam, że wprowadziłem w błąd; to było niezamierzone.
Jonathan Leffler

Odpowiedzi:

106

AFAIK, nie, nie możesz. Musisz go usunąć i odtworzyć. Właściwie możesz nadpisać łącze symboliczne i zaktualizować w ten sposób ścieżkę, do której się ono odwołuje:

$ 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

EDYCJA : Jak OP wskazał w komentarzu, użycie --forceopcji spowoduje lnwykonanie wywołania systemowego unlink()wcześniej symlink(). Poniżej wyjście z stracemojego Linux-a, które to potwierdza:

$ 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

Więc myślę, że ostateczna odpowiedź brzmi „nie”.

EDYCJA : Poniższy tekst jest skopiowany z odpowiedzi Arto Bendikena na unix.stackexchange.com, około 2016 r.

To może być rzeczywiście wykonywane atomowo z rename(2), najpierw tworzenia nowego dowiązania pod tymczasową nazwą, a następnie czysto nadpisanie starego dowiązania w jednym zamachem. Jak stwierdza strona podręcznika :

Jeśli newpath odnosi się do dowiązania symbolicznego, to łącze zostanie nadpisane.

W powłoce zrobiłbyś to mv -Tw następujący sposób:

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

Możesz straceto ostatnie polecenie, aby upewnić się, że rzeczywiście używa rename(2)pod maską:

$ 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

Zauważ, że w powyższym, oba mv -Ti stracesą specyficzne dla Linuksa.

We FreeBSD używaj mv -hnaprzemiennie.

Uwaga redaktora: Tak robi Capistrano od lat, od czasu ~ 2.15. Zobacz to żądanie ściągnięcia .

Pascal Thivent
źródło
2
Czy opcja „-f” nie wymusza na „ln” wykonania wywołań systemowych unlink (), a następnie symbollink ()?
Jonathan Leffler
1
To robi. Ale pytanie mogłoby zostać odebrane jako „jak to zrobić w jednym kroku”, a potem sprowadza się do definicji „kroku” - wiersza poleceń? syscall?
Michael Krelin - haker
1
Właśnie zauważyłem, że dodałeś sformułowanie syscall do swojego pytania ;-)
Michael Krelin - hacker
2
@ Pascal: tak. W Solarisie wynik poleceń „truss ln -spx” i „truss ln -s -fpx” pokazuje wywołanie unlink () przed wywołaniem symlink () w drugim przypadku (i nieudane wywołanie symboliczne () w pierwszym). Spodziewałbym się, że dotyczy to większości, jeśli nie wszystkich, wariantów Uniksa.
Jonathan Leffler
12
+1 do komentarza @Taai - jeśli masz do czynienia z dowiązaniem symbolicznym, które wyłuskuje (wskazuje) katalog, musisz podać "-n", aby upewnić się, że ta sztuczka działa.
wally
161

Tak, możesz!

$ ln -sfn source_file_or_directory_name softlink_name
Taai
źródło
9
Dziękuję za odpowiedź. Te -fśrodki opcja „usunąć istniejący cel” przed utworzeniem nowego. Tak więc to polecenie osiąga wynik, ale przez wykonanie, unlink(2)po którym następuje symlink(2). Nie o to chodziło w pierwotnym pytaniu. Zauważ również, że zaakceptowana odpowiedź i kolejna najczęściej głosowana odpowiedź służą ln -sfdo wykonania zadania, ale jak stracewidać na wyjściu, robi to unlink()i symlink()ponieważ nie ma wywołania systemowego modyfikującego dowiązanie symboliczne.
Jonathan Leffler
17
-N wydaje się być wymagane, gdy oryginalne dowiązanie prowadzi do katalogu zamiast do pliku.
steampowered
11
Przełącznik „n” jest ważny. Zmagałem się z problemem polegającym na tym, że dowiązanie symboliczne nie zostało zaktualizowane, ale polecenie utworzyło inne łącze wewnątrz istniejącego, ponieważ nie ustawiono opcji „no derefencing”.
Jonathan Gruber
14

Nie jest konieczne jawne odłączanie starego łącza symbolicznego. Możesz to zrobić:

ln -s newtarget temp
mv temp mylink

(lub użyj równoważnego łącza symbolicznego i zmień nazwę wywołań). Jest to lepsze niż jawne odłączanie, ponieważ zmiana nazwy jest atomowa, więc możesz mieć pewność, że łącze zawsze będzie wskazywać na stary lub nowy cel. Jednak nie spowoduje to ponownego wykorzystania oryginalnego i-węzła.

W niektórych systemach plików cel dowiązania symbolicznego jest przechowywany w samym i-węźle (w miejscu listy bloków), jeśli jest wystarczająco krótki; jest to określone w momencie tworzenia.

Jeśli chodzi o stwierdzenie, że rzeczywisty właściciel i grupa są nieistotni, link symboliczny (7) w Linuksie mówi, że istnieje przypadek, w którym jest to znaczące:

Właściciela i grupę istniejącego dowiązania symbolicznego można zmienić za pomocą lchown (2). Jedynym przypadkiem, w którym własność dowiązania symbolicznego ma znaczenie, jest usuwanie łącza lub zmiana jego nazwy w katalogu, który ma ustawiony bit lepki (patrz stat (2)).

Znaczniki czasu ostatniego dostępu i ostatniej modyfikacji dowiązania symbolicznego można zmienić za pomocą utimensat (2) lub lutimes (3).

W systemie Linux uprawnienia dowiązania symbolicznego nie są używane w żadnych operacjach; uprawnienia są zawsze 0777 (odczyt, zapis i wykonywanie dla wszystkich kategorii użytkowników) i nie można ich zmienić.

mark4o
źródło
@ mark4o: The Good - Przydatne jest odniesienie do lchown () i własności w katalogu sticky-it - dzięki. Byłem świadomy lchown () i nie było to istotne dla mojej pracy magisterskiej. Zdawałem sobie również sprawę z katalogów sticky-bit; Myślę, że własność jest prawie standardową konsekwencją reguł - różnica i przypuszczalnie dlaczego jest wywoływana polega na tym, że normalnie możesz usunąć plik, jeśli możesz do niego napisać, i nominalnie każdy może pisać do łącza symbolicznego, ponieważ 777 uprawnień, ale w tym przypadku zasady są nieco inne.
Jonathan Leffler
1
@ mark4o: The Not So Good - pokazana sekwencja poleceń nie robi tego, co myślisz, że robi (przynajmniej w scenariuszu:) 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. Jeśli zamiast katalogów utworzysz pliki oldfile i newfile i uruchomisz odpowiedni skrypt (głównie zmieniając olddir na oldfile, newdir na newfile), uzyskasz oczekiwany efekt. Tylko jedna dodatkowa złożoność! Dziękuję za odpowiedź.
Jonathan Leffler
2

Tylko ostrzeżenie przed poprawnymi odpowiedziami powyżej:

Użycie metody -f / --force stwarza ryzyko utraty pliku w przypadku pomieszania źródła i celu:

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

Oczywiście jest to zamierzone, ale zwykle zdarzają się błędy. Tak więc usunięcie i odbudowanie linku symbolicznego wymaga trochę więcej pracy, ale także trochę oszczędności:

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

który przynajmniej zachowuje mój plik.

Markus Bucher
źródło
Używanie opcji -flub --forcejest zawsze nieco niebezpieczne; zakłada, że ​​użytkownik wie, o co mu chodzi. Jest podwójnie zabójczy, jeśli używasz go nałogowo (za rm -fr …każdym razem jest to niebezpieczne).
Jonathan Leffler
1

Czy odłączenie go i utworzenie nowego i tak nie zrobiłoby tego samego?

matowe b
źródło
2
Po co odłączać w pierwszej kolejności? Dlaczego nie po prostu go nadpisać?
S.Lott,
5
Wynik netto jest w przybliżeniu taki sam - ale właściciel i grupa oraz czasy ostatniej modyfikacji (i prawdopodobnie numer i-węzła) byłyby ogólnie różne.
Jonathan Leffler
2
@ S.Lott: jakie wywołanie systemowe „nadpisuje”? W POSIX nie ma takiego wywołania. W Solarisie i MacOS X takiego połączenia nie ma. Czy jest wezwanie do zrobienia tego w ... Linuksie, AIX, HP-UX, czymkolwiek innym, co wygląda jak Unix? Windows tak naprawdę nie ma linków symbolicznych w ten sam sposób, AFAICT, więc nie jest to krytyczne dla mojej analizy - ale informacje o równoważnym API Windows byłyby przydatne.
Jonathan Leffler
@Jonathan Leffler: Ummm .... ln --forcepolecenie całkowicie nadpisze istniejące łącze.
S.Lott,
Chłopaki, myślę, że rozmawiacie w różnych celach. S.Lott omawia plik wykonywalny ln (1), podczas gdy Matt B. omawia fakt, że symlink (2)ma nie obsługuje nadpisywania. Oboje macie rację i sugerowałbym, że przyjrzenie się implementacji ln (1)dałoby najbardziej idomatyczny sposób wykonania procedury rozłączania i ponownego łączenia.
dmckee --- ex-moderator kitten
0

Na wszelki wypadek to pomoże: istnieje sposób na edycję linku symbolicznego za pomocą Midnight Commander (mc). Polecenie menu to (po francusku na moim interfejsie mc):

Fichier / Éditer le lien symbolique

które można przetłumaczyć na:

File / Edit symbolic link

Skrót to Cx Cs

Może wewnętrznie używa ln --forcepolecenia, nie wiem.

Teraz próbuję znaleźć sposób na edycję wielu linków symbolicznych naraz (w ten sposób tu dotarłem).

Pierre
źródło
1
Czy sprawdziłeś, co MC robi za kulisami? Mogę się założyć, że w rzeczywistości unlink()następuje symlink()po prostu a , po prostu dlatego, że zapewniają to systemy podobne do Uniksa.
Jonathan Leffler
Nie, nie sprawdziłem. I tak, jest całkiem prawdopodobne, że faktycznie robi to, co mówisz. Fakt, że edytuję pole tekstowe, daje wrażenie, że faktycznie edytuję cel linku symbolicznego, ale prawdopodobnie zostałem oszukany ...
Pierre
0

Technicznie rzecz biorąc, nie ma wbudowanego polecenia do edycji istniejącego łącza symbolicznego. Można to łatwo osiągnąć za pomocą kilku krótkich poleceń.

Oto mała funkcja bash / zsh, którą napisałem, aby zaktualizować istniejący link symboliczny:

# -----------------------------------------
# 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
źródło
2
Dziękuję za wysiłek. To nie spełnia mojego wymagania bycia wywołaniem systemowym w języku C. Istnieje wiele sposobów zmiany odsyłacza, o ile masz uprawnienia do zapisu w katalogu zawierającym odsyłacz (co jest wymagane). Nie ma możliwości, że znam, nawet teraz, aby zmienić wartość dowiązania symbolicznego nie robiąc unlink()i symlink()z nową wartością, która jest, co dzieje się za kulisami z kodem. Osobiście chciałbym, aby funkcja nalegała na dokładnie dwa (lub być może wielokrotność dwóch) argumentów i zwolniłaby, gdyby wywołanie nie było poprawne. To jednak szczególna perspektywa.
Jonathan Leffler