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/directory_watcher.h" 6 7 #include "base/file_path.h" 8 #include "base/logging.h" 9 #include "base/object_watcher.h" 10 #include "base/ref_counted.h" 11 12 namespace { 13 14 class DirectoryWatcherImpl : public DirectoryWatcher::PlatformDelegate, 15 public base::ObjectWatcher::Delegate { 16 public: 17 DirectoryWatcherImpl() : delegate_(NULL), handle_(INVALID_HANDLE_VALUE) {} 18 19 virtual bool Watch(const FilePath& path, DirectoryWatcher::Delegate* delegate, 20 MessageLoop* backend_loop, bool recursive); 21 22 // Callback from MessageLoopForIO. 23 virtual void OnObjectSignaled(HANDLE object); 24 25 private: 26 virtual ~DirectoryWatcherImpl(); 27 28 // Delegate to notify upon changes. 29 DirectoryWatcher::Delegate* delegate_; 30 // Path we're watching (passed to delegate). 31 FilePath path_; 32 // Handle for FindFirstChangeNotification. 33 HANDLE handle_; 34 // ObjectWatcher to watch handle_ for events. 35 base::ObjectWatcher watcher_; 36 37 DISALLOW_COPY_AND_ASSIGN(DirectoryWatcherImpl); 38 }; 39 40 DirectoryWatcherImpl::~DirectoryWatcherImpl() { 41 if (handle_ != INVALID_HANDLE_VALUE) { 42 watcher_.StopWatching(); 43 FindCloseChangeNotification(handle_); 44 } 45 } 46 47 bool DirectoryWatcherImpl::Watch(const FilePath& path, 48 DirectoryWatcher::Delegate* delegate, 49 MessageLoop* backend_loop, bool recursive) { 50 DCHECK(path_.value().empty()); // Can only watch one path. 51 52 handle_ = FindFirstChangeNotification( 53 path.value().c_str(), 54 recursive, 55 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_SIZE | 56 FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_DIR_NAME); 57 if (handle_ == INVALID_HANDLE_VALUE) 58 return false; 59 60 delegate_ = delegate; 61 path_ = path; 62 watcher_.StartWatching(handle_, this); 63 64 return true; 65 } 66 67 void DirectoryWatcherImpl::OnObjectSignaled(HANDLE object) { 68 DCHECK(object == handle_); 69 // Make sure we stay alive through the body of this function. 70 scoped_refptr<DirectoryWatcherImpl> keep_alive(this); 71 72 delegate_->OnDirectoryChanged(path_); 73 74 // Register for more notifications on file change. 75 BOOL ok = FindNextChangeNotification(object); 76 DCHECK(ok); 77 watcher_.StartWatching(object, this); 78 } 79 80 } // namespace 81 82 DirectoryWatcher::DirectoryWatcher() { 83 impl_ = new DirectoryWatcherImpl(); 84 } 85