Ist `rm -rf` nicht atomar?

11

Ich habe gerade einen verwirrenden Fehler entdeckt:

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

was durch den folgenden Befehl verursacht wurde:

rm -rf $cache_dir/*

wo $cache_dirist definiert alsxxx/app/cache

Ich sehe es also so: rmalles in cache/proddir entfernt, dann kurz bevor es versuchte, das cache/prodVerzeichnis zu entfernen - ein anderes Programm hat eine Datei / ein Verzeichnis darin erstellt, wodurch es einen rmFehler verursachte .

Ist meine Annahme richtig?

zerkms
quelle
7
Ihre Annahme ist richtig - rm -rist nicht atomar. Wenn Sie sicherstellen möchten, dass während der rm -rfAusführung keine weiteren Dateien im Verzeichnis erstellt werden , können Sie diese zuerst umbenennen und dann das umbenannte Verzeichnis entfernen.
Johnny
@ Johnny: Ja, das habe ich eigentlich schon implementiert :-)
Zerkms
Auch wenn das nicht ganz sicher ist. Wenn eine App derzeit außerhalb dieses Verzeichnisses ausgeführt wird, wird sie einfach verschoben und funktioniert weiterhin normal.
Patrick
Dies hat nichts mit rm -rfThread-Sicherheit zu tun : Wenn Sie es mehrmals gleichzeitig im selben Verzeichnis ausführen, wird das Verzeichnis gelöscht. Hier geht es darum, rm -rnicht atomar zu sein.
Gilles 'SO - hör auf böse zu sein'
@ Gilles: Es kommt darauf an: "Ein Code ist threadsicher, wenn er nur gemeinsam genutzte Datenstrukturen so manipuliert, dass eine sichere Ausführung durch mehrere Threads gleichzeitig gewährleistet ist." Wenn wir also "Thread" als rmAufruf annehmen , können wir über Thread-Sicherheit sprechen. Aber es ändert nichts
zerkms

Antworten:

7

Die angegebene Fehlermeldung lautete "Verzeichnis nicht leer" ( ENOTEMPTY). Angesichts dieser Tatsache klingt Ihre Annahme richtig, dass es sich um eine Race-Bedingung handelt, bei der ein Programm eine Datei in diesem Verzeichnis erstellt hat, bevor es rmversucht hat, das Verzeichnis zu entfernen, und den erwarteten ENOTEMPTYFehler aus dem zugrunde liegenden Wert ergibt rmdir(2).

HINWEIS: Um auf der sicheren Seite zu sein, können Sie das Verzeichnis in einen neuen Namen verschieben / umbenennen und dann das Löschen dieses Verzeichnisses ausführen.

slm
quelle
2
Diese Antwort ist falsch. Sie können Verzeichniseinträge entfernen, auch wenn eine Datei verwendet wird, und dann das Verzeichnis löschen. Ein einfacher Test von mkdir x; cat > x/a &; tail -f x/a &; rm -r xzeigt, dass ein Verzeichnis auch dann entfernt werden kann, wenn Dateien verwendet werden, unabhängig davon, ob sie zum Lesen oder Schreiben geöffnet sind.
Wingedsubmariner
1
Ja, die Dateien sind noch vorhanden, aber dies hat nichts damit zu tun, warum das Löschen des Verzeichnisses nicht erfolgreich war. Diese Aussage in Ihrer Antwort ist speziell falsch: "Das System löscht kein Verzeichnis, in dem sich Dateien befinden, die im Lese- / Schreibmodus geöffnet sind." Es gibt einige gute Sachen in Ihrer Antwort, es bezieht sich einfach nicht auf die Frage :)
wingedsubmariner
1
Achten Sie auch darauf, Dateideskriptoren nicht mit Dateien zu verwechseln. Dateideskriptoren werden niemals gelöscht, sondern nur geschlossen.
Wingedsubmariner
1
Ihr erster Absatz benötigt möglicherweise auch etwas Arbeit. Sie haben Recht damit, dass das Löschen von Dateien nicht erfolgt, wenn die Dateien noch geöffnet sind. Nur wenn die Verknüpfung der Datei mit diesem Verzeichnis aufgehoben wurde, wird das Löschen des Verzeichnisses nicht verhindert. Ja, dies bedeutet, dass UNIX das Vorhandensein von Dateien zulässt, die sich in keinem Verzeichnis befinden, so seltsam das zunächst erscheint.
Wingedsubmariner
1
Ich kann mir wirklich nur zwei Gründe vorstellen, warum das Löschen fehlschlagen würde: Entweder war die Intuition von OP korrekt und eine neue Datei wurde erstellt, oder es handelt sich um einen Berechtigungsfehler. rmbeschwert sich über Berechtigungsfehler, daher denke ich, dass wir das beseitigen können. Ich bin jedoch nicht sicher genug, um eine Antwort zu schreiben.
Wingedsubmariner