Bug 1627805 - Obtain path for the download XML r=agashlin
authorKirk Steuber <ksteuber@mozilla.com>
Tue, 28 Apr 2020 20:50:51 +0000
changeset 526558 8fde1306bba7cf2020fb6b05abc7bee19d0047b8
parent 526557 e78e8f677ca081e8227d304cb994c3d1b5860932
child 526559 772c8a4a58ae59473746d89ce13846b248d11c16
push id37358
push useropoprus@mozilla.com
push dateWed, 29 Apr 2020 03:05:14 +0000
treeherdermozilla-central@6bb8423186c1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersagashlin
bugs1627805
milestone77.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1627805 - Obtain path for the download XML r=agashlin Differential Revision: https://phabricator.services.mozilla.com/D69875
toolkit/components/updateagent/src/update_paths.rs
toolkit/mozapps/update/common/commonupdatedir.cpp
--- a/toolkit/components/updateagent/src/update_paths.rs
+++ b/toolkit/components/updateagent/src/update_paths.rs
@@ -1,24 +1,61 @@
 /* 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 https://mozilla.org/MPL/2.0/. */
 
-use std::{ffi::OsString, path::PathBuf};
+use std::{env::current_exe, ffi::OsString, path::PathBuf};
+use winapi::shared::{
+    minwindef::MAX_PATH,
+    winerror::{FAILED, HRESULT},
+};
+use wio::wide::{FromWide, ToWide};
 
 pub fn get_download_xml() -> Result<OsString, String> {
     let mut update_dir = PathBuf::from(get_update_directory()?);
     update_dir.push("download.xml");
     Ok(update_dir.into_os_string())
 }
 
 pub fn get_install_hash() -> Result<OsString, String> {
     let update_dir = PathBuf::from(get_update_directory()?);
     update_dir
         .file_name()
         .map(|file_name| OsString::from(file_name))
         .ok_or("Couldn't get update directory name".to_string())
 }
 
+#[link(name = "updatecommon", kind = "static")]
+extern "C" {
+    fn get_common_update_directory(install_path: *const u16, result: *mut u16) -> HRESULT;
+}
 pub fn get_update_directory() -> Result<OsString, String> {
-    // TODO: Get the real update directory
-    Ok(OsString::from("C:\\test\\"))
+    let mut binary_path = current_exe()
+        .map_err(|e| format!("Couldn't get executing binary's path: {}", e))?
+        .parent()
+        .ok_or("Couldn't get executing binary's parent directory")?
+        .as_os_str()
+        .to_wide_null();
+    // It looks like Path.as_os_str returns a path without a trailing slash, so this may be
+    // unnecessary. But the documentation does not appear to guarantee the lack of trailing slash.
+    // get_common_update_directory, however, must be given the installation path without a trailing
+    // slash. So remove any trailing path slashes, just to be safe.
+    strip_trailing_path_separators(&mut binary_path);
+
+    let mut buffer: Vec<u16> = Vec::with_capacity(MAX_PATH + 1);
+    let hr = unsafe { get_common_update_directory(binary_path.as_ptr(), buffer.as_mut_ptr()) };
+    if FAILED(hr) {
+        return Err(format!("Failed to get update directory: HRESULT={}", hr));
+    }
+    Ok(unsafe { OsString::from_wide_ptr_null(buffer.as_ptr()) })
 }
+
+fn strip_trailing_path_separators(path: &mut Vec<u16>) {
+    let forward_slash = '/' as u16;
+    let backslash = '\\' as u16;
+    for character in path.iter_mut().rev() {
+        if *character == forward_slash || *character == backslash {
+            *character = 0;
+        } else if *character != 0 {
+            break;
+        }
+    }
+}
--- a/toolkit/mozapps/update/common/commonupdatedir.cpp
+++ b/toolkit/mozapps/update/common/commonupdatedir.cpp
@@ -893,16 +893,33 @@ GetUserUpdateDirectory(const wchar_t* in
                        mozilla::UniquePtr<wchar_t[]>& result) {
   return GetUpdateDirectory(
       installPath, vendor, appName, WhichUpdateDir::UserAppData,
       SetPermissionsOf::BaseDirIfNotExists,  // Arbitrary value
       result);
 }
 
 /**
+ * This is a much more limited version of the GetCommonUpdateDirectory that can
+ * be called from Rust.
+ * The result parameter must be a valid pointer to a buffer of length
+ * MAX_PATH + 1
+ */
+extern "C" HRESULT get_common_update_directory(const wchar_t* installPath,
+                                               wchar_t* result) {
+  mozilla::UniquePtr<wchar_t[]> uniqueResult;
+  HRESULT hr = GetCommonUpdateDirectory(
+      installPath, SetPermissionsOf::BaseDirIfNotExists, uniqueResult);
+  if (FAILED(hr)) {
+    return hr;
+  }
+  return StringCchCopyW(result, MAX_PATH + 1, uniqueResult.get());
+}
+
+/**
  * This is a helper function that does all of the work for
  * GetCommonUpdateDirectory and GetUserUpdateDirectory. It partially exists to
  * prevent callers of GetUserUpdateDirectory from having to pass a useless
  * SetPermissionsOf argument, which will be ignored if whichDir is UserAppData.
  *
  * For information on the parameters and return value, see
  * GetCommonUpdateDirectory.
  */