1. 程式人生 > >dnotify機制與inotify機制

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、應用
 例子:

  1. // 要用fcntl( fd, F_SETSIG, SIGRTMIN + 1 )就要設定這個巨集
  2. #define _GNU_SOURCE 1
  3. #include <fcntl.h>
  4. #include <stdio.h>
  5. #include <unistd.h>
  6. #include <signal.h>
  7. #define FOLDER_MAXLEN   128
  8. staticchar listen_folder[FOLDER_MAXLEN];  
  9. staticvoid myhandler( int );  
  10. int set_folder_signal( 
    void )  
  11. {  
  12.     struct sigaction act;  
  13.     int fd;  
  14.     act.sa_handler = myhandler;  
  15.     sigemptyset( &act.sa_mask );  
  16.     act.sa_flags = 0;  
  17.     sigaction( SIGRTMIN + 1, &act, NULL );  
  18.     if(( fd = open( listen_folder, O_RDONLY )) < 0 )  
  19.         return -1;  
  20.     printf( "fd=%d\n", fd );  
  21.     fcntl( fd, F_SETSIG, SIGRTMIN + 1 );  
  22.     fcntl( fd, F_NOTIFY, DN_CREATE );  
  23.     return 0;  
  24. }  
  25. int main(int argc, char *argv[] )  
  26. {  
  27.     if( argc != 2 )  
  28.     {  
  29.         printf( "%s filepath\n", argv[0] );  
  30.         exit( 0 );  
  31.     }  
  32.     strncpy( listen_folder, argv[1], FOLDER_MAXLEN - 1 );   
  33.     if( set_folder_signal( ) < 0 )  
  34.     {  
  35.         printf( "set signal to %s fail\n", argv[1] );  
  36.         exit( 0 );  
  37.     }  
  38.     while( 1 )  
  39.     {  
  40.         pause();  
  41.         printf( "a signal return\n" );  
  42.     }  
  43. }  
  44. staticvoid myhandler( int signo )  
  45. {  
  46.     printf( "signalno=%d,a file was creat\n", signo );  
  47.     set_folder_signal();  
  48. }  

以上例子訊號處理函式只能得到訊號編號資訊。可以通過sa_sigaction訊號處理函式來獲得更多資訊,但也很有限。比如檔案描述符。
例 子:

  1. //要用 fcntl( fd, F_SETSIG, SIGRTMIN + 1 )就要設定這個巨集
  2. #define _GNU_SOURCE 1
  3. #include <fcntl.h>
  4. #include <stdio.h>
  5. #include <unistd.h>
  6. #include <signal.h>
  7. #define FOLDER_MAXLEN   128
  8. staticchar listen_folder[FOLDER_MAXLEN];  
  9. staticvoid myhandler(int sig, siginfo_t *si, void *data);  
  10. int set_folder_signal( void )  
  11. {  
  12.     struct sigaction act;  
  13.     int fd;  
  14.     act.sa_sigaction = myhandler;  
  15.     sigemptyset( &act.sa_mask );  
  16.     act.sa_flags = SA_SIGINFO;  
  17.     sigaction( SIGRTMIN + 1, &act, NULL );  
  18.     if(( fd = open( listen_folder, O_RDONLY )) < 0 )  
  19.         return -1;  
  20.     printf( "fd=%d\n", fd );  
  21.     fcntl( fd, F_SETSIG, SIGRTMIN + 1 );  
  22.     fcntl( fd, F_NOTIFY, DN_CREATE );  
  23.     return 0;  
  24. }  
  25. int main(int argc, char *argv[] )  
  26. {  
  27.     if( argc != 2 )  
  28.     {  
  29.         printf( "%s filepath\n", argv[0] );  
  30.         exit( 0 );  
  31.     }  
  32.     strncpy( listen_folder, argv[1], FOLDER_MAXLEN - 1 );   
  33.     if( set_folder_signal( ) < 0 )  
  34.     {  
  35.         printf( "set signal to %s fail\n", argv[1] );  
  36.         exit( 0 );  
  37.     }  
  38.     while( 1 )  
  39.     {  
  40.         pause();  
  41.         printf( "a signal return\n" );  
  42.     }  
  43. }  
  44. staticvoid myhandler(int signo, siginfo_t *si, void *data)  
  45. {  
  46.     printf( "signalno=%d=%d,a file was creat\n", signo, si->si_signo );  
  47.     printf( "errno值=%d\n", si->si_errno );  
  48.     printf( "訊號產生的原因=%d\n", si->si_code );  
  49.     printf( "產生訊號的檔案描述符=%d\n", si->si_fd );  
  50.     set_folder_signal();  
  51. }  

二、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、應用
 例子:

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <linux/unistd.h>
  5. #include <linux/inotify.h>
  6. char * event_array[] = {  
  7.     "File was accessed",  
  8.     "File was modified",  
  9.     "File attributes were changed",  
  10.     "writtable file closed",  
  11.     "Unwrittable file closed",  
  12.     "File was opened",  
  13.     "File was moved from X",  
  14.     "File was moved to Y",  
  15.     "Subfile was created",  
  16.     "Subfile was deleted",  
  17.     "Self was deleted",  
  18.     "Self was moved",  
  19.     "",  
  20.     "Backing fs was unmounted",  
  21.     "Event queued overflowed",  
  22.     "File was ignored"
  23. };  
  24. #define EVENT_NUM 16
  25. #define MAX_BUF_SIZE 1024
  26. int main(int argc, char *argv[] )  
  27. {  
  28.     int fd, wd;  
  29.     char buffer[ MAX_BUF_SIZE + 1 ];  
  30.     char * offset = NULL;  
  31.     struct inotify_event * event;  
  32.     int i, len, tmp_len;  
  33.     char strbuf[16];  
  34.     if( argc != 2 )  
  35.     {  
  36.         printf( "%s file|folder\n", argv[0] );  
  37.         exit( 0 );  
  38.     }  
  39.     if(( fd = inotify_init()) < 0 )  
  40.     {  
  41.         printf("Fail to initialize inotify.\n");  
  42.         exit( 0 );  
  43.     }  
  44.     if(( wd = inotify_add_watch(fd, argv[1], IN_ALL_EVENTS)) < 0 )  
  45.     {  
  46.             printf("Can't add watch for %s.\n", argv[1]);  
  47.             exit(0);  
  48.     }  
  49.     while( len = read(fd, buffer, MAX_BUF_SIZE))   
  50.     {  
  51.         offset = buffer;  
  52.         event = (struct inotify_event *)buffer;  
  53.         while(((char *)event - buffer) < len )   
  54.         {  
  55.             printf( "Object type: %s\n",   
  56.                 event->mask & IN_ISDIR ? "Direcotory" : "File" );  
  57.             if(event->wd != wd)   
  58.                 continue;  
  59.             printf("Object name: %s\n"event->name);  
  60.             printf("Event mask: %08X\n"event->mask);  
  61.             for(i=0; i<EVENT_NUM; i++)   
  62.             {  
  63.                 if (event_array[i][0] == '\0')   
  64.                     continue;  
  65.                 if (event->mask & (1<<i))   
  66.                 {  
  67.                     printf("Event: %s\n", event_array[i]);  
  68.                 }  
  69.             }  
  70.             tmp_len = sizeof(struct inotify_event) + event->len;  
  71.             event = (struct inotify_event *)(offset + tmp_len);   
  72.             offset += tmp_len;  
  73.         }  
  74.     }  
  75. }