• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2014 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 // MtabWatcherLinux implementation.
6 
7 #include "components/storage_monitor/mtab_watcher_linux.h"
8 
9 #include <mntent.h>
10 #include <stdio.h>
11 
12 #include "base/bind.h"
13 #include "content/public/browser/browser_thread.h"
14 
15 namespace {
16 
17 // List of file systems we care about.
18 const char* const kKnownFileSystems[] = {
19   "btrfs",
20   "ext2",
21   "ext3",
22   "ext4",
23   "fat",
24   "hfsplus",
25   "iso9660",
26   "msdos",
27   "ntfs",
28   "udf",
29   "vfat",
30 };
31 
32 }  // namespace
33 
34 namespace storage_monitor {
35 
MtabWatcherLinux(const base::FilePath & mtab_path,base::WeakPtr<Delegate> delegate)36 MtabWatcherLinux::MtabWatcherLinux(const base::FilePath& mtab_path,
37                                    base::WeakPtr<Delegate> delegate)
38     : mtab_path_(mtab_path),
39       delegate_(delegate),
40       weak_ptr_factory_(this) {
41   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
42   bool ret = file_watcher_.Watch(
43       mtab_path_, false,
44       base::Bind(&MtabWatcherLinux::OnFilePathChanged,
45                  weak_ptr_factory_.GetWeakPtr()));
46   if (!ret) {
47     LOG(ERROR) << "Adding watch for " << mtab_path_.value() << " failed";
48     return;
49   }
50 
51   ReadMtab();
52 }
53 
~MtabWatcherLinux()54 MtabWatcherLinux::~MtabWatcherLinux() {
55   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
56 }
57 
ReadMtab() const58 void MtabWatcherLinux::ReadMtab() const {
59   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
60 
61   FILE* fp = setmntent(mtab_path_.value().c_str(), "r");
62   if (!fp)
63     return;
64 
65   MountPointDeviceMap device_map;
66   mntent entry;
67   char buf[512];
68 
69   // We return the same device mounted to multiple locations, but hide
70   // devices that have been mounted over.
71   while (getmntent_r(fp, &entry, buf, sizeof(buf))) {
72     // We only care about real file systems.
73     for (size_t i = 0; i < arraysize(kKnownFileSystems); ++i) {
74       if (strcmp(kKnownFileSystems[i], entry.mnt_type) == 0) {
75         device_map[base::FilePath(entry.mnt_dir)] =
76             base::FilePath(entry.mnt_fsname);
77         break;
78       }
79     }
80   }
81   endmntent(fp);
82 
83   content::BrowserThread::PostTask(
84       content::BrowserThread::UI, FROM_HERE,
85       base::Bind(&Delegate::UpdateMtab, delegate_, device_map));
86 }
87 
OnFilePathChanged(const base::FilePath & path,bool error)88 void MtabWatcherLinux::OnFilePathChanged(
89     const base::FilePath& path, bool error) {
90   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
91 
92   if (path != mtab_path_) {
93     // This cannot happen unless FilePathWatcher is buggy. Just ignore this
94     // notification and do nothing.
95     NOTREACHED();
96     return;
97   }
98   if (error) {
99     LOG(ERROR) << "Error watching " << mtab_path_.value();
100     return;
101   }
102 
103   ReadMtab();
104 }
105 
106 }  // namespace storage_monitor
107