Рекурсия символьной ссылки - что заставляет его “сбросить”?

Это стандартно для печати символа замены Unicode вместо символа, который не существует в текущем шрифте.

Возможная фиксация должна просто изменить стандартный шрифт любой Вашей ОС (если браузер наследовал настройки OS), или браузер. Например, мой Firefox 11.0 на Ubuntu 11.10 использует шрифт "засечки" (который мог бы быть синонимом для FreeSerif), который, кажется, поддерживает много символов Unicode.

PS: изображения, кажется, исчезли.

64
16.06.2013, 09:24
2 ответа

Patrice определил источник проблемы в его ответе, но если Вы хотите знать, как добраться оттуда до того, почему Вы получаете это, вот длинная история.

Текущий рабочий каталог процесса - ничто, что Вы думали бы слишком сложные. Это - атрибут процесса, который является дескриптором в файл каталога типа, где относительные пути (в системных вызовах, сделанных процессом), начинают с. При разрешении относительного пути ядро не должно знать (a) полный путь к тому текущему каталогу, это просто читает записи каталога в том файле каталога для нахождения первого компонента относительного пути (и .. похож на любой другой файл в том отношении), и продолжается оттуда.

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

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

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

Это что getwd() или getcwd() C функции делают или по крайней мере используемый, чтобы сделать.

В некоторых системах как современный Linux существует системный вызов для возврата канонического пути к текущему каталогу, который делает тот поиск в пространстве ядра (и позволяет Вам находить свой текущий каталог, даже если у Вас нет доступа для чтения ко всем его компонентам), и это что getcwd() вызовы там. На современном Linux можно также найти путь к текущему каталогу через readlink () на /proc/self/cwd.

Это - то, что большинство языков и ранних оболочек делают при возврате пути к текущему каталогу.

В Вашем случае можно звонить cd a как может времена, как Вы хотите, потому что это - символьная ссылка на ., текущий каталог не изменяет так весь из getcwd(), pwd -P, python -c 'import os; print os.getcwd()', perl -MPOSIX -le 'print getcwd' возвратил бы Ваш ${HOME}.

Теперь, символьные ссылки пошли, усложнив все это.

symlinks позвольте переходы в дереве каталогов. В /a/b/c, если /a или /a/b или /a/b/c символьная ссылка, затем канонический путь /a/b/c было бы что-то совершенно другое. В частности, .. запись в /a/b/c не обязательно /a/b.

В Оболочке Bourne, если Вы делаете:

cd /a/b/c
cd ..

Или даже:

cd /a/b/c/..

Нет никакой гарантии, в которой Вы закончите /a/b.

Точно так же, как:

vi /a/b/c/../d

не обязательно то же как:

vi /a/b/d

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

Для cd и pwd встроенные команды (и только для них (хотя также для popd/pushd на оболочках, которые имеют их)), оболочка поддерживает свою собственную идею текущего рабочего каталога. Это хранится в $PWD специальная переменная.

Когда Вы делаете:

cd c/d

даже если c или c/d символьные ссылки, в то время как $PWD содержит /a/b, это добавляет c/d в конец так $PWD становится /a/b/c/d. И когда Вы делаете:

cd ../e

Вместо выполнения chdir("../e"), это делает chdir("/a/b/c/e").

И pwd управляйте только возвращает содержание $PWD переменная.

Это полезно в интерактивных оболочках потому что pwd производит путь к текущему каталогу, который дает информацию о том, как Вы добрались там и, пока Вы только используете .. в аргументах cd и не другие команды, это, менее вероятно, удивит Вас, потому что cd a; cd .. или cd a/.. обычно возвращал бы Вас туда, где Вы были.

Теперь, $PWD не изменяется, если Вы не делаете a cd. До следующего раза Вы звоните cd или pwd, много вещей могло произойти, любой из компонентов $PWD мог быть переименован. Текущий каталог никогда не изменяется (это всегда - тот же inode, хотя это могло быть удалено), но его путь в дереве каталогов мог измениться полностью. getcwd() вычисляет текущий каталог каждый раз, когда это называют путем спуска с дерева каталогов, таким образом, его информация является всегда достоверной, но для логического каталога, реализованного оболочками POSIX, информацией в $PWD мог бы стать устаревшим. Таким образом после выполнения cd или pwd, некоторые оболочки могут хотеть принять меры против этого.

