Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(192)

Side by Side Diff: base/file_path_component_watcher_mac.cc

Issue 6660001: Getting service process on Mac to handle having things moved/changed underneath it. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 9 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(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>
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.
21 class FilePathComponentWatcherImpl
22 : public base::FilePathComponentWatcher::PlatformDelegate {
23 public:
24 FilePathComponentWatcherImpl() {}
25 virtual ~FilePathComponentWatcherImpl() {}
26
27 void OnFilePathChanged(CFFileDescriptorRef fd);
28
29 // FilePathComponentWatcher::PlatformDelegate overrides.
30 virtual bool Watch(const FilePath& path,
31 FilePathComponentWatcher::Delegate* delegate);
32 virtual void Cancel();
33
34 private:
35 base::mac::ScopedCFTypeRef<CFFileDescriptorRef> kqueue_fd_;
36 std::vector<int> file_descriptors_;
37 scoped_refptr<FilePathComponentWatcher::Delegate> delegate_;
38 FilePath path_;
39
40 DISALLOW_COPY_AND_ASSIGN(FilePathComponentWatcherImpl);
41 };
42
43 void CloseFile(int fd) {
44 if(close(fd) != 0) {
45 PLOG(ERROR) << "close";
46 }
47 }
48
49 void CloseFileDescriptors(std::vector<int>& descriptors) {
50 std::for_each(descriptors.begin(), descriptors.end(), CloseFile);
51 descriptors.clear();
52 }
53
54 bool OpenFileDescriptorsForPath(FilePath path, std::vector<int>* descriptors) {
55 FilePath normalized_path;
56 if (!file_util::NormalizeFilePath(path, &normalized_path)) {
57 return false;
58 }
59
60 std::vector<FilePath::StringType> components;
61 normalized_path.GetComponents(&components);
62
63 if (components.size() < 1) {
64 return false;
65 }
66
67 FilePath built_path(components[0]);
68 std::vector<int> local_descriptors;
69 for(std::vector<FilePath::StringType>::iterator i = components.begin() + 1;
70 i != components.end(); ++i) {
71 built_path = built_path.Append(*i);
72 int fd = open(built_path.value().c_str(), O_RDONLY);
73 if (fd == -1) {
74 PLOG(ERROR) << "open " << built_path.value();
75 CloseFileDescriptors(*descriptors);
76 descriptors->clear();
77 return false;
78 } else {
79 descriptors->push_back(fd);
80 }
81 }
82 return true;
83 }
84
85 void PathComponentWatcherTrampoline(CFFileDescriptorRef fd,
86 CFOptionFlags callBackTypes,
87 void *info) {
88 FilePathComponentWatcherImpl *impl =
89 reinterpret_cast<FilePathComponentWatcherImpl*>(info);
90 impl->OnFilePathChanged(fd);
91 }
92
93 // FilePathComponentWatcherImpl implementation:
94
95 void FilePathComponentWatcherImpl::OnFilePathChanged(CFFileDescriptorRef fd) {
96 int native_fd = CFFileDescriptorGetNativeDescriptor(fd);
97 struct kevent kev;
98 struct timespec timeout = {0, 0};
99 int status = kevent(native_fd, NULL, 0, &kev, 1, &timeout);
100 if (status < 0) {
101 PLOG(ERROR) << "kevent";
102 if (delegate_) {
103 delegate_->OnError();
104 }
105 } else if (delegate_) {
106 char path[MAXPATHLEN];
107 FilePath new_path;
108 int path_fd = file_descriptors_[file_descriptors_.size() - 1];
109 if (fcntl(path_fd, F_GETPATH, path) != -1) {
110 new_path = FilePath(path);
111 }
112 delegate_->OnFilePathComponentsChanged(path_, new_path);
113 }
114 Cancel();
115 }
116
117 bool FilePathComponentWatcherImpl::Watch(
118 const FilePath& path, FilePathComponentWatcher::Delegate* delegate) {
119 delegate_ = delegate;
120 path_ = path;
121 int kq = kqueue();
122 if (kq == -1) {
123 PLOG(ERROR) << "kqueue";
124 return false;
125 }
126 if (!OpenFileDescriptorsForPath(path, &file_descriptors_)) {
127 LOG(ERROR) << "FileDescriptorsForPath: " << path.value();
128 return false;
129 }
130
131 size_t count = file_descriptors_.size();
132
133 scoped_ptr<struct kevent> changes(reinterpret_cast<struct kevent*>(
134 calloc(count, sizeof(struct kevent))));
135
136 for(size_t i = 0; i != count; ++i) {
137 EV_SET(&(changes.get())[i], file_descriptors_[i], EVFILT_VNODE,
138 (EV_ADD | EV_CLEAR | EV_ENABLE),
139 (NOTE_RENAME | NOTE_DELETE | NOTE_ATTRIB | NOTE_REVOKE), 0, NULL);
140 }
141
142 if (HANDLE_EINTR(kevent(kq, changes.get(), count, NULL, 0, NULL)) == -1) {
143 PLOG(ERROR) << "kevent";
144 return false;
145 }
146
147 CFFileDescriptorContext context;
148 memset(&context, 0, sizeof(context));
149 context.info = this;
150
151 kqueue_fd_.reset(
152 CFFileDescriptorCreate(kCFAllocatorDefault, kq, true,
153 PathComponentWatcherTrampoline, &context));
154 CFFileDescriptorEnableCallBacks(kqueue_fd_, kCFFileDescriptorReadCallBack);
155 base::mac::ScopedCFTypeRef<CFRunLoopSourceRef> source(
156 CFFileDescriptorCreateRunLoopSource(kCFAllocatorDefault, kqueue_fd_, 0));
157 CFRunLoopAddSource(CFRunLoopGetMain(),
158 source,
159 kCFRunLoopDefaultMode);
160
161 return true;
162 }
163
164 void FilePathComponentWatcherImpl::Cancel() {
165 if (kqueue_fd_.get()) {
166 CFFileDescriptorInvalidate(kqueue_fd_);
167 kqueue_fd_.reset();
168 }
169 CloseFileDescriptors(file_descriptors_);
170 }
171
172 } // namespace
173
174 FilePathComponentWatcher::FilePathComponentWatcher() {
175 impl_ = new FilePathComponentWatcherImpl();
176 }
177
178 } // namespace base
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698