繁体   English   中英

枚举 Linux 和 macOS 上的可移动驱动器

[英]Enumerate removable drives on Linux and macOS

在 Windows 上,我能够使用FindFirstVolumeFindNextVolumeGetVolumePathNamesForVolumeNameGetDriveType函数枚举可移动驱动器。 如何在 Linux 和 macOS 上实现这一点?

在 macOS 上,您需要使用 IOKit: https://developer.apple.com/documentation/iokit

它可能类似于以下代码:

#include <cstdlib>
#include <iostream>

#include <mach/mach_port.h>

#include <IOKit/IOKitLib.h>
#include <IOKit/IOTypes.h>
#include <IOKit/IOKitKeys.h>
#include <IOKit/IOCFPlugIn.h>
#include <IOKit/usb/IOUSBLib.h>


std::string get_descriptor_idx(IOUSBDeviceInterface **dev, UInt8 idx);

int main(int argc, char *argv[]) {
  
  /*
   * Get the IO registry
   */
  auto entry = IORegistryGetRootEntry(kIOMasterPortDefault);
  if (entry == 0)
    return EXIT_FAILURE;
  
  io_iterator_t iter{};
  auto kret = IORegistryEntryCreateIterator(entry, kIOUSBPlane, kIORegistryIterateRecursively, &iter);
  if (kret != KERN_SUCCESS || iter == 0)
    return EXIT_FAILURE;
  
  io_service_t  service {};
  
  std::cout << std::endl;
  
  while ((service = IOIteratorNext(iter))) {
    
    IOCFPlugInInterface  **plug  = nullptr;
    IOUSBDeviceInterface **dev   = nullptr;
    io_string_t            path;
    SInt32                 score = 0;
    IOReturn               ioret;
    
    kret = IOCreatePlugInInterfaceForService(service, kIOUSBDeviceUserClientTypeID, kIOCFPlugInInterfaceID, &plug, &score);
    IOObjectRelease(service);
    if (kret != KERN_SUCCESS || plug == nullptr) {
      continue;
    }
    
    /*
     * USB
     */
    ioret = (*plug)->QueryInterface(plug, CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID),
                                    static_cast<LPVOID *>((void *) &dev));
    (*plug)->Release(plug);
    if (ioret != kIOReturnSuccess || dev == nullptr) {
      continue;
    }
    
    if (IORegistryEntryGetPath(service, kIOServicePlane, path) != KERN_SUCCESS) {
      (*dev)->Release(dev);
      continue;
    }
    
    std::cout << "USB Path: " << path << std::endl;
    UInt8   si;
    UInt16  u16v;
  
    if ((*dev)->GetDeviceVendor(dev, &u16v) == kIOReturnSuccess)
      std::cout << "VID: "<< u16v << std::endl;
  
    if ((*dev)->GetDeviceProduct(dev, &u16v) == kIOReturnSuccess)
      std::cout << "PID: "<< u16v << std::endl;
  
    if ((*dev)->USBGetManufacturerStringIndex(dev, &si) == kIOReturnSuccess) {
      std::cout << "Manufacturer: " << get_descriptor_idx(dev, si) << std::endl;
    }
  
    if ((*dev)->USBGetProductStringIndex(dev, &si) == kIOReturnSuccess) {
      std::cout << "Product: " << get_descriptor_idx(dev, si) << std::endl;
    }
    
    (*dev)->Release(dev);
    
    std::cout << std::endl;
  }
  
  IOObjectRelease(iter);
  
  return 0;
}


/* a quick version */
std::string get_descriptor_idx(IOUSBDeviceInterface **dev, UInt8 idx)
{
  IOUSBDevRequest request;
  IOReturn        ioret;
  char            buffer[4086] = { 0 };
  CFStringRef     cfstr;
  CFIndex         len;
  
  request.bmRequestType = USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBDevice);
  request.bRequest      = kUSBRqGetDescriptor;
  request.wValue        = (kUSBStringDesc << 8) | idx;
  request.wIndex        = 0x409;
  request.wLength       = sizeof(buffer);
  request.pData         = buffer;
  
  ioret = (*dev)->DeviceRequest(dev, &request);
  if (ioret != kIOReturnSuccess)
    return "n/a";
  
  if (request.wLenDone <= 2)
    return "n/a";
  
  cfstr   = CFStringCreateWithBytes(nullptr, (const UInt8 *)buffer+2, request.wLenDone-2, kCFStringEncodingUTF16LE, 0);
  len     = CFStringGetMaximumSizeForEncoding(CFStringGetLength(cfstr), kCFStringEncodingUTF8) + 1;
  if (len < 0) {
    CFRelease(cfstr);
    return "n/a";
  }
  
  std::string str; str.resize(len);
  
  CFStringGetCString(cfstr, str.data(), len, kCFStringEncodingUTF8);
  
  CFRelease(cfstr);
  return str;
}

就我而言,结果是:

USB Path: IOService:/AppleARMPE/arm-io/xxxx/USB2.1 Hub@01100000
VID: 1507
PID: 1552
Manufacturer: GenesysLogic
Product: USB2.1 USB

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM