inotificar recursivamente cómo hacerlo?

Necesito imprimir eventos en una carpeta con varias subcarpetas. ¿Cómo hacerlo de forma recursiva? Imprima un código C ++. ¡¡Estoy atascado !! Cada vez que se abre el evento, necesito abrir la subcarpeta, tomar el archivo y copiarlo en otro directorio. No quiero enumerar todas las subcarpetas cada 2 segundos y buscar los archivos si los hay. No es eficiente. Necesito usar una carpeta de monitor. Por favor ayuda

El director que quiero supervisar tiene varias subcarpetas. Cada subcarpeta tiene otra subcarpeta que podría contener en un momento un archivo. Carpeta principal-> Subcarpetas-> cada subcarpeta-> subcarpeta -> archivo.

Aquí está el código que tengo para el momento:

/*


*/
  #include <pthread.h>
    #include <unistd.h>

#include <iostream>
#include <sys/inotify.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/inotify.h>
#include <vector>
#include <string>
    #include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
using namespace std;
 vector<string> SS;



void *print_message_function( void *ptr );


int main(int argc, char **argv ){

  pthread_t t1;
    int fd,fd1,wd,wd1,i=0,i1=0,len=0,len1=0;
      int length;
    char pathname[100],buf[1024],buf1[1024];
   int data;
    struct inotify_event *event;
     char *message1 = "Thread 1";



   FILE *fr;
   // fd=inotify_init1(IN_NONBLOCK);//--rewrite
    fd = inotify_init();


    /* watch /test directory for any activity and report it back to me */
    wd=inotify_add_watch(fd,"/home/MainFoder/",IN_ALL_EVENTS);

  //  int flag=0;
   // char*ev="";
//wd=inotifytools_watch_recursively_with_exclude("/home/MainFolder/",IN_ALL_EVENTS);
 while(1)
{
//sleep(30);
        //read 1024  bytes of events from fd into buf

i=0;
        len=read(fd,buf,1024);
        while(i<len){

            event=(struct inotify_event *) &buf[i];


    /* watch /test directory for any activity and report it back to me */


            /* check for changes */
              {
            if((event->mask & IN_OPEN) ||(event->mask & IN_CREATE))

             {  


                 printf("\n %s :was opened\n",event->name);
                SS.push_back(event->name);



             }

       }
            /* update index to start of next event */
            i+=sizeof(struct inotify_event)+event->len;
        }

         vector<string>::const_iterator cii;
for(cii=SS.begin(); cii!=SS.end(); cii++)
       {


wd1 = watch_from_filename(*ci);
}
/*
vector<string>::const_iterator cii;
       for(cii=SS.begin(); cii!=SS.end(); cii++)
       {
          cout <<"HERE:"<< *cii << endl;
       }
*/
int  iret1, iret2;

    /* Create independent threads each of which will execute function */

     iret1 = pthread_create( &t1, NULL, print_message_function, (void*) message1);

}

}
void *print_message_function( void *ptr )
{
    vector<string>::const_iterator cii;
       for(cii=SS.begin(); cii!=SS.end(); cii++)
       {

          cout <<"HERE:"<< *cii << endl;
          std::string path=exec

       }
}

preguntado el 05 de febrero de 12 a las 03:02

puedo publicar un código. por favor saque el voto -1 -

5 Respuestas

Esta muestra de trabajo en Github hace lo que estás buscando: inotify-ejemplo.cpp

En los eventos CREATE, el wd actual (descriptor del reloj), más el wd inotify_event y los componentes de nombre, se agregan a un objeto Watch (ver ejemplo). La clase incluye métodos para buscar wd y nombres de varias formas.

Este fragmento muestra cómo se manejan los eventos CREATE / DELETE:

            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 );
                }
            }

Respondido 17 Jul 13, 02:07

Creo que todavía hay un agujero aquí. Si mira A y luego A / B y A / B / C se agregan rápidamente, para cuando procese la notificación para A / B (y agregue B al reloj), C ya se ha creado y se perdió su evento de creación desde que todavía no estaba escuchando en B. Entonces te pierdes cualquier evento que se encuentre en C. - costillar

