//#include <iostream>
//#include <experimental/filesystem>
//#include <sys/inotify.h>
//#include <unistd.h>
//#define EVENT_SIZE ( sizeof (struct inotify_event) )
//#define EVENT_BUF_LEN ( 1024 * ( EVENT_SIZE + 16 ) )
//using namespace std;
//namespace core {
// using namespace std::experimental;
//}
//class FileWatcher {
//public:
// FileWatcher(core::filesystem::path _file, int mask = IN_CLOSE_WRITE)
// : file { std::move(_file) }
// {
// buffer.resize(EVENT_BUF_LEN);
// fd = inotify_init();
// if ( fd < 0 ) {
// throw std::runtime_error("inotify_init() error");
// }
// wd = inotify_add_watch( fd, file.parent_path().c_str(), mask);
// }
// int pollEvents() {
// std::string filename = file.filename();
// for (;;) {
// if ((currentEvent * sizeof(struct inotify_event)) >= readBytes) {
// for (;;) {
// int length = read(fd, buffer.data(), EVENT_BUF_LEN);
// if (length < 0) {
// throw std::runtime_error("length < 0");
// }
// if (length == 0) {
// continue;
// }
// readBytes = length;
// currentEvent = 0;
// break;
// }
// }
// for (; (currentEvent * sizeof(struct inotify_event)) < readBytes; currentEvent++) {
// struct inotify_event *event = reinterpret_cast<struct inotify_event *>(buffer.data()) + currentEvent;
// if (!event->len) {
// continue;
// }
// if (filename.compare(event->name) == 0) {
// currentEvent++;
// return event->mask;
// }
// }
// }
// }
// ~FileWatcher() {
// inotify_rm_watch(fd, wd);
// close(fd);
// }
//private:
// std::vector<char> buffer;
// int currentEvent = 0;
// int readBytes = 0;
// int fd = 0, wd = 0;
// core::filesystem::path file;
//};
#include <iostream>
#include <experimental/filesystem>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/fanotify.h>
#include <unistd.h>
#define EVENT_SIZE ( sizeof (struct fanotify_event_metadata) )
#define EVENT_BUF_LEN ( 1024 * ( EVENT_SIZE + 16 ) )
using namespace std;
namespace core {
using namespace std::experimental;
}
struct ApplicationInfo {
pid_t pid;
std::string name;
uid_t uid;
};
class FileWatcher {
public:
FileWatcher(core::filesystem::path _file, int events = FAN_CLOSE)
: file { std::move(_file) }
{
buffer.resize(EVENT_BUF_LEN);
fd = fanotify_init(FAN_CLOEXEC | FAN_CLASS_CONTENT, O_RDONLY | O_LARGEFILE);
if ( fd < 0 ) {
throw std::system_error(errno, std::generic_category());
}
if (fanotify_mark(fd, FAN_MARK_ADD, events | FAN_OPEN_PERM, AT_FDCWD, file.c_str()) == -1) {
throw std::system_error(errno, std::generic_category());
}
}
int pollEvents() {
std::string filename = file.filename();
for (;;) {
if (bytes < FAN_EVENT_METADATA_LEN) {
for (;;) {
int length = read(fd, buffer.data(), EVENT_BUF_LEN);
if (length < 0) {
throw std::runtime_error("length < 0");
}
if (length == 0) {
continue;
}
bytes = length;
shift = 0;
break;
}
}
const struct fanotify_event_metadata * metadata = reinterpret_cast<fanotify_event_metadata *>(buffer.data() + shift);
while (FAN_EVENT_OK(metadata, bytes)) {
auto ev = metadata;
metadata = FAN_EVENT_NEXT(metadata, bytes);
shift += sizeof(fanotify_event_metadata);
if (ev->mask & FAN_OPEN_PERM) {
struct fanotify_response resp;
resp.fd = ev->fd;
resp.response = FAN_ALLOW;
write(fd, &resp, sizeof(resp));
fsync(fd);
close(ev->fd);
continue;
}
return ev->mask;
}
}
}
~FileWatcher() {
close(fd);
}
private:
std::vector<char> buffer;
long shift = 0;
long bytes = 0;
//std::map<pid_t, ApplicationInfo> info;
int fd = 0, wd = 0;
core::filesystem::path file;
};
int main()
{
FileWatcher ev("/home/bastion/test/test1.txt");
for (;;) {
int res = ev.pollEvents();
std::cout << "event " << res << std::endl;
}
return 0;
}