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/syscall.h>
00035 #include <sys/inotify.h>
00036
00037
00038 #ifndef __NR_inotify_init
00039 #include <sys/inotify-syscalls.h>
00040 #endif // __NR_inotify_init
00041
00043 #define INOTIFY_EVENT_SIZE (sizeof(struct inotify_event))
00044
00046 #define INOTIFY_BUFLEN (1024 * (INOTIFY_EVENT_SIZE + 16))
00047
00049
00052 #define IN_EXC_MSG(msg) (std::string(__PRETTY_FUNCTION__) + ": " + msg)
00053
00055 typedef enum
00056 {
00057 IN_MAX_EVENTS = 0,
00058 IN_MAX_INSTANCES = 1,
00059 IN_MAX_WATCHES = 2
00060 } InotifyCapability_t;
00061
00063
00081 #ifdef INOTIFY_THREAD_SAFE
00082
00083 #include <pthread.h>
00084
00085 #define IN_LOCK_DECL mutable pthread_rwlock_t __m_lock;
00086
00087 #define IN_LOCK_INIT \
00088 { \
00089 pthread_rwlockattr_t attr; \
00090 int res = 0; \
00091 if ((res = pthread_rwlockattr_init(&attr)) != 0) \
00092 throw InotifyException(IN_EXC_MSG("cannot initialize lock attributes"), res, this); \
00093 if ((res = pthread_rwlockattr_setkind_np(&attr, PTHREAD_RWLOCK_PREFER_WRITER_NP)) != 0) \
00094 throw InotifyException(IN_EXC_MSG("cannot set lock kind"), res, this); \
00095 if ((res = pthread_rwlock_init(&__m_lock, &attr)) != 0) \
00096 throw InotifyException(IN_EXC_MSG("cannot initialize lock"), res, this); \
00097 pthread_rwlockattr_destroy(&attr); \
00098 }
00099
00100 #define IN_LOCK_DONE pthread_rwlock_destroy(&__m_lock);
00101
00102 #define IN_READ_BEGIN \
00103 { \
00104 int res = pthread_rwlock_rdlock(&__m_lock); \
00105 if (res != 0) \
00106 throw InotifyException(IN_EXC_MSG("locking for reading failed"), res, (void*) this); \
00107 }
00108
00109 #define IN_READ_END \
00110 { \
00111 int res = pthread_rwlock_unlock(&__m_lock); \
00112 if (res != 0) \
00113 throw InotifyException(IN_EXC_MSG("unlocking failed"), res, (void*) this); \
00114 }
00115
00116 #define IN_READ_END_NOTHROW pthread_rwlock_unlock(&__m_lock);
00117
00118 #define IN_WRITE_BEGIN \
00119 { \
00120 int res = pthread_rwlock_wrlock(&__m_lock); \
00121 if (res != 0) \
00122 throw InotifyException(IN_EXC_MSG("locking for writing failed"), res, (void*) this); \
00123 }
00124
00125 #define IN_WRITE_END IN_READ_END
00126 #define IN_WRITE_END_NOTHROW IN_READ_END_NOTHROW
00127
00128 #else // INOTIFY_THREAD_SAFE
00129
00130 #define IN_LOCK_DECL
00131 #define IN_LOCK_INIT
00132 #define IN_LOCK_DONE
00133 #define IN_READ_BEGIN
00134 #define IN_READ_END
00135 #define IN_READ_END_NOTHROW
00136 #define IN_WRITE_BEGIN
00137 #define IN_WRITE_END
00138 #define IN_WRITE_END_NOTHROW
00139
00140 #endif // INOTIFY_THREAD_SAFE
00141
00142
00143
00144
00145
00146 class InotifyWatch;
00147 class Inotify;
00148
00149
00151
00159 class InotifyException
00160 {
00161 public:
00163
00168 InotifyException(const std::string& rMsg = "", int iErr = 0, void* pSrc = NULL)
00169 : m_msg(rMsg),
00170 m_err(iErr)
00171 {
00172 m_pSrc = pSrc;
00173 }
00174
00176
00179 inline const std::string& GetMessage() const
00180 {
00181 return m_msg;
00182 }
00183
00185
00190 inline int GetErrorNumber() const
00191 {
00192 return m_err;
00193 }
00194
00196
00199 inline void* GetSource() const
00200 {
00201 return m_pSrc;
00202 }
00203
00204 protected:
00205 std::string m_msg;
00206 int m_err;
00207 mutable void* m_pSrc;
00208 };
00209
00210
00212
00220 class InotifyEvent
00221 {
00222 public:
00224
00227 InotifyEvent()
00228 : m_uMask(0),
00229 m_uCookie(0)
00230 {
00231 m_pWatch = NULL;
00232 }
00233
00235
00242 InotifyEvent(const struct inotify_event* pEvt, InotifyWatch* pWatch)
00243 : m_uMask(0),
00244 m_uCookie(0)
00245 {
00246 if (pEvt != NULL) {
00247 m_uMask = (uint32_t) pEvt->mask;
00248 m_uCookie = (uint32_t) pEvt->cookie;
00249 if (pEvt->name != NULL)
00250 m_name = pEvt->name;
00251 m_pWatch = pWatch;
00252 }
00253 else {
00254 m_pWatch = NULL;
00255 }
00256 }
00257
00259 ~InotifyEvent() {}
00260
00262
00267 int32_t GetDescriptor() const;
00268
00270
00275 inline uint32_t GetMask() const
00276 {
00277 return m_uMask;
00278 }
00279
00281
00286 inline static bool IsType(uint32_t uValue, uint32_t uType)
00287 {
00288 return ((uValue & uType) != 0) && ((~uValue & uType) == 0);
00289 }
00290
00292
00296 inline bool IsType(uint32_t uType) const
00297 {
00298 return IsType(m_uMask, uType);
00299 }
00300
00302
00305 inline uint32_t GetCookie() const
00306 {
00307 return m_uCookie;
00308 }
00309
00311
00314 inline uint32_t GetLength() const
00315 {
00316 return (uint32_t) m_name.length();
00317 }
00318
00320
00323 inline const std::string& GetName() const
00324 {
00325 return m_name;
00326 }
00327
00329
00332 inline void GetName(std::string& rName) const
00333 {
00334 rName = GetName();
00335 }
00336
00338
00341 inline InotifyWatch* GetWatch()
00342 {
00343 return m_pWatch;
00344 }
00345
00347
00351 static uint32_t GetMaskByName(const std::string& rName);
00352
00354
00358 static void DumpTypes(uint32_t uValue, std::string& rStr);
00359
00361
00364 void DumpTypes(std::string& rStr) const;
00365
00366 private:
00367 uint32_t m_uMask;
00368 uint32_t m_uCookie;
00369 std::string m_name;
00370 InotifyWatch* m_pWatch;
00371 };
00372
00373
00374
00376
00382 class InotifyWatch
00383 {
00384 public:
00386
00394 InotifyWatch(const std::string& rPath, int32_t uMask, bool fEnabled = true)
00395 : m_path(rPath),
00396 m_uMask(uMask),
00397 m_wd((int32_t) -1),
00398 m_fEnabled(fEnabled)
00399 {
00400 IN_LOCK_INIT
00401 }
00402
00404 ~InotifyWatch()
00405 {
00406 IN_LOCK_DONE
00407 }
00408
00410
00413 inline int32_t GetDescriptor() const
00414 {
00415 return m_wd;
00416 }
00417
00419
00422 inline const std::string& GetPath() const
00423 {
00424 return m_path;
00425 }
00426
00428
00431 inline uint32_t GetMask() const
00432 {
00433 return (uint32_t) m_uMask;
00434 }
00435
00437
00446 void SetMask(uint32_t uMask) throw (InotifyException);
00447
00449
00452 inline Inotify* GetInotify()
00453 {
00454 return m_pInotify;
00455 }
00456
00458
00469 void SetEnabled(bool fEnabled) throw (InotifyException);
00470
00472
00475 inline bool IsEnabled() const
00476 {
00477 return m_fEnabled;
00478 }
00479
00481
00490 inline bool IsRecursive() const
00491 {
00492 return false;
00493 }
00494
00495 private:
00496 friend class Inotify;
00497
00498 std::string m_path;
00499 uint32_t m_uMask;
00500 int32_t m_wd;
00501 Inotify* m_pInotify;
00502 bool m_fEnabled;
00503
00504 IN_LOCK_DECL
00505
00507
00512 void OnOneshotEvent();
00513 };
00514
00515
00517 typedef std::map<int32_t, InotifyWatch*> IN_WATCH_MAP;
00518
00520 typedef std::map<std::string, InotifyWatch*> IN_WP_MAP;
00521
00522
00524
00530 class Inotify
00531 {
00532 public:
00534
00540 Inotify() throw (InotifyException);
00541
00543
00546 ~Inotify();
00547
00549 void Close();
00550
00552
00557 void Add(InotifyWatch* pWatch) throw (InotifyException);
00558
00560
00565 inline void Add(InotifyWatch& rWatch) throw (InotifyException)
00566 {
00567 Add(&rWatch);
00568 }
00569
00571
00578 void Remove(InotifyWatch* pWatch) throw (InotifyException);
00579
00581
00588 inline void Remove(InotifyWatch& rWatch) throw (InotifyException)
00589 {
00590 Remove(&rWatch);
00591 }
00592
00594 void RemoveAll();
00595
00597
00605 inline size_t GetWatchCount() const
00606 {
00607 IN_READ_BEGIN
00608 size_t n = (size_t) m_paths.size();
00609 IN_READ_END
00610 return n;
00611 }
00612
00614
00619 inline size_t GetEnabledCount() const
00620 {
00621 IN_READ_BEGIN
00622 size_t n = (size_t) m_watches.size();
00623 IN_READ_END
00624 return n;
00625 }
00626
00628
00639 void WaitForEvents(bool fNoIntr = false) throw (InotifyException);
00640
00642
00648 inline size_t GetEventCount()
00649 {
00650 IN_READ_BEGIN
00651 size_t n = (size_t) m_events.size();
00652 IN_READ_END
00653 return n;
00654 }
00655
00657
00665 bool GetEvent(InotifyEvent* pEvt) throw (InotifyException);
00666
00668
00675 bool GetEvent(InotifyEvent& rEvt) throw (InotifyException)
00676 {
00677 return GetEvent(&rEvt);
00678 }
00679
00681
00689 bool PeekEvent(InotifyEvent* pEvt) throw (InotifyException);
00690
00692
00699 bool PeekEvent(InotifyEvent& rEvt) throw (InotifyException)
00700 {
00701 return PeekEvent(&rEvt);
00702 }
00703
00705
00711 InotifyWatch* FindWatch(int iDescriptor);
00712
00714
00724 InotifyWatch* FindWatch(const std::string& rPath);
00725
00727
00735 inline int GetDescriptor() const
00736 {
00737 return m_fd;
00738 }
00739
00741
00752 void SetNonBlock(bool fNonBlock) throw (InotifyException);
00753
00755
00760 static uint32_t GetCapability(InotifyCapability_t cap) throw (InotifyException);
00761
00763
00771 static void SetCapability(InotifyCapability_t cap, uint32_t val) throw (InotifyException);
00772
00774
00778 inline static uint32_t GetMaxEvents() throw (InotifyException)
00779 {
00780 return GetCapability(IN_MAX_EVENTS);
00781 }
00782
00784
00792 inline static void SetMaxEvents(uint32_t val) throw (InotifyException)
00793 {
00794 SetCapability(IN_MAX_EVENTS, val);
00795 }
00796
00798
00805 inline static uint32_t GetMaxInstances() throw (InotifyException)
00806 {
00807 return GetCapability(IN_MAX_INSTANCES);
00808 }
00809
00811
00819 inline static void SetMaxInstances(uint32_t val) throw (InotifyException)
00820 {
00821 SetCapability(IN_MAX_INSTANCES, val);
00822 }
00823
00825
00832 inline static uint32_t GetMaxWatches() throw (InotifyException)
00833 {
00834 return GetCapability(IN_MAX_WATCHES);
00835 }
00836
00838
00846 inline static void SetMaxWatches(uint32_t val) throw (InotifyException)
00847 {
00848 SetCapability(IN_MAX_WATCHES, val);
00849 }
00850
00851 private:
00852 int m_fd;
00853 IN_WATCH_MAP m_watches;
00854 IN_WP_MAP m_paths;
00855 unsigned char m_buf[INOTIFY_BUFLEN];
00856 std::deque<InotifyEvent> m_events;
00857
00858 IN_LOCK_DECL
00859
00860 friend class InotifyWatch;
00861
00862 static std::string GetCapabilityPath(InotifyCapability_t cap) throw (InotifyException);
00863 };
00864
00865
00866 #endif //_INOTIFYCXX_H_
00867