Subversion Repositories public

Rev

Rev 11 | Rev 17 | 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 header
3
/**
4
 * \file inotify-cxx.h
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
 
24
 
25
 
26
#ifndef _INOTIFYCXX_H_
27
#define _INOTIFYCXX_H_
28
 
29
#include <string>
30
#include <deque>
31
#include <map>
32
 
33
// Please ensure that the following headers take the right place.
34
#include <sys/inotify.h>
35
#include <sys/inotify-syscalls.h>
36
 
37
/// Event struct size
38
#define INOTIFY_EVENT_SIZE (sizeof(struct inotify_event))
39
 
40
/// Event buffer length
41
#define INOTIFY_BUFLEN (1024 * (INOTIFY_EVENT_SIZE + 16))
42
 
13 luk 43
/// Helper macro for creating exception messages.
44
/**
45
 * It prepends the message by the function name.
46
 */
47
#define IN_EXC_MSG(msg) (std::string(__PRETTY_FUNCTION__) + ": " + msg)
11 luk 48
 
13 luk 49
 
50
 
11 luk 51
// forward declaration
52
class InotifyWatch;
53
class Inotify;
54
 
55
 
13 luk 56
/// Class for inotify exceptions
57
class InotifyException
58
{
59
public:
60
  /// Constructor
61
  /**
62
   * \param[in] rMsg message
63
   * \param[in] iErr error number (see errno.h)
64
   * \param[in] pSrc source
65
   */
66
  InotifyException(const std::string& rMsg = "", int iErr = 0, void* pSrc = NULL)
67
  : m_msg(rMsg),
68
    m_err(iErr)
69
  {
70
    m_pSrc = pSrc;
71
  }
72
 
73
  /// Returns the exception message.
74
  /**
75
   * \return message
76
   */
77
  inline const std::string& GetMessage() const
78
  {
79
    return m_msg;
80
  }
81
 
82
  /// Returns the exception error number.
83
  /**
84
   * If not applicable this value is 0 (zero).
85
   *
86
   * \return error number (standardized; see errno.h)
87
   */
88
  inline int GetErrorNumber() const
89
  {
90
    return m_err;
91
  }
92
 
93
  /// Returns the exception source.
94
  /**
95
   * \return source
96
   */
97
  inline void* GetSource() const
98
  {
99
    return m_pSrc;
100
  }
101
 
102
protected:
103
  std::string m_msg;      ///< message
104
  int m_err;              ///< error number
105
  mutable void* m_pSrc;   ///< source
106
};
107
 
108
 
3 luk 109
/// inotify event class
110
/**
111
 * It holds all information about inotify event and provides
112
 * access to its particular values.
113
 */