В том конкретном экземпляре Вы видите различные поведения с различными оболочками.

Некоторым нравится ksh93 проигнорируйте проблему полностью, так возвратит неправильную информацию даже после вызова cd (и Вы не видели бы поведения, с которым Вы видите bash там).

Некоторым нравится bash или zsh действительно проверьте это $PWD все еще путь к текущему каталогу на cd, но не на pwd.

pdksh действительно проверяет на обоих pwd и cd (но на pwd, не обновляет $PWD)

ash (по крайней мере, тот, найденный на Debian), не проверяет, и когда Вы делаете cd a, это на самом деле делает cd "$PWD/a", таким образом, если текущий каталог изменился и $PWD больше точки к текущему каталогу, это на самом деле не изменится на a каталог в текущем каталоге, но тот в $PWD (и возвратите ошибку, если она не существует).

Если Вы хотите играть с ним, можно сделать:

cd
mkdir -p a/b
cd a
pwd
mv ~/a ~/b 
pwd
echo "$PWD"
cd b
pwd; echo "$PWD"; pwd -P # (and notice the bug in ksh93)

в различных оболочках.

В Вашем случае, так как Вы используете bash, после a cd a, bash проверки это $PWD неподвижные точки к текущему каталогу. Чтобы сделать это, это звонит stat() на значении $PWD проверить его inode число и сравнить его с числом ..

Но когда поиск $PWD путь включает разрешение слишком многих символьных ссылок, этого stat() возвраты с ошибкой, таким образом, оболочка не может проверить ли $PWD все еще соответствует текущему каталогу, таким образом, он вычисляет его снова с getcwd() и обновления $PWD соответственно.

Теперь, для разъяснения ответа Patrice та проверка количества символьных ссылок, с которыми встречаются при поиске пути, должна принять меры против циклов символьной ссылки. Самый простой цикл может быть сделан с

rm -f a b
ln -s a b
ln -s b a

Без той безопасности, на a cd a/x, система должна была бы найти где a ссылки на, находит, что это b и символьная ссылка, которая связывается с a, и это продолжилось бы неограниченно долго. Самый простой способ принять меры, который должен сдаться после разрешения больше, чем произвольное число символьных ссылок.

Теперь назад к логическому текущему рабочему каталогу и почему это не настолько хорошая функция. Важно понять, что это только для cd в оболочке и не других командах.

Например:

cd -- "$dir" &&  vi -- "$file"

не всегда то же как:

vi -- "$dir/$file"

Вот почему Вы будете иногда находить, что люди рекомендуют всегда использовать cd -P в сценариях для предотвращения беспорядка (Вы не хотите, чтобы Ваше программное обеспечение обработало аргумент ../x по-другому по сравнению с другими командами просто, потому что это записано в оболочке вместо другого языка).

-P опция состоит в том, чтобы отключить логический каталог, обрабатывающий так cd -P -- "$var" на самом деле звонит chdir() на содержании $var (кроме тех случаев, когда $var - но это - другая история). И после a cd -P, $PWD будет содержать канонический путь.

90
27.01.2020, 19:32
  • 1
    Милый Jesus! Спасибо за такой всесторонний ответ это - действительно довольно интересный :) –  Lucas 16.06.2013, 23:27
  • 2
    Потрясающий ответ, большое спасибо! Я чувствую, что отчасти знал все эти вещи, но я никогда не понимал или думал о том, как они все объединились. Большое объяснение. огромное спасибо –  dimo414 27.02.2017, 02:32

Это - результат трудно кодированного предела в источнике ядра Linux; для предотвращения отказа в обслуживании предел на количество вложенных символьных ссылок равняется 40 (найденный в follow_link() функция внутри fs/namei.c, названный nested_symlink() в источнике ядра).

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

42
27.01.2020, 19:32
  • 1
    Есть ли причина его, чтобы "сбросить", вместо того, чтобы просто остановиться. т.е. x%40 вместо max(x,40). Я предполагаю, что можно все еще видеть изменение каталога. –  Lucas 16.06.2013, 10:24
  • 2
    ссылка на источник, для кого-либо еще любопытного: lxr.linux.no/linux+v3.9.6/fs/namei.c#L818 –  Ben 16.06.2013, 19:10

Теги

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