Last active
February 12, 2024 07:51
-
-
Save royratcliffe/8a8f383386d55ba63812ad076f669812 to your computer and use it in GitHub Desktop.
inotifyxx
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
{ | |
// Use IntelliSense to learn about possible attributes. | |
// Hover to view descriptions of existing attributes. | |
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 | |
"version": "0.2.0", | |
"configurations": [ | |
{ | |
"name": "(gdb) Launch", | |
"type": "cppdbg", | |
"request": "launch", | |
"program": "${workspaceFolder}/build/inotifyxx", | |
"args": [ | |
"." | |
], | |
"stopAtEntry": false, | |
"cwd": "${fileDirname}", | |
"environment": [], | |
"externalConsole": false, | |
"MIMode": "gdb", | |
"setupCommands": [ | |
{ | |
"description": "Enable pretty-printing for gdb", | |
"text": "-enable-pretty-printing", | |
"ignoreFailures": true | |
}, | |
{ | |
"description": "Set Disassembly Flavor to Intel", | |
"text": "-gdb-set disassembly-flavor intel", | |
"ignoreFailures": true | |
} | |
] | |
}, | |
// https://github.com/microsoft/vscode-cmake-tools/blob/main/docs/debug-launch.md | |
{ | |
"name": "(ctest) Launch", | |
"type": "cppdbg", | |
"request": "launch", | |
"cwd": "${cmake.testWorkingDirectory}", | |
"program": "${cmake.testProgram}", | |
"args": [ | |
"${cmake.testArgs}" | |
] | |
} | |
] | |
} |
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
{ | |
"files.associations": { | |
"map": "cpp", | |
"bit": "cpp", | |
"bitset": "cpp", | |
"cwchar": "cpp", | |
"string": "cpp", | |
"exception": "cpp", | |
"initializer_list": "cpp", | |
"iosfwd": "cpp", | |
"istream": "cpp", | |
"new": "cpp", | |
"ostream": "cpp", | |
"stdexcept": "cpp", | |
"streambuf": "cpp", | |
"tuple": "cpp", | |
"type_traits": "cpp", | |
"utility": "cpp", | |
"string_view": "cpp", | |
"array": "cpp", | |
"atomic": "cpp", | |
"*.tcc": "cpp", | |
"cctype": "cpp", | |
"clocale": "cpp", | |
"cmath": "cpp", | |
"compare": "cpp", | |
"concepts": "cpp", | |
"cstdarg": "cpp", | |
"cstddef": "cpp", | |
"cstdint": "cpp", | |
"cstdio": "cpp", | |
"cstdlib": "cpp", | |
"cwctype": "cpp", | |
"deque": "cpp", | |
"unordered_map": "cpp", | |
"vector": "cpp", | |
"algorithm": "cpp", | |
"functional": "cpp", | |
"iterator": "cpp", | |
"memory": "cpp", | |
"memory_resource": "cpp", | |
"numeric": "cpp", | |
"random": "cpp", | |
"system_error": "cpp", | |
"iostream": "cpp", | |
"limits": "cpp", | |
"numbers": "cpp", | |
"typeinfo": "cpp" | |
}, | |
"cmake.configureOnOpen": true, | |
"files.trimTrailingWhitespace": true, | |
"files.insertFinalNewline": true, | |
"files.trimFinalNewlines": true, | |
"editor.renderFinalNewline": "dimmed" | |
} |
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
cmake_minimum_required (VERSION 3.28) | |
project (inotifyxx) | |
add_executable (inotifyxx inotifyxx.cc) | |
set_property (TARGET inotifyxx PROPERTY CXX_STANDARD 20) | |
include (CTest) | |
create_test_sourcelist (Tests | |
tests.c | |
inotifyxx_test.cc | |
) | |
add_executable (tests ${Tests}) | |
set_property (TARGET tests PROPERTY CXX_STANDARD 20) | |
set (TestsToRun ${Tests}) | |
remove (TestsToRun tests.c) | |
foreach (test ${TestsToRun}) | |
get_filename_component (TName ${test} NAME_WE) | |
add_test (NAME ${TName} COMMAND tests ${TName}) | |
endforeach () |
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 "inotifyxx.hh" | |
#include <iostream> | |
int main(int argc, char **argv) { | |
sys::inotify inotify; | |
for (int optind = 1; optind < argc; optind++) | |
inotify.add_watch(argv[optind]); | |
for (;;) | |
if (inotify.poll(POLLIN, 1000) & POLLIN) | |
for (auto event : inotify.read()) { | |
std::cout << event.wd << "/" << event.name; | |
for (auto in : event.mask_to_strings()) | |
std::cout << " " << in; | |
std::cout << std::endl; | |
} | |
return EXIT_SUCCESS; | |
} |
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 <bit> | |
#include <bitset> | |
#include <cerrno> | |
#include <map> | |
#include <system_error> | |
#include <unordered_map> | |
#include <vector> | |
extern "C" { | |
#include <poll.h> | |
#include <sys/inotify.h> | |
#include <unistd.h> | |
} | |
namespace sys { | |
class inotify { | |
const int fd_; | |
std::unordered_map<int, std::string> wds_; | |
public: | |
inotify() : fd_{inotify_init1(IN_NONBLOCK)} { | |
if (fd_ < 0) | |
throw std::system_error(errno, std::system_category()); | |
} | |
int add_watch(const std::string &pathname, uint32_t mask = IN_ALL_EVENTS) { | |
const int wd = inotify_add_watch(fd_, pathname.c_str(), mask); | |
if (wd < 0) | |
throw std::system_error(errno, std::system_category()); | |
wds_.insert(std::make_pair(wd, pathname)); | |
return wd; | |
} | |
virtual ~inotify() { close(fd_); } | |
int poll(short events = POLLIN, int timeout = 0) { | |
pollfd fds = {fd_, events, 0}; | |
int rc = ::poll(&fds, 1, timeout); | |
if (rc < 0) | |
throw std::system_error(errno, std::system_category()); | |
// Polling returns a non-zero successful number of pollings. Answer the | |
// returned events. | |
return rc == 1 ? fds.revents : 0; | |
} | |
struct event { | |
std::string wd; | |
uint32_t mask; | |
std::string name; | |
auto mask_to_strings() const { | |
std::vector<std::string> strings; | |
static const std::map<int, std::string> in{ | |
{std::countr_zero(uint32_t(IN_ACCESS)), "ACCESS"}, | |
{std::countr_zero(uint32_t(IN_MODIFY)), "MODIFY"}, | |
{std::countr_zero(uint32_t(IN_ATTRIB)), "ATTRIB"}, | |
{std::countr_zero(uint32_t(IN_CLOSE_WRITE)), "CLOSE_WRITE"}, | |
{std::countr_zero(uint32_t(IN_CLOSE_NOWRITE)), "CLOSE_NOWRITE"}, | |
{std::countr_zero(uint32_t(IN_OPEN)), "OPEN"}, | |
{std::countr_zero(uint32_t(IN_MOVED_FROM)), "MOVED_FROM"}, | |
{std::countr_zero(uint32_t(IN_MOVED_TO)), "MOVED_TO"}, | |
{std::countr_zero(uint32_t(IN_CREATE)), "CREATE"}, | |
{std::countr_zero(uint32_t(IN_DELETE)), "DELETE"}, | |
{std::countr_zero(uint32_t(IN_DELETE_SELF)), "DELETE_SELF"}, | |
{std::countr_zero(uint32_t(IN_MOVE_SELF)), "MOVE_SELF"}, | |
{std::countr_zero(uint32_t(IN_UNMOUNT)), "UNMOUNT"}, | |
{std::countr_zero(uint32_t(IN_Q_OVERFLOW)), "Q_OVERFLOW"}, | |
{std::countr_zero(uint32_t(IN_IGNORED)), "IGNORED"}, | |
{std::countr_zero(uint32_t(IN_ONLYDIR)), "ONLYDIR"}, | |
{std::countr_zero(uint32_t(IN_DONT_FOLLOW)), "DONT_FOLLOW"}, | |
{std::countr_zero(uint32_t(IN_EXCL_UNLINK)), "EXCL_UNLINK"}, | |
{std::countr_zero(uint32_t(IN_MASK_CREATE)), "MASK_CREATE"}, | |
{std::countr_zero(uint32_t(IN_MASK_ADD)), "MASK_ADD"}, | |
{std::countr_zero(uint32_t(IN_ISDIR)), "ISDIR"}, | |
{std::countr_zero(uint32_t(IN_ONESHOT)), "ONESHOT"}}; | |
std::bitset<32> bitset{mask}; | |
while (bitset.any()) { | |
auto count = std::countr_zero(bitset.to_ulong()); | |
auto it = in.find(count); | |
strings.push_back(it == in.end() | |
? std::string("bit") + std::to_string(count) | |
: it->second); | |
bitset.reset(count); | |
} | |
return strings; | |
} | |
}; | |
std::vector<event> read() { | |
char buf[BUFSIZ]; | |
auto len = ::read(fd_, buf, sizeof(buf)); | |
if (len < 0) | |
throw std::system_error(errno, std::system_category()); | |
std::vector<event> events; | |
const inotify_event *event; | |
for (auto ptr = buf; ptr < buf + len; | |
ptr += sizeof(inotify_event) + event->len) { | |
event = reinterpret_cast<typeof(event)>(ptr); | |
// Assume that the event name carries a null terminator. The event's total | |
// length steps over the name and its terminator. | |
events.push_back( | |
inotify::event{.wd = wds_[event->wd], | |
.mask = event->mask, | |
.name = std::string(event->name)}); | |
} | |
return events; | |
} | |
}; | |
} // namespace sys |
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 "inotifyxx.hh" | |
int inotifyxx_test(int argc, char **argv) { return EXIT_SUCCESS; } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment