Rev 39 | 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 | * |
||
103 | luk | 8 | * Copyright (C) 2006, 2007, 2009 Lukas Jelinek <lukas@aiken.cz> |
3 | luk | 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. |
||
103 | luk | 19 | * |
20 | * Credits: |
||
21 | * Mike Frysinger (cleanup of includes) |
||
3 | luk | 22 | * |
23 | */ |
||
24 | |||
25 | |||
26 | #include <errno.h> |
||
27 | #include <unistd.h> |
||
13 | luk | 28 | #include <fcntl.h> |
103 | luk | 29 | #include <fstream> |
3 | luk | 30 | |
103 | luk | 31 | #include <sys/syscall.h> |
32 | |||
33 | // Use this if syscalls not defined |
||
34 | #ifndef __NR_inotify_init |
||
35 | #include <sys/inotify-syscalls.h> |
||
36 | #endif // __NR_inotify_init |
||
37 | |||
3 | luk | 38 | #include "inotify-cxx.h" |
39 | |||
29 | luk | 40 | /// procfs inotify base path |
41 | #define PROCFS_INOTIFY_BASE "/proc/sys/fs/inotify/" |
||
42 | |||
13 | luk | 43 | /// dump separator (between particular entries) |
3 | luk | 44 | #define DUMP_SEP \ |
45 | ({ \ |
||
46 | if (!rStr.empty()) { \ |
||
11 | luk | 47 | rStr.append(","); \ |
3 | luk | 48 | } \ |
49 | }) |
||
50 | |||
13 | luk | 51 | |
23 | luk | 52 | |
13 | luk | 53 | int32_t InotifyEvent::GetDescriptor() const |
54 | { |
||
55 | return m_pWatch != NULL // if watch exists |
||
56 | ? m_pWatch->GetDescriptor() // return its descriptor |
||
57 | : -1; // else return -1 |
||
58 | } |
||
59 | |||
11 | luk | 60 | uint32_t InotifyEvent::GetMaskByName(const std::string& rName) |
61 | { |
||
62 | if (rName == "IN_ACCESS") |
||
63 | return IN_ACCESS; |
||
64 | else if (rName == "IN_MODIFY") |
||
65 | return IN_MODIFY; |
||
66 | else if (rName == "IN_ATTRIB") |
||
67 | return IN_ATTRIB; |
||
68 | else if (rName == "IN_CLOSE_WRITE") |
||
69 | return IN_CLOSE_WRITE; |
||
70 | else if (rName == "IN_CLOSE_NOWRITE") |
||
71 | return IN_CLOSE_NOWRITE; |
||
25 | luk | 72 | else if (rName == "IN_OPEN") |
73 | return IN_OPEN; |
||
11 | luk | 74 | else if (rName == "IN_MOVED_FROM") |
75 | return IN_MOVED_FROM; |
||
76 | else if (rName == "IN_MOVED_TO") |
||
77 | return IN_MOVED_TO; |
||
78 | else if (rName == "IN_CREATE") |
||
79 | return IN_CREATE; |
||
80 | else if (rName == "IN_DELETE") |
||
81 | return IN_DELETE; |
||
82 | else if (rName == "IN_DELETE_SELF") |
||
83 | return IN_DELETE_SELF; |
||
84 | else if (rName == "IN_UNMOUNT") |
||
85 | return IN_UNMOUNT; |
||
86 | else if (rName == "IN_Q_OVERFLOW") |
||
87 | return IN_Q_OVERFLOW; |
||
88 | else if (rName == "IN_IGNORED") |
||
89 | return IN_IGNORED; |
||
90 | else if (rName == "IN_CLOSE") |
||
91 | return IN_CLOSE; |
||
92 | else if (rName == "IN_MOVE") |
||
93 | return IN_MOVE; |
||
94 | else if (rName == "IN_ISDIR") |
||
95 | return IN_ISDIR; |
||
96 | else if (rName == "IN_ONESHOT") |
||
97 | return IN_ONESHOT; |
||
98 | else if (rName == "IN_ALL_EVENTS") |
||
99 | return IN_ALL_EVENTS; |
||
100 | |||
17 | luk | 101 | #ifdef IN_DONT_FOLLOW |
102 | else if (rName == "IN_DONT_FOLLOW") |
||
103 | return IN_DONT_FOLLOW; |
||
104 | #endif // IN_DONT_FOLLOW |
||
105 | |||
106 | #ifdef IN_ONLYDIR |
||
107 | else if (rName == "IN_ONLYDIR") |
||
108 | return IN_ONLYDIR; |
||
109 | #endif // IN_ONLYDIR |
||
29 | luk | 110 | |
111 | #ifdef IN_MOVE_SELF |
||
112 | else if (rName == "IN_MOVE_SELF") |
||
113 | return IN_MOVE_SELF; |
||
114 | #endif // IN_MOVE_SELF |
||
17 | luk | 115 | |
11 | luk | 116 | return (uint32_t) 0; |
117 | } |
||
3 | luk | 118 | |
11 | luk | 119 | void InotifyEvent::DumpTypes(uint32_t uValue, std::string& rStr) |
3 | luk | 120 | { |
121 | rStr = ""; |
||
122 | |||
11 | luk | 123 | if (IsType(uValue, IN_ALL_EVENTS)) { |
124 | rStr.append("IN_ALL_EVENTS"); |
||
3 | luk | 125 | } |
11 | luk | 126 | else { |
127 | if (IsType(uValue, IN_ACCESS)) { |
||
128 | DUMP_SEP; |
||
129 | rStr.append("IN_ACCESS"); |
||
130 | } |
||
131 | if (IsType(uValue, IN_MODIFY)) { |
||
132 | DUMP_SEP; |
||
133 | rStr.append("IN_MODIFY"); |
||
134 | } |
||
135 | if (IsType(uValue, IN_ATTRIB)) { |
||
136 | DUMP_SEP; |
||
137 | rStr.append("IN_ATTRIB"); |
||
138 | } |
||
139 | if (IsType(uValue, IN_CREATE)) { |
||
140 | DUMP_SEP; |
||
141 | rStr.append("IN_CREATE"); |
||
142 | } |
||
143 | if (IsType(uValue, IN_DELETE)) { |
||
144 | DUMP_SEP; |
||
145 | rStr.append("IN_DELETE"); |
||
146 | } |
||
147 | if (IsType(uValue, IN_DELETE_SELF)) { |
||
148 | DUMP_SEP; |
||
149 | rStr.append("IN_DELETE_SELF"); |
||
150 | } |
||
151 | if (IsType(uValue, IN_OPEN)) { |
||
152 | DUMP_SEP; |
||
153 | rStr.append("IN_OPEN"); |
||
154 | } |
||
155 | if (IsType(uValue, IN_CLOSE)) { |
||
156 | DUMP_SEP; |
||
157 | rStr.append("IN_CLOSE"); |
||
158 | } |
||
35 | luk | 159 | |
160 | #ifdef IN_MOVE_SELF |
||
161 | if (IsType(uValue, IN_MOVE_SELF)) { |
||
162 | DUMP_SEP; |
||
163 | rStr.append("IN_MOVE_SELF"); |
||
164 | } |
||
165 | #endif // IN_MOVE_SELF |
||
166 | |||
11 | luk | 167 | else { |
168 | if (IsType(uValue, IN_CLOSE_WRITE)) { |
||
169 | DUMP_SEP; |
||
170 | rStr.append("IN_CLOSE_WRITE"); |
||
171 | } |
||
172 | if (IsType(uValue, IN_CLOSE_NOWRITE)) { |
||
173 | DUMP_SEP; |
||
174 | rStr.append("IN_CLOSE_NOWRITE"); |
||
175 | } |
||
176 | } |
||
177 | if (IsType(uValue, IN_MOVE)) { |
||
178 | DUMP_SEP; |
||
179 | rStr.append("IN_MOVE"); |
||
180 | } |
||
181 | else { |
||
182 | if (IsType(uValue, IN_MOVED_FROM)) { |
||
183 | DUMP_SEP; |
||
184 | rStr.append("IN_MOVED_FROM"); |
||
185 | } |
||
186 | if (IsType(uValue, IN_MOVED_TO)) { |
||
187 | DUMP_SEP; |
||
188 | rStr.append("IN_MOVED_TO"); |
||
189 | } |
||
190 | } |
||
3 | luk | 191 | } |
11 | luk | 192 | if (IsType(uValue, IN_UNMOUNT)) { |
3 | luk | 193 | DUMP_SEP; |
194 | rStr.append("IN_UNMOUNT"); |
||
195 | } |
||
11 | luk | 196 | if (IsType(uValue, IN_Q_OVERFLOW)) { |
3 | luk | 197 | DUMP_SEP; |
198 | rStr.append("IN_Q_OVERFLOW"); |
||
199 | } |
||
11 | luk | 200 | if (IsType(uValue, IN_IGNORED)) { |
3 | luk | 201 | DUMP_SEP; |
202 | rStr.append("IN_IGNORED"); |
||
203 | } |
||
11 | luk | 204 | if (IsType(uValue, IN_ISDIR)) { |
3 | luk | 205 | DUMP_SEP; |
206 | rStr.append("IN_ISDIR"); |
||
207 | } |
||
11 | luk | 208 | if (IsType(uValue, IN_ONESHOT)) { |
3 | luk | 209 | DUMP_SEP; |
210 | rStr.append("IN_ONESHOT"); |
||
211 | } |
||
17 | luk | 212 | |
213 | #ifdef IN_DONT_FOLLOW |
||
214 | if (IsType(uValue, IN_DONT_FOLLOW)) { |
||
215 | DUMP_SEP; |
||
216 | rStr.append("IN_DONT_FOLLOW"); |
||
217 | } |
||
218 | #endif // IN_DONT_FOLLOW |
||
219 | |||
220 | #ifdef IN_ONLYDIR |
||
221 | if (IsType(uValue, IN_ONLYDIR)) { |
||
222 | DUMP_SEP; |
||
223 | rStr.append("IN_ONLYDIR"); |
||
224 | } |
||
225 | #endif // IN_ONLYDIR |
||
3 | luk | 226 | } |
227 | |||
11 | luk | 228 | void InotifyEvent::DumpTypes(std::string& rStr) const |
229 | { |
||
13 | luk | 230 | DumpTypes(m_uMask, rStr); |
11 | luk | 231 | } |
3 | luk | 232 | |
11 | luk | 233 | |
17 | luk | 234 | void InotifyWatch::SetMask(uint32_t uMask) throw (InotifyException) |
235 | { |
||
21 | luk | 236 | IN_WRITE_BEGIN |
237 | |||
17 | luk | 238 | if (m_wd != -1) { |
239 | int wd = inotify_add_watch(m_pInotify->GetDescriptor(), m_path.c_str(), uMask); |
||
21 | luk | 240 | if (wd != m_wd) { |
241 | IN_WRITE_END_NOTHROW |
||
17 | luk | 242 | throw InotifyException(IN_EXC_MSG("changing mask failed"), wd == -1 ? errno : EINVAL, this); |
21 | luk | 243 | } |
17 | luk | 244 | } |
245 | |||
246 | m_uMask = uMask; |
||
21 | luk | 247 | |
248 | IN_WRITE_END |
||
17 | luk | 249 | } |
250 | |||
251 | void InotifyWatch::SetEnabled(bool fEnabled) throw (InotifyException) |
||
252 | { |
||
21 | luk | 253 | IN_WRITE_BEGIN |
254 | |||
255 | if (fEnabled == m_fEnabled) { |
||
256 | IN_WRITE_END_NOTHROW |
||
17 | luk | 257 | return; |
21 | luk | 258 | } |
17 | luk | 259 | |
260 | if (m_pInotify != NULL) { |
||
261 | if (fEnabled) { |
||
262 | m_wd = inotify_add_watch(m_pInotify->GetDescriptor(), m_path.c_str(), m_uMask); |
||
21 | luk | 263 | if (m_wd == -1) { |
264 | IN_WRITE_END_NOTHROW |
||
17 | luk | 265 | throw InotifyException(IN_EXC_MSG("enabling watch failed"), errno, this); |
21 | luk | 266 | } |
17 | luk | 267 | m_pInotify->m_watches.insert(IN_WATCH_MAP::value_type(m_wd, this)); |
268 | } |
||
269 | else { |
||
21 | luk | 270 | if (inotify_rm_watch(m_pInotify->GetDescriptor(), m_wd) != 0) { |
271 | IN_WRITE_END_NOTHROW |
||
17 | luk | 272 | throw InotifyException(IN_EXC_MSG("disabling watch failed"), errno, this); |
21 | luk | 273 | } |
17 | luk | 274 | m_pInotify->m_watches.erase(m_wd); |
275 | m_wd = -1; |
||
276 | } |
||
277 | } |
||
278 | |||
279 | m_fEnabled = fEnabled; |
||
21 | luk | 280 | |
281 | IN_WRITE_END |
||
17 | luk | 282 | } |
283 | |||
37 | luk | 284 | void InotifyWatch::__Disable() |
33 | luk | 285 | { |
286 | IN_WRITE_BEGIN |
||
287 | |||
288 | if (!m_fEnabled) { |
||
289 | IN_WRITE_END_NOTHROW |
||
290 | throw InotifyException(IN_EXC_MSG("event cannot occur on disabled watch"), EINVAL, this); |
||
291 | } |
||
292 | |||
293 | if (m_pInotify != NULL) { |
||
294 | m_pInotify->m_watches.erase(m_wd); |
||
295 | m_wd = -1; |
||
296 | } |
||
297 | |||
298 | m_fEnabled = false; |
||
299 | |||
300 | IN_WRITE_END |
||
301 | } |
||
17 | luk | 302 | |
33 | luk | 303 | |
13 | luk | 304 | Inotify::Inotify() throw (InotifyException) |
3 | luk | 305 | { |
21 | luk | 306 | IN_LOCK_INIT |
307 | |||
13 | luk | 308 | m_fd = inotify_init(); |
21 | luk | 309 | if (m_fd == -1) { |
310 | IN_LOCK_DONE |
||
17 | luk | 311 | throw InotifyException(IN_EXC_MSG("inotify init failed"), errno, NULL); |
21 | luk | 312 | } |
3 | luk | 313 | } |
314 | |||
315 | Inotify::~Inotify() |
||
316 | { |
||
317 | Close(); |
||
21 | luk | 318 | |
319 | IN_LOCK_DONE |
||
3 | luk | 320 | } |
321 | |||
322 | void Inotify::Close() |
||
323 | { |
||
21 | luk | 324 | IN_WRITE_BEGIN |
325 | |||
3 | luk | 326 | if (m_fd != -1) { |
327 | RemoveAll(); |
||
328 | close(m_fd); |
||
329 | m_fd = -1; |
||
330 | } |
||
21 | luk | 331 | |
332 | IN_WRITE_END |
||
3 | luk | 333 | } |
334 | |||
13 | luk | 335 | void Inotify::Add(InotifyWatch* pWatch) throw (InotifyException) |
3 | luk | 336 | { |
21 | luk | 337 | IN_WRITE_BEGIN |
338 | |||
17 | luk | 339 | // invalid descriptor - this case shouldn't occur - go away |
21 | luk | 340 | if (m_fd == -1) { |
341 | IN_WRITE_END_NOTHROW |
||
13 | luk | 342 | throw InotifyException(IN_EXC_MSG("invalid file descriptor"), EBUSY, this); |
21 | luk | 343 | } |
17 | luk | 344 | |
345 | // this path already watched - go away |
||
21 | luk | 346 | if (FindWatch(pWatch->GetPath()) != NULL) { |
347 | IN_WRITE_END_NOTHROW |
||
17 | luk | 348 | throw InotifyException(IN_EXC_MSG("path already watched"), EBUSY, this); |
21 | luk | 349 | } |
17 | luk | 350 | |
351 | // for enabled watch |
||
352 | if (pWatch->IsEnabled()) { |
||
3 | luk | 353 | |
17 | luk | 354 | // try to add watch to kernel |
355 | int wd = inotify_add_watch(m_fd, pWatch->GetPath().c_str(), pWatch->GetMask()); |
||
356 | |||
357 | // adding failed - go away |
||
21 | luk | 358 | if (wd == -1) { |
359 | IN_WRITE_END_NOTHROW |
||
17 | luk | 360 | throw InotifyException(IN_EXC_MSG("adding watch failed"), errno, this); |
21 | luk | 361 | } |
17 | luk | 362 | |
363 | // this path already watched (but defined another way) |
||
364 | InotifyWatch* pW = FindWatch(wd); |
||
365 | if (pW != NULL) { |
||
366 | |||
367 | // try to recover old watch because it may be modified - then go away |
||
368 | if (inotify_add_watch(m_fd, pW->GetPath().c_str(), pW->GetMask()) < 0) { |
||
21 | luk | 369 | IN_WRITE_END_NOTHROW |
17 | luk | 370 | throw InotifyException(IN_EXC_MSG("watch collision detected and recovery failed"), errno, this); |
371 | } |
||
372 | else { |
||
373 | // recovery failed - go away |
||
21 | luk | 374 | IN_WRITE_END_NOTHROW |
17 | luk | 375 | throw InotifyException(IN_EXC_MSG("path already watched (but defined another way)"), EBUSY, this); |
376 | } |
||
377 | } |
||
378 | |||
379 | pWatch->m_wd = wd; |
||
380 | m_watches.insert(IN_WATCH_MAP::value_type(pWatch->m_wd, pWatch)); |
||
381 | } |
||
382 | |||
383 | m_paths.insert(IN_WP_MAP::value_type(pWatch->m_path, pWatch)); |
||
13 | luk | 384 | pWatch->m_pInotify = this; |
21 | luk | 385 | |
386 | IN_WRITE_END |
||
3 | luk | 387 | } |
388 | |||
13 | luk | 389 | void Inotify::Remove(InotifyWatch* pWatch) throw (InotifyException) |
3 | luk | 390 | { |
21 | luk | 391 | IN_WRITE_BEGIN |
392 | |||
17 | luk | 393 | // invalid descriptor - this case shouldn't occur - go away |
21 | luk | 394 | if (m_fd == -1) { |
395 | IN_WRITE_END_NOTHROW |
||
13 | luk | 396 | throw InotifyException(IN_EXC_MSG("invalid file descriptor"), EBUSY, this); |
21 | luk | 397 | } |
17 | luk | 398 | |
399 | // for enabled watch |
||
400 | if (pWatch->m_wd != -1) { |
||
3 | luk | 401 | |
17 | luk | 402 | // removing watch failed - go away |
21 | luk | 403 | if (inotify_rm_watch(m_fd, pWatch->m_wd) == -1) { |
404 | IN_WRITE_END_NOTHROW |
||
17 | luk | 405 | throw InotifyException(IN_EXC_MSG("removing watch failed"), errno, this); |
21 | luk | 406 | } |
17 | luk | 407 | m_watches.erase(pWatch->m_wd); |
408 | pWatch->m_wd = -1; |
||
409 | } |
||
410 | |||
411 | m_paths.erase(pWatch->m_path); |
||
13 | luk | 412 | pWatch->m_pInotify = NULL; |
21 | luk | 413 | |
414 | IN_WRITE_END |
||
3 | luk | 415 | } |
416 | |||
417 | void Inotify::RemoveAll() |
||
418 | { |
||
21 | luk | 419 | IN_WRITE_BEGIN |
420 | |||
17 | luk | 421 | IN_WP_MAP::iterator it = m_paths.begin(); |
422 | while (it != m_paths.end()) { |
||
11 | luk | 423 | InotifyWatch* pW = (*it).second; |
17 | luk | 424 | if (pW->m_wd != -1) { |
425 | inotify_rm_watch(m_fd, pW->m_wd); |
||
426 | pW->m_wd = -1; |
||
427 | } |
||
11 | luk | 428 | pW->m_pInotify = NULL; |
3 | luk | 429 | it++; |
430 | } |
||
431 | |||
432 | m_watches.clear(); |
||
17 | luk | 433 | m_paths.clear(); |
21 | luk | 434 | |
435 | IN_WRITE_END |
||
3 | luk | 436 | } |
437 | |||
13 | luk | 438 | void Inotify::WaitForEvents(bool fNoIntr) throw (InotifyException) |
3 | luk | 439 | { |
440 | ssize_t len = 0; |
||
441 | |||
442 | do { |
||
443 | len = read(m_fd, m_buf, INOTIFY_BUFLEN); |
||
444 | } while (fNoIntr && len == -1 && errno == EINTR); |
||
445 | |||
27 | luk | 446 | if (len == -1 && !(errno == EWOULDBLOCK || errno == EINTR)) |
447 | throw InotifyException(IN_EXC_MSG("reading events failed"), errno, this); |
||
448 | |||
449 | if (len == -1) |
||
15 | luk | 450 | return; |
451 | |||
21 | luk | 452 | IN_WRITE_BEGIN |
453 | |||
3 | luk | 454 | ssize_t i = 0; |
455 | while (i < len) { |
||
13 | luk | 456 | struct inotify_event* pEvt = (struct inotify_event*) &m_buf[i]; |
457 | InotifyWatch* pW = FindWatch(pEvt->wd); |
||
17 | luk | 458 | if (pW != NULL) { |
13 | luk | 459 | InotifyEvent evt(pEvt, pW); |
37 | luk | 460 | if ( InotifyEvent::IsType(pW->GetMask(), IN_ONESHOT) |
461 | || InotifyEvent::IsType(evt.GetMask(), IN_IGNORED)) |
||
462 | pW->__Disable(); |
||
13 | luk | 463 | m_events.push_back(evt); |
464 | } |
||
465 | i += INOTIFY_EVENT_SIZE + (ssize_t) pEvt->len; |
||
3 | luk | 466 | } |
467 | |||
21 | luk | 468 | IN_WRITE_END |
3 | luk | 469 | } |
470 | |||
13 | luk | 471 | bool Inotify::GetEvent(InotifyEvent* pEvt) throw (InotifyException) |
3 | luk | 472 | { |
21 | luk | 473 | if (pEvt == NULL) |
474 | throw InotifyException(IN_EXC_MSG("null pointer to event"), EINVAL, this); |
||
13 | luk | 475 | |
21 | luk | 476 | IN_WRITE_BEGIN |
477 | |||
478 | bool b = !m_events.empty(); |
||
479 | if (b) { |
||
480 | *pEvt = m_events.front(); |
||
3 | luk | 481 | m_events.pop_front(); |
21 | luk | 482 | } |
483 | |||
484 | IN_WRITE_END |
||
13 | luk | 485 | |
3 | luk | 486 | return b; |
487 | } |
||
488 | |||
13 | luk | 489 | bool Inotify::PeekEvent(InotifyEvent* pEvt) throw (InotifyException) |
3 | luk | 490 | { |
13 | luk | 491 | if (pEvt == NULL) |
492 | throw InotifyException(IN_EXC_MSG("null pointer to event"), EINVAL, this); |
||
3 | luk | 493 | |
21 | luk | 494 | IN_READ_BEGIN |
495 | |||
496 | bool b = !m_events.empty(); |
||
497 | if (b) { |
||
13 | luk | 498 | *pEvt = m_events.front(); |
499 | } |
||
500 | |||
21 | luk | 501 | IN_READ_END |
502 | |||
503 | return b; |
||
3 | luk | 504 | } |
505 | |||
506 | InotifyWatch* Inotify::FindWatch(int iDescriptor) |
||
507 | { |
||
21 | luk | 508 | IN_READ_BEGIN |
509 | |||
3 | luk | 510 | IN_WATCH_MAP::iterator it = m_watches.find(iDescriptor); |
21 | luk | 511 | InotifyWatch* pW = it == m_watches.end() ? NULL : (*it).second; |
512 | |||
513 | IN_READ_END |
||
514 | |||
515 | return pW; |
||
3 | luk | 516 | } |
17 | luk | 517 | |
518 | InotifyWatch* Inotify::FindWatch(const std::string& rPath) |
||
519 | { |
||
21 | luk | 520 | IN_READ_BEGIN |
521 | |||
17 | luk | 522 | IN_WP_MAP::iterator it = m_paths.find(rPath); |
21 | luk | 523 | InotifyWatch* pW = it == m_paths.end() ? NULL : (*it).second; |
524 | |||
525 | IN_READ_END |
||
17 | luk | 526 | |
21 | luk | 527 | return pW; |
17 | luk | 528 | } |
3 | luk | 529 | |
13 | luk | 530 | void Inotify::SetNonBlock(bool fNonBlock) throw (InotifyException) |
531 | { |
||
21 | luk | 532 | IN_WRITE_BEGIN |
533 | |||
534 | if (m_fd == -1) { |
||
535 | IN_WRITE_END_NOTHROW |
||
13 | luk | 536 | throw InotifyException(IN_EXC_MSG("invalid file descriptor"), EBUSY, this); |
21 | luk | 537 | } |
13 | luk | 538 | |
539 | int res = fcntl(m_fd, F_GETFL); |
||
21 | luk | 540 | if (res == -1) { |
541 | IN_WRITE_END_NOTHROW |
||
13 | luk | 542 | throw InotifyException(IN_EXC_MSG("cannot get inotify flags"), errno, this); |
21 | luk | 543 | } |
13 | luk | 544 | |
545 | if (fNonBlock) { |
||
546 | res |= O_NONBLOCK; |
||
547 | } |
||
548 | else { |
||
549 | res &= ~O_NONBLOCK; |
||
550 | } |
||
551 | |||
21 | luk | 552 | if (fcntl(m_fd, F_SETFL, res) == -1) { |
553 | IN_WRITE_END_NOTHROW |
||
13 | luk | 554 | throw InotifyException(IN_EXC_MSG("cannot set inotify flags"), errno, this); |
21 | luk | 555 | } |
556 | |||
557 | IN_WRITE_END |
||
29 | luk | 558 | } |
13 | luk | 559 | |
39 | luk | 560 | void Inotify::SetCloseOnExec(bool fClOnEx) throw (InotifyException) |
561 | { |
||
562 | IN_WRITE_BEGIN |
||
563 | |||
564 | if (m_fd == -1) { |
||
565 | IN_WRITE_END_NOTHROW |
||
566 | throw InotifyException(IN_EXC_MSG("invalid file descriptor"), EBUSY, this); |
||
567 | } |
||
568 | |||
569 | int res = fcntl(m_fd, F_GETFD); |
||
570 | if (res == -1) { |
||
571 | IN_WRITE_END_NOTHROW |
||
572 | throw InotifyException(IN_EXC_MSG("cannot get inotify flags"), errno, this); |
||
573 | } |
||
574 | |||
575 | if (fClOnEx) { |
||
576 | res |= FD_CLOEXEC; |
||
577 | } |
||
578 | else { |
||
579 | res &= ~FD_CLOEXEC; |
||
580 | } |
||
581 | |||
582 | if (fcntl(m_fd, F_SETFD, res) == -1) { |
||
583 | IN_WRITE_END_NOTHROW |
||
584 | throw InotifyException(IN_EXC_MSG("cannot set inotify flags"), errno, this); |
||
585 | } |
||
586 | |||
587 | IN_WRITE_END |
||
588 | } |
||
589 | |||
29 | luk | 590 | uint32_t Inotify::GetCapability(InotifyCapability_t cap) throw (InotifyException) |
591 | { |
||
592 | FILE* f = fopen(GetCapabilityPath(cap).c_str(), "r"); |
||
593 | if (f == NULL) |
||
594 | throw InotifyException(IN_EXC_MSG("cannot get capability"), errno, NULL); |
||
595 | |||
596 | unsigned int val = 0; |
||
597 | if (fscanf(f, "%u", &val) != 1) { |
||
598 | fclose(f); |
||
599 | throw InotifyException(IN_EXC_MSG("cannot get capability"), EIO, NULL); |
||
600 | } |
||
601 | |||
602 | fclose(f); |
||
603 | |||
604 | return (uint32_t) val; |
||
605 | } |
||
606 | |||
607 | void Inotify::SetCapability(InotifyCapability_t cap, uint32_t val) throw (InotifyException) |
||
608 | { |
||
609 | FILE* f = fopen(GetCapabilityPath(cap).c_str(), "w"); |
||
610 | if (f == NULL) |
||
611 | throw InotifyException(IN_EXC_MSG("cannot set capability"), errno, NULL); |
||
612 | |||
613 | if (fprintf(f, "%u", (unsigned int) val) <= 0) { |
||
614 | fclose(f); |
||
615 | throw InotifyException(IN_EXC_MSG("cannot set capability"), EIO, NULL); |
||
616 | } |
||
617 | |||
618 | fclose(f); |
||
619 | } |
||
620 | |||
621 | std::string Inotify::GetCapabilityPath(InotifyCapability_t cap) throw (InotifyException) |
||
622 | { |
||
623 | std::string path(PROCFS_INOTIFY_BASE); |
||
624 | |||
625 | switch (cap) { |
||
626 | case IN_MAX_EVENTS: |
||
627 | path.append("max_queued_events"); |
||
628 | break; |
||
629 | case IN_MAX_INSTANCES: |
||
630 | path.append("max_user_instances"); |
||
631 | break; |
||
632 | case IN_MAX_WATCHES: |
||
633 | path.append("max_user_watches"); |
||
634 | break; |
||
635 | default: |
||
636 | throw InotifyException(IN_EXC_MSG("unknown capability type"), EINVAL, NULL); |
||
637 | } |
||
638 | |||
639 | return path; |
||
640 | } |
||
641 |