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