dnotify機制與inotify機制
一、dnotify機制
1、使用
通過對檔案描述符設定監聽訊號實現。
//設定檔案相應訊號
fcntl(fd, F_SETSIG, SIGRTMIN + 1);
//設定該檔案要監聽事件
fcntl(fd, F_NOTIFY, DN_ACCESS|DN_MODIFY|DN_CREATE|DN_RENAME|DN_DELETE|DN_ATTRIB|DN_MULTISHOT);
剩 下的就是訊號處理了。
2、缺點
缺點1:dnotify機制對監視的每個資料夾都打開了一個檔案描述符,如果資料夾所在檔案系統需要 umount就不行了。
缺點2:dnotify機制只能對資料夾程序監視。
3、應用
例子:
- // 要用fcntl( fd, F_SETSIG, SIGRTMIN + 1 )就要設定這個巨集
- #define _GNU_SOURCE 1
- #include <fcntl.h>
- #include <stdio.h>
- #include <unistd.h>
- #include <signal.h>
- #define FOLDER_MAXLEN 128
- staticchar listen_folder[FOLDER_MAXLEN];
- staticvoid myhandler( int );
-
int set_folder_signal(
- {
- struct sigaction act;
- int fd;
- act.sa_handler = myhandler;
- sigemptyset( &act.sa_mask );
- act.sa_flags = 0;
- sigaction( SIGRTMIN + 1, &act, NULL );
- if(( fd = open( listen_folder, O_RDONLY )) < 0 )
- return -1;
-
printf( "fd=%d\n", fd );
- fcntl( fd, F_SETSIG, SIGRTMIN + 1 );
- fcntl( fd, F_NOTIFY, DN_CREATE );
- return 0;
- }
- int main(int argc, char *argv[] )
- {
- if( argc != 2 )
- {
- printf( "%s filepath\n", argv[0] );
- exit( 0 );
- }
- strncpy( listen_folder, argv[1], FOLDER_MAXLEN - 1 );
- if( set_folder_signal( ) < 0 )
- {
- printf( "set signal to %s fail\n", argv[1] );
- exit( 0 );
- }
- while( 1 )
- {
- pause();
- printf( "a signal return\n" );
- }
- }
- staticvoid myhandler( int signo )
- {
- printf( "signalno=%d,a file was creat\n", signo );
- set_folder_signal();
- }
以上例子訊號處理函式只能得到訊號編號資訊。可以通過sa_sigaction訊號處理函式來獲得更多資訊,但也很有限。比如檔案描述符。
例 子:
- //要用 fcntl( fd, F_SETSIG, SIGRTMIN + 1 )就要設定這個巨集
- #define _GNU_SOURCE 1
- #include <fcntl.h>
- #include <stdio.h>
- #include <unistd.h>
- #include <signal.h>
- #define FOLDER_MAXLEN 128
- staticchar listen_folder[FOLDER_MAXLEN];
- staticvoid myhandler(int sig, siginfo_t *si, void *data);
- int set_folder_signal( void )
- {
- struct sigaction act;
- int fd;
- act.sa_sigaction = myhandler;
- sigemptyset( &act.sa_mask );
- act.sa_flags = SA_SIGINFO;
- sigaction( SIGRTMIN + 1, &act, NULL );
- if(( fd = open( listen_folder, O_RDONLY )) < 0 )
- return -1;
- printf( "fd=%d\n", fd );
- fcntl( fd, F_SETSIG, SIGRTMIN + 1 );
- fcntl( fd, F_NOTIFY, DN_CREATE );
- return 0;
- }
- int main(int argc, char *argv[] )
- {
- if( argc != 2 )
- {
- printf( "%s filepath\n", argv[0] );
- exit( 0 );
- }
- strncpy( listen_folder, argv[1], FOLDER_MAXLEN - 1 );
- if( set_folder_signal( ) < 0 )
- {
- printf( "set signal to %s fail\n", argv[1] );
- exit( 0 );
- }
- while( 1 )
- {
- pause();
- printf( "a signal return\n" );
- }
- }
- staticvoid myhandler(int signo, siginfo_t *si, void *data)
- {
- printf( "signalno=%d=%d,a file was creat\n", signo, si->si_signo );
- printf( "errno值=%d\n", si->si_errno );
- printf( "訊號產生的原因=%d\n", si->si_code );
- printf( "產生訊號的檔案描述符=%d\n", si->si_fd );
- set_folder_signal();
- }
二、inotify機制(核心2.6.13以上版本才支援,你可以uname -a看看)
1、使用
#include <linux/inotify.h>
//初始化inotify機制
int inotify_init (void);
//新增目錄或檔案程序監視
int inotify_add_watch (int fd, const char *path, __u32 mask);
//刪除一個監視
int inotify_rm_watch (int fd, __u32 mask);
//獲得監視事件反饋資訊struct inotify_event
size_t len = read (fd, buf, BUF_LEN);
struct inotify_event {
__s32 wd; /* 監視描述符 */
__u32 mask; /* 監視掩碼 */
__u32 len; /* 產生事件物件名稱長度 */
char name[0]; /* 產生事件物件名稱 */
};
inotify機制可以監視檔案系統事件:
IN_ACCESS,檔案被訪問
IN_MODIFY,檔案被 write
IN_ATTRIB, 檔案屬性被修改,如 chmod、chown、touch 等
IN_CLOSE_WRITE,可寫檔案被 close
IN_CLOSE_NOWRITE, 不可寫檔案被 close
IN_OPEN,檔案被 open
IN_MOVED_FROM,檔案被移走,如 mv
IN_MOVED_TO, 檔案被移來,如 mv、cp
IN_CREATE,建立新檔案
IN_DELETE,檔案被刪除,如 rm
IN_DELETE_SELF, 自刪除,即一個可執行檔案在執行時刪除自己
IN_MOVE_SELF,自移動,即一個可執行檔案在執行時移動自己
IN_UNMOUNT, 宿主檔案系統被 umount
IN_CLOSE,檔案被關閉,等同於(IN_CLOSE_WRITE | IN_CLOSE_NOWRITE)
IN_MOVE,檔案被移動,等同於(IN_MOVED_FROM | IN_MOVED_TO)
2、 優點
優點1:inotify不開啟目標物件描述符,所以目標umount時不影響,且會產生一個umount事件通知inotify機 制,inotify自動刪除該監視。
優點2:inotify既可以監視檔案,也可以監視目錄。
優點3:inotify使用系統調 用而不是訊號的方式來通知檔案系統事件,效率應該比較高。
優點4:inotify中的新增監視後產生的是新的檔案描述符作為介面,因此可以通 過select和poll來監視檔案系統的變化。
3、應用
例子:
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <linux/unistd.h>
- #include <linux/inotify.h>
- 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(int argc, char *argv[] )
- {
- int fd, wd;
- char buffer[ MAX_BUF_SIZE + 1 ];
- char * offset = NULL;
- struct inotify_event * event;
- int i, len, tmp_len;
- char strbuf[16];
- if( argc != 2 )
- {
- printf( "%s file|folder\n", argv[0] );
- exit( 0 );
- }
- if(( fd = inotify_init()) < 0 )
- {
- printf("Fail to initialize inotify.\n");
- exit( 0 );
- }
- if(( wd = inotify_add_watch(fd, argv[1], IN_ALL_EVENTS)) < 0 )
- {
- printf("Can't add watch for %s.\n", argv[1]);
- exit(0);
- }
- while( len = read(fd, buffer, MAX_BUF_SIZE))
- {
- offset = buffer;
- event = (struct inotify_event *)buffer;
- while(((char *)event - buffer) < len )
- {
- printf( "Object type: %s\n",
- event->mask & IN_ISDIR ? "Direcotory" : "File" );
- if(event->wd != wd)
- continue;
- printf("Object name: %s\n", event->name);
- printf("Event mask: %08X\n", event->mask);
- for(i=0; i<EVENT_NUM; i++)
- {
- if (event_array[i][0] == '\0')
- continue;
- if (event->mask & (1<<i))
- {
- printf("Event: %s\n", event_array[i]);
- }
- }
- tmp_len = sizeof(struct inotify_event) + event->len;
- event = (struct inotify_event *)(offset + tmp_len);
- offset += tmp_len;
- }
- }
- }