]> git.ipfire.org Git - thirdparty/grub.git/commitdiff
Workaround windows bug when querying EFI system partition parameters.
authorVladimir Serbinenko <phcoder@gmail.com>
Sat, 14 Dec 2013 22:23:11 +0000 (23:23 +0100)
committerVladimir Serbinenko <phcoder@gmail.com>
Sat, 14 Dec 2013 22:23:11 +0000 (23:23 +0100)
ChangeLog
grub-core/osdep/windows/getroot.c
grub-core/osdep/windows/relpath.c
include/grub/util/windows.h

index ee26842b79eefe138d9b732da4569277d3092678..f66ac253c98db04f3a250bb93261f5c792a5b848 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2013-12-14  Vladimir Serbinenko  <phcoder@gmail.com>
+
+       Workaround windows bug when querying EFI system partition parameters.
+
 2013-12-14  Vladimir Serbinenko  <phcoder@gmail.com>
 
        * grub-core/kern/i386/qemu/init.c (resource): Decrease struct size
index 160e8c92c92f25d0d82f450b49d69077473f88d8..c81372d2260b69eec6b9a473073ce603eb89c97b 100644 (file)
 #define tcsnicmp wcsnicmp
 #endif
 
+TCHAR *
+grub_get_mount_point (const TCHAR *path)
+{
+  const TCHAR *ptr;
+  TCHAR *out;
+  TCHAR letter = 0;
+  size_t allocsize;
+
+  for (ptr = path; *ptr; ptr++);
+  allocsize = (ptr - path + 10) * 2;
+  out = xmalloc (allocsize * sizeof (out[0]));
+
+  /* When pointing to EFI system partition GetVolumePathName fails
+     for ESP root and returns abberant information for everything
+     else. Since GetVolumePathName shouldn't fail for any valid
+     //?/X: we use it as indicator.  */
+  if ((path[0] == '/' || path[0] == '\\')
+      && (path[1] == '/' || path[1] == '\\')
+      && (path[2] == '?' || path[2] == '.')
+      && (path[3] == '/' || path[3] == '\\')
+      && path[4]
+      && (path[5] == ':'))
+    letter = path[4];
+  if (path[0] && path[1] == ':')
+    letter = path[0];
+  if (letter)
+    {
+      TCHAR letterpath[10] = TEXT("\\\\?\\#:");
+      letterpath[4] = letter;
+      if (!GetVolumePathName (letterpath, out, allocsize))
+       {
+         if (path[1] == ':')
+           {
+             out[0] = path[0];
+             out[1] = ':';
+             out[2] = '\0';
+             return out;
+           }
+         memcpy (out, path, sizeof (out[0]) * 6);
+         out[6] = '\0';
+         return out;
+       }
+    }
+
+  if (!GetVolumePathName (path, out, allocsize))
+    {
+      free (out);
+      return NULL;
+    }
+  return out;
+}
+
 char **
 grub_guess_root_devices (const char *dir)
 {
@@ -62,21 +114,17 @@ grub_guess_root_devices (const char *dir)
   TCHAR *dirwindows, *mntpointwindows;
   TCHAR *ptr;
   TCHAR volumename[100];
-  size_t mntpointwindows_sz;
 
   dirwindows = grub_util_get_windows_path (dir);
   if (!dirwindows)
     return 0;
 
-  mntpointwindows_sz = strlen (dir) * 2 + 1;
-  mntpointwindows = xmalloc ((mntpointwindows_sz + 1) * sizeof (mntpointwindows[0]));
+  mntpointwindows = grub_get_mount_point (dirwindows);
 
-  if (!GetVolumePathName (dirwindows,
-                         mntpointwindows,
-                         mntpointwindows_sz))
+  if (!mntpointwindows)
     {
       free (dirwindows);
-      free (mntpointwindows);
+      grub_util_info ("can't get volume path name: %d", (int) GetLastError ());
       return 0;      
     }
 
@@ -98,9 +146,29 @@ grub_guess_root_devices (const char *dir)
                                         volumename,
                                         ARRAY_SIZE (volumename)))
     {
-      free (dirwindows);
-      free (mntpointwindows);
-      return 0;
+      TCHAR letter = 0;
+      if ((mntpointwindows[0] == '/' || mntpointwindows[0] == '\\')
+         && (mntpointwindows[1] == '/' || mntpointwindows[1] == '\\')
+         && (mntpointwindows[2] == '?' || mntpointwindows[2] == '.')
+         && (mntpointwindows[3] == '/' || mntpointwindows[3] == '\\')
+         && mntpointwindows[4]
+         && (mntpointwindows[5] == ':'))
+       letter = mntpointwindows[4];
+      if (mntpointwindows[0] && mntpointwindows[1] == ':')
+       letter = mntpointwindows[0];
+      if (!letter)
+       {
+         free (dirwindows);
+         free (mntpointwindows);
+         return 0;
+       }
+      volumename[0] = '\\';
+      volumename[1] = '\\';
+      volumename[2] = '?';
+      volumename[3] = '\\';
+      volumename[4] = letter;
+      volumename[5] = ':';
+      volumename[6] = '\0';
     }
   os_dev = xmalloc (2 * sizeof (os_dev[0]));
 
index 731cd0ca641ecddea1b127e46efd283d82eef9e3..b9e2cac45a2b079e029d72a01dca4b405d6af002 100644 (file)
@@ -44,8 +44,6 @@ grub_make_system_path_relative_to_its_root (const char *path)
 {
   TCHAR *dirwindows, *mntpointwindows;
   TCHAR *ptr;
-  TCHAR volumename[100];
-  size_t mntpointwindows_sz;
   size_t offset, flen;
   TCHAR *ret;
   char *cret;
@@ -54,12 +52,9 @@ grub_make_system_path_relative_to_its_root (const char *path)
   if (!dirwindows)
     return xstrdup (path);
 
-  mntpointwindows_sz = strlen (path) * 2 + 1;
-  mntpointwindows = xmalloc ((mntpointwindows_sz + 1) * sizeof (mntpointwindows[0]));
+  mntpointwindows = grub_get_mount_point (dirwindows);
 
-  if (!GetVolumePathName (dirwindows,
-                         mntpointwindows,
-                         mntpointwindows_sz))
+  if (!mntpointwindows)
     {
       offset = 0;
       if (dirwindows[0] && dirwindows[1] == ':')
index 2645fccbf6a0fdff6dd126e9ce345c41436a6830..6309483938cdf6e24fe114d1abeaf0864ea35fc3 100644 (file)
@@ -27,4 +27,7 @@ grub_util_get_windows_path (const char *unix_path);
 char *
 grub_util_tchar_to_utf8 (LPCTSTR in);
 
+TCHAR *
+grub_get_mount_point (const TCHAR *path);
+
 #endif