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 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
118 void Cancel() override; | 118 void Cancel() override; |
119 | 119 |
120 // Cleans up and stops observing the message_loop() thread. | 120 // Cleans up and stops observing the message_loop() thread. |
121 void CancelOnMessageLoopThread() override; | 121 void CancelOnMessageLoopThread() override; |
122 | 122 |
123 // Deletion of the FilePathWatcher will call Cancel() to dispose of this | 123 // Deletion of the FilePathWatcher will call Cancel() to dispose of this |
124 // object in the right thread. This also observes destruction of the required | 124 // object in the right thread. This also observes destruction of the required |
125 // cleanup thread, in case it quits before Cancel() is called. | 125 // cleanup thread, in case it quits before Cancel() is called. |
126 void WillDestroyCurrentMessageLoop() override; | 126 void WillDestroyCurrentMessageLoop() override; |
127 | 127 |
128 // Inotify watches are installed for all directory components of |target_|. A | 128 // Inotify watches are installed for all directory components of |target_|. |
129 // WatchEntry instance holds the watch descriptor for a component and the | 129 // A WatchEntry instance holds: |
130 // subdirectory for that identifies the next component. If a symbolic link | 130 // - |watch|: the watch descriptor for a component. |
131 // is being watched, the target of the link is also kept. | 131 // - |subdir|: the subdirectory that identifies the next component. |
| 132 // - For the last component, there is no next component, so it is empty. |
| 133 // - |linkname|: the target of the symlink. |
| 134 // - Only if the target being watched is a symbolic link. |
132 struct WatchEntry { | 135 struct WatchEntry { |
133 explicit WatchEntry(const FilePath::StringType& dirname) | 136 explicit WatchEntry(const FilePath::StringType& dirname) |
134 : watch(InotifyReader::kInvalidWatch), | 137 : watch(InotifyReader::kInvalidWatch), |
135 subdir(dirname) {} | 138 subdir(dirname) {} |
136 | 139 |
137 InotifyReader::Watch watch; | 140 InotifyReader::Watch watch; |
138 FilePath::StringType subdir; | 141 FilePath::StringType subdir; |
139 FilePath::StringType linkname; | 142 FilePath::StringType linkname; |
140 }; | 143 }; |
141 typedef std::vector<WatchEntry> WatchVector; | 144 typedef std::vector<WatchEntry> WatchVector; |
(...skipping 232 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
374 if (fired_watch != watch_entry.watch) | 377 if (fired_watch != watch_entry.watch) |
375 continue; | 378 continue; |
376 | 379 |
377 // Check whether a path component of |target_| changed. | 380 // Check whether a path component of |target_| changed. |
378 bool change_on_target_path = | 381 bool change_on_target_path = |
379 child.empty() || | 382 child.empty() || |
380 (child == watch_entry.linkname) || | 383 (child == watch_entry.linkname) || |
381 (child == watch_entry.subdir); | 384 (child == watch_entry.subdir); |
382 | 385 |
383 // Check if the change references |target_| or a direct child of |target_|. | 386 // Check if the change references |target_| or a direct child of |target_|. |
384 bool is_watch_for_target = watch_entry.subdir.empty(); | 387 bool target_changed; |
385 bool target_changed = | 388 if (watch_entry.subdir.empty()) { |
386 (is_watch_for_target && (child == watch_entry.linkname)) || | 389 // The fired watch is for a WatchEntry without a subdir. Thus for a given |
387 (is_watch_for_target && watch_entry.linkname.empty()) || | 390 // |target_| = "/path/to/foo", this is for "foo". Here, check either: |
388 (watch_entry.subdir == child && watches_[i + 1].subdir.empty()); | 391 // - the target has no symlink: it is the target and it changed. |
| 392 // - the target has a symlink, and it matches |child|. |
| 393 target_changed = (watch_entry.linkname.empty() || |
| 394 child == watch_entry.linkname); |
| 395 } else { |
| 396 // The fired watch is for a WatchEntry with a subdir. Thus for a given |
| 397 // |target_| = "/path/to/foo", this is for {"/", "/path", "/path/to"}. |
| 398 // So we can safely access the next WatchEntry since we have not reached |
| 399 // the end yet. Check |watch_entry| is for "/path/to", i.e. the next |
| 400 // element is "foo". |
| 401 bool next_watch_may_be_for_target = watches_[i + 1].subdir.empty(); |
| 402 if (next_watch_may_be_for_target) { |
| 403 // The current |watch_entry| is for "/path/to", so check if the |child| |
| 404 // that changed is "foo". |
| 405 target_changed = watch_entry.subdir == child; |
| 406 } else { |
| 407 // The current |watch_entry| is not for "/path/to", so the next entry |
| 408 // cannot be "foo". Thus |target_| has not changed. |
| 409 target_changed = false; |
| 410 } |
| 411 } |
389 | 412 |
390 // Update watches if a directory component of the |target_| path | 413 // Update watches if a directory component of the |target_| path |
391 // (dis)appears. Note that we don't add the additional restriction of | 414 // (dis)appears. Note that we don't add the additional restriction of |
392 // checking the event mask to see if it is for a directory here as changes | 415 // checking the event mask to see if it is for a directory here as changes |
393 // to symlinks on the target path will not have IN_ISDIR set in the event | 416 // to symlinks on the target path will not have IN_ISDIR set in the event |
394 // masks. As a result we may sometimes call UpdateWatches() unnecessarily. | 417 // masks. As a result we may sometimes call UpdateWatches() unnecessarily. |
395 if (change_on_target_path && (created || deleted) && !did_update) { | 418 if (change_on_target_path && (created || deleted) && !did_update) { |
396 UpdateWatches(); | 419 UpdateWatches(); |
397 did_update = true; | 420 did_update = true; |
398 } | 421 } |
(...skipping 261 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
660 return watches_[watches_.size() - 1].subdir.empty(); | 683 return watches_[watches_.size() - 1].subdir.empty(); |
661 } | 684 } |
662 | 685 |
663 } // namespace | 686 } // namespace |
664 | 687 |
665 FilePathWatcher::FilePathWatcher() { | 688 FilePathWatcher::FilePathWatcher() { |
666 impl_ = new FilePathWatcherImpl(); | 689 impl_ = new FilePathWatcherImpl(); |
667 } | 690 } |
668 | 691 |
669 } // namespace base | 692 } // namespace base |
OLD | NEW |