1 // Copyright 2013 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 #include <libudev.h> 6 7 #include "base/files/file_util.h" 8 #include "base/strings/string_number_conversions.h" 9 #include "chrome/browser/extensions/api/image_writer_private/removable_storage_provider.h" 10 #include "content/public/browser/browser_thread.h" 11 12 namespace extensions { 13 // TODO(haven): Udev code may be duplicated in the Chrome codebase. 14 // https://code.google.com/p/chromium/issues/detail?id=284898 15 16 // Returns the integer contained in |attr|. Returns 0 on error. 17 static uint64 get_int_attr(const char* attr){ 18 uint64 result = 0; 19 // In error cases, StringToInt will set result to 0 20 base::StringToUint64(attr, &result); 21 return result; 22 } 23 24 static int get_device_blk_size(const std::string& path) { 25 base::FilePath file_path(path); 26 std::string device = file_path.BaseName().value(); 27 28 base::FilePath info_file_path = base::FilePath("/sys/block") 29 .Append(device) 30 .Append("queue/logical_block_size"); 31 32 std::string file_contents; 33 int blk_size; 34 35 if (!base::ReadFileToString(info_file_path, &file_contents)) { 36 return 0; 37 } 38 // In error cases, StringToInt will set blk_size to 0 39 base::StringToInt(file_contents, &blk_size); 40 41 return blk_size; 42 } 43 44 bool RemovableStorageProvider::PopulateDeviceList( 45 scoped_refptr<StorageDeviceList> device_list) { 46 struct udev* udev; 47 struct udev_enumerate* enumerate; 48 struct udev_list_entry* devices, *dev_list_entry; 49 struct udev_device* dev, *parent; 50 51 udev = udev_new(); 52 if (!udev) { 53 DLOG(ERROR) << "Can't create udev"; 54 return false; 55 } 56 57 /* Create a list of the devices in the 'block' subsystem. */ 58 enumerate = udev_enumerate_new(udev); 59 60 udev_enumerate_add_match_subsystem(enumerate, "block"); 61 udev_enumerate_scan_devices(enumerate); 62 devices = udev_enumerate_get_list_entry(enumerate); 63 64 udev_list_entry_foreach(dev_list_entry, devices) { 65 const char* path = udev_list_entry_get_name(dev_list_entry); 66 dev = udev_device_new_from_syspath(udev, path); 67 68 const char* partition = udev_device_get_sysattr_value(dev, "partition"); 69 if (partition && get_int_attr(partition)){ 70 // This is a partition of a device, not the device itself 71 continue; 72 } 73 74 const char* removable = udev_device_get_sysattr_value(dev, "removable"); 75 if (!removable || !get_int_attr(removable)) { 76 // This is not a removable storage device. 77 continue; 78 } 79 80 /* Get the parent SCSI device that contains the model 81 and manufacturer. You can look at the hierarchy with 82 udevadm info -a -n /dev/<device> */ 83 parent = udev_device_get_parent_with_subsystem_devtype( 84 dev, 85 "scsi", 86 NULL); 87 if (!parent) { 88 // this is not a usb device 89 continue; 90 } 91 92 linked_ptr<api::image_writer_private::RemovableStorageDevice> device( 93 new api::image_writer_private::RemovableStorageDevice()); 94 device->vendor = udev_device_get_sysattr_value(parent, "vendor"); 95 device->model = udev_device_get_sysattr_value(parent, "model"); 96 // TODO (smaskell): Don't expose raw device path 97 device->storage_unit_id = udev_device_get_devnode(dev); 98 device->capacity = get_int_attr(udev_device_get_sysattr_value(dev, "size")) 99 * get_device_blk_size(device->storage_unit_id); 100 device->removable = removable; 101 102 device_list->data.push_back(device); 103 104 udev_device_unref(dev); 105 } 106 /* Free the enumerator object */ 107 udev_enumerate_unref(enumerate); 108 udev_unref(udev); 109 110 return true; 111 } 112 113 } // namespace extensions 114