Bug 685236 - Stop using GetNativePath in Telemetry.cpp. r?gfritzsche draft
authorMasatoshi Kimura <VYV03354@nifty.ne.jp>
Sat, 16 Dec 2017 22:40:32 +0900
changeset 715696 a027c68063f6e3e45cf38bd6097788f8cc554a3f
parent 715695 2e5f214481fa64000262a8043612fb9c94bd014e
child 715697 2561f64694f0fde3cfeafc54cdbeac3920c9d6bd
push id94228
push userVYV03354@nifty.ne.jp
push dateThu, 04 Jan 2018 11:56:10 +0000
reviewersgfritzsche
bugs685236
milestone59.0a1
Bug 685236 - Stop using GetNativePath in Telemetry.cpp. r?gfritzsche MozReview-Commit-ID: A8CCpfWAf73
toolkit/components/telemetry/Telemetry.cpp
--- a/toolkit/components/telemetry/Telemetry.cpp
+++ b/toolkit/components/telemetry/Telemetry.cpp
@@ -2,16 +2,20 @@
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include <algorithm>
 
 #include <fstream>
+#ifdef __MINGW32__
+#include <fcntl.h>
+#include <ext/stdio_filebuf.h>
+#endif
 
 #include <prio.h>
 #include <prproces.h>
 #ifdef XP_LINUX
 #include <time.h>
 #else
 #include <chrono>
 #endif
@@ -230,19 +234,27 @@ TelemetryImpl::CollectReports(nsIHandleR
 }
 
 void
 InitHistogramRecordingEnabled()
 {
   TelemetryHistogram::InitHistogramRecordingEnabled();
 }
 
+using PathChar = filesystem::Path::value_type;
+using PathCharPtr = const PathChar*;
+using PathString = filesystem::Path::string_type;
+
 static uint32_t
