OLD | NEW |
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "base/file_watcher.h" | 5 #include "chrome/browser/file_watcher.h" |
6 | 6 |
7 #include <errno.h> | 7 #include <errno.h> |
8 #include <string.h> | 8 #include <string.h> |
9 #include <sys/inotify.h> | 9 #include <sys/inotify.h> |
10 #include <sys/ioctl.h> | 10 #include <sys/ioctl.h> |
11 #include <sys/select.h> | 11 #include <sys/select.h> |
12 #include <unistd.h> | 12 #include <unistd.h> |
13 | 13 |
14 #include <algorithm> | 14 #include <algorithm> |
15 #include <set> | 15 #include <set> |
(...skipping 11 matching lines...) Expand all Loading... |
27 #include "base/singleton.h" | 27 #include "base/singleton.h" |
28 #include "base/task.h" | 28 #include "base/task.h" |
29 #include "base/thread.h" | 29 #include "base/thread.h" |
30 #include "base/waitable_event.h" | 30 #include "base/waitable_event.h" |
31 | 31 |
32 namespace { | 32 namespace { |
33 | 33 |
34 class FileWatcherImpl; | 34 class FileWatcherImpl; |
35 | 35 |
36 // Singleton to manage all inotify watches. | 36 // Singleton to manage all inotify watches. |
| 37 // TODO(tony): It would be nice if this wasn't a singleton. |
| 38 // http://crbug.com/38174 |
37 class InotifyReader { | 39 class InotifyReader { |
38 public: | 40 public: |
39 typedef int Watch; // Watch descriptor used by AddWatch and RemoveWatch. | 41 typedef int Watch; // Watch descriptor used by AddWatch and RemoveWatch. |
40 static const Watch kInvalidWatch = -1; | 42 static const Watch kInvalidWatch = -1; |
41 | 43 |
42 // Watch |path| for changes. |watcher| will be notified on each change. | 44 // Watch |path| for changes. |watcher| will be notified on each change. |
43 // Returns kInvalidWatch on failure. | 45 // Returns kInvalidWatch on failure. |
44 Watch AddWatch(const FilePath& path, FileWatcherImpl* watcher); | 46 Watch AddWatch(const FilePath& path, FileWatcherImpl* watcher); |
45 | 47 |
46 // Remove |watch|. Returns true on success. | 48 // Remove |watch|. Returns true on success. |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
81 class FileWatcherImpl : public FileWatcher::PlatformDelegate { | 83 class FileWatcherImpl : public FileWatcher::PlatformDelegate { |
82 public: | 84 public: |
83 FileWatcherImpl(); | 85 FileWatcherImpl(); |
84 ~FileWatcherImpl(); | 86 ~FileWatcherImpl(); |
85 | 87 |
86 // Called for each event coming from the watch. | 88 // Called for each event coming from the watch. |
87 void OnInotifyEvent(const inotify_event* event); | 89 void OnInotifyEvent(const inotify_event* event); |
88 | 90 |
89 // Start watching |path| for changes and notify |delegate| on each change. | 91 // Start watching |path| for changes and notify |delegate| on each change. |
90 // Returns true if watch for |path| has been added successfully. | 92 // Returns true if watch for |path| has been added successfully. |
91 virtual bool Watch(const FilePath& path, FileWatcher::Delegate* delegate, | 93 virtual bool Watch(const FilePath& path, FileWatcher::Delegate* delegate); |
92 MessageLoop* backend_loop); | |
93 | 94 |
94 private: | 95 private: |
95 // Delegate to notify upon changes. | 96 // Delegate to notify upon changes. |
96 FileWatcher::Delegate* delegate_; | 97 FileWatcher::Delegate* delegate_; |
97 | 98 |
98 // Watch returned by InotifyReader. | 99 // Watch returned by InotifyReader. |
99 InotifyReader::Watch watch_; | 100 InotifyReader::Watch watch_; |
100 | 101 |
101 // The file we're watching. | 102 // The file we're watching. |
102 FilePath path_; | 103 FilePath path_; |
103 | 104 |
104 // Loop where we post file change notifications to. | |
105 MessageLoop* loop_; | |
106 | |
107 DISALLOW_COPY_AND_ASSIGN(FileWatcherImpl); | 105 DISALLOW_COPY_AND_ASSIGN(FileWatcherImpl); |
108 }; | 106 }; |
109 | 107 |
110 class FileWatcherImplNotifyTask : public Task { | 108 class FileWatcherImplNotifyTask : public Task { |
111 public: | 109 public: |
112 FileWatcherImplNotifyTask(FileWatcher::Delegate* delegate, | 110 FileWatcherImplNotifyTask(FileWatcher::Delegate* delegate, |
113 const FilePath& path) | 111 const FilePath& path) |
114 : delegate_(delegate), path_(path) { | 112 : delegate_(delegate), path_(path) { |
115 } | 113 } |
116 | 114 |
(...skipping 170 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
287 | 285 |
288 Singleton<InotifyReader>::get()->RemoveWatch(watch_, this); | 286 Singleton<InotifyReader>::get()->RemoveWatch(watch_, this); |
289 } | 287 } |
290 | 288 |
291 void FileWatcherImpl::OnInotifyEvent(const inotify_event* event) { | 289 void FileWatcherImpl::OnInotifyEvent(const inotify_event* event) { |
292 // Since we're watching the directory, filter out inotify events | 290 // Since we're watching the directory, filter out inotify events |
293 // if it's not related to the file we're watching. | 291 // if it's not related to the file we're watching. |
294 if (path_ != path_.DirName().Append(event->name)) | 292 if (path_ != path_.DirName().Append(event->name)) |
295 return; | 293 return; |
296 | 294 |
297 loop_->PostTask(FROM_HERE, | 295 ChromeThread::PostTask(ChromeThread::FILE, FROM_HERE, |
298 new FileWatcherImplNotifyTask(delegate_, path_)); | 296 new FileWatcherImplNotifyTask(delegate_, path_)); |
299 } | 297 } |
300 | 298 |
301 bool FileWatcherImpl::Watch(const FilePath& path, | 299 bool FileWatcherImpl::Watch(const FilePath& path, |
302 FileWatcher::Delegate* delegate, | 300 FileWatcher::Delegate* delegate) { |
303 MessageLoop* backend_loop) { | |
304 // Each FileWatcherImpl can only watch one file. | 301 // Each FileWatcherImpl can only watch one file. |
305 DCHECK(watch_ == InotifyReader::kInvalidWatch); | 302 DCHECK(watch_ == InotifyReader::kInvalidWatch); |
306 | 303 |
307 // It's not possible to watch a file that doesn't exist, so instead, | 304 // It's not possible to watch a file that doesn't exist, so instead, |
308 // watch the parent directory. | 305 // watch the parent directory. |
309 if (!file_util::PathExists(path.DirName())) | 306 if (!file_util::PathExists(path.DirName())) |
310 return false; | 307 return false; |
311 | 308 |
312 delegate_ = delegate; | 309 delegate_ = delegate; |
313 path_ = path; | 310 path_ = path; |
314 loop_ = MessageLoop::current(); | |
315 watch_ = Singleton<InotifyReader>::get()->AddWatch(path.DirName(), this); | 311 watch_ = Singleton<InotifyReader>::get()->AddWatch(path.DirName(), this); |
316 return watch_ != InotifyReader::kInvalidWatch; | 312 return watch_ != InotifyReader::kInvalidWatch; |
317 } | 313 } |
318 | 314 |
319 } // namespace | 315 } // namespace |
320 | 316 |
321 FileWatcher::FileWatcher() { | 317 FileWatcher::FileWatcher() { |
322 impl_ = new FileWatcherImpl(); | 318 impl_ = new FileWatcherImpl(); |
323 } | 319 } |
OLD | NEW |