Очень часто новички слышат фразу, "Все - файл на Linux/Unix". Однако, каковы каталоги затем? Как они отличаются из файлов?
Примечание: первоначально это было записано для поддержки моего ответа для того, Почему находится текущий каталог в ls
команда, определенная, как связано с собой? но я чувствовал, что это - тема, которая имеет право стоять самостоятельно, и следовательно это Вопросы и ответы.
По существу каталог является просто специальным файлом, который содержит список записей и их идентификатор.
Прежде чем мы начнем обсуждение, важно сделать различие между несколькими условиями и понять то, что действительно представляют каталоги и файлы. Вы, возможно, услышали выражение, "Все - файл" для Unix/Linux. Ну, что часто понимают пользователи, поскольку файл - это: /etc/passwd
- Объект с путем и именем. В действительности имя (быть этим каталог или файл, или безотносительно) является просто строкой текста - свойство фактического объекта. Тот объект называют inode или I-числом, и хранят на диске в inode таблице. Открытые программы также имеют inode таблицы, но это не наше беспокойство на данный момент.
Понятие Unix каталога - как Ken Thompson выразился в интервью 1989 года:
... И затем некоторые из тех файлов, были каталоги, которые просто содержали имя и I-число.
Интересное наблюдение может быть сделано из разговора Dennis Ritchie в 1972 этим
"... каталог является на самом деле не больше, чем файлом, но его содержанием управляет система, и содержание является названиями других файлов. (Каталог иногда называют каталогом в других системах.)"
... но нет никакого упоминания о inodes нигде в разговоре. Однако руководство 1971 года по format of directories
состояния:
То, что файл является каталогом, обозначается немного в слове флага я — запись узла.
Записи каталога 10 байтов длиной. Первое слово является мной — узел файла, представленного записью, если не — обнуляют; если нуль, запись пуста.
Таким образом, это было там с начала.
Соединение каталога и inode также объяснено в том, Как структуры каталогов хранятся в файловой системе UNIX?. сам каталог является структурой данных, более конкретно: список объектов (файлы и inode числа) указывающий на списки о тех объектах (полномочия, тип, владелец, размер, и т.д.). Таким образом, каждый каталог содержит свое собственное inode число, и затем имена файлов и их inode числа. Самый известный inode № 2, который является /
каталог. (Отметьте, хотя это /dev
и /run
виртуальные файловые системы, поэтому так как они - корневые папки для своей файловой системы, у них также есть inode 2; т.е. inode уникален самостоятельно fileystem, но с несколькими присоединенными файловыми системами, у Вас есть групповой inodes). схема, одолженная от связанного вопроса, вероятно, объясняет это более кратко:
Через всю эту информацию, хранившую в inode, можно получить доступ stat()
системные вызовы, согласно Linux man 7 inode
:
Каждый файл имеет inode, содержащий метаданные о файле. Приложение может получить эти метаданные с помощью статистики (2) (или связанные вызовы), который возвращает структуру статистики или 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
). Да, сокеты и каналы являются технически также файлами - анонимные файлы, которые не могут иметь имени файла на диске. FIFOs и Доменные Unix сокеты действительно имеют имена файлов в файловой системе.
Сами данные могут быть уникальными, но inode числами, не уникальны. Если у нас есть жесткая ссылка на нечто, названное foobar, который укажет на inode 123 также. Этот inode сам содержит информацию относительно того, какие фактические блоки дискового пространства заняты этим inode. И это технически, как Вы можете иметь .
будучи связанным с именем файла каталога. Ну, почти: Вы не можете создать hardlinks к каталогам на Linux сами, но файловые системы могут позволить жесткие ссылки на каталоги очень дисциплинированным способом, который делает ограничение из наличия только .
и ..
как жесткие ссылки.
Файловые системы реализуют дерево каталогов как одно из дерева datastructures. В частности,
Ключевой пункт здесь - то, что сами каталоги являются узлами в дереве, и подкаталоги являются дочерними узлами с каждым ребенком, имеющим ссылку назад на родительский узел. Таким образом для ссылки каталога количество inode минимально 2 для пустого каталога (свяжитесь с именем каталога /home/example/
и свяжитесь с сам /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
Схема, найденная на странице курса Ian D. Allen, показывает упрощенную очень четкую схему:
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
Заключить Linus Torvalds в кавычки:
Самым главным со "всем является файл", не то, что у Вас есть некоторое случайное имя файла (действительно, сокеты и каналы показывают, что "файл" и "имя файла" не имеют никакого отношения друг к другу), но то, что можно использовать общие инструменты для работы на разные вещи.
При полагании, что каталог является просто особым случаем файла, естественно должны быть API, которые позволяют нам открывать/читать/писать/закрывать их подобным способом в регулярные файлы.
Это то, где dirent.h
Библиотека C въезжает в место, которое определяет dirent
структура, которую можно найти в человеке 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] он записи каталога для точки и точечной точки являются дополнительными" и readdir ручными состояниями struct dirent
только требуется, чтобы иметь d_name
и d_ino
поля.
Примечание по "записи" в каталоги: запись в каталог изменяет свой "список" записей. Следовательно, создание или удаление файла непосредственно связаны с полномочиями записи каталога, и добавляющие/удаляющие файлы являются операцией записи на упомянутом каталоге.