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
00073 #ifdef INOTIFY_THREAD_SAFE
00074
00075 #include <pthread.h>
00076
00077 #define IN_LOCK_DECL mutable pthread_rwlock_t __m_lock;
00078
00079 #define IN_LOCK_INIT \
00080 { \
00081 pthread_rwlockattr_t attr; \
00082 int res = 0; \
00083 if ((res = pthread_rwlockattr_init(&attr)) != 0) \
00084 throw InotifyException(IN_EXC_MSG("cannot initialize lock attributes"), res, this); \
00085 if ((res = pthread_rwlockattr_setkind_np(&attr, PTHREAD_RWLOCK_PREFER_WRITER_NP)) != 0) \
00086 throw InotifyException(IN_EXC_MSG("cannot set lock kind"), res, this); \
00087 if ((res = pthread_rwlock_init(&__m_lock, &attr)) != 0) \
00088 throw InotifyException(IN_EXC_MSG("cannot initialize lock"), res, this); \
00089 pthread_rwlockattr_destroy(&attr); \
00090 }
00091
00092 #define IN_LOCK_DONE pthread_rwlock_destroy(&__m_lock);
00093
00094 #define IN_READ_BEGIN \
00095 { \
00096 int res = pthread_rwlock_rdlock(&__m_lock); \
00097 if (res != 0) \
00098 throw InotifyException(IN_EXC_MSG("locking for reading failed"), res, (void*) this); \
00099 }
00100
00101 #define IN_READ_END \
00102 { \
00103 int res = pthread_rwlock_unlock(&__m_lock); \
00104 if (res != 0) \
00105 throw InotifyException(IN_EXC_MSG("unlocking failed"), res, (void*) this); \
00106 }
00107
00108 #define IN_READ_END_NOTHROW pthread_rwlock_unlock(&__m_lock);
00109
00110 #define IN_WRITE_BEGIN \
00111 { \
00112 int res = pthread_rwlock_wrlock(&__m_lock); \
00113 if (res != 0) \
00114 throw InotifyException(IN_EXC_MSG("locking for writing failed"), res, (void*) this); \
00115 }
00116
00117 #define IN_WRITE_END IN_READ_END
00118 #define IN_WRITE_END_NOTHROW IN_READ_END_NOTHROW
00119
00120 #else // INOTIFY_THREAD_SAFE
00121
00122 #define IN_LOCK_DECL
00123 #define IN_LOCK_INIT
00124 #define IN_LOCK_DONE
00125 #define IN_READ_BEGIN
00126 #define IN_READ_END
00127 #define IN_READ_END_NOTHROW
00128 #define IN_WRITE_BEGIN
00129 #define IN_WRITE_END
00130 #define IN_WRITE_END_NOTHROW
00131
00132 #endif // INOTIFY_THREAD_SAFE
00133
00134
00135
00136
00137
00138 class InotifyWatch;
00139 class Inotify;
00140
00141
00143
00151 class InotifyException
00152 {
00153 public:
00155
00160 InotifyException(const std::string& rMsg = "", int iErr = 0, void* pSrc = NULL)
00161 : m_msg(rMsg),
00162 m_err(iErr)
00163 {
00164 m_pSrc = pSrc;
00165 }
00166
00168
00171 inline const std::string& GetMessage() const
00172 {
00173 return m_msg;
00174 }
00175
00177
00182 inline int GetErrorNumber() const
00183 {
00184 return m_err;
00185 }
00186
00188
00191 inline void* GetSource() const
00192 {
00193 return m_pSrc;
00194 }
00195
00196 protected:
00197 std::string m_msg;
00198 int m_err;
00199 mutable void* m_pSrc;
00200 };
00201
00202
00204
00212 class InotifyEvent
00213 {
00214 public:
00216
00219 InotifyEvent()
00220 : m_uMask(0),
00221 m_uCookie(0)
00222 {
00223 m_pWatch = NULL;
00224 }
00225
00227
00234 InotifyEvent(const struct inotify_event* pEvt, InotifyWatch* pWatch)
00235 : m_uMask(0),
00236 m_uCookie(0)
00237 {
00238 if (pEvt != NULL) {
00239 m_uMask = (uint32_t) pEvt->mask;
00240 m_uCookie = (uint32_t) pEvt->cookie;
00241 if (pEvt->name != NULL)
00242 m_name = pEvt->name;
00243 m_pWatch = pWatch;
00244 }
00245 else {
00246 m_pWatch = NULL;
00247 }
00248 }
00249
00251 ~InotifyEvent() {}
00252
00254
00259 int32_t GetDescriptor() const;
00260
00262
00267 inline uint32_t GetMask() const
00268 {
00269 return m_uMask;
00270 }
00271
00273
00278 inline static bool IsType(uint32_t uValue, uint32_t uType)
00279 {
00280 return ((uValue & uType) != 0) && ((~uValue & uType) == 0);
00281 }
00282
00284
00288 inline bool IsType(uint32_t uType) const
00289 {
00290 return IsType(m_uMask, uType);
00291 }
00292
00294
00297 inline uint32_t GetCookie() const
00298 {
00299 return m_uCookie;
00300 }
00301
00303
00306 inline uint32_t GetLength() const
00307 {
00308 return (uint32_t) m_name.length();
00309 }
00310
00312
00315 inline const std::string& GetName() const
00316 {
00317 return m_name;
00318 }
00319
00321
00324 inline void GetName(std::string& rName) const
00325 {
00326 rName = GetName();
00327 }
00328
00330
00333 inline InotifyWatch* GetWatch()
00334 {
00335 return m_pWatch;
00336 }
00337
00339
00343 static uint32_t GetMaskByName(const std::string& rName);
00344
00346
00350 static void DumpTypes(uint32_t uValue, std::string& rStr);
00351
00353
00356 void DumpTypes(std::string& rStr) const;
00357
00358 private:
00359 uint32_t m_uMask;
00360 uint32_t m_uCookie;
00361 std::string m_name;
00362 InotifyWatch* m_pWatch;
00363 };
00364
00365
00366
00368
00374 class InotifyWatch
00375 {
00376 public:
00378
00386 InotifyWatch(const std::string& rPath, int32_t uMask, bool fEnabled = true)
00387 : m_path(rPath),
00388 m_uMask(uMask),
00389 m_wd((int32_t) -1),
00390 m_fEnabled(fEnabled)
00391 {
00392 IN_LOCK_INIT
00393 }
00394
00396 ~InotifyWatch()
00397 {
00398 IN_LOCK_DONE
00399 }
00400
00402
00405 inline int32_t GetDescriptor() const
00406 {
00407 return m_wd;
00408 }
00409
00411
00414 inline const std::string& GetPath() const
00415 {
00416 return m_path;
00417 }
00418
00420
00423 inline uint32_t GetMask() const
00424 {
00425 return (uint32_t) m_uMask;
00426 }
00427
00429
00438 void SetMask(uint32_t uMask) throw (InotifyException);
00439
00441
00444 inline Inotify* GetInotify()
00445 {
00446 return m_pInotify;
00447 }
00448
00450
00461 void SetEnabled(bool fEnabled) throw (InotifyException);
00462
00464
00467 inline bool IsEnabled() const
00468 {
00469 return m_fEnabled;
00470 }
00471
00472 private:
00473 friend class Inotify;
00474
00475 std::string m_path;
00476 uint32_t m_uMask;
00477 int32_t m_wd;
00478 Inotify* m_pInotify;
00479 bool m_fEnabled;
00480
00481 IN_LOCK_DECL
00482 };
00483
00484
00486 typedef std::map<int32_t, InotifyWatch*> IN_WATCH_MAP;
00487
00489 typedef std::map<std::string, InotifyWatch*> IN_WP_MAP;
00490
00491
00493
00499 class Inotify
00500 {
00501 public:
00503
00509 Inotify() throw (InotifyException);
00510
00512
00515 ~Inotify();
00516
00518 void Close();
00519
00521
00526 void Add(InotifyWatch* pWatch) throw (InotifyException);
00527
00529
00534 inline void Add(InotifyWatch& rWatch) throw (InotifyException)
00535 {
00536 Add(&rWatch);
00537 }
00538
00540
00547 void Remove(InotifyWatch* pWatch) throw (InotifyException);
00548
00550
00557 inline void Remove(InotifyWatch& rWatch) throw (InotifyException)
00558 {
00559 Remove(&rWatch);
00560 }
00561
00563 void RemoveAll();
00564
00566
00574 inline size_t GetWatchCount() const
00575 {
00576 IN_READ_BEGIN
00577 size_t n = (size_t) m_paths.size();
00578 IN_READ_END
00579 return n;
00580 }
00581
00583
00588 inline size_t GetEnabledCount() const
00589 {
00590 IN_READ_BEGIN
00591 size_t n = (size_t) m_watches.size();
00592 IN_READ_END
00593 return n;
00594 }
00595
00597
00608 void WaitForEvents(bool fNoIntr = false) throw (InotifyException);
00609
00611
00617 inline size_t GetEventCount()
00618 {
00619 IN_READ_BEGIN
00620 size_t n = (size_t) m_events.size();
00621 IN_READ_END
00622 return n;
00623 }
00624
00626
00634 bool GetEvent(InotifyEvent* pEvt) throw (InotifyException);
00635
00637
00644 bool GetEvent(InotifyEvent& rEvt) throw (InotifyException)
00645 {
00646 return GetEvent(&rEvt);
00647 }
00648
00650
00658 bool PeekEvent(InotifyEvent* pEvt) throw (InotifyException);
00659
00661
00668 bool PeekEvent(InotifyEvent& rEvt) throw (InotifyException)
00669 {
00670 return PeekEvent(&rEvt);
00671 }
00672
00674
00680 InotifyWatch* FindWatch(int iDescriptor);
00681
00683
00693 InotifyWatch* FindWatch(const std::string& rPath);
00694
00696
00704 inline int GetDescriptor() const
00705 {
00706 return m_fd;
00707 }
00708
00710
00721 void SetNonBlock(bool fNonBlock) throw (InotifyException);
00722
00723 private:
00724 int m_fd;
00725 IN_WATCH_MAP m_watches;
00726 IN_WP_MAP m_paths;
00727 unsigned char m_buf[INOTIFY_BUFLEN];
00728 std::deque<InotifyEvent> m_events;
00729
00730 IN_LOCK_DECL
00731
00732 friend class InotifyWatch;
00733 };
00734
00735
00736 #endif //_INOTIFYCXX_H_
00737