| Index: chrome/browser/extensions/api/image_writer_private/removable_storage_provider_win.cc
|
| diff --git a/chrome/browser/extensions/api/image_writer_private/removable_storage_provider_win.cc b/chrome/browser/extensions/api/image_writer_private/removable_storage_provider_win.cc
|
| index d0d9a9f394384794ac4faff730c8e64823f40d8e..cfd232431dc0b9eda5b3fcaca4f9e3876fc2ac51 100644
|
| --- a/chrome/browser/extensions/api/image_writer_private/removable_storage_provider_win.cc
|
| +++ b/chrome/browser/extensions/api/image_writer_private/removable_storage_provider_win.cc
|
| @@ -2,15 +2,202 @@
|
| // Use of this source code is governed by a BSD-style license that can be
|
| // found in the LICENSE file.
|
|
|
| +// devguid requires Windows.h be imported first.
|
| +#include <windows.h>
|
| +#include <setupapi.h>
|
| +#include <winioctl.h>
|
| +
|
| +#include "base/strings/string_util.h"
|
| +#include "base/strings/utf_string_conversions.h"
|
| +#include "base/win/scoped_handle.h"
|
| #include "chrome/browser/extensions/api/image_writer_private/removable_storage_provider.h"
|
|
|
| namespace extensions {
|
|
|
| -void RemovableStorageProvider::GetAllDevices(
|
| - DeviceListReadyCallback callback) {
|
| +namespace {
|
| +
|
| +bool AddDeviceInfo(HANDLE interface_enumerator,
|
| + SP_DEVICE_INTERFACE_DATA* interface_data,
|
| + StorageDeviceList* device_list) {
|
| + // Get the required buffer size by calling with a null output buffer.
|
| + DWORD interface_detail_data_size;
|
| + BOOL status = SetupDiGetDeviceInterfaceDetail(
|
| + interface_enumerator,
|
| + interface_data,
|
| + NULL, // Output buffer.
|
| + 0, // Output buffer size.
|
| + &interface_detail_data_size, // Receives the buffer size.
|
| + NULL); // Optional DEVINFO_DATA.
|
| +
|
| + if (status == FALSE && GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
|
| + PLOG(ERROR) << "SetupDiGetDeviceInterfaceDetail failed";
|
| + return false;
|
| + }
|
| +
|
| +
|
| + scoped_ptr<char[]> interface_detail_data_buffer(
|
| + new char[interface_detail_data_size]);
|
| +
|
| + SP_DEVICE_INTERFACE_DETAIL_DATA* interface_detail_data =
|
| + reinterpret_cast<SP_DEVICE_INTERFACE_DETAIL_DATA*>(
|
| + interface_detail_data_buffer.get());
|
| +
|
| + interface_detail_data->cbSize = sizeof(SP_INTERFACE_DEVICE_DETAIL_DATA);
|
| +
|
| + status = SetupDiGetDeviceInterfaceDetail(
|
| + interface_enumerator,
|
| + interface_data,
|
| + interface_detail_data, // Output struct.
|
| + interface_detail_data_size, // Output struct size.
|
| + NULL, // Receives required size, unneeded.
|
| + NULL); // Optional DEVINFO_Data.
|
| +
|
| + if (status == FALSE) {
|
| + PLOG(ERROR) << "SetupDiGetDeviceInterfaceDetail failed";
|
| + return false;
|
| + }
|
| +
|
| + // Open a handle to the device to send DeviceIoControl messages.
|
| + base::win::ScopedHandle device_handle(CreateFile(
|
| + interface_detail_data->DevicePath,
|
| + // Desired access, which is none as we only need metadata.
|
| + 0,
|
| + // Required to be read + write for devices.
|
| + FILE_SHARE_READ | FILE_SHARE_WRITE,
|
| + NULL, // Optional security attributes.
|
| + OPEN_EXISTING, // Devices already exist.
|
| + 0, // No optional flags.
|
| + NULL)); // No template file.
|
| +
|
| + if (!device_handle) {
|
| + PLOG(ERROR) << "Opening device handle failed.";
|
| + return false;
|
| + }
|
| +
|
| + DISK_GEOMETRY geometry;
|
| + DWORD bytes_returned;
|
| + status = DeviceIoControl(
|
| + device_handle, // Device handle.
|
| + IOCTL_DISK_GET_DRIVE_GEOMETRY, // Flag to request disk size.
|
| + NULL, // Optional additional parameters.
|
| + 0, // Optional parameter size.
|
| + &geometry, // output buffer.
|
| + sizeof(DISK_GEOMETRY), // output size.
|
| + &bytes_returned, // Must be non-null. If overlapped is null,
|
| + // then value is meaningless.
|
| + NULL); // Optional unused overlapped parameter.
|
| +
|
| + if (status == FALSE) {
|
| + PLOG(ERROR) << "DeviceIoControl";
|
| + return false;
|
| + }
|
| +
|
| + ULONGLONG disk_capacity = geometry.Cylinders.QuadPart *
|
| + geometry.TracksPerCylinder *
|
| + geometry.SectorsPerTrack *
|
| + geometry.BytesPerSector;
|
| +
|
| + STORAGE_PROPERTY_QUERY query = STORAGE_PROPERTY_QUERY();
|
| + query.PropertyId = StorageDeviceProperty;
|
| + query.QueryType = PropertyStandardQuery;
|
| +
|
| + scoped_ptr<char[]> output_buf(new char[1024]);
|
| + status = DeviceIoControl(
|
| + device_handle, // Device handle.
|
| + IOCTL_STORAGE_QUERY_PROPERTY, // Flag to request device properties.
|
| + &query, // Query parameters.
|
| + sizeof(STORAGE_PROPERTY_QUERY), // query parameters size.
|
| + output_buf.get(), // output buffer.
|
| + 1024, // Size of buffer.
|
| + &bytes_returned, // Number of bytes returned.
|
| + // Must not be null.
|
| + NULL); // Optional unused overlapped perameter.
|
| +
|
| + if (status == FALSE) {
|
| + PLOG(ERROR) << "Storage property query failed.";
|
| + return false;
|
| + }
|
| +
|
| + STORAGE_DEVICE_DESCRIPTOR* device_descriptor =
|
| + reinterpret_cast<STORAGE_DEVICE_DESCRIPTOR*>(output_buf.get());
|
| +
|
| + if (!device_descriptor->RemovableMedia) {
|
| + // Return true to indicate success but not add anything to the device list.
|
| + return true;
|
| + }
|
| +
|
| + linked_ptr<api::image_writer_private::RemovableStorageDevice> device(
|
| + new api::image_writer_private::RemovableStorageDevice());
|
| + device->capacity = disk_capacity;
|
| +
|
| + base::string16 device_path_16(interface_detail_data->DevicePath);
|
| + device->storage_unit_id = base::UTF16ToUTF8(device_path_16);
|
| +
|
| + if (device_descriptor->VendorIdOffset &&
|
| + output_buf[device_descriptor->VendorIdOffset]) {
|
| + device->vendor.assign(output_buf.get() + device_descriptor->VendorIdOffset);
|
| + }
|
| +
|
| + std::string product_id;
|
| + if (device_descriptor->ProductIdOffset &&
|
| + output_buf[device_descriptor->ProductIdOffset]) {
|
| + device->model.assign(output_buf.get() + device_descriptor->ProductIdOffset);
|
| + }
|
| +
|
| + device_list->data.push_back(device);
|
| +
|
| + return true;
|
| +}
|
| +
|
| +bool PopulateList(StorageDeviceList* device_list) {
|
| + HDEVINFO interface_enumerator = SetupDiGetClassDevs(
|
| + &DiskClassGuid,
|
| + NULL, // Enumerator.
|
| + NULL, // Parent window.
|
| + // Only devices present & interface class.
|
| + (DIGCF_PRESENT | DIGCF_INTERFACEDEVICE));
|
| +
|
| + if (interface_enumerator == INVALID_HANDLE_VALUE) {
|
| + DPLOG(ERROR) << "SetupDiGetClassDevs failed.";
|
| + return false;
|
| + }
|
| +
|
| + DWORD index = 0;
|
| + SP_DEVICE_INTERFACE_DATA interface_data;
|
| + interface_data.cbSize = sizeof(SP_INTERFACE_DEVICE_DATA);
|
| +
|
| + while (SetupDiEnumDeviceInterfaces(
|
| + interface_enumerator,
|
| + NULL, // Device Info data.
|
| + &GUID_DEVINTERFACE_DISK, // Only disk devices.
|
| + index,
|
| + &interface_data)) {
|
| + AddDeviceInfo(interface_enumerator, &interface_data, device_list);
|
| + index++;
|
| + }
|
| +
|
| + DWORD error_code = GetLastError();
|
| +
|
| + if (error_code != ERROR_NO_MORE_ITEMS) {
|
| + PLOG(ERROR) << "SetupDiEnumDeviceInterfaces failed";
|
| + SetupDiDestroyDeviceInfoList(interface_enumerator);
|
| + return false;
|
| + }
|
| +
|
| + SetupDiDestroyDeviceInfoList(interface_enumerator);
|
| + return true;
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +void RemovableStorageProvider::GetAllDevices(DeviceListReadyCallback callback) {
|
| scoped_refptr<StorageDeviceList> device_list(new StorageDeviceList());
|
|
|
| - callback.Run(device_list, false);
|
| + if (PopulateList(device_list.get())) {
|
| + callback.Run(device_list, true);
|
| + } else {
|
| + callback.Run(device_list, false);
|
| + }
|
| }
|
|
|
| } // namespace extensions
|
|
|