Home | History | Annotate | Download | only in storage_monitor
      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 
     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 
     54 MtabWatcherLinux::~MtabWatcherLinux() {
     55   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
     56 }
     57 
     58 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 
     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