file_path_watcher.h 4.04 KB
Newer Older
gejun's avatar
gejun committed
1 2 3 4 5 6 7 8 9
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// This module provides a way to monitor a file or directory for changes.

#ifndef BASE_FILES_FILE_PATH_WATCHER_H_
#define BASE_FILES_FILE_PATH_WATCHER_H_

10 11 12 13 14 15
#include "butil/base_export.h"
#include "butil/basictypes.h"
#include "butil/callback.h"
#include "butil/files/file_path.h"
#include "butil/memory/ref_counted.h"
#include "butil/message_loop/message_loop_proxy.h"
gejun's avatar
gejun committed
16

17
namespace butil {
gejun's avatar
gejun committed
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32

// This class lets you register interest in changes on a FilePath.
// The callback will get called whenever the file or directory referenced by the
// FilePath is changed, including created or deleted. Due to limitations in the
// underlying OS APIs, FilePathWatcher has slightly different semantics on OS X
// than on Windows or Linux. FilePathWatcher on Linux and Windows will detect
// modifications to files in a watched directory. FilePathWatcher on Mac will
// detect the creation and deletion of files in a watched directory, but will
// not detect modifications to those files. See file_path_watcher_kqueue.cc for
// details.
class BASE_EXPORT FilePathWatcher {
 public:
  // Callback type for Watch(). |path| points to the file that was updated,
  // and |error| is true if the platform specific code detected an error. In
  // that case, the callback won't be invoked again.
33
  typedef butil::Callback<void(const FilePath& path, bool error)> Callback;
gejun's avatar
gejun committed
34 35

  // Used internally to encapsulate different members on different platforms.
36
  class PlatformDelegate : public butil::RefCountedThreadSafe<PlatformDelegate> {
gejun's avatar
gejun committed
37 38 39 40 41 42 43 44 45 46 47 48 49 50
   public:
    PlatformDelegate();

    // Start watching for the given |path| and notify |delegate| about changes.
    virtual bool Watch(const FilePath& path,
                       bool recursive,
                       const Callback& callback) WARN_UNUSED_RESULT = 0;

    // Stop watching. This is called from FilePathWatcher's dtor in order to
    // allow to shut down properly while the object is still alive.
    // It can be called from any thread.
    virtual void Cancel() = 0;

   protected:
51
    friend class butil::RefCountedThreadSafe<PlatformDelegate>;
gejun's avatar
gejun committed
52 53 54 55 56 57 58 59 60
    friend class FilePathWatcher;

    virtual ~PlatformDelegate();

    // Stop watching. This is only called on the thread of the appropriate
    // message loop. Since it can also be called more than once, it should
    // check |is_cancelled()| to avoid duplicate work.
    virtual void CancelOnMessageLoopThread() = 0;

61
    scoped_refptr<butil::MessageLoopProxy> message_loop() const {
gejun's avatar
gejun committed
62 63 64
      return message_loop_;
    }

65
    void set_message_loop(butil::MessageLoopProxy* loop) {
gejun's avatar
gejun committed
66 67 68 69 70 71 72 73 74 75 76 77 78
      message_loop_ = loop;
    }

    // Must be called before the PlatformDelegate is deleted.
    void set_cancelled() {
      cancelled_ = true;
    }

    bool is_cancelled() const {
      return cancelled_;
    }

   private:
79
    scoped_refptr<butil::MessageLoopProxy> message_loop_;
gejun's avatar
gejun committed
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108
    bool cancelled_;
  };

  FilePathWatcher();
  virtual ~FilePathWatcher();

  // A callback that always cleans up the PlatformDelegate, either when executed
  // or when deleted without having been executed at all, as can happen during
  // shutdown.
  static void CancelWatch(const scoped_refptr<PlatformDelegate>& delegate);

  // Returns true if the platform and OS version support recursive watches.
  static bool RecursiveWatchAvailable();

  // Invokes |callback| whenever updates to |path| are detected. This should be
  // called at most once, and from a MessageLoop of TYPE_IO. Set |recursive| to
  // true, to watch |path| and its children. The callback will be invoked on
  // the same loop. Returns true on success.
  //
  // Recursive watch is not supported on all platforms and file systems.
  // Watch() will return false in the case of failure.
  bool Watch(const FilePath& path, bool recursive, const Callback& callback);

 private:
  scoped_refptr<PlatformDelegate> impl_;

  DISALLOW_COPY_AND_ASSIGN(FilePathWatcher);
};

109
}  // namespace butil
gejun's avatar
gejun committed
110 111

#endif  // BASE_FILES_FILE_PATH_WATCHER_H_