Ниже приведена программа, использующая уведомление о смене каталога для вывода сообщений об удалении либо добавлении файлов в любые контролируемые ею каталоги (их количество указывается в командной строке). Она отказывается принять SIGRTMIN
при смене каталога и использует si_fd
, чтобы обнаружить, какой именно каталог был изменен. С целью предотвращения условий состязаний программа использует сигналы с очередизацией и блокирование сигналов. Сигнал может быть доставлен только один раз — при вызове sigsuspend()
в строке 203. Это обеспечивает повторное сканирование каталога в случае внесения изменений в каталог во время его сканирования; иначе эти изменения останутся незамеченными. Использование сигналов с очередизацией разрешает любые изменения каталога во время работы программы; эти сигналы доставляется при каждом новом вызове sigsuspend()
, гарантируя, что ничего не пропущено.
1: /* dirchange.с */
2:
3: #define _GNU_SOURCE
4: #include
5: #include
6: #include
7: #include
8: #include
9: #include
10: #include
11: #include
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) {
38: DIR * dir;
39: struct dirent * ent;
40: struct fileInfo * list = NULL;
41:
42: if (!(dir = opendir(path))) {
43: perror("opendir");
44: return 1;
45: }
46:
47: while ((ent = readdir(dir))) {
48: if (!list) {
49: list = malloc(sizeof(*list));
50: list->next = NULL;
51: *listPtr = list;
52: } else {
53: list->next = malloc(sizeof(*list));
54: list = list->next;
55: }
56:
57: list->name = strdup(ent->d_name);
58: }
59:
60: if (errno) {
61: perror("readdir");
62: closedir(dir);
63: return 1;
64: }
65:
66: closedir(dir);
67:
68: return 0;
69: }
70:
71: /* Сканирует путь каталога в поисках изменений предыдущего
72: содержимого, как указано *listPtr. Связанный список
73: обновляется новым содержимым, и выводятся сообщения,
74: описывающие произошедшие изменения. */
75: int updateDirectoryList(char * path, struct fileInfo ** listPtr) {
76: DIR * dir;
77: struct dirent * ent;
78: struct fileInfo * list = *listPtr;
79: struct fileInfo * file, * prev;
80: