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