Hi
I want to watch directory for modification by kqueue mechanism. Simple code:
After XXX hours of googling, I still can not figure out how I can get the name of the newly created file.
For get the filename that already was on the kqueue initialization - I can fill the structure from fullpath (pdent->d_name).
I see one way - have one copy of files and after creation compare lists and see what has been added. Also i need to re-initialization of the monitor to restart for monitoring newly created file. but I think it's stupid. In the Linux event/inotify mechanism i can get the file name from @->userdata data.
I am right that in the case of kqueue I have to constantly re-read and compare the lists to get the name of the created file? Thanks.
I want to watch directory for modification by kqueue mechanism. Simple code:
Code:
#include <dirent.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h> /* for strerror () */
#include <unistd.h>
#include <sys/event.h>
#include <sys/types.h>
#include <dirent.h>
#define MAX_ENTRIES 256
/* Function prototypes */
void diep(const char *s);
int main(int argc, char *argv[])
{
struct kevent evlist[MAX_ENTRIES]; /* events we want to monitor */
struct kevent chlist[MAX_ENTRIES]; /* events that were triggered */
struct dirent *pdent;
DIR *pdir;
char fullpath[256];
int fdlist[MAX_ENTRIES], cnt, i, error, kq, nev;
/* Check argument count */
if (argc != 2) {
fprintf(stderr, "Usage: %s directory\n", argv[0]);
exit(EXIT_FAILURE);
}
/* Create a new kernel event queue */
if ((kq = kqueue()) == -1)
diep("kqueue()");
/*
* Open directory named by argv[1], associate a directory stream
* with it and return a pointer to it.
*/
if ((pdir = opendir(argv[1])) == NULL)
diep("opendir()");
/* Skip . and .. entries */
cnt = 0;
while((pdent = readdir(pdir)) != NULL && cnt++ < 2)
; /* VOID */
/*
* Get all directory entries and for each one of them,
* initialise a kevent structure.
*/
cnt = 0;
while((pdent = readdir(pdir)) != NULL) {
/*
* Check whether we have exceeded the max number of
* entries that we can monitor.
*/
if (cnt > MAX_ENTRIES - 1) {
fprintf(stderr, "Max number of entries exceeded\n");
goto CLEANUP_AND_EXIT;
}
/*
* Check path length
* don't forget +1 for the '\0'
*/
if (strlen(argv[1] + strlen(pdent->d_name) + 2) > 256) {
fprintf(stderr,"Max path length exceeded\n");
goto CLEANUP_AND_EXIT;
}
strcpy(fullpath, argv[1]);
strcat(fullpath, "/");
strcat(fullpath, pdent->d_name);
/* Open directory entry */
if ((fdlist[cnt] = open(fullpath, O_RDONLY)) == -1) {
perror("open()");
continue;
}
/* Initialise kevent structure */
EV_SET(&chlist[cnt], fdlist[cnt], EVFILT_VNODE,
EV_ADD | EV_ENABLE | EV_ONESHOT,
NOTE_DELETE | NOTE_WRITE | NOTE_EXTEND | NOTE_ATTRIB | NOTE_LINK | NOTE_RENAME | NOTE_REVOKE,
0, 0);
cnt++;
}
/* Loop forever */
for (;;) {
nev = kevent(kq, chlist, cnt, evlist, cnt, NULL);
if (nev == -1)
perror("kevent()");
else if (nev > 0) {
for (i = 0; i < nev; i++) {
if (evlist[i].flags & EV_ERROR) {
fprintf(stderr, "EV_ERROR: %s\n", strerror(evlist[i].data));
goto CLEANUP_AND_EXIT;
}
if (evlist[i].fflags & NOTE_DELETE)
printf("fd: %d Deleted\n", evlist[i].ident);
else if (evlist[i].fflags & NOTE_EXTEND
|| evlist[i].fflags & NOTE_WRITE)
printf("fd: %d Modified\n", evlist[i].ident);
else if (evlist[i].fflags & NOTE_ATTRIB)
printf("fd: %d Attributes modified\n", evlist[i].ident);
else if (evlist[i].fflags & NOTE_LINK)
printf("fd: %d link\n", evlist[i].ident);
else if (evlist[i].fflags & NOTE_RENAME)
printf("fd: %d rename\n", evlist[i].ident);
else if (evlist[i].fflags & NOTE_REVOKE)
printf("fd: %d revoke\n", evlist[i].ident);
}
}
}
/* Clean up file descriptors, directory stream, kqueue */
CLEANUP_AND_EXIT:;
error = EXIT_SUCCESS;
for (i = 0; i < cnt; i++)
if (close(fdlist[i]) == -1) {
error = EXIT_FAILURE;
perror("close");
}
if ((closedir(pdir) == -1) || (close(kq) == -1)) {
error = EXIT_FAILURE;
perror("close");
}
return error;
}
void diep(const char *s)
{
perror(s);
exit(EXIT_FAILURE);
}
After XXX hours of googling, I still can not figure out how I can get the name of the newly created file.
For get the filename that already was on the kqueue initialization - I can fill the structure from fullpath (pdent->d_name).
I see one way - have one copy of files and after creation compare lists and see what has been added. Also i need to re-initialization of the monitor to restart for monitoring newly created file. but I think it's stupid. In the Linux event/inotify mechanism i can get the file name from @->userdata data.
I am right that in the case of kqueue I have to constantly re-read and compare the lists to get the name of the created file? Thanks.