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

Side by Side Diff: base/files/file_path_watcher_win.cc

Issue 11415066: FilePathWatcher::Watch() - Listen for sub directory changes. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix mac compile error. Created 8 years, 1 month 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
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "base/files/file_path_watcher.h" 5 #include "base/files/file_path_watcher.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/file_path.h" 8 #include "base/file_path.h"
9 #include "base/file_util.h" 9 #include "base/file_util.h"
10 #include "base/logging.h" 10 #include "base/logging.h"
11 #include "base/memory/ref_counted.h" 11 #include "base/memory/ref_counted.h"
12 #include "base/message_loop_proxy.h" 12 #include "base/message_loop_proxy.h"
13 #include "base/time.h" 13 #include "base/time.h"
14 #include "base/win/object_watcher.h" 14 #include "base/win/object_watcher.h"
15 15
16 namespace base { 16 namespace base {
17 namespace files { 17 namespace files {
18 18
19 namespace { 19 namespace {
20 20
21 class FilePathWatcherImpl : public FilePathWatcher::PlatformDelegate, 21 class FilePathWatcherImpl : public FilePathWatcher::PlatformDelegate,
22 public base::win::ObjectWatcher::Delegate, 22 public base::win::ObjectWatcher::Delegate,
23 public MessageLoop::DestructionObserver { 23 public MessageLoop::DestructionObserver {
24 public: 24 public:
25 FilePathWatcherImpl() : delegate_(NULL), handle_(INVALID_HANDLE_VALUE) {} 25 FilePathWatcherImpl() : delegate_(NULL), handle_(INVALID_HANDLE_VALUE) {}
26 26
27 // FilePathWatcher::PlatformDelegate overrides. 27 // FilePathWatcher::PlatformDelegate overrides.
28 virtual bool Watch(const FilePath& path, 28 virtual bool Watch(const FilePath& path,
29 bool recursive,
29 FilePathWatcher::Delegate* delegate) OVERRIDE; 30 FilePathWatcher::Delegate* delegate) OVERRIDE;
30 virtual void Cancel() OVERRIDE; 31 virtual void Cancel() OVERRIDE;
31 32
32 // Deletion of the FilePathWatcher will call Cancel() to dispose of this 33 // Deletion of the FilePathWatcher will call Cancel() to dispose of this
33 // object in the right thread. This also observes destruction of the required 34 // object in the right thread. This also observes destruction of the required
34 // cleanup thread, in case it quits before Cancel() is called. 35 // cleanup thread, in case it quits before Cancel() is called.
35 virtual void WillDestroyCurrentMessageLoop() OVERRIDE; 36 virtual void WillDestroyCurrentMessageLoop() OVERRIDE;
36 37
37 // Callback from MessageLoopForIO. 38 // Callback from MessageLoopForIO.
38 virtual void OnObjectSignaled(HANDLE object); 39 virtual void OnObjectSignaled(HANDLE object);
39 40
40 private: 41 private:
41 virtual ~FilePathWatcherImpl() {} 42 virtual ~FilePathWatcherImpl() {}
42 43
43 // Setup a watch handle for directory |dir|. Returns true if no fatal error 44 // Setup a watch handle for directory |dir|. Set |recursive| to true to watch
44 // occurs. |handle| will receive the handle value if |dir| is watchable, 45 // the directory sub trees. Returns true if no fatal error occurs. |handle|
45 // otherwise INVALID_HANDLE_VALUE. 46 // will receive the handle value if |dir| is watchable, otherwise
46 static bool SetupWatchHandle(const FilePath& dir, HANDLE* handle) 47 // INVALID_HANDLE_VALUE.
47 WARN_UNUSED_RESULT; 48 static bool SetupWatchHandle(const FilePath& dir,
49 bool recursive,
50 HANDLE* handle) WARN_UNUSED_RESULT;
48 51
49 // (Re-)Initialize the watch handle. 52 // (Re-)Initialize the watch handle.
50 bool UpdateWatch() WARN_UNUSED_RESULT; 53 bool UpdateWatch() WARN_UNUSED_RESULT;
51 54
52 // Destroy the watch handle. 55 // Destroy the watch handle.
53 void DestroyWatch(); 56 void DestroyWatch();
54 57
55 // Cleans up and stops observing the |message_loop_| thread. 58 // Cleans up and stops observing the |message_loop_| thread.
56 void CancelOnMessageLoopThread() OVERRIDE; 59 void CancelOnMessageLoopThread() OVERRIDE;
57 60
58 // Delegate to notify upon changes. 61 // Delegate to notify upon changes.
59 scoped_refptr<FilePathWatcher::Delegate> delegate_; 62 scoped_refptr<FilePathWatcher::Delegate> delegate_;
60 63
61 // Path we're supposed to watch (passed to delegate). 64 // Path we're supposed to watch (passed to delegate).
62 FilePath target_; 65 FilePath target_;
63 66
64 // Handle for FindFirstChangeNotification. 67 // Handle for FindFirstChangeNotification.
65 HANDLE handle_; 68 HANDLE handle_;
66 69
67 // ObjectWatcher to watch handle_ for events. 70 // ObjectWatcher to watch handle_ for events.
68 base::win::ObjectWatcher watcher_; 71 base::win::ObjectWatcher watcher_;
69 72
73 // Set to true to watch the sub trees of the specified directory file path.
74 bool recursive_watch_;
Lei Zhang 2012/11/21 03:36:49 You need to initialize this.
kmadhusu 2012/11/21 04:13:26 Done.
75
70 // Keep track of the last modified time of the file. We use nulltime 76 // Keep track of the last modified time of the file. We use nulltime
71 // to represent the file not existing. 77 // to represent the file not existing.
72 base::Time last_modified_; 78 base::Time last_modified_;
73 79
74 // The time at which we processed the first notification with the 80 // The time at which we processed the first notification with the
75 // |last_modified_| time stamp. 81 // |last_modified_| time stamp.
76 base::Time first_notification_; 82 base::Time first_notification_;
77 83
78 DISALLOW_COPY_AND_ASSIGN(FilePathWatcherImpl); 84 DISALLOW_COPY_AND_ASSIGN(FilePathWatcherImpl);
79 }; 85 };
80 86
81 bool FilePathWatcherImpl::Watch(const FilePath& path, 87 bool FilePathWatcherImpl::Watch(const FilePath& path,
88 bool recursive,
82 FilePathWatcher::Delegate* delegate) { 89 FilePathWatcher::Delegate* delegate) {
83 DCHECK(target_.value().empty()); // Can only watch one path. 90 DCHECK(target_.value().empty()); // Can only watch one path.
84 91
85 set_message_loop(base::MessageLoopProxy::current()); 92 set_message_loop(base::MessageLoopProxy::current());
86 delegate_ = delegate; 93 delegate_ = delegate;
87 target_ = path; 94 target_ = path;
95 recursive_watch_ = recursive;
88 MessageLoop::current()->AddDestructionObserver(this); 96 MessageLoop::current()->AddDestructionObserver(this);
89 97
90 if (!UpdateWatch()) 98 if (!UpdateWatch())
91 return false; 99 return false;
92 100
93 watcher_.StartWatching(handle_, this); 101 watcher_.StartWatching(handle_, this);
94 102
95 return true; 103 return true;
96 } 104 }
97 105
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after
172 delegate_->OnFilePathChanged(target_); 180 delegate_->OnFilePathChanged(target_);
173 } 181 }
174 182
175 // The watch may have been cancelled by the callback. 183 // The watch may have been cancelled by the callback.
176 if (handle_ != INVALID_HANDLE_VALUE) 184 if (handle_ != INVALID_HANDLE_VALUE)
177 watcher_.StartWatching(handle_, this); 185 watcher_.StartWatching(handle_, this);
178 } 186 }
179 187
180 // static 188 // static
181 bool FilePathWatcherImpl::SetupWatchHandle(const FilePath& dir, 189 bool FilePathWatcherImpl::SetupWatchHandle(const FilePath& dir,
190 bool recursive,
182 HANDLE* handle) { 191 HANDLE* handle) {
183 *handle = FindFirstChangeNotification( 192 *handle = FindFirstChangeNotification(
184 dir.value().c_str(), 193 dir.value().c_str(),
185 false, // Don't watch subtrees 194 recursive,
186 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_SIZE | 195 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_SIZE |
187 FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_DIR_NAME | 196 FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_DIR_NAME |
188 FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_SECURITY); 197 FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_SECURITY);
189 if (*handle != INVALID_HANDLE_VALUE) { 198 if (*handle != INVALID_HANDLE_VALUE) {
190 // Make sure the handle we got points to an existing directory. It seems 199 // Make sure the handle we got points to an existing directory. It seems
191 // that windows sometimes hands out watches to direectories that are 200 // that windows sometimes hands out watches to directories that are
192 // about to go away, but doesn't sent notifications if that happens. 201 // about to go away, but doesn't sent notifications if that happens.
193 if (!file_util::DirectoryExists(dir)) { 202 if (!file_util::DirectoryExists(dir)) {
194 FindCloseChangeNotification(*handle); 203 FindCloseChangeNotification(*handle);
195 *handle = INVALID_HANDLE_VALUE; 204 *handle = INVALID_HANDLE_VALUE;
196 } 205 }
197 return true; 206 return true;
198 } 207 }
199 208
200 // If FindFirstChangeNotification failed because the target directory 209 // If FindFirstChangeNotification failed because the target directory
201 // doesn't exist, access is denied (happens if the file is already gone but 210 // doesn't exist, access is denied (happens if the file is already gone but
(...skipping 23 matching lines...) Expand all
225 last_modified_ = file_info.last_modified; 234 last_modified_ = file_info.last_modified;
226 first_notification_ = base::Time::Now(); 235 first_notification_ = base::Time::Now();
227 } 236 }
228 237
229 // Start at the target and walk up the directory chain until we succesfully 238 // Start at the target and walk up the directory chain until we succesfully
230 // create a watch handle in |handle_|. |child_dirs| keeps a stack of child 239 // create a watch handle in |handle_|. |child_dirs| keeps a stack of child
231 // directories stripped from target, in reverse order. 240 // directories stripped from target, in reverse order.
232 std::vector<FilePath> child_dirs; 241 std::vector<FilePath> child_dirs;
233 FilePath watched_path(target_); 242 FilePath watched_path(target_);
234 while (true) { 243 while (true) {
235 if (!SetupWatchHandle(watched_path, &handle_)) 244 if (!SetupWatchHandle(watched_path, recursive_watch_, &handle_))
236 return false; 245 return false;
237 246
238 // Break if a valid handle is returned. Try the parent directory otherwise. 247 // Break if a valid handle is returned. Try the parent directory otherwise.
239 if (handle_ != INVALID_HANDLE_VALUE) 248 if (handle_ != INVALID_HANDLE_VALUE)
240 break; 249 break;
241 250
242 // Abort if we hit the root directory. 251 // Abort if we hit the root directory.
243 child_dirs.push_back(watched_path.BaseName()); 252 child_dirs.push_back(watched_path.BaseName());
244 FilePath parent(watched_path.DirName()); 253 FilePath parent(watched_path.DirName());
245 if (parent == watched_path) { 254 if (parent == watched_path) {
246 DLOG(ERROR) << "Reached the root directory"; 255 DLOG(ERROR) << "Reached the root directory";
247 return false; 256 return false;
248 } 257 }
249 watched_path = parent; 258 watched_path = parent;
250 } 259 }
251 260
252 // At this point, handle_ is valid. However, the bottom-up search that the 261 // At this point, handle_ is valid. However, the bottom-up search that the
253 // above code performs races against directory creation. So try to walk back 262 // above code performs races against directory creation. So try to walk back
254 // down and see whether any children appeared in the mean time. 263 // down and see whether any children appeared in the mean time.
255 while (!child_dirs.empty()) { 264 while (!child_dirs.empty()) {
256 watched_path = watched_path.Append(child_dirs.back()); 265 watched_path = watched_path.Append(child_dirs.back());
257 child_dirs.pop_back(); 266 child_dirs.pop_back();
258 HANDLE temp_handle = INVALID_HANDLE_VALUE; 267 HANDLE temp_handle = INVALID_HANDLE_VALUE;
259 if (!SetupWatchHandle(watched_path, &temp_handle)) 268 if (!SetupWatchHandle(watched_path, recursive_watch_, &temp_handle))
260 return false; 269 return false;
261 if (temp_handle == INVALID_HANDLE_VALUE) 270 if (temp_handle == INVALID_HANDLE_VALUE)
262 break; 271 break;
263 FindCloseChangeNotification(handle_); 272 FindCloseChangeNotification(handle_);
264 handle_ = temp_handle; 273 handle_ = temp_handle;
265 } 274 }
266 275
267 return true; 276 return true;
268 } 277 }
269 278
270 void FilePathWatcherImpl::DestroyWatch() { 279 void FilePathWatcherImpl::DestroyWatch() {
271 watcher_.StopWatching(); 280 watcher_.StopWatching();
272 FindCloseChangeNotification(handle_); 281 FindCloseChangeNotification(handle_);
273 handle_ = INVALID_HANDLE_VALUE; 282 handle_ = INVALID_HANDLE_VALUE;
274 } 283 }
275 284
276 } // namespace 285 } // namespace
277 286
278 FilePathWatcher::FilePathWatcher() { 287 FilePathWatcher::FilePathWatcher() {
279 impl_ = new FilePathWatcherImpl(); 288 impl_ = new FilePathWatcherImpl();
280 } 289 }
281 290
282 } // namespace files 291 } // namespace files
283 } // namespace base 292 } // namespace base
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698