114
class InotifyEvent
115
{
116
public:
117
  /// Constructor.
118
  /**
119
   * Creates a plain event.
120
   */
121
  InotifyEvent()
13 luk 122
  : m_uMask(0),
123
    m_uCookie(0)
3 luk 124
  {
11 luk 125
    m_pWatch = NULL;
3 luk 126
  }
127
 
128
  /// Constructor.
129
  /**
130
   * Creates an event based on inotify event data.
11 luk 131
   * For NULL pointers it works the same way as InotifyEvent().
3 luk 132
   *
133
   * \param[in] pEvt event data
11 luk 134
   * \param[in] pWatch inotify watch
3 luk 135
   */
11 luk 136
  InotifyEvent(const struct inotify_event* pEvt, InotifyWatch* pWatch)
13 luk 137
  : m_uMask(0),
138
    m_uCookie(0)
3 luk 139
  {
140
    if (pEvt != NULL) {
13 luk 141
      m_uMask = (uint32_t) pEvt->mask;
142
      m_uCookie = (uint32_t) pEvt->cookie;
3 luk 143
      if (pEvt->name != NULL)
144
        m_name = pEvt->name;
11 luk 145
      m_pWatch = pWatch;
3 luk 146
    }
147
    else {
11 luk 148
      m_pWatch = NULL;
3 luk 149
    }
150
  }
151
 
152
  /// Destructor.
153
  ~InotifyEvent() {}
154
 
155
  /// Returns the event watch descriptor.
156
  /**
157
   * \return watch descriptor
158
   *
159
   * \sa InotifyWatch::GetDescriptor()
160
   */
13 luk 161
  int32_t GetDescriptor() const;
3 luk 162
 
163
  /// Returns the event mask.
164
  /**
165
   * \return event mask
166
   *
167
   * \sa InotifyWatch::GetMask()
168
   */
169
  inline uint32_t GetMask() const
170
  {
13 luk 171
    return m_uMask;
3 luk 172
  }
173
 
11 luk 174
  /// Checks a value for the event type.
175
  /**
176
   * \param[in] uValue checked value
177
   * \param[in] uType type which is checked for
178
   * \return true = the value contains the given type, false = otherwise
179
   */
180
  inline static bool IsType(uint32_t uValue, uint32_t uType)
181
  {
182
    return ((uValue & uType) != 0) && ((~uValue & uType) == 0);
183
  }
184
 
3 luk 185
  /// Checks for the event type.
186
  /**
187
   * \param[in] uType type which is checked for
188
   * \return true = event mask contains the given type, false = otherwise
189
   */
190
  inline bool IsType(uint32_t uType) const
191
  {
13 luk 192
    return IsType(m_uMask, uType);
3 luk 193
  }
194
 
195
  /// Returns the event cookie.
196
  /**
197
   * \return event cookie
198
   */
199
  inline uint32_t GetCookie() const
200
  {
13 luk 201
    return m_uCookie;
3 luk 202
  }
203
 
204
  /// Returns the event name length.
205
  /**
206
   * \return event name length
207
   */
208
  inline uint32_t GetLength() const
209
  {
13 luk 210
    return (uint32_t) m_name.length();
3 luk 211
  }
212
 
213
  /// Returns the event name.
214
  /**
215
   * \return event name
216
   */
217
  inline const std::string& GetName() const
218
  {
219
    return m_name;
220
  }
221
 
222
  /// Extracts the event name.
223
  /**
224
   * \param[out] rName event name
225
   */
226
  inline void GetName(std::string& rName) const
227
  {
228
    rName = GetName();
229
  }
230
 
11 luk 231
  /// Returns the source watch.
232
  /**
233
   * \return source watch
234
   */
235
  inline InotifyWatch* GetWatch()
236
  {
237
    return m_pWatch;
238
  }
239
 
240
  /// Finds the appropriate mask for a name.
241
  /**
242
   * \param[in] rName mask name
243
   * \return mask for name; 0 on failure
244
   */
245
  static uint32_t GetMaskByName(const std::string& rName);
246
 
247
  /// Fills the string with all types contained in an event mask value.
248
  /**
249
   * \param[in] uValue event mask value
250
   * \param[out] rStr dumped event types
251
   */
252
  static void DumpTypes(uint32_t uValue, std::string& rStr);
253
 
3 luk 254
  /// Fills the string with all types contained in the event mask.
255
  /**
256
   * \param[out] rStr dumped event types
257
   */
258
  void DumpTypes(std::string& rStr) const;
259
 
260
private:
13 luk 261
  uint32_t m_uMask;           ///< mask
262
  uint32_t m_uCookie;         ///< cookie
263
  std::string m_name;         ///< name
11 luk 264
  InotifyWatch* m_pWatch;     ///< source watch
3 luk 265
};
266
 
267
 
268
 
