secure_backup 0.1.0

Take an incremental secure backup from a directory
Documentation
use crate::common;
use crate::db::Database;
use crate::util::{decode, decrypt_file, derive_key, get_files};
use openssl::symm::Cipher;
use std::ffi::OsString;
use std::fs::{self};
use std::os::unix::prelude::OsStringExt;
use std::path::Path;
use std::sync::{Arc, RwLock};

pub fn restore_backup(
  cipher_type: common::Cipher,
  backup_dir: &Path,
  restore_dir: &Path,
  password: &str,
  salt: &str,
) {
  let cipher: Cipher = match cipher_type {
    common::Cipher::AES256 => Cipher::aes_256_ctr(),
    common::Cipher::ChaCha20 => Cipher::chacha20(),
  };
  let key = derive_key(password, salt, cipher.key_len());

  let db_path = Path::new(&backup_dir).join(Path::new("db.json"));
  let backup_files_dir = Path::new(&backup_dir).join(Path::new("files"));

  fs::create_dir(restore_dir).expect("Restore directory exists.");

  let db = Arc::new(RwLock::new(Database::new(cipher, &key, &db_path)));
  let mut db_writer = db.write().unwrap();
  db_writer.init();
  drop(db_writer);

  get_files(&backup_files_dir, &|file| {
    let db_reader = db.read().unwrap();
    let file_id = decode(&file.file_name().into_string().unwrap());
    let file_record = db_reader.find_file_record(&file_id);
    drop(db_reader);

    if file_record.is_none() {
      return;
    }

    let (_, file_info) = file_record.unwrap();
    let restore_path =
      Path::new(restore_dir).join(Path::new(&OsString::from_vec(file_info.source_path)));

    fs::create_dir_all(&restore_path.parent().unwrap()).unwrap();

    decrypt_file(cipher, &key, &file_info.encryption_iv, &file.path(), &restore_path);
  });
}