Subversion Repositories public

Rev

Rev 11 | Rev 15 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
3 luk 1
 
2
/// inotify C++ interface implementation
3
/**
4
 * \file inotify-cxx.cpp
5
 *
6
 * inotify C++ interface
7
 *
8
 * Copyright (C) 2006 Lukas Jelinek <lukas@aiken.cz>
9
 *
10
 * This program is free software; you can redistribute it and/or
11
 * modify it under the terms of one of the following licenses:
12
 *
13
 * \li 1. X11-style license (see LICENSE-X11)
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)
16
 *
17
 * If you want to help with choosing the best license for you,
18
 * please visit http://www.gnu.org/licenses/license-list.html.
19
 *
20
 */
21
 
22
 
23
#include <errno.h>
24
#include <unistd.h>
13 luk 25
#include <fcntl.h>
3 luk 26
 
27
#include "inotify-cxx.h"
28
 
13 luk 29
/// dump separator (between particular entries)
3 luk 30
#define DUMP_SEP \
31
  ({ \
32
    if (!rStr.empty()) { \
11 luk 33
      rStr.append(","); \
3 luk 34
    } \
35
  })
36
 
13 luk 37
 
38
int32_t InotifyEvent::GetDescriptor() const
39
{
40
  return  m_pWatch != NULL            // if watch exists
41
      ?   m_pWatch->GetDescriptor()   // return its descriptor
42
      :   -1;                         // else return -1
43
}
44
 
11 luk 45
uint32_t InotifyEvent::GetMaskByName(const std::string& rName)
46
{
47
  if (rName == "IN_ACCESS")
48
    return IN_ACCESS;
49
  else if (rName == "IN_MODIFY")
50
    return IN_MODIFY;
51
  else if (rName == "IN_ATTRIB")
52
    return IN_ATTRIB;
53
  else if (rName == "IN_CLOSE_WRITE")
54
    return IN_CLOSE_WRITE;
55
  else if (rName == "IN_CLOSE_NOWRITE")
56
    return IN_CLOSE_NOWRITE;
57
  else if (rName == "IN_MOVED_FROM")
58
    return IN_MOVED_FROM;
59
  else if (rName == "IN_MOVED_TO")
60
    return IN_MOVED_TO;
61
  else if (rName == "IN_CREATE")
62
    return IN_CREATE;
63
  else if (rName == "IN_DELETE")
64
    return IN_DELETE;
65
  else if (rName == "IN_DELETE_SELF")
66
    return IN_DELETE_SELF;
67
  else if (rName == "IN_UNMOUNT")
68
    return IN_UNMOUNT;
69
  else if (rName == "IN_Q_OVERFLOW")
70
    return IN_Q_OVERFLOW;
71
  else if (rName == "IN_IGNORED")
72
    return IN_IGNORED;
73
  else if (rName == "IN_CLOSE")
74
    return IN_CLOSE;
75
  else if (rName == "IN_MOVE")
76
    return IN_MOVE;
77
  else if (rName == "IN_ISDIR")
78
    return IN_ISDIR;
79
  else if (rName == "IN_ONESHOT")
80
    return IN_ONESHOT;
81
  else if (rName == "IN_ALL_EVENTS")
82
    return IN_ALL_EVENTS;
83
 
84
  return (uint32_t) 0;
85
}
3 luk 86
 
