1ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved.
23345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// Use of this source code is governed by a BSD-style license that can be
33345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// found in the LICENSE file.
43345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
5ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/files/file_path_watcher.h"
63345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
73345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/file_path.h"
83345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/file_util.h"
93345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/logging.h"
10ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/memory/ref_counted.h"
11ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/message_loop_proxy.h"
123345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/time.h"
133f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#include "base/win/object_watcher.h"
143345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
15ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsennamespace base {
16ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsennamespace files {
17ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
183345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merricknamespace {
193345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
203345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickclass FilePathWatcherImpl : public FilePathWatcher::PlatformDelegate,
21ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                            public base::win::ObjectWatcher::Delegate,
22ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                            public MessageLoop::DestructionObserver {
233345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick public:
243345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  FilePathWatcherImpl() : delegate_(NULL), handle_(INVALID_HANDLE_VALUE) {}
253345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
26ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // FilePathWatcher::PlatformDelegate overrides.
27ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  virtual bool Watch(const FilePath& path,
28ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                     FilePathWatcher::Delegate* delegate) OVERRIDE;
29ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  virtual void Cancel() OVERRIDE;
30ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
31ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Deletion of the FilePathWatcher will call Cancel() to dispose of this
32ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // object in the right thread. This also observes destruction of the required
33ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // cleanup thread, in case it quits before Cancel() is called.
34ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  virtual void WillDestroyCurrentMessageLoop() OVERRIDE;
353345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
363345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Callback from MessageLoopForIO.
373345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  virtual void OnObjectSignaled(HANDLE object);
383345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
393345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick private:
40ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  virtual ~FilePathWatcherImpl() {}
413345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
423345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Setup a watch handle for directory |dir|. Returns true if no fatal error
433345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // occurs. |handle| will receive the handle value if |dir| is watchable,
443345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // otherwise INVALID_HANDLE_VALUE.
453345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  static bool SetupWatchHandle(const FilePath& dir, HANDLE* handle)
463345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      WARN_UNUSED_RESULT;
473345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
483345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // (Re-)Initialize the watch handle.
493345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  bool UpdateWatch() WARN_UNUSED_RESULT;
503345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
513345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Destroy the watch handle.
523345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  void DestroyWatch();
533345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
54ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Cleans up and stops observing the |message_loop_| thread.
55ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  void CancelOnMessageLoopThread() OVERRIDE;
56ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
573345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Delegate to notify upon changes.
583345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  scoped_refptr<FilePathWatcher::Delegate> delegate_;
593345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
603345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Path we're supposed to watch (passed to delegate).
613345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  FilePath target_;
623345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
633345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Handle for FindFirstChangeNotification.
643345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  HANDLE handle_;
653345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
663345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // ObjectWatcher to watch handle_ for events.
673f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  base::win::ObjectWatcher watcher_;
683345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
693345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Keep track of the last modified time of the file.  We use nulltime
703345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // to represent the file not existing.
713345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  base::Time last_modified_;
723345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
733345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // The time at which we processed the first notification with the
743345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // |last_modified_| time stamp.
753345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  base::Time first_notification_;
763345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
773345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  DISALLOW_COPY_AND_ASSIGN(FilePathWatcherImpl);
783345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick};
793345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
803345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickbool FilePathWatcherImpl::Watch(const FilePath& path,
813345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                FilePathWatcher::Delegate* delegate) {
823345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  DCHECK(target_.value().empty());  // Can only watch one path.
83ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
84ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  set_message_loop(base::MessageLoopProxy::CreateForCurrentThread());
853345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  delegate_ = delegate;
863345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  target_ = path;
87ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  MessageLoop::current()->AddDestructionObserver(this);
883345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
893345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (!UpdateWatch())
903345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    return false;
913345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
923345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  watcher_.StartWatching(handle_, this);
933345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
943345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  return true;
953345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
963345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
973345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid FilePathWatcherImpl::Cancel() {
98ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (!delegate_) {
99ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // Watch was never called, or the |message_loop_| has already quit.
100ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    set_cancelled();
1013345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    return;
1023345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
1033345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
104ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Switch to the file thread if necessary so we can stop |watcher_|.
105ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (!message_loop()->BelongsToCurrentThread()) {
106ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    message_loop()->PostTask(FROM_HERE,
107ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                             new FilePathWatcher::CancelTask(this));
108ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  } else {
109ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    CancelOnMessageLoopThread();
110ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
111ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
112ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
113ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid FilePathWatcherImpl::CancelOnMessageLoopThread() {
114ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  set_cancelled();
115ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
1163345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (handle_ != INVALID_HANDLE_VALUE)
1173345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    DestroyWatch();
118ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
119ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (delegate_) {
120ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    MessageLoop::current()->RemoveDestructionObserver(this);
121ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    delegate_ = NULL;
122ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
123ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
124ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
125ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid FilePathWatcherImpl::WillDestroyCurrentMessageLoop() {
126ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  CancelOnMessageLoopThread();
1273345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
1283345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1293345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid FilePathWatcherImpl::OnObjectSignaled(HANDLE object) {
1303345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  DCHECK(object == handle_);
1313345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Make sure we stay alive through the body of this function.
1323345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  scoped_refptr<FilePathWatcherImpl> keep_alive(this);
1333345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1343345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (!UpdateWatch()) {
135ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    delegate_->OnFilePathError(target_);
1363345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    return;
1373345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
1383345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1393345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Check whether the event applies to |target_| and notify the delegate.
1403345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  base::PlatformFileInfo file_info;
1413345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  bool file_exists = file_util::GetFileInfo(target_, &file_info);
1423345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (file_exists && (last_modified_.is_null() ||
1433345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      last_modified_ != file_info.last_modified)) {
1443345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    last_modified_ = file_info.last_modified;
1453345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    first_notification_ = base::Time::Now();
1463345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    delegate_->OnFilePathChanged(target_);
1473345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  } else if (file_exists && !first_notification_.is_null()) {
1483345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    // The target's last modification time is equal to what's on record. This
1493345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    // means that either an unrelated event occurred, or the target changed
1503345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    // again (file modification times only have a resolution of 1s). Comparing
1513345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    // file modification times against the wall clock is not reliable to find
1523345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    // out whether the change is recent, since this code might just run too
1533345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    // late. Moreover, there's no guarantee that file modification time and wall
1543345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    // clock times come from the same source.
1553345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    //
1563345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    // Instead, the time at which the first notification carrying the current
1573345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    // |last_notified_| time stamp is recorded. Later notifications that find
1583345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    // the same file modification time only need to be forwarded until wall
1593345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    // clock has advanced one second from the initial notification. After that
1603345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    // interval, client code is guaranteed to having seen the current revision
1613345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    // of the file.
1623345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    if (base::Time::Now() - first_notification_ >
1633345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        base::TimeDelta::FromSeconds(1)) {
1643345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      // Stop further notifications for this |last_modification_| time stamp.
1653345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      first_notification_ = base::Time();
1663345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    }
1673345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    delegate_->OnFilePathChanged(target_);
1683345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  } else if (!file_exists && !last_modified_.is_null()) {
1693345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    last_modified_ = base::Time();
1703345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    delegate_->OnFilePathChanged(target_);
1713345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
1723345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1733345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // The watch may have been cancelled by the callback.
1743345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (handle_ != INVALID_HANDLE_VALUE)
1753345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    watcher_.StartWatching(handle_, this);
1763345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
1773345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1783345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// static
1793345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickbool FilePathWatcherImpl::SetupWatchHandle(const FilePath& dir,
1803345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                           HANDLE* handle) {
1813345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  *handle = FindFirstChangeNotification(
1823345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      dir.value().c_str(),
1833345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      false,  // Don't watch subtrees
1843345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_SIZE |
1853345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_DIR_NAME |
1863345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_SECURITY);
1873345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (*handle != INVALID_HANDLE_VALUE) {
1883345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    // Make sure the handle we got points to an existing directory. It seems
1893345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    // that windows sometimes hands out watches to direectories that are
1903345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    // about to go away, but doesn't sent notifications if that happens.
1913345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    if (!file_util::DirectoryExists(dir)) {
1923345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      FindCloseChangeNotification(*handle);
1933345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      *handle = INVALID_HANDLE_VALUE;
1943345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    }
1953345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    return true;
1963345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
1973345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1983345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // If FindFirstChangeNotification failed because the target directory
1993345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // doesn't exist, access is denied (happens if the file is already gone but
2003345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // there are still handles open), or the target is not a directory, try the
2013345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // immediate parent directory instead.
2023345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  DWORD error_code = GetLastError();
2033345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (error_code != ERROR_FILE_NOT_FOUND &&
2043345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      error_code != ERROR_PATH_NOT_FOUND &&
2053345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      error_code != ERROR_ACCESS_DENIED &&
206731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      error_code != ERROR_SHARING_VIOLATION &&
2073345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      error_code != ERROR_DIRECTORY) {
208ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    using ::operator<<; // Pick the right operator<< below.
2093345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    PLOG(ERROR) << "FindFirstChangeNotification failed for "
2103345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                << dir.value();
2113345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    return false;
2123345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
2133345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
2143345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  return true;
2153345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
2163345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
2173345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickbool FilePathWatcherImpl::UpdateWatch() {
2183345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (handle_ != INVALID_HANDLE_VALUE)
2193345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    DestroyWatch();
2203345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
2213345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  base::PlatformFileInfo file_info;
2223345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (file_util::GetFileInfo(target_, &file_info)) {
2233345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    last_modified_ = file_info.last_modified;
2243345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    first_notification_ = base::Time::Now();
2253345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
2263345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
2273345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Start at the target and walk up the directory chain until we succesfully
2283345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // create a watch handle in |handle_|. |child_dirs| keeps a stack of child
2293345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // directories stripped from target, in reverse order.
2303345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  std::vector<FilePath> child_dirs;
2313345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  FilePath watched_path(target_);
2323345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  while (true) {
2333345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    if (!SetupWatchHandle(watched_path, &handle_))
2343345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      return false;
2353345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
2363345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    // Break if a valid handle is returned. Try the parent directory otherwise.
2373345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    if (handle_ != INVALID_HANDLE_VALUE)
2383345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      break;
2393345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
2403345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    // Abort if we hit the root directory.
2413345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    child_dirs.push_back(watched_path.BaseName());
2423345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    FilePath parent(watched_path.DirName());
2433345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    if (parent == watched_path) {
2443345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      LOG(ERROR) << "Reached the root directory";
2453345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      return false;
2463345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    }
2473345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    watched_path = parent;
2483345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
2493345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
2503345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // At this point, handle_ is valid. However, the bottom-up search that the
2513345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // above code performs races against directory creation. So try to walk back
2523345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // down and see whether any children appeared in the mean time.
2533345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  while (!child_dirs.empty()) {
2543345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    watched_path = watched_path.Append(child_dirs.back());
2553345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    child_dirs.pop_back();
2563345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    HANDLE temp_handle = INVALID_HANDLE_VALUE;
2573345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    if (!SetupWatchHandle(watched_path, &temp_handle))
2583345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      return false;
2593345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    if (temp_handle == INVALID_HANDLE_VALUE)
2603345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      break;
2613345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    FindCloseChangeNotification(handle_);
2623345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    handle_ = temp_handle;
2633345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
2643345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
2653345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  return true;
2663345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
2673345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
2683345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid FilePathWatcherImpl::DestroyWatch() {
2693345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  watcher_.StopWatching();
2703345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  FindCloseChangeNotification(handle_);
2713345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  handle_ = INVALID_HANDLE_VALUE;
2723345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
2733345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
2743345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}  // namespace
2753345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
2763345a6884c488ff3a535c2c9acdd33d74b37e311Iain MerrickFilePathWatcher::FilePathWatcher() {
2773345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  impl_ = new FilePathWatcherImpl();
2783345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
279ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
280ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}  // namespace files
281ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}  // namespace base
282