inotify recursively how to do it?

大憨熊 提交于 2019-12-05 10:31:07

This working sample on Github does what you're looking for: inotify-example.cpp

On CREATE events, the current wd (watch descriptor), plus the inotify_event wd and name components, are added to a Watch object (see sample). The class includes methods to lookup wd and names in several ways.

This snippet shows how CREATE/DELETE events are handled:

            if ( event->mask & IN_CREATE ) {
                current_dir = watch.get(event->wd);
                if ( event->mask & IN_ISDIR ) {
                    new_dir = current_dir + "/" + event->name;
                    wd = inotify_add_watch( fd, new_dir.c_str(), WATCH_FLAGS );
                    watch.insert( event->wd, event->name, wd );
                    total_dir_events++;
                    printf( "New directory %s created.\n", new_dir.c_str() );
                } else {
                    total_file_events++;
                    printf( "New file %s/%s created.\n", current_dir.c_str(), event->name );
                }
            } else if ( event->mask & IN_DELETE ) {
                if ( event->mask & IN_ISDIR ) {
                    new_dir = watch.erase( event->wd, event->name, &wd );
                    inotify_rm_watch( fd, wd );
                    total_dir_events--;
                    printf( "Directory %s deleted.\n", new_dir.c_str() );
                } else {
                    current_dir = watch.get(event->wd);
                    total_file_events--;
                    printf( "File %s/%s deleted.\n", current_dir.c_str(), event->name );
                }
            }

You can do it in two steps:

  1. Detect all the changes you're interested in on the root directory, plus (if not already included) creations (IN_CREATE).
  2. If the creation is a directory, do the whole algorithm on it.
Akatsuki

I have written the code for you. Now, you have to do only one change in this code. Just give path of your directory in main function.

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/inotify.h>
#include <limits.h>
#include<sys/stat.h>
#include<dirent.h>
#include<time.h>
#include<string.h>
#include<unistd.h>

#define MAX_EVENTS 1024 /*Max. number of events to process at one go*/
#define LEN_NAME 16 /*Assuming that the length of the filename won't exceed 16 bytes*/
#define EVENT_SIZE  ( sizeof (struct inotify_event) ) /*size of one event*/
#define BUF_LEN     ( MAX_EVENTS * ( EVENT_SIZE + LEN_NAME )) /*buffer to store the data of events*/

void monitor(char *);
int evnt_mon(char *); 




void main()
{
    if(fork()==0)
    evnt_mon("./usssb");// give path of your directory which you want to monitor
    monitor("./usssb");// give path of your directory which you want to monitor
    while(1);
}

void monitor(char * rt_dir)
{

    struct stat st;
    DIR *dirp; 
    struct dirent *dp;
    char str[100][100]={ };
    char temp[100];
    char str1[500]=" ";
    int i=0,j=0,src_ret=9,src_ret1=9;
    strcpy(str1,rt_dir);
    dirp=opendir(str1);
    if(dirp==NULL)
    {
        perror("opendir");
        return;
    }

    while(1)
    {
        dp=readdir(dirp);
        if(dp==NULL)
        break;
        if((strcmp(dp->d_name,".\0")==0) || (strcmp(dp->d_name,"..")==0))
        continue;   

        if((dp->d_type==DT_DIR)&&((strcmp(dp->d_name,".")!=0)&&(strcmp(dp->d_name,"..")!=0)))
        {   
            strcat(str[i],str1);
            strcat(str[i],"/");
            strcat(str[i],dp->d_name);
            if(fork()==0)   
            {
                evnt_mon(str[i]);
            }
            i++;
        }

    }

    closedir(dirp);
    if(i>0)
    {
        for(j=0;j<i;j++)
        {
            monitor(str[j]);    
        }
    }

}




int evnt_mon(char *argv) 
{
    int length, i = 0, wd;
    int fd;
    char buffer[BUF_LEN];

    /* Initialize Inotify*/
    fd = inotify_init();
    if ( fd < 0 )
    {
        perror( "Couldn't initialize inotify");
    }

    /* add watch to starting directory */
    wd = inotify_add_watch(fd, argv, IN_CREATE | IN_MODIFY | IN_DELETE); 

    if (wd == -1)
    {
        printf("Couldn't add watch to %s\n",argv);
    }
    else
    {
        printf("Watching:: %s\n",argv);
    }

    /* do it forever*/
    while(1)
    {
        i = 0;
        length = read( fd, buffer, BUF_LEN );  
        if ( length < 0 )
        {
            perror( "read" );
        }  

        while ( i < length )
        {
            struct inotify_event *event = ( struct inotify_event * ) &buffer[ i ];
            if ( event->len )
            {
                if ( event->mask & IN_CREATE)
                {
                    if (event->mask & IN_ISDIR)
                    {
                        printf( "The directory %s was Created in %s.\n", event->name,argv );    


                        if(fork()==0)
                        {
                            char p[100]=" ";
                            strcpy(p,argv);
                            strcat(p,"/");
                            strcat(p,event->name);
                            evnt_mon(p);
                        }

                    }                       
                    else
                            printf( "The file %s was Created with WD %d\n", event->name, event->wd );       
                    }

                    if ( event->mask & IN_MODIFY)
                {
                            if (event->mask & IN_ISDIR)
                            printf( "The directory %s was modified.\n", event->name );       
                            else
                            printf( "The file %s was modified with WD %d\n", event->name, event->wd );       
                    }

                    if ( event->mask & IN_DELETE)
                {
                            if (event->mask & IN_ISDIR)
                            printf( "The directory %s was deleted from %s.\n", event->name,argv );       
                            else
                            printf( "The file %s was deleted with WD %d\n", event->name, event->wd );       
                    }  

                i += EVENT_SIZE + event->len;
            }
            }
        }

    /* Clean up*/
    inotify_rm_watch( fd, wd );
    close( fd );

    return 0;
}

To address the problem stated by ribram (the 'hole':)). one possible solution i can think of is that we can do a combination of 'polling the directory' and 'using inotify'... i.e. Each time a directory is detected (directory only, don't do it for files):

  • add a watchpoint for the newly detected directory to inotify
  • 'poll' (or 'scan') the newly detected directory (man readdir()) to see if there're already items (files, directories) created. Those are possibly the ones that are missing.

Note that to build an 'air-tight' case, the above steps' order is important. you need to add the watchpoint first than scan ... This will guarantee that an item is picked up by either 'scan' or inotify or both. In that case you may also need to aware of the dups. i.e. the same item can be both yielded by the scan and the inotify

You might use the fanotify API. It allows you to monitor a complete mount. The only drawback is that you need to be root.

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!