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