Subversion Repositories public

Rev

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

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