Дуже часто початківці чують фразу "Все є файлом в Linux / Unix". Однак які каталоги тоді? Чим вони відрізняються від файлів?
Дуже часто початківці чують фразу "Все є файлом в Linux / Unix". Однак які каталоги тоді? Чим вони відрізняються від файлів?
Відповіді:
Примітка: спочатку це було написано на підтримку моєї відповіді на те, чому поточний каталог у ls
команді визначений як пов'язаний з собою? але я відчув, що це тема, яка заслуговує на те, щоб стати самостійно, а отже, це питання .
По суті, каталог - це лише спеціальний файл, який містить список записів та їх ідентифікатор.
Перш ніж розпочати дискусію, важливо зробити відмінність між декількома термінами та зрозуміти, що насправді представляють каталоги та файли. Можливо, ви чули вираз "Все - це файл" для Unix / Linux. Що ж, користувачі часто розуміють як файл, це: /etc/passwd
- Об'єкт із контуром та назвою. Насправді ім’я (будь то каталог чи файл, чи будь-що інше) - це лише рядок тексту - властивість фактичного об’єкта. Цей об'єкт називається inode або I-число і зберігається на диску в таблиці inode. Відкриті програми також мають таблиці inode, але це зараз не хвилює нас.
Поняття Unix про каталог, як Кен Томпсон в інтерв'ю 1989 року :
... А потім деякі з цих файлів були каталогами, які просто містили ім'я та I-номер.
Цікаве спостереження можна зробити з розмови Денніса Річі в 1972 році, що
"... каталог насправді не більше ніж файл, але його вміст контролюється системою, а вміст - це імена інших файлів. (Каталог іноді називається каталогом в інших системах.)"
... але ніде в розмові немає згадок про індекси. Однак у посібнику 1971 р. Йдеться про format of directories
:
Про те, що файл є каталогом, позначається бітом у слові прапора його входу i-node.
Записи в каталозі мають довжину 10 байт. Перше слово - i-вузол файла, представлений записом, якщо він не є нулем; якщо нуль, запис порожній.
Так воно було там з самого початку.
Спарювання каталогів та inode також пояснено у розділі Як зберігаються структури каталогів у файловій системі UNIX? . сам каталог - це структура даних, точніше: перелік об'єктів (файлів та номерів inode), що вказує на списки про ці об'єкти (дозволи, тип, власник, розмір тощо). Отже, кожен каталог містить власний номер inode, а потім імена файлів та їхні номери inode. Найвідомішим є inode №2, який є /
каталогом . (Зауважте, хоча це /dev
і /run
є віртуальні файлові системи, тому, оскільки вони є кореневими папками для їх файлової системи, вони також мають inode 2; наприклад, inode є унікальним у власній файловій системі, але з доданими декількома файловими системами у вас є не унікальні вставки). діаграма, запозичена з пов'язаного питання, ймовірно, пояснює це більш коротко:
Всю інформацію, що зберігається в inode, можна отримати через stat()
системні дзвінки відповідно до Linux man 7 inode
:
Кожен файл має вкладку, що містить метадані про файл. Додаток може отримати ці метадані, використовуючи stat (2) (або пов'язані з ним виклики), що повертає структуру stat, або statx (2), яка повертає структуру statx.
Чи можна отримати доступ до файлу лише знаючи його номер inode ( ref1 , ref2 )? У деяких реалізаціях Unix це можливо, але це обходить перевірки дозволу та доступу, тому в Linux це не реалізовано, і вам доведеться перейти до дерева файлової системи ( find <DIR> -inum 1234
наприклад, наприклад), щоб отримати ім'я файлу та його відповідний inode.
На рівні вихідного коду він визначений у джерелі ядра Linux, а також прийнятий багатьма файловими системами, що працюють в операційних системах Unix / Linux, включаючи файлові системи ext3 та ext4 (за замовчуванням Ubuntu). Цікава річ: оскільки дані є лише блоками інформації, Linux насправді має функцію inode_init_always, яка може визначити, чи є inode трубою ( inode->i_pipe
). Так, розетки та труби технічно також є файлами - анонімними файлами, які можуть не мати на диску файлу. У сокетів FIFO та Unix-Domain є назви файлів у файловій системі.
Дані самі по собі можуть бути унікальними, але номери inode не є унікальними. Якщо у нас є жорстке посилання на foo з назвою foobar, це також вказуватиме на inode 123. Цей самий inode містить інформацію про те, які фактичні блоки дискового простору займають цей інод. І це технічно, як ви можете .
бути пов'язані з назвою файлу каталогу. Ну, майже: ви не можете створювати жорсткі посилання на каталоги в Linux самостійно , але файлові системи можуть дозволяти жорсткі посилання на каталоги дуже дисципліновано, що обмежує наявність лише .
та ..
жорстких посилань.
Файлові системи реалізують дерево каталогів як одну з структур даних дерева. Зокрема,
Ключовим моментом тут є те, що самі каталоги є вузлами в дереві, а підкаталоги - дочірніми вузлами, причому кожна дитина має посилання назад до батьківського вузла. Таким чином, для посилання на каталог кількість inode становить мінімум 2 для голого каталогу (посилання на ім'я каталогу /home/example/
та посилання на self /home/example/.
), і кожен додатковий підкаталог є додатковою посиланням / вузлом:
# new directory has link count of 2
$ stat --format=%h .
2
# Adding subdirectories increases link count
$ mkdir subdir1
$ stat --format=%h .
3
$ mkdir subdir2
$ stat --format=%h .
4
# Count of links for root
$ stat --format=%h /
25
# Count of subdirectories, minus .
$ find / -maxdepth 1 -type d | wc -l
24
Діаграма, знайдена на сторінці курсу курсу Ієна Д. Аллена, показує спрощену дуже чітку схему:
WRONG - names on things RIGHT - names above things
======================= ==========================
R O O T ---> [etc,bin,home] <-- ROOT directory
/ | \ / | \
etc bin home ---> [passwd] [ls,rm] [abcd0001]
| / \ \ | / \ |
| ls rm abcd0001 ---> | <data> <data> [.bashrc]
| | | |
passwd .bashrc ---> <data> <data>
Єдине, що невірно в діаграмі ПРАВО - це те, що файли технічно не вважаються самим деревом каталогів: додавання файлу не впливає на кількість посилань:
$ mkdir subdir2
$ stat --format=%h .
4
# Adding files doesn't make difference
$ cp /etc/passwd passwd.copy
$ stat --format=%h .
4
Щоб цитувати Лінуса Торвальда :
Вся справа в тому, що "все є файлом" полягає не в тому, що у вас є якесь випадкове ім'я файлу (дійсно, розетки та труби показують, що "файл" і "ім'я файлу" не мають нічого спільного), а в тому, що ви можете використовувати загальну інструменти для роботи над різними речами.
Враховуючи, що каталог - це лише особливий випадок файлу, природно, повинні бути API, які дозволяють нам відкривати / читати / записувати / закривати їх аналогічно звичайним файлам.
Ось де dirent.h
створена бібліотека C, яка визначає dirent
структуру, яку ви можете знайти в man 3 readdir :
struct dirent {
ino_t d_ino; /* Inode number */
off_t d_off; /* Not an offset; see below */
unsigned short d_reclen; /* Length of this record */
unsigned char d_type; /* Type of file; not supported
by all filesystem types */
char d_name[256]; /* Null-terminated filename */
};
Таким чином, у вашому коді C ви повинні визначитись struct dirent *entry_p
, і коли ми відкриємо каталог із ним opendir()
і почнемо його читати readdir()
, ми будемо зберігати кожен елемент у цій entry_p
структурі. Звичайно, кожен елемент буде містити поля, визначені в шаблоні, dirent
показаному вище.
Практичний приклад того, як це працює, ви можете знайти у моїй відповіді на тему « Перерахування файлів та їх номерів inode у поточному робочому каталозі .
Зауважте, що в посібнику POSIX на fdopen зазначено, що "[t] he записи в каталозі для крапки та крапки є необов'язковими", а в посібниках readdir в ручному режимі struct dirent
потрібно мати лише поля d_name
та d_ino
поля.
Зауважте про "запис" у каталоги: запис у каталог змінює його "список" записів. Отже, створення або видалення файлу безпосередньо пов'язане з дозволами на запис у каталог , а додавання / видалення файлів - це операція запису у вказаному каталозі.
open()
і read()
сокети, connect()
і read()
теж. Що точніше, це те, що "файл" - це дійсно організовані "дані", що зберігаються на диску або пам'яті, а деякі файли є анонімними - вони не мають імені файлу. Зазвичай користувачі думають про файли з точки зору цього значка на робочому столі, але це не єдине, що існує. Дивіться також unix.stackexchange.com/a/116616/85039