Subversion Repositories public

Rev

Rev 108 | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

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