Чтение онлайн

ЖАНРЫ

Разработка приложений в среде Linux. Второе издание

Троан Эрик В.

Шрифт:

Если контролируется несколько каталогов и для всех каталогов выбран один сигнал, крайне необходимо использовать сигнал реального времени, чтобы убедиться, что ни одно из событий не затерялось.

Ниже приведена программа, использующая уведомление о смене каталога для вывода сообщений об удалении либо добавлении файлов в любые контролируемые ею каталоги (их количество указывается в командной строке). Она отказывается принять

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) {

 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;

Поделиться с друзьями: