diff --git a/runtime/src/snapshot_utils.rs b/runtime/src/snapshot_utils.rs index 650ad7daa4c052..f000312d658ea1 100644 --- a/runtime/src/snapshot_utils.rs +++ b/runtime/src/snapshot_utils.rs @@ -422,6 +422,21 @@ pub enum VerifySlotDeltasError { BadSlotHistory, } +/// Creates directories if they do not exist, and canonicalizes the paths. +pub fn create_and_canonicalize_directories(directories: &[PathBuf]) -> Result> { + directories + .iter() + .map(|path| { + std::fs::create_dir_all(path).map_err(|err| { + SnapshotError::IoWithSourceAndFile(err, "create_dir_all", path.clone()) + })?; + path.canonicalize().map_err(|err| { + SnapshotError::IoWithSourceAndFile(err, "canonicalize", path.clone()) + }) + }) + .collect() +} + /// Delete the files and subdirectories in a directory. /// This is useful if the process does not have permission /// to delete the top level directory it might be able to diff --git a/validator/src/main.rs b/validator/src/main.rs index 573d512b558680..451334d36fcbff 100644 --- a/validator/src/main.rs +++ b/validator/src/main.rs @@ -44,7 +44,8 @@ use { runtime_config::RuntimeConfig, snapshot_config::{SnapshotConfig, SnapshotUsage}, snapshot_utils::{ - self, create_all_accounts_run_and_snapshot_dirs, ArchiveFormat, SnapshotVersion, + self, create_all_accounts_run_and_snapshot_dirs, create_and_canonicalize_directories, + ArchiveFormat, SnapshotVersion, }, }, solana_sdk::{ @@ -963,11 +964,13 @@ pub fn main() { .map(BlockstoreRecoveryMode::from); // Canonicalize ledger path to avoid issues with symlink creation - let _ = fs::create_dir_all(&ledger_path); - let ledger_path = fs::canonicalize(&ledger_path).unwrap_or_else(|err| { - eprintln!("Unable to access ledger path: {err:?}"); - exit(1); - }); + let ledger_path = create_and_canonicalize_directories(&[ledger_path]) + .unwrap_or_else(|err| { + eprintln!("Unable to access ledger path: {err}"); + exit(1); + }) + .pop() + .unwrap(); let debug_keys: Option>> = if matches.is_present("debug_key") { Some(Arc::new( @@ -1396,6 +1399,12 @@ pub fn main() { } else { vec![ledger_path.join("accounts")] }; + let account_paths = snapshot_utils::create_and_canonicalize_directories(&account_paths) + .unwrap_or_else(|err| { + eprintln!("Unable to access account path: {err}"); + exit(1); + }); + let account_shrink_paths: Option> = values_t!(matches, "account_shrink_path", String) .map(|shrink_paths| shrink_paths.into_iter().map(PathBuf::from).collect()) @@ -1413,20 +1422,10 @@ pub fn main() { validator_config.account_snapshot_paths = account_snapshot_paths; validator_config.account_shrink_paths = account_shrink_paths.map(|paths| { - paths - .into_iter() - .map(|account_path| { - match fs::create_dir_all(&account_path) - .and_then(|_| fs::canonicalize(&account_path)) - { - Ok(account_path) => account_path, - Err(err) => { - eprintln!("Unable to access account path: {account_path:?}, err: {err:?}"); - exit(1); - } - } - }) - .collect() + create_and_canonicalize_directories(&paths).unwrap_or_else(|err| { + eprintln!("Unable to access account shrink path: {err}"); + exit(1); + }) }); let maximum_local_snapshot_age = value_t_or_exit!(matches, "maximum_local_snapshot_age", u64);