Проблема с обнаружением перемещения файлов с помощью inotify.

Я хотел использовать inotify для мониторинга содержимого каталога. Кажется, все в порядке, пока я не попытаюсь переименовать файл в каталоге с помощью команды mv. Я получаю IN_MOVED_FROM, как и ожидалось, но IN_MOVED_TO не приходит.

Ниже моя тестовая программа. Скомпилировать с:

g++ -Wall -o test test.cpp

Запустить с помощью:

./test dir_to_watch
#include <cstdio>
#include <cstring>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/inotify.h>

int main (int argc, char *argv[])
{
  int inotify_fd = inotify_init();

  if (inotify_fd < 0)
  {
    fprintf(stderr, "Unable to init inotify: %m\n");
    return 1;
  }

  int watch_descriptor = inotify_add_watch(inotify_fd,
                       argv[1],
                       IN_ALL_EVENTS);

  if (watch_descriptor < 0)
  {
    fprintf(stderr, "Unable to add inotify watch: %m\n");
    return 1;
  }

  union
  {
    inotify_event event;
    char pad[1024];
  }
  buffer;

  struct events
  {
    int mask;
    const char *name;
  }
  events[] =
  {
    {IN_ACCESS         , "IN_ACCESS        "}, 
    {IN_ATTRIB         , "IN_ATTRIB        "}, 
    {IN_CLOSE_WRITE    , "IN_CLOSE_WRITE   "}, 
    {IN_CLOSE_NOWRITE  , "IN_CLOSE_NOWRITE "}, 
    {IN_CREATE         , "IN_CREATE        "}, 
    {IN_DELETE         , "IN_DELETE        "}, 
    {IN_DELETE_SELF    , "IN_DELETE_SELF   "}, 
    {IN_MODIFY         , "IN_MODIFY        "}, 
    {IN_MOVE_SELF      , "IN_MOVE_SELF     "}, 
    {IN_MOVED_FROM     , "IN_MOVED_FROM    "}, 
    {IN_MOVED_TO       , "IN_MOVED_TO      "}, 
    {IN_OPEN           , "IN_OPEN          "}, 
  };

  while (read(inotify_fd, &buffer, sizeof buffer) > 0)
  {
    for (unsigned i = 0; i < sizeof events / sizeof events[0]; i++)
    {
      if (events[i].mask & buffer.event.mask)
      {
    if (buffer.event.len)
    {
      printf("Inotify %s: %s\n", events[i].name, buffer.event.name);
    }
    else
    {
      printf("Inotify %s\n", events[i].name);
    }
      }
    }
  }
}

person kyku    schedule 02.06.2011    source источник


Ответы (1)


Самостоятельное решение: оказывается, что inotify может возвращать несколько событий в одном вызове read(). Итак, исправленный исходный код выглядит так:

#include <cstdio>
#include <cstring>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/inotify.h>

int main (int argc, char *argv[])
{
  int inotify_fd = inotify_init();

  if (inotify_fd < 0)
  {
    fprintf(stderr, "Unable to init inotify: %m\n");
    return 1;
  }

  int watch_descriptor = inotify_add_watch(inotify_fd,
                       argv[1],
                       IN_ALL_EVENTS);

  if (watch_descriptor < 0)
  {
    fprintf(stderr, "Unable to add inotify watch: %m\n");
    return 1;
  }

  struct events
  {
    int mask;
    const char *name;
  }
  events[] =
  {
    {IN_ACCESS         , "IN_ACCESS        "}, 
    {IN_ATTRIB         , "IN_ATTRIB        "}, 
    {IN_CLOSE_WRITE    , "IN_CLOSE_WRITE   "}, 
    {IN_CLOSE_NOWRITE  , "IN_CLOSE_NOWRITE "}, 
    {IN_CREATE         , "IN_CREATE        "}, 
    {IN_DELETE         , "IN_DELETE        "}, 
    {IN_DELETE_SELF    , "IN_DELETE_SELF   "}, 
    {IN_MODIFY         , "IN_MODIFY        "}, 
    {IN_MOVE_SELF      , "IN_MOVE_SELF     "}, 
    {IN_MOVED_FROM     , "IN_MOVED_FROM    "}, 
    {IN_MOVED_TO       , "IN_MOVED_TO      "}, 
    {IN_OPEN           , "IN_OPEN          "}, 
  };

  ssize_t rd;
  char buffer[1024];

  while ((rd = read(inotify_fd, buffer, sizeof buffer)) > 0)
  {
    for (char *ptr = buffer; ptr != buffer + rd; ptr += sizeof(inotify_event) + reinterpret_cast<inotify_event*>(ptr)->len)
    {
      inotify_event *event = reinterpret_cast<inotify_event*>(ptr);

      for (unsigned i = 0; i < sizeof events / sizeof events[0]; i++)
      {
    if (events[i].mask & event->mask)
    {
      if (event->len)
      {
        printf("Inotify %d %s: %s\n", inotify_fd, events[i].name, event->name);
      }
      else
      {
        printf("Inotify %d %s\n", inotify_fd, events[i].name);
      }
    }
      }
    }
  }

  if (rd < 0)
  {
    fprintf(stderr, "inotify read %d event error: %m\n", inotify_fd);
    return 1;
  }
}
person kyku    schedule 02.06.2011