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