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
20 namespace extensions {
21
22 // static
PopulateDeviceList(scoped_refptr<StorageDeviceList> device_list)23 bool RemovableStorageProvider::PopulateDeviceList(
24 scoped_refptr<StorageDeviceList> device_list) {
25 base::ThreadRestrictions::AssertIOAllowed();
26 // Match only removable, ejectable, non-internal, whole disks.
27 CFMutableDictionaryRef matching = IOServiceMatching(kIOMediaClass);
28 CFDictionaryAddValue(matching, CFSTR(kIOMediaWholeKey), kCFBooleanTrue);
29 CFDictionaryAddValue(matching, CFSTR(kIOMediaEjectableKey), kCFBooleanTrue);
30 CFDictionaryAddValue(matching, CFSTR(kIOMediaRemovableKey), kCFBooleanTrue);
31 CFDictionaryAddValue(matching, CFSTR(kIOMediaWritableKey), kCFBooleanTrue);
32
33 io_service_t disk_iterator;
34 if (IOServiceGetMatchingServices(
35 kIOMasterPortDefault, matching, &disk_iterator) != KERN_SUCCESS) {
36 LOG(ERROR) << "Unable to get disk services.";
37 return false;
38 }
39 base::mac::ScopedIOObject<io_service_t> iterator_ref(disk_iterator);
40
41 io_object_t disk_obj;
42 while ((disk_obj = IOIteratorNext(disk_iterator))) {
43 base::mac::ScopedIOObject<io_object_t> disk_obj_ref(disk_obj);
44
45 CFMutableDictionaryRef dict;
46 if (IORegistryEntryCreateCFProperties(
47 disk_obj, &dict, kCFAllocatorDefault, 0) != KERN_SUCCESS) {
48 LOG(ERROR) << "Unable to get properties of disk object.";
49 continue;
50 }
51 base::ScopedCFTypeRef<CFMutableDictionaryRef> dict_ref(dict);
52
53 CFStringRef cf_bsd_name = base::mac::GetValueFromDictionary<CFStringRef>(
54 dict, CFSTR(kIOBSDNameKey));
55 std::string bsd_name = base::SysCFStringRefToUTF8(cf_bsd_name);
56
57 CFNumberRef size_number = base::mac::GetValueFromDictionary<CFNumberRef>(
58 dict, CFSTR(kIOMediaSizeKey));
59 uint64 size_in_bytes = 0;
60 if (size_number)
61 CFNumberGetValue(size_number, kCFNumberLongLongType, &size_in_bytes);
62
63 base::ScopedCFTypeRef<CFDictionaryRef> characteristics(
64 static_cast<CFDictionaryRef>(IORegistryEntrySearchCFProperty(
65 disk_obj,
66 kIOServicePlane,
67 CFSTR(kIOPropertyDeviceCharacteristicsKey),
68 kCFAllocatorDefault,
69 kIORegistryIterateParents | kIORegistryIterateRecursively)));
70
71 if (characteristics == NULL) {
72 LOG(ERROR) << "Unable to find device characteristics for " << cf_bsd_name;
73 continue;
74 }
75
76 CFStringRef cf_vendor = base::mac::GetValueFromDictionary<CFStringRef>(
77 characteristics, CFSTR(kIOPropertyVendorNameKey));
78 std::string vendor = base::SysCFStringRefToUTF8(cf_vendor);
79
80 CFStringRef cf_model = base::mac::GetValueFromDictionary<CFStringRef>(
81 characteristics, CFSTR(kIOPropertyProductNameKey));
82 std::string model = base::SysCFStringRefToUTF8(cf_model);
83
84 linked_ptr<api::image_writer_private::RemovableStorageDevice> device(
85 new api::image_writer_private::RemovableStorageDevice());
86 device->storage_unit_id = bsd_name;
87 device->capacity = size_in_bytes;
88 device->vendor = vendor;
89 device->model = model;
90 device_list->data.push_back(device);
91 }
92
93 return true;
94 }
95
96 } // namespace extensions
97