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

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: fixed up phajdan's comments, got things working properly 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>
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698