158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved.
258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// found in the LICENSE file.
458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
55d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// devguid requires Windows.h be imported first.
65d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <windows.h>
75d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <setupapi.h>
85d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <winioctl.h>
95d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
10116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "base/strings/string_number_conversions.h"
115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/strings/string_util.h"
125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/strings/utf_string_conversions.h"
135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/win/scoped_handle.h"
14d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "chrome/browser/extensions/api/image_writer_private/removable_storage_provider.h"
1558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
1658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)namespace extensions {
1758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)namespace {
195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool AddDeviceInfo(HANDLE interface_enumerator,
215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                   SP_DEVICE_INTERFACE_DATA* interface_data,
22cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                   scoped_refptr<StorageDeviceList> device_list) {
235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Get the required buffer size by calling with a null output buffer.
245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DWORD interface_detail_data_size;
255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  BOOL status = SetupDiGetDeviceInterfaceDetail(
265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      interface_enumerator,
275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      interface_data,
285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      NULL,                         // Output buffer.
295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      0,                            // Output buffer size.
305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      &interface_detail_data_size,  // Receives the buffer size.
315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      NULL);                        // Optional DEVINFO_DATA.
325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (status == FALSE && GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    PLOG(ERROR) << "SetupDiGetDeviceInterfaceDetail failed";
355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return false;
365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_ptr<char[]> interface_detail_data_buffer(
395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      new char[interface_detail_data_size]);
405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  SP_DEVICE_INTERFACE_DETAIL_DATA* interface_detail_data =
425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      reinterpret_cast<SP_DEVICE_INTERFACE_DETAIL_DATA*>(
435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          interface_detail_data_buffer.get());
445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  interface_detail_data->cbSize = sizeof(SP_INTERFACE_DEVICE_DETAIL_DATA);
465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  status = SetupDiGetDeviceInterfaceDetail(
485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      interface_enumerator,
495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      interface_data,
505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      interface_detail_data, // Output struct.
515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      interface_detail_data_size,  // Output struct size.
525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      NULL,                        // Receives required size, unneeded.
535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      NULL);                       // Optional DEVINFO_Data.
545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (status == FALSE) {
565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    PLOG(ERROR) << "SetupDiGetDeviceInterfaceDetail failed";
575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return false;
585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Open a handle to the device to send DeviceIoControl messages.
615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::win::ScopedHandle device_handle(CreateFile(
625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      interface_detail_data->DevicePath,
635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      // Desired access, which is none as we only need metadata.
645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      0,
655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      // Required to be read + write for devices.
665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      FILE_SHARE_READ | FILE_SHARE_WRITE,
675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      NULL,           // Optional security attributes.
685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      OPEN_EXISTING,  // Devices already exist.
695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      0,              // No optional flags.
705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      NULL));          // No template file.
715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (!device_handle.IsValid()) {
735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    PLOG(ERROR) << "Opening device handle failed.";
745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return false;
755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DISK_GEOMETRY geometry;
785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DWORD bytes_returned;
795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  status = DeviceIoControl(
801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      device_handle.Get(),           // Device handle.
815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      IOCTL_DISK_GET_DRIVE_GEOMETRY, // Flag to request disk size.
825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      NULL,                          // Optional additional parameters.
835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      0,                             // Optional parameter size.
845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      &geometry,                     // output buffer.
855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      sizeof(DISK_GEOMETRY),         // output size.
865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      &bytes_returned,               // Must be non-null. If overlapped is null,
875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                     // then value is meaningless.
885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      NULL);                         // Optional unused overlapped parameter.
895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (status == FALSE) {
915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    PLOG(ERROR) << "DeviceIoControl";
925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return false;
935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ULONGLONG disk_capacity = geometry.Cylinders.QuadPart *
965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    geometry.TracksPerCylinder *
975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    geometry.SectorsPerTrack *
985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    geometry.BytesPerSector;
995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  STORAGE_PROPERTY_QUERY query = STORAGE_PROPERTY_QUERY();
1015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  query.PropertyId = StorageDeviceProperty;
1025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  query.QueryType = PropertyStandardQuery;
1035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_ptr<char[]> output_buf(new char[1024]);
1055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  status = DeviceIoControl(
1061320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      device_handle.Get(),            // Device handle.
1075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      IOCTL_STORAGE_QUERY_PROPERTY,   // Flag to request device properties.
1085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      &query,                         // Query parameters.
1095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      sizeof(STORAGE_PROPERTY_QUERY), // query parameters size.
1105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      output_buf.get(),               // output buffer.
1115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      1024,                           // Size of buffer.
1125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      &bytes_returned,                // Number of bytes returned.
1135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                      // Must not be null.
1145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      NULL);                          // Optional unused overlapped perameter.
1155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (status == FALSE) {
1175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    PLOG(ERROR) << "Storage property query failed.";
1185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return false;
1195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  STORAGE_DEVICE_DESCRIPTOR* device_descriptor =
1225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      reinterpret_cast<STORAGE_DEVICE_DESCRIPTOR*>(output_buf.get());
1235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
124116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (!device_descriptor->RemovableMedia &&
125116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      !(device_descriptor->BusType == BusTypeUsb)) {
126116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    // Reject non-removable and non-USB devices.
1275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // Return true to indicate success but not add anything to the device list.
1285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return true;
1295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
131116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // Create a drive identifier from the drive number.
132116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  STORAGE_DEVICE_NUMBER device_number = {0};
133116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  status = DeviceIoControl(
1341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      device_handle.Get(),            // Device handle.
135116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      IOCTL_STORAGE_GET_DEVICE_NUMBER,// Flag to request device number.
136116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      NULL,                           // Query parameters, should be NULL.
137116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      0,                              // Query parameters size, should be 0.
138116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      &device_number,                 // output buffer.
139116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      sizeof(device_number),          // Size of buffer.
140116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      &bytes_returned,                // Number of bytes returned.
141116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      NULL);                          // Optional unused overlapped perameter.
142116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
143116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (status == FALSE) {
144116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    PLOG(ERROR) << "Storage device number query failed.";
145116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return false;
146116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
147116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
148116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  std::string drive_id = "\\\\.\\PhysicalDrive";
149116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  drive_id.append(base::Uint64ToString(device_number.DeviceNumber));
150116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
1515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  linked_ptr<api::image_writer_private::RemovableStorageDevice> device(
1525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    new api::image_writer_private::RemovableStorageDevice());
1535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  device->capacity = disk_capacity;
154116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  device->storage_unit_id = drive_id;
1556e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  device->removable = device_descriptor->RemovableMedia == TRUE;
1565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (device_descriptor->VendorIdOffset &&
1585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      output_buf[device_descriptor->VendorIdOffset]) {
1595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    device->vendor.assign(output_buf.get() + device_descriptor->VendorIdOffset);
1605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string product_id;
1635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (device_descriptor->ProductIdOffset &&
1645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      output_buf[device_descriptor->ProductIdOffset]) {
1655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    device->model.assign(output_buf.get() + device_descriptor->ProductIdOffset);
1665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  device_list->data.push_back(device);
1695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return true;
1715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
173cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}  // namespace
174cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
175cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)bool RemovableStorageProvider::PopulateDeviceList(
176cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    scoped_refptr<StorageDeviceList> device_list) {
1775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  HDEVINFO interface_enumerator = SetupDiGetClassDevs(
1785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      &DiskClassGuid,
1795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      NULL, // Enumerator.
1805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      NULL, // Parent window.
1815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      // Only devices present & interface class.
1825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      (DIGCF_PRESENT | DIGCF_INTERFACEDEVICE));
1835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (interface_enumerator == INVALID_HANDLE_VALUE) {
1855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DPLOG(ERROR) << "SetupDiGetClassDevs failed.";
1865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return false;
1875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DWORD index = 0;
1905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  SP_DEVICE_INTERFACE_DATA interface_data;
1915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  interface_data.cbSize = sizeof(SP_INTERFACE_DEVICE_DATA);
1925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  while (SetupDiEnumDeviceInterfaces(
1945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      interface_enumerator,
1955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      NULL,                    // Device Info data.
1965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      &GUID_DEVINTERFACE_DISK, // Only disk devices.
1975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      index,
1985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      &interface_data)) {
1995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    AddDeviceInfo(interface_enumerator, &interface_data, device_list);
2005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    index++;
2015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DWORD error_code = GetLastError();
2045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (error_code != ERROR_NO_MORE_ITEMS) {
2065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    PLOG(ERROR) << "SetupDiEnumDeviceInterfaces failed";
2075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    SetupDiDestroyDeviceInfoList(interface_enumerator);
2085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return false;
2095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  SetupDiDestroyDeviceInfoList(interface_enumerator);
2125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return true;
2135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
21558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)} // namespace extensions
216