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 |