Skip to content

Commit 44126f3

Browse files
author
Milind Deore
committed
Adding second device
Adding second devices using sync. This patch make it happen. Bug: Test: This patch also required changes in the application and privitty side changes. This is verified on the real phone and it works.
1 parent 3d0717a commit 44126f3

2 files changed

Lines changed: 146 additions & 1 deletion

File tree

src/imex.rs

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ pub use transfer::{BackupProvider, get_backup};
3838
// Name of the database file in the backup.
3939
const DBFILE_BACKUP_NAME: &str = "dc_database_backup.sqlite";
4040
pub(crate) const BLOBS_BACKUP_NAME: &str = "blobs_backup";
41+
pub(crate) const PRIVITTY_BACKUP_NAME: &str = ".privitty";
4142

4243
/// Import/export command.
4344
#[derive(Debug, Display, Copy, Clone, PartialEq, Eq, FromPrimitive, ToPrimitive)]
@@ -322,6 +323,15 @@ async fn import_backup_stream_inner<R: tokio::io::AsyncRead + Unpin>(
322323
let backup_file = ProgressReader::new(backup_file, context.clone(), file_size);
323324
let mut archive = Archive::new(backup_file);
324325

326+
let context_dir = context
327+
.get_blobdir()
328+
.parent()
329+
.context("Context dir not found");
330+
let context_dir = match context_dir {
331+
Ok(dir) => dir.to_path_buf(),
332+
Err(e) => return (Err(e).context("Failed to get context dir"),),
333+
};
334+
325335
let mut entries = match archive.entries() {
326336
Ok(entries) => entries,
327337
Err(e) => return (Err(e).context("Failed to get archive entries"),),
@@ -338,6 +348,38 @@ async fn import_backup_stream_inner<R: tokio::io::AsyncRead + Unpin>(
338348
Ok(path) => path.to_path_buf(),
339349
Err(e) => break Err(e).context("Failed to get entry path"),
340350
};
351+
352+
// Handle .privitty folder separately - extract to context_dir instead of blobdir
353+
// Check if the path starts with .privitty component (skipping leading CurDir components)
354+
// This handles paths like ".privitty/file.txt", "./.privitty/file.txt", etc.
355+
let is_privitty_entry = path
356+
.components()
357+
.skip_while(|c| matches!(c, std::path::Component::CurDir))
358+
.next()
359+
.and_then(|c| {
360+
if let std::path::Component::Normal(name) = c {
361+
name.to_str()
362+
} else {
363+
None
364+
}
365+
})
366+
.map(|name| name == PRIVITTY_BACKUP_NAME)
367+
.unwrap_or(false);
368+
369+
if is_privitty_entry {
370+
// Ensure target directory exists
371+
if let Err(e) = fs::create_dir_all(&context_dir).await {
372+
warn!(context, "Failed to create context dir {}: {:#}", context_dir.display(), e);
373+
}
374+
if let Err(e) = f.unpack_in(&context_dir).await {
375+
warn!(context, "Failed to unpack .privitty entry {} to {}: {:#}", path.display(), context_dir.display(), e);
376+
// Continue processing other entries even if .privitty extraction fails
377+
} else {
378+
info!(context, "Successfully unpacked .privitty entry {} to {}", path.display(), context_dir.display());
379+
}
380+
continue;
381+
}
382+
341383
if let Err(e) = f.unpack_in(context.get_blobdir()).await {
342384
break Err(e).context("Failed to unpack file");
343385
}
@@ -465,6 +507,14 @@ async fn export_backup(context: &Context, dir: &Path, passphrase: String) -> Res
465507
for blob in blobdir.iter() {
466508
file_size += blob.to_abs_path().metadata()?.len()
467509
}
510+
511+
// Add size of .privitty folder if it exists
512+
let context_dir = context
513+
.get_blobdir()
514+
.parent()
515+
.context("Context dir not found")?;
516+
let privitty_dir = context_dir.join(PRIVITTY_BACKUP_NAME);
517+
file_size += calculate_dir_size(&privitty_dir).await?;
468518

469519
export_backup_stream(context, &temp_db_path, blobdir, file, file_size)
470520
.await
@@ -545,6 +595,73 @@ where
545595
}
546596
}
547597

