2 #include <sys/inotify.h> // for INOTIFY duh
3 #include <stdio.h> // for stdio, NULL
4 #include <stdlib.h> // for malloc, etc
5 #include <unistd.h> // for close
7 #define _XOPEN_SOURCE 500
8 #define __USE_XOPEN_EXTENDED
9 #include <ftw.h> /* for nftw, tree walker */
11 #include "pnd_notify.h"
12 #include "pnd_pathiter.h"
15 int fd; // notify API file descriptor
18 static int notify_handle;
20 static void pnd_notify_hookup ( int fd );
22 #define PND_INOTIFY_MASK IN_CREATE | IN_DELETE | IN_UNMOUNT \
23 | IN_DELETE_SELF | IN_MOVE_SELF \
24 | IN_MOVED_FROM | IN_MOVED_TO
26 pnd_notify_handle pnd_notify_init ( void ) {
36 p = malloc ( sizeof(pnd_notify_t) );
40 return ( NULL ); // uhh..
45 // setup some default watches
46 pnd_notify_hookup ( fd );
51 void pnd_notify_shutdown ( pnd_notify_handle h ) {
52 pnd_notify_t *p = (pnd_notify_t*) h;
59 static int pnd_notify_callback ( const char *fpath, const struct stat *sb,
60 int typeflag, struct FTW *ftwbuf )
63 // only include directories
64 if ( ! ( typeflag & FTW_D ) ) {
65 return ( 0 ); // continue the tree walk
68 //printf ( "Implicitly watching dir '%s'\n", fpath );
70 inotify_add_watch ( notify_handle, fpath, PND_INOTIFY_MASK );
72 return ( 0 ); // continue the tree walk
75 void pnd_notify_watch_path ( pnd_notify_handle h, char *fullpath, unsigned int flags ) {
76 pnd_notify_t *p = (pnd_notify_t*) h;
79 inotify_add_watch ( p -> fd, fullpath, PND_INOTIFY_MASK );
81 inotify_add_watch ( p -> fd, fullpath, IN_ALL_EVENTS );
84 if ( flags & PND_NOTIFY_RECURSE ) {
86 notify_handle = p -> fd;
88 nftw ( fullpath, // path to descend
89 pnd_notify_callback, // callback to do processing
90 10, // no more than X open fd's at once
91 FTW_PHYS ); // do not follow symlinks
100 static void pnd_notify_hookup ( int fd ) {
102 inotify_add_watch ( fd, "./testdata", IN_CREATE | IN_DELETE | IN_UNMOUNT );
107 unsigned char pnd_notify_rediscover_p ( pnd_notify_handle h ) {
108 pnd_notify_t *p = (pnd_notify_t*) h;
114 // don't block for long..
116 //t.tv_usec = 0; //5000;
120 // only for our useful fd
122 FD_SET ( (p->fd), &rfds );
125 retcode = select ( (p->fd) + 1, &rfds, NULL, NULL, &t );
128 return ( 0 ); // hmm.. need a better error code handler
129 } else if ( retcode == 0 ) {
130 return ( 0 ); // timeout
133 if ( ! FD_ISSET ( (p->fd), &rfds ) ) {
137 // by this point, something must have happened on our watch
138 #define BINBUFLEN ( 100 * ( sizeof(struct inotify_event) + 30 ) ) /* approx 100 events in a shot? */
139 unsigned char binbuf [ BINBUFLEN ];
142 actuallen = read ( (p->fd), binbuf, BINBUFLEN );
144 if ( actuallen < 0 ) {
145 return ( 0 ); // error
146 } else if ( actuallen == 0 ) {
147 return ( 0 ); // nothing, or overflow, or .. whatever.
151 struct inotify_event *e;
153 while ( i < actuallen ) {
154 e = (struct inotify_event *) &binbuf [ i ];
160 //printf ( "Got event against '%s'\n", e -> name );
167 i += ( sizeof(struct inotify_event) + e -> len );