lighthouse/common/eth2_wallet_manager/src/filesystem.rs
Akihito Nakano 4186d117af Replace OpenOptions::new with File::options to be readable (#3059)
## Issue Addressed

Closes #3049 

This PR updates widely but this replace is safe as `File::options()` is equivelent to `OpenOptions::new()`.
ref: https://doc.rust-lang.org/stable/src/std/fs.rs.html#378-380
2022-03-07 06:30:18 +00:00

98 lines
3.2 KiB
Rust

//! Provides some CRUD functions for wallets on the filesystem.
use eth2_wallet::Error as WalletError;
use eth2_wallet::{Uuid, Wallet};
use std::fs::{copy as copy_file, remove_file, File};
use std::io;
use std::path::{Path, PathBuf};
#[derive(Debug)]
pub enum Error {
WalletAlreadyExists(PathBuf),
WalletDoesNotExist(PathBuf),
WalletBackupAlreadyExists(PathBuf),
UnableToCreateBackup(io::Error),
UnableToRemoveBackup(io::Error),
UnableToRemoveWallet(io::Error),
UnableToCreateWallet(io::Error),
UnableToReadWallet(io::Error),
JsonWrite(WalletError),
JsonRead(WalletError),
}
/// Read a wallet with the given `uuid` from the `wallet_dir`.
pub fn read<P: AsRef<Path>>(wallet_dir: P, uuid: &Uuid) -> Result<Wallet, Error> {
let json_path = wallet_json_path(wallet_dir, uuid);
if !json_path.exists() {
Err(Error::WalletDoesNotExist(json_path))
} else {
File::options()
.read(true)
.create(false)
.open(json_path)
.map_err(Error::UnableToReadWallet)
.and_then(|f| Wallet::from_json_reader(f).map_err(Error::JsonRead))
}
}
/// Update the JSON file in the `wallet_dir` with the given `wallet`.
///
/// Performs a three-step copy:
///
/// 1. Copy the current JSON file to a backup file.
/// 2. Over-write the existing JSON file.
/// 3. Delete the backup file.
pub fn update<P: AsRef<Path>>(wallet_dir: P, wallet: &Wallet) -> Result<(), Error> {
let wallet_dir = wallet_dir.as_ref();
let json_path = wallet_json_path(wallet_dir, wallet.uuid());
let json_backup_path = wallet_json_backup_path(wallet_dir, wallet.uuid());
// Require that a wallet already exists.
if !json_path.exists() {
return Err(Error::WalletDoesNotExist(json_path));
// Require that there is no existing backup.
} else if json_backup_path.exists() {
return Err(Error::WalletBackupAlreadyExists(json_backup_path));
}
// Copy the existing wallet to the backup location.
copy_file(&json_path, &json_backup_path).map_err(Error::UnableToCreateBackup)?;
// Remove the existing wallet
remove_file(json_path).map_err(Error::UnableToRemoveWallet)?;
// Create the new wallet.
create(wallet_dir, wallet)?;
// Remove the backup file.
remove_file(json_backup_path).map_err(Error::UnableToRemoveBackup)?;
Ok(())
}
/// Writes the `wallet` into the `wallet_dir`, returning an error if it already exists.
pub fn create<P: AsRef<Path>>(wallet_dir: P, wallet: &Wallet) -> Result<(), Error> {
let json_path = wallet_json_path(wallet_dir, wallet.uuid());
if json_path.exists() {
Err(Error::WalletAlreadyExists(json_path))
} else {
File::options()
.write(true)
.create_new(true)
.open(json_path)
.map_err(Error::UnableToCreateWallet)
.and_then(|f| wallet.to_json_writer(f).map_err(Error::JsonWrite))
}
}
fn wallet_json_backup_path<P: AsRef<Path>>(wallet_dir: P, uuid: &Uuid) -> PathBuf {
wallet_dir.as_ref().join(format!("{}.backup", uuid))
}
fn wallet_json_path<P: AsRef<Path>>(wallet_dir: P, uuid: &Uuid) -> PathBuf {
wallet_dir.as_ref().join(format!("{}", uuid))
}