Czy `rm -rf` nie jest atomowy?

11

Właśnie złapałem mylący błąd:

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

który został spowodowany przez następujące polecenie:

rm -rf $cache_dir/*

gdzie $cache_dirjest zdefiniowany jakoxxx/app/cache

Widzę to tak: rmusunąłem wszystko cache/prodz cache/prodkatalogu , a następnie tuż przed próbą usunięcia katalogu - inny program utworzył w nim plik / katalog, co spowodowało rmawarię.

Czy moje założenie jest prawidłowe?

zerkms
źródło
7
Twoje założenie jest poprawne - rm -rnie jest atomowe. Jeśli chcesz mieć pewność, że w trakcie działania katalogu nie zostaną utworzone żadne pliki rm -rf, możesz najpierw zmienić jego nazwę, a następnie usunąć katalog o zmienionej nazwie.
Johnny
@Johnny: tak, właśnie to już zaimplementowałem :-)
zerkms
Chociaż nawet to nie jest całkowicie bezpieczne. Jeśli aplikacja działa obecnie poza tym katalogiem, po prostu pójdzie z ruchem i będzie działać normalnie.
Patrick
Nie ma to nic wspólnego z rm -rfbezpieczeństwem wątków: jeśli uruchomisz go wiele razy jednocześnie w tym samym katalogu, katalog zostanie usunięty. Chodzi o to, aby rm -rnie być atomowym.
Gilles „SO- przestań być zły”
@Gilles: zależy: „Fragment kodu jest bezpieczny dla wątków, jeśli manipuluje tylko współużytkowanymi strukturami danych w sposób gwarantujący bezpieczne wykonanie wielu wątków jednocześnie”. Jeśli więc przyjmiemy „wątek” jako rmwywołanie, możemy mówić o bezpieczeństwie wątków. Ale i tak nic to nie zmienia
zerkms

Odpowiedzi:

7

Podany komunikat o błędzie brzmiał: „Katalog nie jest pusty” ( ENOTEMPTY), biorąc pod uwagę, że twoje założenie brzmi poprawnie, że jest to wyścig, w którym program utworzył plik w tym katalogu tuż przed rmpróbą usunięcia katalogu, dając oczekiwany ENOTEMPTYbłąd z bazy rmdir(2).

UWAGA: Aby zachować bezpieczeństwo, możesz przenieść / zmienić nazwę katalogu na nową nazwę, a następnie wykonać usunięcie tego katalogu.

slm
źródło
2
Ta odpowiedź jest nieprawidłowa, możesz usunąć wpisy katalogu, nawet gdy plik jest w użyciu, a następnie usunąć katalog. Prosty test mkdir x; cat > x/a &; tail -f x/a &; rm -r xpokazuje, że katalog można usunąć nawet wtedy, gdy pliki są używane, niezależnie od tego, czy są otwarte do odczytu, czy zapisu.
wingedsubmariner
1
Tak, pliki nadal istnieją, ale nie ma to nic wspólnego z tym, dlaczego usunięcie katalogu nie powiodło się. To stwierdzenie w odpowiedzi jest fałszywe: „System nie usunie katalogu, w którym znajdują się pliki, które są otwarte w trybie odczytu / zapisu”. W twojej odpowiedzi jest kilka dobrych rzeczy, to po prostu nie dotyczy pytania :)
wingedsubmariner
1
Uważaj również, aby nie pomylić deskryptorów plików z plikami. Deskryptory plików nigdy nie są usuwane, tylko zamykane.
wingedsubmariner
1
Twój pierwszy akapit również może wymagać trochę pracy. Masz rację, że usuwanie pliku nie dzieje się, gdy pliki są nadal otwarte, po prostu po odłączeniu pliku od tego katalogu nie zapobiegają one usunięciu katalogu. Tak, oznacza to, że UNIX zezwala na istnienie plików, które nie znajdują się w żadnym katalogu, co wydaje się dziwne na pierwszy rzut oka.
wingedsubmariner
1
Naprawdę potrafię wymyślić tylko dwa powody, dla których usunięcie nie powiodło się: albo intuicja OP była poprawna i utworzono nowy plik, albo błąd zezwolenia. rmskarży się na błędy uprawnień, więc myślę, że możemy to wyeliminować. Jednak nie jestem wystarczająco pewny siebie, aby opublikować odpowiedź.
wingedsubmariner