aboutsummaryrefslogtreecommitdiff
path: root/src/3rdParty/efsw/FileWatcherFSEvents.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/3rdParty/efsw/FileWatcherFSEvents.cpp')
-rwxr-xr-xsrc/3rdParty/efsw/FileWatcherFSEvents.cpp240
1 files changed, 240 insertions, 0 deletions
diff --git a/src/3rdParty/efsw/FileWatcherFSEvents.cpp b/src/3rdParty/efsw/FileWatcherFSEvents.cpp
new file mode 100755
index 0000000..970810d
--- /dev/null
+++ b/src/3rdParty/efsw/FileWatcherFSEvents.cpp
@@ -0,0 +1,240 @@
1#include <efsw/Debug.hpp>
2#include <efsw/FileSystem.hpp>
3#include <efsw/FileWatcherFSEvents.hpp>
4#include <efsw/Lock.hpp>
5#include <efsw/String.hpp>
6#include <efsw/System.hpp>
7
8#if EFSW_PLATFORM == EFSW_PLATFORM_FSEVENTS
9
10#include <sys/utsname.h>
11
12namespace efsw {
13
14int getOSXReleaseNumber() {
15 static int osxR = -1;
16
17 if ( -1 == osxR ) {
18 struct utsname os;
19
20 if ( -1 != uname( &os ) ) {
21 std::string release( os.release );
22
23 size_t pos = release.find_first_of( '.' );
24
25 if ( pos != std::string::npos ) {
26 release = release.substr( 0, pos );
27 }
28
29 int rel = 0;
30
31 if ( String::fromString<int>( rel, release ) ) {
32 osxR = rel;
33 }
34 }
35 }
36
37 return osxR;
38}
39
40bool FileWatcherFSEvents::isGranular() {
41 return getOSXReleaseNumber() >= 11;
42}
43
44void FileWatcherFSEvents::FSEventCallback( ConstFSEventStreamRef streamRef, void* userData,
45 size_t numEvents, void* eventPaths,
46 const FSEventStreamEventFlags eventFlags[],
47 const FSEventStreamEventId eventIds[] ) {
48 WatcherFSEvents* watcher = static_cast<WatcherFSEvents*>( userData );
49
50 std::vector<FSEvent> events;
51 events.reserve( numEvents );
52
53 for ( size_t i = 0; i < numEvents; i++ ) {
54 events.push_back( FSEvent( std::string( ( (char**)eventPaths )[i] ), (long)eventFlags[i],
55 (Uint64)eventIds[i] ) );
56 }
57
58 watcher->handleActions( events );
59
60 watcher->process();
61
62 efDEBUG( "\n" );
63}
64
65FileWatcherFSEvents::FileWatcherFSEvents( FileWatcher* parent ) :
66 FileWatcherImpl( parent ), mRunLoopRef( NULL ), mLastWatchID( 0 ), mThread( NULL ) {
67 mInitOK = true;
68
69 watch();
70}
71
72FileWatcherFSEvents::~FileWatcherFSEvents() {
73 mInitOK = false;
74
75 if ( mRunLoopRef.load() )
76 CFRunLoopStop( mRunLoopRef.load() );
77
78 efSAFE_DELETE( mThread );
79
80 WatchMap::iterator iter = mWatches.begin();
81
82 for ( ; iter != mWatches.end(); ++iter ) {
83 WatcherFSEvents* watch = iter->second;
84
85 efSAFE_DELETE( watch );
86 }
87
88 mWatches.clear();
89}
90
91WatchID FileWatcherFSEvents::addWatch( const std::string& directory, FileWatchListener* watcher,
92 bool recursive ) {
93 /// Wait to the RunLoopRef to be ready
94 while ( NULL == mRunLoopRef.load() ) {
95 System::sleep( 1 );
96 }
97
98 std::string dir( directory );
99
100 FileInfo fi( dir );
101
102 if ( !fi.isDirectory() ) {
103 return Errors::Log::createLastError( Errors::FileNotFound, dir );
104 } else if ( !fi.isReadable() ) {
105 return Errors::Log::createLastError( Errors::FileNotReadable, dir );
106 }
107
108 FileSystem::dirAddSlashAtEnd( dir );
109
110 if ( pathInWatches( dir ) ) {
111 return Errors::Log::createLastError( Errors::FileRepeated, directory );
112 }
113
114 /// Check if the directory is a symbolic link
115 std::string curPath;
116 std::string link( FileSystem::getLinkRealPath( dir, curPath ) );
117
118 if ( "" != link ) {
119 /// If it's a symlink check if the realpath exists as a watcher, or
120 /// if the path is outside the current dir
121 if ( pathInWatches( link ) ) {
122 return Errors::Log::createLastError( Errors::FileRepeated, directory );
123 } else if ( !linkAllowed( curPath, link ) ) {
124 return Errors::Log::createLastError( Errors::FileOutOfScope, dir );
125 } else {
126 dir = link;
127 }
128 }
129
130 mLastWatchID++;
131
132 WatcherFSEvents* pWatch = new WatcherFSEvents();
133 pWatch->Listener = watcher;
134 pWatch->ID = mLastWatchID;
135 pWatch->Directory = dir;
136 pWatch->Recursive = recursive;
137 pWatch->FWatcher = this;
138
139 pWatch->init();
140
141 Lock lock( mWatchesLock );
142 mWatches.insert( std::make_pair( mLastWatchID, pWatch ) );
143
144 return pWatch->ID;
145}
146
147void FileWatcherFSEvents::removeWatch( const std::string& directory ) {
148 Lock lock( mWatchesLock );
149
150 WatchMap::iterator iter = mWatches.begin();
151
152 for ( ; iter != mWatches.end(); ++iter ) {
153 if ( directory == iter->second->Directory ) {
154 removeWatch( iter->second->ID );
155 return;
156 }
157 }
158}
159
160void FileWatcherFSEvents::removeWatch( WatchID watchid ) {
161 Lock lock( mWatchesLock );
162
163 WatchMap::iterator iter = mWatches.find( watchid );
164
165 if ( iter == mWatches.end() )
166 return;
167
168 WatcherFSEvents* watch = iter->second;
169
170 mWatches.erase( iter );
171
172 efDEBUG( "Removed watch %s\n", watch->Directory.c_str() );
173
174 efSAFE_DELETE( watch );
175}
176
177void FileWatcherFSEvents::watch() {
178 if ( NULL == mThread ) {
179 mThread = new Thread( &FileWatcherFSEvents::run, this );
180 mThread->launch();
181 }
182}
183
184void FileWatcherFSEvents::run() {
185 mRunLoopRef = CFRunLoopGetCurrent();
186
187 while ( mInitOK ) {
188 mNeedInitMutex.lock();
189
190 if ( !mNeedInit.empty() ) {
191 for ( std::vector<WatcherFSEvents*>::iterator it = mNeedInit.begin();
192 it != mNeedInit.end(); ++it ) {
193 ( *it )->initAsync();
194 }
195
196 mNeedInit.clear();
197 }
198
199 mNeedInitMutex.unlock();
200
201 if ( mWatches.empty() ) {
202 System::sleep( 100 );
203 } else {
204 CFRunLoopRunInMode( kCFRunLoopDefaultMode, 0.5, kCFRunLoopRunTimedOut );
205 }
206 }
207
208 mRunLoopRef = NULL;
209}
210
211void FileWatcherFSEvents::handleAction( Watcher* watch, const std::string& filename,
212 unsigned long action, std::string oldFilename ) {
213 /// Not used
214}
215
216std::list<std::string> FileWatcherFSEvents::directories() {
217 std::list<std::string> dirs;
218
219 Lock lock( mWatchesLock );
220
221 for ( WatchMap::iterator it = mWatches.begin(); it != mWatches.end(); ++it ) {
222 dirs.push_back( std::string( it->second->Directory ) );
223 }
224
225 return dirs;
226}
227
228bool FileWatcherFSEvents::pathInWatches( const std::string& path ) {
229 for ( WatchMap::iterator it = mWatches.begin(); it != mWatches.end(); ++it ) {
230 if ( it->second->Directory == path ) {
231 return true;
232 }
233 }
234
235 return false;
236}
237
238} // namespace efsw
239
240#endif