2011-06-02 43 views
2

我想用inotify來監視目錄的內容。一切似乎都很好,直到我嘗試使用mv命令重命名目錄中的文件。按預期得到IN_MOVED_FROM,但IN_MOVED_TO未到。使用inotify檢測文件移動的問題。

以下是我的測試程序。與編譯:

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); 
    } 
     } 
    } 
    } 
} 

回答

7

自我解決:事實證明,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; 
    } 
}