http://blog.csdn.net/tommy_wxie/article/details/45149921
1.inotify机制简介:
inotify是Linux内核提供的一个文件系统变化通知机制,从2.6.13版本的内核开始提供,比如你在创建一个文件时它可以通知你哪个文件被创建了,删除文件时通知你哪个文件被删除了,修改文件时通知你哪个文件被修改了,关闭文件时哪个文件被关闭了,是可写关闭还是不可写关闭等等。这个机制在某些特定用途下是很必要的,比如桌面搜索引擎,一般当我们不记得某一文件放在哪个地方时,我们可以直接通过这个桌面搜索引擎来搜索该文件以得到其位置,在Linux下的beagle搜索引擎就是用inotify实现的;还有就是用在文件同步方面和文件的增量备份方面,当本地的文件被修改保存后可以即时的将该文件同步到远程服务器上去。
在2.6.13版本的内核之前文件系统变化通知机制用的是dnotify,当然为了兼容以前的版本,现在的内核也还提供dnotify,inotify与dnotify相比具有很多优势,比如inotify资源占用少,特别是表现在文件描述符这块,inotify通过系统调用实现,而dnotify通过信号等等,具体优势感兴趣的可以自己去查查资料;在2.6.36内核版本后又提供了另一个文件系统变化通知机制fanotify用以替代inotify,fanotify机制相对于inotify又有其自己的优势,比如通过适当设置fanotify可以阻断你对文件进行的操作,而inotify只通知不阻断,fanotify可以对指定目录下的所有文件的某些变化进行通知,而inotify只能对指定目录下的两级目录内的文件系统变化进行通知,即只能对指定目录下的文件或者子目录的变化进行通知,而对子目录下的文件和目录的变化探测不到,但当前fanotify能进行通知的事件较少,感觉还不完善,有兴趣的可以自己去查查相关资料。
2.inotify机制能通知的事件:
以下代码摘自include/linux/inotify.h
/* the following are legal, implemented events that user-space can watch for */
#define IN_ACCESS 0x00000001 /* File was accessed */
#define IN_MODIFY 0x00000002 /* File was modified */
#define IN_ATTRIB 0x00000004 /* Metadata changed */
#define IN_CLOSE_WRITE 0x00000008 /* Writtable file was closed */
#define IN_CLOSE_NOWRITE 0x00000010 /* Unwrittable file closed */
#define IN_OPEN 0x00000020 /* File was opened */
#define IN_MOVED_FROM 0x00000040 /* File was moved from X */
#define IN_MOVED_TO 0x00000080 /* File was moved to Y */
#define IN_CREATE 0x00000100 /* Subfile was created */
#define IN_DELETE 0x00000200 /* Subfile was deleted */
#define IN_DELETE_SELF 0x00000400 /* Self was deleted */
#define IN_MOVE_SELF 0x00000800 /* Self was moved */
/* the following are legal events. they are sent as needed to any watch */
#define IN_UNMOUNT 0x00002000 /* Backing fs was unmounted */
#define IN_Q_OVERFLOW 0x00004000 /* Event queued overflowed */
#define IN_IGNORED 0x00008000 /* File was ignored */
/* helper events */
#define IN_CLOSE (IN_CLOSE_WRITE | IN_CLOSE_NOWRITE) /* close */
#define IN_MOVE (IN_MOVED_FROM | IN_MOVED_TO) /* moves */
/* special flags */
#define IN_ONLYDIR 0x01000000 /* only watch the path if it is a directory */
#define IN_DONT_FOLLOW 0x02000000 /* don't follow a sym link */
#define IN_MASK_ADD 0x20000000 /* add to the mask of an already existing watch */
#define IN_ISDIR 0x40000000 /* event occurred against dir */
#define IN_ONESHOT 0x80000000 /* only send event once */
/*
* All of the events - we build the list by hand so that we can add flags in
* the future and not break backward compatibility. Apps will get only the
* events that they originally wanted. Be sure to add new events here!
*/
#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)
以上所定义的常量在下面用于下面介绍的mask设置或mask值判断
3.inotify机制用户态接口函数:
3.1:inotify_init():创建一个inotify实例,返回值为一个文件描述符,具体可查看man手册。
3.2:inotify_init1(...):在2.6.27版本中出现,功能更细致,用于替代inotify_init(),具体可查看man手册。
3.3:inotify_add_watch(...):用于在inotify_init...返回的文件描述符上添加一个监控实例,具体可查看man手册。
3.4:inotufy_rm_watch(...):用于移除指定的监控实例,具体可查看man手册。
3.5:read(...):用于读取发生的事件,具体可参看man手册。
4.inotify机制事件数据结构解析:
通过read读取到的每一个事件,其结构体定义如下:
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 */};
此处说明一下字段len和name[0],当我们在一个监控目录下新建一个文件file1时,会得到len=6(5+1,5代表file1长度,1代表字符串结束字符null),name指针中指向的就是file1这个字符串,该字符串紧接在读取到的event事件后,并且以null结尾。
5.一下是我写的一个使用inotify机制的简短程序:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/inotify.h>
struct wd_path
{
int wd;
char *path;
};
char * event_array[] = {
"File was accessed",
"File was modified",
"File attributes were changed",
"writtable file closed",
"Unwrittable file closed",
"File was opened",
"File was moved from X",
"File was moved to Y",
"Subfile was created",
"Subfile was deleted",
"Self was deleted",
"Self was moved",
"",
"Backing fs was unmounted",
"Event queued overflowed",
"File was ignored"
};
#define EVENT_NUM 16
int main(int argc,char *argv[])
{
int fd,wd,len,tmp_len,i;
char buffer[1024],*offset,target[1024];
struct wd_path *wd_array;
struct inotify_event *event;
wd_array=(struct wd_path*)malloc((argc-1)*sizeof(struct wd_path));
fd=inotify_init();
if(-1==fd)
{
printf("failed to init inotifyn");
return 0;
}
for(i=0;i<argc-1;i++)
{
wd_array[i].path=argv[i+1];
wd=inotify_add_watch(fd,wd_array[i].path,IN_ALL_EVENTS);
wd_array[i].wd=wd;
}
memset(buffer,0,1024);
while(len=read(fd,buffer,1024))
{
offset=buffer;
event=(struct inotify_event*)buffer;
while(((char *)event-buffer)<len)
{
for(i=0;i<argc-1;i++)
{
if(event->wd==wd_array[i].wd)
{
memset(target,0,1024);
strcpy(target,wd_array[i].path);
strcat(target,"/");
strcat(target,event->name);
printf("nnntarget:%s:n",target);
}
}
for(i=0;i<EVENT_NUM;i++)
{
if(event->mask&(1<<i))
printf(" event:%sn",event_array[i]);
}
tmp_len=sizeof(struct inotify_event)+event->len;
event=(struct inotify_event*)(offset+tmp_len);
offset+=tmp_len;
}
}
return 1;
}