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