1ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Use of this source code is governed by a BSD-style license that can be
3ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// found in the LICENSE file.
4ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
5ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// This module provides a way to monitor a file or directory for changes.
6ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
7ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#ifndef BASE_FILES_FILE_PATH_WATCHER_H_
8ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#define BASE_FILES_FILE_PATH_WATCHER_H_
9ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#pragma once
10ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
11ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/basictypes.h"
12ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/file_path.h"
13ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/memory/ref_counted.h"
14ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/message_loop_proxy.h"
15ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
16ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsennamespace base {
17ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsennamespace files {
18ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
19ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// This class lets you register interest in changes on a FilePath.
20ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// The delegate will get called whenever the file or directory referenced by the
21ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// FilePath is changed, including created or deleted. Due to limitations in the
22ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// underlying OS APIs, FilePathWatcher has slightly different semantics on OS X
23ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// than on Windows or Linux. FilePathWatcher on Linux and Windows will detect
24ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// modifications to files in a watched directory. FilePathWatcher on Mac will
25ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// detect the creation and deletion of files in a watched directory, but will
26ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// not detect modifications to those files. See file_path_watcher_mac.cc for
27ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// details.
28ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenclass FilePathWatcher {
29ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen public:
30ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Declares the callback client code implements to receive notifications. Note
31ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // that implementations of this interface should not keep a reference to the
32ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // corresponding FileWatcher object to prevent a reference cycle.
33ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  class Delegate : public base::RefCountedThreadSafe<Delegate> {
34ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen   public:
35ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    virtual ~Delegate() {}
36ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    virtual void OnFilePathChanged(const FilePath& path) = 0;
37ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // Called when platform specific code detected an error. The watcher will
38ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // not call OnFilePathChanged for future changes.
39ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    virtual void OnFilePathError(const FilePath& path) {}
40ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  };
41ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
42ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  FilePathWatcher();
43ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  ~FilePathWatcher();
44ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
45ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Register interest in any changes on |path|. OnPathChanged will be called
46ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // back for each change. Returns true on success.
47ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // OnFilePathChanged() will be called on the same thread as Watch() is called,
48ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // which should have a MessageLoop of TYPE_IO.
49ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  bool Watch(const FilePath& path, Delegate* delegate) WARN_UNUSED_RESULT;
50ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
51ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  class PlatformDelegate;
52ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
53ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // A custom Task that always cleans up the PlatformDelegate, either when
54ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // executed or when deleted without having been executed at all, as can
55ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // happen during shutdown.
56ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  class CancelTask : public Task {
57ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen   public:
58ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    CancelTask(PlatformDelegate* delegate): delegate_(delegate) {}
59ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    virtual ~CancelTask() {
60ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      delegate_->CancelOnMessageLoopThread();
61ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    }
62ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
63ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    virtual void Run() {
64ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      delegate_->CancelOnMessageLoopThread();
65ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    }
66ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen   private:
67ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    scoped_refptr<PlatformDelegate> delegate_;
68ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
69ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    DISALLOW_COPY_AND_ASSIGN(CancelTask);
70ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  };
71ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
72ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Used internally to encapsulate different members on different platforms.
73ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  class PlatformDelegate : public base::RefCountedThreadSafe<PlatformDelegate> {
74ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen   public:
75ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    PlatformDelegate();
76ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
77ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // Start watching for the given |path| and notify |delegate| about changes.
78ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    virtual bool Watch(const FilePath& path,
79ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                       Delegate* delegate) WARN_UNUSED_RESULT = 0;
80ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
81ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // Stop watching. This is called from FilePathWatcher's dtor in order to
82ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // allow to shut down properly while the object is still alive.
83ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // It can be called from any thread.
84ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    virtual void Cancel() = 0;
85ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
86ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen   protected:
87ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    virtual ~PlatformDelegate();
88ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
89ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // Stop watching. This is only called on the thread of the appropriate
90ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // message loop. Since it can also be called more than once, it should
91ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // check |is_cancelled()| to avoid duplicate work.
92ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    virtual void CancelOnMessageLoopThread() = 0;
93ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
94ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    scoped_refptr<base::MessageLoopProxy> message_loop() const {
95ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      return message_loop_;
96ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    }
97ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
98ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    void set_message_loop(base::MessageLoopProxy* loop) {
99ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      message_loop_ = loop;
100ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    }
101ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
102ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // Must be called before the PlatformDelegate is deleted.
103ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    void set_cancelled() {
104ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      cancelled_ = true;
105ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    }
106ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
107ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    bool is_cancelled() const {
108ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      return cancelled_;
109ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    }
110ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
111ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen   private:
112ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    friend class base::RefCountedThreadSafe<PlatformDelegate>;
113ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    friend class CancelTask;
114ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
115ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    scoped_refptr<base::MessageLoopProxy> message_loop_;
116ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    bool cancelled_;
117ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  };
118ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
119ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen private:
120ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  scoped_refptr<PlatformDelegate> impl_;
121ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
122ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DISALLOW_COPY_AND_ASSIGN(FilePathWatcher);
123ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen};
124ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
125ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}  // namespace files
126ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}  // namespace base
127ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
128ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#endif  // BASE_FILES_FILE_PATH_WATCHER_H_
129