From 51c16f23d89543a94f059d9f9fa3a4e2f151dec5 Mon Sep 17 00:00:00 2001 From: rishflab Date: Wed, 24 Feb 2021 18:08:25 +1100 Subject: [PATCH] Download and run monero wallet rpc on swap cli startup If the monero wallet rpc has not already been downloaded we download the monero cli package and extract the wallet rpc. The unneeded files are cleaned up. The monero wallet rpc is started on a random port which is provided to the swap cli. We added a fork of tokio-tar via a git subtree because we needed a tokio-tar version that was compatible with tokio 1.0. Remove this subtree in favor of a regular cargo dependency when this PR merges: https://github.com/vorot93/tokio-tar/pull/3. --- Cargo.lock | 146 ++++++++++++++++++++++++++++-- swap/Cargo.toml | 7 +- swap/src/bin/swap_cli.rs | 16 +++- swap/src/cli/config.rs | 19 ---- swap/src/monero.rs | 2 + swap/src/monero/wallet_rpc.rs | 164 ++++++++++++++++++++++++++++++++++ tokio-tar/src/archive.rs | 15 ++-- tokio-tar/src/builder.rs | 3 +- tokio-tar/src/entry.rs | 18 ++-- tokio-tar/src/header.rs | 6 +- tokio-tar/tests/all.rs | 7 +- tokio-tar/tests/header/mod.rs | 3 +- 12 files changed, 354 insertions(+), 52 deletions(-) create mode 100644 swap/src/monero/wallet_rpc.rs diff --git a/Cargo.lock b/Cargo.lock index bd5667d0..7c7da167 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -115,6 +115,19 @@ dependencies = [ "syn", ] +[[package]] +name = "async-compression" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b72c1f1154e234325b50864a349b9c8e56939e266a4c307c0f159812df2f9537" +dependencies = [ + "bzip2", + "futures-core", + "memchr", + "pin-project-lite", + "tokio", +] + [[package]] name = "async-io" version = "1.3.1" @@ -479,6 +492,27 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b700ce4376041dcd0a327fd0097c41095743c4c8af8887265942faf1100bd040" +[[package]] +name = "bzip2" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abf8012c8a15d5df745fcf258d93e6149dcf102882c8d8702d9cff778eab43a8" +dependencies = [ + "bzip2-sys", + "libc", +] + +[[package]] +name = "bzip2-sys" +version = "0.1.10+1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17fa3d1ac1ca21c5c4e36a97f3c3eb25084576f6fc47bf0139c1123434216c6c" +dependencies = [ + "cc", + "libc", + "pkg-config", +] + [[package]] name = "cache-padded" version = "1.1.1" @@ -888,12 +922,12 @@ checksum = "21453800c95bb1aaa57490458c42d60c6277cb8a3e386030ec2381d5c2d4fa77" dependencies = [ "bitcoin", "log", - "rustls", + "rustls 0.16.0", "serde", "serde_json", "socks", "webpki", - "webpki-roots", + "webpki-roots 0.19.0", ] [[package]] @@ -962,6 +996,18 @@ dependencies = [ "instant", ] +[[package]] +name = "filetime" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d34cfa13a63ae058bfa601fe9e313bbdb3746427c1459185464ce0fcf62e1e8" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "redox_syscall 0.2.4", + "winapi 0.3.9", +] + [[package]] name = "fixed-hash" version = "0.2.5" @@ -1409,6 +1455,21 @@ dependencies = [ "want", ] +[[package]] +name = "hyper-rustls" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f9f7a97316d44c0af9b0301e65010573a853a9fc97046d7331d7f6bc0fd5a64" +dependencies = [ + "futures-util", + "hyper", + "log", + "rustls 0.19.0", + "tokio", + "tokio-rustls", + "webpki", +] + [[package]] name = "idna" version = "0.2.0" @@ -2851,6 +2912,7 @@ dependencies = [ "http", "http-body", "hyper", + "hyper-rustls", "ipnet", "js-sys", "lazy_static", @@ -2858,14 +2920,17 @@ dependencies = [ "mime", "percent-encoding", "pin-project-lite", + "rustls 0.19.0", "serde", "serde_json", "serde_urlencoded", "tokio", + "tokio-rustls", "url", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", + "webpki-roots 0.21.0", "winreg", ] @@ -2941,6 +3006,19 @@ dependencies = [ "webpki", ] +[[package]] +name = "rustls" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "064fd21ff87c6e87ed4506e68beb42459caa4a0e2eb144932e6776768556980b" +dependencies = [ + "base64 0.13.0", + "log", + "ring", + "sct", + "webpki", +] + [[package]] name = "rw-stream-sink" version = "0.2.1" @@ -3193,6 +3271,15 @@ dependencies = [ "serde", ] +[[package]] +name = "signal-hook-registry" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16f1d0fef1604ba8f7a073c7e701f213e056707210e9020af4528e0101ce11a6" +dependencies = [ + "libc", +] + [[package]] name = "signature" version = "1.3.0" @@ -3431,6 +3518,7 @@ name = "swap" version = "0.1.0" dependencies = [ "anyhow", + "async-compression", "async-recursion", "async-trait", "atty", @@ -3475,7 +3563,9 @@ dependencies = [ "thiserror", "time", "tokio", + "tokio-tar", "tokio-tungstenite", + "tokio-util", "toml", "tracing", "tracing-futures", @@ -3687,8 +3777,12 @@ dependencies = [ "memchr", "mio", "num_cpus", + "once_cell", + "parking_lot", "pin-project-lite", + "signal-hook-registry", "tokio-macros", + "winapi 0.3.9", ] [[package]] @@ -3712,6 +3806,17 @@ dependencies = [ "tokio", ] +[[package]] +name = "tokio-rustls" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc6844de72e57df1980054b38be3a9f4702aba4858be64dd700181a8a6d0e1b6" +dependencies = [ + "rustls 0.19.0", + "tokio", + "webpki", +] + [[package]] name = "tokio-stream" version = "0.1.2" @@ -3723,6 +3828,20 @@ dependencies = [ "tokio", ] +[[package]] +name = "tokio-tar" +version = "0.2.0" +dependencies = [ + "filetime", + "futures-core", + "libc", + "redox_syscall 0.2.4", + "tempfile", + "tokio", + "tokio-stream", + "xattr", +] + [[package]] name = "tokio-tungstenite" version = "0.13.0" @@ -3740,9 +3859,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.6.1" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12ae4751faa60b9f96dd8344d74592e5a17c0c9a220413dbc6942d14139bbfcc" +checksum = "ebb7cb2f00c5ae8df755b252306272cd1790d39728363936e01827e11f0b017b" dependencies = [ "bytes", "futures-core", @@ -3750,7 +3869,6 @@ dependencies = [ "log", "pin-project-lite", "tokio", - "tokio-stream", ] [[package]] @@ -4164,6 +4282,15 @@ dependencies = [ "webpki", ] +[[package]] +name = "webpki-roots" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82015b7e0b8bad8185994674a13a93306bea76cf5a16c5a181382fd3a5ec2376" +dependencies = [ + "webpki", +] + [[package]] name = "wepoll-sys" version = "3.0.1" @@ -4256,6 +4383,15 @@ dependencies = [ "zeroize 1.2.0", ] +[[package]] +name = "xattr" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "244c3741f4240ef46274860397c7c74e50eb23624996930e484c16679633a54c" +dependencies = [ + "libc", +] + [[package]] name = "yamux" version = "0.8.0" diff --git a/swap/Cargo.toml b/swap/Cargo.toml index d9d15118..73f926d3 100644 --- a/swap/Cargo.toml +++ b/swap/Cargo.toml @@ -13,6 +13,7 @@ name = "swap" [dependencies] anyhow = "1" +async-compression = { version = "0.3", features = ["bzip2", "tokio"] } async-recursion = "0.3.1" async-trait = "0.1" atty = "0.2" @@ -36,7 +37,7 @@ pem = "0.8" prettytable-rs = "0.8" rand = "0.7" rand_chacha = "0.2.0" -reqwest = { version = "0.11", default-features = false } +reqwest = { version = "0.11", features = ["rustls-tls", "stream"], default-features = false } rust_decimal = "1.10" serde = { version = "1", features = ["derive"] } serde_cbor = "0.11" @@ -48,8 +49,10 @@ structopt = "0.3" strum = { version = "0.20", features = ["derive"] } thiserror = "1" time = "0.2" -tokio = { version = "1.0", features = ["rt-multi-thread", "time", "macros", "sync"] } +tokio = { version = "1.0", features = ["rt-multi-thread", "time", "macros", "sync", "process", "fs"] } +tokio-tar = { path = "../tokio-tar" } tokio-tungstenite = { version = "0.13", features = [ "tls" ] } +tokio-util = { version = "0.6.3", features = ["io"] } toml = "0.5" tracing = { version = "0.1", features = ["attributes"] } tracing-futures = { version = "0.2", features = ["std-future", "futures-03"] } diff --git a/swap/src/bin/swap_cli.rs b/swap/src/bin/swap_cli.rs index 4b13e6ba..c4fed8c1 100644 --- a/swap/src/bin/swap_cli.rs +++ b/swap/src/bin/swap_cli.rs @@ -14,6 +14,7 @@ use anyhow::{Context, Result}; use prettytable::{row, Table}; +use reqwest::Url; use std::{path::Path, sync::Arc}; use structopt::StructOpt; use swap::{ @@ -84,6 +85,12 @@ async fn main() -> Result<()> { let monero_network = monero::Network::Stagenet; let execution_params = execution_params::Testnet::get_execution_params(); + let monero_wallet_rpc = monero::WalletRpc::new(config.data.dir.join("monero")).await?; + + let monero_wallet_rpc_process = monero_wallet_rpc + .run(monero_network, "stagenet.community.xmr.to") + .await?; + match opt.cmd { Command::BuyXmr { alice_peer_id, @@ -96,6 +103,7 @@ async fn main() -> Result<()> { &wallet_data_dir, monero_network, seed, + monero_wallet_rpc_process.endpoint(), ) .await?; @@ -149,6 +157,7 @@ async fn main() -> Result<()> { &wallet_data_dir, monero_network, seed, + monero_wallet_rpc_process.endpoint(), ) .await?; @@ -180,6 +189,7 @@ async fn main() -> Result<()> { &wallet_data_dir, monero_network, seed, + monero_wallet_rpc_process.endpoint(), ) .await?; @@ -230,6 +240,7 @@ async fn main() -> Result<()> { &wallet_data_dir, monero_network, seed, + monero_wallet_rpc_process.endpoint(), ) .await?; @@ -268,6 +279,7 @@ async fn init_wallets( bitcoin_wallet_data_dir: &Path, monero_network: monero::Network, seed: Seed, + monero_wallet_rpc_url: Url, ) -> Result<(bitcoin::Wallet, monero::Wallet)> { let bitcoin_wallet = bitcoin::Wallet::new( config.bitcoin.electrum_rpc_url, @@ -290,7 +302,7 @@ async fn init_wallets( ); let monero_wallet = monero::Wallet::new( - config.monero.wallet_rpc_url.clone(), + monero_wallet_rpc_url.clone(), monero_network, MONERO_BLOCKCHAIN_MONITORING_WALLET_NAME.to_string(), ); @@ -306,7 +318,7 @@ async fn init_wallets( .context(format!( "Unable to create Monero wallet for blockchain monitoring.\ Please ensure that the monero-wallet-rpc is available at {}", - config.monero.wallet_rpc_url + monero_wallet_rpc_url ))?; info!( diff --git a/swap/src/cli/config.rs b/swap/src/cli/config.rs index 2252f181..156fe269 100644 --- a/swap/src/cli/config.rs +++ b/swap/src/cli/config.rs @@ -13,13 +13,11 @@ use url::Url; pub const DEFAULT_ELECTRUM_HTTP_URL: &str = "https://blockstream.info/testnet/api/"; const DEFAULT_ELECTRUM_RPC_URL: &str = "ssl://electrum.blockstream.info:60002"; -const DEFAULT_MONERO_WALLET_RPC_TESTNET_URL: &str = "http://127.0.0.1:38083/json_rpc"; #[derive(Clone, Debug, serde::Serialize, serde::Deserialize, PartialEq)] pub struct Config { pub data: Data, pub bitcoin: Bitcoin, - pub monero: Monero, } impl Config { @@ -48,12 +46,6 @@ pub struct Bitcoin { pub electrum_rpc_url: Url, } -#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)] -#[serde(deny_unknown_fields)] -pub struct Monero { - pub wallet_rpc_url: Url, -} - #[derive(thiserror::Error, Debug, Clone, Copy)] #[error("config not initialized")] pub struct ConfigNotInitialized {} @@ -118,11 +110,6 @@ pub fn query_user_for_initial_testnet_config() -> Result { .interact_text()?; let electrum_rpc_url = Url::parse(electrum_rpc_url.as_str())?; - let monero_wallet_rpc_url = Input::with_theme(&ColorfulTheme::default()) - .with_prompt("Enter Monero Wallet RPC URL or hit enter to use default") - .default(DEFAULT_MONERO_WALLET_RPC_TESTNET_URL.to_owned()) - .interact_text()?; - let monero_wallet_rpc_url = monero_wallet_rpc_url.as_str().parse()?; println!(); Ok(Config { @@ -131,9 +118,6 @@ pub fn query_user_for_initial_testnet_config() -> Result { electrum_http_url, electrum_rpc_url, }, - monero: Monero { - wallet_rpc_url: monero_wallet_rpc_url, - }, }) } @@ -156,9 +140,6 @@ mod tests { electrum_http_url: Url::from_str(DEFAULT_ELECTRUM_HTTP_URL).unwrap(), electrum_rpc_url: Url::from_str(DEFAULT_ELECTRUM_RPC_URL).unwrap(), }, - monero: Monero { - wallet_rpc_url: Url::from_str("http://127.0.0.1:38083/json_rpc").unwrap(), - }, }; initial_setup(config_path.clone(), || Ok(expected.clone())).unwrap(); diff --git a/swap/src/monero.rs b/swap/src/monero.rs index e17e137b..38b091b0 100644 --- a/swap/src/monero.rs +++ b/swap/src/monero.rs @@ -1,8 +1,10 @@ pub mod wallet; +mod wallet_rpc; pub use ::monero::{Network, PrivateKey, PublicKey}; pub use curve25519_dalek::scalar::Scalar; pub use wallet::Wallet; +pub use wallet_rpc::{WalletRpc, WalletRpcProcess}; use crate::bitcoin; use ::bitcoin::hashes::core::fmt::Formatter; diff --git a/swap/src/monero/wallet_rpc.rs b/swap/src/monero/wallet_rpc.rs new file mode 100644 index 00000000..82328210 --- /dev/null +++ b/swap/src/monero/wallet_rpc.rs @@ -0,0 +1,164 @@ +use ::monero::Network; +use anyhow::{Context, Result}; +use async_compression::tokio::bufread::BzDecoder; +use futures::{StreamExt, TryStreamExt}; +use reqwest::Url; +use std::{ + io::ErrorKind, + path::{Path, PathBuf}, + process::Stdio, +}; +use tokio::{ + fs::{remove_file, OpenOptions}, + io::{AsyncBufReadExt, AsyncWriteExt, BufReader}, + process::{Child, Command}, +}; +use tokio_tar::Archive; +use tokio_util::{ + codec::{BytesCodec, FramedRead}, + io::StreamReader, +}; + +#[cfg(target_os = "macos")] +const DOWNLOAD_URL: &str = "http://downloads.getmonero.org/cli/monero-mac-x64-v0.17.1.9.tar.bz2"; + +#[cfg(target_os = "linux")] +const DOWNLOAD_URL: &str = "https://downloads.getmonero.org/cli/monero-linux-x64-v0.17.1.9.tar.bz2"; + +#[cfg(not(any(target_os = "macos", target_os = "linux")))] +compile_error!("unsupported operating system"); + +const PACKED_FILE: &str = "monero-wallet-rpc"; + +pub struct WalletRpcProcess { + _child: Child, + port: u16, +} + +impl WalletRpcProcess { + pub fn endpoint(&self) -> Url { + Url::parse(&format!("http://127.0.0.1:{}/json_rpc", self.port)) + .expect("Static url template is always valid") + } +} + +pub struct WalletRpc { + working_dir: PathBuf, +} + +impl WalletRpc { + pub async fn new(working_dir: impl AsRef) -> Result { + let working_dir = working_dir.as_ref(); + + if !working_dir.exists() { + tokio::fs::create_dir(working_dir).await?; + } + + let monero_wallet_rpc = WalletRpc { + working_dir: working_dir.to_path_buf(), + }; + + if monero_wallet_rpc.tar_path().exists() { + remove_file(monero_wallet_rpc.tar_path()).await?; + } + + if !monero_wallet_rpc.exec_path().exists() { + let mut options = OpenOptions::new(); + let mut file = options + .read(true) + .write(true) + .create_new(true) + .open(monero_wallet_rpc.tar_path()) + .await?; + + let byte_stream = reqwest::get(DOWNLOAD_URL) + .await? + .bytes_stream() + .map_err(|err| std::io::Error::new(ErrorKind::Other, err)); + + let mut stream = FramedRead::new( + BzDecoder::new(StreamReader::new(byte_stream)), + BytesCodec::new(), + ) + .map_ok(|bytes| bytes.freeze()); + + while let Some(chunk) = stream.next().await { + file.write(&chunk?).await?; + } + + file.flush().await?; + + let mut options = OpenOptions::new(); + let file = options + .read(true) + .open(monero_wallet_rpc.tar_path()) + .await?; + + let mut ar = Archive::new(file); + let mut entries = ar.entries()?; + + while let Some(file) = entries.next().await { + let mut f = file?; + if f.path()? + .to_str() + .context("Could not find convert path to str in tar ball")? + .contains(PACKED_FILE) + { + f.unpack(monero_wallet_rpc.exec_path()).await?; + } + } + + remove_file(monero_wallet_rpc.tar_path()).await?; + } + + Ok(monero_wallet_rpc) + } + pub async fn run(&self, network: Network, daemon_host: &str) -> Result { + let port = tokio::net::TcpListener::bind("127.0.0.1:0") + .await? + .local_addr()? + .port(); + + let mut child = Command::new(self.exec_path()) + .stdout(Stdio::piped()) + .kill_on_drop(true) + .arg(match network { + Network::Mainnet => "--mainnet", + Network::Stagenet => "--stagenet", + Network::Testnet => "--testnet", + }) + .arg("--daemon-host") + .arg(daemon_host) + .arg("--rpc-bind-port") + .arg(format!("{}", port)) + .arg("--disable-rpc-login") + .arg("--wallet-dir") + .arg(self.working_dir.join("monero-data")) + .spawn()?; + + let stdout = child + .stdout + .take() + .expect("monero wallet rpc stdout was not piped parent process"); + + let mut reader = BufReader::new(stdout).lines(); + + while let Some(line) = reader.next_line().await? { + if line.contains("Starting wallet RPC server") { + break; + } + } + Ok(WalletRpcProcess { + _child: child, + port, + }) + } + + fn tar_path(&self) -> PathBuf { + self.working_dir.join("monero-cli-wallet.tar") + } + + fn exec_path(&self) -> PathBuf { + self.working_dir.join(PACKED_FILE) + } +} diff --git a/tokio-tar/src/archive.rs b/tokio-tar/src/archive.rs index 1e4d3b3b..6bccf558 100644 --- a/tokio-tar/src/archive.rs +++ b/tokio-tar/src/archive.rs @@ -98,10 +98,11 @@ impl ArchiveBuilder { self } - /// Ignore zeroed headers, which would otherwise indicate to the archive that it has no more - /// entries. + /// Ignore zeroed headers, which would otherwise indicate to the archive + /// that it has no more entries. /// - /// This can be used in case multiple tar archives have been concatenated together. + /// This can be used in case multiple tar archives have been concatenated + /// together. pub fn set_ignore_zeros(mut self, ignore_zeros: bool) -> Self { self.ignore_zeros = ignore_zeros; self @@ -365,8 +366,8 @@ fn poll_next_raw( } // If a header is not all zeros, we have another valid header. - // Otherwise, check if we are ignoring zeros and continue, or break as if this is the - // end of the archive. + // Otherwise, check if we are ignoring zeros and continue, or break as if this + // is the end of the archive. if !header.as_bytes().iter().all(|i| *i == 0) { *next += 512; break; @@ -559,8 +560,8 @@ impl Read for Archive { /// Try to fill the buffer from the reader. /// -/// If the reader reaches its end before filling the buffer at all, returns `false`. -/// Otherwise returns `true`. +/// If the reader reaches its end before filling the buffer at all, returns +/// `false`. Otherwise returns `true`. fn poll_try_read_all( mut source: R, cx: &mut Context<'_>, diff --git a/tokio-tar/src/builder.rs b/tokio-tar/src/builder.rs index 08c46ba0..15e008b1 100644 --- a/tokio-tar/src/builder.rs +++ b/tokio-tar/src/builder.rs @@ -597,7 +597,8 @@ async fn append_dir_all( while let Some((src, is_dir, is_symlink)) = stack.pop() { let dest = path.join(src.strip_prefix(&src_path).unwrap()); - // In case of a symlink pointing to a directory, is_dir is false, but src.is_dir() will return true + // In case of a symlink pointing to a directory, is_dir is false, but + // src.is_dir() will return true if is_dir || (is_symlink && follow && src.is_dir()) { let mut entries = fs::read_dir(&src).await?; while let Some(entry) = entries.next_entry().await.transpose() { diff --git a/tokio-tar/src/entry.rs b/tokio-tar/src/entry.rs index e239799b..d6cec73d 100644 --- a/tokio-tar/src/entry.rs +++ b/tokio-tar/src/entry.rs @@ -144,8 +144,8 @@ impl Entry { /// Returns the link name for this entry, in bytes, if listed. /// /// Note that this will not always return the same value as - /// `self.header().link_name_bytes()` as some archive formats have support for - /// longer path names described in separate entries. + /// `self.header().link_name_bytes()` as some archive formats have support + /// for longer path names described in separate entries. pub fn link_name_bytes(&self) -> Option> { self.fields.link_name_bytes() } @@ -414,14 +414,12 @@ impl EntryFields { async fn unpack_in(&mut self, dst: &Path) -> io::Result { // Notes regarding bsdtar 2.8.3 / libarchive 2.8.3: - // * Leading '/'s are trimmed. For example, `///test` is treated as - // `test`. - // * If the filename contains '..', then the file is skipped when - // extracting the tarball. - // * '//' within a filename is effectively skipped. An error is - // logged, but otherwise the effect is as if any two or more - // adjacent '/'s within the filename were consolidated into one - // '/'. + // * Leading '/'s are trimmed. For example, `///test` is treated as `test`. + // * If the filename contains '..', then the file is skipped when extracting the + // tarball. + // * '//' within a filename is effectively skipped. An error is logged, but + // otherwise the effect is as if any two or more adjacent '/'s within the + // filename were consolidated into one '/'. // // Most of this is handled by the `path` module of the standard // library, but we specially handle a few cases here as well. diff --git a/tokio-tar/src/header.rs b/tokio-tar/src/header.rs index 71f0deed..34769c6e 100644 --- a/tokio-tar/src/header.rs +++ b/tokio-tar/src/header.rs @@ -777,7 +777,8 @@ impl Header { #[cfg(windows)] fn fill_platform_from(&mut self, meta: &Metadata, mode: HeaderMode) { - // There's no concept of a file mode on Windows, so do a best approximation here. + // There's no concept of a file mode on Windows, so do a best approximation + // here. match mode { HeaderMode::Complete => { self.set_uid(0); @@ -1100,7 +1101,8 @@ impl GnuHeader { truncate(&self.uname) } - /// Gets the fullname (group:user) in a "lossy" way, used for error reporting ONLY. + /// Gets the fullname (group:user) in a "lossy" way, used for error + /// reporting ONLY. fn fullname_lossy(&self) -> String { format!( "{}:{}", diff --git a/tokio-tar/tests/all.rs b/tokio-tar/tests/all.rs index 7fefb10a..46c8841f 100644 --- a/tokio-tar/tests/all.rs +++ b/tokio-tar/tests/all.rs @@ -37,8 +37,8 @@ macro_rules! tar { mod header; -/// test that we can concatenate the simple.tar archive and extract the same entries twice when we -/// use the ignore_zeros option. +/// test that we can concatenate the simple.tar archive and extract the same +/// entries twice when we use the ignore_zeros option. #[tokio::test] async fn simple_concat() { let bytes = tar!("simple.tar"); @@ -52,7 +52,8 @@ async fn simple_concat() { // concat two archives (with null in-between); archive_bytes.extend(bytes); - // test now that when we read the archive, it stops processing at the first zero header. + // test now that when we read the archive, it stops processing at the first zero + // header. let actual = decode_names(&mut Archive::new(Cursor::new(&archive_bytes))).await; assert_eq!(expected, actual); diff --git a/tokio-tar/tests/header/mod.rs b/tokio-tar/tests/header/mod.rs index 33f479d4..d4812655 100644 --- a/tokio-tar/tests/header/mod.rs +++ b/tokio-tar/tests/header/mod.rs @@ -189,7 +189,8 @@ fn set_metadata_deterministic() { h } - // Create "the same" File twice in a row, one second apart, with differing readonly values. + // Create "the same" File twice in a row, one second apart, with differing + // readonly values. let one = mk_header(tmppath.as_path(), false); thread::sleep(time::Duration::from_millis(1050)); let two = mk_header(tmppath.as_path(), true);