Subversion Repositories public

Rev

Rev 27 | Rev 33 | Go to most recent revision | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

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