cp перезаписать vs rm, затем cp

18

При попытке перезаписи двоичного файла , который в настоящее время запущен, cpне может перезаписать, но это возможно rmэто тогда cp. Например:

user@poste:~$ cp binaryFile /tmp
user@poste:~$ sudo cp /tmp/binaryFile binaryFile 
[sudo] password for user:
cp: cannot create regular file `binaryFile`: Text file busy
user@poste:~$ sudo rm binaryFile 
user@poste:~$ sudo cp /tmp/binaryFile  binaryFile 
user@poste:~$ file binaryFile 
binaryFile : ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.24, BuildID[sha1]=0x7ce005d9eb50e2574246b6a881e625802f7e49f2, not stripped

Есть идеи почему?

M4rty
источник
2
Интересная небольшая тема, но должна быть на Unix / Linux.SE IMO.
underscore_d

Ответы:

41

В первом случае вы пытаетесь перезаписать содержимое файла, который в данный момент работает как программа. Linux не позволяет этого - если бы это было так, вы бы перезаписали код прямо в тот момент, когда его выполняла ОС; первое отличие может привести к сбою программы или к ее неисправности.

Но во втором случае вы фактически не изменяете содержимое старого файла - вы создаете новый файл на его месте, в то время как старый просто теряет имя файла, но сохраняет его содержимое без изменений.

(Помните, что техническиrm не удаляются файлы, он просто удаляет ссылки на каталоги - подобно тому, как добавляет больше ссылок на тот же файл. Только когда у файла нет ссылок и нет ссылок на открытый файл, он автоматически удаляется.)ln

Система ссылается на используемые файлы по их иноду, поэтому не имеет значения, что они имеют одинаковое имя файла - это все еще старый файл, который остается открытым системой, и даже если у него больше нет ссылок, он будет только удален как только все программы закроют его.

user1686
источник
7
Другой прием, который часто используется с использованием той же логики: откройте (временный) файл в программном обеспечении и немедленно удалите его, не закрывая файл в первую очередь. Ваша программа по-прежнему может использовать его так, как хочет, и когда ваша программа закрывает его (контролирует) или забывает закрыть (например, ваша программа потерпела крах без очистки), она будет автоматически удалена ОС. (Конец программы, независимо от того, как это произошло, освобождает все ссылки на программу, относящиеся к файлу.)
Тонни
2
Именно поэтому, когда вы удаляете какой-либо файл журнала запущенного процесса, команда df не возвращает исправленный размер, пока вы не остановите процесс
M4rty
Есть ли способ для внешней программы (с правами root) найти и создать новый дескриптор для этого висящего inode? Я предполагаю, что есть программы, которые используют это как «функцию безопасности», поэтому интересно понять всю историю.
BenPen
3
@BenPen: в Linux да - используйте /proc/*/fdдля доступа к нему и, при необходимости, linkat () для добавления новой ссылки в файловую систему.
user1686
3
@BenPen и grawity: На самом деле, вы не можете связать индекс обратно в структуру каталогов, если он имеет нулевые ссылки, даже из- linkat()за соображений безопасности . (Исключение из этого правила: если оно не было создано с open(O_TMPFILE)тем, чтобы оно начиналось с нулевых ссылок.) Если вы попытаетесь, linkat()возвращает ENOENT, даже как root. Посмотрите мой ответ на этот вопрос о том, как на самом деле запустить Perl-скрипт, linkatи докажите, что он не работает, даже с правами root: /
Peter Cordes