Если контролируется несколько каталогов и для всех каталогов выбран один сигнал, крайне необходимо использовать сигнал реального времени, чтобы убедиться, что ни одно из событий не затерялось.
Ниже приведена программа, использующая уведомление о смене каталога для вывода сообщений об удалении либо добавлении файлов в любые контролируемые ею каталоги (их количество указывается в командной строке). Она отказывается принять 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:
81: if (!(dir = opendir(path))) {
82: perror("opendir");
83: return 1;
84: }
85:
86: for (file = list; file; file = file->next)
87: file->exists = 0;
88:
89: while ((ent = readdir(dir))) {
90: file = list;
91: while (file && strcmp(file->name, ent->d_name))
92: file = file->next;
93:
94: if (!file) {
95: /* новый файл, добавить его имя в список */
96: printf("%s создан в %s\n", ent->d_name, path);
97: file = malloc(sizeof(*file));
98: file->name = strdup(ent->d_name);
99: file->next = list;
100: file->exists = 1;
101: list = file;
102: } else {
103: file->exists = 1;
104: }
105: }
106:
107: closedir(dir);
108:
109: file = list;
110: prev = NULL;
111: while (file) {
112: if (!file->exists) {
113: printf("%s удален из %s\n", file->name, path);
114: free(file->name);
115:
116: if (!prev) {
117: /* удалить головной узел */
118: list = file->next;
119: free(file);
120: file = list;
121: } else {
122: prev->next = file->next;
Читать дальше