Como alguém altera atomicamente um link simbólico para um diretório no busybox?


18

Estou tentando (o mais próximo possível) alterar atomicamente um link simbólico. Eu tentei:

ln -sf other_dir existing_symlink

Isso acabou de colocar o novo link simbólico no diretório que o existente_symlink apontou.

ln -sf other_dir new_symlink
mv -f new_symlink existing_symlink

Isso fez a mesma coisa: moveu o link simbólico para o diretório.

cp -s other_dir existing_symlink

Recusa porque é um diretório.

Eu li que isso mv -Tfoi feito para isso, mas o busybox não tem a -Tbandeira.

Respostas:


1

Não vejo como você pode obter operação atômica. A página de manual para symlink(2)indica EEXISTse o destino já existe. Se o kernel não suportar operação atômica, suas limitações na área do usuário são irrelevantes.

Também não vejo como mv -Tajuda, mesmo que você a tenha. Experimente em uma caixa Linux normal, uma com GNU mv:

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

Acho que você precisará fazer isso em duas etapas: remova o link simbólico antigo e recrie-o.


11
De fato, infelizmente não há como você modificar um simbólico atomicamente. O melhor que você pode fazer é remover o link antigo e criar um novo. O GNU coreutils tem uma opção para fazer isso com um único comando ( ln -snf), mas ainda existem duas chamadas de sistema ocultas.
Gilles 'SO- stop be evil'

43

Na verdade, isso pode ser feito atomicamente rename(2), criando primeiro o novo link simbólico com um nome temporário e depois substituindo de maneira limpa o link simbólico antigo de uma só vez. Como a página de manual afirma:

Se newpath se referir a um link simbólico, o link será substituído.

No shell, você faria isso da mv -Tseguinte maneira:

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

Você pode straceexecutar esse último comando para garantir que ele esteja realmente sendo usado por rename(2)baixo do capô:

$ 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

Observe que, acima, ambos mv -Te stracesão específicos do Linux.

No FreeBSD, use mv -halternadamente.


11
Muito agradável! Pode ser útil dizer que, no final, você tem um link de z para b!
Vincenzo Pii

Para uma solução independente do SO, use uma linguagem de script capaz de usar o renamesyscall diretamente em vez de mv -hou mv -T. Por exemplo, com Perl:perl -e 'rename "z.new", "z" or die $!'
Slaven Rezic 04/04/19

8

Escolhendo de onde Arto parou aqui, isso é totalmente possível, mesmo sem mv -T, você só precisa criar um novo link simbólico com o mesmo nome que o diretório de destino e mvno diretório pai do seu destino:

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 ./

Exemplo de código obtido por meio de ( http://axialcorps.wordpress.com/2013/07/03/atomically-replacing-files-and-directories/ )


3

Você já tentou ln -snf?

A opção -nsubstitui o destino em vez de escrevê-lo quando o destino é um link simbólico para um diretório.

Felicidades


3
ln -snfnão é atômico: ele desvincula o destino e cria o link simbólico desejado.
Gilles 'SO- stop be evil'

2
Dado que o OP estava interessado em "o mais próximo possível" de alterar atomicamente um link simbólico, essa é uma resposta perfeitamente razoável. Se houver um melhor que possa se aproximar (ou ser) atômico, esse poderá ser aceito. Eu não acho que há uma necessidade de voto negativo.
Wilco
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.