Skip to content

Commit

Permalink
Add fs utilities
Browse files Browse the repository at this point in the history
Add dependency `remove_dir_all`
Note: On windows `std::fs::remove_dir_all` doesn't really work (rust-lang/rust#29497).
  • Loading branch information
N3xed committed Aug 31, 2021
1 parent 0909ae3 commit a4c48e6
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 0 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,4 @@ bindgen = "0.57"
xmas-elf = "0.8"
bitflags = "1.3"
shlex = "1.0"
remove_dir_all = "0.7"
88 changes: 88 additions & 0 deletions src/fs.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
//! Filesystem utilities

use std::fs::{self, File};
use std::io::{self, Read, Seek};
use std::path::Path;

use anyhow::Result;

pub use remove_dir_all::*;

/// Copy `src_file` to `dest_file_or_dir` if `src_file` is different or the destination
/// file doesn't exist.
pub fn copy_file_if_different(
src_file: impl AsRef<Path>,
dest_file_or_dir: impl AsRef<Path>,
) -> Result<()> {
let src_file: &Path = src_file.as_ref();
let dest_file_or_dir: &Path = dest_file_or_dir.as_ref();

assert!(src_file.is_file());

let mut src_fd = fs::File::open(src_file)?;

let (dest_fd, dest_file) = if dest_file_or_dir.exists() {
if dest_file_or_dir.is_dir() {
let dest_file = dest_file_or_dir.join(src_file.file_name().unwrap());
if dest_file.exists() {
(Some(fs::File::open(&dest_file)?), dest_file)
} else {
(None, dest_file)
}
} else {
(
Some(fs::File::open(dest_file_or_dir)?),
dest_file_or_dir.to_owned(),
)
}
} else {
(None, dest_file_or_dir.to_owned())
};

if let Some(mut dest_fd) = dest_fd {
if !is_file_eq(&mut src_fd, &mut dest_fd)? {
drop(dest_fd);
drop(src_fd);
fs::copy(src_file, dest_file)?;
}
} else {
fs::copy(src_file, dest_file)?;
}
Ok(())
}

/// Whether the file type and contents of `file` are equal to `other`.
pub fn is_file_eq(file: &mut File, other: &mut File) -> Result<bool> {
let file_meta = file.metadata()?;
let other_meta = other.metadata()?;

if file_meta.file_type() == other_meta.file_type() && file_meta.len() == other_meta.len() {
let mut file_bytes = io::BufReader::new(&*file).bytes();
let mut other_bytes = io::BufReader::new(&*other).bytes();

// TODO: check performance
let result = loop {
match (file_bytes.next(), other_bytes.next()) {
(Some(Ok(b0)), Some(Ok(b1))) => {
if b0 != b1 {
break Ok(false);
}
}
(None, None) => break Ok(true),
(None, Some(_)) | (Some(_), None) => break Ok(false),
(Some(Err(e)), _) | (_, Some(Err(e))) => return Err(e.into()),
}
};
drop(file_bytes);
drop(other_bytes);

// rewind files
// TODO: is this needed?
file.seek(io::SeekFrom::Start(0))?;
other.seek(io::SeekFrom::Start(0))?;

result
} else {
Ok(false)
}
}
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ pub mod pio;
pub mod python;
pub mod symgen;
pub mod utils;
pub mod fs;

0 comments on commit a4c48e6

Please sign in to comment.