Це насправді досить просто, принаймні, якщо вам не потрібні деталі реалізації.
По-перше, в Linux всі файлові системи (ext2, ext3, btrfs, reiserfs, tmpfs, zfs, ...) реалізовані в ядрі. Деякі можуть вивантажити роботу з кодом користувача через FUSE, а деякі надходять лише у вигляді модуля ядра ( рідний ZFS є помітним прикладом останнього через ліцензійні обмеження), але в будь-якому випадку залишається компонент ядра. Це важлива основна.
Коли програма хоче читати з файлу, він буде видавати різні виклики бібліотек системи , яка в кінцевому рахунку , в кінцевому підсумку в ядрі у вигляді open()
, read()
, close()
послідовність (можливо , з seek()
доданими для хорошої заходом). Ядро приймає наданий шлях та ім'я файлу, і через файлову систему та пристрій шар вводу / виводу переводить їх у фізичні запити на читання (а також у багатьох випадках також запити запису - подумайте, наприклад, оновлення atime) до деякого базового сховища.
Однак не потрібно перекладати ці запити спеціально на постійне зберігання . Контракт ядра полягає в тому, що видача цього конкретного набору системних викликів надаватиме вміст відповідного файлу . Там, де саме в нашій фізичній царині існує "файл", є вторинним для цього.
На /proc
зазвичай монтується те, що відомо procfs
. Це особливий тип файлової системи, але оскільки це файлова система, вона насправді не відрізняється від, наприклад, ext3
файлової системи, десь встановлена. Тож запит передається до коду драйвера файлової системи procfs, який знає про всі ці файли та каталоги та повертає окремі фрагменти інформації з структур даних ядра .
У цьому випадку "рівень зберігання" - це структура даних ядра і procfs
забезпечує чистий, зручний інтерфейс для доступу до них. Майте на увазі, що монтаж profs /proc
просто - це умова ; ви могли так само легко встановити його в іншому місці. Насправді, це іноді робиться, наприклад, у в'язницях Chroot, коли процес, який там працює, потребує доступу до / proc з певних причин.
Це працює так само, якщо ви записуєте значення в якийсь файл; на рівні ядра, що призводить до ряду open()
, seek()
, write()
, close()
виклики , які знову отримати передаються драйверу файлової системи; знову ж таки, у цьому конкретному випадку код procfs.
Конкретна причина, чому ви бачите file
повернення, empty
полягає в тому, що багато файлів, які піддаються procfs, піддаються розміру в 0 байт. Розмір 0 байтів, ймовірно, є оптимізацією на стороні ядра (багато файлів в / proc є динамічними і можуть легко змінюватися по довжині, можливо, навіть від одного читання до другого, і обчислення довжини кожного файлу в кожному прочитаному каталозі буде потенційно можуть бути дуже дорогими). Переходячи до коментарів до цієї відповіді, яку ви можете перевірити у власній системі, пропустивши через strace або подібний інструмент, file
спочатку надсилає stat()
виклик для виявлення будь-яких спеціальних файлів, а потім користується можливістю, якщо розмір файлу повідомляється як 0 , перервіть і повідомте про файл як про порожній.
Така поведінка фактично задокументовані і можуть бути перевизначені шляхом вказівки -s
або --special-files
на file
виклик, хоча , як зазначено на сторінці керівництва , які можуть мати побічні ефекти. Цитата нижче - із підручної сторінки файлу BSD 5,11 від 17 жовтня 2011 року.
Зазвичай файл намагається лише прочитати та визначити тип файлів аргументів, які звіти stat (2) є звичайними файлами. Це запобігає проблемам, оскільки читання спеціальних файлів може мати особливі наслідки. Визначення -s
параметра призводить до того, що файл також може читати файли аргументів, які є блоковими або символьними спеціальними файлами. Це корисно для визначення типів файлової системи даних у необроблених дискових розділах, які є блоком спеціальних файлів. Ця опція також призводить до того, що файл не враховує розмір файлу, як повідомляє stat (2), оскільки в деяких системах він повідомляє нульовий розмір для необроблених розділів диска.
strace file /proc/version
абоltrace -S /proc/version
, оптимізація досить мала. Здійснюєstat()
дзвінок спочатку і виявляє, що розмір дорівнює 0, тим самим пропускаючиopen()
- але перед цим завантажуючи кілька магічних файлів.