Использование чтения с inotify

Я изучал вызов inotify, но я все еще немного шелушат, когда дело доходит до интерфейса чтения. Это наиболее релевантные ресурсы, которые я могу найти относительно правильного взаимодействия с inotify с помощью read (2):

Они оба реализуют его таким же образом, они сначала определяют следующие размеры:

#define EVENT_SIZE  ( sizeof (struct inotify_event) )
#define BUF_LEN     ( 1024 * ( EVENT_SIZE + 16 )

И затем они используют их таким образом:

length = read( fd, buffer, BUF_LEN );  

if ( length < 0 ) {
    perror( "read" );
}  

while ( i < length ) {
    struct inotify_event *event = ( struct inotify_event * ) &buffer[ i ];
    /* some processing */
    i += EVENT_SIZE + event->len;
}

Теперь мы знаем, что имя является частью struct inotify_event и что оно имеет переменную длину. Итак, не удалось ли усечь последний inotify_event в буфере?

Предположим, что есть 1023 inotify_events с контуром 16 байт и один с контуром 32 байта. Что будет тогда? Будет ли позднее усечено? Или ядро ​​увидит, что оно не будет вписываться в буфер и вообще оставить его?

Ответы

Ответ 1

Основное использование

В соответствии с inotify (7) вы можете использовать FIONREAD ioctl, чтобы узнать, сколько данных доступно для чтения и размер вашего буфера соответственно. Вот некоторый (очень грубый) код, который может выполнить это:

unsigned int avail;
ioctl(inotify_fd, FIONREAD, &avail);

char buffer[avail];
read(fd, buffer, avail);

int offset = 0;
while (offset < avail) {
    struct inotify_event *event = (inotify_event*)(buffer + offset);

    // Insert logic here
    my_process_inotify_event(event);

    offset = offset + sizeof(inotify_event) + event->len;
}

Более надежное использование

inotify-tools обеспечивает интерфейс более высокого уровня для inotify. Вы можете использовать его вместо доступа к inotify, или вы можете увидеть, как он реализует inotifytools_next_events безопасное и надежное чтение всех доступных событий.

Частичные события и усечение

В ответ на ваши вопросы об усечении я не думаю, что ядро ​​когда-либо вернет частичный inotify_event или усекает inotify_event, если указанный буфер слишком мал для всех событий. Следующий параграф из man-страницы inotify (7) предлагает следующее:

Поведение, когда буфер, указанный для чтения (2), слишком мал, чтобы возвращать информацию о следующем событии, зависит от версии ядра: в ядрах до 2.6.21 чтение (2) возвращает 0; поскольку ядро ​​2.6.21, чтение (2) не выполняется с ошибкой EINVAL.

Как и следующие комментарии inotifytools.c:

// oh... no.  this can't be happening.  An incomplete event.
// Copy what we currently have into first element, call self to
// read remainder.
// oh, and they BETTER NOT overlap.
// Boy I hope this code works.
// But I think this can never happen due to how inotify is written.