Rev 13 | Rev 17 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
3 | luk | 1 | |
2 | /// inotify C++ interface implementation |
||
3 | /** |
||
4 | * \file inotify-cxx.cpp |
||
5 | * |
||
6 | * inotify C++ interface |
||
7 | * |
||
8 | * Copyright (C) 2006 Lukas Jelinek <lukas@aiken.cz> |
||
9 | * |
||
10 | * This program is free software; you can redistribute it and/or |
||
11 | * modify it under the terms of one of the following licenses: |
||
12 | * |
||
13 | * \li 1. X11-style license (see LICENSE-X11) |
||
14 | * \li 2. GNU Lesser General Public License, version 2.1 (see LICENSE-LGPL) |
||
15 | * \li 3. GNU General Public License, version 2 (see LICENSE-GPL) |
||
16 | * |
||
17 | * If you want to help with choosing the best license for you, |
||
18 | * please visit http://www.gnu.org/licenses/license-list.html. |
||
19 | * |
||
20 | */ |
||
21 | |||
22 | |||
23 | #include <errno.h> |
||
24 | #include <unistd.h> |
||
13 | luk | 25 | #include <fcntl.h> |
3 | luk | 26 | |
27 | #include "inotify-cxx.h" |
||
28 | |||
13 | luk | 29 | /// dump separator (between particular entries) |
3 | luk | 30 | #define DUMP_SEP \ |
31 | ({ \ |
||
32 | if (!rStr.empty()) { \ |
||
11 | luk | 33 | rStr.append(","); \ |
3 | luk | 34 | } \ |
35 | }) |
||
36 | |||
13 | luk | 37 | |
38 | int32_t InotifyEvent::GetDescriptor() const |
||
39 | { |
||
40 | return m_pWatch != NULL // if watch exists |
||
41 | ? m_pWatch->GetDescriptor() // return its descriptor |
||
42 | : -1; // else return -1 |
||
43 | } |
||
44 | |||
11 | luk | 45 | uint32_t InotifyEvent::GetMaskByName(const std::string& rName) |
46 | { |
||
47 | if (rName == "IN_ACCESS") |
||
48 | return IN_ACCESS; |
||
49 | else if (rName == "IN_MODIFY") |
||
50 | return IN_MODIFY; |
||
51 | else if (rName == "IN_ATTRIB") |
||
52 | return IN_ATTRIB; |
||
53 | else if (rName == "IN_CLOSE_WRITE") |
||
54 | return IN_CLOSE_WRITE; |
||
55 | else if (rName == "IN_CLOSE_NOWRITE") |
||
56 | return IN_CLOSE_NOWRITE; |
||
57 | else if (rName == "IN_MOVED_FROM") |
||
58 | return IN_MOVED_FROM; |
||
59 | else if (rName == "IN_MOVED_TO") |
||
60 | return IN_MOVED_TO; |
||
61 | else if (rName == "IN_CREATE") |
||
62 | return IN_CREATE; |
||
63 | else if (rName == "IN_DELETE") |
||
64 | return IN_DELETE; |
||
65 | else if (rName == "IN_DELETE_SELF") |
||
66 | return IN_DELETE_SELF; |
||
67 | else if (rName == "IN_UNMOUNT") |
||
68 | return IN_UNMOUNT; |
||
69 | else if (rName == "IN_Q_OVERFLOW") |
||
70 | return IN_Q_OVERFLOW; |
||
71 | else if (rName == "IN_IGNORED") |
||
72 | return IN_IGNORED; |
||
73 | else if (rName == "IN_CLOSE") |
||
74 | return IN_CLOSE; |
||
75 | else if (rName == "IN_MOVE") |
||
76 | return IN_MOVE; |
||
77 | else if (rName == "IN_ISDIR") |
||
78 | return IN_ISDIR; |
||
79 | else if (rName == "IN_ONESHOT") |
||
80 | return IN_ONESHOT; |
||
81 | else if (rName == "IN_ALL_EVENTS") |
||
82 | return IN_ALL_EVENTS; |
||
83 | |||
84 | return (uint32_t) 0; |
||
85 | } |
||
3 | luk | 86 | |
11 | luk | 87 | void InotifyEvent::DumpTypes(uint32_t uValue, std::string& rStr) |
3 | luk | 88 | { |
89 | rStr = ""; |
||
90 | |||
11 | luk | 91 | if (IsType(uValue, IN_ALL_EVENTS)) { |
92 | rStr.append("IN_ALL_EVENTS"); |
||
3 | luk | 93 | } |
11 | luk | 94 | else { |
95 | if (IsType(uValue, IN_ACCESS)) { |
||
96 | DUMP_SEP; |
||
97 | rStr.append("IN_ACCESS"); |
||
98 | } |
||
99 | if (IsType(uValue, IN_MODIFY)) { |
||
100 | DUMP_SEP; |
||
101 | rStr.append("IN_MODIFY"); |
||
102 | } |
||
103 | if (IsType(uValue, IN_ATTRIB)) { |
||
104 | DUMP_SEP; |
||
105 | rStr.append("IN_ATTRIB"); |
||
106 | } |
||
107 | if (IsType(uValue, IN_CREATE)) { |
||
108 | DUMP_SEP; |
||
109 | rStr.append("IN_CREATE"); |
||
110 | } |
||
111 | if (IsType(uValue, IN_DELETE)) { |
||
112 | DUMP_SEP; |
||
113 | rStr.append("IN_DELETE"); |
||
114 | } |
||
115 | if (IsType(uValue, IN_DELETE_SELF)) { |
||
116 | DUMP_SEP; |
||
117 | rStr.append("IN_DELETE_SELF"); |
||
118 | } |
||
119 | if (IsType(uValue, IN_OPEN)) { |
||
120 | DUMP_SEP; |
||
121 | rStr.append("IN_OPEN"); |
||
122 | } |
||
123 | if (IsType(uValue, IN_CLOSE)) { |
||
124 | DUMP_SEP; |
||
125 | rStr.append("IN_CLOSE"); |
||
126 | } |
||
127 | else { |
||
128 | if (IsType(uValue, IN_CLOSE_WRITE)) { |
||
129 | DUMP_SEP; |
||
130 | rStr.append("IN_CLOSE_WRITE"); |
||
131 | } |
||
132 | if (IsType(uValue, IN_CLOSE_NOWRITE)) { |
||
133 | DUMP_SEP; |
||
134 | rStr.append("IN_CLOSE_NOWRITE"); |
||
135 | } |
||
136 | } |
||
137 | if (IsType(uValue, IN_MOVE)) { |
||
138 | DUMP_SEP; |
||
139 | rStr.append("IN_MOVE"); |
||
140 | } |
||
141 | else { |
||
142 | if (IsType(uValue, IN_MOVED_FROM)) { |
||
143 | DUMP_SEP; |
||
144 | rStr.append("IN_MOVED_FROM"); |
||
145 | } |
||
146 | if (IsType(uValue, IN_MOVED_TO)) { |
||
147 | DUMP_SEP; |
||
148 | rStr.append("IN_MOVED_TO"); |
||
149 | } |
||
150 | } |
||
3 | luk | 151 | } |
11 | luk | 152 | if (IsType(uValue, IN_UNMOUNT)) { |
3 | luk | 153 | DUMP_SEP; |
154 | rStr.append("IN_UNMOUNT"); |
||
155 | } |
||
11 | luk | 156 | if (IsType(uValue, IN_Q_OVERFLOW)) { |
3 | luk | 157 | DUMP_SEP; |
158 | rStr.append("IN_Q_OVERFLOW"); |
||
159 | } |
||
11 | luk | 160 | if (IsType(uValue, IN_IGNORED)) { |
3 | luk | 161 | DUMP_SEP; |
162 | rStr.append("IN_IGNORED"); |
||
163 | } |
||
11 | luk | 164 | if (IsType(uValue, IN_ISDIR)) { |
3 | luk | 165 | DUMP_SEP; |
166 | rStr.append("IN_ISDIR"); |
||
167 | } |
||
11 | luk | 168 | if (IsType(uValue, IN_ONESHOT)) { |
3 | luk | 169 | DUMP_SEP; |
170 | rStr.append("IN_ONESHOT"); |
||
171 | } |
||
172 | } |
||
173 | |||
11 | luk | 174 | void InotifyEvent::DumpTypes(std::string& rStr) const |
175 | { |
||
13 | luk | 176 | DumpTypes(m_uMask, rStr); |
11 | luk | 177 | } |
3 | luk | 178 | |
11 | luk | 179 | |
13 | luk | 180 | Inotify::Inotify() throw (InotifyException) |
3 | luk | 181 | { |
13 | luk | 182 | m_fd = inotify_init(); |
183 | if (m_fd == -1) |
||
184 | throw InotifyException(std::string(__PRETTY_FUNCTION__) + ": inotify init failed", errno, NULL); |
||
3 | luk | 185 | } |
186 | |||
187 | Inotify::~Inotify() |
||
188 | { |
||
189 | Close(); |
||
190 | } |
||
191 | |||
192 | void Inotify::Close() |
||
193 | { |
||
194 | if (m_fd != -1) { |
||
195 | RemoveAll(); |
||
196 | close(m_fd); |
||
197 | m_fd = -1; |
||
198 | } |
||
199 | } |
||
200 | |||
13 | luk | 201 | void Inotify::Add(InotifyWatch* pWatch) throw (InotifyException) |
3 | luk | 202 | { |
203 | if (m_fd == -1) |
||
13 | luk | 204 | throw InotifyException(IN_EXC_MSG("invalid file descriptor"), EBUSY, this); |
3 | luk | 205 | |
206 | pWatch->m_wd = inotify_add_watch(m_fd, pWatch->GetPath().c_str(), pWatch->GetMask()); |
||
13 | luk | 207 | |
208 | if (pWatch->m_wd == -1) |
||
209 | throw InotifyException(IN_EXC_MSG("adding watch failed"), errno, this); |
||
210 | |||
211 | m_watches.insert(IN_WATCH_MAP::value_type(pWatch->m_wd, pWatch)); |
||
212 | pWatch->m_pInotify = this; |
||
3 | luk | 213 | } |
214 | |||
13 | luk | 215 | void Inotify::Remove(InotifyWatch* pWatch) throw (InotifyException) |
3 | luk | 216 | { |
217 | if (m_fd == -1) |
||
13 | luk | 218 | throw InotifyException(IN_EXC_MSG("invalid file descriptor"), EBUSY, this); |
3 | luk | 219 | |
13 | luk | 220 | if (inotify_rm_watch(m_fd, pWatch->GetMask()) == -1) |
221 | throw InotifyException(IN_EXC_MSG("removing watch failed"), errno, this); |
||
222 | |||
223 | m_watches.erase(pWatch->m_wd); |
||
224 | pWatch->m_wd = -1; |
||
225 | pWatch->m_pInotify = NULL; |
||
3 | luk | 226 | } |
227 | |||
228 | void Inotify::RemoveAll() |
||
229 | { |
||
230 | IN_WATCH_MAP::iterator it = m_watches.begin(); |
||
231 | while (it != m_watches.end()) { |
||
11 | luk | 232 | InotifyWatch* pW = (*it).second; |
233 | inotify_rm_watch(m_fd, pW->GetMask()); |
||
234 | pW->m_wd = -1; |
||
235 | pW->m_pInotify = NULL; |
||
3 | luk | 236 | it++; |
237 | } |
||
238 | |||
239 | m_watches.clear(); |
||
240 | } |
||
241 | |||
13 | luk | 242 | void Inotify::WaitForEvents(bool fNoIntr) throw (InotifyException) |
3 | luk | 243 | { |
244 | ssize_t len = 0; |
||
245 | |||
246 | do { |
||
247 | len = read(m_fd, m_buf, INOTIFY_BUFLEN); |
||
248 | } while (fNoIntr && len == -1 && errno == EINTR); |
||
249 | |||
15 | luk | 250 | if (errno == EWOULDBLOCK) |
251 | return; |
||
252 | |||
13 | luk | 253 | if (len < 0) |
254 | throw InotifyException(IN_EXC_MSG("reading events failed"), errno, this); |
||
3 | luk | 255 | |
256 | ssize_t i = 0; |
||
257 | while (i < len) { |
||
13 | luk | 258 | struct inotify_event* pEvt = (struct inotify_event*) &m_buf[i]; |
259 | InotifyWatch* pW = FindWatch(pEvt->wd); |
||
260 | if (pW != NULL && pW->IsEnabled()) { |
||
261 | InotifyEvent evt(pEvt, pW); |
||
262 | m_events.push_back(evt); |
||
263 | } |
||
264 | i += INOTIFY_EVENT_SIZE + (ssize_t) pEvt->len; |
||
3 | luk | 265 | } |
266 | } |
||
267 | |||
268 | int Inotify::GetEventCount() |
||
269 | { |
||
270 | return m_events.size(); |
||
271 | } |
||
272 | |||
13 | luk | 273 | bool Inotify::GetEvent(InotifyEvent* pEvt) throw (InotifyException) |
3 | luk | 274 | { |
13 | luk | 275 | bool b = PeekEvent(pEvt); |
276 | |||
3 | luk | 277 | if (b) |
278 | m_events.pop_front(); |
||
13 | luk | 279 | |
3 | luk | 280 | return b; |
281 | } |
||
282 | |||
13 | luk | 283 | bool Inotify::PeekEvent(InotifyEvent* pEvt) throw (InotifyException) |
3 | luk | 284 | { |
13 | luk | 285 | if (pEvt == NULL) |
286 | throw InotifyException(IN_EXC_MSG("null pointer to event"), EINVAL, this); |
||
3 | luk | 287 | |
13 | luk | 288 | if (!m_events.empty()) { |
289 | *pEvt = m_events.front(); |
||
290 | return true; |
||
291 | } |
||
292 | |||
293 | return false; |
||
3 | luk | 294 | } |
295 | |||
296 | InotifyWatch* Inotify::FindWatch(int iDescriptor) |
||
297 | { |
||
298 | IN_WATCH_MAP::iterator it = m_watches.find(iDescriptor); |
||
299 | if (it == m_watches.end()) |
||
300 | return NULL; |
||
301 | |||
302 | return (*it).second; |
||
303 | } |
||
304 | |||
13 | luk | 305 | void Inotify::SetNonBlock(bool fNonBlock) throw (InotifyException) |
306 | { |
||
307 | if (m_fd == -1) |
||
308 | throw InotifyException(IN_EXC_MSG("invalid file descriptor"), EBUSY, this); |
||
309 | |||
310 | int res = fcntl(m_fd, F_GETFL); |
||
311 | if (res == -1) |
||
312 | throw InotifyException(IN_EXC_MSG("cannot get inotify flags"), errno, this); |
||
313 | |||
314 | if (fNonBlock) { |
||
315 | res |= O_NONBLOCK; |
||
316 | } |
||
317 | else { |
||
318 | res &= ~O_NONBLOCK; |
||
319 | } |
||
320 | |||
321 | if (fcntl(m_fd, F_SETFL, res) == -1) |
||
322 | throw InotifyException(IN_EXC_MSG("cannot set inotify flags"), errno, this); |
||
323 | } |
||
324 |