Почему жесткие ссылки на каталоги не разрешены в UNIX / Linux?


130

Я читал в учебниках, что Unix / Linux не разрешает жесткие ссылки на каталоги, но разрешает мягкие ссылки. Это потому, что когда у нас есть циклы и если мы создаем жесткие ссылки и через некоторое время удаляем исходный файл, он будет указывать на какое-то мусорное значение?

Если циклы были единственной причиной запрета жестких ссылок, то почему разрешены мягкие ссылки на каталоги?


2
Где следует ..указать? Особенно после удаления жесткой ссылки на этот каталог, в каталог, на который указывает ..? Это должно указать куда-то.
Турбьерн Равн Андерсен

2
..не нужно физически существовать на любом диске. В любом случае, операционная система отслеживает текущий рабочий каталог, поэтому относительно просто хранить список инодов, связанных с каждым процессом cwd, и ссылаться на него, когда он видит использование ... Конечно, это будет означать, что символические ссылки нужно создавать с учетом этого, но вы уже должны быть осторожны, чтобы не нарушать символические ссылки, и я не думаю, что дополнительное правило сделает их бесполезными.
Парфянский выстрел

Мне нравится это объяснение . Краткий и легкий для чтения и / или читать.
Тревор Бойд Смит

Ответы:


143

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

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

Во-первых, чтобы понять это, давайте поговорим об инодах. Данные в файловой системе хранятся в блоках на диске, и эти блоки собираются вместе с помощью inode. Вы можете думать об иноде как о файле. У inode нет имен файлов. Вот где приходят ссылки.

Ссылка - это просто указатель на индекс. Каталог - это индекс, который содержит ссылки. Каждое имя файла в каталоге - это просто ссылка на индекс. Открытие файла в Unix также создает ссылку, но это другой тип ссылки (это не именованная ссылка).

Жесткая ссылка - это просто дополнительная запись каталога, указывающая на этот индекс. Когда вы ls -l, число после разрешений является именованным количеством ссылок. Большинство обычных файлов будут иметь одну ссылку. Создание новой жесткой ссылки на файл заставит оба имени файла указывать на один и тот же индекс. Примечание:

% ls -l test
ls: test: No such file or directory
% touch test
% ls -l test
-rw-r--r--  1 danny  staff  0 Oct 13 17:58 test
% ln test test2
% ls -l test*
-rw-r--r--  2 danny  staff  0 Oct 13 17:58 test
-rw-r--r--  2 danny  staff  0 Oct 13 17:58 test2
% touch test3
% ls -l test*
-rw-r--r--  2 danny  staff  0 Oct 13 17:58 test
-rw-r--r--  2 danny  staff  0 Oct 13 17:58 test2
-rw-r--r--  1 danny  staff  0 Oct 13 17:59 test3
            ^
            ^ this is the link count

Теперь вы можете ясно видеть, что нет такой вещи, как жесткая ссылка. Жесткая ссылка такая же, как и обычное имя. В приведенном выше примере, testили test2, что является исходным файлом, а какая жесткая ссылка? В конце концов, вы не можете сказать (даже по меткам времени), потому что оба имени указывают на одно и то же содержимое, один и тот же индекс:

% ls -li test*  
14445750 -rw-r--r--  2 danny  staff  0 Oct 13 17:58 test
14445750 -rw-r--r--  2 danny  staff  0 Oct 13 17:58 test2
14445892 -rw-r--r--  1 danny  staff  0 Oct 13 17:59 test3

-iФлаг lsпоказывает иноды номера в начале строки. Обратите внимание, что testи test2есть один и тот же номер инода, но test3другой.

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

Почему этот цикл вызывает беспокойство? Потому что когда вы пересекаете, нет никакого способа обнаружить, что вы зацикливаетесь (без отслеживания номеров инодов во время прохождения). Представьте, что вы пишете duкоманду, которую необходимо выполнить через подпапки, чтобы узнать об использовании диска. Как бы duзнать, когда он попадет в петлю? Это подвержено ошибкам и много бухгалтерии, duчто нужно сделать, просто чтобы выполнить эту простую задачу.

Симлинки - это совершенно другой зверь в том смысле, что они представляют собой особый тип «файла», за которым обычно следуют многие API файловой системы. Обратите внимание, что символическая ссылка может указывать на несуществующий пункт назначения, потому что они указывают по имени, а не напрямую на индекс. Эта концепция не имеет смысла для жестких ссылок, потому что само существование «жесткой ссылки» означает, что файл существует.

Так почему же можно duлегко справиться с символическими ссылками, а не с жесткими ссылками? Выше мы увидели, что жесткие ссылки неотличимы от обычных записей каталога. Симлинки, однако, особенные, обнаруживаемые и пропускаемые!  duзамечает, что символическая ссылка является символической ссылкой, и пропускает ее полностью!

