86:
87: rc = 0;
88: i = 1;
89: flags = 0;
90: while (i < argc && *argv[i] != '-')
91: rc |= nftw (argv [i++], find, 100, flags);
92:
93: return rc;
94: }
14.8. Уведомление о смене каталога
Иногда приложения желают получать уведомления об изменении оглавления каталога. Например, диспетчеры файлов могут выводить оглавление каталога в окне и обновлять это окно каждый раз при изменении каталога другими программами. В то время как приложение регулярно перепроверяет каталог, Linux может послать программе сигнал о модификации каталога, позволяя своевременные обновления без накладных расходов и задержек на страничный обмен.
Системный вызов fcntl() используется для регистрации уведомлений об обновлениях каталога. В главе 11 уже говорилось о том, что этот системный вызов принимает три аргумента. Первый аргумент — это интересующий файловый дескриптор, второй — это команда, которую необходимо выполнить fcntl(), а последний — это целое число, специфическое для этой команды. Для уведомлений каталогов первый аргумент является файловым дескриптором, относящимся к интересующему каталогу. Это единственный случай, при котором каталог следует открывать с помощью нормального системного вызова open() вместо opendir(). Командой регистрации уведомлений является F_NOTIFY, а последний аргумент определяет, какие типы событий вызывают отправку сигнала. Это должен быть один или несколько перечисленных ниже флагов, объединенных по логическому 'ИЛИ'.
DN_ACCESS | Файл в каталоге, который читается. |
DN_ATTRIB | Права владения или доступа к файлу в каталоге были изменены. |
DN_CREATE | В каталоге создан новый файл (включая новые жесткие ссылки на уже существующие файлы). |
DN_DELETE | Файл удален из каталога. |
DN_MODIFY | Файл в каталоге был модифицирован (тип модификации — усечение). |
DN_RENAME | Файл в каталоге был переименован. |
Для отмены уведомления о событии вызовите fcntl() с командой F_NOTIFY и последним аргументом, равным нулю.
Обычно уведомление каталога автоматически отменяется после передачи одного сигнала. Для эффективного уведомления каталога окончательный аргумент для fcntl() должен быть объединен операцией 'ИЛИ' с DN_MULTISHOT, что вызывает отправку сигналов для всех подходящих событий до отмены уведомления.
По умолчанию для уведомления каталога передается SIGIO. Если приложение желает использовать для этого другой сигнал (например, для разных каталогов могут понадобиться разные сигналы), можно применить команду F_SETSIG в fcntl(), а в качестве последнего аргумента определить нужный сигнал. Если используется F_SETSIG (даже если установлен сигнал SIGIO), ядро также помещает файловый дескриптор на каталог в элементе si_fd аргумента обработчика сигналов siginfo_t[103], позволяя приложению узнать, какие из контролируемых каталогов обновились[104].
Если контролируется несколько каталогов и для всех каталогов выбран один сигнал, крайне необходимо использовать сигнал реального времени, чтобы убедиться, что ни одно из событий не затерялось.
Ниже приведена программа, использующая уведомление о смене каталога для вывода сообщений об удалении либо добавлении файлов в любые контролируемые ею каталоги (их количество указывается в командной строке). Она отказывается принять SIGRTMIN при смене каталога и использует si_fd, чтобы обнаружить, какой именно каталог был изменен. С целью предотвращения условий состязаний программа использует сигналы с очередизацией и блокирование сигналов. Сигнал может быть доставлен только один раз — при вызове sigsuspend() в строке 203. Это обеспечивает повторное сканирование каталога в случае внесения изменений в каталог во время его сканирования; иначе эти изменения останутся незамеченными. Использование сигналов с очередизацией разрешает любые изменения каталога во время работы программы; эти сигналы доставляется при каждом новом вызове sigsuspend(), гарантируя, что ничего не пропущено.
1: /* dirchange.с */
2:
3: #define _GNU_SOURCE
4: #include <dirent.h>
5: #include <errno.h>
6: #include <fcntl.h>
7: #include <signal.h>
8: #include <stdio.h>
9: #include <stdlib.h>
10: #include <string.h>
11: #include <unistd.h>
12:
13: /* Для сохранения имен файлов из каталога используется связный
14: список. Поле exists служит для хранения служебной информации
