Subversion Repositories public

Rev

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

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