首先,转载一段关于inotify的介绍:
它是一个内核用于通知用户空间程序文件系统变化的机制。
众所周知,Linux 桌面系统与 MAC 或 Windows相比有许多不如人意的地方,为了改善这种状况,开源社区提出用户态需要内核提供一些机制,以便用户态能够及时地得知内核或底层硬件设备发生了什么,从而能够更好地管理设备,给用户提供更好的服务,如hotplug、udev 和 inotify 就是这种需求催生的。Hotplug是一种内核向用户态应用通报关于热插拔设备一些事件发生的机制,桌面系统能够利用它对设备进行有效的管理,udev 动态地维护 /dev下的设备文件,inotify 是一种文件系统的变化通知机制,如文件增加、删除等事件可以立刻让用户态得知,该机制是著名的桌面搜索引擎项目beagle 引入的,并在 Gamin 等项目中被应用。
按我的理解,inotify本身是linux内核向系统或用户提供的一个API,即发生文件变更请求时,除了处理这个任务本身,还向某个接口播报一个事件,如果我们设置了接收这个目录内的事件(inotify_add_watch (fd, path, mask)),就能够从相应的事件socket中取得相应信息。
inotify库中定义了这几个函数:
inotify_init ();
inotify_add_watch (fd, path, mask);
inotify_rm_watch (fd, wd);
其中,inotify_init ()用于初始化一个实例;
inotify_add_watch (fd, path, mask)将一个目录(path)加入监控,fd为初始化好的inotify实例,mask为监控的事件;
inotify_rm_watch (fd, wd)将一个监控的对象移出监控,wd为已添入监控的对象;
以下为根据inotify库开发的记录文件变更的小工具,它在inotify_add_watch添加单个目录的基础上,加入了递归遍历子文件夹,并将它们全部纳入监控,通过设置一个静态全局结构来对每个纳入监控的目录进行标记,从而能够识别到发生事件的位置并将其记录下来。另外,它还附带了更新机制,即当监控到文件创建事件时,会判断其是否为文件夹,若是的话会将其同样纳入监控。
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <sys/inotify.h>
#include <sys/stat.h>
#include <time.h>
#include <unistd.h>
#include <dirent.h>
#include <malloc.h>
#define EVENT_NUM 12
#define IS_FILE 8
#define IS_DIR 4
#define DATA_W 200
static struct dir_path{
int id;
char **path;
}dir;
char *event_str[EVENT_NUM] =
{
"IN_ACCESS",
"IN_MODIFY", //文件修改
"IN_ATTRIB",
"IN_CLOSE_WRITE",
"IN_CLOSE_NOWRITE",
"IN_OPEN",
"IN_MOVED_FROM", //文件移动from
"IN_MOVED_TO", //文件移动to
"IN_CREATE", //文件创建
"IN_DELETE", //文件删除
"IN_DELETE_SELF",
"IN_MOVE_SELF"
};
//=======================================================================
int id_add(char *path_id){
//free(dir.path[dir.id]);
dir.path[dir.id]=(char *)malloc(DATA_W);
strncpy(dir.path[dir.id],path_id,DATA_W);
printf("%d:%s\n",dir.id,dir.path[dir.id]);
dir.id=dir.id+1;
return 0;
}
//=======================================================================
char *gettime()
{
static char timestr[40];
time_t t;
struct tm *nowtime;
time(&t);
nowtime = localtime(&t);
strftime(timestr,sizeof(timestr),"%Y-%m-%d %H:%M:%S",nowtime);
return timestr;
}
//=======================================================================
int inotify_watch_dir(char *dir_path,int fd)
{
int wd;
int len;
DIR *dp;
char pdir_home[DATA_W];
char pdir[DATA_W];
strcpy(pdir_home,dir_path);
struct dirent *dirp;
struct inotify_event *event;
if (fd < 0)
{
fprintf(stderr, "inotify_init failed\n");
return -1;
}
wd = inotify_add_watch(fd, dir_path, IN_CREATE|IN_ATTRIB|IN_DELETE|IN_MOVED_FROM|IN_MOVED_TO);
if ((dp = opendir(dir_path)) == NULL)
{
return -1;
}
while ((dirp = readdir(dp)) != NULL)
{
if(strcmp(dirp->d_name,".") == 0 || strcmp(dirp->d_name,"..") == 0)
{
continue;
}
if (dirp->d_type == IS_FILE)
{
continue;
}
if (dirp->d_type == IS_DIR)
{
strncpy(pdir,pdir_home,DATA_W);
strncat(pdir,"/",1);
strncat(pdir,dirp->d_name,BUFSIZ);
id_add(pdir);
inotify_watch_dir(pdir, fd);
}
}
closedir(dp);
}
//====================================================================
int main(int argc,char *argv[])
{
dir.id=1;
dir.path=(char **)malloc(65534);
if(argc < 2)
{
fprintf(stderr, "USISZ-TE Hao_zeng\nusage:%s [path]\n", argv[0]);
return -1;
}
id_add(argv[1]);
int fd=inotify_init();
inotify_watch_dir(argv[1],fd);
int i;
int len;
int nread;
struct stat res;
char path[BUFSIZ];
char buf[BUFSIZ];
struct inotify_event *event;
char log_dir[DATA_W]={};
getcwd(log_dir,DATA_W);
strncat(log_dir,"/inotify.log",12);
//printf("log path: %s\n",log_dir);
buf[sizeof(buf) - 1] = 0;
while( (len = read(fd, buf, sizeof(buf) - 1)) > 0 )
{
nread = 0;
while(len> 0)
{
event = (struct inotify_event *)&buf[nread];
for(i=0; i<EVENT_NUM; i++)
{
if((event->mask >> i) & 1)
{
if(event->len > 0)
if(strncmp(event->name,".",1))
{
FILE *fp=NULL;
fp=fopen(log_dir,"a");
fprintf(fp,"%s: %s/%s --- %s\n",gettime(),dir.path[event->wd],event->name,event_str[i]);
fprintf(stdout,"%s: %s/%s --- %s\n",gettime(),dir.path[event->wd],event->name,event_str[i]);
if((!strcmp(event_str[i],"IN_CREATE"))|(!strcmp(event_str[i],"IN_MOVED_TO"))){
memset(path,0,sizeof path);
strncat(path,dir.path[event->wd],BUFSIZ);
strncat(path,"/",1);
strncat(path,event->name,BUFSIZ);
stat(path ,&res);
if (S_ISDIR(res.st_mode))
{
inotify_add_watch(fd, path, IN_CREATE|IN_ATTRIB|IN_DELETE|IN_MOVED_FROM|IN_MOVED_TO);
id_add(path);
}
}
fclose(fp);
}
}
}
nread = nread + sizeof(struct inotify_event) + event->len;
len = len - sizeof(struct inotify_event) - event->len;
}
}
return 0;
}