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

Side by Side Diff: base/file_watcher_mac.cc

Issue 661359: Add a FileWatcher to base/. (Closed)
Patch Set: 2s Created 10 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
« no previous file with comments | « base/file_watcher_inotify.cc ('k') | base/file_watcher_stub.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "base/file_watcher.h"
6
7 #include <CoreServices/CoreServices.h>
8
9 #include "base/file_path.h"
10 #include "base/file_util.h"
11 #include "base/logging.h"
12 #include "base/message_loop.h"
13 #include "base/scoped_cftyperef.h"
14 #include "base/time.h"
15
16 namespace {
17
18 const CFAbsoluteTime kEventLatencySeconds = 0.3;
19
20 class FileWatcherImpl : public FileWatcher::PlatformDelegate {
21 public:
22 FileWatcherImpl() {}
23 ~FileWatcherImpl() {
24 if (!path_.value().empty()) {
25 FSEventStreamStop(fsevent_stream_);
26 FSEventStreamInvalidate(fsevent_stream_);
27 FSEventStreamRelease(fsevent_stream_);
28 }
29 }
30
31 virtual bool Watch(const FilePath& path, FileWatcher::Delegate* delegate,
32 MessageLoop* backend_loop);
33
34 void OnFSEventsCallback(const FilePath& event_path) {
35 DCHECK(!path_.value().empty());
36 FilePath absolute_event_path = event_path;
37 if (!file_util::AbsolutePath(&absolute_event_path))
38 return;
39
40 file_util::FileInfo file_info;
41 bool file_exists = file_util::GetFileInfo(path_, &file_info);
42 if (file_exists && (last_modified_.is_null() ||
43 last_modified_ != file_info.last_modified)) {
44 last_modified_ = file_info.last_modified;
45 delegate_->OnFileChanged(path_);
46 } else if (file_exists && (base::Time::Now() - last_modified_ <
47 base::TimeDelta::FromSeconds(2))) {
48 // Since we only have a resolution of 1s, if we get a callback within
49 // 2s of the file having changed, go ahead and notify our observer. This
50 // might be from a different file change, but it's better to notify too
51 // much rather than miss a notification.
52 delegate_->OnFileChanged(path_);
53 } else if (!file_exists && !last_modified_.is_null()) {
54 last_modified_ = base::Time();
55 delegate_->OnFileChanged(path_);
56 }
57 }
58
59 private:
60 // Delegate to notify upon changes.
61 FileWatcher::Delegate* delegate_;
62
63 // Path we're watching (passed to delegate).
64 FilePath path_;
65
66 // Backend stream we receive event callbacks from (strong reference).
67 FSEventStreamRef fsevent_stream_;
68
69 // Keep track of the last modified time of the file. We use nulltime
70 // to represent the file not existing.
71 base::Time last_modified_;
72
73 DISALLOW_COPY_AND_ASSIGN(FileWatcherImpl);
74 };
75
76 void FSEventsCallback(ConstFSEventStreamRef stream,
77 void* event_watcher, size_t num_events,
78 void* event_paths, const FSEventStreamEventFlags flags[],
79 const FSEventStreamEventId event_ids[]) {
80 char** paths = reinterpret_cast<char**>(event_paths);
81 FileWatcherImpl* watcher =
82 reinterpret_cast<FileWatcherImpl*>(event_watcher);
83 for (size_t i = 0; i < num_events; i++)
84 watcher->OnFSEventsCallback(FilePath(paths[i]));
85 }
86
87 bool FileWatcherImpl::Watch(const FilePath& path,
88 FileWatcher::Delegate* delegate,
89 MessageLoop* backend_loop) {
90 DCHECK(path_.value().empty()); // Can only watch one path.
91 DCHECK(MessageLoop::current()->type() == MessageLoop::TYPE_UI);
92
93 FilePath parent_dir = path.DirName();
94 if (!file_util::AbsolutePath(&parent_dir))
95 return false;
96
97 file_util::FileInfo file_info;
98 if (file_util::GetFileInfo(path, &file_info))
99 last_modified_ = file_info.last_modified;
100
101 path_ = path;
102 delegate_ = delegate;
103
104 scoped_cftyperef<CFStringRef> cf_path(CFStringCreateWithCString(
105 NULL, path.DirName().value().c_str(), kCFStringEncodingMacHFS));
106 CFStringRef path_for_array = cf_path.get();
107 scoped_cftyperef<CFArrayRef> watched_paths(CFArrayCreate(
108 NULL, reinterpret_cast<const void**>(&path_for_array), 1,
109 &kCFTypeArrayCallBacks));
110
111 FSEventStreamContext context;
112 context.version = 0;
113 context.info = this;
114 context.retain = NULL;
115 context.release = NULL;
116 context.copyDescription = NULL;
117
118 fsevent_stream_ = FSEventStreamCreate(NULL, &FSEventsCallback, &context,
119 watched_paths,
120 kFSEventStreamEventIdSinceNow,
121 kEventLatencySeconds,
122 kFSEventStreamCreateFlagNone);
123 FSEventStreamScheduleWithRunLoop(fsevent_stream_, CFRunLoopGetCurrent(),
124 kCFRunLoopDefaultMode);
125 FSEventStreamStart(fsevent_stream_);
126
127 return true;
128 }
129
130 } // namespace
131
132 FileWatcher::FileWatcher() {
133 impl_ = new FileWatcherImpl();
134 }
OLDNEW
« no previous file with comments | « base/file_watcher_inotify.cc ('k') | base/file_watcher_stub.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698