11 luk 87
void InotifyEvent::DumpTypes(uint32_t uValue, std::string& rStr)
3 luk 88
{
89
  rStr = "";
90
 
11 luk 91
  if (IsType(uValue, IN_ALL_EVENTS)) {
92
    rStr.append("IN_ALL_EVENTS");
3 luk 93
  }
11 luk 94
  else {
95
    if (IsType(uValue, IN_ACCESS)) {
96
      DUMP_SEP;
97
      rStr.append("IN_ACCESS");    
98
    }
99
    if (IsType(uValue, IN_MODIFY)) {
100
      DUMP_SEP;
101
      rStr.append("IN_MODIFY");
102
    }
103
    if (IsType(uValue, IN_ATTRIB)) {
104
      DUMP_SEP;
105
      rStr.append("IN_ATTRIB");
106
    }
107
    if (IsType(uValue, IN_CREATE)) {
108
      DUMP_SEP;
109
      rStr.append("IN_CREATE");
110
    }
111
    if (IsType(uValue, IN_DELETE)) {
112
      DUMP_SEP;
113
      rStr.append("IN_DELETE");
114
    }
115
    if (IsType(uValue, IN_DELETE_SELF)) {
116
      DUMP_SEP;
117
      rStr.append("IN_DELETE_SELF");
118
    }
119
    if (IsType(uValue, IN_OPEN)) {
120
      DUMP_SEP;
121
      rStr.append("IN_OPEN");
122
    }
123
    if (IsType(uValue, IN_CLOSE)) {
124
      DUMP_SEP;
125
      rStr.append("IN_CLOSE");
126
    }
127
    else {
128
      if (IsType(uValue, IN_CLOSE_WRITE)) {
129
        DUMP_SEP;
130
        rStr.append("IN_CLOSE_WRITE");
131
      }
132
      if (IsType(uValue, IN_CLOSE_NOWRITE)) {
133
        DUMP_SEP;
134
        rStr.append("IN_CLOSE_NOWRITE");
135
      }
136
    }
137
    if (IsType(uValue, IN_MOVE)) {
138
      DUMP_SEP;
139
      rStr.append("IN_MOVE");
140
    }
141
    else {
142
      if (IsType(uValue, IN_MOVED_FROM)) {
143
        DUMP_SEP;
144
        rStr.append("IN_MOVED_FROM");
145
      }
146
      if (IsType(uValue, IN_MOVED_TO)) {
147
        DUMP_SEP;
148
        rStr.append("IN_MOVED_TO");
149
      }
150
    }
3 luk 151
  }
11 luk 152
  if (IsType(uValue, IN_UNMOUNT)) {
3 luk 153
    DUMP_SEP;
154
    rStr.append("IN_UNMOUNT");
155
  }
11 luk 156
  if (IsType(uValue, IN_Q_OVERFLOW)) {
3 luk 157
    DUMP_SEP;
158
    rStr.append("IN_Q_OVERFLOW");
159
  }
11 luk 160
  if (IsType(uValue, IN_IGNORED)) {
3 luk 161
    DUMP_SEP;
162
    rStr.append("IN_IGNORED");
163
  }
11 luk 164
  if (IsType(uValue, IN_ISDIR)) {
3 luk 165
    DUMP_SEP;
166
    rStr.append("IN_ISDIR");
167
  }
11 luk 168
  if (IsType(uValue, IN_ONESHOT)) {
3 luk 169
    DUMP_SEP;
170
    rStr.append("IN_ONESHOT");
171
  }
172
}
173
 
11 luk 174
void InotifyEvent::DumpTypes(std::string& rStr) const
175
{
13 luk 176
  DumpTypes(m_uMask, rStr);
11 luk 177
}
3 luk 178
 
11 luk 179
 
13 luk 180
Inotify::Inotify() throw (InotifyException)
3 luk 181
{
13 luk 182
  m_fd = inotify_init();
183
  if (m_fd == -1)
184
    throw InotifyException(std::string(__PRETTY_FUNCTION__) + ": inotify init failed", errno, NULL);
3 luk 185
}
186
 
187
Inotify::~Inotify()
188
{
189
  Close();
190
}
191
 
192
void Inotify::Close()
193
{
194
  if (m_fd != -1) {
195
    RemoveAll();
196
    close(m_fd);
197
    m_fd = -1;
198
  }
199
}
200
 
13 luk 201
void Inotify::Add(InotifyWatch* pWatch) throw (InotifyException)
3 luk 202
{
203
  if (m_fd == -1)
13 luk 204
    throw InotifyException(IN_EXC_MSG("invalid file descriptor"), EBUSY, this);
3 luk 205
 
206
  pWatch->m_wd = inotify_add_watch(m_fd, pWatch->GetPath().c_str(), pWatch->GetMask());
13 luk 207
 
208
  if (pWatch->m_wd == -1)
209
    throw InotifyException(IN_EXC_MSG("adding watch failed"), errno, this);
210
 
211
  m_watches.insert(IN_WATCH_MAP::value_type(pWatch->m_wd, pWatch));
212
  pWatch->m_pInotify = this;
3 luk 213
}
214
 
