Chromium Code Reviews| 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 <stddef.h> | 8 #include <stddef.h> |
| 9 #include <string.h> | 9 #include <string.h> |
| 10 #include <sys/inotify.h> | 10 #include <sys/inotify.h> |
| 11 #include <sys/ioctl.h> | 11 #include <sys/ioctl.h> |
| 12 #include <sys/select.h> | 12 #include <sys/select.h> |
| 13 #include <sys/stat.h> | |
| 13 #include <unistd.h> | 14 #include <unistd.h> |
| 14 | 15 |
| 15 #include <algorithm> | 16 #include <algorithm> |
| 16 #include <map> | 17 #include <map> |
| 17 #include <memory> | 18 #include <memory> |
| 18 #include <set> | 19 #include <set> |
| 19 #include <utility> | 20 #include <utility> |
| 20 #include <vector> | 21 #include <vector> |
| 21 | 22 |
| 22 #include "base/bind.h" | 23 #include "base/bind.h" |
| 23 #include "base/containers/hash_tables.h" | 24 #include "base/containers/hash_tables.h" |
| 24 #include "base/files/file_enumerator.h" | 25 #include "base/files/file_enumerator.h" |
| 25 #include "base/files/file_path.h" | 26 #include "base/files/file_path.h" |
| 26 #include "base/files/file_util.h" | 27 #include "base/files/file_util.h" |
| 27 #include "base/lazy_instance.h" | 28 #include "base/lazy_instance.h" |
| 28 #include "base/location.h" | 29 #include "base/location.h" |
| 29 #include "base/logging.h" | 30 #include "base/logging.h" |
| 30 #include "base/macros.h" | 31 #include "base/macros.h" |
| 31 #include "base/posix/eintr_wrapper.h" | 32 #include "base/posix/eintr_wrapper.h" |
| 32 #include "base/single_thread_task_runner.h" | 33 #include "base/single_thread_task_runner.h" |
| 33 #include "base/stl_util.h" | 34 #include "base/stl_util.h" |
| 34 #include "base/synchronization/lock.h" | 35 #include "base/synchronization/lock.h" |
| 35 #include "base/threading/thread.h" | 36 #include "base/threading/thread.h" |
| 36 #include "base/threading/thread_task_runner_handle.h" | 37 #include "base/threading/thread_task_runner_handle.h" |
| 38 #include "base/time/time.h" | |
| 37 #include "base/trace_event/trace_event.h" | 39 #include "base/trace_event/trace_event.h" |
| 38 | 40 |
| 39 namespace base { | 41 namespace base { |
| 40 | 42 |
| 41 namespace { | 43 namespace { |
| 42 | 44 |
| 43 class FilePathWatcherImpl; | 45 class FilePathWatcherImpl; |
| 44 | 46 |
| 45 // Singleton to manage all inotify watches. | 47 // Singleton to manage all inotify watches. |
| 46 // TODO(tony): It would be nice if this wasn't a singleton. | 48 // TODO(tony): It would be nice if this wasn't a singleton. |
| (...skipping 349 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 396 // Report the following events: | 398 // Report the following events: |
| 397 // - The target or a direct child of the target got changed (in case the | 399 // - The target or a direct child of the target got changed (in case the |
| 398 // watched path refers to a directory). | 400 // watched path refers to a directory). |
| 399 // - One of the parent directories got moved or deleted, since the target | 401 // - One of the parent directories got moved or deleted, since the target |
| 400 // disappears in this case. | 402 // disappears in this case. |
| 401 // - One of the parent directories appears. The event corresponding to | 403 // - One of the parent directories appears. The event corresponding to |
| 402 // the target appearing might have been missed in this case, so recheck. | 404 // the target appearing might have been missed in this case, so recheck. |
| 403 if (target_changed || | 405 if (target_changed || |
| 404 (change_on_target_path && deleted) || | 406 (change_on_target_path && deleted) || |
| 405 (change_on_target_path && created && PathExists(target_))) { | 407 (change_on_target_path && created && PathExists(target_))) { |
| 406 if (!did_update) { | 408 struct stat child_stat; |
| 409 stat(target_.Append(watch_entry.subdir).Append(child).value().c_str(), | |
| 410 &child_stat); | |
| 411 if (!did_update && S_ISDIR(child_stat.st_mode)) { | |
| 407 UpdateRecursiveWatches(fired_watch, is_dir); | 412 UpdateRecursiveWatches(fired_watch, is_dir); |
| 408 did_update = true; | 413 did_update = true; |
| 409 } | 414 } |
| 410 callback_.Run(target_, false /* error */); | 415 callback_.Run(target_, false /* error */); |
| 411 return; | 416 return; |
| 412 } | 417 } |
| 413 } | 418 } |
| 414 | 419 |
| 415 if (ContainsKey(recursive_paths_by_watch_, fired_watch)) { | 420 if (ContainsKey(recursive_paths_by_watch_, fired_watch)) { |
| 416 if (!did_update) | 421 if (!did_update) |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 522 } | 527 } |
| 523 | 528 |
| 524 // Check to see if this is a forced update or if some component of |target_| | 529 // Check to see if this is a forced update or if some component of |target_| |
| 525 // has changed. For these cases, redo the watches for |target_| and below. | 530 // has changed. For these cases, redo the watches for |target_| and below. |
| 526 if (!ContainsKey(recursive_paths_by_watch_, fired_watch)) { | 531 if (!ContainsKey(recursive_paths_by_watch_, fired_watch)) { |
| 527 UpdateRecursiveWatchesForPath(target_); | 532 UpdateRecursiveWatchesForPath(target_); |
| 528 return; | 533 return; |
| 529 } | 534 } |
| 530 | 535 |
| 531 // Underneath |target_|, only directory changes trigger watch updates. | 536 // Underneath |target_|, only directory changes trigger watch updates. |
| 532 if (!is_dir) | 537 if (!is_dir) |
|
Shuhei Takahashi
2016/09/05 10:48:09
Hmm, is this check insufficient?
dspaid
2016/09/05 12:57:22
Good catch. It should be, but observations sugges
| |
| 533 return; | 538 return; |
| 534 | 539 |
| 535 const FilePath& changed_dir = recursive_paths_by_watch_[fired_watch]; | 540 const FilePath& changed_dir = recursive_paths_by_watch_[fired_watch]; |
| 536 | 541 |
| 537 std::map<FilePath, InotifyReader::Watch>::iterator start_it = | 542 std::map<FilePath, InotifyReader::Watch>::iterator start_it = |
| 538 recursive_watches_by_path_.lower_bound(changed_dir); | 543 recursive_watches_by_path_.lower_bound(changed_dir); |
| 539 std::map<FilePath, InotifyReader::Watch>::iterator end_it = start_it; | 544 std::map<FilePath, InotifyReader::Watch>::iterator end_it = start_it; |
| 540 for (; end_it != recursive_watches_by_path_.end(); ++end_it) { | 545 for (; end_it != recursive_watches_by_path_.end(); ++end_it) { |
| 541 const FilePath& cur_path = end_it->first; | 546 const FilePath& cur_path = end_it->first; |
| 542 if (!changed_dir.IsParent(cur_path)) | 547 if (!changed_dir.IsParent(cur_path)) |
| (...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 652 return watches_.back().subdir.empty(); | 657 return watches_.back().subdir.empty(); |
| 653 } | 658 } |
| 654 | 659 |
| 655 } // namespace | 660 } // namespace |
| 656 | 661 |
| 657 FilePathWatcher::FilePathWatcher() { | 662 FilePathWatcher::FilePathWatcher() { |
| 658 impl_ = new FilePathWatcherImpl(); | 663 impl_ = new FilePathWatcherImpl(); |
| 659 } | 664 } |
| 660 | 665 |
| 661 } // namespace base | 666 } // namespace base |
| OLD | NEW |