]> git.proxmox.com Git - mirror_smartmontools-debian.git/blobdiff - os_win32.cpp
Imported Upstream version 6.4+svn4214
[mirror_smartmontools-debian.git] / os_win32.cpp
index 11b73198a73bb375df0afe9d681e00b79f945144..dae4f66ea46fe5379f0f730185d8c6bedcf1b560 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * os_win32.cpp
  *
- * Home page of code is: http://smartmontools.sourceforge.net
+ * Home page of code is: http://www.smartmontools.org
  *
  * Copyright (C) 2004-15 Christian Franke
  *
 #define strnicmp strncasecmp
 #endif
 
-const char * os_win32_cpp_cvsid = "$Id: os_win32.cpp 4098 2015-05-30 16:37:37Z chrfranke $";
+const char * os_win32_cpp_cvsid = "$Id: os_win32.cpp 4156 2015-10-18 12:20:40Z samm2 $";
 
 /////////////////////////////////////////////////////////////////////////////
 // Windows I/O-controls, some declarations are missing in the include files
@@ -643,60 +643,37 @@ std::string win_smart_interface::get_os_version_str()
   const int vlen = sizeof(vstr)-sizeof(SMARTMONTOOLS_BUILD_HOST);
   assert(vptr == vstr+strlen(vstr) && vptr+vlen+1 == vstr+sizeof(vstr));
 
-  OSVERSIONINFOEXA vi; memset(&vi, 0, sizeof(vi));
+  // Starting with Windows 8.1, GetVersionEx() does no longer report the
+  // actual OS version, see:
+  // http://msdn.microsoft.com/en-us/library/windows/desktop/dn302074.aspx
+
+  // RtlGetVersion() is not affected
+  LONG /*NTSTATUS*/ (WINAPI /*NTAPI*/ * RtlGetVersion_p)(LPOSVERSIONINFOEXW) =
+    (LONG (WINAPI *)(LPOSVERSIONINFOEXW))
+    GetProcAddress(GetModuleHandleA("ntdll.dll"), "RtlGetVersion");
+
+  OSVERSIONINFOEXW vi; memset(&vi, 0, sizeof(vi));
   vi.dwOSVersionInfoSize = sizeof(vi);
