• linux文件系统变化通知机制—inotify


    概述

    inotify — a powerful yet simple file change notification system.
    inotify是linux内核2.6.13以后支持的一种特性,功能是监视文件系统的变化,在监视到文件系统发生变化
    以后,会向相应的应用程序发送变化事件。
    inotify是一种文件系统的变化通知机制,如文件增加、删除等事件可以立刻让用户得知,该机制是著名的
    桌面搜索引擎项目beagle引入的。

    监测事件

    头文件:#include <sys/inotify.h>

    Supported events suitable for MASK parameter of inotify_add_watch.

    /* File was accessed. 文件被访问。*/
    #define IN_ACCESS 0x00000001 
    
    /* FIle was modified. 文件被修改。*/
    #define IN_MODIFY 0x00000002 
    
    /* Metadata changed. 文件属性被修改,如chmod、chown、touch等。*/
    #define IN_ATTRIB 0x00000004 
    
    /* Writtable file was closed. 可写文件被关闭。*/
    #define IN_CLOSE_WRITE 0x00000008 
    
    /* Unwrittable file closed. 不可写文件被关闭。*/
    #define IN_CLOSE_NOWRITE 0x00000010 
    
    /* 文件被关闭。*/
    #define IN_CLOSE (IN_CLOSE_WRITE | IN_CLOSE_NOWRITE) 
    
    /* File was opened. 文件被打开。*/
    #define IN_OPEN 0x00000020
    
    /* File was moved from X. 文件被移走,如mv。*/
    #define IN_MOVED_FROM 0x00000040 
    
    /* File was moved to Y. 文件被移来,如mv、cp。*/
    #define IN_MOVED_TO 0x00000080 
    
    /* Moves. 文件被移动。*/
    #define IN_MOVED (IN_MOVED_FROM | IN_MOVED_TO) 
    
    /* Subfile was created. 创建新文件。*/
    #define IN_CREATE 0x00000100
    
    /* Subfile was deleted. 文件被删除,如rm。*/
    #define IN_DELETE 0x00000200 
    
    /* Self was deleted. 自删除,即一个可执行文件在执行时删除自己。*/
    #define IN_DELETE_SELF 0x00000400 
    
    /* Self was moved.  自移动,即一个可执行文件在执行时移动自己。*/
    #define IN_MOVE_SELF 0x00000800

    Events sent by the kernel.

    /* Backing fs was unmounted. 宿主文件系统被unmount。*/
    #define IN_UNMOUNT 0x00002000
    
    /* Event queued overflowed. 在内核中,事件的数据超过了
     * inotify_device中的max_events。*/
    #define IN_Q_OVERFLOW 0x00004000
    
    /* File was ignored. 表示系统把该文件对应的watch从inotify实例中
     * 删除,因为文件已经被删除了!*/
    #define IN_IGNORED 0x00008000  

    Special flags.

    /* Only watch the path if it is a directory. */
    #define IN_ONLYDIR 0x01000000 
    
    /* Do not follow a sym link. */
    #define IN_DONT_FOLLOW 0x02000000
    
    /* Add to the mask of an already existing watch. */
    #define IN_MASK_ADD 0x20000000 
    
    /* Event occurred against dir. */
    #define IN_ISDIR 0x40000000 
    
    /* Only send event once. */
    #define IN_ONESHOT 0x80000000  

    All events which a program can wait on.

    #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_CREATE | IN_DELETE | IN_DELETE_SELF | IN_MOVE_SELF)

    API函数

    inotify主要提供如下API。

    (1)创建inotify实体

    /* Create and initialize inotify instance. */
    extern int inotify_init (void) __THROW;

    inotify_init()在内核中创建一个实体:inotify_device,并返回一个文件描述符。
    使用:int fd = inotify_init();

    (2)创建监视器

    /* Add watch of object NAME to inotify instance FD. Notify about events 
     * specified by MASK. 
     */
    extern int inotify_add_watch (int __fd, const char * __name, uint32_t __mask) 
        __THROW;

    inotify_add_watch用于向inotify_device中的监视器列表添加监视器:inotify_watch。
    创建监视器要提供:
    (1) inotify实例inotify_device的文件描述符:fd
    (2) 监视目标路径:name
    (3) 监视事件列表:mask
    如果成功,返回监视器描述符wd,否则返回-1。

    (3)删除监视器

    /* Remove the watch specified by WD from the inotify instance FD. */
    extern int inotify_rm_watch (int __fd, uint32_t __wd) __THROW;

     用于从inotify_device的监视器列表中删除一个监视器。

    读取事件

    为了确定哪些文件系统事件发生,需要用read系统调用读取inotify_init()返回的文件描述符。
    read()会返回一个或多个inotify_event。

    /* Structure describing an inotify event. */
    
    struct inotify_event
    {
        int wd; /* Watch descriptor. */
        unit32_t mask; /* Watch mask */
        unit32_t cookie; /* Cookie to synchronize two events. */
        unit32_t len; /* Length (including NULLs) of name. */
        char name __flexarr; /* Name. */
    };

    inotify_event为文件系统事件。
    其中wd为被监视目标的watch描述符,mask为事件掩码,name为监视目标的路径名,
    len为name的长度。
    每个notify_event的结构体大小为:sizeof(struct inotify_event) + len。
    通过inotify_event可以看出:

    (1) 监视目标(什么文件/目录) —> name,len
    (2) 监视器 —> wd
    (3) 监视目标的什么事件 —> mask

    通过read()可以一次性获得多个事件,只要提供的buf足够大。
    size_t len = read(fd, buf , MAX_BUF_SIZE);
    len为实际获得的事件集总长度。
    可以在函数inotify()返回的文件描述符fd上使用select()或poll()、epoll(),也可以在fd上使用ioctl命令
    FIONREAD来得到当前队列的长度。
    close(fd)将删除所有添加到fd中的watch并做必要的清理。 

    内核实现简述

    Each inotify instance is represented by an inotify_handle structure.
    Inotify's userspace consumers also have an inotify_device which is
    associated with the inotify_handle, and on which events are queued.
    Each watch is associated with an inotify_watch structure. Watches are chained
    off of each associated inotify_handle and each associated inode.
    See fs/notify/inotify/inotify_fsnotify.c and fs/notify/inotify/inotify_user.c for
    the locking and lifetime rules.

    无论是目录还是文件,在内核中都对应一个inode结构,inotify系统再inode结构中增加了两个字段:
    #ifdef CONFIG_INOTIFY
            struct list_head inotify_watches; /* watches on this  inode */
            struct semaphore inotify_sem; /* protects the watches list */
    #endif

    Reference

    1. documentation \ filesystems \ inotify.txt
    2. include \ linux \ inotify.h
    3. http://www.ibm.com/developerworks/cn/linux/l-inotifynew/
    4
    . http://tianyapiaozi.blogbus.com/logs/61783047.html

  • 相关阅读:
    开源作品-PHP写的Redis管理工具(单文件绿色版)-SuRedisAdmin_PHP_1_0
    开源作品-PHP写的JS和CSS文件压缩利器(单文件绿色版)-SuMinify_PHP_1_5
    Javascript关于JSON集合的几种循环方法
    正式安家
    Oracle 常用脚本
    Centos6安装zabbix_server
    centos_6下源码编译安装zabbix之一 LNMP环境的搭建
    reg51.h
    C语言浮点数存储结构分析
    WinForm程序中两份mdf文件问题的解决
  • 原文地址:https://www.cnblogs.com/aiwz/p/6333384.html
Copyright © 2020-2023  润新知