Жесткие и мягкие ссылки
Оказывается тут не все так прозрачно, как ожидалось. Поэтому я выкладываю пост на всеобщее обозрение.
С символическими ссылками все более-менее понятно. Это файлы-указатели. Аналог из жизни -- дорожные указатели типа там "Тамбов", там "Москва", а там "Крыжополь". Можно удалить указатель, но населенный пункт останется. Можно наоборот -- разбомбить населенный пункт, стереть с лица земли. Останется только указатель, который направляет в никуда.
Сложнее с жесткими ссылками. Начнем несколько из далека. Что такое файл? Согласно про-майкрософтовскому определению (FAT12, FAT16, FAT32, VFAT и в некоторой степени NTFS), файл -- это именованная область памяти, в которой могут содержаться данные. Доступ к данным осуществляется по имени файла.
В файловых системах NIX-ов (ext2, ext3, ext4 и др.) доступ к контенту файла осуществляется не по имени, а по так называемому ноду (NOD). Нод -- это, если хотите, индекс (т.е. число), которое однозначно идентифицирует файл. Точнее его содержимое (контент). Но использовать на практике числа, конечно же, будет крайне неудобно. Поэтому, так же как в FAT-ах, в ext-ах применяются имена. Разница только в том, что имена файлов несколько отдалены от контента, хотя и логически связаны. Файловая система работает примерно так: она берет имя файла, ищет в таблице соответствующий ему (имени) нод, и только потом уже по ноду идет к области, где лежит контент файла. Вот такой длинный путь.
Казалось бы, зачем это надо. Длиннее путь, дольше времени добираться до файла и т.д. На самом деле потери времени настолько мизерные, что их даже никак не померить. А вот преимущество есть!
Поскольку имя ссылается на нод, а нод ссылается на контент, то можно создать два и более имен, которые могут ссылаться на один и тот же нод. Тогда получится, что у контента будет два имени. Пример из жизни: Игорь и Гарик -- это одно и тоже лицо. Только в разных компаниях его по разному называют. Пока оставим вопрос, а зачем это надо -- иметь несколько имен, в подвешенном состоянии. Рассмотрим плюсы его применения несколько позже.
Итак, мы имеем некоторый контент и имеем два имени для этого контента. Умные книжки по Unix/Linux-ам говорят, что если открыть файл по одному из имен и изменить его контент, то во втором имени контент также изменится. Можете проверить. Создайте какой-нибудь текстовый файл. Откройте консоль и наберите команду:
cat > mytext
После чего напечатайте какую-нибудь строку, например
это первый файл
и нажмите Ctrl-D. Эта комбинация укажет системе закончить прием текста с клавиатуры. После чего система закроет файл и сохранит его под именем mytext.
Теперь создайте к этому файлу жесткую ссылку.
ln myfile myfile2
myfile2 -- это имя жесткой ссылки. Точнее, это еще одно имя файла. Оно ничем не отличается от первого. Оба имени равнозначны, ни одно из них не имеет преимущества перед другим и никак не отличается. Теперь вы можете открывать и редактировать файл как по первому имени, так и по второму. Системе это без разницы. Оба имени ссылаются на один и тот же нод. Проверьте -- выполните команду:
ls -il
в первой колонке будут напечатан ноды файлов.
К стати говоря, ноды знать не знают об именах файлов. Но ноды ведут учет количества имен. Добавление еще одного имени увеличивает счетчик у нода, а удаление имени, уменьшает его. Когда будет удалено последнее имя и счетчик станет равен нулю, файловая система удалит так же и нод, а область памяти, где располагался файл, перейдет в общий пул памяти. Таким образом файл прекратит свое существование.
Теперь давайте вспомним о "подвешенном" вопросе. Unix/Linux-системы -- это как правило многопользовательские системы, в отличие от "многопользовательской" Венды. Допустим, у вас на компе имеются два юзера, которые работают с каким-то файлом. Допустим, используют одну туже программу. Потом, один из юзеров решает удалить ее. и успешно удаляет. Что остается второму юзеру? Если это была Венда, то второй юзер впадает в глубокое отчаяние и начинает листать словарь нецензурных терминов. Если это Nix-ы, то ничего страшного не произойдет. Второе имя-то программы никуда не делось!
Удобно? Еще бы! Никаких танцев вокруг костра, никакого удвоенного расхода дискового пространства. После удаления проги, первый юзер уже не видит ее, и не будет переживать, что ее нужно удалить. А второй -- даже не почувствует, что прога была удалена. Она как работала для него, так и будет продолжать работать, пока он ее сам (для себя) не удалит.
А теперь пару слов скажу про грабли, на которые я только что наступил.
UPDATED следущий текст неправильный (я выделил его в цитату). Я проверил свою "хипотезу" и хочу признаться. Господа, я был не правв. Я жестоко ошибся и увел вас в не туда. Прошу простить.
Я написал прогу. И создал к ней жесткую ссылку. Убедился в том, что оба имени принадлежат одной и той же проге. А потом я решил удалить из проги отладочую информацию (для тех, кто в теме -- утилита strip). Удаление отладочной информации из бинарника уменьшает его объем, т.е. изменяет контент файла. Так должно быть... Но система повела себя не так как я ожидал.
В результате работы утилиты strip вместо одного файла с двума именами, стало два файла каждый со своим именем. Тот файл, который я "стрипал" стал меньше по объему. (Все правильно!) А тот, имя которого я не трогал, сохранился. Но вместо двух ссылок у него стала одна. Вау! Т.е. система сделала так называемую операцию "копирование при изменении".
Другими словами, если мы ссылаемся на «нечто» по двум именам, то мы обращаемся к одному и тому же этому "нечто". Оба имени равнозначны. Это так до тех пор, пока мы обращаемся только для чтения. Но стоит нам по одному из имен произвести изменения в этом "нечто", как тут же создается его клон (дубль). Любые изменения будут внесены в клон, в то время как первая копия остается нетронутой. Во как!
Я-то думал, такое возможно только при работе с объектами, размещенными в оперативной памяти, но оказывается и файловая система также следует этому принципу. Причем следует не полностью, а частично: принцип распространяется на бинарники, но не распространяется на текстовые файлы. второй раз -- во, как!
Более тщательный разбор ситуации показал, что при изменения конктента файла не происходит его дублирования. Все работает правильно! Ошибка в ДНК. И состоит она в том, что я не уделил должного внимания ситуации.
Произошло следущее. Сначала я "стрипал" файл, а потом (как я уже говорил -- по невнимателоьности) я еще раз компилировал проект. И только потом я смотрел, что получилось. При "стрипании" происходит изменение в файле. Все правильно, так и должно быть. Оба имени ссылаются на одни и тот же контент. Размер файла для обоих имен будет один и тот же. Это ж один файл!
Я не заметил капкан, который был замаскирован в процессе компиляции: компилятор сначала удаляет файл, а потом создает его за-но-во.
При удалении файла, происходило только удаление одного его из его имен (первого имени). Второе имя осталось. Затем компилятор создавал новый файл, т.е. создавал новый нод. Другое дело -- имена стертого и нового файлов совпадают. Но это ведь не есть один и тот же файл, содержимое которого меняется в процессе компиляции! Это просто другой файл с точно таким же именем, какое было у его предшественника. А раз это другой файл, то никакого отношения к старому файлу он не имеет. Еще раз мои извинения 
Век живи, век учись!
Я -- разработчик устройств на микроконтроллерах (AVR, ARM7, MSP430). Отлично знаю электронику.
Программирую на C/C++. 2008 году перешел с Windows на Ubuntu.
Пишите свои вопросы мне в ЛС -- возможно, смогу помочь.
# хочешь насмешить Бога, расскажи ему о своих планах.