00001
00003
00026 #ifndef _INOTIFYCXX_H_
00027 #define _INOTIFYCXX_H_
00028
00029 #include <string>
00030 #include <deque>
00031 #include <map>
00032
00033
00034 #include <sys/inotify.h>
00035
00036
00037 #ifndef __NR_inotify_init
00038 #include <sys/inotify-syscalls.h>
00039 #endif // __NR_inotify_init
00040
00042 #define INOTIFY_EVENT_SIZE (sizeof(struct inotify_event))
00043
00045 #define INOTIFY_BUFLEN (1024 * (INOTIFY_EVENT_SIZE + 16))
00046
00048
00051 #define IN_EXC_MSG(msg) (std::string(__PRETTY_FUNCTION__) + ": " + msg)
00052
00054
00072 #ifdef INOTIFY_THREAD_SAFE
00073
00074 #include <pthread.h>
00075
00076 #define IN_LOCK_DECL mutable pthread_rwlock_t __m_lock;
00077
00078 #define IN_LOCK_INIT \
00079 { \
00080 pthread_rwlockattr_t attr; \
00081 int res = 0; \
00082 if ((res = pthread_rwlockattr_init(&attr)) != 0) \
00083 throw InotifyException(IN_EXC_MSG("cannot initialize lock attributes"), res, this); \
00084 if ((res = pthread_rwlockattr_setkind_np(&attr, PTHREAD_RWLOCK_PREFER_WRITER_NP)) != 0) \
00085 throw InotifyException(IN_EXC_MSG("cannot set lock kind"), res, this); \
00086 if ((res = pthread_rwlock_init(&__m_lock, &attr)) != 0) \
00087 throw InotifyException(IN_EXC_MSG("cannot initialize lock"), res, this); \
00088 pthread_rwlockattr_destroy(&attr); \
00089 }
00090
00091 #define IN_LOCK_DONE pthread_rwlock_destroy(&__m_lock);
00092
00093 #define IN_READ_BEGIN \
00094 { \
00095 int res = pthread_rwlock_rdlock(&__m_lock); \
00096 if (res != 0) \
00097 throw InotifyException(IN_EXC_MSG("locking for reading failed"), res, (void*) this); \
00098 }
00099
00100 #define IN_READ_END \
00101 { \
00102 int res = pthread_rwlock_unlock(&__m_lock); \
00103 if (res != 0) \
00104 throw InotifyException(IN_EXC_MSG("unlocking failed"), res, (void*) this); \
00105 }
00106
00107 #define IN_READ_END_NOTHROW pthread_rwlock_unlock(&__m_lock);
00108
00109 #define IN_WRITE_BEGIN \
00110 { \
00111 int res = pthread_rwlock_wrlock(&__m_lock); \
00112 if (res != 0) \
00113 throw InotifyException(IN_EXC_MSG("locking for writing failed"), res, (void*) this); \
00114 }
00115
00116 #define IN_WRITE_END IN_READ_END
00117 #define IN_WRITE_END_NOTHROW IN_READ_END_NOTHROW
00118
00119 #else // INOTIFY_THREAD_SAFE
00120
00121 #define IN_LOCK_DECL
00122 #define IN_LOCK_INIT
00123 #define IN_LOCK_DONE
00124 #define IN_READ_BEGIN
00125 #define IN_READ_END
00126 #define IN_READ_END_NOTHROW
00127 #define IN_WRITE_BEGIN
00128 #define IN_WRITE_END
00129 #define IN_WRITE_END_NOTHROW
00130
00131 #endif // INOTIFY_THREAD_SAFE
00132
00133
00134
00135
00136
00137 class InotifyWatch;
00138 class Inotify;
00139
00140
00142
00150 class InotifyException
00151 {
00152 public:
00154
00159 InotifyException(const std::string& rMsg = "", int iErr = 0, void* pSrc = NULL)
00160 : m_msg(rMsg),
00161 m_err(iErr)
00162 {
00163 m_pSrc = pSrc;
00164 }
00165
00167
00170 inline const std::string& GetMessage() const
00171 {
00172 return m_msg;
00173 }
00174
00176
00181 inline int GetErrorNumber() const
00182 {
00183 return m_err;
00184 }
00185
00187
00190 inline void* GetSource() const
00191 {
00192 return m_pSrc;
00193 }
00194
00195 protected:
00196 std::string m_msg;
00197 int m_err;
00198 mutable void* m_pSrc;
00199 };
00200
00201
00203
00211 class InotifyEvent
00212 {
00213 public:
00215
00218 InotifyEvent()
00219 : m_uMask(0),
00220 m_uCookie(0)
00221 {
00222 m_pWatch = NULL;
00223 }
00224
00226
00233 InotifyEvent(const struct inotify_event* pEvt, InotifyWatch* pWatch)
00234 : m_uMask(0),
00235 m_uCookie(0)
00236 {
00237 if (pEvt != NULL) {
00238 m_uMask = (uint32_t) pEvt->mask;
00239 m_uCookie = (uint32_t) pEvt->cookie;
00240 if (pEvt->name != NULL)
00241 m_name = pEvt->name;
00242 m_pWatch = pWatch;
00243 }
00244 else {
00245 m_pWatch = NULL;
00246 }
00247 }
00248
00250 ~InotifyEvent() {}
00251
00253
00258 int32_t GetDescriptor() const;
00259
00261
00266 inline uint32_t GetMask() const
00267 {
00268 return m_uMask;
00269 }
00270
00272
00277 inline static bool IsType(uint32_t uValue, uint32_t uType)
00278 {
00279 return ((uValue & uType) != 0) && ((~uValue & uType) == 0);
00280 }
00281
00283
00287 inline bool IsType(uint32_t uType) const
00288 {
00289 return IsType(m_uMask, uType);
00290 }
00291
00293
00296 inline uint32_t GetCookie() const
00297 {
00298 return m_uCookie;
00299 }
00300
00302
00305 inline uint32_t GetLength() const
00306 {
00307 return (uint32_t) m_name.length();
00308 }
00309
00311
00314 inline const std::string& GetName() const
00315 {
00316 return m_name;
00317 }
00318
00320
00323 inline void GetName(std::string& rName) const
00324 {
00325 rName = GetName();
00326 }
00327
00329
00332 inline InotifyWatch* GetWatch()
00333 {
00334 return m_pWatch;
00335 }
00336
00338
00342 static uint32_t GetMaskByName(const std::string& rName);
00343
00345
00349 static void DumpTypes(uint32_t uValue, std::string& rStr);
00350
00352
00355 void DumpTypes(std::string& rStr) const;
00356
00357 private:
00358 uint32_t m_uMask;
00359 uint32_t m_uCookie;
00360 std::string m_name;
00361 InotifyWatch* m_pWatch;
00362 };
00363
00364
00365
00367
00373 class InotifyWatch
00374 {
00375 public:
00377
00385 InotifyWatch(const std::string& rPath, int32_t uMask, bool fEnabled = true)
00386 : m_path(rPath),
00387 m_uMask(uMask),
00388 m_wd((int32_t) -1),
00389 m_fEnabled(fEnabled)
00390 {
00391 IN_LOCK_INIT
00392 }
00393
00395 ~InotifyWatch()
00396 {
00397 IN_LOCK_DONE
00398 }
00399
00401
00404 inline int32_t GetDescriptor() const
00405 {
00406 return m_wd;
00407 }
00408
00410
00413 inline const std::string& GetPath() const
00414 {
00415 return m_path;
00416 }
00417
00419
00422 inline uint32_t GetMask() const
00423 {
00424 return (uint32_t) m_uMask;
00425 }
00426
00428
00437 void SetMask(uint32_t uMask) throw (InotifyException);
00438
00440
00443 inline Inotify* GetInotify()
00444 {
00445 return m_pInotify;
00446 }
00447
00449
00460 void SetEnabled(bool fEnabled) throw (InotifyException);
00461
00463
00466 inline bool IsEnabled() const
00467 {
00468 return m_fEnabled;
00469 }
00470
00471 private:
00472 friend class Inotify;
00473
00474 std::string m_path;
00475 uint32_t m_uMask;
00476 int32_t m_wd;
00477 Inotify* m_pInotify;
00478 bool m_fEnabled;
00479
00480 IN_LOCK_DECL
00481 };
00482
00483
00485 typedef std::map<int32_t, InotifyWatch*> IN_WATCH_MAP;
00486
00488 typedef std::map<std::string, InotifyWatch*> IN_WP_MAP;
00489
00490
00492
00498 class Inotify
00499 {
00500 public:
00502
00508 Inotify() throw (InotifyException);
00509
00511
00514 ~Inotify();
00515
00517 void Close();
00518
00520
00525 void Add(InotifyWatch* pWatch) throw (InotifyException);
00526
00528
00533 inline void Add(InotifyWatch& rWatch) throw (InotifyException)
00534 {
00535 Add(&rWatch);
00536 }
00537
00539
00546 void Remove(InotifyWatch* pWatch) throw (InotifyException);
00547
00549
00556 inline void Remove(InotifyWatch& rWatch) throw (InotifyException)
00557 {
00558 Remove(&rWatch);
00559 }
00560
00562 void RemoveAll();
00563
00565
00573 inline size_t GetWatchCount() const
00574 {
00575 IN_READ_BEGIN
00576 size_t n = (size_t) m_paths.size();
00577 IN_READ_END
00578 return n;
00579 }
00580
00582
00587 inline size_t GetEnabledCount() const
00588 {
00589 IN_READ_BEGIN
00590 size_t n = (size_t) m_watches.size();
00591 IN_READ_END
00592 return n;
00593 }
00594
00596
00607 void WaitForEvents(bool fNoIntr = false) throw (InotifyException);
00608
00610
00616 inline size_t GetEventCount()
00617 {
00618 IN_READ_BEGIN
00619 size_t n = (size_t) m_events.size();
00620 IN_READ_END
00621 return n;
00622 }
00623
00625
00633 bool GetEvent(InotifyEvent* pEvt) throw (InotifyException);
00634
00636
00643 bool GetEvent(InotifyEvent& rEvt) throw (InotifyException)
00644 {
00645 return GetEvent(&rEvt);
00646 }
00647
00649
00657 bool PeekEvent(InotifyEvent* pEvt) throw (InotifyException);
00658
00660
00667 bool PeekEvent(InotifyEvent& rEvt) throw (InotifyException)
00668 {
00669 return PeekEvent(&rEvt);
00670 }
00671
00673
00679 InotifyWatch* FindWatch(int iDescriptor);
00680
00682
00692 InotifyWatch* FindWatch(const std::string& rPath);
00693
00695
00703 inline int GetDescriptor() const
00704 {
00705 return m_fd;
00706 }
00707
00709
00720 void SetNonBlock(bool fNonBlock) throw (InotifyException);
00721
00722 private:
00723 int m_fd;
00724 IN_WATCH_MAP m_watches;
00725 IN_WP_MAP m_paths;
00726 unsigned char m_buf[INOTIFY_BUFLEN];
00727 std::deque<InotifyEvent> m_events;
00728
00729 IN_LOCK_DECL
00730
00731 friend class InotifyWatch;
00732 };
00733
00734
00735 #endif //_INOTIFYCXX_H_
00736