[ Пред. ] [ Содержание ] [ След. ]

Симлинки и хардлинки

[ @теория @symlink @hardlink ]

 


Что такое файл?


Любой файл/каталог (каталоги тоже файлы, но особого формата) — это набор каких-то данных, которые записаны на одном секторе на диске. Или, если они большие, то на каком-то множестве секторов на жестком диске.


Мы привыкли идентифицировать файлы по их именам. А операционная система определяет файлы на диске через inode — Индексный Дескриптор — это структура данных в традиционных для ОС UNIX файловых системах вроде ext4. В этой структуре хранятся только метаданные файлов, каталогов или других объектов файловой системы. Непосредственно данные файлов/каталогов хранятся сами по себе, они могут находиться последовательно на нескольких секторах, а могут быть разбросаны по всему диску.


Метаданные — это только техническая информация о файле, без его имени и содержимого:



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


Увидеть inode файла:


ls -i /home/astenix/test.txt


Пример ответа:


7734848 /home/astenix/test.txt


Циферки — это указатель места (точнее, область) на диске — inode.


Собственно, на вопрос «Что такое файл?» единственно корректным ответом будет «Файл — это ссылка на inode».


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


Что такое ссылка на файл?


Есть условность, которую надо знать и учитывать — в Linux у каждого файла/каталога всегда только один inode, но может быть одновременно несколько имён.


Хардлинк


Каждое отдельное имя одного и того же файла называется hardlink, оно же «жёсткая ссылка». На диске набор информации в файле один, а имён для него (хардлинков) — несколько. И все они равноценны.


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


Зачем это нужно? Это даёт возможность обращаться к одному и тому же файлу из разных каталогов и из разных userspace да под разными именами. Предположим, что на сервере в общем доступе находится файл «dailyReports.txt» Я могу в своём /home сделать хардлинк на этот файл и назову его «Отчёт.txt»; другой пользователь на том же компьютере в своём /home назовёт этот же файл (точнее, ссылку к нему) — «Анекдоты.txt», третий назовёт тот же файл «Важные данные.txt»… Ну или не txt, а файл базы данных — sql. Файл один и тот же, а названия у него разные. И каждый пользователь, который будет редактировать как будто бы разные файлы, а на деле — один и тот же.


Можно в одном каталоге сделать два хардлинка на один и тот же файл из другого каталога. Можно даже сделать хардлинк на файл в том же каталоге, что и оригинал (незачем, но можно).


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


Если оригинальный файл будет переименован или перенесён в другой каталог — хардлинк на него останется тем же и будет открывать переименованный/перемещенный файл так, словно никто ничего не менял.


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


В MC после редактирования оригинального файла при сохранении появляется вопрос — «Файл имеет жёсткие ссылки. Отсоединить перед сохранением?». Если сказать да — изменения в файле не будут отображаться при открытии файла через хардлинк. А хардлинк вроде бы откроет тот же файл на редактирование, но изменения в нём не будут отображаться (нет ссылки — нет изменений). На самом деле хардлинк начинает указывать на новый inode, и будет сохранять все изменения в новом файле. Вполне резонно, что может возникнуть путаница с тем, кто кто-то клянётся, что записал в файл что-то новое, а кто-то открывает этот же файл, но изменений не видит. Оба одновременно правы…


Хардлинки можно переносить в разные каталоги — при этом на жёстком диске сам файл/каталог, на который сделана ссылка, останется на месте.


И даже при удалении одного из имён/хардлинков, файл физически остаётся на диске, но только до тех пор, пока в системе есть другие имена для этого же файла.


Если я у себя удалю файл «Отчёт.txt» — его оригинал «dailyReports.txt» останется, и другие пользователи будут всё так же редактировать его под соответствующими именами — «Анекдоты.txt» и «Важные данные.txt».


Если я сделаю в своих каталогах несколько хардлинков на файл «dailyReports.txt», и удалю один из них — оригинал останется на месте.


Но если все пользователи, у которых есть хардлинки на этот файл, эти самые хардлинки у себя удалят — вот тогда и оригинальный файл будет удалён с сервера (или же с того места на жёстком диске, где он находился). Упс. Поэтому разумнее делать симлинки на файлы.


См. Common:HowTo:Сделать:hardlink


Симлинк


Symbolic link, он же сокращённо «симлинк» — это ссылка не на inode файла, а на имя файла (на хардлинк).


То есть, при обращении к симлинку происходит обращение к хардлинку, который сообщает, к какому именно inode надо обратиться.


Внешне симлинк тоже не распознать — файл и файл, но в Midnight Commander они нарочно отображаются с дополнительными символами:


