fix(updater): fallback if tmp is on different mount point, closes #4500 (#4504)

This commit is contained in:
Lucas Fernandes Nogueira
2022-06-28 08:20:59 -07:00
committed by GitHub
parent f6edc6df29
commit fd125f76d7
3 changed files with 75 additions and 55 deletions

View File

@@ -0,0 +1,5 @@
---
"tauri": patch
---
Adjust the updater to fallback to `$HOME/.cache` or the current working directory as temp directory if the system default is in a different mount point.

View File

@@ -3,7 +3,6 @@
// SPDX-License-Identifier: MIT
use super::error::{Error, Result};
#[cfg(feature = "updater")]
use crate::api::file::{ArchiveFormat, Extract, Move};
use crate::{
api::http::{ClientBuilder, HttpRequestBuilder},
@@ -21,7 +20,6 @@ use tauri_utils::{platform::current_exe, Env};
use time::OffsetDateTime;
use url::Url;
#[cfg(feature = "updater")]
use std::io::Seek;
use std::{
collections::HashMap,
@@ -33,7 +31,6 @@ use std::{
time::Duration,
};
#[cfg(feature = "updater")]
#[cfg(not(target_os = "macos"))]
use std::ffi::OsStr;
@@ -602,29 +599,27 @@ impl<R: Runtime> Update<R> {
// if there is no signature, bail out.
verify_signature(&mut archive_buffer, &self.signature, &pub_key)?;
#[cfg(feature = "updater")]
{
// we copy the files depending of the operating system
// we run the setup, appimage re-install or overwrite the
// macos .app
#[cfg(target_os = "windows")]
copy_files_and_run(
archive_buffer,
&self.extract_path,
self.with_elevated_task,
self
.app
.config()
.tauri
.updater
.windows
.install_mode
.clone()
.msiexec_args(),
)?;
#[cfg(not(target_os = "windows"))]
copy_files_and_run(archive_buffer, &self.extract_path)?;
}
// we copy the files depending of the operating system
// we run the setup, appimage re-install or overwrite the
// macos .app
#[cfg(target_os = "windows")]
copy_files_and_run(
archive_buffer,
&self.extract_path,
self.with_elevated_task,
self
.app
.config()
.tauri
.updater
.windows
.install_mode
.clone()
.msiexec_args(),
)?;
#[cfg(not(target_os = "windows"))]
copy_files_and_run(archive_buffer, &self.extract_path)?;
// We are done!
Ok(())
}
@@ -640,42 +635,60 @@ impl<R: Runtime> Update<R> {
// We should have an AppImage already installed to be able to copy and install
// the extract_path is the current AppImage path
// tmp_dir is where our new AppImage is found
#[cfg(feature = "updater")]
#[cfg(target_os = "linux")]
fn copy_files_and_run<R: Read + Seek>(archive_buffer: R, extract_path: &Path) -> Result {
use std::os::unix::fs::PermissionsExt;
let tmp_dir = tempfile::Builder::new()
.prefix("tauri_current_app")
.tempdir()?;
let mut perms = std::fs::metadata(tmp_dir.path())?.permissions();
perms.set_mode(0o700);
std::fs::set_permissions(tmp_dir.path(), perms)?;
use std::os::unix::fs::{MetadataExt, PermissionsExt};
let tmp_app_image = &tmp_dir.path().join("current_app.AppImage");
let extract_path_metadata = extract_path.metadata()?;
// create a backup of our current app image
Move::from_source(extract_path).to_dest(tmp_app_image)?;
let tmp_dir_locations = vec![
Box::new(|| Some(env::temp_dir())) as Box<dyn FnOnce() -> Option<PathBuf>>,
Box::new(dirs_next::cache_dir),
Box::new(|| Some(extract_path.parent().unwrap().to_path_buf())),
];
// extract the buffer to the tmp_dir
// we extract our signed archive into our final directory without any temp file
let mut extractor =
Extract::from_cursor(archive_buffer, ArchiveFormat::Tar(Some(Compression::Gz)));
for tmp_dir_location in tmp_dir_locations {
if let Some(tmp_dir_location) = tmp_dir_location() {
let tmp_dir = tempfile::Builder::new()
.prefix("tauri_current_app")
.tempdir_in(tmp_dir_location)?;
let tmp_dir_metadata = tmp_dir.path().metadata()?;
extractor.with_files(|entry| {
let path = entry.path()?;
if path.extension() == Some(OsStr::new("AppImage")) {
// if something went wrong during the extraction, we should restore previous app
if let Err(err) = entry.extract(extract_path) {
Move::from_source(tmp_app_image).to_dest(extract_path)?;
return Err(crate::api::Error::Extract(err.to_string()));
if extract_path_metadata.dev() == tmp_dir_metadata.dev() {
let mut perms = tmp_dir_metadata.permissions();
perms.set_mode(0o700);
std::fs::set_permissions(tmp_dir.path(), perms)?;
let tmp_app_image = &tmp_dir.path().join("current_app.AppImage");
// create a backup of our current app image
Move::from_source(extract_path).to_dest(tmp_app_image)?;
// extract the buffer to the tmp_dir
// we extract our signed archive into our final directory without any temp file
let mut extractor =
Extract::from_cursor(archive_buffer, ArchiveFormat::Tar(Some(Compression::Gz)));
return extractor
.with_files(|entry| {
let path = entry.path()?;
if path.extension() == Some(OsStr::new("AppImage")) {
// if something went wrong during the extraction, we should restore previous app
if let Err(err) = entry.extract(extract_path) {
Move::from_source(tmp_app_image).to_dest(extract_path)?;
return Err(crate::api::Error::Extract(err.to_string()));
}
// early finish we have everything we need here
return Ok(true);
}
Ok(false)
})
.map_err(Into::into);
}
// early finish we have everything we need here
return Ok(true);
}
Ok(false)
})?;
}
Ok(())
Err(Error::TempDirNotOnSameMountPoint)
}
// Windows
@@ -692,7 +705,6 @@ fn copy_files_and_run<R: Read + Seek>(archive_buffer: R, extract_path: &Path) ->
// ## EXE
// Update server can provide a custom EXE (installer) who can run any task.
#[cfg(feature = "updater")]
#[cfg(target_os = "windows")]
#[allow(clippy::unnecessary_wraps)]
fn copy_files_and_run<R: Read + Seek>(
@@ -795,7 +807,6 @@ fn copy_files_and_run<R: Read + Seek>(
// │ └── Contents # Application contents...
// │ └── ...
// └── ...
#[cfg(feature = "updater")]
#[cfg(target_os = "macos")]
fn copy_files_and_run<R: Read + Seek>(archive_buffer: R, extract_path: &Path) -> Result {
let mut extracted_files: Vec<PathBuf> = Vec::new();

View File

@@ -65,6 +65,10 @@ pub enum Error {
/// HTTP error.
#[error(transparent)]
Http(#[from] http::Error),
/// Temp dir is not on same mount mount. This prevents our updater to rename the AppImage to a temp file.
#[cfg(target_os = "linux")]
#[error("temp directory is not on the same mount point as the AppImage")]
TempDirNotOnSameMountPoint,
}
pub type Result<T = ()> = std::result::Result<T, Error>;