use crate::config::WorldConfig; use crate::region::Region; use flate2::write::GzEncoder; use flate2::Compression; use std::convert::TryFrom; use std::fs::{copy, create_dir, File}; use std::path::PathBuf; /// Backup a file /// /// # Param /// * `file_name` - file name /// * `world_path` - path to the world folder /// * `backup_path` - path to the backup folder pub fn backup_file( file_name: &str, mut world_path: PathBuf, mut backup_path: PathBuf, ) -> Result { world_path.push(file_name); backup_path.push(file_name); copy(world_path, backup_path) } /// Backup a directory /// /// # Param /// * `dir_name` - directory name /// * `world_path` - path to the world folder /// * `backup_path` - path to the backup folder pub fn backup_dir( dir_name: &str, world_path: &PathBuf, backup_path: &PathBuf, ) -> Result { let mut src_dir = world_path.clone(); src_dir.push(dir_name); let mut backup_dir = backup_path.clone(); backup_dir.push(dir_name); create_dir(&backup_dir)?; let mut file_count = 0; for entry in src_dir.read_dir()? { let entry = entry?; let mut target = backup_dir.clone(); target.push(entry.file_name()); copy(entry.path(), target)?; file_count += 1; } Ok(file_count) } /// Backup the regions /// /// # Param /// * `dir_name` - name of the backup folder /// * `save_radius` - block radius to save /// * `world_path` - path to the world folder /// * `backup_path` - path to the backup folder pub fn backup_region( dir_name: &str, save_radius: u64, world_path: &PathBuf, backup_path: &PathBuf, ) -> Result { let mut count: u64 = 0; let mut src_dir = world_path.clone(); src_dir.push(dir_name); let mut backup_dir = backup_path.clone(); backup_dir.push(dir_name); create_dir(&backup_dir)?; let save_radius = (save_radius as f64 / 512.0).ceil() as i64; for entry in src_dir.read_dir()? { let entry = entry?; let file_name = entry.file_name().to_str().unwrap().to_string(); if let Ok(region) = Region::try_from(file_name) { if region.x.abs() <= save_radius && region.y.abs() <= save_radius { let mut target = backup_dir.clone(); target.push(entry.file_name()); copy(entry.path(), target)?; count += 1; } } } Ok(count) } /// Backup a world /// /// # Param /// * `world_path` - path to the world folder /// * `backup_path` - path to the backup folder /// * `world_config` - world config options pub fn backup_world( world_path: PathBuf, mut backup_path: PathBuf, world_config: &WorldConfig, ) -> Result { let region_count; backup_path.push(&world_config.world_name); create_dir(backup_path.as_path())?; backup_region("poi", world_config.save_radius, &world_path, &backup_path)?; region_count = backup_region( "region", world_config.save_radius, &world_path, &backup_path, )?; Ok(region_count) } /// Backup the overworld /// /// # Param /// * `world_path` - path to the world folder /// * `backup_path` - path to the backup folder /// * `world_config` - world config options pub fn backup_overworld( world_path: PathBuf, backup_path: PathBuf, world_config: &WorldConfig, ) -> Result<(u64, u64), std::io::Error> { backup_dir("data", &world_path, &backup_path)?; backup_dir("stats", &world_path, &backup_path)?; backup_file("level.dat", world_path.clone(), backup_path.clone())?; backup_file("level.dat_old", world_path.clone(), backup_path.clone())?; backup_file("session.lock", world_path.clone(), backup_path.clone())?; backup_file("uid.dat", world_path.clone(), backup_path.clone())?; let player_count = backup_dir("playerdata", &world_path, &backup_path)?; let region_count = backup_world(world_path, backup_path, world_config)?; Ok((region_count, player_count)) } /// Backup the nether /// /// # Param /// * `world_path` - path to the world folder /// * `backup_path` - path to the backup folder /// * `world_config` - world config options pub fn backup_nether( world_path: PathBuf, backup_path: PathBuf, world_config: &WorldConfig, ) -> Result { let mut nether_path = world_path; nether_path.push("DIM-1"); backup_world(nether_path, backup_path, world_config) } /// Backup the end /// /// # Param /// * `world_path` - path to the world folder /// * `backup_path` - path to the backup folder /// * `world_config` - world config options pub fn backup_end( world_path: PathBuf, backup_path: PathBuf, world_config: &WorldConfig, ) -> Result { let mut end_path = world_path; end_path.push("DIM1"); backup_world(end_path, backup_path, world_config) } /// Compress the backup after the files have been copied /// /// # Param /// * `tmp_dir`: tmp directory with the backed up files /// * `output_file`: output archive pub fn compress_backup(tmp_dir: &PathBuf, output_file: &PathBuf) -> Result<(), std::io::Error> { let archive = File::create(output_file)?; let enc = GzEncoder::new(archive, Compression::default()); let mut tar_builder = tar::Builder::new(enc); tar_builder.append_dir_all(".", tmp_dir)?; Ok(()) }