i2pd-launch 0.5.0-beta.12

Launches i2pd with clean state
use std::fs::OpenOptions;
use std::io::{self, BufWriter, Write};
use std::path::Path;

/** 2MB souborový buffer používaný pro zápis */
const BUFFER_SIZE: usize = 2 * 1024 * 1024;

/** 32KB velikost dávky používaná pro zápis do bufferu */
const BATCH_SIZE: usize = 32 * 1024;
const BATCH_SIZE_U64: u64 = BATCH_SIZE as u64; // Pro výpočty s u64

/// Přepíše obsah souboru nulami.
///
/// Tato funkce otevře soubor, zjistí jeho velikost a poté jej přepíše
/// nulovými bajty s využitím `BufWriteru` pro zvýšení výkonu.
/// Tato funkce je nyní zaměřena pouze na bezpečné přepsání dat.
///
/// Funkce je generická přes `P` a přijímá jakýkoli typ, který implementuje `AsRef<Path>`.
///
/// # Typové parametry
/// * `P`: Typ cesty k souboru, který musí implementovat `AsRef<Path>`.
///
/// # Argumenty
/// * `path`: Cesta k souboru, který má být přepsán nulami.
///
/// # Návratová hodnota
/// Vrací `Result<(), io::Error>`, kde `Ok(())` značí úspěch,
/// a `Err(io::Error)` značí chybu.
pub fn wipe_with_zeros<P: AsRef<Path>>(path: P) -> io::Result<()> {
   let file_path = path.as_ref();

   // Krok 1: Otevření souboru pro čtení a zápis.
   let file = OpenOptions::new()
      .read(true)
      .write(true)
      .truncate(false) // Důležité: soubor nebude zkrácen na nulu při otevření
      .create_new(false) // Soubor už musí existovat
      .open(file_path)?;

   // Krok 2: Zjištění velikosti souboru.
   let file_size = file.metadata()?.len();

   // Krok 3: Inicializace BufWriteru a nulového bloku.
   let mut writer = BufWriter::with_capacity(BUFFER_SIZE, file);
   let zero_batch = vec![0u8; BATCH_SIZE];

   // Krok 4: Přepsání souboru nulami.
   let num_batches = (file_size + BATCH_SIZE_U64 - 1) / BATCH_SIZE_U64;
   for _ in 0..num_batches {
      writer.write_all(&zero_batch)?;
   }

   // Krok 5: Vyprázdnění bufferu BufWriteru.
   // Zajistí, že data z bufferu jdou do OS.
   writer.flush()?;

   // Krok 6: Získání zpět vnitřního souboru a zajištění zápisu na fyzický disk.
   let inner_file = writer.into_inner()?;
   inner_file.sync_data()?;

   Ok(())
}

// --- Makro `wipe_and_delete!` ---
/// Makro pro bezpečné přepsání souboru nulami a jeho následné smazání.
///
/// Toto makro volá funkci `wipe_with_zeros` pro přepsání dat
/// a následně `std::fs::remove_file` pro smazání souboru.
/// Vrací `Result<(), io::Error>`.
///
/// # Příklady
/// ```
/// # use std::fs;
/// # use std::io;
/// # use std::path::Path;
/// # // Pro účely příkladu definujeme dummy funkci
/// # pub fn wipe_with_zeros<P: AsRef<Path>>(_path: P) -> io::Result<()> { Ok(()) }
/// # #[macro_export]
/// # macro_rules! wipe_and_delete {
/// #     ($path:expr) => {{
/// #         let path_ref = ($path).as_ref();
/// #         $crate::wipe_with_zeros(path_ref)
/// #             .and_then(|_| std::fs::remove_file(path_ref))
/// #     }};
/// # }
/// # // Pro kompilaci příkladu s makrem potřebujeme dummy crate name
/// # #[allow(unused_imports)]
/// # use wipe_and_delete;
/// # #[macro_use]
/// # extern crate your_crate_name;
/// // Vytvoříme testovací soubor
/// let test_file = "my_secret_doc.txt";
/// fs::File::create(test_file).unwrap();
///
/// // Použijeme makro pro přepsání a smazání
/// match wipe_and_delete!(test_file) {
///     Ok(_) => println!("Soubor byl bezpečně přepsán a smazán."),
///     Err(e) => eprintln!("Chyba při mazání souboru: {}", e),
/// }
/// assert!(!Path::new(test_file).exists());
/// ```
#[macro_export]
macro_rules! wipe_and_delete {
   ($path:expr) => {{
      let path_ref: &Path = ($path).as_ref();
      $crate::wipe::wipe_with_zeros(path_ref).and_then(|_| std::fs::remove_file(path_ref))
   }};
}

#[macro_export]
macro_rules! wipe_workdir {
   ($workdir:expr) => {{
      let wipe_op = wipe_files(&$workdir);
      if !wipe_op {
         eprintln!(concat!(
            "Unable to delete all i2pd state files, ",
            "but no more retries left."
         ));
      } else {
         println!("i2pd router state cleared.");
      }
      // Poslední výraz bez středníku určuje návratovou hodnotu makra
      wipe_op
   }};
}

#[cfg(test)]
#[path = "wipe_tests.rs"]
mod wipe_tests;