Como um atomicamente muda um symlink para um diretório no busybox?

17

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

ln -sf other_dir existing_symlink

Isso apenas coloca o novo symlink no diretório que o existing_symlink apontou.

ln -sf other_dir new_symlink
mv -f new_symlink existing_symlink

Isso fez o mesmo: mudou o link simbólico para o diretório.

cp -s other_dir existing_symlink

Ele se recusa porque é um diretório.

Eu li que mv -T foi feito para isso, mas o busybox não tem o sinal -T .

    
por Shawn J. Goff 22.12.2010 / 16:11

4 respostas

2

Eu não vejo como você pode obter operação atômica. A man page para symlink(2) diz que dá EEXIST se o destino já existir. Se o kernel não suporta operação atômica, suas limitações são irrelevantes.

Eu também não vejo como o mv -T ajuda, mesmo que você o tenha. Experimente em uma caixa Linux comum, 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ê terá que fazer isso em duas etapas: remover o link simbólico antigo e recriá-lo.

    
por 22.12.2010 / 16:37
36

De fato, isso pode ser feito atomicamente com rename(2) , criando primeiro o novo symlink com um nome temporário e, em seguida, substituindo de forma limpa o antigo symlink de uma só vez. Como a página do manual afirma:

If newpath refers to a symbolic link the link will be overwritten.

No shell, você faria isso com mv -T da seguinte forma:

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

Você pode strace do último comando para ter certeza de que está usando 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

Observe que, acima, mv -T e strace são específicos do Linux.

No FreeBSD, use mv -h alternadamente.

    
por 02.02.2011 / 11:33
5

Pegando onde Arto parou aqui, isso é totalmente possível, mesmo sem mv -T , você só precisa criar um novo symlink com o mesmo nome que o diretório de destino e mv no 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 via ( link )

    
por 05.07.2013 / 16:57
2

Você já tentou ln -snf ?

A opção -n sobrescreve o destino em vez de escrever sob ele quando o destino é um link simbólico para um diretório.

Felicidades

    
por 13.08.2011 / 11:56