Subversion Repositories public

Rev

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

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