Created
October 27, 2020 18:49
-
-
Save caiorss/6e3fc8a39a3a6089ad7002738e4d509a to your computer and use it in GitHub Desktop.
Linux-only Inotify API sample code
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <iostream> | |
#include <string> | |
#include <cstring> // strerror() | |
#include <memory> | |
#include <cassert> | |
#include <map> | |
// ---- Unix-specific headers ----------// | |
#include <unistd.h> | |
#include <limits.h> | |
// ---- Linux-specific headers --------// | |
#include <sys/inotify.h> | |
constexpr int FAILURE = -1; | |
void exit_on_failure(int fd, const char* error_message) | |
{ | |
if(fd != FAILURE){ return; } | |
int err = errno; | |
std::fprintf( stderr, " [ERROR] %s ; errno = %d ; errno-msg = %s \n" | |
, error_message, err, strerror(err)); | |
// Execute exit system call and terminate this process. | |
exit(1); | |
} | |
int main(int argc, char** argv) | |
{ | |
// Create inotify instance, returning file descriptor | |
int fd_inotify = ::inotify_init(); | |
exit_on_failure(fd_inotify, "Cannot create Inotify instance"); | |
using WatcheFileDescriptor = int; | |
using DirectoryPath = std::string; | |
auto watch_table = std::map<WatcheFileDescriptor, DirectoryPath>{}; | |
if(argc < 2){ | |
std::fprintf(stderr, " [ERROR] Requires one or more directories to be watched. \n"); | |
return EXIT_FAILURE; | |
} | |
for(int i = 1; i < argc; i++) | |
{ | |
const char* directory = argv[i]; | |
// Create watch instance, returning a file descriptor for the watcher | |
int fd_watch = inotify_add_watch(fd_inotify, directory, IN_ALL_EVENTS); | |
// Error checking | |
std::string error_msg = std::string("Cannot create watcher for this directory: ") + directory; | |
exit_on_failure(fd_watch, error_msg.c_str()); | |
watch_table[fd_watch] = directory; | |
std::fprintf( stdout, " [INFO] Watching directory => wd = %d ; directory = %s \n" | |
, fd_watch, directory); | |
} | |
// Maximum number of events | |
constexpr size_t MAX_EVENTS = 1024; | |
// Size of data structure inotify_event in bytes | |
constexpr size_t EVENT_SIZE = sizeof(struct inotify_event); | |
// Lenght of buffer for events storage in bytes | |
constexpr size_t BUFFER_LENGTH = MAX_EVENTS * ( EVENT_SIZE + NAME_MAX + 1 ); | |
std::uint8_t buffer[BUFFER_LENGTH]; | |
// -------------- Inotify event loop ----------------// | |
for(;;) | |
{ | |
// std::fprintf(stderr, " [INFO] Waiting for Inotify event \n"); | |
// nn_read => signed number of bytes read from the file descriptor | |
// It is (-1) in the case of errrors. | |
ssize_t nn_read = read(fd_inotify, buffer, BUFFER_LENGTH); | |
assert(nn_read != -1 && "Placeholder for future error handling."); | |
ssize_t offset = 0; | |
// Iterate over all events | |
while( offset < nn_read ) | |
{ | |
auto event = reinterpret_cast<inotify_event*>(buffer + offset); | |
auto directory = watch_table[event->wd]; | |
// Create file | |
if(event->mask & IN_CREATE && !(event->mask & IN_ISDIR) ) | |
std::fprintf(stdout | |
, " [INFO] CREATE file event => (file = %s ) ; (dir = %s) \n" | |
, event->name, directory.c_str()); | |
// Create directory event | |
if(event->mask & IN_CREATE && event->mask & IN_ISDIR ) | |
std::fprintf( stdout | |
, " [INFO] CREATE directory event => (file = %s ) ; (dir = %s) \n" | |
, event->name, directory.c_str()); | |
// Delete file or directory event. | |
if(event->mask & IN_DELETE) | |
std::fprintf( stdout, " [INFO] DELETE file event => (file = %s ) ; (dir = %s) \n" | |
, event->name, directory.c_str()); | |
// Modify file | |
if( event->mask & IN_MODIFY && !(event->mask & IN_ISDIR) ) | |
std::fprintf( stdout | |
, " [INFO] MODIFY file event => (file = %s ) ; (dir = %s) \n" | |
, event->name, directory.c_str()); | |
// Event happens when file system is unmounted. | |
if(event->mask & IN_IGNORED) | |
std::fprintf( stdout | |
, " [INFO] IGNRED file monitor removed or file system unmounted => dir = %s \n" | |
, directory.c_str()); | |
offset = offset + EVENT_SIZE + event->len; | |
} | |
} // --------- End of Inotify event loop() --------------// | |
//free(event); | |
std::fprintf(stdout, " [INFO] Terminate application gracefully \n\n"); | |
close(fd_inotify); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment