Subversion Repositories public

Rev

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

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