-  if (!GetVersionExA((OSVERSIONINFOA *)&vi)) {
-    memset(&vi, 0, sizeof(vi));
-    vi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
-    if (!GetVersionExA((OSVERSIONINFOA *)&vi))
+  if (!RtlGetVersion_p || RtlGetVersion_p(&vi)) {
+    if (!GetVersionExW((OSVERSIONINFOW *)&vi))
       return vstr;
   }
 
   const char * w = 0;
-  if (vi.dwPlatformId == VER_PLATFORM_WIN32_NT) {
-
-    if (vi.dwMajorVersion > 6 || (vi.dwMajorVersion == 6 && vi.dwMinorVersion >= 2)) {
-      // Starting with Windows 8.1 Preview, GetVersionEx() does no longer report the
-      // actual OS version, see:
-      // http://msdn.microsoft.com/en-us/library/windows/desktop/dn302074.aspx
-
-      ULONGLONG major_equal = VerSetConditionMask(0, VER_MAJORVERSION, VER_EQUAL);
-      for (unsigned major = vi.dwMajorVersion; major <= 9; major++) {
-        OSVERSIONINFOEXA vi2; memset(&vi2, 0, sizeof(vi2));
-        vi2.dwOSVersionInfoSize = sizeof(vi2); vi2.dwMajorVersion = major;
-        if (!VerifyVersionInfo(&vi2, VER_MAJORVERSION, major_equal))
-          continue;
-        if (vi.dwMajorVersion < major) {
-          vi.dwMajorVersion = major; vi.dwMinorVersion = 0;
-        }
-
-        ULONGLONG minor_equal = VerSetConditionMask(0, VER_MINORVERSION, VER_EQUAL);
-        for (unsigned minor = vi.dwMinorVersion; minor <= 9; minor++) {
-          memset(&vi2, 0, sizeof(vi2)); vi2.dwOSVersionInfoSize = sizeof(vi2);
-          vi2.dwMinorVersion = minor;
-          if (!VerifyVersionInfo(&vi2, VER_MINORVERSION, minor_equal))
-            continue;
-          vi.dwMinorVersion = minor;
-          break;
-        }
-
-        break;
-      }
-    }
-
-    if (vi.dwMajorVersion <= 0xf && vi.dwMinorVersion <= 0xf) {
-      bool ws = (vi.wProductType <= VER_NT_WORKSTATION);
-      switch (vi.dwMajorVersion << 4 | vi.dwMinorVersion) {
-        case 0x50: w =       "2000";              break;
-        case 0x51: w =       "xp";                break;
-        case 0x52: w = (!GetSystemMetrics(89/*SM_SERVERR2*/)
-                           ? "2003"  : "2003r2"); break;
-        case 0x60: w = (ws ? "vista" : "2008"  ); break;
-        case 0x61: w = (ws ? "win7"  : "2008r2"); break;
-        case 0x62: w = (ws ? "win8"  : "2012"  ); break;
-        case 0x63: w = (ws ? "win8.1": "2012r2"); break;
-        case 0x64: w = (ws ? "win10" : "w10srv"); break;
-      }
+  if (   vi.dwPlatformId == VER_PLATFORM_WIN32_NT
+      && vi.dwMajorVersion <= 0xf && vi.dwMinorVersion <= 0xf) {
+    bool ws = (vi.wProductType <= VER_NT_WORKSTATION);
+    switch (vi.dwMajorVersion << 4 | vi.dwMinorVersion) {
+      case 0x50: w =       "2000";              break;
+      case 0x51: w =       "xp";                break;
+      case 0x52: w = (!GetSystemMetrics(89/*SM_SERVERR2*/)
+                         ? "2003"  : "2003r2"); break;
+      case 0x60: w = (ws ? "vista" : "2008"  ); break;
+      case 0x61: w = (ws ? "win7"  : "2008r2"); break;
+      case 0x62: w = (ws ? "win8"  : "2012"  ); break;
+      case 0x63: w = (ws ? "win8.1": "2012r2"); break;
+      case 0x64: w = (ws ? "w10tp" : "w10tps"); break; //  6.4 = Win 10 Technical Preview
+      case 0xa0: w = (ws ? "win10" : "w10srv"); break; // 10.0 = Win 10 Final
     }
   }
 
@@ -750,7 +727,8 @@ enum win_dev_type { DEV_UNKNOWN = 0, DEV_ATA, DEV_SCSI, DEV_SAT, DEV_USB };
 static win_dev_type get_phy_drive_type(int drive);
 static win_dev_type get_phy_drive_type(int drive, GETVERSIONINPARAMS_EX * ata_version_ex);
 static win_dev_type get_log_drive_type(int drive);
-static bool get_usb_id(int drive, unsigned short & vendor_id,
+static bool get_usb_id(int phydrive, int logdrive,
+                       unsigned short & vendor_id,
                        unsigned short & product_id);
 
 static const char * ata_get_def_options(void);
@@ -807,9 +785,10 @@ static int sdxy_to_phydrive(const char (& xy)[2+1])
   return phydrive;
 }
 
-static win_dev_type get_dev_type(const char * name, int & phydrive)
+static win_dev_type get_dev_type(const char * name, int & phydrive, int & logdrive)
 {
-  phydrive = -1;
+  phydrive = logdrive = -1;
+
   name = skipdev(name);
   if (!strncmp(name, "st", 2))
     return DEV_SCSI;
@@ -818,7 +797,7 @@ static win_dev_type get_dev_type(const char * name, int & phydrive)
   if (!strncmp(name, "tape", 4))
     return DEV_SCSI;
 
-  int logdrive = drive_letter(name);
+  logdrive = drive_letter(name);
   if (logdrive >= 0) {
     win_dev_type type = get_log_drive_type(logdrive);
     return (type != DEV_UNKNOWN ? type : DEV_SCSI);
@@ -830,9 +809,9 @@ static win_dev_type get_dev_type(const char * name, int & phydrive)
     return get_phy_drive_type(phydrive);
   }
 
-  phydrive = -1;
   if (sscanf(name, "pd%d", &phydrive) == 1 && phydrive >= 0)
     return get_phy_drive_type(phydrive);
+
   return DEV_UNKNOWN;
 }
 
@@ -949,8 +928,8 @@ smart_device * win_smart_interface::autodetect_smart_device(const char * name)
   if (str_starts_with(testname, "csmi"))
     return new win_csmi_device(this, name, "");
 
-  int phydrive = -1;
-  win_dev_type type = get_dev_type(name, phydrive);
+  int phydrive = -1, logdrive = -1;
+  win_dev_type type = get_dev_type(name, phydrive, logdrive);
 
   if (type == DEV_ATA)
     return new win_ata_device(this, name, "");
@@ -964,7 +943,7 @@ smart_device * win_smart_interface::autodetect_smart_device(const char * name)
   if (type == DEV_USB) {
     // Get USB bridge ID
     unsigned short vendor_id = 0, product_id = 0;
-    if (!(phydrive >= 0 && get_usb_id(phydrive, vendor_id, product_id))) {
+    if (!get_usb_id(phydrive, logdrive, vendor_id, product_id)) {
       set_err(EINVAL, "Unable to read USB device ID");
       return 0;
     }
@@ -1064,7 +1043,7 @@ bool win_smart_interface::scan_smart_devices(smart_device_list & devlist,
             raid_seen[vers_ex.wControllerId] = true;
             // Add physical drives
             int len = strlen(name);
-            for (int pi = 0; pi < 32; pi++) {
+            for (unsigned int pi = 0; pi < 32; pi++) {
               if (vers_ex.dwDeviceMapEx & (1L << pi)) {
                 snprintf(name+len, sizeof(name)-1-len, ",%u", pi);
                 devlist.push_back( new win_ata_device(this, name, "ata") );
@@ -1098,7 +1077,7 @@ bool win_smart_interface::scan_smart_devices(smart_device_list & devlist,
             // TODO: Use common function for this and autodetect_smart_device()
             // Get USB bridge ID
             unsigned short vendor_id = 0, product_id = 0;
-            if (!get_usb_id(i, vendor_id, product_id))
+            if (!get_usb_id(i, -1, vendor_id, product_id))
               continue;
             // Get type name for this ID
             const char * usbtype = get_usb_dev_type_by_id(vendor_id, product_id);
@@ -2314,8 +2293,10 @@ static bool get_serial_from_wmi(int drive, ata_identify_device * id)
 /////////////////////////////////////////////////////////////////////////////
 // USB ID detection using WMI
 
-// Get USB ID for a physical drive number
-static bool get_usb_id(int drive, unsigned short & vendor_id, unsigned short & product_id)
+// Get USB ID for a physical or logical drive number
+static bool get_usb_id(int phydrive, int logdrive,
+                       unsigned short & vendor_id,
+                       unsigned short & product_id)
 {
   bool debug = (scsi_debugmode > 1);
 
@@ -2327,13 +2308,41 @@ static bool get_usb_id(int drive, unsigned short & vendor_id, unsigned short & p
   }
 
   // Get device name
+  std::string name;
+
   wbem_object wo;
-  if (!ws.query1(wo, "SELECT Model FROM Win32_DiskDrive WHERE DeviceID=\"\\\\\\\\.\\\\PHYSICALDRIVE%d\"", drive))
+  if (0 <= logdrive && logdrive <= 'Z'-'A') {
+    // Drive letter -> Partition info
+    if (!ws.query1(wo, "ASSOCIATORS OF {Win32_LogicalDisk.DeviceID=\"%c:\"} WHERE ResultClass = Win32_DiskPartition",
+                   'A'+logdrive))
+      return false;
+
+    std::string partid = wo.get_str("DeviceID");
+    if (debug)
+      pout("%c: --> \"%s\" -->\n", 'A'+logdrive, partid.c_str());
+
+    // Partition ID -> Physical drive info
+    if (!ws.query1(wo, "ASSOCIATORS OF {Win32_DiskPartition.DeviceID=\"%s\"} WHERE ResultClass = Win32_DiskDrive",
+                   partid.c_str()))
+      return false;
+
+    name = wo.get_str("Model");
+    if (debug)
+      pout("%s --> \"%s\":\n", wo.get_str("DeviceID").c_str(), name.c_str());
+  }
+
+  else if (phydrive >= 0) {
+    // Physical drive number -> Physical drive info
+    if (!ws.query1(wo, "SELECT Model FROM Win32_DiskDrive WHERE DeviceID=\"\\\\\\\\.\\\\PHYSICALDRIVE%d\"", phydrive))
+      return false;
+
+    name = wo.get_str("Model");
+    if (debug)
+      pout("\\.\\\\PHYSICALDRIVE%d --> \"%s\":\n", phydrive, name.c_str());
+  }
+  else
     return false;
 
-  std::string name = wo.get_str("Model");
-  if (debug)
-    pout("PhysicalDrive%d, \"%s\":\n", drive, name.c_str());
 
   // Get USB_CONTROLLER -> DEVICE associations
   wbem_enumerator we;
@@ -2376,10 +2385,9 @@ static bool get_usb_id(int drive, unsigned short & vendor_id, unsigned short & p
       prev_usb_ant = ant;
       if (debug)
         pout("  +-> \"%s\" [0x%04x:0x%04x]\n", devid.c_str(), prev_usb_venid, prev_usb_proid);
-      continue;
     }
-    else if (str_starts_with(devid, "USBSTOR\\\\")) {
-      // USBSTOR device found
+    else if (str_starts_with(devid, "USBSTOR\\\\") || str_starts_with(devid, "SCSI\\\\")) {
+      // USBSTORage or SCSI device found
       if (debug)
         pout("  +--> \"%s\"\n", devid.c_str());
 
@@ -2643,7 +2651,6 @@ bool win_ata_device::open(int phydrive, int logdrive, const char * options, int
       close();
       return set_err(ENOSYS);
     }
-    devmap = 0x0f;
   }
   m_smartver_state = 1;
 
@@ -2896,9 +2903,10 @@ bool win_ata_device::ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out)
         break;
       case 'f':
         if (in.in_regs.command == ATA_IDENTIFY_DEVICE) {
-            rc = get_identify_from_device_property(get_fh(), (ata_identify_device *)data);
+            ata_identify_device * id = reinterpret_cast<ata_identify_device *>(data);
+            rc = get_identify_from_device_property(get_fh(), id);
             if (rc == 0 && m_phydrive >= 0)
-              get_serial_from_wmi(m_phydrive, (ata_identify_device *)data);
+              get_serial_from_wmi(m_phydrive, id);
             id_is_cached = true;
         }
         else if (in.in_regs.command == ATA_SMART_CMD) switch (in.in_regs.features) {
@@ -3889,10 +3897,8 @@ bool win_areca_ata_device::open()
 
 smart_device * win_areca_ata_device::autodetect_open()
 {
-  int is_ata = 1;
-
   // autodetect device type
-  is_ata = arcmsr_get_dev_type();
+  int is_ata = arcmsr_get_dev_type();
   if(is_ata < 0)
   {
     set_err(EIO);