Ссылки и файлы

Чтобы лучше усвоить суть некоторых операций с файлами и каталогами, желательно понимать модель файлов и каталогов в системе UNIX, даже если вы работаете в другой системе, которая ведет себя несколько иначе. Как обычно, наше краткое изложение не дает полной картины; за подробностями обращайтесь к любой хорошей книге по внутреннему устройству UNIX. Смонтированный том представляет собой дисковое устройство (или нечто иное, что работает более или менее похожим образом, – раздел жесткого диска, флоппи-диск, CD-ROM или DVD-ROM). Том может содержать любое количество файлов и каталогов. Каждый файл хранится в пронумерованном индексном узле, который можно рассматривать как конкретный фрагмент дискового пространства.

Один файл может храниться в индексном узле 613, другой – в узле 7033 и т. д. Чтобы найти некоторый файл, необходимо провести поиск по каталогу. Каталог является особой разновидностью файла, находящейся под управлением системы. Фактически в каталоге хранится таблица с именами файлов и соответствующими им индексными узлами. Наряду с другими объектами каждый каталог всегда содержит две специальные записи. Одна из них (.) представляет сам каталог, а другая (..) – родительский каталог2, то есть каталог более высокого уровня в иерархии.


В одном из них хранится файл с именем chicken, а в другом – каталог /home/barney/ poems, содержащий этот файл. Файл хранится в индексном узле 613, а каталог – в индексном узле 919. (Имя самого каталога poems на рисунке не показано, потому что оно хранится в другом каталоге.) Каталог содержит записи трех файлов (включая chicken) и двух каталогов (один из которых содержит ссылку на сам каталог с индексным узлом 919); для каждой записи в каталоге хранится номер соответствующего индексного узла.

Когда наступает момент создания нового файла в каталоге, система добавляет запись с именем файла и номером нового индексного узла. Но как система определяет, свободен ли тот или иной индексный узел? В каждом индексном узле хранится число, называемое счетчиком ссылок. Счетчик ссылок всегда равен 0, если узел не присутствует ни в одном каталоге, поэтому любой индексный узел с нулевым счетчиком ссылок свободен для размещения нового файла. При добавлении индексного узла в каталог счетчик ссылок увеличивается, а при удалении сведений о нем уменьшается. Для файла chicken из предыдущего примера счетчик 1 показан над данными индексного узла. Но некоторые индексные узлы упоминаются в более чем одной записи каталогов.


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

Таким образом, счетчик ссылок каталога всегда содержит значение не менее 2: для его записи в родительском каталоге и записи в нем самом. Если каталог содержит подкаталоги, каждый из них тоже увеличивает счетчик ссылок, потому что каждый подкаталог содержит элемент. Счетчик ссылок определяет количество полноценных имен индексного узла. Могут ли ссылки на обычный файл присутствовать в нескольких записях каталогов? Конечно, могут. Допустим, в показанном выше каталоге функция Perl link используется для создания новой ссылки:

link "chicken", "egg"
or warn "can't link chicken to egg: $!";

Результат будет таким же, как если бы вы ввели "ln chicken egg" в приглашении командного процессора UNIX. Если вызов link завершится успешно, функция возвращает true. В случае неудачи функция возвращает false и устанавливает переменную $!, которая включается в сообщение об ошибке. После выполнения фрагмента имя egg становится вторым именем файла chicken, и наоборот; ни одно имя не является более «настоящим», чем другое, и чтобы узнать, какое из них появилось первым, придется основательно постараться.


Итак, эти два имени ссылаются на одну область диска. Если файл chicken содержит 200 байт данных, то egg содержит те же 200 байт (а их суммарный объем составляет 200 байт, потому что это всего лишь один файл с двумя именами). Если добавить новую строку текста в файл egg, эта строка появится в конце chicken. Если теперь пользователь случайно (или намеренно) удалит chicken, данные не потеряются – они все еще будут доступны под именем egg. И наоборот: после удаления egg у нас останется файл chicken. Конечно, при удалении обоих файлов данные пропадут. Также для ссылок в содержимом каталогов установлено еще одно правило: номера индексных узлов в каталоге всегда относятся к одному смонтированному тому.

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

Для ссылок устанавливается еще одно ограничение: они не могут использоваться для создания новых имен каталогов. Это объясняется тем, что каталоги объединены в иерархию. Если нарушить эту иерархию, служебные программы, вроде find или pwd, потеряются в своих блужданиях по файловой системе. Итак, ссылки не могут создаваться для каталогов и не могут вести с одного смонтированного тома на другой. К счастью, эти ограничения обходятся при помощи другой разновидности: символических ссылок. Символические ссылки (также называемые мягкими ссылками, в отличие от жестких ссылок, о которых мы говорили ранее) представляют собой специальные записи в каталоге, которые перенаправляют систему к другому месту. Допустим, пользователь создает в каталоге poems из предыдущего примера символическую ссылку; для этого он использует функцию Perl symlink:

