Skip to content

Commit

Permalink
Add the option to use reflinks (i.e. copy on write semantics).
Browse files Browse the repository at this point in the history
Using the reflink crate, with the option to disallow completely
(never), auto (use when available), or always (fail if not possible).
  • Loading branch information
Markus Wanner committed Apr 21, 2020
1 parent f75439c commit 1140e53
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 2 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,4 @@ include = [
]

[dependencies]
reflink = "0.1"
6 changes: 5 additions & 1 deletion src/dir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@ use std::convert::From;
use std::fs::{create_dir, create_dir_all, read_dir, remove_dir_all, Metadata};
use std::path::{Path, PathBuf};
use std::time::SystemTime;
use super::RefLinkUsage;

/// Options and flags which can be used to configure how a file will be copied or moved.
#[derive(Clone)]
#[derive(Debug, Copy, Clone)]
pub struct CopyOptions {
/// Sets the option true for overwrite existing files.
pub overwrite: bool,
Expand All @@ -22,6 +23,8 @@ pub struct CopyOptions {
///
/// Warrning: Work only for copy operations!
pub depth: u64,
/// Controls the usage of reflinks for files on filesystems supporting it.
pub reflink: RefLinkUsage,
}

impl CopyOptions {
Expand All @@ -44,6 +47,7 @@ impl CopyOptions {
copy_inside: false,
content_only: false,
depth: 0,
reflink: RefLinkUsage::Never,
}
}
}
Expand Down
25 changes: 24 additions & 1 deletion src/file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use std::convert::From;
use std::fs::{remove_file, File};
use std::io::{Read, Write};
use std::path::Path;
use super::RefLinkUsage;

/// Options and flags which can be used to configure how a file will be copied or moved.
#[derive(Debug, Copy, Clone)]
Expand All @@ -14,6 +15,8 @@ pub struct CopyOptions {
pub skip_exist: bool,
/// Sets buffer size for copy/move work only with receipt information about process work.
pub buffer_size: usize,
/// Controls the usage of reflinks on filesystems supporting it.
pub reflink: RefLinkUsage,
}

impl CopyOptions {
Expand All @@ -32,6 +35,7 @@ impl CopyOptions {
overwrite: false,
skip_exist: false,
buffer_size: 64000, //64kb
reflink: RefLinkUsage::Never,
}
}
}
Expand All @@ -42,6 +46,7 @@ impl From<&super::dir::CopyOptions> for CopyOptions {
overwrite: dir_options.overwrite,
skip_exist: dir_options.skip_exist,
buffer_size: dir_options.buffer_size,
reflink: dir_options.reflink,
}
}
}
Expand Down Expand Up @@ -112,7 +117,14 @@ where
}
}

Ok(std::fs::copy(from, to)?)
Ok(match options.reflink {
RefLinkUsage::Never => std::fs::copy(from, to)?,
RefLinkUsage::Auto => reflink::reflink_or_copy(from, to)?.unwrap_or(0),
RefLinkUsage::Always => {
reflink::reflink(from, to)?;
0
},
})
}

/// Copies the contents of one file to another with recept information about process.
Expand Down Expand Up @@ -181,6 +193,17 @@ where
err!(&msg, ErrorKind::AlreadyExists);
}
}

if options.reflink != RefLinkUsage::Never {
match reflink::reflink(&from, &to) {
Ok(()) => return Ok(0),
Err(e) if options.reflink == RefLinkUsage::Always => {
return Err(::std::convert::From::from(e));
},
Err(_) => { /* continue with plain copy */ }
}
}

let mut file_from = File::open(from)?;
let mut buf = vec![0; options.buffer_size];
let file_size = file_from.metadata()?.len();
Expand Down
14 changes: 14 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
extern crate reflink;

macro_rules! err {
($text:expr, $kind:expr) => {
return Err(Error::new($kind, $text));
Expand Down Expand Up @@ -152,6 +154,18 @@ pub mod dir;
use error::*;
use std::path::Path;

/// Possible values for the reflink field in CopyOptions. These
/// correspond to the `--reflink` option of the Unix `cp` command.
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum RefLinkUsage {
/// Do not use reflinks.
Never,
/// Use reflinks if possible.
Auto,
/// Force use of reflinks, error out if not possible.
Always,
}

/// Copies list directories and files to another place using recursive method. This function will
/// also copy the permission bits of the original files to destionation files (not for
/// directories).
Expand Down

0 comments on commit 1140e53

Please sign in to comment.