Симлинки, как и хардлинки, тоже можно свободно переносить в разные каталоги — оригинал останется на месте.


Основная разница между ними в том, что происходит с оригиналами inode при удалении хардлинка и симлинка. Если хардлинки делает один пользователь, и хардлинк тоже один, то при удалении хардлинка, вероятнее всего, оригинальный файл тоже будет удалён (inode будет помечен как свободный), это неоднозначно и иногда откровенно стрёмно. А при удалении симлинков с оригиналом файла ОДНОЗНАЧНО ничего не происходит:


А если снова создать на месте старого файла новый файл, то симлинк снова заработает.


И да, симлинки тоже можно именовать как угодно — ссылка на оригинальный файл/каталог остаётся неизменной.


См. Common:HowTo:Сделать:symlink


Примеры


В Linux можно запускать любой скрипт в консоли из любого каталога как обычную команду, если сделать на нужный скрипт симлинк в каталоге с бинарниками.


Например, я собрал последовательнось команд для обновления Debian и положил его в файл „/home/mySettings/myScripts/debian/debian_update_and_upgrade.sh”.


Сделал скрипт.


В консоли можно запустить этот скрипт так:


/home/mySettings/myScripts/debian/debian_update_and_upgrade.sh


Или сперва зайти в каталог с файлом


cd /home/mySettings/myScripts/debian/


и уже оттуда его запустить:


./debian_update_and_upgrade.sh


А ещё можно сделать символическую ссылку на этот файл, положить её в какой-то каталог «внутри профиля пользователя» и вызывать её в консоли как консольную команду.


Или можно сделать такой симлинк доступным для всех пользователей на компьютере (разумно, когда общий сервер).


У симлинка может быть любое имя, отличное от оригинального файла, и иногда это приносит дополнительное удобство. Например, оригинал будет называться „debian_update_and_upgrade.sh”, а симлинк можно называть очень сокращенно, например, „debup” — расширение для файла в этом случае вообще не имеет значения.


Или „updeb”.
Или „dp”.
Или „updatemazafaka”.
Или все сразу.


Другой сценарий: ссылки на программное обеспечение. Например, пишем программу, которая обращается к исполняемым файлам Java. Где они находятся?


В консоли при вызове


java


происходит пробег по нескольким каталогам и файлам — да, симлинк может ссылаться на другой симлинк, который ссылается на третий симлинк…


  1. Читаем /usr/bin/java — это не просто файл без расширения, это симлинк на /etc/alternatives/java
  2. Читаем /etc/alternatives/java — это симлинк на /usr/lib/jvm/java-17-openjdk-amd64/bin/java
  3. Читаем /usr/lib/jvm/java-17-openjdk-amd64/bin/java — это симлинк на /usr/lib64/ld-linux-x86-64.so.2
  4. Читаем /usr/lib64/ld-linux-x86-64.so.2 — это симлинк на /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 с набором дополнительных инструкций
  5. Читаем, если не надоело, файл /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2

Версии java постоянно меняются, меняется и содержимое файлов, и их расположение. Но через систему симлинков на стороне пользователя вызов java всегда происходит через одну и ту же команду. А вызов


java --version


с ответом вроде


openjdk 17.0.13 2024-10-15
OpenJDK Runtime Environment (build 17.0.13+11-Debian-2deb12u1)
OpenJDK 64-Bit Server VM (build 17.0.13+11-Debian-2deb12u1, mixed mode, sharing)


это же чтение содержимого переменных из разных файлов, в том числе и из /usr/lib/jvm/java-17-openjdk-amd64/release:


IMPLEMENTOR="Debian"
JAVA_RUNTIME_VERSION="17.0.13+11-Debian-2deb12u1"
JAVA_VERSION="17.0.13"
JAVA_VERSION_DATE="2024-10-15"


При выпуске следующей версии — java-18 — исполняемые файлы уже будут находиться в каталоге с другим названием, и информацию о версии придется читать из другого файла в каталоге с другим названием — /usr/lib/jvm/java-18-openjdk-amd64/release Однако благодаря системе перекрёстных хард и симлинков команда обращения будет прежняя.


Третий пример характерен для древних времён, когда на дисках всегда было ОЧЕНЬ мало места. Есть набор файлов, которые находятся в разных каталогах. И надо собрать их них условный плэйлист (сделаем прямую аналогию с аудиофайлами). Можно скопировать все нужные нам файлы в один новый каталог, но это значит, что на диске станет меньше свободного места. А можно в этот новый каталог положить только симлинки на нужные файлы, которые лежат в разных каталогах — если таких файлов много, то получится однозначная экономия места на hdd.


См. Common:HowTo:Сделать:alias