Разве `rm -rf` не атомарен?

11

Я только что обнаружил непонятную ошибку:

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

который был вызван следующей командой:

rm -rf $cache_dir/*

где $cache_dirопределяется какxxx/app/cache

Таким образом, я вижу это так: rmудалил все в cache/proddir, затем прямо перед попыткой удалить cache/prodкаталог - другая программа создала файл / каталог внутри него, что вызвало rmсбой.

Правильно ли мое предположение?

zerkms
источник
7
Ваше предположение верно - rm -rне атомарно. Если вы хотите быть уверены, что файлы не будут созданы в каталоге во время rm -rfработы, вы можете сначала переименовать его, а затем удалить переименованный каталог.
Джонни
@Johnny: да, это то, что я фактически уже реализовал :-)
zerkms
Хотя даже это не совсем безопасно. Если приложение в данный момент работает из этого каталога, оно просто будет двигаться и будет работать нормально.
Патрик
Это не имеет ничего общего с rm -rfпоточной безопасностью: если вы запускаете его несколько раз одновременно в одном и том же каталоге, каталог удаляется. Это rm -rне атомарность.
Жиль "ТАК - перестать быть злым"
@Gilles: это зависит: «Часть кода является поточно-ориентированной, если она только манипулирует общими структурами данных таким образом, который гарантирует безопасное выполнение несколькими потоками одновременно». Поэтому, если мы примем «поток» в качестве rmвызова, мы можем говорить о безопасности потока. Но в любом случае, это ничего не меняет
zerkms

Ответы:

7

Появилось сообщение об ошибке «Каталог не пуст» ( ENOTEMPTY), учитывая, что ваше предположение звучит правильно, что это состояние гонки, когда программа создала файл в этом каталоге непосредственно перед rmпопыткой удалить каталог, выдавая ожидаемую ENOTEMPTYошибку из базового rmdir(2).

ПРИМЕЧАНИЕ. Чтобы быть в безопасности, вы можете переместить / переименовать каталог на новое имя, а затем выполнить удаление этого каталога.

SLM
источник
2
Этот ответ неверен, вы можете удалить записи каталога, даже если файл используется, а затем удалить каталог. Простой тест mkdir x; cat > x/a &; tail -f x/a &; rm -r xпоказывает, что каталог может быть удален, даже когда файлы используются, независимо от того, открыты ли они для чтения или записи.
wingedsubmariner
1
Да, файлы все еще существуют, но это не имеет отношения к тому, почему удаление каталога не удалось. Это утверждение в вашем ответе, в частности, неверно: «Система не удалит каталог, в котором находятся файлы, открытые в режиме чтения / записи». В вашем ответе есть что-то хорошее, но это не относится к вопросу :)
wingedsubmariner
1
Кроме того, будьте осторожны, чтобы не перепутать файловые дескрипторы с файлами. Файловые дескрипторы никогда не удаляются, только закрываются.
wingedsubmariner
1
Вашему первому абзацу может потребоваться некоторая работа. Вы правы в том, что удаление файла не происходит, когда файлы все еще открыты, просто, когда файл был удален из этого каталога, они не препятствуют удалению каталога. Да, это означает, что UNIX позволяет существовать файлам, которых нет ни в одном каталоге, как это ни странно кажется на первый взгляд.
wingedsubmariner
1
Я действительно могу думать только о двух причинах, по которым удаление не удастся: либо интуиция OP была правильной, и был создан новый файл, либо это ошибка разрешения. rmжалуется на ошибки разрешения, поэтому я думаю, что мы можем устранить это. Я не достаточно уверен, чтобы опубликовать ответ, хотя.
wingedsubmariner