Операционные системы

Теория: Файлы и inode

Когда программа записывает файл на диск, операционной системе нужно решить простую, но фундаментальную задачу: где именно эти данные хранить и как потом их найти.

Диск — это просто огромное поле байтов. Без структуры система не поймёт, где один файл заканчивается, а другой начинается. Поэтому ОС накладывает на диск файловую систему — слой, который превращает хаос байтов в упорядоченную схему: имена, каталоги, права, время изменения.

Главная проблема — файлов может быть миллионы, и все они постоянно создаются, удаляются, переносятся. Нужно быстро находить каждый, знать, где лежат его данные и кто им владеет. Для этого в UNIX-подобных системах придумали механизм inode.

Почему inode вообще нужен

Когда файловая система создаётся, она разбивает диск не только на блоки для данных, но и на таблицу inode — структур, где хранится всё, что нужно знать о каждом файле. Если представить диск как большую таблицу, то inode — это строка с паспортом файла: кто владелец, какие права доступа, когда файл был создан и изменён, сколько он весит и по каким адресам на диске лежат его блоки.

Само имя файла в inode не хранится. Имена живут в каталогах — это отдельные файлы, в которых записаны пары «имя → номер inode». Когда система открывает путь /home/user/report.txt, она просто идёт по цепочке каталогов, на каждом шаге смотря в таблицу и переходя к нужному inode. Именно поэтому имя можно поменять, не трогая сам файл: обновляется лишь запись в каталоге, а inode и данные остаются прежними.

На этой особенности строятся жёсткие ссылки. Если создать второе имя для того же inode, появится два разных пути к одному и тому же файлу. Оба имени равноправны: изменишь содержимое через одно — обновится и через другое. Файл действительно исчезает только тогда, когда счётчик ссылок в inode падает до нуля, то есть не осталось ни одного имени, указывающего на него.

Отсюда вытекает типичная системная ситуация — «нет свободных inode». Каждому файлу, даже самому маленькому, нужен свой inode. Если их количество заранее ограничено и диск забит тысячами крошечных файлов, система перестаёт создавать новые: свободные блоки ещё есть, а карточек под них нет. Проверить можно командой df -i: она показывает процент занятых inode.

Иногда бывает и наоборот — файл вроде удалили, а место не освободилось. Это происходит, если файл всё ещё открыт каким-то процессом. Имя из каталога исчезло, но inode остаётся «живым», пока программа держит его дескриптор. Такие «висячие» файлы можно увидеть через lsof | grep deleted. Как только процесс закроет файл, ядро освободит inode и очистит место.

Что такое каталоги и как система находит файл

Каталог в UNIX — это не «папка» в привычном смысле, а обычный файл особого типа, в котором хранятся пары «имя → номер inode». Ядро использует этот список, чтобы понять, где физически лежат нужные данные.

Когда пользователь открывает файл по пути /home/user/report.txt, система начинает с корня /. В этом каталоге она ищет запись с именем home, находит её inode и переходит к следующему каталогу. Внутри home ищет user, снова получает номер inode, открывает соответствующий каталог и уже там находит запись report.txt. Этот последний inode указывает на структуру, где записаны все атрибуты файла и адреса блоков, в которых лежат реальные данные.

Таким образом, путь к файлу — это не строка, а цепочка переходов по таблицам. Каждая часть пути — это поиск имени в каталоге и переход к следующему inode. Такая система кажется простой, но именно она делает возможной работу с миллионами файлов. Файловая система не держит всё дерево в памяти — она просто поэтапно ищет нужные inode, пока не дойдёт до цели.

Эта идея объясняет, почему переименование файла не требует копирования данных: меняется только запись в каталоге. Сам inode и содержимое файла остаются на месте, а значит, любые другие ссылки на этот inode продолжают работать.

Проблема разных типов файлов

В UNIX-системах идея «всё — это файл» стала одной из самых гениальных. Она позволила сделать ядро простым и единообразным: одно и то же API работает и для текста, и для устройств, и для сети. Но за этим принципом скрывается сложная внутренняя структура — ведь далеко не все файлы действительно хранят байты на диске.

Обычные файлы содержат данные — то, что лежит на жёстком диске или SSD. Их можно читать, писать, копировать. Это привычные документы, картинки, программы.

Каталоги тоже считаются файлами, но в них не хранятся данные. Они содержат таблицу — список имён и соответствующих им inode. Когда пользователь открывает каталог, ядро просто читает этот список и показывает, какие файлы в нём есть.

