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 "chrome/browser/extensions/api/image_writer_private/removable_storage_provider.h" 6 7#include <CoreFoundation/CoreFoundation.h> 8#include <IOKit/storage/IOBlockStorageDevice.h> 9#include <IOKit/IOBSD.h> 10#include <IOKit/IOKitLib.h> 11#include <IOKit/storage/IOMedia.h> 12#include <IOKit/storage/IOStorageProtocolCharacteristics.h> 13 14#include "base/mac/foundation_util.h" 15#include "base/mac/scoped_cftyperef.h" 16#include "base/mac/scoped_ioobject.h" 17#include "base/strings/sys_string_conversions.h" 18#include "base/threading/thread_restrictions.h" 19#include "chrome/common/extensions/image_writer/image_writer_util_mac.h" 20 21namespace extensions { 22 23// static 24bool RemovableStorageProvider::PopulateDeviceList( 25 scoped_refptr<StorageDeviceList> device_list) { 26 base::ThreadRestrictions::AssertIOAllowed(); 27 // Match only writable whole-disks. 28 CFMutableDictionaryRef matching = IOServiceMatching(kIOMediaClass); 29 CFDictionaryAddValue(matching, CFSTR(kIOMediaWholeKey), kCFBooleanTrue); 30 CFDictionaryAddValue(matching, CFSTR(kIOMediaWritableKey), kCFBooleanTrue); 31 32 io_service_t disk_iterator; 33 if (IOServiceGetMatchingServices( 34 kIOMasterPortDefault, matching, &disk_iterator) != KERN_SUCCESS) { 35 LOG(ERROR) << "Unable to get disk services."; 36 return false; 37 } 38 base::mac::ScopedIOObject<io_service_t> iterator_ref(disk_iterator); 39 40 io_object_t disk_obj; 41 while ((disk_obj = IOIteratorNext(disk_iterator))) { 42 base::mac::ScopedIOObject<io_object_t> disk_obj_ref(disk_obj); 43 44 CFMutableDictionaryRef dict; 45 if (IORegistryEntryCreateCFProperties( 46 disk_obj, &dict, kCFAllocatorDefault, 0) != KERN_SUCCESS) { 47 LOG(ERROR) << "Unable to get properties of disk object."; 48 continue; 49 } 50 base::ScopedCFTypeRef<CFMutableDictionaryRef> dict_ref(dict); 51 52 CFStringRef cf_bsd_name = base::mac::GetValueFromDictionary<CFStringRef>( 53 dict, CFSTR(kIOBSDNameKey)); 54 std::string bsd_name = base::SysCFStringRefToUTF8(cf_bsd_name); 55 56 CFNumberRef size_number = base::mac::GetValueFromDictionary<CFNumberRef>( 57 dict, CFSTR(kIOMediaSizeKey)); 58 uint64 size_in_bytes = 0; 59 if (size_number) 60 CFNumberGetValue(size_number, kCFNumberLongLongType, &size_in_bytes); 61 62 CFBooleanRef cf_removable = base::mac::GetValueFromDictionary<CFBooleanRef>( 63 dict, CFSTR(kIOMediaRemovableKey)); 64 bool removable = CFBooleanGetValue(cf_removable); 65 66 bool is_usb = IsUsbDevice(disk_obj); 67 68 if (!removable && !is_usb) { 69 continue; 70 } 71 72 base::ScopedCFTypeRef<CFDictionaryRef> characteristics( 73 static_cast<CFDictionaryRef>(IORegistryEntrySearchCFProperty( 74 disk_obj, 75 kIOServicePlane, 76 CFSTR(kIOPropertyDeviceCharacteristicsKey), 77 kCFAllocatorDefault, 78 kIORegistryIterateParents | kIORegistryIterateRecursively))); 79 80 if (characteristics == NULL) { 81 LOG(ERROR) << "Unable to find device characteristics for " << cf_bsd_name; 82 continue; 83 } 84 85 CFStringRef cf_vendor = base::mac::GetValueFromDictionary<CFStringRef>( 86 characteristics, CFSTR(kIOPropertyVendorNameKey)); 87 std::string vendor = base::SysCFStringRefToUTF8(cf_vendor); 88 89 CFStringRef cf_model = base::mac::GetValueFromDictionary<CFStringRef>( 90 characteristics, CFSTR(kIOPropertyProductNameKey)); 91 std::string model = base::SysCFStringRefToUTF8(cf_model); 92 93 linked_ptr<api::image_writer_private::RemovableStorageDevice> device( 94 new api::image_writer_private::RemovableStorageDevice()); 95 device->storage_unit_id = bsd_name; 96 device->capacity = size_in_bytes; 97 device->vendor = vendor; 98 device->model = model; 99 device->removable = removable; 100 device_list->data.push_back(device); 101 } 102 103 return true; 104} 105 106} // namespace extensions 107