Linux 文件操作监控inotify功能及实现原理【转】
转自:http://blog.chinaunix.net/uid-26585427-id-5012973.html
1. inotify主要功能
它是一个内核用于通知用户空间程序文件系统变化的机制。
众所周知,Linux 桌面系统与 MAC 或 Windows 相比有许多不如人意的地方,为了改善这种状况,开源社区提出用户态需要内核提供一些机制,以便用户态能够及时地得知内核或底层硬件设备发生了什么,从而能够更好地管理设备,给用户提供更好的服务,如 hotplug、udev 和 inotify 就是这种需求催生的。Hotplug 是一种内核向用户态应用通报关于热插拔设备一些事件发生的机制,桌面系统能够利用它对设备进行有效的管理,udev 动态地维护 /dev 下的设备文件,inotify 是一种文件系统的变化通知机制,如文件增加、删除等事件可以立刻让用户态得知,该机制是著名的桌面搜索引擎项目 beagle 引入的,并在 Gamin 等项目中被应用。
缺点只能单独监控一个目录或文件,不能监控目录下的所有子目录,想要监控子目录必须得自己通过递归的方法将所有目录都添加到监控中去
2. 用户接口
在用户态,inotify 通过三个系统调用和在返回的文件描述符上的文件 I/ 操作来使用,使用 inotify 的第一步是创建 inotify 实例:
int fd = inotify_init (); |
每一个 inotify 实例对应一个独立的排序的队列。
文件系统的变化事件被称做 watches 的一个对象管理,每一个
watch 是一个二元组(目标,事件掩码),目标可以是文件或目录,事件掩码表示应用希望关注的 inotify 事件,每一个位对应一个
inotify 事件。Watch 对象通过 watch描述符引用,watches 通过文件或目录的路径名来添加。目录 watches
将返回在该目录下的所有文件上面发生的事件。
下面函数用于添加一个 watch:
int wd = inotify_add_watch (fd, path, mask); |
fd 是 inotify_init() 返回的文件描述符,path 是被监视的目标的路径名(即文件名或目录名),mask 是事件掩码, 在头文件 linux/inotify.h 中定义了每一位代表的事件。可以使用同样的方式来修改事件掩码,即改变希望被通知的inotify 事件。Wd 是 watch 描述符。
下面的函数用于删除一个 watch:
int ret = inotify_rm_watch (fd, wd); |
fd 是 inotify_init() 返回的文件描述符,wd 是 inotify_add_watch() 返回的 watch 描述符。Ret 是函数的返回值。
文件事件用一个 inotify_event 结构表示,它通过由 inotify_init() 返回的文件描述符使用通常文件读取函数 read 来获得
:
struct inotify_event { |
结构中的 wd 为被监视目标的 watch 描述符,mask 为事件掩码,len 为 name字符串的长度,name
为被监视目标的路径名,该结构的 name 字段为一个桩,它只是为了用户方面引用文件名,文件名是变长的,它实际紧跟在该结构的后面,文件名将被 0
填充以使下一个事件结构能够 4 字节对齐。注意,len 也把填充字节数统计在内。
通过 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 并做必要的清理。
int inotify_init (void); |
3. 内核实现原理
在内核中,每一个 inotify 实例对应一个 inotify_device 结构:
struct inotify_device { |
d_list 指向所有 inotify_device
组成的列表的,i_list 指向所有被监视 inode 组成的列表,count 是引用计数,dev 指向该 watch 所在的 inotify
实例对应的 inotify_device 结构,inode 指向该 watch 要监视的 inode,wd 是分配给该 watch
的描述符,mask 是该 watch 的事件掩码,表示它对哪些文件系统事件感兴趣。
结构 inotify_device 在用户态调用
inotify_init() 时创建,当关闭 inotify_init()返回的文件描述符时将被释放。结构 inotify_watch
在用户态调用 inotify_add_watch()时创建,在用户态调用 inotify_rm_watch() 或 close(fd)
时被释放。
无论是目录还是文件,在内核中都对应一个 inode 结构,inotify 系统在 inode 结构中增加了两个字段:
struct inotify_watch { |
d_list 指向所有 inotify_device
组成的列表的,i_list 指向所有被监视 inode 组成的列表,count 是引用计数,dev 指向该 watch 所在的 inotify
实例对应的 inotify_device 结构,inode 指向该 watch 要监视的 inode,wd 是分配给该 watch
的描述符,mask 是该 watch 的事件掩码,表示它对哪些文件系统事件感兴趣。
结构 inotify_device 在用户态调用
inotify_init() 时创建,当关闭 inotify_init()返回的文件描述符时将被释放。结构 inotify_watch
在用户态调用 inotify_add_watch()时创建,在用户态调用 inotify_rm_watch() 或 close(fd)
时被释放。
无论是目录还是文件,在内核中都对应一个 inode 结构,inotify 系统在 inode 结构中增加了两个字段:
#ifdef CONFIG_INOTIFY |
inotify_watches 是在被监视目标上的 watch
列表,每当用户调用 inotify_add_watch()时,内核就为添加的 watch 创建一个 inotify_watch
结构,并把它插入到被监视目标对应的 inode 的 inotify_watches 列表。inotify_sem 用于同步对
inotify_watches 列表的访问。当文件系统发生第一部分提到的事件之一时,相应的文件系统代码将显示调用fsnotify_*
来把相应的事件报告给 inotify 系统,其中*号就是相应的事件名,目前实现包括:
fsnotify_move,文件从一个目录移动到另一个目录fsnotify_nameremove,文件从目录中删除fsnotify_inoderemove,自删除fsnotify_create,创建新文件fsnotify_mkdir,创建新目录fsnotify_access,文件被读fsnotify_modify,文件被写fsnotify_open,文件被打开fsnotify_close,文件被关闭fsnotify_xattr,文件的扩展属性被修改fsnotify_change,文件被修改或原数据被修改有一个例外情况,就是
inotify_unmount_inodes,它会在文件系统被 umount 时调用来通知 umount 事件给 inotify 系统。
以上提到的通知函数最后都调用
inotify_inode_queue_event(inotify_unmount_inodes直接调用
inotify_dev_queue_event ),该函数首先判断对应的inode是否被监视,这通过查看 inotify_watches
列表是否为空来实现,如果发现 inode 没有被监视,什么也不做,立刻返回,反之,遍历 inotify_watches
列表,看是否当前的文件操作事件被某个 watch 监视,如果是,调用
inotify_dev_queue_event,否则,返回。函数inotify_dev_queue_event
首先判断该事件是否是上一个事件的重复,如果是就丢弃该事件并返回,否则,它判断是否 inotify 实例即 inotify_device
的事件队列是否溢出,如果溢出,产生一个溢出事件,否则产生一个当前的文件操作事件,这些事件通过kernel_event
构建,kernel_event 将创建一个 inotify_kernel_event 结构,然后把该结构插入到对应的
inotify_device 的 events 事件列表,然后唤醒等待在inotify_device 结构中的 wq
指向的等待队列。想监视文件系统事件的用户态进程在inotify 实例(即 inotify_init() 返回的文件描述符)上调用 read
时但没有事件时就挂在等待队列 wq 上。
4. 使用示例
下面是一个使用 inotify 来监视文件系统事件的例子:
#include
#include
#include _syscall0(int, inotify_init)
_syscall3(int, inotify_add_watch, int, fd, const char *, path, __u32, mask)
_syscall2(int, inotify_rm_watch, int, fd, __u32, mask) char * monitored_files[] = {
"./tmp_file",
"./tmp_dir",
"/mnt/sda3/windows_file"
}; struct wd_name {
int wd;
char * name;
}; #define WD_NUM 3
struct wd_name wd_array[WD_NUM]; 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
#define MAX_BUF_SIZE 1024 int main(void)
{
int fd;
int wd;
char buffer[1024];
char * offset = NULL;
struct inotify_event * event;
int len, tmp_len;
char strbuf[16];
int i = 0; fd = inotify_init();
if (fd < 0) {
printf("Fail to initialize inotify.\n");
exit(-1);
} for (i=0; imask & IN_ISDIR) {
memcpy(strbuf, "Direcotory", 11);
}
else {
memcpy(strbuf, "File", 5);
}
printf("Object type: %s\n", strbuf);
for (i=0; iwd != wd_array[i].wd) continue;
printf("Object name: %s\n", wd_array[i].name);
break;
}
printf("Event mask: %08X\n", event->mask);
for (i=0; imask & (1<len;
event = (struct inotify_event *)(offset + tmp_len);
offset += tmp_len;
}
}
}
Linux 文件操作监控inotify功能及实现原理【转】的更多相关文章
- 针对Linux 文件完整性监控的实现
针对Linux 文件完整性监控的实现 摘要 计算机和互联网是20世纪以来最伟大的发明之一,随着计算机技术的不断发展,人们的生活方式发生了巨大的变化.计算机和互联网的发展给人们的生产生活带来了极大的便利 ...
- C/C++以及Linux文件操作备忘录
目录 C文件操作 文件开关 文件读写 C++文件操作 Linux文件操作 打开 C文件操作 #include<stdio.h> stdin, stdout, stderr 文件开关 /* ...
- Linux 文件操作接口
目录 Linux 文件操作接口 C语言文件操作接口 C语言文件描述 fopen() r模式打开文件 w模式打开文件 a模式打开文件 其他模式类似 fclose() fwrite() fread() 系 ...
- Windows与Linux下文件操作监控的实现
一.需求分析: 随着渲染业务的不断进行,数据传输渐渐成为影响业务时间最大的因素.究其原因就是因为数据传输耗费较长的时间.于是,依托于渲染业务的网盘开发逐渐成为迫切需要解决的需求.该网盘的实现和当前市场 ...
- Linux inotify功能及实现原理
http://www.cnblogs.com/jiejnan/archive/2012/05/18/2507476.html 简介: 当需要对 Linux®文件系统进行高效率.细粒度.异步地监控时,可 ...
- 文件读写监控(inotify, systemtap)
一.inotify inotify是内核的一个特性,可以用来监控目录.文件的读写等事件,当监控目标是目录时,inotify除了会监控目录本身,还会监控目录中的文件.inotify的监控功能由 ...
- Linux inotify功能及实现原理【转】
转自:http://blog.csdn.net/myarrow/article/details/7096460 1. inotify主要功能 它是一个内核用于通知用户空间程序文件系统变化的机制. 众所 ...
- Linux文件操作的主要接口API及相关细节
操作系统API: 1.API是一些函数,这些函数是由linux系统提供支持的,由应用层程序来使用,应用层程序通过调用API来调用操作系统中的各种功能,来干活 文件操作的一般步骤: 1.在linux系统 ...
- Linux 文件操作总结
http://blog.163.com/he_junwei/blog/static/19793764620152592737741/ ioctl?? lseek?? 文件是linux中的一个重要概念. ...
随机推荐
- C++的简单“五子棋”游戏,只是核心代码,资源代码未添加
ChessBoard.h #ifndef __CHESS_BOARD_H__ #define __CHESS_BOARD_H__ #include "DataStruct.h" # ...
- 【iCore3应用开发平台】发布 iCore3 应用开发平台PID控制代码
说明:1.本代码包包含FPGA和STM32F407两部分内容2.FPGA工程为出厂代码FPGA工程,版本为REV43.STM32F407为只含PID控制的ARM工程4.在使用风扇过程中,请勿将手伸入扇 ...
- git常使用命令整理
1.git撤销本地所有修改(tracked和untracked) . git clean -df . git reset --hard 第一个命令只删除所有untracked的文件,如果文件已经被tr ...
- PHPUnit入门
PHPUnit是PHP语言的单元测试框架.工具,xunit单元测试工具系列成员之一,可以单独运行在Linux或windows系统下面,也可以集成到zend studio等IDE工具中. 工具下载:ht ...
- strace追踪mysql执行语句
一.strace参数 strace是Linux环境下的一款程序调试工具,用来监察一个应用程序所使用的系统调用及它所接收的系统信息.追踪程序运行时的整个生命周期,输出每一个系统调用的名字,参数,返回值和 ...
- 掌握Thinkphp3.2.0----模型初步
1.为什么要学习框架?框架是什么? 简单的说就是为了简单,提高开发的效率.至于什么是框架(一种规范),现在的我还不是很理解,容后再议. 学习框架最重要的就是遵循,按照开发者的意图来使用该框架. 2.t ...
- java中return与finally的执行顺序
可不能小看这个简单的 finally,看似简单的问题背后,却隐藏了无数的玄机.接下来我就带您一步一步的揭开这个 finally 的神秘面纱. 问题分析 首先来问大家一个问题:finally 语句块一定 ...
- C# fun
C#中Func<T,TResult>的用法和Lambda表达式 代码片段: Func<int,string,string> t=(int x, string b) => ...
- Echarts学习笔记之饼图
注:ECHarts的相关文件请到ECharts官网下载,下载地址:http://echarts.baidu.com/download.html 1.前台 <div style="ali ...
- SQL优化----百万数据查询优化
百万数据查询优化 1.合理使用索引 索引是数据库中重要的数据结构,它的根本目的就是为了提高查询效率.现在大多数的数据库产品都采用IBM最先提出的ISAM索引结构.索引的使用要恰到好处,其使用原则如下: ...