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