summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/filesize.rs23
-rw-r--r--src/lib.rs8
-rw-r--r--src/main.rs24
-rw-r--r--src/walk.rs17
-rw-r--r--tests/walk.rs4
5 files changed, 61 insertions, 15 deletions
diff --git a/src/filesize.rs b/src/filesize.rs
new file mode 100644
index 0000000..0ac4c7e
--- /dev/null
+++ b/src/filesize.rs
@@ -0,0 +1,23 @@
+#[derive(Debug, Clone, Copy)]
+pub enum FilesizeType {
+ DiskUsage,
+ ApparentSize,
+}
+
+impl FilesizeType {
+ #[cfg(not(windows))]
+ pub fn size(self, metadata: &std::fs::Metadata) -> u64 {
+ use std::os::unix::fs::MetadataExt;
+
+ match self {
+ Self::ApparentSize => metadata.len(),
+ // block size is always 512 byte, see stat(2) manpage
+ Self::DiskUsage => metadata.blocks() * 512,
+ }
+ }
+
+ #[cfg(windows)]
+ pub fn size(self, metadata: &std::fs::Metadata) -> u64 {
+ metadata.len()
+ }
+}
diff --git a/src/lib.rs b/src/lib.rs
index 0867b2b..5f2b447 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -2,15 +2,17 @@
//!
//! ```
//! use std::path::PathBuf;
-//! use diskus::Walk;
+//! use diskus::{Walk, FilesizeType};
//!
//! let num_threads = 4;
//! let root_directories = &[PathBuf::from(".")];
-//! let walk = Walk::new(root_directories, num_threads);
+//! let walk = Walk::new(root_directories, num_threads, FilesizeType::DiskUsage);
//! let (size_in_bytes, errors) = walk.run();
//! ```
+mod filesize;
mod unique_id;
pub mod walk;
-pub use crate::walk::Walk;
+pub use crate::filesize::FilesizeType;
+pub use crate::walk::{Error, Walk};
diff --git a/src/main.rs b/src/main.rs
index 57f7c9e..693003d 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -5,19 +5,19 @@ use humansize::file_size_opts::{self, FileSizeOpts};
use humansize::FileSize;
use num_format::{Locale, ToFormattedString};
-use diskus::walk::{self, Walk};
+use diskus::{Error, FilesizeType, Walk};
-fn print_result(size: u64, errors: &[walk::Error], size_format: &FileSizeOpts, verbose: bool) {
+fn print_result(size: u64, errors: &[Error], size_format: &FileSizeOpts, verbose: bool) {
if verbose {
for err in errors {
match err {
- walk::Error::NoMetadataForPath(path) => {
+ Error::NoMetadataForPath(path) => {
eprintln!(
"diskus: could not retrieve metadata for path '{}'",
path.to_string_lossy()
);
}
- walk::Error::CouldNotReadDir(path) => {
+ Error::CouldNotReadDir(path) => {
eprintln!(
"diskus: could not read contents of directory '{}'",
path.to_string_lossy()
@@ -80,6 +80,14 @@ fn main() {
.help("Do not hide filesystem errors"),
);
+ #[cfg(not(windows))]
+ let app = app.arg(
+ Arg::with_name("apparent-size")
+ .long("apparent-size")
+ .short("b")
+ .help("Compute apparent size instead of disk usage"),
+ );
+
let matches = app.get_matches();
// Setting the number of threads to 3x the number of cores is a good tradeoff between
@@ -97,6 +105,12 @@ fn main() {
.map(|paths| paths.map(PathBuf::from).collect())
.unwrap_or_else(|| vec![PathBuf::from(".")]);
+ let filesize_type = if matches.is_present("apparent-size") {
+ FilesizeType::ApparentSize
+ } else {
+ FilesizeType::DiskUsage
+ };
+
let size_format = match matches.value_of("size-format") {
Some("decimal") => file_size_opts::DECIMAL,
_ => file_size_opts::BINARY,
@@ -104,7 +118,7 @@ fn main() {
let verbose = matches.is_present("verbose");
- let walk = Walk::new(&paths, num_threads);
+ let walk = Walk::new(&paths, num_threads, filesize_type);
let (size, errors) = walk.run();
print_result(size, &errors, &size_format, verbose);
}
diff --git a/src/walk.rs b/src/walk.rs
index e982549..64ea982 100644
--- a/src/walk.rs
+++ b/src/walk.rs
@@ -7,6 +7,7 @@ use crossbeam_channel as channel;
use rayon::{self, prelude::*};
+use crate::filesize::FilesizeType;
use crate::unique_id::{generate_unique_id, UniqueID};
pub enum Error {
@@ -19,12 +20,12 @@ enum Message {
Error { error: Error },
}
-fn walk(tx: channel::Sender<Message>, entries: &[PathBuf]) {
+fn walk(tx: channel::Sender<Message>, entries: &[PathBuf], filesize_type: FilesizeType) {
entries.into_par_iter().for_each_with(tx, |tx_ref, entry| {
if let Ok(metadata) = entry.symlink_metadata() {
let unique_id = generate_unique_id(&metadata);
- let size = metadata.len();
+ let size = filesize_type.size(&metadata);
tx_ref.send(Message::SizeEntry(unique_id, size)).unwrap();
@@ -47,7 +48,7 @@ fn walk(tx: channel::Sender<Message>, entries: &[PathBuf]) {
}
}
- walk(tx_ref.clone(), &children[..]);
+ walk(tx_ref.clone(), &children[..], filesize_type);
};
} else {
tx_ref
@@ -62,13 +63,19 @@ fn walk(tx: channel::Sender<Message>, entries: &[PathBuf]) {
pub struct Walk<'a> {
root_directories: &'a [PathBuf],
num_threads: usize,
+ filesize_type: FilesizeType,
}
impl<'a> Walk<'a> {
- pub fn new(root_directories: &'a [PathBuf], num_threads: usize) -> Walk {
+ pub fn new(
+ root_directories: &'a [PathBuf],
+ num_threads: usize,
+ filesize_type: FilesizeType,
+ ) -> Walk {
Walk {
root_directories,
num_threads,
+ filesize_type,
}
}
@@ -103,7 +110,7 @@ impl<'a> Walk<'a> {
.num_threads(self.num_threads)
.build()
.unwrap();
- pool.install(|| walk(tx, self.root_directories));
+ pool.install(|| walk(tx, self.root_directories, self.filesize_type));
receiver_thread.join().unwrap()
}
diff --git a/tests/walk.rs b/tests/walk.rs
index 5f2d3d2..6e1dd35 100644
--- a/tests/walk.rs
+++ b/tests/walk.rs
@@ -5,7 +5,7 @@ use std::path::PathBuf;
use tempdir::TempDir;
-use diskus::Walk;
+use diskus::{FilesizeType, Walk};
#[test]
fn size_of_single_file() -> Result<(), Box<dyn Error>> {
@@ -16,7 +16,7 @@ fn size_of_single_file() -> Result<(), Box<dyn Error>> {
let num_threads = 1;
let root_directories = &[PathBuf::from(file_path)];
- let walk = Walk::new(root_directories, num_threads);
+ let walk = Walk::new(root_directories, num_threads, FilesizeType::ApparentSize);
let (size_in_bytes, errors) = walk.run();
assert!(errors.is_empty());