O `rm -rf` não é atômico?

11

Acabei de pegar um erro confuso:

rm: cannot remove `xxx/app/cache/prod': Directory not empty

que foi causado pelo seguinte comando:

rm -rf $cache_dir/*

onde $cache_diré definido comoxxx/app/cache

Então, eu vejo como: rmremoveu tudo no cache/proddiretório e logo antes de tentar remover o cache/proddiretório - outro programa criou um arquivo / diretório dentro dele, causando rmfalha.

Minha suposição está correta?

zerkms
fonte
7
Sua suposição está correta - rm -rnão é atômica. Se quiser ter certeza de que não há mais arquivos criados no diretório enquanto este rm -rfestiver em execução, renomeie-o primeiro e remova o diretório renomeado.
22413 Johnny
@Johnny: Sim, isso é o que eu realmente já implementadas :-)
zerkms
Embora nem isso seja completamente seguro. Se um aplicativo estiver operando atualmente fora desse diretório, ele seguirá com a mudança e continuará funcionando normalmente.
22413 Patrick
Isso não tem nada a ver com a rm -rfsegurança de threads: se você executá-lo várias vezes simultaneamente no mesmo diretório, o diretório será excluído. Trata-se de rm -rnão ser atômico.
Gilles 'SO- stop be evil' (
@ Gilles: depende: "Um pedaço de código é seguro para threads se apenas manipular estruturas de dados compartilhadas de uma maneira que garanta a execução segura de vários threads ao mesmo tempo". Portanto, se assumirmos "thread" como uma rminvocação, poderemos falar sobre segurança de threads. Mas de qualquer maneira, isso não muda nada
zerkms

Respostas:

7

A mensagem de erro fornecida foi "Diretório não vazio" ( ENOTEMPTY), considerando que sua suposição parece correta, que é uma condição de corrida em que um programa criou um arquivo nesse diretório antes de rmtentar remover o diretório, fornecendo o ENOTEMPTYerro esperado do subjacente rmdir(2).

NOTA: Para estar seguro, você pode mover / renomear o diretório para um novo nome e, em seguida, executar sua exclusão deste diretório.

slm
fonte
2
Esta resposta está errada, você pode remover as entradas do diretório, mesmo quando um arquivo estiver em uso, e excluir o diretório. Um teste simples mkdir x; cat > x/a &; tail -f x/a &; rm -r xmostra que um diretório pode ser removido mesmo quando os arquivos estão em uso, independentemente de estarem abertos para leitura ou gravação.
wingedsubmariner
1
Sim, os arquivos ainda existem, mas isso não tem nada a ver com o motivo de a exclusão do diretório não ter êxito. Esta afirmação em sua resposta especificamente é falsa: "O sistema não excluirá um diretório que possui arquivos que estão abertos no modo de leitura / gravação". Há algumas coisas boas na sua resposta, ele simplesmente não dizem respeito à questão :)
wingedsubmariner
1
Além disso, tome cuidado para não confundir descritores de arquivos com arquivos. Os descritores de arquivo nunca são excluídos, apenas fechados.
wingedsubmariner
1
Seu primeiro parágrafo pode precisar de algum trabalho também. Você está certo sobre a exclusão do arquivo não ocorrer quando os arquivos ainda estão abertos, é que, uma vez que o arquivo foi desvinculado desse diretório, eles não impedem que o diretório seja excluído. Sim, isso significa que o UNIX permite a existência de arquivos que não estão em nenhum diretório, por mais estranho que pareça a princípio.
wingedsubmariner
1
Eu realmente só consigo pensar em duas razões pelas quais a exclusão falharia: a intuição do OP estava correta e um novo arquivo foi criado, ou é um erro de permissão. rmreclama de erros de permissão, então acho que podemos eliminar isso. Não estou confiante o suficiente para postar uma resposta.
wingedsubmariner