00001
00003
00029 #ifndef _INOTIFYCXX_H_
00030 #define _INOTIFYCXX_H_
00031
00032 #include <stdint.h>
00033 #include <string>
00034 #include <deque>
00035 #include <map>
00036
00037
00038 #include <sys/inotify.h>
00039
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 typedef enum
00055 {
00056 IN_MAX_EVENTS = 0,
00057 IN_MAX_INSTANCES = 1,
00058 IN_MAX_WATCHES = 2
00059 } InotifyCapability_t;
00060
00062
00080 #ifdef INOTIFY_THREAD_SAFE
00081
00082 #include <pthread.h>
00083
00084 #define IN_LOCK_DECL mutable pthread_rwlock_t __m_lock;
00085
00086 #define IN_LOCK_INIT \
00087 { \
00088 pthread_rwlockattr_t attr; \
00089 int res = 0; \
00090 if ((res = pthread_rwlockattr_init(&attr)) != 0) \
00091 throw InotifyException(IN_EXC_MSG("cannot initialize lock attributes"), res, this); \
00092 if ((res = pthread_rwlockattr_setkind_np(&attr, PTHREAD_RWLOCK_PREFER_WRITER_NP)) != 0) \
00093 throw InotifyException(IN_EXC_MSG("cannot set lock kind"), res, this); \
00094 if ((res = pthread_rwlock_init(&__m_lock, &attr)) != 0) \
00095 throw InotifyException(IN_EXC_MSG("cannot initialize lock"), res, this); \
00096 pthread_rwlockattr_destroy(&attr); \
00097 }
00098
00099 #define IN_LOCK_DONE pthread_rwlock_destroy(&__m_lock);
00100
00101 #define IN_READ_BEGIN \
00102 { \
00103 int res = pthread_rwlock_rdlock(&__m_lock); \
00104 if (res != 0) \
00105 throw InotifyException(IN_EXC_MSG("locking for reading failed"), res, (void*) this); \
00106 }
00107
00108 #define IN_READ_END \
00109 { \
00110 int res = pthread_rwlock_unlock(&__m_lock); \
00111 if (res != 0) \
00112 throw InotifyException(IN_EXC_MSG("unlocking failed"), res, (void*) this); \
00113 }
00114
00115 #define IN_READ_END_NOTHROW pthread_rwlock_unlock(&__m_lock);
00116
00117 #define IN_WRITE_BEGIN \
00118 { \
00119 int res = pthread_rwlock_wrlock(&__m_lock); \
00120 if (res != 0) \
00121 throw InotifyException(IN_EXC_MSG("locking for writing failed"), res, (void*) this); \
00122 }
00123
00124 #define IN_WRITE_END IN_READ_END
00125 #define IN_WRITE_END_NOTHROW IN_READ_END_NOTHROW
00126
00127 #else // INOTIFY_THREAD_SAFE
00128
00129 #define IN_LOCK_DECL
00130 #define IN_LOCK_INIT
00131 #define IN_LOCK_DONE
00132 #define IN_READ_BEGIN
00133 #define IN_READ_END
00134 #define IN_READ_END_NOTHROW
00135 #define IN_WRITE_BEGIN
00136 #define IN_WRITE_END
00137 #define IN_WRITE_END_NOTHROW
00138
00139 #endif // INOTIFY_THREAD_SAFE
00140
00141
00142
00143
00144
00145 class InotifyWatch;
00146 class Inotify;
00147
00148
00150
00158 class InotifyException
00159 {
00160 public:
00162
00167 InotifyException(const std::string& rMsg = "", int iErr = 0, void* pSrc = NULL)
00168 : m_msg(rMsg),
00169 m_err(iErr)
00170 {
00171 m_pSrc = pSrc;
00172 }
00173
00175
00178 inline const std::string& GetMessage() const
00179 {
00180 return m_msg;
00181 }
00182
00184
00189 inline int GetErrorNumber() const
00190 {
00191 return m_err;
00192 }
00193
00195
00198 inline void* GetSource() const
00199 {
00200 return m_pSrc;
00201 }
00202
00203 protected:
00204 std::string m_msg;
00205 int m_err;
00206 mutable void* m_pSrc;
00207 };
00208
00209
00211
00219 class InotifyEvent
00220 {
00221 public:
00223
00226 InotifyEvent()
00227 : m_uMask(0),
00228 m_uCookie(0)
00229 {
00230 m_pWatch = NULL;
00231 }
00232
00234
00241 InotifyEvent(const struct inotify_event* pEvt, InotifyWatch* pWatch)
00242 : m_uMask(0),
00243 m_uCookie(0)
00244 {
00245 if (pEvt != NULL) {
00246 m_uMask = (uint32_t) pEvt->mask;
00247 m_uCookie = (uint32_t) pEvt->cookie;
00248 if (pEvt->name != NULL) {
00249 m_name = pEvt->len > 0
00250 ? pEvt->name
00251 : "";
00252 }
00253 m_pWatch = pWatch;
00254 }
00255 else {
00256 m_pWatch = NULL;
00257 }
00258 }
00259
00261 ~InotifyEvent() {}
00262
00264
00269 int32_t GetDescriptor() const;
00270
00272
00277 inline uint32_t GetMask() const
00278 {
00279 return m_uMask;
00280 }
00281
00283
00288 inline static bool IsType(uint32_t uValue, uint32_t uType)
00289 {
00290 return ((uValue & uType) != 0) && ((~uValue & uType) == 0);
00291 }
00292
00294
00298 inline bool IsType(uint32_t uType) const
00299 {
00300 return IsType(m_uMask, uType);
00301 }
00302
00304
00307 inline uint32_t GetCookie() const
00308 {
00309 return m_uCookie;
00310 }
00311
00313
00316 inline uint32_t GetLength() const
00317 {
00318 return (uint32_t) m_name.length();
00319 }
00320
00322
00325 inline const std::string& GetName() const
00326 {
00327 return m_name;
00328 }
00329
00331
00334 inline void GetName(std::string& rName) const
00335 {
00336 rName = GetName();
00337 }
00338
00340
00343 inline InotifyWatch* GetWatch()
00344 {
00345 return m_pWatch;
00346 }
00347
00349
00353 static uint32_t GetMaskByName(const std::string& rName);
00354
00356
00360 static void DumpTypes(uint32_t uValue, std::string& rStr);
00361
00363
00366 void DumpTypes(std::string& rStr) const;
00367
00368 private:
00369 uint32_t m_uMask;
00370 uint32_t m_uCookie;
00371 std::string m_name;
00372 InotifyWatch* m_pWatch;
00373 };
00374
00375
00376
00378
00384 class InotifyWatch
00385 {
00386 public:
00388
00396 InotifyWatch(const std::string& rPath, int32_t uMask, bool fEnabled = true)
00397 : m_path(rPath),
00398 m_uMask(uMask),
00399 m_wd((int32_t) -1),
00400 m_fEnabled(fEnabled)
00401 {
00402 IN_LOCK_INIT
00403 }
00404
00406 ~InotifyWatch()
00407 {
00408 IN_LOCK_DONE
00409 }
00410
00412
00415 inline int32_t GetDescriptor() const
00416 {
00417 return m_wd;
00418 }
00419
00421
00424 inline const std::string& GetPath() const
00425 {
00426 return m_path;
00427 }
00428
00430
00433 inline uint32_t GetMask() const
00434 {
00435 return (uint32_t) m_uMask;
00436 }
00437
00439
00448 void SetMask(uint32_t uMask) throw (InotifyException);
00449
00451
00454 inline Inotify* GetInotify()
00455 {
00456 return m_pInotify;
00457 }
00458
00460
00471 void SetEnabled(bool fEnabled) throw (InotifyException);
00472
00474
00477 inline bool IsEnabled() const
00478 {
00479 return m_fEnabled;
00480 }
00481
00483
00492 inline bool IsRecursive() const
00493 {
00494 return false;
00495 }
00496
00497 private:
00498 friend class Inotify;
00499
00500 std::string m_path;
00501 uint32_t m_uMask;
00502 int32_t m_wd;
00503 Inotify* m_pInotify;
00504 bool m_fEnabled;
00505
00506 IN_LOCK_DECL
00507
00509
00514 void __Disable();
00515 };
00516
00517
00519 typedef std::map<int32_t, InotifyWatch*> IN_WATCH_MAP;
00520
00522 typedef std::map<std::string, InotifyWatch*> IN_WP_MAP;
00523
00524
00526
00532 class Inotify
00533 {
00534 public:
00536
00542 Inotify() throw (InotifyException);
00543
00545
00548 ~Inotify();
00549
00551 void Close();
00552
00554
00559 void Add(InotifyWatch* pWatch) throw (InotifyException);
00560
00562
00567 inline void Add(InotifyWatch& rWatch) throw (InotifyException)
00568 {
00569 Add(&rWatch);
00570 }
00571
00573
00580 void Remove(InotifyWatch* pWatch) throw (InotifyException);
00581
00583
00590 inline void Remove(InotifyWatch& rWatch) throw (InotifyException)
00591 {
00592 Remove(&rWatch);
00593 }
00594
00596 void RemoveAll();
00597
00599
00607 inline size_t GetWatchCount() const
00608 {
00609 IN_READ_BEGIN
00610 size_t n = (size_t) m_paths.size();
00611 IN_READ_END
00612 return n;
00613 }
00614
00616
00621 inline size_t GetEnabledCount() const
00622 {
00623 IN_READ_BEGIN
00624 size_t n = (size_t) m_watches.size();
00625 IN_READ_END
00626 return n;
00627 }
00628
00630
00641 void WaitForEvents(bool fNoIntr = false) throw (InotifyException);
00642
00644
00650 inline size_t GetEventCount()
00651 {
00652 IN_READ_BEGIN
00653 size_t n = (size_t) m_events.size();
00654 IN_READ_END
00655 return n;
00656 }
00657
00659
00667 bool GetEvent(InotifyEvent* pEvt) throw (InotifyException);
00668
00670
00677 bool GetEvent(InotifyEvent& rEvt) throw (InotifyException)
00678 {
00679 return GetEvent(&rEvt);
00680 }
00681
00683
00691 bool PeekEvent(InotifyEvent* pEvt) throw (InotifyException);
00692
00694
00701 bool PeekEvent(InotifyEvent& rEvt) throw (InotifyException)
00702 {
00703 return PeekEvent(&rEvt);
00704 }
00705
00707
00713 InotifyWatch* FindWatch(int iDescriptor);
00714
00716
00726 InotifyWatch* FindWatch(const std::string& rPath);
00727
00729
00737 inline int GetDescriptor() const
00738 {
00739 return m_fd;
00740 }
00741
00743
00756 void SetNonBlock(bool fNonBlock) throw (InotifyException);
00757
00759
00772 void SetCloseOnExec(bool fClOnEx) throw (InotifyException);
00773
00775
00780 static uint32_t GetCapability(InotifyCapability_t cap) throw (InotifyException);
00781
00783
00791 static void SetCapability(InotifyCapability_t cap, uint32_t val) throw (InotifyException);
00792
00794
00798 inline static uint32_t GetMaxEvents() throw (InotifyException)
00799 {
00800 return GetCapability(IN_MAX_EVENTS);
00801 }
00802
00804
00812 inline static void SetMaxEvents(uint32_t val) throw (InotifyException)
00813 {
00814 SetCapability(IN_MAX_EVENTS, val);
00815 }
00816
00818
00825 inline static uint32_t GetMaxInstances() throw (InotifyException)
00826 {
00827 return GetCapability(IN_MAX_INSTANCES);
00828 }
00829
00831
00839 inline static void SetMaxInstances(uint32_t val) throw (InotifyException)
00840 {
00841 SetCapability(IN_MAX_INSTANCES, val);
00842 }
00843
00845
00852 inline static uint32_t GetMaxWatches() throw (InotifyException)
00853 {
00854 return GetCapability(IN_MAX_WATCHES);
00855 }
00856
00858
00866 inline static void SetMaxWatches(uint32_t val) throw (InotifyException)
00867 {
00868 SetCapability(IN_MAX_WATCHES, val);
00869 }
00870
00871 private:
00872 int m_fd;
00873 IN_WATCH_MAP m_watches;
00874 IN_WP_MAP m_paths;
00875 unsigned char m_buf[INOTIFY_BUFLEN];
00876 std::deque<InotifyEvent> m_events;
00877
00878 IN_LOCK_DECL
00879
00880 friend class InotifyWatch;
00881
00882 static std::string GetCapabilityPath(InotifyCapability_t cap) throw (InotifyException);
00883 };
00884
00885
00886 #endif //_INOTIFYCXX_H_
00887