Hello,
Please find attached the source code. Could anyone explain why the callback
is never invoked when I do change the files?
Thank you,
Roustam
// custom
#include "watcher.h"
// standard
#include <cstring>
// cross-platform
#include <ev++.h>
// Linux
#include <sys/inotify.h>
#include <unistd.h>
#include <dirent.h>
#include <sys/stat.h>
std::string dir_path;
int file_descriptor, watch_descriptor;
ev::io watcher;
std::list<Event> events;
static void io_callback (ev::io &event_watcher, int revents) {
events.clear();
char buffer[4096] __attribute__ ((aligned(__alignof__(struct inotify_event))));
const struct inotify_event *p_file_event;
std::size_t event_size = sizeof(struct inotify_event);
struct stat metadata;
while (true) {
ssize_t bytes_count = read(file_descriptor, buffer, sizeof buffer);
if (bytes_count == -1) {// no new events to process, exit the loop
if (errno != EAGAIN)
std::perror("read");
break;
}
// process new events
for (char *p_event = buffer, *end = buffer + bytes_count; p_event < end; p_event += event_size + p_file_event->len) {
p_file_event = (const struct inotify_event *) p_event;
if (!(p_file_event->mask & IN_ISDIR) && p_file_event->len) {// the file is not a directory and has a name
Event file_event;
file_event.name = p_file_event->name;
if (p_file_event->mask & IN_DELETE || p_file_event->mask & IN_MOVED_FROM)// the file was removed
file_event.status = removed;
else if(stat((dir_path + '/' + file_event.name).c_str(), &metadata) != -1) {// successfully got file metadata
file_event.size = (long long) metadata.st_size;
file_event.modified = ctime(&metadata.st_mtime);
if (p_file_event->mask & IN_MODIFY || p_file_event->mask & IN_MOVED_TO)// the file was created or modified
file_event.status = modified;
else// dismiss the event
continue;
}
else// dismiss the event
continue;
events.push_back(file_event);
}
}
}
}
std::list<Event> engage_watcher(const std::string &directory_path) {
std::list<Event> result;
if (!dir_path.empty())
return result;
struct stat metadata;
struct dirent *entry = nullptr;// a file
// open the directory
DIR *directory = nullptr;
directory = opendir(directory_path.c_str());
if (directory != nullptr) {
dir_path = directory_path;
// initialize a file descriptor
file_descriptor = inotify_init1(IN_NONBLOCK);
if (file_descriptor == -1) {
std::perror("inotify_init1");
return result;
}
// initialize a watch descriptor
watch_descriptor = inotify_add_watch(file_descriptor, dir_path.c_str(), IN_MODIFY | IN_MOVED_TO | IN_DELETE | IN_MOVED_FROM);
if (watch_descriptor == -1) {
std::fprintf(stderr, "Cannot watch the directory. Error: %s\en", std::strerror(errno));
close(file_descriptor);
return result;}
// iterate through all files in the watched directory
while ((entry = readdir(directory))) {// get next file from the watched directory
if (entry->d_type != 4) {// the file is not a directory
if (stat((dir_path + '/' + entry->d_name).c_str(), &metadata) != -1) {// get file metadata
Event file_event;
file_event.name = entry->d_name;
file_event.size = (long long) metadata.st_size;
file_event.modified = ctime(&metadata.st_mtime);
file_event.status = modified;
result.push_back(file_event);
}
}
}
// set the callback for the watcher and start watching
watcher.set <io_callback> ();
watcher.start(file_descriptor, ev::READ);
ev::get_default_loop().run(EVRUN_NOWAIT);
}
closedir(directory);
return result;
}
void disengage_watcher() {
if (dir_path.empty())
return;
watcher.stop();
dir_path.clear();
inotify_rm_watch(file_descriptor, watch_descriptor);
close(file_descriptor);
return;
}
#ifndef WATCHER_H
#define WATCHER_H
// standard
#include <list>
#include <string>
enum FileStatus {modified, removed};
struct Event {
std::string modified;
std::string name;
long long size;
FileStatus status;
};
std::list<Event> engage_watcher(const std::string &directory_path);
void disengage_watcher();
#endif // WATCHER_H
_______________________________________________
libev mailing list
[email protected]
http://lists.schmorp.de/mailman/listinfo/libev