% ls -l 
total 4
drwxr-xr-x  3 danny  staff  102 Oct 13 18:14 test1/
lrwxr-xr-x  1 danny  staff    5 Oct 13 18:13 test2@ -> test1
% du -ah
242M    ./test1/bigfile
242M    ./test1
4.0K    ./test2
242M    .

7
Allowing hard links to directories would break the directed acyclic graph structure of the filesystem, Можете ли вы объяснить больше о проблеме с циклами, используя жесткие ссылки? Почему это нормально с символическими
ссылками

33
Похоже, что они разрешили это на Mac, добавив обнаружение цикла к системному вызову link () и отказавшись разрешить вам создавать жесткую ссылку на каталог, если это создаст цикл. Кажется, разумное решение.
Псуси

10
@psusi mkdir -pa / b; ночеклн ча; мв ц / б; - нет теоретического, что он не проверяет наличие аргументов каталога и просто переходит к ссылке, и поскольку цикл не выполнен, мы все хороши в создании 'c'. затем мы перемещаем 'c' в 'a / b', и цикл создается из a / b / c -> a / - проверка в link () недостаточно хороша
Дэнни Дулай

3
Циклы очень плохие. Windows имеет эту проблему с "соединениями", которые являются жесткими ссылочными каталогами. Если вы случайно применили разрешения ко всему своему профилю, он обнаружит серию соединений, которые создают бесконечный цикл. Повторение через каталоги происходит до тех пор, пока ограничения длины пути не остановят его.
doug65536

4
@WhiteWinterWolf, по этой ссылке, они специально добавили поддержку для машины времени, но делать это может только root: superuser.com/questions/360926/…
psusi

14

За исключением точек монтирования, каждый каталог имеет один и только родитель: ...

Один из способов pwd- проверить устройство: inode для «.» а также '..'. Если они совпадают, вы достигли корня файловой системы. В противном случае, найдите имя текущего каталога в родительском, поместите его в стек и начните сравнивать '../.' с '../ ..', затем '../../.' с '../../ ..' и т. д. Как только вы дойдете до корня, начните выталкивать и печатать имена из стека. Этот алгоритм основан на том факте, что каждый каталог имеет одного и только одного родителя.

Если разрешены жесткие ссылки на каталоги, на кого должен ..указывать один из нескольких родителей ? Это одна из веских причин, по которым жесткие ссылки на каталоги запрещены.

Символьные ссылки на каталоги не вызывают этой проблемы. Если программа хочет, она может выполнить lstat()каждую часть имени пути и обнаружить, когда встречается символическая ссылка. pwdАлгоритм возвращает истинный абсолютный путь к файлу для целевого каталога. Тот факт, что где-то есть фрагмент текста (символическая ссылка), указывающий на целевой каталог, в значительной степени не имеет значения. Существование такой символической ссылки не создает петлю в графе.


3
Не уверен в этом. Если мы считаем, ..что это своего рода виртуальная жесткая ссылка на родителя, то нет технической причины, по которой у цели ссылки может быть только одна другая ссылка. pwdпросто придется использовать другой алгоритм для разрешения пути.
Benubird

13

Вы можете использовать bind mount для симуляции жестких ссылок на каталоги

sudo mount --bind /some/existing_real_contents /else/dummy_but_existing_directory
sudo umount /else/dummy_but_existing_directory

7

Я хотел бы добавить еще несколько моментов по этому вопросу. Жесткие ссылки на каталоги разрешены в Linux, но ограниченным способом.

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