269
/// inotify watch class
270
class InotifyWatch
271
{
272
public:
273
  /// Constructor.
274
  /**
275
   * Creates an inotify watch. Because this watch is
276
   * inactive it has an invalid descriptor (-1).
277
   *
278
   * \param[in] rPath watched file path
279
   * \param[in] uMask mask for events
13 luk 280
   * \param[in] fEnabled events enabled yes/no
3 luk 281
   */
13 luk 282
  InotifyWatch(const std::string& rPath, int32_t uMask, bool fEnabled = true)
283
  : m_path(rPath),
284
    m_uMask(uMask),
285
    m_wd((int32_t) -1),
286
    m_fEnabled(fEnabled)
3 luk 287
  {
13 luk 288
 
3 luk 289
  }
290
 
291
  /// Destructor.
292
  ~InotifyWatch() {}
293
 
294
  /// Returns the watch descriptor.
295
  /**
296
   * \return watch descriptor; -1 for inactive watch
297
   */
298
  inline int32_t GetDescriptor() const
299
  {
300
    return m_wd;
301
  }
302
 
303
  /// Returns the watched file path.
304
  /**
305
   * \return file path
306
   */
307
  inline const std::string& GetPath() const
308
  {
309
    return m_path;
310
  }
311
 
312
  /// Returns the watch event mask.
313
  /**
314
   * \return event mask
315
   */
316
  inline uint32_t GetMask() const
317
  {
318
    return (uint32_t) m_uMask;
319
  }
320
 
11 luk 321
  /// Returns the appropriate inotify class instance.
322
  /**
323
   * \return inotify instance
324
   */
325
  inline Inotify* GetInotify()
326
  {
327
    return m_pInotify;
328
  }
329
 
13 luk 330
  inline void SetEnabled(bool fEnabled)
331
  {
332
    m_fEnabled = fEnabled;
333
  }  
334
 
335
  inline bool IsEnabled() const
336
  {
337
    return m_fEnabled;
338
  }
339
 
3 luk 340
private:
341
  friend class Inotify;
342
 
343
  std::string m_path;   ///< watched file path
344
  uint32_t m_uMask;     ///< event mask
345
  int32_t m_wd;         ///< watch descriptor
11 luk 346
  Inotify* m_pInotify;  ///< inotify object
13 luk 347
  bool m_fEnabled;      ///< events enabled yes/no
3 luk 348
};
349
 
350
 
351
/// Mapping from watch descriptors to watch objects.
352
typedef std::map<int32_t, InotifyWatch*> IN_WATCH_MAP;
353
 
354
 
