Skip to content

Commit a9d77bd

Browse files
committed
fix: handle in-place updates by preserving old file as .old backup
1 parent 9aa74fc commit a9d77bd

1 file changed

Lines changed: 64 additions & 20 deletions

File tree

src/updater.rs

Lines changed: 64 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,13 @@ use crate::appimage::AppImage;
77
use crate::error::{Error, Result};
88
use crate::update_info::UpdateInfo;
99

10+
struct UpdateContext {
11+
source_size: u64,
12+
target_size: u64,
13+
block_size: usize,
14+
original_perms: Option<fs::Permissions>,
15+
}
16+
1017
#[derive(Debug)]
1118
pub struct UpdateStats {
1219
pub source_path: PathBuf,
@@ -124,7 +131,8 @@ impl Updater {
124131
return Ok(false);
125132
}
126133

127-
if !self.overwrite {
134+
let same_file = self.appimage.path() == output_path;
135+
if !same_file && !self.overwrite {
128136
return Err(Error::AppImage(format!(
129137
"Output file already exists: {}",
130138
output_path.display()
@@ -175,29 +183,67 @@ impl Updater {
175183
return Ok((output_path, stats));
176184
}
177185

178-
if !self.overwrite {
186+
let same_file = self.appimage.path() == output_path;
187+
if !same_file && !self.overwrite {
179188
return Err(Error::AppImage(format!(
180189
"Output file already exists: {}",
181190
output_path.display()
182191
)));
183192
}
184193
}
185194

186-
let original_perms = fs::metadata(self.appimage.path())
187-
.map(|m| m.permissions())
188-
.ok();
195+
let ctx = UpdateContext {
196+
source_size: self.source_size(),
197+
target_size: control.length,
198+
block_size: control.blocksize,
199+
original_perms: fs::metadata(self.appimage.path())
200+
.map(|m| m.permissions())
201+
.ok(),
202+
};
203+
204+
let source_path = self.appimage.path();
205+
let same_file = source_path == output_path;
206+
207+
let (actual_source_path, backup_path) = if same_file {
208+
let filename = source_path
209+
.file_name()
210+
.and_then(|n| n.to_str())
211+
.unwrap_or("appimage");
212+
let backup = source_path.with_file_name(format!("{}.old", filename));
213+
let _ = fs::remove_file(&backup);
214+
fs::rename(source_path, &backup)?;
215+
(backup.clone(), Some(backup))
216+
} else {
217+
(source_path.to_path_buf(), None)
218+
};
219+
220+
let result = self.do_update(&actual_source_path, &output_path, &zsync_url, &ctx);
189221

190-
let source_size = self.source_size();
191-
let target_size = control.length;
192-
let block_size = control.blocksize;
222+
match result {
223+
Ok(stats) => Ok((output_path, stats)),
224+
Err(e) => {
225+
if let Some(backup) = backup_path {
226+
let _ = fs::rename(&backup, source_path);
227+
}
228+
Err(e)
229+
}
230+
}
231+
}
193232

194-
let assembly = ZsyncAssembly::from_url(&zsync_url, &output_path)
233+
fn do_update(
234+
&self,
235+
source_path: &Path,
236+
output_path: &Path,
237+
zsync_url: &str,
238+
ctx: &UpdateContext,
239+
) -> Result<UpdateStats> {
240+
let assembly = ZsyncAssembly::from_url(zsync_url, output_path)
195241
.map_err(|e| Error::Zsync(format!("Failed to initialize zsync: {}", e)))?;
196242

197243
let mut assembly = assembly;
198244

199245
let blocks_reused = assembly
200-
.submit_source_file(self.appimage.path())
246+
.submit_source_file(source_path)
201247
.map_err(|e| Error::Zsync(format!("Failed to submit source file: {}", e)))?;
202248

203249
let self_blocks = assembly
@@ -213,21 +259,19 @@ impl Updater {
213259
.complete()
214260
.map_err(|e| Error::Zsync(format!("Failed to complete assembly: {}", e)))?;
215261

216-
if let Some(perms) = original_perms {
217-
fs::set_permissions(&output_path, perms)?;
262+
if let Some(ref perms) = ctx.original_perms {
263+
fs::set_permissions(output_path, perms.clone())?;
218264
}
219265

220-
let stats = UpdateStats {
266+
Ok(UpdateStats {
221267
source_path: self.appimage.path().to_path_buf(),
222-
source_size,
223-
target_path: output_path.clone(),
224-
target_size,
268+
source_size: ctx.source_size,
269+
target_path: output_path.to_path_buf(),
270+
target_size: ctx.target_size,
225271
blocks_reused,
226272
blocks_downloaded,
227-
block_size,
228-
};
229-
230-
Ok((output_path, stats))
273+
block_size: ctx.block_size,
274+
})
231275
}
232276

233277
pub fn output_path(&self) -> Result<PathBuf> {

0 commit comments

Comments
 (0)