Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "base/file_path_component_watcher.h" | |
| 6 | |
| 7 #include <CoreFoundation/CoreFoundation.h> | |
| 8 #include <fcntl.h> | |
| 9 #include <sys/event.h> | |
| 10 #include <sys/param.h> | |
| 11 #include <vector> | |
|
Mark Mentovai
2011/03/11 20:13:52
Blank line before. C++ system headers are in a sep
| |
| 12 | |
| 13 #include "base/file_util.h" | |
| 14 #include "base/mac/scoped_cftyperef.h" | |
| 15 | |
| 16 namespace base { | |
| 17 | |
| 18 namespace { | |
| 19 | |
| 20 // Mac-specific file watcher implementation based on kqueue. | |
|
Mark Mentovai
2011/03/11 20:13:52
This sounds like it’s going to eat up a lot of fil
| |
| 21 class FilePathComponentWatcherImpl | |
| 22 : public FilePathComponentWatcher::PlatformDelegate { | |
| 23 public: | |
| 24 FilePathComponentWatcherImpl(FilePathComponentWatcher* watcher) | |
|
Mark Mentovai
2011/03/11 20:13:52
explicit
| |
| 25 : watcher_(watcher) {} | |
| 26 virtual ~FilePathComponentWatcherImpl() {} | |
|
Mark Mentovai
2011/03/11 20:13:52
Not needed?
Scott Byer
2011/03/11 20:25:02
What about closing the file descriptors on exit, i
| |
| 27 | |
| 28 void OnFilePathChanged(CFFileDescriptorRef fd); | |
| 29 | |
| 30 // FilePathComponentWatcher::PlatformDelegate overrides. | |
| 31 virtual bool Watch(const FilePath& path, | |
| 32 FilePathComponentWatcher::Delegate* delegate); | |
| 33 virtual void Cancel(); | |
| 34 | |
| 35 private: | |
| 36 FilePathComponentWatcher* watcher_; | |
| 37 base::mac::ScopedCFTypeRef<CFFileDescriptorRef> kqueue_fd_; | |
| 38 std::vector<int> file_descriptors_; | |
| 39 scoped_refptr<FilePathComponentWatcher::Delegate> delegate_; | |
| 40 FilePath path_; | |
| 41 | |
| 42 DISALLOW_COPY_AND_ASSIGN(FilePathComponentWatcherImpl); | |
| 43 }; | |
| 44 | |
| 45 void CloseFile(int fd) { | |
| 46 if(close(fd) != 0) { | |
|
Mark Mentovai
2011/03/11 20:13:52
if<space>(close…
| |
| 47 PLOG(ERROR) << "close"; | |
| 48 } | |
| 49 } | |
| 50 | |
| 51 void CloseFileDescriptors(std::vector<int>& descriptors) { | |
|
Mark Mentovai
2011/03/11 20:13:52
It’s uncommon (and therefore unexpected) to pass n
| |
| 52 std::for_each(descriptors.begin(), descriptors.end(), CloseFile); | |
| 53 descriptors.clear(); | |
| 54 } | |
| 55 | |
| 56 bool OpenFileDescriptorsForPath(FilePath path, std::vector<int>* descriptors) { | |
|
Mark Mentovai
2011/03/11 20:13:52
Start this function with CloseFileDescriptors(*des
| |
| 57 FilePath normalized_path; | |
| 58 if (!file_util::NormalizeFilePath(path, &normalized_path)) { | |
| 59 return false; | |
| 60 } | |
| 61 | |
| 62 std::vector<FilePath::StringType> components; | |
| 63 normalized_path.GetComponents(&components); | |
| 64 | |
| 65 if (components.size() < 1) { | |
| 66 return false; | |
| 67 } | |
| 68 | |
| 69 FilePath built_path(components[0]); | |
| 70 std::vector<int> local_descriptors; | |
| 71 for(std::vector<FilePath::StringType>::iterator i = components.begin() + 1; | |
| 72 i != components.end(); ++i) { | |
| 73 built_path = built_path.Append(*i); | |
| 74 int fd = open(built_path.value().c_str(), O_RDONLY); | |
| 75 if (fd == -1) { | |
| 76 PLOG(ERROR) << "open " << built_path.value(); | |
| 77 CloseFileDescriptors(*descriptors); | |
| 78 descriptors->clear(); | |
| 79 return false; | |
| 80 } else { | |
|
Mark Mentovai
2011/03/11 20:13:52
No else needed after a return.
| |
| 81 descriptors->push_back(fd); | |
| 82 } | |
| 83 } | |
| 84 return true; | |
| 85 } | |
| 86 | |
| 87 void PathComponentWatcherTrampoline(CFFileDescriptorRef fd, | |
| 88 CFOptionFlags callBackTypes, | |
|
Mark Mentovai
2011/03/11 20:13:52
Match our style: callback_types.
| |
| 89 void *info) { | |
| 90 FilePathComponentWatcherImpl *impl = | |
| 91 reinterpret_cast<FilePathComponentWatcherImpl*>(info); | |
| 92 impl->OnFilePathChanged(fd); | |
| 93 } | |
| 94 | |
| 95 // FilePathComponentWatcherImpl implementation: | |
| 96 | |
| 97 void FilePathComponentWatcherImpl::OnFilePathChanged(CFFileDescriptorRef fd) { | |
|
Mark Mentovai
2011/03/11 20:13:52
I would find this class implementation easier to r
| |
| 98 int native_fd = CFFileDescriptorGetNativeDescriptor(fd); | |
| 99 struct kevent kev; | |
| 100 struct timespec timeout = {0, 0}; | |
| 101 int status = kevent(native_fd, NULL, 0, &kev, 1, &timeout); | |
| 102 FilePath new_path; | |
|
Mark Mentovai
2011/03/11 20:13:52
Don’t declare this ’til you use it, which looks li
| |
| 103 if (status < 0) { | |
| 104 PLOG(ERROR) << "kevent"; | |
| 105 if (delegate_) { | |
| 106 delegate_->OnError(watcher_); | |
| 107 } | |
| 108 } else if (delegate_) { | |
|
Mark Mentovai
2011/03/11 20:13:52
When will there not be a delegate?
Scott Byer
2011/03/11 20:25:02
If delegate_ is NULL, I would think we'd want to D
| |
| 109 char path[MAXPATHLEN]; | |
|
Mark Mentovai
2011/03/11 20:13:52
Anything involving MAXPATHLEN is a hack. I think w
| |
| 110 int path_fd = file_descriptors_[file_descriptors_.size() - 1]; | |
|
Mark Mentovai
2011/03/11 20:13:52
You can just use file_descriptors_.back().
| |
| 111 if (fcntl(path_fd, F_GETPATH, path) != -1) { | |
| 112 new_path = FilePath(path); | |
| 113 } | |
| 114 delegate_->OnFilePathComponentsChanged(watcher_, path_, new_path); | |
|
Mark Mentovai
2011/03/11 20:13:52
new_path may be empty here, which I’m assuming is
| |
| 115 } | |
| 116 } | |
| 117 | |
| 118 bool FilePathComponentWatcherImpl::Watch( | |
| 119 const FilePath& path, FilePathComponentWatcher::Delegate* delegate) { | |
| 120 delegate_ = delegate; | |
| 121 path_ = path; | |
| 122 int kq = kqueue(); | |
| 123 if (kq == -1) { | |
| 124 PLOG(ERROR) << "kqueue"; | |
| 125 return false; | |
| 126 } | |
| 127 if (!OpenFileDescriptorsForPath(path, &file_descriptors_)) { | |
| 128 LOG(ERROR) << "FileDescriptorsForPath: " << path.value(); | |
|
Mark Mentovai
2011/03/11 20:13:52
OpenFileDescriptorsForPath?
| |
| 129 return false; | |
| 130 } | |
| 131 | |
| 132 size_t count = file_descriptors_.size(); | |
| 133 | |
| 134 scoped_ptr<struct kevent> changes(reinterpret_cast<struct kevent*>( | |
|
Mark Mentovai
2011/03/11 20:13:52
scoped_ptr is intended to be used with objects all
| |
| 135 calloc(count, sizeof(struct kevent)))); | |
| 136 | |
| 137 for(size_t i = 0; i != count; ++i) { | |
|
Mark Mentovai
2011/03/11 20:13:52
for<space>(size_t…
| |
| 138 EV_SET(&(changes.get())[i], file_descriptors_[i], EVFILT_VNODE, | |
| 139 (EV_ADD | EV_CLEAR | EV_ENABLE), | |
| 140 (NOTE_RENAME | NOTE_DELETE | NOTE_ATTRIB | NOTE_REVOKE), 0, NULL); | |
| 141 } | |
| 142 | |
| 143 if (HANDLE_EINTR(kevent(kq, changes.get(), count, NULL, 0, NULL)) == -1) { | |
|
Mark Mentovai
2011/03/11 20:13:52
This confused me for a second, because I saw the N
| |
| 144 PLOG(ERROR) << "kevent"; | |
| 145 return false; | |
| 146 } | |
| 147 | |
| 148 CFFileDescriptorContext context; | |
| 149 memset(&context, 0, sizeof(context)); | |
|
Mark Mentovai
2011/03/11 20:13:52
Or just CFFileDescriptorContext context = {0};
| |
| 150 context.info = this; | |
| 151 | |
| 152 kqueue_fd_.reset( | |
| 153 CFFileDescriptorCreate(kCFAllocatorDefault, kq, true, | |
| 154 PathComponentWatcherTrampoline, &context)); | |
| 155 CFFileDescriptorEnableCallBacks(kqueue_fd_, kCFFileDescriptorReadCallBack); | |
| 156 base::mac::ScopedCFTypeRef<CFRunLoopSourceRef> source( | |
| 157 CFFileDescriptorCreateRunLoopSource(kCFAllocatorDefault, kqueue_fd_, 0)); | |
| 158 CFRunLoopAddSource(CFRunLoopGetMain(), | |
|
Mark Mentovai
2011/03/11 20:13:52
The run loop source leaks because nobody ever remo
Mark Mentovai
2011/03/11 20:13:52
I usually use CFRunLoopGetCurrent. Do you have a r
| |
| 159 source, | |
|
Mark Mentovai
2011/03/11 20:13:52
This didn’t all fit on one line?
| |
| 160 kCFRunLoopDefaultMode); | |
| 161 | |
| 162 return true; | |
| 163 } | |
| 164 | |
| 165 void FilePathComponentWatcherImpl::Cancel() { | |
| 166 if (kqueue_fd_.get()) { | |
| 167 CFFileDescriptorInvalidate(kqueue_fd_); | |
| 168 kqueue_fd_.reset(); | |
| 169 } | |
| 170 CloseFileDescriptors(file_descriptors_); | |
| 171 } | |
| 172 | |
| 173 } // namespace | |
| 174 | |
| 175 FilePathComponentWatcher::FilePathComponentWatcher() { | |
| 176 impl_ = new FilePathComponentWatcherImpl(this); | |
| 177 } | |
| 178 | |
| 179 } // namespace base | |
| OLD | NEW |