Come si cambia atomicamente un symlink in una directory in busybox?


18

Sto provando a (il più vicino possibile) atomicamente cambiare un link simbolico. Ho provato:

ln -sf other_dir existing_symlink

Ciò ha appena inserito il nuovo symlink nella directory a cui puntava esistente.

ln -sf other_dir new_symlink
mv -f new_symlink existing_symlink

Ha fatto la stessa cosa: ha spostato il collegamento simbolico nella directory.

cp -s other_dir existing_symlink

Rifiuta perché è una directory.

Ho letto che mv -Tè stato creato per questo, ma busybox non ha la -Tbandiera.

Risposte:


1

Non vedo come si possa ottenere un'operazione atomica. La pagina man di symlink(2)dice che indica EEXISTse l'obiettivo esiste già. Se il kernel non supporta il funzionamento atomico, le limitazioni dell'utente sono irrilevanti.

Inoltre non vedo come mv -Taiuti, anche se ce l'hai. Provalo su un normale box Linux, uno con GNU mv:

$ mkdir a b
$ ln -s a z
$ mv -T b z
mv: cannot overwrite non-directory `z' with directory `b'

Penso che dovrai farlo in due passaggi: rimuovere il vecchio symlink e ricrearlo.


1
In effetti, sfortunatamente non è possibile modificare atomicamente un simbolico. Il meglio che puoi fare è rimuovere il vecchio link e crearne uno nuovo. I coreutils GNU hanno un'opzione per farlo con un solo comando ( ln -snf), ma ci sono ancora due chiamate di sistema sotto il cofano.
Gilles 'SO- smetti di essere malvagio' il

43

Questo può effettivamente essere fatto atomicamente con rename(2), creando prima il nuovo symlink con un nome temporaneo e poi sovrascrivendo in modo pulito il vecchio symlink in una volta sola. Come afferma la pagina man :

Se newpath fa riferimento a un collegamento simbolico, il collegamento verrà sovrascritto.

Nella shell, lo faresti mv -Tnel modo seguente:

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

Puoi l' straceultimo comando per assicurarti che stia effettivamente usando rename(2)sotto il cofano:

$ 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

Si noti che in quanto sopra, entrambi mv -Te stracesono specifici di Linux.

Su FreeBSD, usa mv -halternativamente.


1
Molto bella! Potrebbe essere utile dire che alla fine hai un link dalla z alla b!
Vincenzo Pii,

Per una soluzione indipendente dal sistema operativo utilizzare un linguaggio di scripting in grado di utilizzare renamedirettamente syscall invece di mv -ho mv -T. Ad esempio con Perl:perl -e 'rename "z.new", "z" or die $!'
Slaven Rezic

8

Riprendendo da dove Arto aveva interrotto qui, questo è del tutto possibile, anche senza mv -T, è sufficiente creare un nuovo collegamento simbolico con lo stesso nome della directory di destinazione e mvinserirlo nella directory principale della destinazione:

mkdir -p tmp/real_dir1 tmp/real_dir2
touch tmp/real_dir1/a tmp/real_dir2/a
# start with ./target_dir pointing to tmp/real_dir1
ln -s tmp/real_dir1 target_dir
# create a symlink named target_dir in tmp, pointing to real_dir2
ln -sf tmp/real_dir2 tmp/target_dir
# atomically mv it into ./ replacing ./target_dir
mv tmp/target_dir ./

Esempio di codice preso tramite ( http://axialcorps.wordpress.com/2013/07/03/atomically-replacing-files-and-directories/ )


3

Ci hai provato ln -snf?

L'opzione -nsovrascrive la destinazione anziché scrivere sotto di essa quando la destinazione è un collegamento simbolico a una directory.

Saluti


3
ln -snfnon è atomico: scollega la destinazione, quindi crea il collegamento simbolico desiderato.
Gilles 'SO- smetti di essere malvagio' il

2
Dato che l'OP era interessato a "avvicinarsi il più possibile [e]" alla modifica atomica di un collegamento simbolico, questa è una risposta perfettamente ragionevole. Se ce n'è uno migliore che può avvicinarsi (o essere) atomico, quello può essere accettato. Non penso che sia necessario un voto negativo.
Wilco,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.