OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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/files/file_path_watcher.h" | 5 #include "base/files/file_path_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/inotify.h> |
10 #include <sys/ioctl.h> | 10 #include <sys/ioctl.h> |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
85 }; | 85 }; |
86 | 86 |
87 class FilePathWatcherImpl : public FilePathWatcher::PlatformDelegate, | 87 class FilePathWatcherImpl : public FilePathWatcher::PlatformDelegate, |
88 public MessageLoop::DestructionObserver { | 88 public MessageLoop::DestructionObserver { |
89 public: | 89 public: |
90 FilePathWatcherImpl(); | 90 FilePathWatcherImpl(); |
91 | 91 |
92 // Called for each event coming from the watch. |fired_watch| identifies the | 92 // Called for each event coming from the watch. |fired_watch| identifies the |
93 // watch that fired, |child| indicates what has changed, and is relative to | 93 // watch that fired, |child| indicates what has changed, and is relative to |
94 // the currently watched path for |fired_watch|. The flag |created| is true if | 94 // the currently watched path for |fired_watch|. The flag |created| is true if |
95 // the object appears, and |is_directory| is set when the event refers to a | 95 // the object appears. |
96 // directory. | |
97 void OnFilePathChanged(InotifyReader::Watch fired_watch, | 96 void OnFilePathChanged(InotifyReader::Watch fired_watch, |
98 const FilePath::StringType& child, | 97 const FilePath::StringType& child, |
99 bool created, | 98 bool created); |
100 bool is_directory); | |
101 | 99 |
102 // Start watching |path| for changes and notify |delegate| on each change. | 100 // Start watching |path| for changes and notify |delegate| on each change. |
103 // Returns true if watch for |path| has been added successfully. | 101 // Returns true if watch for |path| has been added successfully. |
104 virtual bool Watch(const FilePath& path, | 102 virtual bool Watch(const FilePath& path, |
105 FilePathWatcher::Delegate* delegate) OVERRIDE; | 103 FilePathWatcher::Delegate* delegate) OVERRIDE; |
106 | 104 |
107 // Cancel the watch. This unregisters the instance with InotifyReader. | 105 // Cancel the watch. This unregisters the instance with InotifyReader. |
108 virtual void Cancel() OVERRIDE; | 106 virtual void Cancel() OVERRIDE; |
109 | 107 |
110 // Deletion of the FilePathWatcher will call Cancel() to dispose of this | 108 // Deletion of the FilePathWatcher will call Cancel() to dispose of this |
(...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
284 return; | 282 return; |
285 | 283 |
286 FilePath::StringType child(event->len ? event->name : FILE_PATH_LITERAL("")); | 284 FilePath::StringType child(event->len ? event->name : FILE_PATH_LITERAL("")); |
287 base::AutoLock auto_lock(lock_); | 285 base::AutoLock auto_lock(lock_); |
288 | 286 |
289 for (WatcherSet::iterator watcher = watchers_[event->wd].begin(); | 287 for (WatcherSet::iterator watcher = watchers_[event->wd].begin(); |
290 watcher != watchers_[event->wd].end(); | 288 watcher != watchers_[event->wd].end(); |
291 ++watcher) { | 289 ++watcher) { |
292 (*watcher)->OnFilePathChanged(event->wd, | 290 (*watcher)->OnFilePathChanged(event->wd, |
293 child, | 291 child, |
294 event->mask & (IN_CREATE | IN_MOVED_TO), | 292 event->mask & (IN_CREATE | IN_MOVED_TO)); |
295 event->mask & IN_ISDIR); | |
296 } | 293 } |
297 } | 294 } |
298 | 295 |
299 FilePathWatcherImpl::FilePathWatcherImpl() | 296 FilePathWatcherImpl::FilePathWatcherImpl() |
300 : delegate_(NULL) { | 297 : delegate_(NULL) { |
301 } | 298 } |
302 | 299 |
303 void FilePathWatcherImpl::OnFilePathChanged( | 300 void FilePathWatcherImpl::OnFilePathChanged(InotifyReader::Watch fired_watch, |
304 InotifyReader::Watch fired_watch, | 301 const FilePath::StringType& child, |
305 const FilePath::StringType& child, | 302 bool created) { |
306 bool created, | |
307 bool is_directory) { | |
308 | |
309 if (!message_loop()->BelongsToCurrentThread()) { | 303 if (!message_loop()->BelongsToCurrentThread()) { |
310 // Switch to message_loop_ to access watches_ safely. | 304 // Switch to message_loop_ to access watches_ safely. |
311 message_loop()->PostTask(FROM_HERE, | 305 message_loop()->PostTask(FROM_HERE, |
312 base::Bind(&FilePathWatcherImpl::OnFilePathChanged, | 306 base::Bind(&FilePathWatcherImpl::OnFilePathChanged, |
313 this, | 307 this, |
314 fired_watch, | 308 fired_watch, |
315 child, | 309 child, |
316 created, | 310 created)); |
317 is_directory)); | |
318 return; | 311 return; |
319 } | 312 } |
320 | 313 |
321 DCHECK(MessageLoopForIO::current()); | 314 DCHECK(MessageLoopForIO::current()); |
322 | 315 |
323 // Find the entry in |watches_| that corresponds to |fired_watch|. | 316 // Find the entry in |watches_| that corresponds to |fired_watch|. |
324 WatchVector::const_iterator watch_entry(watches_.begin()); | 317 WatchVector::const_iterator watch_entry(watches_.begin()); |
325 for ( ; watch_entry != watches_.end(); ++watch_entry) { | 318 for ( ; watch_entry != watches_.end(); ++watch_entry) { |
326 if (fired_watch == watch_entry->watch_) { | 319 if (fired_watch == watch_entry->watch_) { |
327 // Check whether a path component of |target_| changed. | 320 // Check whether a path component of |target_| changed. |
328 bool change_on_target_path = child.empty() || | 321 bool change_on_target_path = child.empty() || |
329 ((child == watch_entry->subdir_) && watch_entry->linkname_.empty()) || | 322 ((child == watch_entry->subdir_) && watch_entry->linkname_.empty()) || |
330 (child == watch_entry->linkname_); | 323 (child == watch_entry->linkname_); |
331 | 324 |
332 // Check whether the change references |target_| or a direct child. | 325 // Check whether the change references |target_| or a direct child. |
333 DCHECK(watch_entry->subdir_.empty() || | 326 DCHECK(watch_entry->subdir_.empty() || |
334 (watch_entry + 1) != watches_.end()); | 327 (watch_entry + 1) != watches_.end()); |
335 bool target_changed = | 328 bool target_changed = |
336 (watch_entry->subdir_.empty() && (child == watch_entry->linkname_)) || | 329 (watch_entry->subdir_.empty() && (child == watch_entry->linkname_)) || |
337 (watch_entry->subdir_.empty() && watch_entry->linkname_.empty()) || | 330 (watch_entry->subdir_.empty() && watch_entry->linkname_.empty()) || |
338 (watch_entry->subdir_ == child && (watch_entry + 1)->subdir_.empty()); | 331 (watch_entry->subdir_ == child && (watch_entry + 1)->subdir_.empty()); |
339 | 332 |
340 // Update watches if a directory component of the |target_| path | 333 // Update watches if a directory component of the |target_| path |
341 // (dis)appears. Note that we don't add the additional restriction | 334 // (dis)appears. Note that we don't add the additional restriction |
342 // of checking is_directory here as changes to symlinks on the | 335 // of checking the event mask to see if it is for a directory here |
343 // target path will not have is_directory set but as a result we | 336 // as changes to symlinks on the target path will not have |
344 // may sometimes call UpdateWatches unnecessarily. | 337 // IN_ISDIR set in the event masks. As a result we may sometimes |
| 338 // call UpdateWatches() unnecessarily. |
345 if (change_on_target_path && !UpdateWatches()) { | 339 if (change_on_target_path && !UpdateWatches()) { |
346 delegate_->OnFilePathError(target_); | 340 delegate_->OnFilePathError(target_); |
347 return; | 341 return; |
348 } | 342 } |
349 | 343 |
350 // Report the following events: | 344 // Report the following events: |
351 // - The target or a direct child of the target got changed (in case the | 345 // - The target or a direct child of the target got changed (in case the |
352 // watched path refers to a directory). | 346 // watched path refers to a directory). |
353 // - One of the parent directories got moved or deleted, since the target | 347 // - One of the parent directories got moved or deleted, since the target |
354 // disappears in this case. | 348 // disappears in this case. |
355 // - One of the parent directories appears. The event corresponding to | 349 // - One of the parent directories appears. The event corresponding to |
356 // the target appearing might have been missed in this case, so | 350 // the target appearing might have been missed in this case, so |
357 // recheck. | 351 // recheck. |
358 if (target_changed || | 352 if (target_changed || |
359 (change_on_target_path && !created) || | 353 (change_on_target_path && !created) || |
360 (change_on_target_path && file_util::PathExists(target_))) { | 354 (change_on_target_path && file_util::PathExists(target_))) { |
361 delegate_->OnFilePathChanged(target_); | 355 delegate_->OnFilePathChanged(target_); |
362 return; | 356 return; |
363 } | 357 } |
364 } | 358 } |
365 } | 359 } |
366 | |
367 } | 360 } |
368 | 361 |
369 bool FilePathWatcherImpl::Watch(const FilePath& path, | 362 bool FilePathWatcherImpl::Watch(const FilePath& path, |
370 FilePathWatcher::Delegate* delegate) { | 363 FilePathWatcher::Delegate* delegate) { |
371 DCHECK(target_.empty()); | 364 DCHECK(target_.empty()); |
372 DCHECK(MessageLoopForIO::current()); | 365 DCHECK(MessageLoopForIO::current()); |
373 | 366 |
374 set_message_loop(base::MessageLoopProxy::current()); | 367 set_message_loop(base::MessageLoopProxy::current()); |
375 delegate_ = delegate; | 368 delegate_ = delegate; |
376 target_ = path; | 369 target_ = path; |
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
479 } | 472 } |
480 | 473 |
481 } // namespace | 474 } // namespace |
482 | 475 |
483 FilePathWatcher::FilePathWatcher() { | 476 FilePathWatcher::FilePathWatcher() { |
484 impl_ = new FilePathWatcherImpl(); | 477 impl_ = new FilePathWatcherImpl(); |
485 } | 478 } |
486 | 479 |
487 } // namespace files | 480 } // namespace files |
488 } // namespace base | 481 } // namespace base |
OLD | NEW |