Skip to content

Commit d8f3186

Browse files
committed
Add the option to use reflinks (i.e. copy on write semantics).
Using the reflink crate, with the option to disallow completely (never), auto (use when available), or always (fail if not possible). Conditional on the new feature "copy_on_write", enabled by default (given this already is an "extra" crate).
1 parent aaaa003 commit d8f3186

File tree

4 files changed

+56
-2
lines changed

4 files changed

+56
-2
lines changed

Cargo.toml

+5
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,9 @@ include = [
1616
"CHANGELOG.md",
1717
]
1818

19+
[features]
20+
default = ["copy_on_write"]
21+
copy_on_write = ["reflink"]
22+
1923
[dependencies]
24+
reflink = { version = "^0.1.0", optional = true }

src/dir.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,10 @@ use std::convert::From;
44
use std::fs::{create_dir, create_dir_all, read_dir, remove_dir_all, Metadata};
55
use std::path::{Path, PathBuf};
66
use std::time::SystemTime;
7+
use super::RefLinkUsage;
78

89
/// Options and flags which can be used to configure how a file will be copied or moved.
9-
#[derive(Clone)]
10+
#[derive(Debug, Copy, Clone)]
1011
pub struct CopyOptions {
1112
/// Sets the option true for overwrite existing files.
1213
pub overwrite: bool,
@@ -22,6 +23,8 @@ pub struct CopyOptions {
2223
///
2324
/// Warning: Work only for copy operations!
2425
pub depth: u64,
26+
/// Controls the usage of reflinks for files on filesystems supporting it.
27+
pub reflink: RefLinkUsage,
2528
}
2629

2730
impl CopyOptions {
@@ -44,6 +47,7 @@ impl CopyOptions {
4447
copy_inside: false,
4548
content_only: false,
4649
depth: 0,
50+
reflink: RefLinkUsage::Never,
4751
}
4852
}
4953
}

src/file.rs

+29-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use std::convert::From;
44
use std::fs::{remove_file, File};
55
use std::io::{Read, Write};
66
use std::path::Path;
7+
use super::RefLinkUsage;
78

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

1922
impl CopyOptions {
@@ -32,6 +35,7 @@ impl CopyOptions {
3235
overwrite: false,
3336
skip_exist: false,
3437
buffer_size: 64000, //64kb
38+
reflink: RefLinkUsage::Never,
3539
}
3640
}
3741
}
@@ -48,6 +52,7 @@ impl From<&super::dir::CopyOptions> for CopyOptions {
4852
overwrite: dir_options.overwrite,
4953
skip_exist: dir_options.skip_exist,
5054
buffer_size: dir_options.buffer_size,
55+
reflink: dir_options.reflink,
5156
}
5257
}
5358
}
@@ -118,7 +123,18 @@ where
118123
}
119124
}
120125

121-
Ok(std::fs::copy(from, to)?)
126+
Ok(match options.reflink {
127+
RefLinkUsage::Never => std::fs::copy(from, to)?,
128+
129+
#[cfg(feature = "copy_on_write")]
130+
RefLinkUsage::Auto => reflink::reflink_or_copy(from, to)?.unwrap_or(0),
131+
132+
#[cfg(feature = "copy_on_write")]
133+
RefLinkUsage::Always => {
134+
reflink::reflink(from, to)?;
135+
0
136+
},
137+
})
122138
}
123139

124140
/// Copies the contents of one file to another with recept information about process.
@@ -187,6 +203,18 @@ where
187203
err!(&msg, ErrorKind::AlreadyExists);
188204
}
189205
}
206+
207+
#[cfg(feature = "copy_on_write")]
208+
if options.reflink != RefLinkUsage::Never {
209+
match reflink::reflink(&from, &to) {
210+
Ok(()) => return Ok(0),
211+
Err(e) if options.reflink == RefLinkUsage::Always => {
212+
return Err(::std::convert::From::from(e));
213+
},
214+
Err(_) => { /* continue with plain copy */ }
215+
}
216+
}
217+
190218
let mut file_from = File::open(from)?;
191219
let mut buf = vec![0; options.buffer_size];
192220
let file_size = file_from.metadata()?.len();

src/lib.rs

+17
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
#[cfg(feature = "copy_on_write")]
2+
extern crate reflink;
3+
14
macro_rules! err {
25
($text:expr, $kind:expr) => {
36
return Err(Error::new($kind, $text));
@@ -156,6 +159,20 @@ pub mod dir;
156159
use error::*;
157160
use std::path::Path;
158161

162+
/// Possible values for the reflink field in CopyOptions. These
163+
/// correspond to the `--reflink` option of the Unix `cp` command.
164+
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
165+
pub enum RefLinkUsage {
166+
/// Do not use reflinks.
167+
Never,
168+
/// Use reflinks if possible.
169+
#[cfg(feature = "copy_on_write")]
170+
Auto,
171+
/// Force use of reflinks, error out if not possible.
172+
#[cfg(feature = "copy_on_write")]
173+
Always,
174+
}
175+
159176
/// Copies list directories and files to another place using recursive method. This function will
160177
/// also copy the permission bits of the original files to destionation files (not for
161178
/// directories).

0 commit comments

Comments
 (0)