Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(74)

Unified Diff: chrome/browser/storage_monitor/removable_device_notifications_linux.cc

Issue 12382005: Rename RemovableDeviceNotifications=>StorageMonitor (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 7 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/storage_monitor/removable_device_notifications_linux.cc
diff --git a/chrome/browser/storage_monitor/removable_device_notifications_linux.cc b/chrome/browser/storage_monitor/removable_device_notifications_linux.cc
deleted file mode 100644
index db6ef69c67d59aeb18271830f24244a9dd3a3ac4..0000000000000000000000000000000000000000
--- a/chrome/browser/storage_monitor/removable_device_notifications_linux.cc
+++ /dev/null
@@ -1,464 +0,0 @@
-// 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.
-
-// RemovableDeviceNotificationsLinux implementation.
-
-#include "chrome/browser/storage_monitor/removable_device_notifications_linux.h"
-
-#include <mntent.h>
-#include <stdio.h>
-
-#include <list>
-
-#include "base/basictypes.h"
-#include "base/bind.h"
-#include "base/files/file_path.h"
-#include "base/metrics/histogram.h"
-#include "base/stl_util.h"
-#include "base/string_util.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/utf_string_conversions.h"
-#include "chrome/browser/storage_monitor/media_device_notifications_utils.h"
-#include "chrome/browser/storage_monitor/media_storage_util.h"
-#include "chrome/browser/storage_monitor/removable_device_constants.h"
-#include "chrome/browser/storage_monitor/udev_util_linux.h"
-
-namespace chrome {
-
-using content::BrowserThread;
-
-namespace {
-
-// List of file systems we care about.
-const char* const kKnownFileSystems[] = {
- "ext2",
- "ext3",
- "ext4",
- "fat",
- "hfsplus",
- "iso9660",
- "msdos",
- "ntfs",
- "udf",
- "vfat",
-};
-
-// udev device property constants.
-const char kBlockSubsystemKey[] = "block";
-const char kDiskDeviceTypeKey[] = "disk";
-const char kFsUUID[] = "ID_FS_UUID";
-const char kLabel[] = "ID_FS_LABEL";
-const char kModel[] = "ID_MODEL";
-const char kModelID[] = "ID_MODEL_ID";
-const char kRemovableSysAttr[] = "removable";
-const char kSerialShort[] = "ID_SERIAL_SHORT";
-const char kSizeSysAttr[] = "size";
-const char kVendor[] = "ID_VENDOR";
-const char kVendorID[] = "ID_VENDOR_ID";
-
-// (mount point, mount device)
-// A mapping from mount point to mount device, as extracted from the mtab
-// file.
-typedef std::map<base::FilePath, base::FilePath> MountPointDeviceMap;
-
-// Reads mtab file entries into |mtab|.
-void ReadMtab(const base::FilePath& mtab_path,
- const std::set<std::string>& interesting_file_systems,
- MountPointDeviceMap* mtab) {
- mtab->clear();
-
- FILE* fp = setmntent(mtab_path.value().c_str(), "r");
- if (!fp)
- return;
-
- mntent entry;
- char buf[512];
-
- // We return the same device mounted to multiple locations, but hide
- // devices that have been mounted over.
- while (getmntent_r(fp, &entry, buf, sizeof(buf))) {
- // We only care about real file systems.
- if (!ContainsKey(interesting_file_systems, entry.mnt_type))
- continue;
-
- (*mtab)[base::FilePath(entry.mnt_dir)] = base::FilePath(entry.mnt_fsname);
- }
- endmntent(fp);
-}
-
-// Construct a device id using label or manufacturer (vendor and model) details.
-std::string MakeDeviceUniqueId(struct udev_device* device) {
- std::string uuid = GetUdevDevicePropertyValue(device, kFsUUID);
- if (!uuid.empty())
- return kFSUniqueIdPrefix + uuid;
-
- // If one of the vendor, model, serial information is missing, its value
- // in the string is empty.
- // Format: VendorModelSerial:VendorInfo:ModelInfo:SerialShortInfo
- // E.g.: VendorModelSerial:Kn:DataTravel_12.10:8000000000006CB02CDB
- std::string vendor = GetUdevDevicePropertyValue(device, kVendorID);
- std::string model = GetUdevDevicePropertyValue(device, kModelID);
- std::string serial_short = GetUdevDevicePropertyValue(device,
- kSerialShort);
- if (vendor.empty() && model.empty() && serial_short.empty())
- return std::string();
-
- return kVendorModelSerialPrefix + vendor + ":" + model + ":" + serial_short;
-}
-
-// Records GetDeviceInfo result, to see how often we fail to get device details.
-void RecordGetDeviceInfoResult(bool result) {
- UMA_HISTOGRAM_BOOLEAN("MediaDeviceNotification.UdevRequestSuccess", result);
-}
-
-// Returns the storage partition size of the device specified by |device_path|.
-// If the requested information is unavailable, returns 0.
-uint64 GetDeviceStorageSize(const base::FilePath& device_path,
- struct udev_device* device) {
- // sysfs provides the device size in units of 512-byte blocks.
- const std::string partition_size = udev_device_get_sysattr_value(
- device, kSizeSysAttr);
-
- // Keep track of device size, to see how often this information is
- // unavailable.
- UMA_HISTOGRAM_BOOLEAN(
- "RemovableDeviceNotificationsLinux.device_partition_size_available",
- !partition_size.empty());
-
- uint64 total_size_in_bytes = 0;
- if (!base::StringToUint64(partition_size, &total_size_in_bytes))
- return 0;
- return (total_size_in_bytes <= kuint64max / 512) ?
- total_size_in_bytes * 512 : 0;
-}
-
-// Constructs the device name from the device properties. If the device details
-// are unavailable, returns an empty string.
-string16 GetDeviceName(struct udev_device* device) {
- std::string device_label = GetUdevDevicePropertyValue(device, kLabel);
- if (!device_label.empty() && IsStringUTF8(device_label))
- return UTF8ToUTF16(device_label);
-
- device_label = GetUdevDevicePropertyValue(device, kFsUUID);
- // Keep track of device uuid, to see how often we receive empty uuid values.
- UMA_HISTOGRAM_BOOLEAN(
- "RemovableDeviceNotificationsLinux.device_file_system_uuid_available",
- !device_label.empty());
-
- const string16 name = GetFullProductName(
- GetUdevDevicePropertyValue(device, kVendor),
- GetUdevDevicePropertyValue(device, kModel));
-
- const string16 device_label_utf16 =
- (!device_label.empty() && IsStringUTF8(device_label)) ?
- UTF8ToUTF16(device_label) : string16();
- if (!name.empty() && !device_label_utf16.empty())
- return device_label_utf16 + ASCIIToUTF16(" ") + name;
- return name.empty() ? device_label_utf16 : name;
-}
-
-// Get the device information using udev library.
-// On success, returns true and fill in |unique_id|, |name|, |removable| and
-// |partition_size_in_bytes|.
-void GetDeviceInfo(const base::FilePath& device_path,
- std::string* unique_id,
- string16* name,
- bool* removable,
- uint64* partition_size_in_bytes) {
- DCHECK(!device_path.empty());
- ScopedUdevObject udev_obj(udev_new());
- if (!udev_obj.get()) {
- RecordGetDeviceInfoResult(false);
- return;
- }
-
- struct stat device_stat;
- if (stat(device_path.value().c_str(), &device_stat) < 0) {
- RecordGetDeviceInfoResult(false);
- return;
- }
-
- char device_type;
- if (S_ISCHR(device_stat.st_mode)) {
- device_type = 'c';
- } else if (S_ISBLK(device_stat.st_mode)) {
- device_type = 'b';
- } else {
- RecordGetDeviceInfoResult(false);
- return; // Not a supported type.
- }
-
- ScopedUdevDeviceObject device(
- udev_device_new_from_devnum(udev_obj, device_type, device_stat.st_rdev));
- if (!device.get()) {
- RecordGetDeviceInfoResult(false);
- return;
- }
-
- if (name)
- *name = GetDeviceName(device);
-
- if (unique_id)
- *unique_id = MakeDeviceUniqueId(device);
-
- if (removable) {
- const char* value = udev_device_get_sysattr_value(device,
- kRemovableSysAttr);
- if (!value) {
- // |parent_device| is owned by |device| and does not need to be cleaned
- // up.
- struct udev_device* parent_device =
- udev_device_get_parent_with_subsystem_devtype(device,
- kBlockSubsystemKey,
- kDiskDeviceTypeKey);
- value = udev_device_get_sysattr_value(parent_device, kRemovableSysAttr);
- }
- *removable = (value && atoi(value) == 1);
- }
-
- if (partition_size_in_bytes)
- *partition_size_in_bytes = GetDeviceStorageSize(device_path, device);
- RecordGetDeviceInfoResult(true);
-}
-
-} // namespace
-
-RemovableDeviceNotificationsLinux::RemovableDeviceNotificationsLinux(
- const base::FilePath& path)
- : initialized_(false),
- mtab_path_(path),
- get_device_info_func_(&GetDeviceInfo) {
-}
-
-RemovableDeviceNotificationsLinux::RemovableDeviceNotificationsLinux(
- const base::FilePath& path,
- GetDeviceInfoFunc get_device_info_func)
- : initialized_(false),
- mtab_path_(path),
- get_device_info_func_(get_device_info_func) {
-}
-
-RemovableDeviceNotificationsLinux::~RemovableDeviceNotificationsLinux() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
-}
-
-void RemovableDeviceNotificationsLinux::Init() {
- DCHECK(!mtab_path_.empty());
-
- // Put |kKnownFileSystems| in std::set to get O(log N) access time.
- for (size_t i = 0; i < arraysize(kKnownFileSystems); ++i)
- known_file_systems_.insert(kKnownFileSystems[i]);
-
- BrowserThread::PostTask(
- BrowserThread::FILE, FROM_HERE,
- base::Bind(&RemovableDeviceNotificationsLinux::InitOnFileThread, this));
-}
-
-bool RemovableDeviceNotificationsLinux::GetStorageInfoForPath(
- const base::FilePath& path,
- StorageInfo* device_info) const {
- if (!path.IsAbsolute())
- return false;
-
- base::FilePath current = path;
- while (!ContainsKey(mount_info_map_, current) && current != current.DirName())
- current = current.DirName();
-
- MountMap::const_iterator mount_info = mount_info_map_.find(current);
- if (mount_info == mount_info_map_.end())
- return false;
-
- if (device_info) {
- device_info->device_id = mount_info->second.device_id;
- device_info->name = mount_info->second.device_name;
- device_info->location = current.value();
- }
- return true;
-}
-
-uint64 RemovableDeviceNotificationsLinux::GetStorageSize(
- const std::string& location) const {
- MountMap::const_iterator mount_info = mount_info_map_.find(
- base::FilePath(location));
- return (mount_info != mount_info_map_.end()) ?
- mount_info->second.partition_size_in_bytes : 0;
-}
-
-void RemovableDeviceNotificationsLinux::OnFilePathChanged(
- const base::FilePath& path,
- bool error) {
- if (path != mtab_path_) {
- // This cannot happen unless FilePathWatcher is buggy. Just ignore this
- // notification and do nothing.
- NOTREACHED();
- return;
- }
- if (error) {
- LOG(ERROR) << "Error watching " << mtab_path_.value();
- return;
- }
-
- UpdateMtab();
-}
-
-RemovableDeviceNotificationsLinux::MountPointInfo::MountPointInfo()
- : partition_size_in_bytes(0) {
-}
-
-void RemovableDeviceNotificationsLinux::InitOnFileThread() {
- DCHECK(!initialized_);
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
- initialized_ = true;
-
- // The callback passed to Watch() has to be unretained. Otherwise
- // RemovableDeviceNotificationsLinux will live longer than expected, and
- // FilePathWatcher will get in trouble at shutdown time.
- bool ret = file_watcher_.Watch(
- mtab_path_, false,
- base::Bind(&RemovableDeviceNotificationsLinux::OnFilePathChanged,
- base::Unretained(this)));
- if (!ret) {
- LOG(ERROR) << "Adding watch for " << mtab_path_.value() << " failed";
- return;
- }
-
- UpdateMtab();
-}
-
-void RemovableDeviceNotificationsLinux::UpdateMtab() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
-
- MountPointDeviceMap new_mtab;
- ReadMtab(mtab_path_, known_file_systems_, &new_mtab);
-
- // Check existing mtab entries for unaccounted mount points.
- // These mount points must have been removed in the new mtab.
- std::list<base::FilePath> mount_points_to_erase;
- std::list<base::FilePath> multiple_mounted_devices_needing_reattachment;
- for (MountMap::const_iterator old_iter = mount_info_map_.begin();
- old_iter != mount_info_map_.end(); ++old_iter) {
- const base::FilePath& mount_point = old_iter->first;
- const base::FilePath& mount_device = old_iter->second.mount_device;
- MountPointDeviceMap::iterator new_iter = new_mtab.find(mount_point);
- // |mount_point| not in |new_mtab| or |mount_device| is no longer mounted at
- // |mount_point|.
- if (new_iter == new_mtab.end() || (new_iter->second != mount_device)) {
- MountPriorityMap::iterator priority =
- mount_priority_map_.find(mount_device);
- DCHECK(priority != mount_priority_map_.end());
- ReferencedMountPoint::const_iterator has_priority =
- priority->second.find(mount_point);
- if (MediaStorageUtil::IsRemovableDevice(old_iter->second.device_id)) {
- DCHECK(has_priority != priority->second.end());
- if (has_priority->second) {
- receiver()->ProcessDetach(old_iter->second.device_id);
- }
- if (priority->second.size() > 1)
- multiple_mounted_devices_needing_reattachment.push_back(mount_device);
- }
- priority->second.erase(mount_point);
- if (priority->second.empty())
- mount_priority_map_.erase(mount_device);
- mount_points_to_erase.push_back(mount_point);
- }
- }
-
- // Erase the |mount_info_map_| entries afterwards. Erasing in the loop above
- // using the iterator is slightly more efficient, but more tricky, since
- // calling std::map::erase() on an iterator invalidates it.
- for (std::list<base::FilePath>::const_iterator it =
- mount_points_to_erase.begin();
- it != mount_points_to_erase.end();
- ++it) {
- mount_info_map_.erase(*it);
- }
-
- // For any multiply mounted device where the mount that we had notified
- // got detached, send a notification of attachment for one of the other
- // mount points.
- for (std::list<base::FilePath>::const_iterator it =
- multiple_mounted_devices_needing_reattachment.begin();
- it != multiple_mounted_devices_needing_reattachment.end();
- ++it) {
- ReferencedMountPoint::iterator first_mount_point_info =
- mount_priority_map_.find(*it)->second.begin();
- const base::FilePath& mount_point = first_mount_point_info->first;
- first_mount_point_info->second = true;
-
- const MountPointInfo& mount_info =
- mount_info_map_.find(mount_point)->second;
- DCHECK(MediaStorageUtil::IsRemovableDevice(mount_info.device_id));
- receiver()->ProcessAttach(StorageInfo(
- mount_info.device_id, mount_info.device_name, mount_point.value()));
- }
-
- // Check new mtab entries against existing ones.
- for (MountPointDeviceMap::iterator new_iter = new_mtab.begin();
- new_iter != new_mtab.end(); ++new_iter) {
- const base::FilePath& mount_point = new_iter->first;
- const base::FilePath& mount_device = new_iter->second;
- MountMap::iterator old_iter = mount_info_map_.find(mount_point);
- if (old_iter == mount_info_map_.end() ||
- old_iter->second.mount_device != mount_device) {
- // New mount point found or an existing mount point found with a new
- // device.
- AddNewMount(mount_device, mount_point);
- }
- }
-}
-
-void RemovableDeviceNotificationsLinux::AddNewMount(
- const base::FilePath& mount_device, const base::FilePath& mount_point) {
- MountPriorityMap::iterator priority =
- mount_priority_map_.find(mount_device);
- if (priority != mount_priority_map_.end()) {
- const base::FilePath& other_mount_point = priority->second.begin()->first;
- priority->second[mount_point] = false;
- mount_info_map_[mount_point] =
- mount_info_map_.find(other_mount_point)->second;
- return;
- }
-
- std::string unique_id;
- string16 name;
- bool removable;
- uint64 partition_size_in_bytes;
- get_device_info_func_(mount_device, &unique_id, &name, &removable,
- &partition_size_in_bytes);
-
- // Keep track of device info details to see how often we get invalid values.
- MediaStorageUtil::RecordDeviceInfoHistogram(true, unique_id, name);
- if (unique_id.empty() || name.empty())
- return;
-
- bool has_dcim = IsMediaDevice(mount_point.value());
- MediaStorageUtil::Type type;
- if (removable) {
- if (has_dcim) {
- type = MediaStorageUtil::REMOVABLE_MASS_STORAGE_WITH_DCIM;
- } else {
- type = MediaStorageUtil::REMOVABLE_MASS_STORAGE_NO_DCIM;
- }
- } else {
- type = MediaStorageUtil::FIXED_MASS_STORAGE;
- }
- std::string device_id = MediaStorageUtil::MakeDeviceId(type, unique_id);
-
- MountPointInfo mount_point_info;
- mount_point_info.mount_device = mount_device;
- mount_point_info.device_id = device_id;
- mount_point_info.device_name = name;
- mount_point_info.partition_size_in_bytes = partition_size_in_bytes;
-
- mount_info_map_[mount_point] = mount_point_info;
- mount_priority_map_[mount_device][mount_point] = removable;
-
- if (removable) {
- receiver()->ProcessAttach(StorageInfo(
- device_id, GetDisplayNameForDevice(partition_size_in_bytes, name),
- mount_point.value()));
- }
-}
-
-} // namespace chrome

Powered by Google App Engine
This is Rietveld 408576698