598+
/// Calculates the total size of all files in a directory recursively.
599+
pub(crate) async fn calculate_dir_size(dir: &Path) -> Result<u64> {
600+
let mut total_size = 0u64;
601+
if !dir.exists() {
602+
return Ok(0);
603+
}
604+
// Use iterative approach with a stack to avoid recursion boxing issues
605+
let mut dirs_to_process = vec![dir.to_path_buf()];
606+
607+
while let Some(current_dir) = dirs_to_process.pop() {
608+
let mut entries = tokio::fs::read_dir(&current_dir).await?;
609+
while let Ok(Some(entry)) = entries.next_entry().await {
610+
let path = entry.path();
611+
let metadata = entry.metadata().await?;
612+
if metadata.is_file() {
613+
total_size += metadata.len();
614+
} else if metadata.is_dir() {
615+
dirs_to_process.push(path);
616+
}
617+
}
618+
}
619+
Ok(total_size)
620+
}
621+
622+
/// Adds a directory to the tar archive recursively.
623+
async fn append_dir_to_tar<W>(
624+
builder: &mut tokio_tar::Builder<W>,
625+
source_dir: &Path,
626+
archive_prefix: &Path,
627+
) -> Result<()>
628+
where
629+
W: tokio::io::AsyncWrite + Unpin + Send,
630+
{
631+
if !source_dir.exists() {
632+
return Ok(());
633+
}
634+
// Use iterative approach with a stack to avoid recursion issues
635+
let mut dirs_to_process: Vec<(PathBuf, PathBuf)> = vec![(source_dir.to_path_buf(), archive_prefix.to_path_buf())];
636+
637+
while let Some((current_dir, current_archive_prefix)) = dirs_to_process.pop() {
638+
let mut entries = tokio::fs::read_dir(&current_dir).await?;
639+
while let Ok(Some(entry)) = entries.next_entry().await {
640+
let path = entry.path();
641+
let metadata = entry.metadata().await?;
642+
643+
if metadata.is_file() {
644+
let file_name = path
645+
.file_name()
646+
.and_then(|n| n.to_str())
647+
.ok_or_else(|| format_err!("invalid file name"))?;
648+
let archive_path = current_archive_prefix.join(file_name);
649+
let mut file = File::open(&path).await?;
650+
builder.append_file(archive_path, &mut file).await?;
651+
} else if metadata.is_dir() {
652+
let dir_name = path
653+
.file_name()
654+
.and_then(|n| n.to_str())
655+
.ok_or_else(|| format_err!("invalid directory name"))?;
656+
let archive_path = current_archive_prefix.join(dir_name);
657+
// Add subdirectory to stack for processing
658+
dirs_to_process.push((path, archive_path));
659+
}
660+
}
661+
}
662+
Ok(())
663+
}
664+
548665
/// Exports the database and blobs into a stream.
549666
pub(crate) async fn export_backup_stream<'a, W>(
550667
context: &'a Context,
@@ -569,6 +686,26 @@ where
569686
builder.append_file(path_in_archive, &mut file).await?;
570687
}
571688

689+
// Add .privitty folder if it exists
690+
let context_dir = context
691+
.get_blobdir()
692+
.parent()
693+
.context("Context dir not found")?;
694+
let privitty_dir = context_dir.join(PRIVITTY_BACKUP_NAME);
695+
if privitty_dir.exists() {
696+
info!(context, "Adding .privitty folder to backup from {}", privitty_dir.display());
697+
append_dir_to_tar(
698+
&mut builder,
699+
&privitty_dir,
700+
&PathBuf::from(PRIVITTY_BACKUP_NAME),
701+
)
702+
.await
703+
.context("Failed to add .privitty folder to backup")?;
704+
info!(context, "Successfully added .privitty folder to backup");
705+
} else {
706+
info!(context, ".privitty folder does not exist at {}, skipping", privitty_dir.display());
707+
}
708+
572709
builder.finish().await?;
573710
Ok(())
574711
}

src/imex/transfer.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ use crate::stock_str::backup_transfer_msg_body;
4848
use crate::tools::{TempPathGuard, create_id, time};
4949
use crate::{EventType, e2ee};
5050

51-
use super::{DBFILE_BACKUP_NAME, export_backup_stream, export_database, import_backup_stream};
51+
use super::{DBFILE_BACKUP_NAME, PRIVITTY_BACKUP_NAME, calculate_dir_size, export_backup_stream, export_database, import_backup_stream};
5252

5353
/// ALPN protocol identifier for the backup transfer protocol.
5454
const BACKUP_ALPN: &[u8] = b"/deltachat/backup";
@@ -194,6 +194,14 @@ impl BackupProvider {
194194
for blob in blobdir.iter() {
195195
file_size += blob.to_abs_path().metadata()?.len()
196196
}
197+
198+
// Add size of .privitty folder if it exists
199+
let context_dir = context
200+
.get_blobdir()
201+
.parent()
202+
.context("Context dir not found")?;
203+
let privitty_dir = context_dir.join(PRIVITTY_BACKUP_NAME);
204+
file_size += calculate_dir_size(&privitty_dir).await?;
197205

198206
send_stream.write_all(&file_size.to_be_bytes()).await?;
199207

0 commit comments

Comments
 (0)