Большинство считает, что в unix длина полного пути к файлу ограничена некоторым количеством символов - 1024 в большинстве реализаций, включая ограничительный NUL (то есть 1023 содержательных символа). Все выглядит хорошо: более длинные пути не принимаются, пути короче этого предела работают всегда нормально. Правду же - что реальная длина пути практически неограниченна и ее предел определяется размерами файловой системы - знают достаточно немногие.
bash не даст вам провести следующий простой эксперимент. Стандартный sh из FreeBSD - даст. Делаем:
while :; do mkdir $N; cd $N; echo $N; N=`expr $N+1`; done
Я дошел до 979. Встроенный pwd этого шелла дал ответ, длина которого равна 3817 - он следил за перемещениями и записал их всех. (bash тоже мог следить, но он глупее в этом вопросе - путь больше стандартных 1024 символов его сводит с ума, и работа цикла останавливается.) /bin/pwd не смог определить путь в этом случае, выдав невразумительную диагностику - getcwd() отказал, а /bin/pwd сам не справится. rm -rf на верхний каталог этого безобразия (версия rm из FreeBSD 4.5-release) сумел удалить каталог; в 3.x версии и раньше - не умел. Даже find из той же версии FreeBSD разобрался правильно: `find 1 -print -delete -depth' стерло все безобразие за один заход, правильно показав пути. Это связано с тем, что длина буфера подсистемы fts сейчас равна 64K; тем не менее, она все равно ограничена, и более длинные пути могут привести к отказу find, rm и прочих утилит, использующих fts.
Если у вас нет шелла, который не сойдет с ума оказавшись в слишком глубоком каталоге, можно программу написать на Си - она создаст каталог произвольной глубины, а разбираться с этим придется уже извне.;))
Далее. Делаем маленькую программку:
#include <sys/types.h> #include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <err.h> int main() { int i; for( i = 1; i <= 2048; i++ ) { char s[100]; snprintf( s, sizeof s, "d-%d", i ); if( mkdir( s, 0755 ) < 0 ) err( 1, "mkdir()" ); if( chdir( s ) < 0 ) err( 1, "chdir()" ); } system( "/usr/local/bin/bash" ); return 0; }
Запускаем. Находились в /usr/tmp. Что говорит bash?
14:22:14:netch@iv:/usr/tmp>./s1 shell-init: could not get current directory: getcwd: cannot access parent directories: Result too large 14:22:21:netch@iv:/usr/tmp>
Первый prompt баша - до запуска программы, второй - уже из того баша, который запущен из s1. Не сумев получить текущий путь, он воспользовался значением переменной PWD из окружения. Это можно подтвердить тестом:
14:23:41:netch@iv:/usr/tmp>PWD=/var ./s1 shell-init: could not get current directory: getcwd: cannot access parent directories: Result too large 14:23:53:netch@iv:/var>/bin/pwd pwd: .: No such file or directory 14:23:59:netch@iv:/var>pwd pwd: could not get current directory: getcwd: cannot access parent directories: Result too large 14:24:00:netch@iv:/var>
То есть, bash продолжает сходить с ума. /bin/pwd - тоже.
Меняем bash на sh...
14:24:42:netch@iv:/usr/tmp>./s1 sh: cannot determine working directory $ pwd pwd: getcwd() failed: Result too large $
Этот хоть не стал показывать фиктивный путь - за что ему большое спасибо.
Везде в тестах bash был версии 2.05a - самой последней.
Оба варианта создания "сверхглубокого" каталога - на шелле и на Си - показывают принцип создания: на каждой итерации используется короткий отрезок пути, который сам короче чем предельная длина в 1023 содержательных символа, и все пути относительны - отсчитываются от текущего каталога. Без использования текущего каталога (которому ядро совершенно не мешает быть сколь угодно глубоко) ничего бы не получилось.
(C) 2002 Valentin Nechayev. All rights reserved.
Допускается свободное распространение данного текста в некоммерческих целях
без изменения содержимого и реквизитов.
$Id: ulpaths.html,v 1.3 2002/11/16 12:15:28 netch Exp $