fix sync download failing when temp dir on different mount

https://forums.ankiweb.net/t/problems-with-2-1-41-on-arch-linux/8103
This commit is contained in:
Damien Elmes 2021-03-09 11:44:49 +10:00
parent b81e2c0265
commit 7ce75479b2
4 changed files with 29 additions and 10 deletions

View file

@ -189,7 +189,7 @@ impl Backend {
fn download(&self) -> Result<Vec<u8>> {
let server = Box::new(self.col_into_server()?);
let mut rt = Runtime::new().unwrap();
let file = rt.block_on(server.full_download())?;
let file = rt.block_on(server.full_download(None))?;
let path = file.into_temp_path().keep()?;
Ok(path.to_str().expect("path was not in utf8").into())
}

View file

@ -142,11 +142,19 @@ impl SyncServer for HTTPSyncClient {
Ok(())
}
/// Download collection into a temporary file, returning it.
/// Caller should persist the file in the correct path after checking it.
/// Progress func must be set first.
async fn full_download(mut self: Box<Self>) -> Result<NamedTempFile> {
let mut temp_file = NamedTempFile::new()?;
/// Download collection into a temporary file, returning it. Caller should
/// persist the file in the correct path after checking it. Progress func
/// must be set first. The caller should pass the collection's folder in as
/// the temp folder if it wishes to atomically .persist() it.
async fn full_download(
mut self: Box<Self>,
col_folder: Option<&Path>,
) -> Result<NamedTempFile> {
let mut temp_file = if let Some(folder) = col_folder {
NamedTempFile::new_in(folder)
} else {
NamedTempFile::new()
}?;
let (size, mut stream) = self.download_inner().await?;
let mut progress = FullSyncProgress {
transferred_bytes: 0,
@ -410,7 +418,7 @@ mod test {
syncer.set_full_sync_progress_fn(Some(Box::new(|progress, _throttle| {
println!("progress: {:?}", progress);
})));
let out_path = syncer.full_download().await?;
let out_path = syncer.full_download(None).await?;
let mut syncer = Box::new(HTTPSyncClient::new(None, 0));
syncer.set_full_sync_progress_fn(Some(Box::new(|progress, _throttle| {

View file

@ -672,8 +672,11 @@ impl Collection {
pub(crate) async fn full_download_inner(self, server: Box<dyn SyncServer>) -> Result<()> {
let col_path = self.col_path.clone();
let col_folder = col_path
.parent()
.ok_or_else(|| AnkiError::invalid_input("couldn't get col_folder"))?;
self.close(false)?;
let out_file = server.full_download().await?;
let out_file = server.full_download(Some(col_folder)).await?;
// check file ok
let db = open_and_check_sqlite_file(out_file.path())?;
db.execute_batch("update col set ls=mod")?;

View file

@ -36,7 +36,10 @@ pub trait SyncServer {
/// If `can_consume` is true, the local server will move or remove the file, instead
/// creating a copy. The remote server ignores this argument.
async fn full_upload(self: Box<Self>, col_path: &Path, can_consume: bool) -> Result<()>;
async fn full_download(self: Box<Self>) -> Result<NamedTempFile>;
/// If the calling code intends to .persist() the named temp file to
/// atomically update the collection, it should pass in the collection's
/// folder, as .persist() can't work across filesystems.
async fn full_download(self: Box<Self>, temp_folder: Option<&Path>) -> Result<NamedTempFile>;
}
pub struct LocalServer {
@ -199,7 +202,12 @@ impl SyncServer for LocalServer {
fs::rename(col_path, &target_col_path).map_err(Into::into)
}
async fn full_download(mut self: Box<Self>) -> Result<NamedTempFile> {
/// The provided folder is ignored, as in the server case the local data
/// will be sent over the network, instead of written into a local file.
async fn full_download(
mut self: Box<Self>,
_col_folder: Option<&Path>,
) -> Result<NamedTempFile> {
// bump usn/mod & close
self.col.transact(None, |col| col.storage.increment_usn())?;
let col_path = self.col.col_path.clone();