Brenta Engine 1.2
Loading...
Searching...
No Matches
fswatcher_unix.cpp
1// SPDX-License-Identifier: MIT
2// Author: Giovanni Santini
3// Mail: giovanni.santini@proton.me
4// Github: @San7o
5
6#ifndef _WIN32
7
8#include <brenta/fswatcher.hpp>
9#include <sys/inotify.h>
10
11namespace brenta
12{
13
15{
16 int wd;
17 uint32_t mask;
18 std::filesystem::path pathname;
20};
21
23{
24 int fd;
25 FsWatcherUnixWdList *wd_list;
26};
27
28} // namespace brenta
29
30using namespace brenta;
31
32#define _FSWATCHER_BUFFER_LEN (1024 * (sizeof(struct inotify_event) + 16))
33
34FilesystemWatcher::~FilesystemWatcher()
35{
36 this->destroy();
37}
38
39bool FilesystemWatcher::init()
40{
41 FsWatcherUnix* fw = new FsWatcherUnix();
42 fw->fd = inotify_init();
43 if (fw->fd == -1)
44 return false;
45
46 this->internal = static_cast<void*>(fw);
47 return true;
48}
49
50void FilesystemWatcher::destroy()
51{
52 if (!this->internal) return;
53
54 FsWatcherUnix *fw_unix = static_cast<FsWatcherUnix*>(this->internal);
55
56 close(fw_unix->fd);
57
58 FsWatcherUnixWdList *it = fw_unix->wd_list;
59 FsWatcherUnixWdList *next = NULL;
60 while (it)
61 {
62 next = it->next;
63 delete it;
64 it = next;
65 }
66
67 delete static_cast<FsWatcherUnix*>(this->internal);
68 this->internal = nullptr;
69}
70
71bool FilesystemWatcher::add(const std::filesystem::path &path,
72 tenno::vector<Event> events)
73{
74 if (!this->internal) return false;
75
76 FsWatcherUnix *fw_unix = static_cast<FsWatcherUnix*>(this->internal);
77 uint32_t mask = 0;
78
79 for (auto event : events)
80 {
81 switch(event)
82 {
83 case Event::Modify: mask |= IN_MODIFY; break;
84 default:
85 break;
86 }
87 }
88 int wd = inotify_add_watch(fw_unix->fd, path.c_str(), mask);
89 if (wd == -1)
90 return false;
91
93 wd_item->wd = wd;
94 wd_item->pathname = path;
95 wd_item->mask = mask;
96 wd_item->next = NULL;
97
98 if (!fw_unix->wd_list)
99 {
100 fw_unix->wd_list = wd_item;
101 return true;
102 }
103
104 FsWatcherUnixWdList *it = fw_unix->wd_list;
105 while(it->next) { it = it->next; }
106 it->next = wd_item;
107 return true;
108}
109
110bool FilesystemWatcher::add(const tenno::vector<std::filesystem::path> &paths,
111 tenno::vector<Event> events)
112{
113 bool out = true;
114 for (auto& path : paths)
115 {
116 out |= this->add(path, events);
117 }
118 return out;
119}
120
121bool FilesystemWatcher::rm(const std::filesystem::path &path)
122{
123 if (!this->internal) return false;
124 FsWatcherUnix *fw_unix = static_cast<FsWatcherUnix*>(this->internal);
125
126 FsWatcherUnixWdList *prev = NULL;
127 FsWatcherUnixWdList *it = fw_unix->wd_list;
128 while(it && it->pathname != path)
129 { prev = it; it = it->next; }
130
131 if (!it)
132 return true;
133
134 int ret = inotify_rm_watch(fw_unix->fd, it->wd);
135 if (ret == -1)
136 return -1;
137
138 if (!prev)
139 fw_unix->wd_list = it->next;
140 else
141 prev->next = it->next;
142
143 delete it;
144 return true;
145}
146
147bool FilesystemWatcher::rm(const tenno::vector<std::filesystem::path> &paths)
148{
149 bool out = true;
150 for (auto& path : paths)
151 {
152 out |= this->rm(path);
153 }
154 return out;
155}
156
157std::optional<std::filesystem::path> FilesystemWatcher::watch()
158{
159 if (!this->internal) return {};
160 FsWatcherUnix *fw_unix = static_cast<FsWatcherUnix*>(this->internal);
161
162 char buff[_FSWATCHER_BUFFER_LEN] = {0};
163 ssize_t bytes = read(fw_unix->fd, &buff, sizeof(buff));
164 if (bytes == -1 || bytes == 0)
165 return {};
166
167 for (char *ptr = buff; ptr < buff + bytes; )
168 {
169 struct inotify_event *ev = (struct inotify_event *) ptr;
170
171 FsWatcherUnixWdList *it = fw_unix->wd_list;
172 while (it && ev->wd != it->wd) { it = it->next; }
173 if (it)
174 return it->pathname;
175
176 ptr += sizeof(struct inotify_event) + ev->len;
177 }
178
179 return {};
180}
181
182#endif // _WIN32