1. 程式人生 > >linux檔案系統變化通知機制—inotify

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