355
/// inotify class
356
class Inotify
357
{
358
public:
359
  /// Constructor.
360
  /**
361
   * Creates and initializes an instance of inotify communication
362
   * object (opens the inotify device).
13 luk 363
   *
364
   * \throw InotifyException thrown if inotify isn't available
3 luk 365
   */
13 luk 366
  Inotify() throw (InotifyException);
3 luk 367
 
368
  /// Destructor.
369
  /**
13 luk 370
   * Calls Close() due to clean-up.
3 luk 371
   */
372
  ~Inotify();
373
 
374
  /// Removes all watches and closes the inotify device.
375
  void Close();
13 luk 376
 
3 luk 377
  /// Adds a new watch.
378
  /**
379
   * \param[in] pWatch inotify watch
13 luk 380
   *
381
   * \throw InotifyException thrown if adding failed
3 luk 382
   */
13 luk 383
  void Add(InotifyWatch* pWatch) throw (InotifyException);
3 luk 384
 
385
  /// Adds a new watch.
386
  /**
387
   * \param[in] rWatch inotify watch
13 luk 388
   *
389
   * \throw InotifyException thrown if adding failed
3 luk 390
   */
13 luk 391
  inline void Add(InotifyWatch& rWatch) throw (InotifyException)
3 luk 392
  {
13 luk 393
    Add(&rWatch);
3 luk 394
  }
395
 
396
  /// Removes a watch.
397
  /**
398
   * If the given watch is not present it does nothing.
399
   *
400
   * \param[in] pWatch inotify watch
13 luk 401
   *
402
   * \throw InotifyException thrown if removing failed
3 luk 403
   */
13 luk 404
  void Remove(InotifyWatch* pWatch) throw (InotifyException);
3 luk 405
 
406
  /// Removes a watch.
407
  /**
408
   * If the given watch is not present it does nothing.
409
   *
410
   * \param[in] rWatch inotify watch
13 luk 411
   *
412
   * \throw InotifyException thrown if removing failed
3 luk 413
   */
13 luk 414
  inline void Remove(InotifyWatch& rWatch) throw (InotifyException)
3 luk 415
  {
416
    Remove(&rWatch);
417
  }
418
 
419
  /// Removes all watches.
420
  void RemoveAll();
421
 
422
  /// Returns the count of watches.
423
  /**
424
   * \return count of watches
425
   */
426
  inline size_t GetWatchCount() const
427
  {
428
    return (size_t) m_watches.size();
429
  }
430
 
431
  /// Waits for inotify events.
432
  /**
13 luk 433
   * It waits until one or more events occur. When called
434
   * in nonblocking mode it only retrieves occurred events
435
   * to the internal queue and exits.
3 luk 436
   *
437
   * \param[in] fNoIntr if true it re-calls the system call after a handled signal
13 luk 438
   *
439
   * \throw InotifyException thrown if reading events failed
440
   *
441
   * \sa SetNonBlock()
3 luk 442
   */
13 luk 443
  void WaitForEvents(bool fNoIntr = false) throw (InotifyException);
3 luk 444
 
445
  /// Returns the count of received and queued events.
446
  /**
447
   * This number is related to the events in the queue inside
448
   * this object, not to the events pending in the kernel.
449
   *
450
   * \return count of events
451
   */
452
  int GetEventCount();
453
 
454
  /// Extracts a queued inotify event.
455
  /**
456
   * The extracted event is removed from the queue.
457
   * If the pointer is NULL it does nothing.
458
   *
459
   * \param[in,out] pEvt event object
13 luk 460
   *
461
   * \throw InotifyException thrown if the provided pointer is NULL
3 luk 462
   */
13 luk 463
  bool GetEvent(InotifyEvent* pEvt) throw (InotifyException);
3 luk 464
 
465
  /// Extracts a queued inotify event.
466
  /**
467
   * The extracted event is removed from the queue.
468
   *
469
   * \param[in,out] rEvt event object
13 luk 470
   *
471
   * \throw InotifyException thrown only in very anomalous cases
3 luk 472
   */
13 luk 473
  bool GetEvent(InotifyEvent& rEvt) throw (InotifyException)
3 luk 474
  {
475
    return GetEvent(&rEvt);
476
  }
477
 
478
  /// Extracts a queued inotify event (without removing).
479
  /**
480
   * The extracted event stays in the queue.
481
   * If the pointer is NULL it does nothing.
482
   *
483
   * \param[in,out] pEvt event object
13 luk 484
   *
485
   * \throw InotifyException thrown if the provided pointer is NULL
3 luk 486
   */
13 luk 487
  bool PeekEvent(InotifyEvent* pEvt) throw (InotifyException);
3 luk 488
 
489
  /// Extracts a queued inotify event (without removing).
490
  /**
491
   * The extracted event stays in the queue.
492
   *
493
   * \param[in,out] rEvt event object
13 luk 494
   *
495
   * \throw InotifyException thrown only in very anomalous cases
3 luk 496
   */
13 luk 497
  bool PeekEvent(InotifyEvent& rEvt) throw (InotifyException)
3 luk 498
  {
499
    return PeekEvent(&rEvt);
500
  }
501
 
502
  /// Searches for a watch.
503
  /**
504
   * It tries to find a watch by the given descriptor.
505
   *
506
   * \param[in] iDescriptor watch descriptor
507
   * \return found descriptor; NULL if no such watch exists
508
   */
13 luk 509
  InotifyWatch* FindWatch(int iDescriptor);
510
 
511
  /// Returns the file descriptor.
512
  /**
513
   * The descriptor can be used in standard low-level file
514
   * functions (poll(), select(), fcntl() etc.).
515
   *
516
   * \return valid file descriptor or -1 for inactive object
517
   *
518
   * \sa SetNonBlock()
519
   */
520
  inline int GetDescriptor() const
521
  {
522
    return m_fd;
523
  }
524
 
525
  /// Enables/disables non-blocking mode.
526
  /**
527
   * Use this mode if you want to monitor the descriptor
528
   * (acquired thru GetDescriptor()) in functions such as
529
   * poll(), select() etc.
530
   *
531
   * \param[in] fNonBlock enable/disable non-blocking mode
532
   *
533
   * \throw InotifyException thrown if setting mode failed
534
   *
535
   * \sa GetDescriptor()
536
   */
537
  void SetNonBlock(bool fNonBlock) throw (InotifyException);
3 luk 538
 
539
private:
540
  int m_fd;                             ///< file descriptor
541
  IN_WATCH_MAP m_watches;               ///< watches
542
  unsigned char m_buf[INOTIFY_BUFLEN];  ///< buffer for events
543
  std::deque<InotifyEvent> m_events;    ///< event queue
544
};
545
 
546
 
547
#endif //_INOTIFYCXX_H_