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->len > 0
00251 ? pEvt->name
00252 : "";
00253 }
00254 m_pWatch = pWatch;
00255 }
00256 else {
00257 m_pWatch = NULL;
00258 }
00259 }
00260
00262 ~InotifyEvent() {}
00263
00265
00270 int32_t GetDescriptor() const;
00271
00273
00278 inline uint32_t GetMask() const
00279 {
00280 return m_uMask;
00281 }
00282
00284
00289 inline static bool IsType(uint32_t uValue, uint32_t uType)
00290 {
00291 return ((uValue & uType) != 0) && ((~uValue & uType) == 0);
00292 }
00293
00295
00299 inline bool IsType(uint32_t uType) const
00300 {
00301 return IsType(m_uMask, uType);
00302 }
00303
00305
00308 inline uint32_t GetCookie() const
00309 {
00310 return m_uCookie;
00311 }
00312
00314
00317 inline uint32_t GetLength() const
00318 {
00319 return (uint32_t) m_name.length();
00320 }
00321
00323
00326 inline const std::string& GetName() const
00327 {
00328 return m_name;
00329 }
00330
00332
00335 inline void GetName(std::string& rName) const
00336 {
00337 rName = GetName();
00338 }
00339
00341
00344 inline InotifyWatch* GetWatch()
00345 {
00346 return m_pWatch;
00347 }
00348
00350
00354 static uint32_t GetMaskByName(const std::string& rName);
00355
00357
00361 static void DumpTypes(uint32_t uValue, std::string& rStr);
00362
00364
00367 void DumpTypes(std::string& rStr) const;
00368
00369 private:
00370 uint32_t m_uMask;
00371 uint32_t m_uCookie;
00372 std::string m_name;
00373 InotifyWatch* m_pWatch;
00374 };
00375
00376
00377
00379
00385 class InotifyWatch
00386 {
00387 public:
00389
00397 InotifyWatch(const std::string& rPath, int32_t uMask, bool fEnabled = true)
00398 : m_path(rPath),
00399 m_uMask(uMask),
00400 m_wd((int32_t) -1),
00401 m_fEnabled(fEnabled)
00402 {
00403 IN_LOCK_INIT
00404 }
00405
00407 ~InotifyWatch()
00408 {
00409 IN_LOCK_DONE
00410 }
00411
00413
00416 inline int32_t GetDescriptor() const
00417 {
00418 return m_wd;
00419 }
00420
00422
00425 inline const std::string& GetPath() const
00426 {
00427 return m_path;
00428 }
00429
00431
00434 inline uint32_t GetMask() const
00435 {
00436 return (uint32_t) m_uMask;
00437 }
00438
00440
00449 void SetMask(uint32_t uMask) throw (InotifyException);
00450
00452
00455 inline Inotify* GetInotify()
00456 {
00457 return m_pInotify;
00458 }
00459
00461
00472 void SetEnabled(bool fEnabled) throw (InotifyException);
00473
00475
00478 inline bool IsEnabled() const
00479 {
00480 return m_fEnabled;
00481 }
00482
00484
00493 inline bool IsRecursive() const
00494 {
00495 return false;
00496 }
00497
00498 private:
00499 friend class Inotify;
00500
00501 std::string m_path;
00502 uint32_t m_uMask;
00503 int32_t m_wd;
00504 Inotify* m_pInotify;
00505 bool m_fEnabled;
00506
00507 IN_LOCK_DECL
00508
00510
00515 void __Disable();
00516 };
00517
00518
00520 typedef std::map<int32_t, InotifyWatch*> IN_WATCH_MAP;
00521
00523 typedef std::map<std::string, InotifyWatch*> IN_WP_MAP;
00524
00525
00527
00533 class Inotify
00534 {
00535 public:
00537
00543 Inotify() throw (InotifyException);
00544
00546
00549 ~Inotify();
00550
00552 void Close();
00553
00555
00560 void Add(InotifyWatch* pWatch) throw (InotifyException);
00561
00563
00568 inline void Add(InotifyWatch& rWatch) throw (InotifyException)
00569 {
00570 Add(&rWatch);
00571 }
00572
00574
00581 void Remove(InotifyWatch* pWatch) throw (InotifyException);
00582
00584
00591 inline void Remove(InotifyWatch& rWatch) throw (InotifyException)
00592 {
00593 Remove(&rWatch);
00594 }
00595
00597 void RemoveAll();
00598
00600
00608 inline size_t GetWatchCount() const
00609 {
00610 IN_READ_BEGIN
00611 size_t n = (size_t) m_paths.size();
00612 IN_READ_END
00613 return n;
00614 }
00615
00617
00622 inline size_t GetEnabledCount() const
00623 {
00624 IN_READ_BEGIN
00625 size_t n = (size_t) m_watches.size();
00626 IN_READ_END
00627 return n;
00628 }
00629
00631
00642 void WaitForEvents(bool fNoIntr = false) throw (InotifyException);
00643
00645
00651 inline size_t GetEventCount()
00652 {
00653 IN_READ_BEGIN
00654 size_t n = (size_t) m_events.size();
00655 IN_READ_END
00656 return n;
00657 }
00658
00660
00668 bool GetEvent(InotifyEvent* pEvt) throw (InotifyException);
00669
00671
00678 bool GetEvent(InotifyEvent& rEvt) throw (InotifyException)
00679 {
00680 return GetEvent(&rEvt);
00681 }
00682
00684
00692 bool PeekEvent(InotifyEvent* pEvt) throw (InotifyException);
00693
00695
00702 bool PeekEvent(InotifyEvent& rEvt) throw (InotifyException)
00703 {
00704 return PeekEvent(&rEvt);
00705 }
00706
00708
00714 InotifyWatch* FindWatch(int iDescriptor);
00715
00717
00727 InotifyWatch* FindWatch(const std::string& rPath);
00728
00730
00738 inline int GetDescriptor() const
00739 {
00740 return m_fd;
00741 }
00742
00744
00757 void SetNonBlock(bool fNonBlock) throw (InotifyException);
00758
00760
00773 void SetCloseOnExec(bool fClOnEx) throw (InotifyException);
00774
00776
00781 static uint32_t GetCapability(InotifyCapability_t cap) throw (InotifyException);
00782
00784
00792 static void SetCapability(InotifyCapability_t cap, uint32_t val) throw (InotifyException);
00793
00795
00799 inline static uint32_t GetMaxEvents() throw (InotifyException)
00800 {
00801 return GetCapability(IN_MAX_EVENTS);
00802 }
00803
00805
00813 inline static void SetMaxEvents(uint32_t val) throw (InotifyException)
00814 {
00815 SetCapability(IN_MAX_EVENTS, val);
00816 }
00817
00819
00826 inline static uint32_t GetMaxInstances() throw (InotifyException)
00827 {
00828 return GetCapability(IN_MAX_INSTANCES);
00829 }
00830
00832
00840 inline static void SetMaxInstances(uint32_t val) throw (InotifyException)
00841 {
00842 SetCapability(IN_MAX_INSTANCES, val);
00843 }
00844
00846
00853 inline static uint32_t GetMaxWatches() throw (InotifyException)
00854 {
00855 return GetCapability(IN_MAX_WATCHES);
00856 }
00857
00859
00867 inline static void SetMaxWatches(uint32_t val) throw (InotifyException)
00868 {
00869 SetCapability(IN_MAX_WATCHES, val);
00870 }
00871
00872 private:
00873 int m_fd;
00874 IN_WATCH_MAP m_watches;
00875 IN_WP_MAP m_paths;
00876 unsigned char m_buf[INOTIFY_BUFLEN];
00877 std::deque<InotifyEvent> m_events;
00878
00879 IN_LOCK_DECL
00880
00881 friend class InotifyWatch;
00882
00883 static std::string GetCapabilityPath(InotifyCapability_t cap) throw (InotifyException);
00884 };
00885
00886
00887 #endif //_INOTIFYCXX_H_
00888