Рекурсивно отслеживать каталог для добавления/изменения/удаления файлов

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

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

Способ, который я могу найти с помощью поиска Google, — это отслеживать каждый файл по отдельности; однако у меня есть несколько сотен тысяч файлов для мониторинга, и держать дескриптор файла для каждого, вероятно, неразумно.

Есть ли способ во FreeBSD сделать то, что мне нужно? Или мне придется искать альтернативное решение?

#include <sys/types.h>
#include <sys/event.h>
#include <sys/time.h> 
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h> 

int main(void) {
   int f, kq, nev;
   struct kevent change;
   struct kevent event;

   kq = kqueue();
   if (kq == -1)
       perror("kqueue");

   f = open("/tmp/foo", O_RDONLY);
   if (f == -1)
       perror("open");

   EV_SET(&change, f, EVFILT_VNODE,
          EV_ADD | EV_ENABLE | EV_ONESHOT,
          NOTE_DELETE | NOTE_EXTEND | NOTE_WRITE | NOTE_ATTRIB,
          0, 0);

   for (;;) {
       nev = kevent(kq, &change, 1, &event, 1, NULL);
       if (nev == -1)
           perror("kevent");
       else if (nev > 0) {
           if (event.fflags & NOTE_DELETE) {
               printf("File deleted\n");
               break;
           }
           if (event.fflags & NOTE_EXTEND ||
               event.fflags & NOTE_WRITE)
               printf("File modified\n");
           if (event.fflags & NOTE_ATTRIB)
               printf("File attributes modified\n");
       }
   }

   close(kq);
   close(f);
   return EXIT_SUCCESS;
}

person OmnipotentEntity    schedule 17.12.2013    source источник


Ответы (1)


Как вы правильно догадались, kqueue не масштабируется, потому что вы должны держать дескриптор рассматриваемого файла/каталога, даже если в режиме O_RDONLY. В Linux для этой цели можно использовать inotify (http://linux.die.net/man/7/inotify), но я полагаю, что для FreeBSD не существует порта этой функции ядра!

Если у вас есть время и ресурсы, вы можете посмотреть код для audit в BSD (http://www.freebsd.org/cgi/man.cgi?query=audit&sektion=4) и попробуйте написать версию inotify для BSD! О_О

person vijucat    schedule 24.12.2013
comment
Я не думаю, что это было бы проще с inotify. Inotify также не является рекурсивным, вам все равно придется отслеживать каждый файл индивидуально. Тем не менее, структура аудита является хорошим предложением. Возможно, здесь даже пригодится dtrace. - person Kristof Provost; 24.12.2013
comment
Знаете ли вы, если использование audit потребует открытия fd для каждого отслеживаемого файла. Также в @KristofProvost я не знал, что это не рекурсивно, если требуется рекурсивное решение, это круто. Основная проблема заключается в хранении всех этих файловых дескрипторов. - person OmnipotentEntity; 25.12.2013
comment
Также с Рождеством. :D - person OmnipotentEntity; 25.12.2013
comment
С Рождеством тоже! (Но тогда вы Всемогущая Сущность, так что, может быть, я должен сказать: Спасибо за Рождество!? :-)). - person vijucat; 25.12.2013
comment
Я на 90% уверен, что механизм аудита не требует открытия fds, потому что он в основном работает внутри ядра (в основном) и регистрирует системные вызовы. Например, если кто-то вызывает chmod() для файла, за которым вы следите, код ядра chmod() сам выполняет регистрацию. Я полагаю, что настоящие вопросы сейчас таковы: а) насколько это ресурсоемко? и б) насколько просто настроить рекурсивный мониторинг каталогов? Дайте мне знать, если вы хотите, чтобы я выкопал/помочь. - person vijucat; 25.12.2013
comment
Просто большое спасибо за наводку. Я посмотрю на это. Если я разработаю что-нибудь хорошее, я закину это на github или что-то в этом роде. - person OmnipotentEntity; 26.12.2013