Символические ссылки — особый тип файлов, которые внутри хранят текстовый путь к другому объекту. При обращении к такой ссылке ядро подставляет указанный путь и перенаправляет запрос. Это делает систему гибкой: один и тот же файл может «лежать» в нескольких местах, хотя физически он существует в одном.

FIFO или именованные каналы — это тоже файлы, но в них ничего не хранится на диске. Они используются для обмена данными между процессами. Один процесс пишет в канал, другой читает из него. При этом информация нигде не сохраняется: поток проходит прямо через память ядра.

Сокеты расширяют ту же идею, но позволяют процессам обмениваться данными не только внутри системы, но и по сети. Для ядра сокет выглядит как файл: у него есть дескриптор, его можно читать, писать и закрывать. Но за ним стоит сетевой стек, который передаёт данные по TCP, UDP или локальным протоколам.

Главный смысл этого подхода в том, что программа может работать с любым объектом одинаково. Когда она вызывает open(), read(), write() или close(), ядру не важно, что за этим стоит — обычный файл, устройство, канал или сокет. Это снимает огромное количество сложности: драйверы, сетевые службы и приложения используют один и тот же интерфейс, а операционная система остаётся универсальной и предсказуемой.

Как увидеть всё это руками

Жёсткие и символьные ссылки — это два способа связать разные имена с одним и тем же файлом, но работают они на разных уровнях. Чтобы понять разницу, нужно вспомнить, как устроена файловая система. Каждый файл хранится в виде двух частей: данные (содержимое) и inode — структура с метаданными. В inode записано всё, кроме имени: права, владелец, время изменения и адреса блоков с данными.

Когда создаётся обычный файл, в каталоге появляется запись «имя → inode». Если создать жёсткую ссылку, команда ln file.txt backup.txt просто добавит ещё одно имя, указывающее на тот же inode. Оба имени — file.txt и backup.txt — теперь равноправны. Удалишь одно — ничего не случится, пока существует второе: inode остаётся в файловой системе, и данные не теряются. Только когда исчезнут все имена, связанных inode, ядро освободит место.

Это и есть hard link — жёсткая ссылка. Она работает только в пределах одного раздела, потому что inode уникален внутри конкретной файловой системы. Её невозможно создать между разными дисками или разделами. Ещё один важный момент: жёсткие ссылки нельзя делать на каталоги, чтобы не запутать дерево путей и не нарушить структуру каталогов.

Символьная ссылка (или symbolic link, symlink) — это уже не вторая запись в каталоге, а самостоятельный файл особого типа. Он просто хранит путь до другого файла в виде текста. Создаётся командой ln -s file.txt shortcut.txt. При обращении к shortcut.txt система открывает этот путь и перенаправляет к исходному файлу. Если исходный файл удалить, символьная ссылка «сломается»: она останется существовать, но будет вести в никуда, как битая ярлык в Windows.

Символические ссылки можно создавать на каталоги, между разделами и даже на удалённые точки монтирования — именно поэтому они гибче. Их часто используют для организации настроек и конфигураций: например, /etc/nginx/sites-enabled/ содержит набор symlink'ов, указывающих на реальные файлы из /etc/nginx/sites-available/.

В системах вроде Linux или macOS разница хорошо видна в выводе команды ls -li. У жёстких ссылок одинаковый номер inode, у символьных — свой inode, но в строке видно стрелку:

1001 -rw-r--r-- 2 user user 1024 Oct 28  report.txt
1001 -rw-r--r-- 2 user user 1024 Oct 28  backup.txt
1002 lrwxrwxrwx 1 user user   11 Oct 28  link.txt -> report.txt

Здесь report.txt и backup.txt — это один и тот же файл с inode 1001, а link.txt — символическая ссылка, которая просто указывает путь report.txt.

Hard link — это как два входа в одну комнату: войдёшь через любой — попадёшь в то же место. Symlink — как табличка с надписью «комната там»: пока дверь на месте, всё работает, но если её уберут, табличка останется, а за ней — пустота.

Рекомендуемые программы

+7 800 100 22 47

бесплатно по РФ

+7 495 085 21 62

бесплатно по Москве

108813 г. Москва, вн.тер.г. поселение Московский,
г. Московский, ул. Солнечная, д. 3А, стр. 1, помещ. 20Б/3
ОГРН 1217300010476
ИНН 7325174845