Что такое каталоги, если все на Linux - файл?

Очень часто новички слышат фразу, "Все - файл на Linux/Unix". Однако, каковы каталоги затем? Как они отличаются из файлов?

17
задан 9 September 2018 в 19:36

1 ответ

Примечание: первоначально это было записано для поддержки моего ответа для того, Почему находится текущий каталог в ls команда, определенная, как связано с собой? но я чувствовал, что это - тема, которая имеет право стоять самостоятельно, и следовательно это Вопросы и ответы.

Понимание файловой системы Unix/Linux и файлов: Все - inode

По существу каталог является просто специальным файлом, который содержит список записей и их идентификатор.

Прежде чем мы начнем обсуждение, важно сделать различие между несколькими условиями и понять то, что действительно представляют каталоги и файлы. Вы, возможно, услышали выражение, "Все - файл" для 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). схема, одолженная от связанного вопроса, вероятно, объясняет это более кратко:

Directory-iNode-Block

Через всю эту информацию, хранившую в 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. В частности,

  • ext3 и ext4 используют HTree
  • xfs использует B + Дерево
  • zfs использует хэш-дерево

Ключевой пункт здесь - то, что сами каталоги являются узлами в дереве, и подкаталоги являются дочерними узлами с каждым ребенком, имеющим ссылку назад на родительский узел. Таким образом для ссылки каталога количество 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 поля.

Примечание по "записи" в каталоги: запись в каталог изменяет свой "список" записей. Следовательно, создание или удаление файла непосредственно связаны с полномочиями записи каталога, и добавляющие/удаляющие файлы являются операцией записи на упомянутом каталоге.

21
ответ дан 23 November 2019 в 02:23

Другие вопросы по тегам:

Похожие вопросы: