Skip to main content
 首页 » 编程设计

c之读取 inotify 文件描述符会用二进制垃圾填充缓冲区

2026年05月17日19jpfss

我正在尝试 inotify,下面的代码片段是我认为可以很好地演示其功能的代码:

#include <sys/inotify.h>  /* inotify_init(), inotify_add_watch(), IN_* */ 
#include <stdlib.h>       /* EXIT_SUCCESS, EXIT_FAILURE, malloc() */ 
#include <stdio.h>        /* printf(), puts(), perror() */ 
#include <unistd.h>       /* read() */ 
#include <sys/ioctl.h>    /* ioctl, FIONREAD */ 
#define PTRY(expr)  if((expr) == -1) 
#define PGOTO(label, msg) do{\ 
    perror(msg);\ 
    goto label;\ 
  } while(0) 
 
 
int main(void) { 
 
  int fd; 
  PTRY(fd = inotify_init())                       PGOTO(failure, "inotify_init"); 
  PTRY(inotify_add_watch(fd, ".", IN_ALL_EVENTS)) PGOTO(failure, "inotify_add_watch"); 
 
  while(1) { 
 
    unsigned int avail;                           /* We find out how large a buffer we need */ 
    PTRY(ioctl(fd, FIONREAD, &avail))             PGOTO(failure, "ioctl"); 
 
    char buffer[avail]; 
    ssize_t count = read(fd, buffer, avail);      /* We fill the buffer */ 
    if(avail > 0 && count < avail)                PGOTO(failure, "read"); 
 
    printf("Avail: %d, Read: %d\n", (int)avail, (int)count); 
    if(avail > 0) puts(""); 
 
    for(ssize_t i = 0; i < count; ) {             /* For each event structure in the buffer */ 
 
      struct inotify_event* event = (struct inotify_event*)buffer + i; 
      printf("Byte: %d - %d out of %d\n", (int)i, (int)(sizeof(struct inotify_event) + event->len), (int)count); 
 
      if(event->len > 0) {                        /* We print its contents */ 
        printf("Name: %s\n",   event->name); 
      } printf("Cookie: %d\n", event->cookie); 
 
      if(event->mask & IN_ACCESS)         puts("IN_ACCESS"); 
      if(event->mask & IN_ATTRIB)         puts("IN_ATTRIB"); 
      if(event->mask & IN_CLOSE_WRITE)    puts("IN_CLOSE_WRITE"); 
      if(event->mask & IN_CLOSE_NOWRITE)  puts("IN_CLOSE_NOWRITE"); 
      if(event->mask & IN_CREATE)         puts("IN_CREATE"); 
      if(event->mask & IN_DELETE)         puts("IN_DELETE"); 
      if(event->mask & IN_DELETE_SELF)    puts("IN_DELETE_SELF"); 
      if(event->mask & IN_MODIFY)         puts("IN_MODIFY"); 
      if(event->mask & IN_MOVE_SELF)      puts("IN_MOVE_SELF"); 
      if(event->mask & IN_MOVED_FROM)     puts("IN_MOVED_FROM"); 
      if(event->mask & IN_MOVED_TO)       puts("IN_MOVED_TO"); 
      if(event->mask & IN_OPEN)           puts("IN_OPEN"); 
      puts(""); 
 
      i += sizeof(struct inotify_event) + event->len; 
 
    } 
 
  } 
 
  return EXIT_SUCCESS; 
 
  failure: 
    return EXIT_FAILURE; 
 
} 

但是,我从 read(2) 调用中收到了一些无关的记录,其中充满了二进制垃圾。附件是从 shell 调用 cat notifyTest.c 时程序的输出:

Avail: 0, Read: -1 
Avail: 64, Read: 64 
 
Byte: 0 - 32 out of 64 
Name: notifyTest.c 
Cookie: 0 
IN_OPEN 
 
Byte: 32 - 32783 out of 64 
Name: ▒▒▒ 
Cookie: 1726459283 
IN_ACCESS 
IN_ATTRIB 
IN_CLOSE_WRITE 
IN_CLOSE_NOWRITE 
IN_CREATE 
IN_DELETE 
IN_DELETE_SELF 
IN_MODIFY 
IN_MOVE_SELF 
IN_MOVED_FROM 
IN_MOVED_TO 
IN_OPEN 
 
Avail: 0, Read: -1 
Avail: 32, Read: 32 
 
Byte: 0 - 32 out of 32 
Name: notifyTest.c 
Cookie: 0 
IN_CLOSE_NOWRITE 

这可能会破坏代码,因为如果没有任何终止 ,进程将收到 SIGSEGV 信号并在读取 event->name 时被杀死\0' 静态分配缓冲区范围内的字符。

这可能是一个怪癖,还是我只是做错了什么?我的 uname -a 是:

Linux witiko-D830 3.8.0-32-generic #47-Ubuntu SMP Tue Oct 1 22:35:23 UTC 2013 x86_64 x86_64 x86_64 GNU/Linux 

对于可能出错的任何指示,我将不胜感激。

请您参考如下方法:

你的问题在这一行:

 struct inotify_event* event = (struct inotify_event*)buffer + i; 

该行将指针 buffer 转换为类型 struct inotify_event*,然后添加 i,这是在您的第二次迭代中, 是 32。然后将值增加 32 * sizeof(struct inotify_event)

修复方法是:

 struct inotify_event* event = (struct inotify_event*)(buffer + i);