Home | History | Annotate | Download | only in files
      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:
     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.
     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:
     58     CancelTask(PlatformDelegate* delegate): delegate_(delegate) {}
     59     virtual ~CancelTask() {
     60       delegate_->CancelOnMessageLoopThread();
     61     }
     62 
     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 
     94     scoped_refptr<base::MessageLoopProxy> message_loop() const {
     95       return message_loop_;
     96     }
     97 
     98     void set_message_loop(base::MessageLoopProxy* loop) {
     99       message_loop_ = loop;
    100     }
    101 
    102     // Must be called before the PlatformDelegate is deleted.
    103     void set_cancelled() {
    104       cancelled_ = true;
    105     }
    106 
    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