Subversion Repositories public

Rev

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

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