用户接口
一 inotify工作原理
别人是这样总结的。inotify是linux系统2.6.13以后内核支持的一种特性,功能是监视文件系统的变化,在监听到文件系统变化后会向相应的应用程序发送事件。典型应用场景比如文件管理器,理想情况下应该在用户使用其他手段修改了文件夹的内容后马上反映出最新的内容,而不应该在用户手动刷新后才显示最新内容。如果没有类似inotify的机制,一般会采用轮询的方式实现这种功能,不能在第一时间反映文件系统变化而且浪费CPU时间。inotify用到的数据结构位于和函数声明位置为include/linux/inotify.h和include/sys/inotify.h,函数在notify_inotify.c文件中。
二 主要数据结构
1 inotify_event
struct inotify_event {
__s32 wd; /* watch descriptor */
__u32 mask; /* watch mask */
__u32 cookie; /* cookie to synchronize two events */
__u32 len; /* length (including nulls) of name */
char name[0]; /* stub for possible name */
};
结构中的wd为被监视目标的watch描述符,mask为事件掩码,len为name字符串的长度,name为被监视目标的路径名,该结构的name字段为一个桩,它只是为了用户方面引用文件名,文件名是变长的,它实际紧跟在该结构的后面,文件名将被0填充以使下一个事件结构能够4字节对齐。注意,len也把填充字节数统计在内。
通过read调用可以一次获得多个事件,只要提供的buf足够大。
通过read调用可以一次获得多个事件,只要提供的buf足够大。
size_t len = read (fd, buf, BUF_LEN);
buf是一个inotify_event结构的数组指针,BUF_LEN指定要读取的总长度,buf大小至少要不小于BUF_LEN,该调用返回的事件数取决于BUF_LEN以及事件中文件名的长度。len为实际读去的字节数,即获得的事件的总长度。
可以在函数inotify_init()返回的文件描述符fd上使用select()或poll(), 也可以在fd上使用ioctl命令FIONREAD来得到当前队列的长度。close(fd)将删除所有添加到fd中的watch并做必要的清理。
可以在函数inotify_init()返回的文件描述符fd上使用select()或poll(), 也可以在fd上使用ioctl命令FIONREAD来得到当前队列的长度。close(fd)将删除所有添加到fd中的watch并做必要的清理。
2 一堆宏
这些宏表示mask为事件掩码。
//适用于 inotify_add_watch mask 与 read 返回的inotify_event中mask:
#define IN_ACCESS 0x00000001 //文件被访问
#define IN_MODIFY 0x00000002 //文件被 write
#define IN_ATTRIB 0x00000004 //文件属性被修改,如 chmod、chown、touch 等
#define IN_CLOSE_WRITE 0x00000008 //可写文件被 close
#define IN_CLOSE_NOWRITE 0x00000010 //不可写文件被 close
#define IN_OPEN 0x00000020 //文件被 open
#define IN_MOVED_FROM 0x00000040 //文件被移走,如 mv
#define IN_MOVED_TO 0x00000080/ /文件被移来,如 mv、cp
#define IN_CREATE 0x00000100 //创建新文件
#define IN_DELETE 0x00000200 //文件被删除,如 rm
#define IN_DELETE_SELF 0x00000400 //自删除,即一个可执行文件在执行时删除自己
#define IN_MOVE_SELF 0x00000800 //自移动,即一个可执行文件在执行时移动自己
#define IN_CLOSE (IN_CLOSE_WRITE | IN_CLOSE_NOWRITE) //文件被关闭,等同于(IN_CLOSE_WRITE | IN_CLOSE_NOWRITE)
#define IN_MOVE (IN_MOVED_FROM | IN_MOVED_TO) //文件被移动,等同于(IN_MOVED_FROM | IN_MOVED_TO)
#define IN_ONLYDIR 0x01000000 //只监测目录
#define IN_DONT_FOLLOW 0x02000000 //不跟随符号链接
#define IN_MASK_ADD 0x20000000 //添加mask到被监测的pathname
#define IN_ONESHOT 0x80000000 //只发送一次事件
//仅由read返回:
#define IN_UNMOUNT 0x00002000 //宿主文件系统被 umount
#define IN_Q_OVERFLOW 0x00004000 //事件队列溢出
#define IN_IGNORED 0x00008000 //文件被忽略,inotify_rm_watch,文件被删除或者文件系统被umount
#define IN_ISDIR 0x40000000 //发生事件的是一个目录
#define IN_ALL_EVENTS (IN_ACCESS | IN_MODIFY | IN_ATTRIB | IN_CLOSE_WRITE | IN_CLOSE_NOWRITE | IN_OPEN | IN_MOVED_FROM | IN_MOVED_TO | IN_DELETE | IN_CREATE | IN_DELETE_SELF | IN_MOVE_SELF)
三 主要函数
1 int inotify_init(void);
创建一个inotify实例,每一个 inotify 实例对应一个独立的排序的队列,返回一个文件描述符fd。
2 int inotify_add_watch(int, const char *, __u32);
加入文件或目录到inotify进行监测,就是添加一个watch。
文件系统的变化事件被称做 watches 的一个对象管理,每一个 watch 是一个二元组(目标,事件掩码),目标可以是文件或目录,事件掩码表示应用希望关注的 inotify 事件,每一个位对应一个 inotify 事件。watch 对象通过 watch描述符引用,watches 通过文件或目录的路径名来添加。目录 watches 将返回在该目录下的所有文件上面发生的事件。
fd 是 inotify_init() 返回的文件描述符,path 是被监视的目标的路径名(即文件名或目录名),mask 是事件掩码, 在头文件 linux/inotify.h 中定义了每一位代表的事件。可以使用同样的方式来修改事件掩码,即改变希望被通知的inotify 事件。返回的是一个 watch 描述符wd。
文件系统的变化事件被称做 watches 的一个对象管理,每一个 watch 是一个二元组(目标,事件掩码),目标可以是文件或目录,事件掩码表示应用希望关注的 inotify 事件,每一个位对应一个 inotify 事件。watch 对象通过 watch描述符引用,watches 通过文件或目录的路径名来添加。目录 watches 将返回在该目录下的所有文件上面发生的事件。
fd 是 inotify_init() 返回的文件描述符,path 是被监视的目标的路径名(即文件名或目录名),mask 是事件掩码, 在头文件 linux/inotify.h 中定义了每一位代表的事件。可以使用同样的方式来修改事件掩码,即改变希望被通知的inotify 事件。返回的是一个 watch 描述符wd。
3 int inotify_rm_watch(int, __u32);
移除一个watch。fd 是 inotify_init() 返回的文件描述符,wd 是 inotify_add_watch() 返回的 watch 描述符。
毫无悬念,这些东东,都要通过系统调用,陷入内核。
毫无悬念,这些东东,都要通过系统调用,陷入内核。
static int inotify_init(void)
{
return syscall(__NR_inotify_init);
}
static int inotify_add_watch(int fd, const char *path, __u32 mask)
{
return syscall(__NR_inotify_add_watch, fd, path, mask);
}
static int inotify_rm_watch(int fd, int wd)
{
return syscall(__NR_inotify_rm_watch, fd, wd);
}
int syscall(int number, ...);