Issue with detecting file moves using inotify.
I wanted to use inotify to monitor contents of a directory. Everything seems fine until I try to rename a file in the directory using mv command. I get IN_MOVED_FROM as expected but IN_MOVED_TO doesn't come.
Below is my test program. Compile with:
g++ -Wall -o test test.cpp
Launch with:
./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 开发者_JAVA百科 , "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);
}
}
}
}
}
Self solved: it turns out that inotify can return multiple events in a single read() call. So the corrected source code looks like this:
#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;
}
}
精彩评论