bug 1156300 - symbolstore.py FixFilenameCase doesn't fix up directory names. r?gps draft
authorTed Mielczarek <ted@mielczarek.org>
Mon, 11 Apr 2016 08:53:42 -0400
changeset 349396 d3161905ed131998eb52e44021e36c9269706436
parent 348895 d9b1a9829c8ee2862955043f28183efa07de3d2b
child 518087 c9efedac5d41516d0313c9d18c9b17044bba55e3
push id15073
push usertmielczarek@mozilla.com
push dateMon, 11 Apr 2016 13:12:44 +0000
reviewersgps
bugs1156300
milestone48.0a1
bug 1156300 - symbolstore.py FixFilenameCase doesn't fix up directory names. r?gps MozReview-Commit-ID: 2nEaouS1oHD
toolkit/crashreporter/tools/symbolstore.py
toolkit/crashreporter/tools/unit-symbolstore.py
--- a/toolkit/crashreporter/tools/symbolstore.py
+++ b/toolkit/crashreporter/tools/symbolstore.py
@@ -744,23 +744,42 @@ class Dumper_Win32(Dumper):
 
         # Use a cached version if we have one.
         if file in self.fixedFilenameCaseCache:
             return self.fixedFilenameCaseCache[file]
 
         result = file
 
         ctypes.windll.kernel32.SetErrorMode(ctypes.c_uint(1))
-        (path, filename) = os.path.split(file)
-        if os.path.isdir(path):
-            lc_filename = filename.lower()
-            for f in os.listdir(path):
-                if f.lower() == lc_filename:
-                    result = os.path.join(path, f)
-                    break
+        if not isinstance(file, unicode):
+            file = unicode(file, sys.getfilesystemencoding())
+        handle = ctypes.windll.kernel32.CreateFileW(file,
+                                                    # GENERIC_READ
+                                                    0x80000000,
+                                                    # FILE_SHARE_READ
+                                                    1,
+                                                    None,
+                                                    # OPEN_EXISTING
+                                                    3,
+                                                    0,
+                                                    None)
+        if handle != -1:
+            size = ctypes.windll.kernel32.GetFinalPathNameByHandleW(handle,
+                                                                    None,
+                                                                    0,
+                                                                    0)
+            buf = ctypes.create_unicode_buffer(size)
+            if ctypes.windll.kernel32.GetFinalPathNameByHandleW(handle,
+                                                                buf,
+                                                                size,
+                                                                0) > 0:
+                # The return value of GetFinalPathNameByHandleW uses the
+                # '\\?\' prefix.
+                result = buf.value.encode(sys.getfilesystemencoding())[4:]
+            ctypes.windll.kernel32.CloseHandle(handle)
 
         # Cache the corrected version to avoid future filesystem hits.
         self.fixedFilenameCaseCache[file] = result
         return result
 
     def CopyDebug(self, file, debug_file, guid, code_file, code_id):
         def compress(path):
             compressed_file = path[:-1] + '_'
--- a/toolkit/crashreporter/tools/unit-symbolstore.py
+++ b/toolkit/crashreporter/tools/unit-symbolstore.py
@@ -59,22 +59,25 @@ class HelperMixin(object):
         symbolstore.srcdirRepoInfo = {}
         symbolstore.vcsFileInfoCache = {}
 
     def tearDown(self):
         shutil.rmtree(self.test_dir)
         symbolstore.srcdirRepoInfo = {}
         symbolstore.vcsFileInfoCache = {}
 
+    def make_dirs(self, f):
+        d = os.path.dirname(f)
+        if d and not os.path.exists(d):
+            os.makedirs(d)
+
     def add_test_files(self, files):
         for f in files:
             f = os.path.join(self.test_dir, f)
-            d = os.path.dirname(f)
-            if d and not os.path.exists(d):
-                os.makedirs(d)
+            self.make_dirs(f)
             writer(f)
 
 class TestSizeOrder(HelperMixin, unittest.TestCase):
     def test_size_order(self):
         """
         Test that files are processed ordered by size on disk.
         """
         processed = []
@@ -283,16 +286,41 @@ class TestRepoManifest(HelperMixin, unit
         self.assertEqual("git:example.com/bar/projects/one:src1.c:abcd1234",
                          symbolstore.GetVCSFilename(file1, d.srcdirs)[0])
         self.assertEqual("git:example.com/foo/projects/two:src2.c:ffffffff",
                          symbolstore.GetVCSFilename(file2, d.srcdirs)[0])
         self.assertEqual("git:example.com/bar/something_else:src3.c:00000000",
                          symbolstore.GetVCSFilename(file3, d.srcdirs)[0])
 
 if platform.system() in ("Windows", "Microsoft"):
+    class TestFixFilenameCase(HelperMixin, unittest.TestCase):
+        def test_fix_filename_case(self):
+            # self.test_dir is going to be 8.3 paths...
+            junk = os.path.join(self.test_dir, 'x')
+            with open(junk, 'wb') as o:
+                o.write('x')
+            d = symbolstore.Dumper_Win32(dump_syms='dump_syms',
+                                         symbol_path=self.test_dir)
+            fixed_dir = os.path.dirname(d.FixFilenameCase(junk))
+            files = [
+                'one\\two.c',
+                'three\\Four.d',
+                'Five\\Six.e',
+                'seven\\Eight\\nine.F',
+            ]
+            for rel_path in files:
+                full_path = os.path.normpath(os.path.join(self.test_dir,
+                                                          rel_path))
+                self.make_dirs(full_path)
+                with open(full_path, 'wb') as o:
+                    o.write('x')
+                fixed_path = d.FixFilenameCase(full_path.lower())
+                fixed_path = os.path.relpath(fixed_path, fixed_dir)
+                self.assertEqual(rel_path, fixed_path)
+
     class TestSourceServer(HelperMixin, unittest.TestCase):
         @patch("subprocess.call")
         @patch("subprocess.Popen")
         def test_HGSERVER(self, mock_Popen, mock_call):
             """
             Test that HGSERVER gets set correctly in the source server index.
             """
             symbolpath = os.path.join(self.test_dir, "symbols")