How to detect name of file changed with inotify?

64 Views Asked by At

I would like identify a specific name changed by editor like texstudio or geany. I use inotify

#include<stdio.h>
#include<sys/inotify.h>
#include<unistd.h>
#include<stdlib.h>
#include<signal.h>
#include<fcntl.h> // library for fcntl function
//inotify_02.c

#define MAX_EVENTS 1024  /* Maximum number of events to process*/
#define LEN_NAME 1024  /* 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*/
 
int file_descriptor,watch_descriptor;
 
void sig_handler(int sig){
 
       /* Step 5. Remove the watch descriptor and close the inotify instance*/
       inotify_rm_watch( file_descriptor, watch_descriptor );
       close( file_descriptor );
       exit( 0 );
 
}
 
 
int main(int argc, char **argv){
    char *path_to_be_watched;
    
    signal(SIGINT,sig_handler);
    path_to_be_watched = argv[1];
    
    /* Step 1. Initialize inotify */
    file_descriptor = inotify_init();
    if (fcntl(file_descriptor, F_SETFL, O_NONBLOCK) < 0)  // error checking for fcntl
    exit(2);

    /* Step 2. Add Watch */
    watch_descriptor = inotify_add_watch(file_descriptor,path_to_be_watched,IN_MODIFY | IN_CREATE | IN_DELETE);

    if(watch_descriptor==-1)
        printf("Could not watch : %s\n",path_to_be_watched);
    else
        printf("Watching : %s\n",path_to_be_watched);

    while(1)
    {
        int i=0,length;
        char buffer[BUF_LEN];

        /* Step 3. Read buffer*/
        length = read(file_descriptor,buffer,BUF_LEN);

        /* Step 4. Process the events which has occurred */
        while(i<length)
        {
 
            struct inotify_event *event = (struct inotify_event *) &buffer[i];
 
            if(event->len)
            {
                if ( event->mask & IN_CLOSE  ) 
                /* IN_CLOSE Equates to IN_CLOSE_WRITE | IN_CLOSE_NOWRITE 
                 * File or directory not opened for writing was closed. or
                 * File opened for writing was closed.
                 */
                {
                    if ( event->mask & IN_ISDIR ) 
                    {
                        printf( "File or directory %s not opened for writing was closed.\n", event->name );
                    }
                    else 
                    {
                       printf( "File  %sopened for writing was closed.\n", event->name );
                    }
                }
                /*-------*/
                else if ( event->mask & IN_CREATE ) 
                {
                    if ( event->mask & IN_ISDIR ) 
                    {
                        printf( "The directory %s was created.\n", event->name );
                    }
                    else 
                    {
                       printf( "The file %s was created.\n", event->name );
                    }
                }
                /*-------*/
                else if ( event->mask & IN_DELETE ) 
                {
                    if ( event->mask & IN_ISDIR ) 
                    {
                      printf( "The directory %s was deleted.\n", event->name );
                    }
                    else 
                    {
                      printf( "The file %s was deleted.\n", event->name );
                    }
                }
                /*-------*/
                else 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.\n", event->name );
                    }
                }
           }
           i += EVENT_SIZE + event->len;
        }
    }
}

When I use this software with an directory given in arg, I obtain this since file changed with editor((inotify_02.c)

Watching : /home/francis/.../inotify
The file .goutputstream-V0EIG2 was created.
The file .goutputstream-V0EIG2 was modified.

Obviously .goutputstream-V0EIG2 is like process name and not file name.

when I copy file (inotify_02.c) I have the name of new file duplicated

Watching : /home/francis/.../inotify
The file .goutputstream-V0EIG2 was created.
The file .goutputstream-V0EIG2 was modified.
The file inotify_02 (copie).c was created.
The file inotify_02 (copie).c was modified.

I found this : be careful, however, with file editors who most often do not edit a file on site but overwrite it (deletion then rewriting). So monitoring an IN_MODIFY event will be of no use. The most relevant, in this case, is to monitor IN_CLOSE_WRITE / IN_MOVED_FROM (depending on how the editor works) on the file in question, which makes it possible to only trigger the action once the file is stable, and not at each write()

By default because i am alone to work with my PC, I now what is about. But when latex compilation a lot of change occur. My program need to identify only change on specific file.

Is there any way to obtain the really name?

1

There are 1 best solutions below

0
Manmax On

a mwe in order to show stat give enough data for file: name, date,permission and so one....

If a watch file date change it's good for me

#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <pwd.h>
#include <grp.h>
#include <time.h>
#include <locale.h>
#include <langinfo.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>

struct dirent  *dp;
struct stat     statbuf;
struct passwd  *pwd;
struct group   *grp;
struct tm      *tm;
char            datestring[256];
//stat_02.c
 
char * str_perm(mode_t perms)
{
    char * string_perm = (char *) malloc( 4);
    strcpy(string_perm,(perms & S_IRUSR) ? "r" : "-");
    
    strcat(string_perm,(perms & S_IWUSR) ? "w" : "-");
    strcat(string_perm,(perms & S_IXUSR) ? "x" : "-");
    strcat(string_perm,(perms & S_IRGRP) ? "r" : "-");
    strcat(string_perm,(perms & S_IWGRP) ? "w" : "-");
    strcat(string_perm,(perms & S_IXGRP) ? "x" : "-");
    strcat(string_perm,(perms & S_IROTH) ? "r" : "-");
    strcat(string_perm,(perms & S_IWOTH) ? "w" : "-");
    strcat(string_perm,(perms & S_IXOTH) ? "x" : "-");
    
    return string_perm;
}

int main()
{
    DIR *dir = opendir(".");

    while ((dp = readdir(dir)) != NULL) {

    /* Get entry's information. */
    if (stat(dp->d_name, &statbuf) == -1)
        continue;

    /* Print out type, permissions, and number of links. */
    printf("%10.10s", str_perm (statbuf.st_mode));
    
    printf("%4ld", statbuf.st_nlink);


    /* Print out owner's name if it is found using getpwuid(). */
    if ((pwd = getpwuid(statbuf.st_uid)) != NULL)
        printf(" %-8.8s", pwd->pw_name);
    else
        printf(" %-8d", statbuf.st_uid);


    /* Print out group name if it is found using getgrgid(). */
    if ((grp = getgrgid(statbuf.st_gid)) != NULL)
        printf(" %-8.8s", grp->gr_name);
    else
        printf(" %-8d", statbuf.st_gid);


    /* Print size of file. */
    printf(" %9jd", (intmax_t)statbuf.st_size);


    tm = localtime(&statbuf.st_mtime);


    /* Get localized date string. */
    strftime(datestring, sizeof(datestring), nl_langinfo(D_T_FMT), tm);


    printf(" %s %s\n", datestring, dp->d_name);
}
}