Дозвольте мені її розбити.
При запуску виконуваного файлу, послідовність системних викликів виконуються, в першу чергу , fork()
і execve()
:
fork()
створює дочірній процес процесу виклику, який є (здебільшого) точною копією батьківського, обидва досі працюють однаковим виконуваним файлом (використовуючи сторінки пам'яті копіювати при записі, тому це ефективно). Він повертається двічі: у батьків він повертає дочірній ПІД. У дитини він повертає 0. Зазвичай дочірній процес викликає execve відразу:
execve()
приймає повний шлях до виконуваного файлу як аргумент і замінює процес виклику виконуваним файлом. У цей момент новостворений процес отримує власний віртуальний адресний простір, тобто віртуальну пам'ять, і виконання починається в точці входу (у стані, визначеному правилами платформи ABI для свіжих процесів).
У цей момент завантажувач ELF ядра відобразив текстові та сегменти даних виконуваного файлу в пам'ять, як ніби він використовував mmap()
системний виклик (із спільним відображенням лише для читання та приватним читанням-записом). BSS також відображається як би з MAP_ANONYMOUS. (BTW, я ігнорую тут динамічне посилання для простоти: динамічний лінкер open()
s і mmap()
s всі динамічні бібліотеки перед переходом до точки входу головного виконуваного файлу.)
Лише кілька сторінок фактично завантажуються в пам'ять з диска до того, як нещодавно виконаний () ed почне запускати власний код. Подальші сторінки запитуються під час посилання , якщо / коли процес торкнеться тих частин свого віртуального адресного простору. (Попереднє завантаження будь-яких сторінок коду чи даних перед початком виконання коду простору користувача - це лише оптимізація продуктивності.)
Виконавчий файл ідентифікується за допомогою inode на нижньому рівні. Після того, як файл починає виконуватись, ядро зберігає вміст файлу неушкодженим за посиланням inode, а не за ім'ям файлу, як для відкритих дескрипторів файлів або підтримуваних файлами відображень пам'яті. Таким чином, ви можете легко перемістити виконуваний файл в інше місце файлової системи або навіть в іншу файлову систему. В якості бічної примітки, щоб перевірити різні статистичні дані процесу, ви можете зазирнути до /proc/PID
каталогу (PID - ідентифікатор процесу даного процесу). Ви навіть можете відкрити виконуваний файл як /proc/PID/exe
, навіть він від’єднаний від диска.
Тепер давайте викопаємо рухоме:
При переміщенні файлу в одній і тій же файловій системі виконується системний виклик rename()
, який просто перейменовує файл на інше ім'я, вкладення файлу залишається незмінним.
Тоді як між двома різними файловими системами трапляються дві речі:
Вміст файлу в спочатку копіюються в нове місце, з допомогою read()
іwrite()
Після цього файл від’єднується від вихідного каталогу за допомогою unlink()
та, очевидно, файл отримає новий вклад у новій файловій системі.
rm
насправді просто unlink()
-наведений файл із дерева директорій, тож маючи дозвіл на запис у каталог, ви отримаєте достатнє право видалити будь-який файл із цього каталогу.
Тепер для розваги уявіть, що відбувається, коли ви переміщуєте файли між двома файлами файлів, і у вас немає дозволу на unlink()
файл з джерела?
Ну, файл спочатку буде скопійовано до місця призначення ( read()
, write()
), а потім unlink()
вийде з ладу через недостатній дозвіл. Отже, файл залишиться в обох файлових системах !!