| 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 |