OLD | NEW |
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "base/directory_watcher.h" | 5 #include "base/directory_watcher.h" |
6 | 6 |
7 #include <errno.h> | 7 #include <errno.h> |
8 #include <string.h> | 8 #include <string.h> |
| 9 #include <sys/inotify.h> |
9 #include <sys/ioctl.h> | 10 #include <sys/ioctl.h> |
10 #include <sys/inotify.h> | |
11 #include <sys/select.h> | 11 #include <sys/select.h> |
12 #include <unistd.h> | 12 #include <unistd.h> |
13 | 13 |
14 #include <algorithm> | 14 #include <algorithm> |
15 #include <set> | 15 #include <set> |
16 #include <utility> | 16 #include <utility> |
17 #include <vector> | 17 #include <vector> |
18 | 18 |
19 #include "base/eintr_wrapper.h" | 19 #include "base/eintr_wrapper.h" |
20 #include "base/file_path.h" | 20 #include "base/file_path.h" |
| 21 #include "base/file_util.h" |
21 #include "base/hash_tables.h" | 22 #include "base/hash_tables.h" |
22 #include "base/lock.h" | 23 #include "base/lock.h" |
23 #include "base/logging.h" | 24 #include "base/logging.h" |
24 #include "base/message_loop.h" | 25 #include "base/message_loop.h" |
25 #include "base/scoped_ptr.h" | 26 #include "base/scoped_ptr.h" |
26 #include "base/singleton.h" | 27 #include "base/singleton.h" |
27 #include "base/task.h" | 28 #include "base/task.h" |
28 #include "base/thread.h" | 29 #include "base/thread.h" |
| 30 #include "base/waitable_event.h" |
29 | 31 |
30 namespace { | 32 namespace { |
31 | 33 |
| 34 class DirectoryWatcherImpl; |
| 35 |
32 // Singleton to manage all inotify watches. | 36 // Singleton to manage all inotify watches. |
33 class InotifyReader { | 37 class InotifyReader { |
34 public: | 38 public: |
35 typedef int Watch; // Watch descriptor used by AddWatch and RemoveWatch. | 39 typedef int Watch; // Watch descriptor used by AddWatch and RemoveWatch. |
36 static const Watch kInvalidWatch = -1; | 40 static const Watch kInvalidWatch = -1; |
37 | 41 |
38 // Watch |path| for changes. |delegate| will be notified on each change. Does | 42 // Watch |path| for changes. |watcher| will be notified on each change. |
39 // not check for duplicates. If you call it n times with same |path| | |
40 // and |delegate|, it will receive n notifications for each change | |
41 // in |path|. It makes implementation of DirectoryWatcher simple. | |
42 // Returns kInvalidWatch on failure. | 43 // Returns kInvalidWatch on failure. |
43 Watch AddWatch(const FilePath& path, DirectoryWatcher::Delegate* delegate); | 44 Watch AddWatch(const FilePath& path, DirectoryWatcherImpl* watcher); |
44 | 45 |
45 // Remove |watch| for |delegate|. If you had n watches for same |delegate| | 46 // Remove |watch|. Returns true on success. |
46 // and path, after calling this function you will have n - 1. | 47 bool RemoveWatch(Watch watch, DirectoryWatcherImpl* watcher); |
47 // Returns true on success. | |
48 bool RemoveWatch(Watch watch, DirectoryWatcher::Delegate* delegate); | |
49 | 48 |
50 // Callback for InotifyReaderTask. | 49 // Callback for InotifyReaderTask. |
51 void OnInotifyEvent(inotify_event* event); | 50 void OnInotifyEvent(const inotify_event* event); |
52 | 51 |
53 private: | 52 private: |
54 friend struct DefaultSingletonTraits<InotifyReader>; | 53 friend struct DefaultSingletonTraits<InotifyReader>; |
55 | 54 |
56 typedef std::pair<DirectoryWatcher::Delegate*, MessageLoop*> DelegateInfo; | 55 typedef std::set<DirectoryWatcherImpl*> WatcherSet; |
57 typedef std::multiset<DelegateInfo> DelegateSet; | |
58 | 56 |
59 InotifyReader(); | 57 InotifyReader(); |
60 ~InotifyReader(); | 58 ~InotifyReader(); |
61 | 59 |
62 // We keep track of which delegates want to be notified on which watches. | 60 // We keep track of which delegates want to be notified on which watches. |
63 // Multiset is used because there may be many DirectoryWatchers for same path | 61 base::hash_map<Watch, WatcherSet> watchers_; |
64 // and delegate. | |
65 base::hash_map<Watch, DelegateSet> delegates_; | |
66 | 62 |
67 // For each watch we also want to know the path it's watching. | 63 // For each watch we also want to know the path it's watching. |
68 base::hash_map<Watch, FilePath> paths_; | 64 base::hash_map<Watch, FilePath> paths_; |
69 | 65 |
70 // Lock to protect delegates_ and paths_. | 66 // Lock to protect delegates_ and paths_. |
71 Lock lock_; | 67 Lock lock_; |
72 | 68 |
73 // Separate thread on which we run blocking read for inotify events. | 69 // Separate thread on which we run blocking read for inotify events. |
74 base::Thread thread_; | 70 base::Thread thread_; |
75 | 71 |
76 // File descriptor returned by inotify_init. | 72 // File descriptor returned by inotify_init. |
77 const int inotify_fd_; | 73 const int inotify_fd_; |
78 | 74 |
79 // Use self-pipe trick to unblock select during shutdown. | 75 // Use self-pipe trick to unblock select during shutdown. |
80 int shutdown_pipe_[2]; | 76 int shutdown_pipe_[2]; |
81 | 77 |
82 // Flag set to true when startup was successful. | 78 // Flag set to true when startup was successful. |
83 bool valid_; | 79 bool valid_; |
84 | 80 |
85 DISALLOW_COPY_AND_ASSIGN(InotifyReader); | 81 DISALLOW_COPY_AND_ASSIGN(InotifyReader); |
86 }; | 82 }; |
87 | 83 |
| 84 class DirectoryWatcherImpl : public DirectoryWatcher::PlatformDelegate { |
| 85 public: |
| 86 typedef std::set<FilePath> FilePathSet; |
| 87 |
| 88 DirectoryWatcherImpl(); |
| 89 ~DirectoryWatcherImpl(); |
| 90 |
| 91 void EnsureSetupFinished(); |
| 92 |
| 93 // Called for each event coming from one of watches. |
| 94 void OnInotifyEvent(const inotify_event* event); |
| 95 |
| 96 // Callback for RegisterSubtreeWatchesTask. |
| 97 bool OnEnumeratedSubtree(const FilePathSet& paths); |
| 98 |
| 99 // Start watching |path| for changes and notify |delegate| on each change. |
| 100 // If |recursive| is true, watch entire subtree. |
| 101 // Returns true if watch for |path| has been added successfully. Watches |
| 102 // required for |recursive| are added on a background thread and have no |
| 103 // effect on the return value. |
| 104 virtual bool Watch(const FilePath& path, DirectoryWatcher::Delegate* delegate, |
| 105 MessageLoop* backend_loop, bool recursive); |
| 106 |
| 107 private: |
| 108 typedef std::set<InotifyReader::Watch> WatchSet; |
| 109 typedef std::set<ino_t> InodeSet; |
| 110 |
| 111 // Returns true if |inode| is watched by DirectoryWatcherImpl. |
| 112 bool IsInodeWatched(ino_t inode) const; |
| 113 |
| 114 // Delegate to notify upon changes. |
| 115 DirectoryWatcher::Delegate* delegate_; |
| 116 |
| 117 // Path we're watching (passed to delegate). |
| 118 FilePath root_path_; |
| 119 |
| 120 // Watch returned by InotifyReader. |
| 121 InotifyReader::Watch watch_; |
| 122 |
| 123 // Set of watched inodes. |
| 124 InodeSet inodes_watched_; |
| 125 |
| 126 // Keep track of registered watches. |
| 127 WatchSet watches_; |
| 128 |
| 129 // Lock to protect inodes_watched_ and watches_. |
| 130 Lock lock_; |
| 131 |
| 132 // Flag set to true when recursively watching subtree. |
| 133 bool recursive_; |
| 134 |
| 135 // Loop where we post directory change notifications to. |
| 136 MessageLoop* loop_; |
| 137 |
| 138 // Event signaled when the background task finished adding initial inotify |
| 139 // watches for recursive watch. |
| 140 base::WaitableEvent recursive_setup_finished_; |
| 141 |
| 142 DISALLOW_COPY_AND_ASSIGN(DirectoryWatcherImpl); |
| 143 }; |
| 144 |
| 145 class RegisterSubtreeWatchesTask : public Task { |
| 146 public: |
| 147 RegisterSubtreeWatchesTask(DirectoryWatcherImpl* watcher, |
| 148 const FilePath& path) |
| 149 : watcher_(watcher), |
| 150 path_(path) { |
| 151 } |
| 152 |
| 153 virtual void Run() { |
| 154 file_util::FileEnumerator dir_list(path_, true, |
| 155 file_util::FileEnumerator::DIRECTORIES); |
| 156 |
| 157 DirectoryWatcherImpl::FilePathSet subtree; |
| 158 for (FilePath subdirectory = dir_list.Next(); |
| 159 !subdirectory.empty(); |
| 160 subdirectory = dir_list.Next()) { |
| 161 subtree.insert(subdirectory); |
| 162 } |
| 163 watcher_->OnEnumeratedSubtree(subtree); |
| 164 } |
| 165 |
| 166 private: |
| 167 DirectoryWatcherImpl* watcher_; |
| 168 FilePath path_; |
| 169 |
| 170 DISALLOW_COPY_AND_ASSIGN(RegisterSubtreeWatchesTask); |
| 171 }; |
| 172 |
| 173 class DirectoryWatcherImplNotifyTask : public Task { |
| 174 public: |
| 175 DirectoryWatcherImplNotifyTask(DirectoryWatcher::Delegate* delegate, |
| 176 const FilePath& path) |
| 177 : delegate_(delegate), |
| 178 path_(path) { |
| 179 } |
| 180 |
| 181 virtual void Run() { |
| 182 delegate_->OnDirectoryChanged(path_); |
| 183 } |
| 184 |
| 185 private: |
| 186 DirectoryWatcher::Delegate* delegate_; |
| 187 FilePath path_; |
| 188 |
| 189 DISALLOW_COPY_AND_ASSIGN(DirectoryWatcherImplNotifyTask); |
| 190 }; |
| 191 |
88 class InotifyReaderTask : public Task { | 192 class InotifyReaderTask : public Task { |
89 public: | 193 public: |
90 InotifyReaderTask(InotifyReader* reader, int inotify_fd, int shutdown_fd) | 194 InotifyReaderTask(InotifyReader* reader, int inotify_fd, int shutdown_fd) |
91 : reader_(reader), | 195 : reader_(reader), |
92 inotify_fd_(inotify_fd), | 196 inotify_fd_(inotify_fd), |
93 shutdown_fd_(shutdown_fd) { | 197 shutdown_fd_(shutdown_fd) { |
94 } | 198 } |
95 | 199 |
96 virtual void Run() { | 200 virtual void Run() { |
97 while (true) { | 201 while (true) { |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
144 } | 248 } |
145 | 249 |
146 private: | 250 private: |
147 InotifyReader* reader_; | 251 InotifyReader* reader_; |
148 int inotify_fd_; | 252 int inotify_fd_; |
149 int shutdown_fd_; | 253 int shutdown_fd_; |
150 | 254 |
151 DISALLOW_COPY_AND_ASSIGN(InotifyReaderTask); | 255 DISALLOW_COPY_AND_ASSIGN(InotifyReaderTask); |
152 }; | 256 }; |
153 | 257 |
154 class InotifyReaderNotifyTask : public Task { | |
155 public: | |
156 InotifyReaderNotifyTask(DirectoryWatcher::Delegate* delegate, | |
157 const FilePath& path) | |
158 : delegate_(delegate), | |
159 path_(path) { | |
160 } | |
161 | |
162 virtual void Run() { | |
163 delegate_->OnDirectoryChanged(path_); | |
164 } | |
165 | |
166 private: | |
167 DirectoryWatcher::Delegate* delegate_; | |
168 FilePath path_; | |
169 | |
170 DISALLOW_COPY_AND_ASSIGN(InotifyReaderNotifyTask); | |
171 }; | |
172 | |
173 InotifyReader::InotifyReader() | 258 InotifyReader::InotifyReader() |
174 : thread_("inotify_reader"), | 259 : thread_("inotify_reader"), |
175 inotify_fd_(inotify_init()), | 260 inotify_fd_(inotify_init()), |
176 valid_(false) { | 261 valid_(false) { |
177 shutdown_pipe_[0] = -1; | 262 shutdown_pipe_[0] = -1; |
178 shutdown_pipe_[1] = -1; | 263 shutdown_pipe_[1] = -1; |
179 if (inotify_fd_ >= 0 && pipe(shutdown_pipe_) == 0 && thread_.Start()) { | 264 if (inotify_fd_ >= 0 && pipe(shutdown_pipe_) == 0 && thread_.Start()) { |
180 thread_.message_loop()->PostTask( | 265 thread_.message_loop()->PostTask( |
181 FROM_HERE, new InotifyReaderTask(this, inotify_fd_, shutdown_pipe_[0])); | 266 FROM_HERE, new InotifyReaderTask(this, inotify_fd_, shutdown_pipe_[0])); |
182 valid_ = true; | 267 valid_ = true; |
183 } | 268 } |
184 } | 269 } |
185 | 270 |
186 InotifyReader::~InotifyReader() { | 271 InotifyReader::~InotifyReader() { |
187 if (valid_) { | 272 if (valid_) { |
188 // Write to the self-pipe so that the select call in InotifyReaderTask | 273 // Write to the self-pipe so that the select call in InotifyReaderTask |
189 // returns. | 274 // returns. |
190 HANDLE_EINTR(write(shutdown_pipe_[1], "", 1)); | 275 HANDLE_EINTR(write(shutdown_pipe_[1], "", 1)); |
191 thread_.Stop(); | 276 thread_.Stop(); |
192 } | 277 } |
193 if (inotify_fd_ >= 0) | 278 if (inotify_fd_ >= 0) |
194 close(inotify_fd_); | 279 close(inotify_fd_); |
195 if (shutdown_pipe_[0] >= 0) | 280 if (shutdown_pipe_[0] >= 0) |
196 close(shutdown_pipe_[0]); | 281 close(shutdown_pipe_[0]); |
197 if (shutdown_pipe_[1] >= 0) | 282 if (shutdown_pipe_[1] >= 0) |
198 close(shutdown_pipe_[1]); | 283 close(shutdown_pipe_[1]); |
199 } | 284 } |
200 | 285 |
201 InotifyReader::Watch InotifyReader::AddWatch( | 286 InotifyReader::Watch InotifyReader::AddWatch( |
202 const FilePath& path, DirectoryWatcher::Delegate* delegate) { | 287 const FilePath& path, DirectoryWatcherImpl* watcher) { |
| 288 |
203 if (!valid_) | 289 if (!valid_) |
204 return kInvalidWatch; | 290 return kInvalidWatch; |
205 | 291 |
206 AutoLock auto_lock(lock_); | 292 AutoLock auto_lock(lock_); |
207 | 293 |
208 Watch watch = inotify_add_watch(inotify_fd_, path.value().c_str(), | 294 Watch watch = inotify_add_watch(inotify_fd_, path.value().c_str(), |
209 IN_CREATE | IN_DELETE | | 295 IN_CREATE | IN_DELETE | |
210 IN_CLOSE_WRITE | IN_MOVE); | 296 IN_CLOSE_WRITE | IN_MOVE); |
| 297 |
211 if (watch == kInvalidWatch) | 298 if (watch == kInvalidWatch) |
212 return kInvalidWatch; | 299 return kInvalidWatch; |
213 | 300 |
214 if (paths_[watch].empty()) | 301 if (paths_[watch].empty()) |
215 paths_[watch] = path; // We don't yet watch this path. | 302 paths_[watch] = path; // We don't yet watch this path. |
216 | 303 |
217 delegates_[watch].insert(std::make_pair(delegate, MessageLoop::current())); | 304 watchers_[watch].insert(watcher); |
218 | 305 |
219 return watch; | 306 return watch; |
220 } | 307 } |
221 | 308 |
222 bool InotifyReader::RemoveWatch(Watch watch, | 309 bool InotifyReader::RemoveWatch(Watch watch, |
223 DirectoryWatcher::Delegate* delegate) { | 310 DirectoryWatcherImpl* watcher) { |
224 if (!valid_) | 311 if (!valid_) |
225 return false; | 312 return false; |
226 | 313 |
227 AutoLock auto_lock(lock_); | 314 AutoLock auto_lock(lock_); |
228 | 315 |
229 if (paths_[watch].empty()) | 316 if (paths_[watch].empty()) |
230 return false; // We don't recognize this watch. | 317 return false; // We don't recognize this watch. |
231 | 318 |
232 // Only erase one occurrence of delegate (there may be more). | 319 watchers_[watch].erase(watcher); |
233 delegates_[watch].erase( | |
234 delegates_[watch].find(std::make_pair(delegate, MessageLoop::current()))); | |
235 | 320 |
236 if (delegates_[watch].empty()) { | 321 if (watchers_[watch].empty()) { |
237 paths_.erase(watch); | 322 paths_.erase(watch); |
238 delegates_.erase(watch); | 323 watchers_.erase(watch); |
239 | |
240 return (inotify_rm_watch(inotify_fd_, watch) == 0); | 324 return (inotify_rm_watch(inotify_fd_, watch) == 0); |
241 } | 325 } |
242 | 326 |
243 return true; | 327 return true; |
244 } | 328 } |
245 | 329 |
246 void InotifyReader::OnInotifyEvent(inotify_event* event) { | 330 void InotifyReader::OnInotifyEvent(const inotify_event* event) { |
247 if (event->mask & IN_IGNORED) | 331 if (event->mask & IN_IGNORED) |
248 return; | 332 return; |
249 | 333 |
250 DelegateSet delegates_to_notify; | 334 WatcherSet watchers_to_notify; |
251 FilePath changed_path; | 335 FilePath changed_path; |
252 | 336 |
253 { | 337 { |
254 AutoLock auto_lock(lock_); | 338 AutoLock auto_lock(lock_); |
255 changed_path = paths_[event->wd]; | 339 changed_path = paths_[event->wd]; |
256 delegates_to_notify.insert(delegates_[event->wd].begin(), | 340 watchers_to_notify.insert(watchers_[event->wd].begin(), |
257 delegates_[event->wd].end()); | 341 watchers_[event->wd].end()); |
258 } | 342 } |
259 | 343 |
260 DelegateSet::iterator i; | 344 for (WatcherSet::iterator watcher = watchers_to_notify.begin(); |
261 for (i = delegates_to_notify.begin(); i != delegates_to_notify.end(); ++i) { | 345 watcher != watchers_to_notify.end(); |
262 DirectoryWatcher::Delegate* delegate = i->first; | 346 ++watcher) { |
263 MessageLoop* loop = i->second; | 347 (*watcher)->OnInotifyEvent(event); |
264 loop->PostTask(FROM_HERE, | |
265 new InotifyReaderNotifyTask(delegate, changed_path)); | |
266 } | 348 } |
267 } | 349 } |
268 | 350 |
269 class DirectoryWatcherImpl : public DirectoryWatcher::PlatformDelegate { | 351 DirectoryWatcherImpl::DirectoryWatcherImpl() |
270 public: | 352 : watch_(InotifyReader::kInvalidWatch), |
271 DirectoryWatcherImpl() : watch_(InotifyReader::kInvalidWatch) {} | 353 recursive_setup_finished_(false, false) { |
272 ~DirectoryWatcherImpl(); | 354 } |
273 | |
274 virtual bool Watch(const FilePath& path, DirectoryWatcher::Delegate* delegate, | |
275 bool recursive); | |
276 | |
277 private: | |
278 // Delegate to notify upon changes. | |
279 DirectoryWatcher::Delegate* delegate_; | |
280 | |
281 // Path we're watching (passed to delegate). | |
282 FilePath path_; | |
283 | |
284 // Watch returned by InotifyReader. | |
285 InotifyReader::Watch watch_; | |
286 | |
287 DISALLOW_COPY_AND_ASSIGN(DirectoryWatcherImpl); | |
288 }; | |
289 | 355 |
290 DirectoryWatcherImpl::~DirectoryWatcherImpl() { | 356 DirectoryWatcherImpl::~DirectoryWatcherImpl() { |
291 if (watch_ != InotifyReader::kInvalidWatch) | 357 if (watch_ == InotifyReader::kInvalidWatch) |
292 Singleton<InotifyReader>::get()->RemoveWatch(watch_, delegate_); | 358 return; |
| 359 |
| 360 if (recursive_) |
| 361 recursive_setup_finished_.Wait(); |
| 362 for (WatchSet::iterator watch = watches_.begin(); |
| 363 watch != watches_.end(); |
| 364 ++watch) { |
| 365 Singleton<InotifyReader>::get()->RemoveWatch(*watch, this); |
| 366 } |
| 367 watches_.clear(); |
| 368 inodes_watched_.clear(); |
| 369 } |
| 370 |
| 371 void DirectoryWatcherImpl::OnInotifyEvent(const inotify_event* event) { |
| 372 loop_->PostTask(FROM_HERE, |
| 373 new DirectoryWatcherImplNotifyTask(delegate_, root_path_)); |
| 374 |
| 375 if (!(event->mask & IN_ISDIR)) |
| 376 return; |
| 377 |
| 378 if (event->mask & IN_CREATE || event->mask & IN_MOVED_TO) { |
| 379 // TODO(phajdan.jr): add watch for this new directory. |
| 380 NOTIMPLEMENTED(); |
| 381 } else if (event->mask & IN_DELETE || event->mask & IN_MOVED_FROM) { |
| 382 // TODO(phajdan.jr): remove our watch for this directory. |
| 383 NOTIMPLEMENTED(); |
| 384 } |
| 385 } |
| 386 |
| 387 bool DirectoryWatcherImpl::IsInodeWatched(ino_t inode) const { |
| 388 return inodes_watched_.find(inode) != inodes_watched_.end(); |
| 389 } |
| 390 |
| 391 bool DirectoryWatcherImpl::OnEnumeratedSubtree(const FilePathSet& subtree) { |
| 392 DCHECK(recursive_); |
| 393 |
| 394 if (watch_ == InotifyReader::kInvalidWatch) { |
| 395 recursive_setup_finished_.Signal(); |
| 396 return false; |
| 397 } |
| 398 |
| 399 bool success = true; |
| 400 AutoLock auto_lock(lock_); |
| 401 for (FilePathSet::iterator subdirectory = subtree.begin(); |
| 402 subdirectory != subtree.end(); |
| 403 ++subdirectory) { |
| 404 ino_t inode; |
| 405 if (!file_util::GetInode(*subdirectory, &inode)) { |
| 406 success = false; |
| 407 continue; |
| 408 } |
| 409 if (IsInodeWatched(inode)) |
| 410 continue; |
| 411 InotifyReader::Watch watch = |
| 412 Singleton<InotifyReader>::get()->AddWatch(*subdirectory, this); |
| 413 if (watch != InotifyReader::kInvalidWatch) { |
| 414 watches_.insert(watch); |
| 415 inodes_watched_.insert(inode); |
| 416 } |
| 417 } |
| 418 recursive_setup_finished_.Signal(); |
| 419 return success; |
293 } | 420 } |
294 | 421 |
295 bool DirectoryWatcherImpl::Watch(const FilePath& path, | 422 bool DirectoryWatcherImpl::Watch(const FilePath& path, |
296 DirectoryWatcher::Delegate* delegate, bool recursive) { | 423 DirectoryWatcher::Delegate* delegate, |
297 DCHECK(watch_ == InotifyReader::kInvalidWatch); // Can only watch one path. | 424 MessageLoop* backend_loop, bool recursive) { |
298 | 425 |
299 if (recursive) { | 426 // Can only watch one path. |
300 // TODO(phajdan.jr): Support recursive watches. | 427 DCHECK(watch_ == InotifyReader::kInvalidWatch); |
301 // Unfortunately inotify has no "native" support for them, but it can be | 428 |
302 // emulated by walking the directory tree and setting up watches for each | 429 ino_t inode; |
303 // directory. Of course this is ineffective for large directory trees. | 430 if (!file_util::GetInode(path, &inode)) |
304 // For the algorithm, see the link below: | |
305 // http://osdir.com/ml/gnome.dashboard.devel/2004-10/msg00022.html | |
306 NOTIMPLEMENTED(); | |
307 return false; | 431 return false; |
| 432 |
| 433 InotifyReader::Watch watch = |
| 434 Singleton<InotifyReader>::get()->AddWatch(path, this); |
| 435 if (watch == InotifyReader::kInvalidWatch) |
| 436 return false; |
| 437 |
| 438 delegate_ = delegate; |
| 439 recursive_ = recursive; |
| 440 root_path_ = path; |
| 441 watch_ = watch; |
| 442 loop_ = MessageLoop::current(); |
| 443 |
| 444 { |
| 445 AutoLock auto_lock(lock_); |
| 446 inodes_watched_.insert(inode); |
| 447 watches_.insert(watch_); |
308 } | 448 } |
309 | 449 |
310 delegate_ = delegate; | 450 if (recursive_) { |
311 path_ = path; | 451 Task* subtree_task = new RegisterSubtreeWatchesTask(this, root_path_); |
312 watch_ = Singleton<InotifyReader>::get()->AddWatch(path, delegate_); | 452 if (backend_loop) { |
| 453 backend_loop->PostTask(FROM_HERE, subtree_task); |
| 454 } else { |
| 455 subtree_task->Run(); |
| 456 delete subtree_task; |
| 457 } |
| 458 } |
313 | 459 |
314 return watch_ != InotifyReader::kInvalidWatch; | 460 return true; |
315 } | 461 } |
316 | 462 |
317 } // namespace | 463 } // namespace |
318 | 464 |
319 DirectoryWatcher::DirectoryWatcher() { | 465 DirectoryWatcher::DirectoryWatcher() { |
320 impl_ = new DirectoryWatcherImpl(); | 466 impl_ = new DirectoryWatcherImpl(); |
321 } | 467 } |
| 468 |
OLD | NEW |