Veja padrões como POSIX para garantias de portabilidade. Na prática, a maioria dos sistemas compatíveis com POSIX apresenta pequenos desvios em relação às especificações, mas, em geral, você pode confiar nas garantias dadas na especificação. A maioria dos unices modernos está em conformidade com a especificação, mesmo que não tenham sido formalmente testados. Eles podem precisar ser executados em um modo POSIX, por exemplo definindo POSIXLY_CORRECT=1
com bash ou certificando-se de que /usr/xpg4/bin
esteja à frente de /bin
e /usr/bin
in PATH
no Solaris.
Single Unix v2 (uma antiga extensão do POSIX) tem isto a dizer sobre link
:
The
link()
function will atomically create a new link for the existing file and the link count of the file is incremented by one.
Sobre rename
:
If the link named by the new argument exists, it is removed and old renamed to new. In this case, a link named new will remain visible to other processes throughout the renaming operation and will refer either to the file referred to by new or old before the operation began.
POSIX declara explicitamente que, se o destino existir, sua substituição deve ser atômica. No entanto, ele não declara que o próprio renomeamento deve ser atômico, ou seja, que não há ponto no tempo em que ambos antigo e novo se refiram ao arquivo em questão, ou quando nenhum faz. Na prática, essas propriedades são verdadeiras em sistemas unix, pelo menos com sistemas de arquivos locais.
Além disso, a ordem das operações é garantida: em C, ;
garante a execução sequencial; em sh, ;
/ newline garante execução sequencial (assim como &&
e assim por diante); outras linguagens de programação oferecem garantias semelhantes. Então, em
unlink("/tmp/foo");
unlink("/tmp/bar");
é garantido que não há ponto no tempo em que /tmp/foo
exista, mas não /tmp/bar
(assumindo que /tmp/bar
exista inicialmente). Portanto, um processo simultâneo executando link("/tmp/foo", "/tmp/bar")
não pode ser bem-sucedido.
Note que a atomicidade não garante resiliência . A atomicidade é sobre o comportamento observável em um sistema ao vivo. A resiliência, no contexto dos sistemas de arquivos, é sobre o que acontece em caso de falha do sistema. Muitos sistemas de arquivos sacrificam a resiliência por desempenho, portanto, se a execução de unlink("foo"); unlink("bar");
for interrompida (com o diretório atual no armazenamento em disco), é possível que bar
seja excluído e foo
permaneça atrasado.
Alguns sistemas de arquivos de rede dão menos garantias quando ocorrem operações em diferentes clientes. Implementações mais antigas do NFS eram notórias para isso. Eu acho que as implementações modernas são melhores, mas eu não tenho experiência do NFS moderno.