Home | History | Annotate | Download | only in base
      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