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/file_watcher.h" | 5 #include "chrome/browser/file_watcher.h" |
6 | 6 |
7 #include <CoreServices/CoreServices.h> | 7 #include <CoreServices/CoreServices.h> |
8 | 8 |
9 #include "base/file_path.h" | 9 #include "base/file_path.h" |
10 #include "base/file_util.h" | 10 #include "base/file_util.h" |
11 #include "base/logging.h" | 11 #include "base/logging.h" |
12 #include "base/message_loop.h" | |
13 #include "base/scoped_cftyperef.h" | 12 #include "base/scoped_cftyperef.h" |
14 #include "base/time.h" | 13 #include "base/time.h" |
15 | 14 |
16 namespace { | 15 namespace { |
17 | 16 |
18 const CFAbsoluteTime kEventLatencySeconds = 0.3; | 17 const CFAbsoluteTime kEventLatencySeconds = 0.3; |
19 | 18 |
20 class FileWatcherImpl : public FileWatcher::PlatformDelegate { | 19 class FileWatcherImpl : public FileWatcher::PlatformDelegate { |
21 public: | 20 public: |
22 FileWatcherImpl() {} | 21 FileWatcherImpl() {} |
23 ~FileWatcherImpl() { | 22 ~FileWatcherImpl() { |
24 if (!path_.value().empty()) { | 23 if (!path_.value().empty()) { |
25 FSEventStreamStop(fsevent_stream_); | 24 FSEventStreamStop(fsevent_stream_); |
26 FSEventStreamInvalidate(fsevent_stream_); | 25 FSEventStreamInvalidate(fsevent_stream_); |
27 FSEventStreamRelease(fsevent_stream_); | 26 FSEventStreamRelease(fsevent_stream_); |
28 } | 27 } |
29 } | 28 } |
30 | 29 |
31 virtual bool Watch(const FilePath& path, FileWatcher::Delegate* delegate, | 30 virtual bool Watch(const FilePath& path, FileWatcher::Delegate* delegate) { |
32 MessageLoop* backend_loop); | 31 FilePath parent_dir = path.DirName(); |
| 32 if (!file_util::AbsolutePath(&parent_dir)) |
| 33 return false; |
| 34 |
| 35 // Jump back to the UI thread because FSEventStreamScheduleWithRunLoop |
| 36 // requires a UI thread. |
| 37 if (!ChromeThread::CurrentlyOn(ChromeThread::UI)) { |
| 38 ChromeThread::PostTask(ChromeThread::UI, FROM_HERE, |
| 39 NewRunnableMethod(this, &FileWatcherImpl::WatchImpl, path, delegate)); |
| 40 } else { |
| 41 // During unittests, there is only one thread and it is both the UI |
| 42 // thread and the file thread. |
| 43 WatchImpl(path, delegate); |
| 44 } |
| 45 return true; |
| 46 } |
| 47 |
| 48 bool WatchImpl(const FilePath& path, FileWatcher::Delegate* delegate); |
33 | 49 |
34 void OnFSEventsCallback(const FilePath& event_path) { | 50 void OnFSEventsCallback(const FilePath& event_path) { |
| 51 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); |
35 DCHECK(!path_.value().empty()); | 52 DCHECK(!path_.value().empty()); |
36 FilePath absolute_event_path = event_path; | 53 FilePath absolute_event_path = event_path; |
37 if (!file_util::AbsolutePath(&absolute_event_path)) | 54 if (!file_util::AbsolutePath(&absolute_event_path)) |
38 return; | 55 return; |
39 | 56 |
40 file_util::FileInfo file_info; | 57 file_util::FileInfo file_info; |
41 bool file_exists = file_util::GetFileInfo(path_, &file_info); | 58 bool file_exists = file_util::GetFileInfo(path_, &file_info); |
42 if (file_exists && (last_modified_.is_null() || | 59 if (file_exists && (last_modified_.is_null() || |
43 last_modified_ != file_info.last_modified)) { | 60 last_modified_ != file_info.last_modified)) { |
44 last_modified_ = file_info.last_modified; | 61 last_modified_ = file_info.last_modified; |
(...skipping 28 matching lines...) Expand all Loading... |
73 DISALLOW_COPY_AND_ASSIGN(FileWatcherImpl); | 90 DISALLOW_COPY_AND_ASSIGN(FileWatcherImpl); |
74 }; | 91 }; |
75 | 92 |
76 void FSEventsCallback(ConstFSEventStreamRef stream, | 93 void FSEventsCallback(ConstFSEventStreamRef stream, |
77 void* event_watcher, size_t num_events, | 94 void* event_watcher, size_t num_events, |
78 void* event_paths, const FSEventStreamEventFlags flags[], | 95 void* event_paths, const FSEventStreamEventFlags flags[], |
79 const FSEventStreamEventId event_ids[]) { | 96 const FSEventStreamEventId event_ids[]) { |
80 char** paths = reinterpret_cast<char**>(event_paths); | 97 char** paths = reinterpret_cast<char**>(event_paths); |
81 FileWatcherImpl* watcher = | 98 FileWatcherImpl* watcher = |
82 reinterpret_cast<FileWatcherImpl*>(event_watcher); | 99 reinterpret_cast<FileWatcherImpl*>(event_watcher); |
83 for (size_t i = 0; i < num_events; i++) | 100 for (size_t i = 0; i < num_events; i++) { |
84 watcher->OnFSEventsCallback(FilePath(paths[i])); | 101 if (!ChromeThread::CurrentlyOn(ChromeThread::FILE)) { |
| 102 ChromeThread::PostTask(ChromeThread::FILE, FROM_HERE, |
| 103 NewRunnableMethod(watcher, &FileWatcherImpl::OnFSEventsCallback, |
| 104 FilePath(paths[i]))); |
| 105 } else { |
| 106 // During unittests, there is only one thread and it is both the UI |
| 107 // thread and the file thread. |
| 108 watcher->OnFSEventsCallback(FilePath(paths[i])); |
| 109 } |
| 110 } |
85 } | 111 } |
86 | 112 |
87 bool FileWatcherImpl::Watch(const FilePath& path, | 113 bool FileWatcherImpl::WatchImpl(const FilePath& path, |
88 FileWatcher::Delegate* delegate, | 114 FileWatcher::Delegate* delegate) { |
89 MessageLoop* backend_loop) { | |
90 DCHECK(path_.value().empty()); // Can only watch one path. | 115 DCHECK(path_.value().empty()); // Can only watch one path. |
91 DCHECK(MessageLoop::current()->type() == MessageLoop::TYPE_UI); | 116 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
92 | |
93 FilePath parent_dir = path.DirName(); | |
94 if (!file_util::AbsolutePath(&parent_dir)) | |
95 return false; | |
96 | 117 |
97 file_util::FileInfo file_info; | 118 file_util::FileInfo file_info; |
98 if (file_util::GetFileInfo(path, &file_info)) | 119 if (file_util::GetFileInfo(path, &file_info)) |
99 last_modified_ = file_info.last_modified; | 120 last_modified_ = file_info.last_modified; |
100 | 121 |
101 path_ = path; | 122 path_ = path; |
102 delegate_ = delegate; | 123 delegate_ = delegate; |
103 | 124 |
104 scoped_cftyperef<CFStringRef> cf_path(CFStringCreateWithCString( | 125 scoped_cftyperef<CFStringRef> cf_path(CFStringCreateWithCString( |
105 NULL, path.DirName().value().c_str(), kCFStringEncodingMacHFS)); | 126 NULL, path.DirName().value().c_str(), kCFStringEncodingMacHFS)); |
(...skipping 19 matching lines...) Expand all Loading... |
125 FSEventStreamStart(fsevent_stream_); | 146 FSEventStreamStart(fsevent_stream_); |
126 | 147 |
127 return true; | 148 return true; |
128 } | 149 } |
129 | 150 |
130 } // namespace | 151 } // namespace |
131 | 152 |
132 FileWatcher::FileWatcher() { | 153 FileWatcher::FileWatcher() { |
133 impl_ = new FileWatcherImpl(); | 154 impl_ = new FileWatcherImpl(); |
134 } | 155 } |
OLD | NEW |