Идеи реализации

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

В основе такого алгоритма будет лежать процедура, принимающая имя как параметр и обрабатывающая это имя. Процедура выведет его, если имя принадлежит существующему обычному файлу. Если имя относится к директории, то для такого случая предусмотрен особый план действий. В цикле по очереди обрабатываются все элементы директории (файлы и непосредственные поддиректории): Имя директории соединяется с именем содержащегося в ней элемента через разделитель / имён файлов и отдаётся на обработку этой самой рекурсивной процедуре. Наконец, особый случай: имя не относится к существующему объекту, тогда процедура ворчит и завершает работу.

В этом словесном описании алгоритма имеются некоторые пробелы. Самая главная неприятность нас ждёт при обработке имени директории. Даже пустые директории не совсем пустые: в них, как минимум, содержатся два объекта: . и ... Первый из них, напомним, является альтернативным именем самой директории, второй — синоним директории, расположенной «этажом выше» в файловой иерархии. Наличие этих объектов (в первую очередь второго) обеспечивает связность файловой системы: каждая директория «знает», в какой директории она содержится. Лишь в корневой директории оба объекта — . и .. — указывают на неё саму (это не позволит подняться в иерархии выше корня).

Теперь представим себе, как поведёт себя наша рекурсивная процедура, получив как параметр имя директории, скажем, /etc. Поскольку получено имя директории, в цикле обрабатываются все находящиеся в ней объекты. Список этих объектов начинается, естественно, с директории .. Поэтому дальше следует рекурсивный вызов для имени /etc/.. Что же будет обнаружено там? Конечно же, опять .. Последует рекурсивный вызов для /etc/./., затем для /etc/././., затем для /etc/./././., и так далее. В какой-то момент Perl пожалуется на глубокую рекурсию, а спустя некоторое время уйдёт в себя. До обработки /etc/.. дело даже не дойдёт, но если бы дошло, нас ждал бы не меньший удар. Такого нельзя допустить, поэтому директории . и .. должны обрабатываться особым образом.

Подобную проблему могут создать символические ссылки на директории. Что должна делать программа, обнаружив такую ссылку? Вывести только имя ссылки или также и содержимое той директории, на которую указывает ссылка? Во втором случае возможна ситуация, когда, к примеру, символическая ссылка указывает на корень файловой системы, и тогда мы получаем ту же проблему, что и с директорией .. Заметим, что следование по символическим ссылкам не позволяет, вообще говоря, считать структуру директории древовидной. Так что при обнаружении символической ссылки будем поступать с ней как с обычным файлом.

Есть ещё одна маленькая трудность. При обработке имени корневой директории / каждое выведенное имя будет начинаться с // (имя директории плюс разделитель). Этот особый случай нуждается в особом подходе.

Информатика-54© А. Н. Швец