Skip to content

Commit fd125f7

Browse files
authored
fix(updater): fallback if tmp is on different mount point, closes #4500 (#4504)
1 parent f6edc6d commit fd125f7

File tree

3 files changed

+79
-59
lines changed

3 files changed

+79
-59
lines changed

.changes/fix-updater-linux.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"tauri": patch
3+
---
4+
5+
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.

core/tauri/src/updater/core.rs

Lines changed: 70 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
// SPDX-License-Identifier: MIT
44

55
use super::error::{Error, Result};
6-
#[cfg(feature = "updater")]
76
use crate::api::file::{ArchiveFormat, Extract, Move};
87
use crate::{
98
api::http::{ClientBuilder, HttpRequestBuilder},
@@ -21,7 +20,6 @@ use tauri_utils::{platform::current_exe, Env};
2120
use time::OffsetDateTime;
2221
use url::Url;
2322

24-
#[cfg(feature = "updater")]
2523
use std::io::Seek;
2624
use std::{
2725
collections::HashMap,
@@ -33,7 +31,6 @@ use std::{
3331
time::Duration,
3432
};
3533

36-
#[cfg(feature = "updater")]
3734
#[cfg(not(target_os = "macos"))]
3835
use std::ffi::OsStr;
3936

@@ -602,29 +599,27 @@ impl<R: Runtime> Update<R> {
602599
// if there is no signature, bail out.
603600
verify_signature(&mut archive_buffer, &self.signature, &pub_key)?;
604601

605-
#[cfg(feature = "updater")]
606-
{
607-
// we copy the files depending of the operating system
608-
// we run the setup, appimage re-install or overwrite the
609-
// macos .app
610-
#[cfg(target_os = "windows")]
611-
copy_files_and_run(
612-
archive_buffer,
613-
&self.extract_path,
614-
self.with_elevated_task,
615-
self
616-
.app
617-
.config()
618-
.tauri
619-
.updater
620-
.windows
621-
.install_mode
622-
.clone()
623-
.msiexec_args(),
624-
)?;
625-
#[cfg(not(target_os = "windows"))]
626-
copy_files_and_run(archive_buffer, &self.extract_path)?;
627-
}
602+
// we copy the files depending of the operating system
603+
// we run the setup, appimage re-install or overwrite the
604+
// macos .app
605+
#[cfg(target_os = "windows")]
606+
copy_files_and_run(
607+
archive_buffer,
608+
&self.extract_path,
609+
self.with_elevated_task,
610+
self
611+
.app
612+
.config()
613+
.tauri
614+
.updater
615+
.windows
616+
.install_mode
617+
.clone()
618+
.msiexec_args(),
619+
)?;
620+
#[cfg(not(target_os = "windows"))]
621+
copy_files_and_run(archive_buffer, &self.extract_path)?;
622+
628623
// We are done!
629624
Ok(())
630625
}
@@ -640,42 +635,60 @@ impl<R: Runtime> Update<R> {
640635
// We should have an AppImage already installed to be able to copy and install
641636
// the extract_path is the current AppImage path
642637
// tmp_dir is where our new AppImage is found
643-
#[cfg(feature = "updater")]
644638
#[cfg(target_os = "linux")]
645639
fn copy_files_and_run<R: Read + Seek>(archive_buffer: R, extract_path: &Path) -> Result {
646-
use std::os::unix::fs::PermissionsExt;
647-
let tmp_dir = tempfile::Builder::new()
648-
.prefix("tauri_current_app")
649-
.tempdir()?;
650-
let mut perms = std::fs::metadata(tmp_dir.path())?.permissions();
651-
perms.set_mode(0o700);
652-
std::fs::set_permissions(tmp_dir.path(), perms)?;
653-
654-
let tmp_app_image = &tmp_dir.path().join("current_app.AppImage");
655-
656-
// create a backup of our current app image
657-
Move::from_source(extract_path).to_dest(tmp_app_image)?;
658-
659-
// extract the buffer to the tmp_dir
660-
// we extract our signed archive into our final directory without any temp file
661-
let mut extractor =
662-
Extract::from_cursor(archive_buffer, ArchiveFormat::Tar(Some(Compression::Gz)));
663-
664-
extractor.with_files(|entry| {
665-
let path = entry.path()?;
666-
if path.extension() == Some(OsStr::new("AppImage")) {
667-
// if something went wrong during the extraction, we should restore previous app
668-
if let Err(err) = entry.extract(extract_path) {
669-
Move::from_source(tmp_app_image).to_dest(extract_path)?;
670-
return Err(crate::api::Error::Extract(err.to_string()));
640+
use std::os::unix::fs::{MetadataExt, PermissionsExt};
641+
642+
let extract_path_metadata = extract_path.metadata()?;
643+
644+
let tmp_dir_locations = vec![
645+
Box::new(|| Some(env::temp_dir())) as Box<dyn FnOnce() -> Option<PathBuf>>,
646+
Box::new(dirs_next::cache_dir),
647+
Box::new(|| Some(extract_path.parent().unwrap().to_path_buf())),
648+
];
649+
650+
for tmp_dir_location in tmp_dir_locations {
651+
if let Some(tmp_dir_location) = tmp_dir_location() {
652+
let tmp_dir = tempfile::Builder::new()
653+
.prefix("tauri_current_app")
654+
.tempdir_in(tmp_dir_location)?;
655+
let tmp_dir_metadata = tmp_dir.path().metadata()?;
656+
657+
if extract_path_metadata.dev() == tmp_dir_metadata.dev() {
658+
let mut perms = tmp_dir_metadata.permissions();
659+
perms.set_mode(0o700);
660+
std::fs::set_permissions(tmp_dir.path(), perms)?;
661+
662+
let tmp_app_image = &tmp_dir.path().join("current_app.AppImage");
663+
664+
// create a backup of our current app image
665+
Move::from_source(extract_path).to_dest(tmp_app_image)?;
666+
667+
// extract the buffer to the tmp_dir
668+
// we extract our signed archive into our final directory without any temp file
669+
let mut extractor =
670+
Extract::from_cursor(archive_buffer, ArchiveFormat::Tar(Some(Compression::Gz)));
671+
672+
return extractor
673+
.with_files(|entry| {
674+
let path = entry.path()?;
675+
if path.extension() == Some(OsStr::new("AppImage")) {
676+
// if something went wrong during the extraction, we should restore previous app
677+
if let Err(err) = entry.extract(extract_path) {
678+
Move::from_source(tmp_app_image).to_dest(extract_path)?;
679+
return Err(crate::api::Error::Extract(err.to_string()));
680+
}
681+
// early finish we have everything we need here
682+
return Ok(true);
683+
}
684+
Ok(false)
685+
})
686+
.map_err(Into::into);
671687
}
672-
// early finish we have everything we need here
673-
return Ok(true);
674688
}
675-
Ok(false)
676-
})?;
689+
}
677690

678-
Ok(())
691+
Err(Error::TempDirNotOnSameMountPoint)
679692
}
680693

681694
// Windows
@@ -692,7 +705,6 @@ fn copy_files_and_run<R: Read + Seek>(archive_buffer: R, extract_path: &Path) ->
692705

693706
// ## EXE
694707
// Update server can provide a custom EXE (installer) who can run any task.
695-
#[cfg(feature = "updater")]
696708
#[cfg(target_os = "windows")]
697709
#[allow(clippy::unnecessary_wraps)]
698710
fn copy_files_and_run<R: Read + Seek>(
@@ -795,7 +807,6 @@ fn copy_files_and_run<R: Read + Seek>(
795807
// │ └── Contents # Application contents...
796808
// │ └── ...
797809
// └── ...
798-
#[cfg(feature = "updater")]
799810
#[cfg(target_os = "macos")]
800811
fn copy_files_and_run<R: Read + Seek>(archive_buffer: R, extract_path: &Path) -> Result {
801812
let mut extracted_files: Vec<PathBuf> = Vec::new();

core/tauri/src/updater/error.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,10 @@ pub enum Error {
6565
/// HTTP error.
6666
#[error(transparent)]
6767
Http(#[from] http::Error),
68+
/// Temp dir is not on same mount mount. This prevents our updater to rename the AppImage to a temp file.
69+
#[cfg(target_os = "linux")]
70+
#[error("temp directory is not on the same mount point as the AppImage")]
71+
TempDirNotOnSameMountPoint,
6872
}
6973

7074
pub type Result<T = ()> = std::result::Result<T, Error>;

0 commit comments

Comments
 (0)