用于监控 Linux文件系统事件的inotify接口学习笔记



参考
http://www.ibm.com/developerworks/cn/linux/l-inotify/index.html

从 Linux 2.6.13 内核开始,Linux 就推出了 inotify,允许监控程序打开一个独立文件描述符,并针对事件集监控一个或者多个文件,例如打开、关闭、移动/重命名、删除、创建或者改变属性。

提供的接口

inotify提供的结构和接口(见/usr/include/sys/inotify.h)如下:

inotify_init
    是用于创建一个 inotify 实例的系统调用,并返回一个指向该实例的文件描述符。
inotify_add_watch
    增加对文件或者目录的监控,并指定需要监控哪些事件。标志用于控制是否将事件添加到已有的监控中,是否只有路径代表一个目录才进行监控,是否要追踪符号链接,是否进行一次性监控,当首次事件出现后就停止监控。
inotify_rm_watch
    从监控列表中移出监控项目。
read
    读取包含一个或者多个事件信息的缓存。
close
    关闭文件描述符,并且移除所有在该描述符上的所有监控。当关于某实例的所有文件描述符都关闭时,资源和下层对象都将释放,以供内核再次使用。

因此,典型的监控程序需要进行如下操作:

   1. 使用 inotify_init 打开一个文件描述符
   2. 添加一个或者多个监控
   3. 等待事件
   4. 处理事件,然后返回并等待更多事件
   5. 当监控不再活动时,或者接到某个信号之后,关闭文件描述符,清空,然后退出。

可监控的事件


有几种事件能够被监控。一些事件,比如 IN_DELETE_SELF 只适用于正在被监控的项目,而另一些,比如 IN_ATTRIB 或者 IN_OPEN 则只适用于监控过的项目,或者如果该项目是目录,则可以应用到其所包含的目录或文件。

IN_ACCESS
    被监控项目或者被监控目录中的条目被访问过。例如,一个打开的文件被读取。
IN_MODIFY
    被监控项目或者被监控目录中的条目被修改过。例如,一个打开的文件被修改。
IN_ATTRIB
    被监控项目或者被监控目录中条目的元数据被修改过。例如,时间戳或者许可被修改。
IN_CLOSE_WRITE
    一个打开的,等待写入的文件或目录被关闭。
IN_CLOSE_NOWRITE
    一个以只读方式打开的文件或目录被关闭。
IN_CLOSE
    一个掩码,可以很便捷地对前面提到的两个关闭事件(IN_CLOSE_WRITE | IN_CLOSE_NOWRITE)进行逻辑操作。
IN_OPEN
    文件或目录被打开。
IN_MOVED_FROM
    被监控项目或者被监控目录中的条目被移出监控区域。该事件还包含一个 cookie 来实现 IN_MOVED_FROM 与 IN_MOVED_TO 的关联。
IN_MOVED_TO
    文件或目录被移入监控区域。该事件包含一个针对 IN_MOVED_FROM 的 cookie。如果文件或目录只是被重命名,将能看到这两个事件,如果它只是被移入或移出非监控区域,将只能看到一个事件。如果移动或重命名一个被监控项目,监控将继续进行。参见下面的 IN_MOVE-SELF。
IN_MOVE
    可以很便捷地对前面提到的两个移动事件(IN_MOVED_FROM | IN_MOVED_TO)进行逻辑操作的掩码。
IN_CREATE
    在被监控目录中创建了子目录或文件。
IN_DELETE
    被监控目录中有子目录或文件被删除。
IN_DELETE_SELF
    被监控项目本身被删除。监控终止,并且将收到一个 IN_IGNORED 事件。
IN_MOVE_SELF
    监控项目本身被移动。

使用实例

class InotifyInstance
{
    int m_fd;
    unsigned int m_watched_items;

public:

    InotifyInstance() : m_fd(-1), m_watched_items(0) { }

public:

    int open()
    {
        m_watched_items = 0;
        m_fd = inotify_init();

        if (m_fd < 0)
        {
            perror("inotify_init () = ");
            return m_fd;
        }
        return 0;
    }

    int close()
    {
        m_watched_items = 0;
        if (m_fd <= 0)
            return 0;

        return ::close(m_fd);
    }

public:

    int add_watch(const char *name, unsigned long mask)
    {
        int wd;
        wd = inotify_add_watch(m_fd, name, mask);
        if (wd < 0)
        {
            perror("inotify_add_watch () = ");
        } else
        {
            m_watched_items++;
        }
        return wd;
    }

    int rm_wd(int wd)
    {
        int r = inotify_rm_watch(m_fd, wd);
        if (r < 0)
        {
            perror("inotify_rm_watch(fd, wd) = ");
        } else
        {
            m_watched_items--;
        }
        return r;
    }

public:

    template <typename EventCallback>
    int watch_once(EventCallback& cb)
    {
        int ret = 0;
        if (event_check() > 0)
        {
            ret = handle_events(cb);
        }
        return ret;
    }

    template <typename EventCallback>
    int watch_loop(EventCallback& cb)
    {
        int ret = 0;
        while (m_watched_items > 0)
        {
            ret = watch_once(cb);
            if (ret != 0)
                break;
        }
        return ret;
    }

private:

    int event_check() const
    {
        fd_set rfds;
        FD_ZERO(&rfds);
        FD_SET(m_fd, &rfds);
        /* Wait until an event happens or we get interrupted
           by a signal that we catch */
        return select(FD_SETSIZE, &rfds, NULL, NULL, NULL);
    }

    template <typename EventCallback>
    int handle_events(EventCallback& cb)
    {
        int buf_len = 16384;
        char* buffer = new char[buf_len];

        ssize_t r = read(m_fd, buffer, buf_len);
        if (r <= 0)
            return r;

        size_t buffer_i = 0;
        int ret = 0;
        while (buffer_i < r)
        {
            struct inotify_event *pevent = (struct inotify_event *) &buffer[buffer_i];
            size_t event_size = offsetof(struct inotify_event, name) + pevent->len;
            ret = cb.process_event(pevent);
            if (ret != 0)
                break;
            buffer_i += event_size;
        }

        delete[] buffer;
        return ret;
    }
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值