Acordado. Es imposible agregar relojes de directorio lo suficientemente rápido como para garantizar que los eventos de archivos posteriores no se pierdan. - Pedro Krnjevic

Hasta ahora, este es el mejor enfoque que he visto usando inotify. Comparte si tienes algo mejor. Hay formas más sólidas de rastrear los cambios de archivos a través de Journals en Windows y OS X (y creo que * nix también), pero OP preguntó específicamente sobre inotify. - Pedro Krnjevic

Peter estuvo de acuerdo en que este enfoque es mejor para inotificar. La única solución que conozco es que cuando el consumidor del observador recibe un evento de creación de directorio, el consumidor debe escanear ese directorio de forma recursiva y enviar cualquier subdirectorio secundario que encuentre al observador para asegurarse de que el observador tenga un identificador abierto para ellos. Un efecto secundario desafortunado por no poder especificar un reloj recursivo de forma atómica, pero como dijiste, este es un artefacto desafortunado de la implementación de inotify. - costillar

Tiene toda la razón en que el escaneo posterior de las carpetas recién creadas aumenta la confiabilidad, pero también agrega gastos generales (y no está incluido en mi muestra). Si el OP necesitara ese nivel de confiabilidad y no hubiera mencionado específicamente inotify, habría recomendado fanotify ya que es robusto y no pierde eventos de creación. - Pedro Krnjevic

Puedes hacerlo en dos pasos:

  1. Detecte todos los cambios que le interesan en el directorio raíz, más (si aún no están incluidos) las creaciones (IN_CREATE).
  2. Si la creación es un directorio, haga todo el algoritmo en él.

Respondido 05 Feb 12, 07:02

he publicado un código. por favor dime como cambiarlo Si se crea la primera subcarpeta, necesito notificar los subarchivos - user1165435

@ user1165435, primero corrige tu formato. Como está, es difícil de leer. Use un espaciado uniforme y un estilo de tirantes. Más allá de eso, intente implementar los pasos anteriores y díganos si se atasca. - Mateo Flaschen

@MatthewFlaschen Gracias por el consejo, en realidad estaba buscando lo mismo y tu sugerencia es bastante fácil y tiene mucho sentido. Cuando se crea una carpeta, simplemente observe () esa carpeta también ... - Logan

He escrito el código para ti. Ahora, solo tiene que hacer un cambio en este código. Simplemente proporcione la ruta de su directorio en la función principal.

#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;
}

Respondido 26 Oct 17, 07:10

es bueno, pero hay algunos errores, como: si el archivo fue shift + delete, luego se detectó, pero si solo eliminó el archivo de qué movimiento en la papelera no se eliminó, y si eliminamos ese archivo de la papelera, entonces no hay indicación de mensaje. - Rupesh Yadav.

@Rupesh Yadav, tiene toda la razón, pero este código está escrito para beaglebone en el que usamos el comando rm para eliminarlo. Pero lo actualizaré e intentaré resolver esto. Gracias por notificar. - Akatsuki

El while(1); fin main es una mala idea. Reemplazarlo con pausa (2) - Basile Starynkevitch

Para abordar el problema indicado por ribram (el 'agujero' :)). una posible solución en la que puedo pensar es que podemos hacer una combinación de 'sondear el directorio' y 'usar inotify' ... es decir, cada vez que se detecta un directorio (solo directorio, no lo haga para archivos):

  • agregue un punto de observación para el directorio recién detectado para inotificar
  • 'sondear' (o 'escanear') el directorio recién detectado (man readdir ()) para ver si ya hay elementos (archivos, directorios) creados. Esos son posiblemente los que faltan.

Tenga en cuenta que para construir una carcasa "hermética", el orden de los pasos anteriores es importante. primero debe agregar el punto de vigilancia que escanear ... Esto garantizará que un elemento sea recogido por 'escanear' o inotificar o ambos. En ese caso, es posible que también deba estar al tanto de los dups. es decir, el mismo elemento puede ser generado tanto por el escaneo como por el inotify

Respondido 21 Jul 17, 20:07

Puede utilizar la API fanotify. Le permite monitorear un montaje completo. El único inconveniente es que necesitas ser root.

Respondido 07 Abr '18, 13:04

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.