13 luk 215
void Inotify::Remove(InotifyWatch* pWatch) throw (InotifyException)
3 luk 216
{
217
  if (m_fd == -1)
13 luk 218
    throw InotifyException(IN_EXC_MSG("invalid file descriptor"), EBUSY, this);
3 luk 219
 
13 luk 220
  if (inotify_rm_watch(m_fd, pWatch->GetMask()) == -1)
221
    throw InotifyException(IN_EXC_MSG("removing watch failed"), errno, this);
222
 
223
  m_watches.erase(pWatch->m_wd);
224
  pWatch->m_wd = -1;
225
  pWatch->m_pInotify = NULL;
3 luk 226
}
227
 
228
void Inotify::RemoveAll()
229
{
230
  IN_WATCH_MAP::iterator it = m_watches.begin();
231
  while (it != m_watches.end()) {
11 luk 232
    InotifyWatch* pW = (*it).second;
233
    inotify_rm_watch(m_fd, pW->GetMask());
234
    pW->m_wd = -1;
235
    pW->m_pInotify = NULL;
3 luk 236
    it++;
237
  }
238
 
239
  m_watches.clear();
240
}
241
 
13 luk 242
void Inotify::WaitForEvents(bool fNoIntr) throw (InotifyException)
3 luk 243
{
244
  ssize_t len = 0;
245
 
246
  do {
247
    len = read(m_fd, m_buf, INOTIFY_BUFLEN);
248
  } while (fNoIntr && len == -1 && errno == EINTR);
249
 
13 luk 250
  if (len < 0)
251
    throw InotifyException(IN_EXC_MSG("reading events failed"), errno, this);
3 luk 252
 
253
  ssize_t i = 0;
254
  while (i < len) {
13 luk 255
    struct inotify_event* pEvt = (struct inotify_event*) &m_buf[i];
256
    InotifyWatch* pW = FindWatch(pEvt->wd);
257
    if (pW != NULL && pW->IsEnabled()) {
258
      InotifyEvent evt(pEvt, pW);
259
      m_events.push_back(evt);
260
    }
261
    i += INOTIFY_EVENT_SIZE + (ssize_t) pEvt->len;
3 luk 262
  }
263
}
264
 
265
int Inotify::GetEventCount()
266
{
267
  return m_events.size();
268
}
269
 
13 luk 270
bool Inotify::GetEvent(InotifyEvent* pEvt) throw (InotifyException)
3 luk 271
{
13 luk 272
  bool b = PeekEvent(pEvt);
273
 
3 luk 274
  if (b)
275
    m_events.pop_front();
13 luk 276
 
3 luk 277
  return b;
278
}
279
 
13 luk 280
bool Inotify::PeekEvent(InotifyEvent* pEvt) throw (InotifyException)
3 luk 281
{
13 luk 282
  if (pEvt == NULL)
283
    throw InotifyException(IN_EXC_MSG("null pointer to event"), EINVAL, this);
3 luk 284
 
13 luk 285
  if (!m_events.empty()) {
286
    *pEvt = m_events.front();
287
    return true;
288
  }
289
 
290
  return false;
3 luk 291
}
292
 
293
InotifyWatch* Inotify::FindWatch(int iDescriptor)
294
{
295
  IN_WATCH_MAP::iterator it = m_watches.find(iDescriptor);
296
  if (it == m_watches.end())
297
    return NULL;
298
 
299
  return (*it).second;
300
}
301
 
13 luk 302
void Inotify::SetNonBlock(bool fNonBlock) throw (InotifyException)
303
{
304
  if (m_fd == -1)
305
    throw InotifyException(IN_EXC_MSG("invalid file descriptor"), EBUSY, this);
306
 
307
  int res = fcntl(m_fd, F_GETFL);
308
  if (res == -1)
309
    throw InotifyException(IN_EXC_MSG("cannot get inotify flags"), errno, this);
310
 
311
  if (fNonBlock) {
312
    res |= O_NONBLOCK;
313
  }
314
  else {
315
    res &= ~O_NONBLOCK;
316
  }
317
 
318
  if (fcntl(m_fd, F_SETFL, res) == -1)
319
    throw InotifyException(IN_EXC_MSG("cannot set inotify flags"), errno, this);
320
}  
321