используется для регистрации уведомлений об обновлениях каталога. В главе 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
), ядро также помещает файловый дескриптор на каталог в элементе
Это то же, что и метод, используемый для владения файлами (глава 13).
104
Обработчик сигналов все еще следует регистрировать с помощью флага
SA_SIGINFO
, чтобы файловый дескриптор надлежащим образом получил доступ к сигналу.
Если контролируется несколько каталогов и для всех каталогов выбран один сигнал, крайне необходимо использовать сигнал реального времени, чтобы убедиться, что ни одно из событий не затерялось.
Ниже приведена программа, использующая уведомление о смене каталога для вывода сообщений об удалении либо добавлении файлов в любые контролируемые ею каталоги (их количество указывается в командной строке). Она отказывается принять
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 служит для хранения служебной информации
15: при проверке изменений. */
16: struct fileInfo {
17: char * name;
18: struct fileInfo * next;
19: int exists;
20: };
21:
22: /* Это глобальный массив. Он отображает файловые дескрипторы на пути
23: каталогов, сохраняет список файлов в каталоге и предоставляет
24: обработчику сигналов место для отображения того факта, что каталог
25: должен сканироваться повторно. Последний элемент имеет path,
26: равный NULL, обозначающий конец массива. */
27:
28: struct directoryInfo {
29: char * path;
30: int fd;
31: int changed;
32: struct fileInfo * contents;
33: } * directoryList;
34:
35: /* Это никогда не возвращает пустой список; любой каталог содержит,
36: по крайней мере, "." и ".." */
37: int buildDirectoryList(char * path, struct fileInfo ** listPtr) {