`Rm -rf` n'est-il pas atomique?

11

Je viens de découvrir une erreur déroutante:

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

qui a été provoquée par la commande suivante:

rm -rf $cache_dir/*

$cache_direst défini commexxx/app/cache

Je le vois donc comme: rmtout supprimé dans cache/proddir, puis juste avant de tenter de supprimer le cache/prodrépertoire - un autre programme a créé un fichier / répertoire à l'intérieur, ce qui a provoqué un rméchec.

Mon hypothèse est-elle correcte?

zerkms
la source
7
Votre hypothèse est correcte - rm -rn'est pas atomique. Si vous voulez être sûr qu'aucun autre fichier n'est créé dans le répertoire pendant qu'il rm -rfest en cours d'exécution, vous pouvez le renommer en premier, puis supprimer le répertoire renommé.
Johnny
@Johnny: yep, c'est ce que j'ai déjà implémenté :-)
zerkms
Même si cela n'est pas complètement sûr. Si une application fonctionne actuellement à partir de ce répertoire, elle ne fera que suivre le mouvement et continuera de fonctionner normalement.
Patrick
Cela n'a rien à voir avec la rm -rfsécurité des threads: si vous l'exécutez plusieurs fois simultanément sur le même répertoire, le répertoire est supprimé. Il s'agit de rm -rne pas être atomique.
Gilles 'SO- arrête d'être méchant'
@ Gilles: cela dépend: "Un morceau de code est thread-safe s'il ne manipule que les structures de données partagées de manière à garantir une exécution sûre par plusieurs threads en même temps". Donc, si nous supposons que «thread» est une rminvocation, nous pouvons parler de thread-safety. Mais de toute façon, cela ne change rien
zerkms

Réponses:

7

Le message d'erreur donné était "Répertoire non vide" ( ENOTEMPTY), étant donné que votre hypothèse semble correcte, qu'il s'agit d'une condition de concurrence critique où un programme a créé un fichier dans ce répertoire juste avant d' rmessayer de supprimer le répertoire, donnant l' ENOTEMPTYerreur attendue du sous-jacent rmdir(2).

REMARQUE: pour être sûr, vous pouvez déplacer / renommer le répertoire sous un nouveau nom, puis exécuter la suppression de ce répertoire.

slm
la source
2
Cette réponse est fausse, vous pouvez supprimer des entrées de répertoire même lorsqu'un fichier est en cours d'utilisation, puis supprimer le répertoire. Un simple test de mkdir x; cat > x/a &; tail -f x/a &; rm -r xmontre qu'un répertoire peut être supprimé même lorsque des fichiers sont en cours d'utilisation, qu'ils soient ouverts en lecture ou en écriture.
wingedsubmariner
1
Oui, les fichiers existent toujours, mais cela n'a rien à voir avec la raison pour laquelle la suppression du répertoire n'a pas réussi. Cette déclaration dans votre réponse est spécifiquement fausse: "Le système ne supprimera pas un répertoire contenant des fichiers qui y sont ouverts et ouverts en mode lecture / écriture". Il y a de bonnes choses dans votre réponse, cela ne concerne tout simplement pas la question :)
wingedsubmariner
1
Veillez également à ne pas confondre les descripteurs de fichiers avec les fichiers. Les descripteurs de fichiers ne sont jamais supprimés, seulement fermés.
wingedsubmariner
1
Votre premier paragraphe pourrait également avoir besoin de quelques travaux. Vous avez raison de dire que la suppression de fichiers ne se produit pas lorsque les fichiers sont encore ouverts, c'est juste qu'une fois que le fichier a été dissocié de ce répertoire, ils n'empêchent pas le répertoire d'être supprimé. Oui, cela signifie qu'UNIX permet à des fichiers d'exister qui ne se trouvent dans aucun répertoire, aussi étrange que cela puisse paraître au premier abord.
wingedsubmariner
1
Je ne peux vraiment penser qu'à deux raisons pour lesquelles la suppression échouerait, soit l'intuition d'OP était correcte et un nouveau fichier a été créé, soit c'est une erreur d'autorisation. rmse plaint d'erreurs d'autorisation, donc je pense que nous pouvons éliminer cela. Je ne suis pas assez confiant pour poster une réponse cependant.
wingedsubmariner