Skip to content

Commit

Permalink
Merge #45
Browse files Browse the repository at this point in the history
45: Support copying an image without a bmap file r=obbardc a=Razaloc

--nobmap or -n flag allows copying without a bmap file.
Closes: #39

Signed-off-by: Rafael Garcia Ruiz <[email protected]>

Co-authored-by: Rafael Garcia Ruiz <[email protected]>
  • Loading branch information
bors[bot] and Razaloc authored Jan 16, 2023
2 parents 786c786 + 6385261 commit 6f01e88
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 2 deletions.
19 changes: 19 additions & 0 deletions bmap-parser/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,25 @@ where

position = range.offset() + range.length();
}
Ok(())
}

pub fn copy_nobmap<I, O>(input: &mut I, output: &mut O) -> Result<(), CopyError>
where
I: Read,
O: Write,
{
std::io::copy(input, output).map_err(CopyError::WriteError)?;
Ok(())
}

pub async fn copy_async_nobmap<I, O>(input: &mut I, output: &mut O) -> Result<(), CopyError>
where
I: AsyncRead + AsyncSeekForward + Unpin,
O: AsyncWrite + AsyncSeekForward + Unpin,
{
futures::io::copy(input, output)
.map_err(CopyError::WriteError)
.await?;
Ok(())
}
67 changes: 65 additions & 2 deletions bmap-rs/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use anyhow::{anyhow, bail, ensure, Context, Result};
use async_compression::futures::bufread::GzipDecoder;
use bmap_parser::{AsyncDiscarder, Bmap, Discarder, SeekForward};
use clap::{arg, command, Command};
use clap::{arg, command, Arg, ArgAction, Command};
use flate2::read::GzDecoder;
use futures::TryStreamExt;
use indicatif::{ProgressBar, ProgressState, ProgressStyle};
Expand All @@ -25,6 +25,7 @@ enum Image {
struct Copy {
image: Image,
dest: PathBuf,
nobmap: bool,
}

#[derive(Debug)]
Expand All @@ -48,7 +49,13 @@ impl Opts {
Command::new("copy")
.about("Copy image to block device or file")
.arg(arg!([IMAGE]).required(true))
.arg(arg!([DESTINATION]).required(true)),
.arg(arg!([DESTINATION]).required(true))
.arg(
Arg::new("nobmap")
.short('n')
.long("nobmap")
.action(ArgAction::SetTrue),
),
)
.get_matches();
match matches.subcommand() {
Expand All @@ -62,6 +69,7 @@ impl Opts {
)),
},
dest: PathBuf::from(sub_matches.get_one::<String>("DESTINATION").unwrap()),
nobmap: sub_matches.get_flag("nobmap"),
}
}),
},
Expand Down Expand Up @@ -159,6 +167,12 @@ fn setup_progress_bar(bmap: &Bmap) -> ProgressBar {
pb
}

fn setup_spinner() -> ProgressBar {
let pb = ProgressBar::new_spinner();
pb.set_style(ProgressStyle::with_template("{spinner:.green} {msg}").unwrap());
pb
}

fn setup_output<T: AsRawFd>(output: &T, bmap: &Bmap, metadata: std::fs::Metadata) -> Result<()> {
if metadata.is_file() {
ftruncate(output.as_raw_fd(), bmap.image_size() as i64)
Expand All @@ -168,6 +182,12 @@ fn setup_output<T: AsRawFd>(output: &T, bmap: &Bmap, metadata: std::fs::Metadata
}

async fn copy(c: Copy) -> Result<()> {
if c.nobmap {
return match c.image {
Image::Path(path) => copy_local_input_nobmap(path, c.dest),
Image::Url(url) => copy_remote_input_nobmap(url, c.dest).await,
};
}
match c.image {
Image::Path(path) => copy_local_input(path, c.dest),
Image::Url(url) => copy_remote_input(url, c.dest).await,
Expand Down Expand Up @@ -235,7 +255,50 @@ async fn copy_remote_input(source: Url, destination: PathBuf) -> Result<()> {

println!("Done: Syncing...");
output.sync_all().await?;
Ok(())
}

fn copy_local_input_nobmap(source: PathBuf, destination: PathBuf) -> Result<()> {
ensure!(source.exists(), "Image file doesn't exist");

let output = std::fs::OpenOptions::new()
.write(true)
.create(true)
.open(destination)?;

let mut input = setup_local_input(&source)?;

let pb = setup_spinner();
bmap_parser::copy_nobmap(&mut input, &mut pb.wrap_write(&output))?;
pb.finish_and_clear();

println!("Done: Syncing...");
output.sync_all().expect("Sync failure");

Ok(())
}

async fn copy_remote_input_nobmap(source: Url, destination: PathBuf) -> Result<()> {
let mut output = tokio::fs::OpenOptions::new()
.write(true)
.create(true)
.open(destination)
.await?;

let res = setup_remote_input(source).await?;
let stream = res
.bytes_stream()
.map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e))
.into_async_read();
let reader = GzipDecoder::new(stream);
let mut input = AsyncDiscarder::new(reader);
let pb = setup_spinner();
bmap_parser::copy_async_nobmap(&mut input, &mut pb.wrap_async_write(&mut output).compat())
.await?;
pb.finish_and_clear();

println!("Done: Syncing...");
output.sync_all().await?;
Ok(())
}

Expand Down

0 comments on commit 6f01e88

Please sign in to comment.