Rev 21 | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 21 | Rev 22 | ||
---|---|---|---|
1 | 1 | ||
2 | /// inotify C++ interface implementation
|
2 | /// inotify C++ interface implementation
|
3 | /**
|
3 | /**
|
4 | * \file inotify-cxx.cpp
|
4 | * \file inotify-cxx.cpp
|
5 | *
|
5 | *
|
6 | * inotify C++ interface
|
6 | * inotify C++ interface
|
7 | *
|
7 | *
|
8 | * Copyright (C) 2006 Lukas Jelinek <lukas@aiken.cz>
|
8 | * Copyright (C) 2006 Lukas Jelinek <lukas@aiken.cz>
|
9 | *
|
9 | *
|
10 | * This program is free software; you can redistribute it and/or
|
10 | * This program is free software; you can redistribute it and/or
|
11 | * modify it under the terms of one of the following licenses:
|
11 | * modify it under the terms of one of the following licenses:
|
12 | *
|
12 | *
|
13 | * \li 1. X11-style license (see LICENSE-X11)
|
13 | * \li 1. X11-style license (see LICENSE-X11)
|
14 | * \li 2. GNU Lesser General Public License, version 2.1 (see LICENSE-LGPL)
|
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)
|
15 | * \li 3. GNU General Public License, version 2 (see LICENSE-GPL)
|
16 | *
|
16 | *
|
17 | * If you want to help with choosing the best license for you,
|
17 | * If you want to help with choosing the best license for you,
|
18 | * please visit http://www.gnu.org/licenses/license-list.html.
|
18 | * please visit http://www.gnu.org/licenses/license-list.html.
|
19 | *
|
19 | *
|
20 | */
|
20 | */
|
21 | 21 | ||
22 | 22 | ||
23 | #include <errno.h>
|
23 | #include <errno.h>
|
24 | #include <unistd.h>
|
24 | #include <unistd.h>
|
25 | #include <fcntl.h>
|
25 | #include <fcntl.h>
|
26 | 26 | ||
27 | #include "inotify-cxx.h"
|
27 | #include "inotify-cxx.h"
|
28 | 28 | ||
29 | /// dump separator (between particular entries)
|
29 | /// dump separator (between particular entries)
|
30 | #define DUMP_SEP \
|
30 | #define DUMP_SEP \
|
31 | ({ \
|
31 | ({ \
|
32 | if (!rStr.empty()) { \
|
32 | if (!rStr.empty()) { \
|
33 | rStr.append(","); \
|
33 | rStr.append(","); \
|
34 | } \
|
34 | } \
|
35 | })
|
35 | })
|
36 | 36 | ||
37 | 37 | ||
38 | int32_t InotifyEvent::GetDescriptor() const |
38 | int32_t InotifyEvent::GetDescriptor() const |
39 | {
|
39 | {
|
40 | return m_pWatch != NULL // if watch exists |
40 | return m_pWatch != NULL // if watch exists |
41 | ? m_pWatch->GetDescriptor() // return its descriptor |
41 | ? m_pWatch->GetDescriptor() // return its descriptor |
42 | : -1; // else return -1 |
42 | : -1; // else return -1 |
43 | }
|
43 | }
|
44 | 44 | ||
45 | uint32_t InotifyEvent::GetMaskByName(const std::string& rName) |
45 | uint32_t InotifyEvent::GetMaskByName(const std::string& rName) |
46 | {
|
46 | {
|
47 | if (rName == "IN_ACCESS") |
47 | if (rName == "IN_ACCESS") |
48 | return IN_ACCESS; |
48 | return IN_ACCESS; |
49 | else if (rName == "IN_MODIFY") |
49 | else if (rName == "IN_MODIFY") |
50 | return IN_MODIFY; |
50 | return IN_MODIFY; |
51 | else if (rName == "IN_ATTRIB") |
51 | else if (rName == "IN_ATTRIB") |
52 | return IN_ATTRIB; |
52 | return IN_ATTRIB; |
53 | else if (rName == "IN_CLOSE_WRITE") |
53 | else if (rName == "IN_CLOSE_WRITE") |
54 | return IN_CLOSE_WRITE; |
54 | return IN_CLOSE_WRITE; |
55 | else if (rName == "IN_CLOSE_NOWRITE") |
55 | else if (rName == "IN_CLOSE_NOWRITE") |
56 | return IN_CLOSE_NOWRITE; |
56 | return IN_CLOSE_NOWRITE; |
57 | else if (rName == "IN_MOVED_FROM") |
57 | else if (rName == "IN_MOVED_FROM") |
58 | return IN_MOVED_FROM; |
58 | return IN_MOVED_FROM; |
59 | else if (rName == "IN_MOVED_TO") |
59 | else if (rName == "IN_MOVED_TO") |
60 | return IN_MOVED_TO; |
60 | return IN_MOVED_TO; |
61 | else if (rName == "IN_CREATE") |
61 | else if (rName == "IN_CREATE") |
62 | return IN_CREATE; |
62 | return IN_CREATE; |
63 | else if (rName == "IN_DELETE") |
63 | else if (rName == "IN_DELETE") |
64 | return IN_DELETE; |
64 | return IN_DELETE; |
65 | else if (rName == "IN_DELETE_SELF") |
65 | else if (rName == "IN_DELETE_SELF") |
66 | return IN_DELETE_SELF; |
66 | return IN_DELETE_SELF; |
67 | else if (rName == "IN_UNMOUNT") |
67 | else if (rName == "IN_UNMOUNT") |
68 | return IN_UNMOUNT; |
68 | return IN_UNMOUNT; |
69 | else if (rName == "IN_Q_OVERFLOW") |
69 | else if (rName == "IN_Q_OVERFLOW") |
70 | return IN_Q_OVERFLOW; |
70 | return IN_Q_OVERFLOW; |
71 | else if (rName == "IN_IGNORED") |
71 | else if (rName == "IN_IGNORED") |
72 | return IN_IGNORED; |
72 | return IN_IGNORED; |
73 | else if (rName == "IN_CLOSE") |
73 | else if (rName == "IN_CLOSE") |
74 | return IN_CLOSE; |
74 | return IN_CLOSE; |
75 | else if (rName == "IN_MOVE") |
75 | else if (rName == "IN_MOVE") |
76 | return IN_MOVE; |
76 | return IN_MOVE; |
77 | else if (rName == "IN_ISDIR") |
77 | else if (rName == "IN_ISDIR") |
78 | return IN_ISDIR; |
78 | return IN_ISDIR; |
79 | else if (rName == "IN_ONESHOT") |
79 | else if (rName == "IN_ONESHOT") |
80 | return IN_ONESHOT; |
80 | return IN_ONESHOT; |
81 | else if (rName == "IN_ALL_EVENTS") |
81 | else if (rName == "IN_ALL_EVENTS") |
82 | return IN_ALL_EVENTS; |
82 | return IN_ALL_EVENTS; |
83 | 83 | ||
84 | #ifdef IN_DONT_FOLLOW
|
84 | #ifdef IN_DONT_FOLLOW
|
85 | else if (rName == "IN_DONT_FOLLOW") |
85 | else if (rName == "IN_DONT_FOLLOW") |
86 | return IN_DONT_FOLLOW; |
86 | return IN_DONT_FOLLOW; |
87 | #endif // IN_DONT_FOLLOW
|
87 | #endif // IN_DONT_FOLLOW
|
88 | 88 | ||
89 | #ifdef IN_ONLYDIR
|
89 | #ifdef IN_ONLYDIR
|
90 | else if (rName == "IN_ONLYDIR") |
90 | else if (rName == "IN_ONLYDIR") |
91 | return IN_ONLYDIR; |
91 | return IN_ONLYDIR; |
92 | #endif // IN_ONLYDIR
|
92 | #endif // IN_ONLYDIR
|
93 | 93 | ||
94 | return (uint32_t) 0; |
94 | return (uint32_t) 0; |
95 | }
|
95 | }
|
96 | 96 | ||
97 | void InotifyEvent::DumpTypes(uint32_t uValue, std::string& rStr) |
97 | void InotifyEvent::DumpTypes(uint32_t uValue, std::string& rStr) |
98 | {
|
98 | {
|
99 | rStr = ""; |
99 | rStr = ""; |
100 | 100 | ||
101 | if (IsType(uValue, IN_ALL_EVENTS)) { |
101 | if (IsType(uValue, IN_ALL_EVENTS)) { |
102 | rStr.append("IN_ALL_EVENTS"); |
102 | rStr.append("IN_ALL_EVENTS"); |
103 | }
|
103 | }
|
104 | else { |
104 | else { |
105 | if (IsType(uValue, IN_ACCESS)) { |
105 | if (IsType(uValue, IN_ACCESS)) { |
106 | DUMP_SEP;
|
106 | DUMP_SEP;
|
107 | rStr.append("IN_ACCESS"); |
107 | rStr.append("IN_ACCESS"); |
108 | }
|
108 | }
|
109 | if (IsType(uValue, IN_MODIFY)) { |
109 | if (IsType(uValue, IN_MODIFY)) { |
110 | DUMP_SEP;
|
110 | DUMP_SEP;
|
111 | rStr.append("IN_MODIFY"); |
111 | rStr.append("IN_MODIFY"); |
112 | }
|
112 | }
|
113 | if (IsType(uValue, IN_ATTRIB)) { |
113 | if (IsType(uValue, IN_ATTRIB)) { |
114 | DUMP_SEP;
|
114 | DUMP_SEP;
|
115 | rStr.append("IN_ATTRIB"); |
115 | rStr.append("IN_ATTRIB"); |
116 | }
|
116 | }
|
117 | if (IsType(uValue, IN_CREATE)) { |
117 | if (IsType(uValue, IN_CREATE)) { |
118 | DUMP_SEP;
|
118 | DUMP_SEP;
|
119 | rStr.append("IN_CREATE"); |
119 | rStr.append("IN_CREATE"); |
120 | }
|
120 | }
|
121 | if (IsType(uValue, IN_DELETE)) { |
121 | if (IsType(uValue, IN_DELETE)) { |
122 | DUMP_SEP;
|
122 | DUMP_SEP;
|
123 | rStr.append("IN_DELETE"); |
123 | rStr.append("IN_DELETE"); |
124 | }
|
124 | }
|
125 | if (IsType(uValue, IN_DELETE_SELF)) { |
125 | if (IsType(uValue, IN_DELETE_SELF)) { |
126 | DUMP_SEP;
|
126 | DUMP_SEP;
|
127 | rStr.append("IN_DELETE_SELF"); |
127 | rStr.append("IN_DELETE_SELF"); |
128 | }
|
128 | }
|
129 | if (IsType(uValue, IN_OPEN)) { |
129 | if (IsType(uValue, IN_OPEN)) { |
130 | DUMP_SEP;
|
130 | DUMP_SEP;
|
131 | rStr.append("IN_OPEN"); |
131 | rStr.append("IN_OPEN"); |
132 | }
|
132 | }
|
133 | if (IsType(uValue, IN_CLOSE)) { |
133 | if (IsType(uValue, IN_CLOSE)) { |
134 | DUMP_SEP;
|
134 | DUMP_SEP;
|
135 | rStr.append("IN_CLOSE"); |
135 | rStr.append("IN_CLOSE"); |
136 | }
|
136 | }
|
137 | else { |
137 | else { |
138 | if (IsType(uValue, IN_CLOSE_WRITE)) { |
138 | if (IsType(uValue, IN_CLOSE_WRITE)) { |
139 | DUMP_SEP;
|
139 | DUMP_SEP;
|
140 | rStr.append("IN_CLOSE_WRITE"); |
140 | rStr.append("IN_CLOSE_WRITE"); |
141 | }
|
141 | }
|
142 | if (IsType(uValue, IN_CLOSE_NOWRITE)) { |
142 | if (IsType(uValue, IN_CLOSE_NOWRITE)) { |
143 | DUMP_SEP;
|
143 | DUMP_SEP;
|
144 | rStr.append("IN_CLOSE_NOWRITE"); |
144 | rStr.append("IN_CLOSE_NOWRITE"); |
145 | }
|
145 | }
|
146 | }
|
146 | }
|
147 | if (IsType(uValue, IN_MOVE)) { |
147 | if (IsType(uValue, IN_MOVE)) { |
148 | DUMP_SEP;
|
148 | DUMP_SEP;
|
149 | rStr.append("IN_MOVE"); |
149 | rStr.append("IN_MOVE"); |
150 | }
|
150 | }
|
151 | else { |
151 | else { |
152 | if (IsType(uValue, IN_MOVED_FROM)) { |
152 | if (IsType(uValue, IN_MOVED_FROM)) { |
153 | DUMP_SEP;
|
153 | DUMP_SEP;
|
154 | rStr.append("IN_MOVED_FROM"); |
154 | rStr.append("IN_MOVED_FROM"); |
155 | }
|
155 | }
|
156 | if (IsType(uValue, IN_MOVED_TO)) { |
156 | if (IsType(uValue, IN_MOVED_TO)) { |
157 | DUMP_SEP;
|
157 | DUMP_SEP;
|
158 | rStr.append("IN_MOVED_TO"); |
158 | rStr.append("IN_MOVED_TO"); |
159 | }
|
159 | }
|
160 | }
|
160 | }
|
161 | }
|
161 | }
|
162 | if (IsType(uValue, IN_UNMOUNT)) { |
162 | if (IsType(uValue, IN_UNMOUNT)) { |
163 | DUMP_SEP;
|
163 | DUMP_SEP;
|
164 | rStr.append("IN_UNMOUNT"); |
164 | rStr.append("IN_UNMOUNT"); |
165 | }
|
165 | }
|
166 | if (IsType(uValue, IN_Q_OVERFLOW)) { |
166 | if (IsType(uValue, IN_Q_OVERFLOW)) { |
167 | DUMP_SEP;
|
167 | DUMP_SEP;
|
168 | rStr.append("IN_Q_OVERFLOW"); |
168 | rStr.append("IN_Q_OVERFLOW"); |
169 | }
|
169 | }
|
170 | if (IsType(uValue, IN_IGNORED)) { |
170 | if (IsType(uValue, IN_IGNORED)) { |
171 | DUMP_SEP;
|
171 | DUMP_SEP;
|
172 | rStr.append("IN_IGNORED"); |
172 | rStr.append("IN_IGNORED"); |
173 | }
|
173 | }
|
174 | if (IsType(uValue, IN_ISDIR)) { |
174 | if (IsType(uValue, IN_ISDIR)) { |
175 | DUMP_SEP;
|
175 | DUMP_SEP;
|
176 | rStr.append("IN_ISDIR"); |
176 | rStr.append("IN_ISDIR"); |
177 | }
|
177 | }
|
178 | if (IsType(uValue, IN_ONESHOT)) { |
178 | if (IsType(uValue, IN_ONESHOT)) { |
179 | DUMP_SEP;
|
179 | DUMP_SEP;
|
180 | rStr.append("IN_ONESHOT"); |
180 | rStr.append("IN_ONESHOT"); |
181 | }
|
181 | }
|
182 | 182 | ||
183 | #ifdef IN_DONT_FOLLOW
|
183 | #ifdef IN_DONT_FOLLOW
|
184 | if (IsType(uValue, IN_DONT_FOLLOW)) { |
184 | if (IsType(uValue, IN_DONT_FOLLOW)) { |
185 | DUMP_SEP;
|
185 | DUMP_SEP;
|
186 | rStr.append("IN_DONT_FOLLOW"); |
186 | rStr.append("IN_DONT_FOLLOW"); |
187 | }
|
187 | }
|
188 | #endif // IN_DONT_FOLLOW
|
188 | #endif // IN_DONT_FOLLOW
|
189 | 189 | ||
190 | #ifdef IN_ONLYDIR
|
190 | #ifdef IN_ONLYDIR
|
191 | if (IsType(uValue, IN_ONLYDIR)) { |
191 | if (IsType(uValue, IN_ONLYDIR)) { |
192 | DUMP_SEP;
|
192 | DUMP_SEP;
|
193 | rStr.append("IN_ONLYDIR"); |
193 | rStr.append("IN_ONLYDIR"); |
194 | }
|
194 | }
|
195 | #endif // IN_ONLYDIR
|
195 | #endif // IN_ONLYDIR
|
196 | }
|
196 | }
|
197 | 197 | ||
198 | void InotifyEvent::DumpTypes(std::string& rStr) const |
198 | void InotifyEvent::DumpTypes(std::string& rStr) const |
199 | {
|
199 | {
|
200 | DumpTypes(m_uMask, rStr); |
200 | DumpTypes(m_uMask, rStr); |
201 | }
|
201 | }
|
202 | 202 | ||
203 | 203 | ||
204 | void InotifyWatch::SetMask(uint32_t uMask) throw (InotifyException) |
204 | void InotifyWatch::SetMask(uint32_t uMask) throw (InotifyException) |
205 | {
|
205 | {
|
206 | IN_WRITE_BEGIN |
206 | IN_WRITE_BEGIN |
207 | 207 | ||
208 | if (m_wd != -1) { |
208 | if (m_wd != -1) { |
209 | int wd = inotify_add_watch(m_pInotify->GetDescriptor(), m_path.c_str(), uMask); |
209 | int wd = inotify_add_watch(m_pInotify->GetDescriptor(), m_path.c_str(), uMask); |
210 | if (wd != m_wd) { |
210 | if (wd != m_wd) { |
211 | IN_WRITE_END_NOTHROW |
211 | IN_WRITE_END_NOTHROW |
212 | throw InotifyException(IN_EXC_MSG("changing mask failed"), wd == -1 ? errno : EINVAL, this); |
212 | throw InotifyException(IN_EXC_MSG("changing mask failed"), wd == -1 ? errno : EINVAL, this); |
213 | }
|
213 | }
|
214 | }
|
214 | }
|
215 | 215 | ||
216 | m_uMask = uMask; |
216 | m_uMask = uMask; |
217 | 217 | ||
218 | IN_WRITE_END |
218 | IN_WRITE_END |
219 | }
|
219 | }
|
220 | 220 | ||
221 | void InotifyWatch::SetEnabled(bool fEnabled) throw (InotifyException) |
221 | void InotifyWatch::SetEnabled(bool fEnabled) throw (InotifyException) |
222 | {
|
222 | {
|
223 | IN_WRITE_BEGIN |
223 | IN_WRITE_BEGIN |
224 | 224 | ||
225 | if (fEnabled == m_fEnabled) { |
225 | if (fEnabled == m_fEnabled) { |
226 | IN_WRITE_END_NOTHROW |
226 | IN_WRITE_END_NOTHROW |
227 | return; |
227 | return; |
228 | }
|
228 | }
|
229 | 229 | ||
230 | if (m_pInotify != NULL) { |
230 | if (m_pInotify != NULL) { |
231 | if (fEnabled) { |
231 | if (fEnabled) { |
232 | m_wd = inotify_add_watch(m_pInotify->GetDescriptor(), m_path.c_str(), m_uMask); |
232 | m_wd = inotify_add_watch(m_pInotify->GetDescriptor(), m_path.c_str(), m_uMask); |
233 | if (m_wd == -1) { |
233 | if (m_wd == -1) { |
234 | IN_WRITE_END_NOTHROW |
234 | IN_WRITE_END_NOTHROW |
235 | throw InotifyException(IN_EXC_MSG("enabling watch failed"), errno, this); |
235 | throw InotifyException(IN_EXC_MSG("enabling watch failed"), errno, this); |
236 | }
|
236 | }
|
237 | m_pInotify->m_watches.insert(IN_WATCH_MAP::value_type(m_wd, this)); |
237 | m_pInotify->m_watches.insert(IN_WATCH_MAP::value_type(m_wd, this)); |
238 | }
|
238 | }
|
239 | else { |
239 | else { |
240 | if (inotify_rm_watch(m_pInotify->GetDescriptor(), m_wd) != 0) { |
240 | if (inotify_rm_watch(m_pInotify->GetDescriptor(), m_wd) != 0) { |
241 | IN_WRITE_END_NOTHROW |
241 | IN_WRITE_END_NOTHROW |
242 | throw InotifyException(IN_EXC_MSG("disabling watch failed"), errno, this); |
242 | throw InotifyException(IN_EXC_MSG("disabling watch failed"), errno, this); |
243 | }
|
243 | }
|
244 | m_pInotify->m_watches.erase(m_wd); |
244 | m_pInotify->m_watches.erase(m_wd); |
245 | m_wd = -1; |
245 | m_wd = -1; |
246 | }
|
246 | }
|
247 | }
|
247 | }
|
248 | 248 | ||
249 | m_fEnabled = fEnabled; |
249 | m_fEnabled = fEnabled; |
250 | 250 | ||
251 | IN_WRITE_END |
251 | IN_WRITE_END |
252 | }
|
252 | }
|
253 | 253 | ||
254 | 254 | ||
255 | Inotify::Inotify() throw (InotifyException) |
255 | Inotify::Inotify() throw (InotifyException) |
256 | {
|
256 | {
|
257 | IN_LOCK_INIT |
257 | IN_LOCK_INIT |
258 | 258 | ||
259 | m_fd = inotify_init(); |
259 | m_fd = inotify_init(); |
260 | if (m_fd == -1) { |
260 | if (m_fd == -1) { |
261 | IN_LOCK_DONE |
261 | IN_LOCK_DONE |
262 | throw InotifyException(IN_EXC_MSG("inotify init failed"), errno, NULL); |
262 | throw InotifyException(IN_EXC_MSG("inotify init failed"), errno, NULL); |
263 | }
|
263 | }
|
264 | }
|
264 | }
|
265 | 265 | ||
266 | Inotify::~Inotify() |
266 | Inotify::~Inotify() |
267 | {
|
267 | {
|
268 | Close(); |
268 | Close(); |
269 | 269 | ||
270 | IN_LOCK_DONE |
270 | IN_LOCK_DONE |
271 | }
|
271 | }
|
272 | 272 | ||
273 | void Inotify::Close() |
273 | void Inotify::Close() |
274 | {
|
274 | {
|
275 | IN_WRITE_BEGIN |
275 | IN_WRITE_BEGIN |
276 | 276 | ||
277 | if (m_fd != -1) { |
277 | if (m_fd != -1) { |
278 | RemoveAll(); |
278 | RemoveAll(); |
279 | close(m_fd); |
279 | close(m_fd); |
280 | m_fd = -1; |
280 | m_fd = -1; |
281 | }
|
281 | }
|
282 | 282 | ||
283 | IN_WRITE_END |
283 | IN_WRITE_END |
284 | }
|
284 | }
|
285 | 285 | ||
286 | void Inotify::Add(InotifyWatch* pWatch) throw (InotifyException) |
286 | void Inotify::Add(InotifyWatch* pWatch) throw (InotifyException) |
287 | {
|
287 | {
|
288 | IN_WRITE_BEGIN |
288 | IN_WRITE_BEGIN |
289 | 289 | ||
290 | // invalid descriptor - this case shouldn't occur - go away
|
290 | // invalid descriptor - this case shouldn't occur - go away
|
291 | if (m_fd == -1) { |
291 | if (m_fd == -1) { |
292 | IN_WRITE_END_NOTHROW |
292 | IN_WRITE_END_NOTHROW |
293 | throw InotifyException(IN_EXC_MSG("invalid file descriptor"), EBUSY, this); |
293 | throw InotifyException(IN_EXC_MSG("invalid file descriptor"), EBUSY, this); |
294 | }
|
294 | }
|
295 | 295 | ||
296 | // this path already watched - go away
|
296 | // this path already watched - go away
|
297 | if (FindWatch(pWatch->GetPath()) != NULL) { |
297 | if (FindWatch(pWatch->GetPath()) != NULL) { |
298 | IN_WRITE_END_NOTHROW |
298 | IN_WRITE_END_NOTHROW |
299 | throw InotifyException(IN_EXC_MSG("path already watched"), EBUSY, this); |
299 | throw InotifyException(IN_EXC_MSG("path already watched"), EBUSY, this); |
300 | }
|
300 | }
|
301 | 301 | ||
302 | // for enabled watch
|
302 | // for enabled watch
|
303 | if (pWatch->IsEnabled()) { |
303 | if (pWatch->IsEnabled()) { |
304 | 304 | ||
305 | // try to add watch to kernel
|
305 | // try to add watch to kernel
|
306 | int wd = inotify_add_watch(m_fd, pWatch->GetPath().c_str(), pWatch->GetMask()); |
306 | int wd = inotify_add_watch(m_fd, pWatch->GetPath().c_str(), pWatch->GetMask()); |
307 | 307 | ||
308 | // adding failed - go away
|
308 | // adding failed - go away
|
309 | if (wd == -1) { |
309 | if (wd == -1) { |
310 | IN_WRITE_END_NOTHROW |
310 | IN_WRITE_END_NOTHROW |
311 | throw InotifyException(IN_EXC_MSG("adding watch failed"), errno, this); |
311 | throw InotifyException(IN_EXC_MSG("adding watch failed"), errno, this); |
312 | }
|
312 | }
|
313 | 313 | ||
314 | // this path already watched (but defined another way)
|
314 | // this path already watched (but defined another way)
|
315 | InotifyWatch* pW = FindWatch(wd); |
315 | InotifyWatch* pW = FindWatch(wd); |
316 | if (pW != NULL) { |
316 | if (pW != NULL) { |
317 | 317 | ||
318 | // try to recover old watch because it may be modified - then go away
|
318 | // try to recover old watch because it may be modified - then go away
|
319 | if (inotify_add_watch(m_fd, pW->GetPath().c_str(), pW->GetMask()) < 0) { |
319 | if (inotify_add_watch(m_fd, pW->GetPath().c_str(), pW->GetMask()) < 0) { |
320 | IN_WRITE_END_NOTHROW |
320 | IN_WRITE_END_NOTHROW |
321 | throw InotifyException(IN_EXC_MSG("watch collision detected and recovery failed"), errno, this); |
321 | throw InotifyException(IN_EXC_MSG("watch collision detected and recovery failed"), errno, this); |
322 | }
|
322 | }
|
323 | else { |
323 | else { |
324 | // recovery failed - go away
|
324 | // recovery failed - go away
|
325 | IN_WRITE_END_NOTHROW |
325 | IN_WRITE_END_NOTHROW |
326 | throw InotifyException(IN_EXC_MSG("path already watched (but defined another way)"), EBUSY, this); |
326 | throw InotifyException(IN_EXC_MSG("path already watched (but defined another way)"), EBUSY, this); |
327 | }
|
327 | }
|
328 | }
|
328 | }
|
329 | 329 | ||
330 | pWatch->m_wd = wd; |
330 | pWatch->m_wd = wd; |
331 | m_watches.insert(IN_WATCH_MAP::value_type(pWatch->m_wd, pWatch)); |
331 | m_watches.insert(IN_WATCH_MAP::value_type(pWatch->m_wd, pWatch)); |
332 | }
|
332 | }
|
333 | 333 | ||
334 | m_paths.insert(IN_WP_MAP::value_type(pWatch->m_path, pWatch)); |
334 | m_paths.insert(IN_WP_MAP::value_type(pWatch->m_path, pWatch)); |
335 | pWatch->m_pInotify = this; |
335 | pWatch->m_pInotify = this; |
336 | 336 | ||
337 | IN_WRITE_END |
337 | IN_WRITE_END |
338 | }
|
338 | }
|
339 | 339 | ||
340 | void Inotify::Remove(InotifyWatch* pWatch) throw (InotifyException) |
340 | void Inotify::Remove(InotifyWatch* pWatch) throw (InotifyException) |
341 | {
|
341 | {
|
342 | IN_WRITE_BEGIN |
342 | IN_WRITE_BEGIN |
343 | 343 | ||
344 | // invalid descriptor - this case shouldn't occur - go away
|
344 | // invalid descriptor - this case shouldn't occur - go away
|
345 | if (m_fd == -1) { |
345 | if (m_fd == -1) { |
346 | IN_WRITE_END_NOTHROW |
346 | IN_WRITE_END_NOTHROW |
347 | throw InotifyException(IN_EXC_MSG("invalid file descriptor"), EBUSY, this); |
347 | throw InotifyException(IN_EXC_MSG("invalid file descriptor"), EBUSY, this); |
348 | }
|
348 | }
|
349 | 349 | ||
350 | // for enabled watch
|
350 | // for enabled watch
|
351 | if (pWatch->m_wd != -1) { |
351 | if (pWatch->m_wd != -1) { |
352 | 352 | ||
353 | // removing watch failed - go away
|
353 | // removing watch failed - go away
|
354 | if (inotify_rm_watch(m_fd, pWatch->m_wd) == -1) { |
354 | if (inotify_rm_watch(m_fd, pWatch->m_wd) == -1) { |
355 | IN_WRITE_END_NOTHROW |
355 | IN_WRITE_END_NOTHROW |
356 | throw InotifyException(IN_EXC_MSG("removing watch failed"), errno, this); |
356 | throw InotifyException(IN_EXC_MSG("removing watch failed"), errno, this); |
357 | }
|
357 | }
|
358 | m_watches.erase(pWatch->m_wd); |
358 | m_watches.erase(pWatch->m_wd); |
359 | pWatch->m_wd = -1; |
359 | pWatch->m_wd = -1; |
360 | }
|
360 | }
|
361 | 361 | ||
362 | m_paths.erase(pWatch->m_path); |
362 | m_paths.erase(pWatch->m_path); |
363 | pWatch->m_pInotify = NULL; |
363 | pWatch->m_pInotify = NULL; |
364 | 364 | ||
365 | IN_WRITE_END |
365 | IN_WRITE_END |
366 | }
|
366 | }
|
367 | 367 | ||
368 | void Inotify::RemoveAll() |
368 | void Inotify::RemoveAll() |
369 | {
|
369 | {
|
370 | IN_WRITE_BEGIN |
370 | IN_WRITE_BEGIN |
371 | 371 | ||
372 | IN_WP_MAP::iterator it = m_paths.begin(); |
372 | IN_WP_MAP::iterator it = m_paths.begin(); |
373 | while (it != m_paths.end()) { |
373 | while (it != m_paths.end()) { |
374 | InotifyWatch* pW = (*it).second; |
374 | InotifyWatch* pW = (*it).second; |
375 | if (pW->m_wd != -1) { |
375 | if (pW->m_wd != -1) { |
376 | inotify_rm_watch(m_fd, pW->m_wd); |
376 | inotify_rm_watch(m_fd, pW->m_wd); |
377 | pW->m_wd = -1; |
377 | pW->m_wd = -1; |
378 | }
|
378 | }
|
379 | pW->m_pInotify = NULL; |
379 | pW->m_pInotify = NULL; |
380 | it++; |
380 | it++; |
381 | }
|
381 | }
|
382 | 382 | ||
383 | m_watches.clear(); |
383 | m_watches.clear(); |
384 | m_paths.clear(); |
384 | m_paths.clear(); |
385 | 385 | ||
386 | IN_WRITE_END |
386 | IN_WRITE_END |
387 | }
|
387 | }
|
388 | 388 | ||
389 | void Inotify::WaitForEvents(bool fNoIntr) throw (InotifyException) |
389 | void Inotify::WaitForEvents(bool fNoIntr) throw (InotifyException) |
390 | {
|
390 | {
|
391 | ssize_t len = 0; |
391 | ssize_t len = 0; |
392 | 392 | ||
393 | do { |
393 | do { |
394 | len = read(m_fd, m_buf, INOTIFY_BUFLEN); |
394 | len = read(m_fd, m_buf, INOTIFY_BUFLEN); |
395 | } while (fNoIntr && len == -1 && errno == EINTR); |
395 | } while (fNoIntr && len == -1 && errno == EINTR); |
396 | 396 | ||
397 | if (errno == EWOULDBLOCK) |
397 | if (errno == EWOULDBLOCK) |
398 | return; |
398 | return; |
399 | 399 | ||
400 | if (len < 0) |
400 | if (len < 0) |
401 | throw InotifyException(IN_EXC_MSG("reading events failed"), errno, this); |
401 | throw InotifyException(IN_EXC_MSG("reading events failed"), errno, this); |
402 | 402 | ||
403 | IN_WRITE_BEGIN |
403 | IN_WRITE_BEGIN |
404 | 404 | ||
405 | ssize_t i = 0; |
405 | ssize_t i = 0; |
406 | while (i < len) { |
406 | while (i < len) { |
407 | struct inotify_event* pEvt = (struct inotify_event*) &m_buf[i]; |
407 | struct inotify_event* pEvt = (struct inotify_event*) &m_buf[i]; |
408 | InotifyWatch* pW = FindWatch(pEvt->wd); |
408 | InotifyWatch* pW = FindWatch(pEvt->wd); |
409 | if (pW != NULL) { |
409 | if (pW != NULL) { |
410 | InotifyEvent evt(pEvt, pW); |
410 | InotifyEvent evt(pEvt, pW); |
411 | m_events.push_back(evt); |
411 | m_events.push_back(evt); |
412 | }
|
412 | }
|
413 | i += INOTIFY_EVENT_SIZE + (ssize_t) pEvt->len; |
413 | i += INOTIFY_EVENT_SIZE + (ssize_t) pEvt->len; |
414 | }
|
414 | }
|
415 | 415 | ||
416 | IN_WRITE_END |
416 | IN_WRITE_END |
417 | }
|
417 | }
|
418 | 418 | ||
419 | bool Inotify::GetEvent(InotifyEvent* pEvt) throw (InotifyException) |
419 | bool Inotify::GetEvent(InotifyEvent* pEvt) throw (InotifyException) |
420 | {
|
420 | {
|
421 | if (pEvt == NULL) |
421 | if (pEvt == NULL) |
422 | throw InotifyException(IN_EXC_MSG("null pointer to event"), EINVAL, this); |
422 | throw InotifyException(IN_EXC_MSG("null pointer to event"), EINVAL, this); |
423 | 423 | ||
424 | IN_WRITE_BEGIN |
424 | IN_WRITE_BEGIN |
425 | 425 | ||
426 | bool b = !m_events.empty(); |
426 | bool b = !m_events.empty(); |
427 | if (b) { |
427 | if (b) { |
428 | *pEvt = m_events.front(); |
428 | *pEvt = m_events.front(); |
429 | m_events.pop_front(); |
429 | m_events.pop_front(); |
430 | }
|
430 | }
|
431 | 431 | ||
432 | IN_WRITE_END |
432 | IN_WRITE_END |
433 | 433 | ||
434 | return b; |
434 | return b; |
435 | }
|
435 | }
|
436 | 436 | ||
437 | bool Inotify::PeekEvent(InotifyEvent* pEvt) throw (InotifyException) |
437 | bool Inotify::PeekEvent(InotifyEvent* pEvt) throw (InotifyException) |
438 | {
|
438 | {
|
439 | if (pEvt == NULL) |
439 | if (pEvt == NULL) |
440 | throw InotifyException(IN_EXC_MSG("null pointer to event"), EINVAL, this); |
440 | throw InotifyException(IN_EXC_MSG("null pointer to event"), EINVAL, this); |
441 | 441 | ||
442 | IN_READ_BEGIN |
442 | IN_READ_BEGIN |
443 | 443 | ||
444 | bool b = !m_events.empty(); |
444 | bool b = !m_events.empty(); |
445 | if (b) { |
445 | if (b) { |
446 | *pEvt = m_events.front(); |
446 | *pEvt = m_events.front(); |
447 | }
|
447 | }
|
448 | 448 | ||
449 | IN_READ_END |
449 | IN_READ_END |
450 | 450 | ||
451 | return b; |
451 | return b; |
452 | }
|
452 | }
|
453 | 453 | ||
454 | InotifyWatch* Inotify::FindWatch(int iDescriptor) |
454 | InotifyWatch* Inotify::FindWatch(int iDescriptor) |
455 | {
|
455 | {
|
456 | IN_READ_BEGIN |
456 | IN_READ_BEGIN |
457 | 457 | ||
458 | IN_WATCH_MAP::iterator it = m_watches.find(iDescriptor); |
458 | IN_WATCH_MAP::iterator it = m_watches.find(iDescriptor); |
459 | InotifyWatch* pW = it == m_watches.end() ? NULL : (*it).second; |
459 | InotifyWatch* pW = it == m_watches.end() ? NULL : (*it).second; |
460 | 460 | ||
461 | IN_READ_END |
461 | IN_READ_END |
462 | 462 | ||
463 | return pW; |
463 | return pW; |
464 | }
|
464 | }
|
465 | 465 | ||
466 | InotifyWatch* Inotify::FindWatch(const std::string& rPath) |
466 | InotifyWatch* Inotify::FindWatch(const std::string& rPath) |
467 | {
|
467 | {
|
468 | IN_READ_BEGIN |
468 | IN_READ_BEGIN |
469 | 469 | ||
470 | IN_WP_MAP::iterator it = m_paths.find(rPath); |
470 | IN_WP_MAP::iterator it = m_paths.find(rPath); |
471 | InotifyWatch* pW = it == m_paths.end() ? NULL : (*it).second; |
471 | InotifyWatch* pW = it == m_paths.end() ? NULL : (*it).second; |
472 | 472 | ||
473 | IN_READ_END |
473 | IN_READ_END |
474 | 474 | ||
475 | return pW; |
475 | return pW; |
476 | }
|
476 | }
|
477 | 477 | ||
478 | void Inotify::SetNonBlock(bool fNonBlock) throw (InotifyException) |
478 | void Inotify::SetNonBlock(bool fNonBlock) throw (InotifyException) |
479 | {
|
479 | {
|
480 | IN_WRITE_BEGIN |
480 | IN_WRITE_BEGIN |
481 | 481 | ||
482 | if (m_fd == -1) { |
482 | if (m_fd == -1) { |
483 | IN_WRITE_END_NOTHROW |
483 | IN_WRITE_END_NOTHROW |
484 | throw InotifyException(IN_EXC_MSG("invalid file descriptor"), EBUSY, this); |
484 | throw InotifyException(IN_EXC_MSG("invalid file descriptor"), EBUSY, this); |
485 | }
|
485 | }
|
486 | 486 | ||
487 | int res = fcntl(m_fd, F_GETFL); |
487 | int res = fcntl(m_fd, F_GETFL); |
488 | if (res == -1) { |
488 | if (res == -1) { |
489 | IN_WRITE_END_NOTHROW |
489 | IN_WRITE_END_NOTHROW |
490 | throw InotifyException(IN_EXC_MSG("cannot get inotify flags"), errno, this); |
490 | throw InotifyException(IN_EXC_MSG("cannot get inotify flags"), errno, this); |
491 | }
|
491 | }
|
492 | 492 | ||
493 | if (fNonBlock) { |
493 | if (fNonBlock) { |
494 | res |= O_NONBLOCK; |
494 | res |= O_NONBLOCK; |
495 | }
|
495 | }
|
496 | else { |
496 | else { |
497 | res &= ~O_NONBLOCK; |
497 | res &= ~O_NONBLOCK; |
498 | }
|
498 | }
|
499 | 499 | ||
500 | if (fcntl(m_fd, F_SETFL, res) == -1) { |
500 | if (fcntl(m_fd, F_SETFL, res) == -1) { |
501 | IN_WRITE_END_NOTHROW |
501 | IN_WRITE_END_NOTHROW |
502 | throw InotifyException(IN_EXC_MSG("cannot set inotify flags"), errno, this); |
502 | throw InotifyException(IN_EXC_MSG("cannot set inotify flags"), errno, this); |
503 | }
|
503 | }
|
504 | 504 | ||
505 | IN_WRITE_END |
505 | IN_WRITE_END |
506 | }
|
506 | }
|
507 | 507 | ||
508 | 508 |