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