77 /* Вышеприведенное обрабатывает --help и --version.
78 Поскольку других вызовов getopt нет, обработать здесь '--'. */
79 if (1 < argc && STREQ(argv[1], "--"))
80 {
81 --argc;
82 ++argv;
83 }
84
85 if (argc < 3)
86 {
87 error(0, 0, _("too few arguments"));
88 usage(EXIT_FAILURE);
89 }
90
91 if (3 < argc)
92 {
93 error(0, 0, _("too many arguments"));
94 usage(EXIT_FAILURE);
95 }
96
97 if (link(argv[1], argv[2]) != 0)
98 error(EXIT_FAILURE, errno, _("cannot create link %s to %s"),
99 quote_n(0, argv[2]), quote_n(1, argv[1]));
100
101 exit(EXIT_SUCCESS);
102 }
Строки 67–75 являются типичным шаблоном Coreutils, устанавливающими интернациональные настройки, выход по завершении и анализ аргументов. Строки 79–95 гарантируют, что
link
вызывается лишь с двумя аргументами. Сам системный вызов
link
осуществляется в строке 97 (Функция
quote_n
обеспечивает отображение аргументов в стиле, подходящем для текущей локали; подробности сейчас несущественны.)
5.1.3.2. Точка и точка-точка
Завершая обсуждение ссылок, давайте взглянем на то, как обрабатываются специальные имена '
.
' и '
..
'. На самом деле они просто являются прямыми ссылками. В первом случае '
.
' является прямой ссылкой на каталог, содержащий ее, а '
..
' — прямой ссылкой на родительский каталог. Операционная система создает для вас эти ссылки; как упоминалось ранее, код уровня пользователя не может создать прямую ссылку на каталог. Этот пример иллюстрирует ссылки:
$ pwd /* Отобразить текущий
каталог */
/tmp
$ ls -ldi /tmp /* Показать номер его индекса */
225345 drwxrwxrwt 14 root root 4096 May 4 16:15 /tmp
$ mkdir x /* Создать новый каталог */
$ ls -ldi x /* И показать номер его индекса */
52794 drwxr-xr-x 2 arnold devel 4096 May 4 16:27 x
$ ls -ldi x/. x/.. /* Показать номера индексов . И .. */
52794 drwxr-xr-x 2 arnold devel 4096 May 4 16:27 x/.
225345 drwxrwxrwt 15 root root 4096 May 4 16:27 x/..
Родительский каталог корневого каталога (
/..
) является особым случаем; мы отложим его обсуждение до главы 8 «Файловые системы и обход каталогов».
5.1.4. Переименование файлов
При данном способе отображения элементами каталога имен на номера индексов, переименование файла концептуально очень просто:
1. Если новое имя файла обозначает существующий файл, сначала удалить этот файл.
2. Создать новую ссылку на файл через новое имя.
3. Удалить старое имя (ссылку) для файла. (Удаление имен обсуждается в следующем разделе.)
Ранние версии команды mv работали таким способом. Однако, при таком способе переименование файла не является атомарным; т.е. оно не осуществляется посредством одной непрерываемой операции. И на сильно загруженной системе злонамеренный пользователь мог бы воспользоваться условиями состояния гонки [51] , разрушая операцию переименования и подменяя оригинальный файл другим.
51
Состояние .гонки (race condition) является ситуацией, при которой детали временных соотношений могут вызывать непреднамеренные побочные эффекты или ошибки. В данном случае, каталог в течение короткого периода времени находится в противоречивом состоянии, и именно эта противоречивость и создаёт уязвимость — Примеч. автора.
По этой причине 4.2 BSD ввело системный вызов
rename
:
#include <stdio.h> /* ISO С */
int rename(const char *oldpath, const char *newpath);
На системах Linux операция переименования является атомарной; справочная страница утверждает:
Если
newpath
уже существует, он будет атомарно замещен
..,
таким образом, что при попытке другого процесса получить доступ к
newpath
он никогда не обнаружит его отсутствующим.
Если
newpath
существует, но по какой-либо причине операция завершается неудачей,
rename
гарантирует, что экземпляр
newpath
останется на месте. Однако, в ходе переписывания возможно будет окно, в котором как
oldpath
, так и
newpath
ссылаются на переименовываемый файл.
Как и в случае с другими системными вызовами, возвращенный 0 означает успех, а (-1) означает ошибку.
5.1.5. Удаление файла
Удаление файла означает удаление элемента каталога для файла и уменьшение счетчика ссылок на файл, который содержится в индексе. Содержимое файла и дисковые блоки, в котором оно размешается, не освобождаются до тех пор, пока счетчик ссылок не достигнет нуля.