Итак, давайте создадим дерево каталогов, где «a» является родительским каталогом, у которого каталог «b» является дочерним.

 a
 `-- b

Запишите индекс каталога "а". И когда мы делаем ls -laиз каталога «а», мы можем видеть, что «.» каталог также указывает на тот же индекс.

797358 drwxr-xr-x 3 mkannan mkannan 4096 Sep 17 19:13 a

И здесь мы можем обнаружить, что каталог «а» имеет три жестких ссылки. Это связано с тем, что индекс 797358 имеет три жесткие ссылки на имя "." внутри каталога "a" и имя как ".." внутри каталога "b" и один с именем "a" itslef.

$ ls -ali a/
797358 drwxr-xr-x 3 mkannan mkannan 4096 Sep 17 19:13 .

$ ls -ali a/b/
797358 drwxr-xr-x 3 mkannan mkannan 4096 Sep 17 19:13 ..

Таким образом, здесь мы можем понять, что жесткие ссылки существуют только для каталогов, связанных с их родительскими и дочерними каталогами. Таким образом, каталог без дочерних элементов будет иметь только две жесткие ссылки, и поэтому каталог «b» будет иметь только две жесткие ссылки.

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

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


1
Хороший пример. Это очистило мои сомнения. Таким образом, эти случаи обрабатываются особым образом, чтобы избежать бесконечных циклов. правильно?
G Gill

1
Поскольку у нас есть ограниченный способ разрешения жестких ссылок для каталогов, то есть ".." и "." мы не достигнем бесконечного цикла, и поэтому нам не потребуются какие-либо особые способы избежать их, поскольку они не произойдут :)
Kannan Mohan

6

Ничто из перечисленного не является реальной причиной запрещения жестких ссылок на каталоги; каждую проблему довольно легко решить:

  • циклы в древовидной структуре вызывают сложный обход
  • несколько родителей, так что же является «настоящим»?
  • сборка мусора в файловой системе

Реальная причина (как намекают @ Турбьёрна Равн Andersen) приходит , когда вы удалите каталог , который имеет несколько родителей, из каталога , на который указывает ..:

На что ..сейчас следует указывать?

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

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


3
Это также легко решить: ведите список родителей дочернего каталога, который вы обновляете при добавлении или удалении ссылки на дочерний каталог. Когда вы удаляете канонического родителя (цель ребенка ..), обновитесь, ..чтобы указать на одного из других родителей в списке.
Джет

2
Я согласен. Не ракетостроение, чтобы решить. Но, тем не менее, это приводит к снижению производительности, и это заняло бы немного больше места в метаданных файловой системы и добавило бы сложности. И поэтому дизайнеры пошли на простой, быстрый подход - не разрешать ссылки на жесткие каталоги.
Lqueryvg

1
Ссылки Sym на dirs "нарушают устоявшуюся семантику и поведение", но все же они разрешены. Таким образом, некоторые команды нуждаются в параметрах для контроля за тем, идут ли ссылки sym (например, -L в find и cp). Когда программа следует за «..», возникает дальнейшая путаница, отсюда и разница в выводе из pwd и / bin / pwd после обхода ссылки sym. Там нет "Unix ответы"; просто дизайнерские решения. Этот вращается вокруг того, что становится "..", как я сказал в своем ответе. К сожалению, «..» даже не упоминается в ответе, за который все остальные так смущенно голосуют.
Lqueryvg

Кстати, я не говорю, что я за жесткие ссылки на dirs. Не за что. Я не хочу, чтобы моя дневная работа была тяжелее, чем сейчас.
Lqueryvg

Это не то, что говорит POSIX, но IMO '..' никогда не должно было быть концепцией файловой системы, а должно быть синтаксически разрешено в путях, так что a/..это всегда будет означать .. Вот как работают URL, кстати. Это браузер, который разрешает «..» еще до того, как он попадает на сервер. И это прекрасно работает.
ybungalobill

3

Создание жесткой ссылки на каталоги было бы необратимым. Предположим, у нас есть:

/dir1
├──this.txt
├──directory
│  └──subfiles
└──etc

Я жестко связываю это с /dir2.

Так что /dir2теперь также содержит все эти файлы и каталоги

Что если я передумаю? Я не могу просто rmdir /dir2(потому что это не пусто)

И если я рекурсивно удаляю в /dir2... он тоже будет удален /dir1!

ИМХО, это в значительной степени достаточная причина, чтобы избежать этого!

Редактировать :

Комментарии предлагают удалить каталог, сделав rmна нем. Но rmв непустом каталоге происходит сбой, и это поведение должно сохраняться независимо от того, является ли каталог жестким или нет. Так что вы не можете просто rmотключить его. Для этого потребуется новый аргумент rm, просто чтобы сказать: «если индекс узла имеет счетчик ссылок> 1, то только отсоединить каталог».

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

Я перефразирую свое предложение: без дальнейшей разработки создание жесткой ссылки было бы необратимым (поскольку никакая текущая команда не может обработать удаление, не будучи несовместимым с текущим поведением)

Если мы позволим доработать кейс для разработки, количество подводных камней и риск потери данных, если вы недостаточно осведомлены о том, как работает система, такое развитие событий подразумевает ИМХО достаточную причину для ограничения жестких ссылок на каталоги.


Это не должно быть проблемой. В вашем случае, когда мы создаем hardlink для dir2, мы должны сделать hardlink для всего содержимого в dir1, и поэтому, если мы переименуем или удалим dir2, будет удалена только дополнительная ссылка на inode. И это не должно влиять на dir1 и его содержимое, так как существует хотя бы одна ссылка (dir1) на inode.
Каннан Мохан

3
Ваш аргумент неверен. Вы бы просто отсоединили его, а не делали rm -rf. И если количество ссылок достигнет 0, то система будет знать, что она может также удалить все содержимое.
LtWorf

Это более или менее все rmделает в любом случае (unlink). См .: unix.stackexchange.com/questions/151951/… Это действительно не проблема, равно как и с файлами с жесткими ссылками . Отмена ссылок просто удаляет именованную ссылку и уменьшает количество ссылок. Тот факт, что rmdirне удаляются непустые каталоги, не имеет значения - он не будет делать это dir1 ни для чего . Жесткие ссылки не являются копиями данных, они представляют собой один и тот же фактический файл, поэтому фактически «удаление» файла dir2 приведет к удалению списка каталогов для dir1. Вы всегда должны будете отменить связь.
BryKKan

Вы не можете просто отсоединить его, как обычный файл, потому что rmв каталоге не отсоединяйте его, если он не пустой. Смотрите Редактировать.
Пьер-Оливье Варес

1

Это хорошее объяснение. Относительно "Кто из нескольких родителей должен .. указать на?" Одним из решений было бы для процесса поддерживать свой полный путь wd, либо в виде inode, либо в виде строки. Иноды будут более надежными, так как имена могут быть изменены. По крайней мере, в прежние времена для каждого открытого файла существовал внутренний индекс, который увеличивался при каждом открытии файла, уменьшался при закрытии. Когда он достигнет нуля, хранилище, на которое он указывал, будет освобождено. Когда файл больше не был открыт никому, он (копия в ядре) был бы заброшен. Это позволило бы сохранить путь действительным, если какой-либо другой процесс переместил каталог в другой каталог, в то время как подкаталог находился в пути другого процесса. Подобно тому, как вы можете удалить открытый файл, но он просто удаляется из каталога,

Жесткие ссылки на каталоги раньше свободно разрешались в Bell Labs UNIX, по крайней мере, V6 и V7. Не знаю о Беркли или более поздних версиях. Флаг не требуется. Не могли бы вы сделать петли? Да, не делай этого. Это очень ясно, что вы делаете, если вы делаете петлю. Если вы будете практиковать завязывание узлов вокруг шеи, пока вы ждете своей очереди, чтобы выпрыгнуть из самолета, если у вас другой конец удобно подвешен на крюке на насадке.

То, что я надеялся сделать с этим сегодня, это жестко связать lhome с home, чтобы я мог иметь доступ к / home / admin независимо от того, был ли / home скрыт с помощью автомаута над home, причем этот автомонтирование имеет символическую ссылку с именем admin на / lhome. / administ. Это позволяет мне иметь административную учетную запись, которая работает независимо от состояния моей основной домашней файловой системы. Это IS эксперимент для Linux, но я думаю , что узнал в свое время на основе UCB в SunOS , что automounts делаются на уровне строки ASCII. Трудно понять, как их можно было бы сделать иначе, как слой поверх любой произвольной ФС.

Я читал в другом месте, что. и .. больше не являются файлами в каталоге. Я уверен, что для всего этого есть веские причины, и многое из того, что нам нравится (например, возможность монтировать NTFS), возможно благодаря таким вещам, но некоторая элегантность UNIX была в реализации. Именно такие преимущества, как универсальность и гибкость, обеспеченные этой элегантностью, позволили ей быть настолько прочной и выдерживать в течение четырех десятилетий. По мере того, как мы теряем изящные реализации, в конечном итоге он становится похожим на Windows (надеюсь, я ошибаюсь!). Кто-то тогда создаст новую ОС, основанную на элегантных принципах. Что-то думать о. Возможно, я ошибаюсь, я (очевидно) не знаком с текущей реализацией. это является Удивительно, насколько 30-летнее понимание применимо к Linux ... большую часть времени!


Я думаю, хотя я могу ошибаться, .и ..это не жесткие ссылки в файловой системе для современных файловых систем. Однако драйвер файловой системы подделывает их. Именно эти файловые системы останавливают жесткие ссылки на каталоги. Для старых файловых систем это было возможно (но опасно). Чтобы сделать то, что вы пытаетесь, посмотрите mount --bind, посмотрите также mount --make…и, возможно, контейнеры.
Ctrl-Alt-Delor

0

Исходя из того, что я понял, основная причина заключается в том, что полезно иметь возможность изменять имена каталогов, не портя запущенные программы, которые используют свой рабочий каталог для ссылки на другие файлы. Предположим, вы использовали Wine для запуска ~/.newwineprefix/drive_c/Program Files/Firefox/Firefox.exeи ~/.wineвместо него хотите переместить весь префикс . Если по какой-то странной причине Firefox drive_c/windowsобращался к нему ../../windows, ссылаясь на него , переименование ~/.newwineprefixпрерывает реализации, ..которые отслеживают родительский каталог как текстовую строку вместо inode.

Хранить inode одного родительского каталога должно быть проще, чем пытаться отслеживать каждый путь как текстовую строку, так и серию inode.

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

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

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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.