-ReadLastShutdownDuration(const char *filename) {
+ReadLastShutdownDuration(PathCharPtr filename) {
+#ifdef XP_WIN
+  FILE *f = _wfopen(char16ptr_t(filename), L"r");
+#else
   FILE *f = fopen(filename, "r");
+#endif
   if (!f) {
     return 0;
   }
 
   int shutdownTime;
   int r = fscanf(f, "%d\n", &shutdownTime);
   fclose(f);
   if (r != 1) {
@@ -276,29 +288,29 @@ GetFailedProfileLockFile(nsIFile* *aFile
 
   (*aFile)->AppendNative(NS_LITERAL_CSTRING("Telemetry.FailedProfileLocks.txt"));
   return NS_OK;
 }
 
 class nsFetchTelemetryData : public Runnable
 {
 public:
-  nsFetchTelemetryData(const char* aShutdownTimeFilename,
+  nsFetchTelemetryData(PathCharPtr aShutdownTimeFilename,
                        nsIFile* aFailedProfileLockFile,
                        nsIFile* aProfileDir)
     : mozilla::Runnable("nsFetchTelemetryData")
     , mShutdownTimeFilename(aShutdownTimeFilename)
     , mFailedProfileLockFile(aFailedProfileLockFile)
     , mTelemetry(TelemetryImpl::sTelemetry)
     , mProfileDir(aProfileDir)
   {
   }
 
 private:
-  const char* mShutdownTimeFilename;
+  PathCharPtr mShutdownTimeFilename;
   nsCOMPtr<nsIFile> mFailedProfileLockFile;
   RefPtr<TelemetryImpl> mTelemetry;
   nsCOMPtr<nsIFile> mProfileDir;
 
 public:
   void MainThread() {
     mTelemetry->mCachedTelemetryData = true;
     for (unsigned int i = 0, n = mTelemetry->mCallbacks.Count(); i < n; ++i) {
@@ -344,38 +356,34 @@ private:
 
     mFailedProfileLockFile->Remove(false);
     return NS_OK;
   }
 };
 
 static TimeStamp gRecordedShutdownStartTime;
 static bool gAlreadyFreedShutdownTimeFileName = false;
-static char *gRecordedShutdownTimeFileName = nullptr;
+static PathCharPtr gRecordedShutdownTimeFileName = nullptr;
 
-static char *
+static PathCharPtr
 GetShutdownTimeFileName()
 {
   if (gAlreadyFreedShutdownTimeFileName) {
     return nullptr;
   }
 
   if (!gRecordedShutdownTimeFileName) {
     nsCOMPtr<nsIFile> mozFile;
     NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, getter_AddRefs(mozFile));
     if (!mozFile)
       return nullptr;
 
     mozFile->AppendNative(NS_LITERAL_CSTRING("Telemetry.ShutdownTime.txt"));
-    nsAutoCString nativePath;
-    nsresult rv = mozFile->GetNativePath(nativePath);
-    if (!NS_SUCCEEDED(rv))
-      return nullptr;
 
-    gRecordedShutdownTimeFileName = PL_strdup(nativePath.get());
+    gRecordedShutdownTimeFileName = NS_strdup(mozFile->NativePath().get());
   }
 
   return gRecordedShutdownTimeFileName;
 }
 
 NS_IMETHODIMP
 TelemetryImpl::GetLastShutdownDuration(uint32_t *aResult)
 {
@@ -436,17 +444,17 @@ TelemetryImpl::AsyncFetchTelemetryData(n
     do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
   if (!targetThread) {
     mCachedTelemetryData = true;
     aCallback->Complete();
     return NS_OK;
   }
 
   // We have to get the filename from the main thread.
-  const char *shutdownTimeFilename = GetShutdownTimeFileName();
+  PathCharPtr shutdownTimeFilename = GetShutdownTimeFileName();
   if (!shutdownTimeFilename) {
     mCachedTelemetryData = true;
     aCallback->Complete();
     return NS_OK;
   }
 
   nsCOMPtr<nsIFile> profileDir;
   nsresult rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
@@ -967,19 +975,27 @@ IsValidBreakpadId(const std::string &bre
     }
   }
   return true;
 }
 
 // Read a stack from the given file name. In case of any error, aStack is
 // unchanged.
 static void
-ReadStack(const char *aFileName, Telemetry::ProcessedStack &aStack)
+ReadStack(PathCharPtr aFileName, Telemetry::ProcessedStack &aStack)
 {
+#ifdef __MINGW32__
+  int fd = _wopen(static_cast<char16ptr_t>(aFileName), _O_RDONLY | _O_TEXT);
+  __gnu_cxx::stdio_filebuf<char> fb(fd, std::ios::in);
+  std::istream file(&fb);
+#elif defined(XP_WIN)
+  std::ifstream file(static_cast<char16ptr_t>(aFileName));
+#else
   std::ifstream file(aFileName);
+#endif
 
   size_t numModules;
   file >> numModules;
   if (file.fail()) {
     return;
   }
 
   char newline = file.get();
@@ -1041,49 +1057,78 @@ ReadStack(const char *aFileName, Telemet
   }
 
   aStack = stack;
 }
 
 void
 TelemetryImpl::ReadLateWritesStacks(nsIFile* aProfileDir)
 {
-  nsAutoCString nativePath;
-  nsresult rv = aProfileDir->GetNativePath(nativePath);
-  if (NS_FAILED(rv)) {
+#ifdef XP_WIN
+  nsString path = aProfileDir->NativePath();
+
+  WIN32_FIND_DATAW ent;
+  nsAutoString mask(path);
+  mask.AppendLiteral(XPCOM_FILE_PATH_SEPARATOR "*");
+  HANDLE dir = FindFirstFileW(mask.get(), &ent);
+  if (dir == INVALID_HANDLE_VALUE) {
     return;
   }
 
+  const wchar_t *prefix = L"Telemetry.LateWriteFinal-";
+  unsigned int prefixLen = wcslen(prefix);
+  do {
+    if (wcsncmp(prefix, ent.cFileName, prefixLen) != 0) {
+      continue;
+    }
+
+    nsAutoString stackPath(path);
+    stackPath.AppendLiteral(XPCOM_FILE_PATH_SEPARATOR);
+    stackPath += nsDependentString(ent.cFileName);
+
+    Telemetry::ProcessedStack stack;
+    ReadStack(stackPath.get(), stack);
+    if (stack.GetStackSize() != 0) {
+      mLateWritesStacks.AddStack(stack);
+    }
+    // Delete the file so that we don't report it again on the next run.
+    DeleteFileW(stackPath.get());
+  } while (FindNextFileW(dir, &ent));
+  FindClose(dir);
+#else
+  nsCString nativePath = aProfileDir->NativePath();
+
   const char *name = nativePath.get();
   PRDir *dir = PR_OpenDir(name);
   if (!dir) {
     return;
   }
 
   PRDirEntry *ent;
   const char *prefix = "Telemetry.LateWriteFinal-";
   unsigned int prefixLen = strlen(prefix);
   while ((ent = PR_ReadDir(dir, PR_SKIP_NONE))) {
     if (strncmp(prefix, ent->name, prefixLen) != 0) {
       continue;
     }
 
-    nsAutoCString stackNativePath = nativePath;
+    nsAutoCString stackNativePath(nativePath);
     stackNativePath += XPCOM_FILE_PATH_SEPARATOR;
     stackNativePath += nsDependentCString(ent->name);
 
     Telemetry::ProcessedStack stack;
     ReadStack(stackNativePath.get(), stack);
     if (stack.GetStackSize() != 0) {
       mLateWritesStacks.AddStack(stack);
     }
     // Delete the file so that we don't report it again on the next run.
     PR_Delete(stackNativePath.get());
   }
   PR_CloseDir(dir);
+#endif
 }
 
 NS_IMETHODIMP
 TelemetryImpl::GetLateWrites(JSContext *cx, JS::MutableHandle<JS::Value> ret)
 {
   // The user must call AsyncReadTelemetryData first. We return an empty list
   // instead of reporting a failure so that the rest of telemetry can uniformly
   // handle the read not being available yet.
@@ -1861,53 +1906,66 @@ RecordShutdownStartTimeStamp() {
   GetShutdownTimeFileName();
 }
 
 void
 RecordShutdownEndTimeStamp() {
   if (!gRecordedShutdownTimeFileName || gAlreadyFreedShutdownTimeFileName)
     return;
 
-  nsCString name(gRecordedShutdownTimeFileName);
-  PL_strfree(gRecordedShutdownTimeFileName);
+  PathString name(gRecordedShutdownTimeFileName);
+  free(const_cast<PathChar*>(gRecordedShutdownTimeFileName));
   gRecordedShutdownTimeFileName = nullptr;
   gAlreadyFreedShutdownTimeFileName = true;
 
   if (gRecordedShutdownStartTime.IsNull()) {
     // If |CanRecordExtended()| is true before |AsyncFetchTelemetryData| is called and
     // then disabled before shutdown, |RecordShutdownStartTimeStamp| will bail out and
     // we will end up with a null |gRecordedShutdownStartTime| here. This can happen
     // during tests.
     return;
   }
 
-  nsCString tmpName = name;
-  tmpName += ".tmp";
+  PathString tmpName = name;
+  tmpName.AppendLiteral(".tmp");
+#ifdef XP_WIN
+  FILE *f = _wfopen(tmpName.get(), L"w");
+#else
   FILE *f = fopen(tmpName.get(), "w");
+#endif
   if (!f)
     return;
   // On a normal release build this should be called just before
   // calling _exit, but on a debug build or when the user forces a full
   // shutdown this is called as late as possible, so we have to
   // white list this write as write poisoning will be enabled.
   MozillaRegisterDebugFILE(f);
 
   TimeStamp now = TimeStamp::Now();
   MOZ_ASSERT(now >= gRecordedShutdownStartTime);
   TimeDuration diff = now - gRecordedShutdownStartTime;
   uint32_t diff2 = diff.ToMilliseconds();
   int written = fprintf(f, "%d\n", diff2);
   MozillaUnRegisterDebugFILE(f);
   int rv = fclose(f);
   if (written < 0 || rv != 0) {
+#ifdef XP_WIN
+    DeleteFileW(tmpName.get());
+#else
     PR_Delete(tmpName.get());
+#endif
     return;
   }
+#ifdef XP_WIN
+  DeleteFileW(name.get());
+  MoveFileW(tmpName.get(), name.get());
+#else
   PR_Delete(name.get());
   PR_Rename(tmpName.get(), name.get());
+#endif
 }
 
 } // namespace mozilla
 
 
 ////////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////////
 //