00001
00003
00026 #ifndef _INOTIFYCXX_H_
00027 #define _INOTIFYCXX_H_
00028
00029 #include <stdint.h>
00030 #include <string>
00031 #include <deque>
00032 #include <map>
00033
00034
00035 #include <sys/syscall.h>
00036 #include <sys/inotify.h>
00037
00038
00039 #ifndef __NR_inotify_init
00040 #include <sys/inotify-syscalls.h>
00041 #endif // __NR_inotify_init
00042
00044 #define INOTIFY_EVENT_SIZE (sizeof(struct inotify_event))
00045
00047 #define INOTIFY_BUFLEN (1024 * (INOTIFY_EVENT_SIZE + 16))
00048
00050
00053 #define IN_EXC_MSG(msg) (std::string(__PRETTY_FUNCTION__) + ": " + msg)
00054
00056 typedef enum
00057 {
00058 IN_MAX_EVENTS = 0,
00059 IN_MAX_INSTANCES = 1,
00060 IN_MAX_WATCHES = 2
00061 } InotifyCapability_t;
00062
00064
00082 #ifdef INOTIFY_THREAD_SAFE
00083
00084 #include <pthread.h>
00085
00086 #define IN_LOCK_DECL mutable pthread_rwlock_t __m_lock;
00087
00088 #define IN_LOCK_INIT \
00089 { \
00090 pthread_rwlockattr_t attr; \
00091 int res = 0; \
00092 if ((res = pthread_rwlockattr_init(&attr)) != 0) \
00093 throw InotifyException(IN_EXC_MSG("cannot initialize lock attributes"), res, this); \
00094 if ((res = pthread_rwlockattr_setkind_np(&attr, PTHREAD_RWLOCK_PREFER_WRITER_NP)) != 0) \
00095 throw InotifyException(IN_EXC_MSG("cannot set lock kind"), res, this); \
00096 if ((res = pthread_rwlock_init(&__m_lock, &attr)) != 0) \
00097 throw InotifyException(IN_EXC_MSG("cannot initialize lock"), res, this); \
00098 pthread_rwlockattr_destroy(&attr); \
00099 }
00100
00101 #define IN_LOCK_DONE pthread_rwlock_destroy(&__m_lock);
00102
00103 #define IN_READ_BEGIN \
00104 { \
00105 int res = pthread_rwlock_rdlock(&__m_lock); \
00106 if (res != 0) \
00107 throw InotifyException(IN_EXC_MSG("locking for reading failed"), res, (void*) this); \
00108 }
00109
00110 #define IN_READ_END \
00111 { \
00112 int res = pthread_rwlock_unlock(&__m_lock); \
00113 if (res != 0) \
00114 throw InotifyException(IN_EXC_MSG("unlocking failed"), res, (void*) this); \
00115 }
00116
00117 #define IN_READ_END_NOTHROW pthread_rwlock_unlock(&__m_lock);
00118
00119 #define IN_WRITE_BEGIN \
00120 { \
00121 int res = pthread_rwlock_wrlock(&__m_lock); \
00122 if (res != 0) \
00123 throw InotifyException(IN_EXC_MSG("locking for writing failed"), res, (void*) this); \
00124 }
00125
00126 #define IN_WRITE_END IN_READ_END
00127 #define IN_WRITE_END_NOTHROW IN_READ_END_NOTHROW
00128
00129 #else // INOTIFY_THREAD_SAFE
00130
00131 #define IN_LOCK_DECL
00132 #define IN_LOCK_INIT
00133 #define IN_LOCK_DONE
00134 #define IN_READ_BEGIN
00135 #define IN_READ_END
00136 #define IN_READ_END_NOTHROW
00137 #define IN_WRITE_BEGIN
00138 #define IN_WRITE_END
00139 #define IN_WRITE_END_NOTHROW
00140
00141 #endif // INOTIFY_THREAD_SAFE
00142
00143
00144
00145
00146
00147 class InotifyWatch;
00148 class Inotify;
00149
00150
00152
00160 class InotifyException
00161 {
00162 public:
00164
00169 InotifyException(const std::string& rMsg = "", int iErr = 0, void* pSrc = NULL)
00170 : m_msg(rMsg),
00171 m_err(iErr)
00172 {
00173 m_pSrc = pSrc;
00174 }
00175
00177
00180 inline const std::string& GetMessage() const
00181 {
00182 return m_msg;
00183 }
00184
00186
00191 inline int GetErrorNumber() const
00192 {
00193 return m_err;
00194 }
00195
00197
00200 inline void* GetSource() const
00201 {
00202 return m_pSrc;
00203 }
00204
00205 protected:
00206 std::string m_msg;
00207 int m_err;
00208 mutable void* m_pSrc;
00209 };
00210
00211
00213
00221 class InotifyEvent
00222 {
00223 public:
00225
00228 InotifyEvent()
00229 : m_uMask(0),
00230 m_uCookie(0)
00231 {
00232 m_pWatch = NULL;
00233 }
00234
00236
00243 InotifyEvent(const struct inotify_event* pEvt, InotifyWatch* pWatch)
00244 : m_uMask(0),
00245 m_uCookie(0)
00246 {
00247 if (pEvt != NULL) {
00248 m_uMask = (uint32_t) pEvt->mask;
00249 m_uCookie = (uint32_t) pEvt->cookie;
00250 if (pEvt->name != NULL) {
00251 m_name = pEvt->len > 0
00252 ? pEvt->name
00253 : "";
00254 }
00255 m_pWatch = pWatch;
00256 }
00257 else {
00258 m_pWatch = NULL;
00259 }
00260 }
00261
00263 ~InotifyEvent() {}
00264
00266
00271 int32_t GetDescriptor() const;
00272
00274
00279 inline uint32_t GetMask() const
00280 {
00281 return m_uMask;
00282 }
00283
00285
00290 inline static bool IsType(uint32_t uValue, uint32_t uType)
00291 {
00292 return ((uValue & uType) != 0) && ((~uValue & uType) == 0);
00293 }
00294
00296
00300 inline bool IsType(uint32_t uType) const
00301 {
00302 return IsType(m_uMask, uType);
00303 }
00304
00306
00309 inline uint32_t GetCookie() const
00310 {
00311 return m_uCookie;
00312 }
00313
00315
00318 inline uint32_t GetLength() const
00319 {
00320 return (uint32_t) m_name.length();
00321 }
00322
00324
00327 inline const std::string& GetName() const
00328 {
00329 return m_name;
00330 }
00331
00333
00336 inline void GetName(std::string& rName) const
00337 {
00338 rName = GetName();
00339 }
00340
00342
00345 inline InotifyWatch* GetWatch()
00346 {
00347 return m_pWatch;
00348 }
00349
00351
00355 static uint32_t GetMaskByName(const std::string& rName);
00356
00358
00362 static void DumpTypes(uint32_t uValue, std::string& rStr);
00363
00365
00368 void DumpTypes(std::string& rStr) const;
00369
00370 private:
00371 uint32_t m_uMask;
00372 uint32_t m_uCookie;
00373 std::string m_name;
00374 InotifyWatch* m_pWatch;
00375 };
00376
00377
00378
00380
00386 class InotifyWatch
00387 {
00388 public:
00390
00398 InotifyWatch(const std::string& rPath, int32_t uMask, bool fEnabled = true)
00399 : m_path(rPath),
00400 m_uMask(uMask),
00401 m_wd((int32_t) -1),
00402 m_fEnabled(fEnabled)
00403 {
00404 IN_LOCK_INIT
00405 }
00406
00408 ~InotifyWatch()
00409 {
00410 IN_LOCK_DONE
00411 }
00412
00414
00417 inline int32_t GetDescriptor() const
00418 {
00419 return m_wd;
00420 }
00421
00423
00426 inline const std::string& GetPath() const
00427 {
00428 return m_path;
00429 }
00430
00432
00435 inline uint32_t GetMask() const
00436 {
00437 return (uint32_t) m_uMask;
00438 }
00439
00441
00450 void SetMask(uint32_t uMask) throw (InotifyException);
00451
00453
00456 inline Inotify* GetInotify()
00457 {
00458 return m_pInotify;
00459 }
00460
00462
00473 void SetEnabled(bool fEnabled) throw (InotifyException);
00474
00476
00479 inline bool IsEnabled() const
00480 {
00481 return m_fEnabled;
00482 }
00483
00485
00494 inline bool IsRecursive() const
00495 {
00496 return false;
00497 }
00498
00499 private:
00500 friend class Inotify;
00501
00502 std::string m_path;
00503 uint32_t m_uMask;
00504 int32_t m_wd;
00505 Inotify* m_pInotify;
00506 bool m_fEnabled;
00507
00508 IN_LOCK_DECL
00509
00511
00516 void __Disable();
00517 };
00518
00519
00521 typedef std::map<int32_t, InotifyWatch*> IN_WATCH_MAP;
00522
00524 typedef std::map<std::string, InotifyWatch*> IN_WP_MAP;
00525
00526
00528
00534 class Inotify
00535 {
00536 public:
00538
00544 Inotify() throw (InotifyException);
00545
00547
00550 ~Inotify();
00551
00553 void Close();
00554
00556
00561 void Add(InotifyWatch* pWatch) throw (InotifyException);
00562
00564
00569 inline void Add(InotifyWatch& rWatch) throw (InotifyException)
00570 {
00571 Add(&rWatch);
00572 }
00573
00575
00582 void Remove(InotifyWatch* pWatch) throw (InotifyException);
00583
00585
00592 inline void Remove(InotifyWatch& rWatch) throw (InotifyException)
00593 {
00594 Remove(&rWatch);
00595 }
00596
00598 void RemoveAll();
00599
00601
00609 inline size_t GetWatchCount() const
00610 {
00611 IN_READ_BEGIN
00612 size_t n = (size_t) m_paths.size();
00613 IN_READ_END
00614 return n;
00615 }
00616
00618
00623 inline size_t GetEnabledCount() const
00624 {
00625 IN_READ_BEGIN
00626 size_t n = (size_t) m_watches.size();
00627 IN_READ_END
00628 return n;
00629 }
00630
00632
00643 void WaitForEvents(bool fNoIntr = false) throw (InotifyException);
00644
00646
00652 inline size_t GetEventCount()
00653 {
00654 IN_READ_BEGIN
00655 size_t n = (size_t) m_events.size();
00656 IN_READ_END
00657 return n;
00658 }
00659
00661
00669 bool GetEvent(InotifyEvent* pEvt) throw (InotifyException);
00670
00672
00679 bool GetEvent(InotifyEvent& rEvt) throw (InotifyException)
00680 {
00681 return GetEvent(&rEvt);
00682 }
00683
00685
00693 bool PeekEvent(InotifyEvent* pEvt) throw (InotifyException);
00694
00696
00703 bool PeekEvent(InotifyEvent& rEvt) throw (InotifyException)
00704 {
00705 return PeekEvent(&rEvt);
00706 }
00707
00709
00715 InotifyWatch* FindWatch(int iDescriptor);
00716
00718
00728 InotifyWatch* FindWatch(const std::string& rPath);
00729
00731
00739 inline int GetDescriptor() const
00740 {
00741 return m_fd;
00742 }
00743
00745
00758 void SetNonBlock(bool fNonBlock) throw (InotifyException);
00759
00761
00774 void SetCloseOnExec(bool fClOnEx) throw (InotifyException);
00775
00777
00782 static uint32_t GetCapability(InotifyCapability_t cap) throw (InotifyException);
00783
00785
00793 static void SetCapability(InotifyCapability_t cap, uint32_t val) throw (InotifyException);
00794
00796
00800 inline static uint32_t GetMaxEvents() throw (InotifyException)
00801 {
00802 return GetCapability(IN_MAX_EVENTS);
00803 }
00804
00806
00814 inline static void SetMaxEvents(uint32_t val) throw (InotifyException)
00815 {
00816 SetCapability(IN_MAX_EVENTS, val);
00817 }
00818
00820
00827 inline static uint32_t GetMaxInstances() throw (InotifyException)
00828 {
00829 return GetCapability(IN_MAX_INSTANCES);
00830 }
00831
00833
00841 inline static void SetMaxInstances(uint32_t val) throw (InotifyException)
00842 {
00843 SetCapability(IN_MAX_INSTANCES, val);
00844 }
00845
00847
00854 inline static uint32_t GetMaxWatches() throw (InotifyException)
00855 {
00856 return GetCapability(IN_MAX_WATCHES);
00857 }
00858
00860
00868 inline static void SetMaxWatches(uint32_t val) throw (InotifyException)
00869 {
00870 SetCapability(IN_MAX_WATCHES, val);
00871 }
00872
00873 private:
00874 int m_fd;
00875 IN_WATCH_MAP m_watches;
00876 IN_WP_MAP m_paths;
00877 unsigned char m_buf[INOTIFY_BUFLEN];
00878 std::deque<InotifyEvent> m_events;
00879
00880 IN_LOCK_DECL
00881
00882 friend class InotifyWatch;
00883
00884 static std::string GetCapabilityPath(InotifyCapability_t cap) throw (InotifyException);
00885 };
00886
00887
00888 #endif //_INOTIFYCXX_H_
00889