symlink "dodgson", "carroll"
or warn "can't symlink dodgson to carroll: $!";

Происходит практически то же, что произошло бы при выполнении команды ln-s dodgson carroll в командном процессоре. Новое состояние файловой системы с файлом в индексном узле 7033. Если пользователь захочет прочитать файл /home/barney/poems/carroll, он получит те же данные, как если бы он открыл /home/ barney/poems/dodgson напрямую, потому что система автоматически переходит по символическим ссылкам. Однако новое имя не является «полноценным» именем файла, потому что (как видно из рисунка) счетчик ссылок для узла 7033 по-прежнему содержит 1. Символическая ссылка просто сообщает системе: «Если вы заглянули сюда в поисках carroll, теперь переходите к поискам dodgson». В отличие от жестких ссылок, символические ссылки могут свободно выходить за границы смонтированных файловых систем или определять новые имена для каталогов. Более того, символическая ссылка может указывать на любое имя в текущем или другом каталоге и даже на имя файла, который еще не существует! Но это также означает, что
мягкие ссылки (в отличие от жестких) не могут предотвратить потерю данных, потому что они не учитываются в значении счетчика ссылок.

Если пользователь удалит файл dodgson, система не сможет переходить по мягкой ссылке. Запись carroll останется в каталоге, но попытка прочитать данные из нее приведет к ошибке вида «файл не найден». Проверка –l 'carroll' вернет true, а проверка –e 'carroll' вернет false: это символическая ссылка, но она указывает на несуществующий файл. Так как мягкая ссылка может указывать на файл, который еще не существует, она также может использоваться при создании файла. Пользователь Барни хранит большинство своих файлов в домашнем каталоге /home/barney, но ему также приходится часто обращаться к каталогу с длинным именем, которое так неудобно вводить: /usr/local/opt/system/httpd/root-dev/users/staging/barney/cgi-bin. Он создает символическую ссылку /home/barney/my_stuff, которая указывает на длинное имя, и теперь попасть в нужный каталог становится совсем легко. Если Барни создаст (из своего домашнего каталога) файл my_stuff/bowling, то настоящим именем файла будет /usr/local/opt/system/httpd/root-dev/users/staging/barne /cgi-bin/bowling. На следующей неделе системный администратор перемещает все файлы в каталог /usr/local/opt/internal/httpd/www-dev/users/staging/barney/cgiQbin, но Барни достаточно перенастроить одну символическую ссылку, и все его программы по-прежнему будут легко находить свои файлы.

Во многих системах /usr/bin/perl или /usr/local/bin/perl (или оба имени) являются символическими ссылками на «настоящий» двоичный файл Perl в вашей системе. Это упрощает переход на новую версию Perl. Допустим, вы, будучи системным администратором, построили новую версию Perl. Конечно, старая версия все еще работает, и вы не хотите ничего портить. Когда все будет готово к переходу, достаточно переназначить одну-две символических ссылки; каждая программа, начинающаяся со строки #!/usr/bin/perl, будет автоматически использовать новую версию. Если с новой версией вдруг возникнут проблемы, восстановите старые ссылки, и старая версия Perl снова заработает, как положено. (Конечно, вы, как любой хороший администратор, заранее оповестили своих пользователей о необходимости тестирования кода с новой версией /usr/bin/perlQ7.2, а также о том, что во время «переходного периода» при необходимости они могут использовать старую версию, заменив первые строки в своих программах на #!/usr/bin/perl-6.1.)

Как ни странно, обе разновидности ссылок – и жесткие, и мягкие – чрезвычайно полезны. Во многих операционных системах, не входящих в семейство UNIX, ссылки вообще не поддерживаются, и их там весьма не хватает. В некоторых системах символические ссылки реализуются в виде «ярлыков» (shortcuts) или «псевдонимов» (aliases) – за дополнительной информацией обращайтесь к man-странице perlport. Чтобы узнать, на какой объект указывает символическая ссылка, воспользуйтесь функцией readlink. Функция вернет либо информацию о целевом объекте, либо undef, если аргумент не является символической ссылкой:

my $where = readlink "carroll"; # Получаем "dodgson"
my $perl = readlink "/usr/local/bin/perl"; # Вероятно, сообщит,
# где находится perl

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

Оцените статью: (0 голосов)
0 5 0

Статьи из раздела Perl на эту тему:
Альтернативный синтаксис глобов
Глобы
Дескрипторы каталогов
Изменение временных меток
Изменение разрешений

Вернуться в раздел: Perl / 12. Операции с каталогами