Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement mtime and atime copying #53

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@ language: rust
rust:
- stable
script:
- cargo build --verbose
- cargo test --verbose
- cargo doc
- cargo build --verbose --features filetime
- cargo test --verbose --features filetime
- cargo doc --features filetime
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,4 @@ include = [
]

[dependencies]
filetime = { version = "0.2", optional = true }
88 changes: 44 additions & 44 deletions src/dir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ use std::fs::{create_dir, create_dir_all, read_dir, remove_dir_all, Metadata};
use std::path::{Path, PathBuf};
use std::time::SystemTime;

#[cfg(feature = "filetime")]
use crate::time::{TimeOptions, copy_time};

/// Options and flags which can be used to configure how a file will be copied or moved.
#[derive(Clone)]
pub struct CopyOptions {
Expand All @@ -21,6 +24,9 @@ pub struct CopyOptions {
///
/// Warning: Work only for copy operations!
pub depth: u64,
/// File time options.
#[cfg(feature = "filetime")]
pub time_options: TimeOptions,
}

impl CopyOptions {
Expand All @@ -43,6 +49,8 @@ impl CopyOptions {
copy_inside: false,
content_only: false,
depth: 0,
#[cfg(feature = "filetime")]
time_options: TimeOptions::new(),
}
}
}
Expand Down Expand Up @@ -561,17 +569,9 @@ where
}

let dir_content = get_dir_content2(from, &read_options)?;
for directory in dir_content.directories {
let tmp_to = Path::new(&directory).strip_prefix(from)?;
let dir = to.join(&tmp_to);
if !dir.exists() {
if options.copy_inside {
create_all(dir, false)?;
} else {
create(dir, false)?;
}
}
}

copy_dir_structure(from, to.as_path(), &dir_content, &options);

let mut result: u64 = 0;
for file in dir_content.files {
let to = to.to_path_buf();
Expand All @@ -582,6 +582,8 @@ where
overwrite: options.overwrite,
skip_exist: options.skip_exist,
buffer_size: options.buffer_size,
#[cfg(feature = "filetime")]
time_options: options.time_options.clone(),
};
let mut result_copy: Result<u64>;
let mut work = true;
Expand Down Expand Up @@ -841,17 +843,8 @@ where
}

let dir_content = get_dir_content2(from, &read_options)?;
for directory in dir_content.directories {
let tmp_to = Path::new(&directory).strip_prefix(from)?;
let dir = to.join(&tmp_to);
if !dir.exists() {
if options.copy_inside {
create_all(dir, false)?;
} else {
create(dir, false)?;
}
}
}

copy_dir_structure(from, to.as_path(), &dir_content, &options);

let mut result: u64 = 0;
let mut info_process = TransitProcess {
Expand Down Expand Up @@ -880,6 +873,8 @@ where
overwrite: options.overwrite,
skip_exist: options.skip_exist,
buffer_size: options.buffer_size,
#[cfg(feature = "filetime")]
time_options: options.time_options.clone(),
};

if let Some(file_name) = file_name.to_str() {
Expand Down Expand Up @@ -1054,17 +1049,9 @@ where
to.push(dir_name);
}
let dir_content = get_dir_content(from)?;
for directory in dir_content.directories {
let tmp_to = Path::new(&directory).strip_prefix(from)?;
let dir = to.join(&tmp_to);
if !dir.exists() {
if options.copy_inside {
create_all(dir, false)?;
} else {
create(dir, false)?;
}
}
}

copy_dir_structure(from, to.as_path(), &dir_content, &options);

let mut result: u64 = 0;
for file in dir_content.files {
let to = to.to_path_buf();
Expand All @@ -1075,6 +1062,8 @@ where
overwrite: options.overwrite,
skip_exist: options.skip_exist,
buffer_size: options.buffer_size,
#[cfg(feature = "filetime")]
time_options: options.time_options.clone(),
};

let mut result_copy: Result<u64>;
Expand Down Expand Up @@ -1178,17 +1167,8 @@ where
}

let dir_content = get_dir_content(from)?;
for directory in dir_content.directories {
let tmp_to = Path::new(&directory).strip_prefix(from)?;
let dir = to.join(&tmp_to);
if !dir.exists() {
if options.copy_inside {
create_all(dir, false)?;
} else {
create(dir, false)?;
}
}
}

copy_dir_structure(from, to.as_path(), &dir_content, &options);

let mut result: u64 = 0;
let mut info_process = TransitProcess {
Expand Down Expand Up @@ -1217,6 +1197,8 @@ where
overwrite: options.overwrite,
skip_exist: options.skip_exist,
buffer_size: options.buffer_size,
#[cfg(feature = "filetime")]
time_options: options.time_options.clone(),
};

if let Some(file_name) = file_name.to_str() {
Expand Down Expand Up @@ -1345,3 +1327,21 @@ pub fn remove<P: AsRef<Path>>(path: P) -> Result<()> {
Ok(())
}
}

fn copy_dir_structure(from: &Path, to: &Path, dir_content: &DirContent, options: &CopyOptions) -> Result<()> {
for directory in &dir_content.directories {
let path_from = Path::new(directory);
let tmp_to = path_from.strip_prefix(from)?;
let dir = to.join(&tmp_to);
if !dir.exists() {
if options.copy_inside {
create_all(dir.as_path(), false)?;
} else {
create(dir.as_path(), false)?;
}
#[cfg(feature = "filetime")]
copy_time(&path_from, dir, &options.time_options);
}
}
Ok(())
}
18 changes: 16 additions & 2 deletions src/file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ use std::fs::{remove_file, File};
use std::io::{Read, Write};
use std::path::Path;

#[cfg(feature = "filetime")]
use crate::time::{TimeOptions, copy_time};

// Options and flags which can be used to configure how a file will be copied or moved.
pub struct CopyOptions {
/// Sets the option true for overwrite existing files.
Expand All @@ -12,6 +15,9 @@ 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,
/// File time options.
#[cfg(feature = "filetime")]
pub time_options: TimeOptions,
}

impl CopyOptions {
Expand All @@ -30,6 +36,8 @@ impl CopyOptions {
overwrite: false,
skip_exist: false,
buffer_size: 64000, //64kb
#[cfg(feature = "filetime")]
time_options: TimeOptions::new(),
}
}
}
Expand Down Expand Up @@ -106,7 +114,11 @@ where
}
}

Ok(std::fs::copy(from, to)?)
let result = std::fs::copy(from, to.as_ref())?;
#[cfg(feature = "filetime")]
copy_time(from, to, &options.time_options);

Ok(result)
}

/// Copies the contents of one file to another file with information about progress.
Expand Down Expand Up @@ -180,7 +192,7 @@ where
let file_size = file_from.metadata()?.len();
let mut copied_bytes: u64 = 0;

let mut file_to = File::create(to)?;
let mut file_to = File::create(to.as_ref())?;
while !buf.is_empty() {
match file_from.read(&mut buf) {
Ok(0) => break,
Expand All @@ -200,6 +212,8 @@ where
Err(e) => return Err(::std::convert::From::from(e)),
}
}
#[cfg(feature = "filetime")]
copy_time(from, to, &options.time_options);
Ok(file_size)
}

Expand Down
12 changes: 12 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@ macro_rules! err {

/// The error type for fs_extra operations on files and directories.
pub mod error;

/// This module includes an additional method for working with file and
/// directory modification times and access times.
#[cfg(feature = "filetime")]
pub mod time;

/// This module includes additional methods for working with files.
///
/// One of the distinguishing features is receipt information
Expand Down Expand Up @@ -354,6 +360,8 @@ where
overwrite: options.overwrite,
skip_exist: options.skip_exist,
buffer_size: options.buffer_size,
#[cfg(feature = "filetime")]
time_options: options.time_options.clone(),
};

if let Some(file_name) = item.file_name() {
Expand Down Expand Up @@ -541,6 +549,8 @@ where
overwrite: options.overwrite,
skip_exist: options.skip_exist,
buffer_size: options.buffer_size,
#[cfg(feature = "filetime")]
time_options: options.time_options.clone(),
};

if let Some(file_name) = item.file_name() {
Expand Down Expand Up @@ -666,6 +676,8 @@ where
overwrite: options.overwrite,
skip_exist: options.skip_exist,
buffer_size: options.buffer_size,
#[cfg(feature = "filetime")]
time_options: options.time_options.clone(),
};

if let Some(file_name) = item.file_name() {
Expand Down
50 changes: 50 additions & 0 deletions src/time.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
use crate::error::*;
use std::path::Path;

use filetime::{set_file_atime, set_file_mtime, FileTime};

/// Flags which can be used to configure how file and directory times will be
/// assigned.
#[derive(Clone)]
pub struct TimeOptions {
/// Keep the same modification time.
pub retain_modification_time: bool,
/// Keep the same access time.
pub retain_access_time: bool,
}

impl TimeOptions {
/// Initialize struct TimeOptions with default value.
pub fn new() -> Self {
TimeOptions {
retain_modification_time: false,
retain_access_time: false,
}
}
}

/// Assign time attributes for `to` same as in `from`.
pub fn copy_time<P, Q>(from: P, to: Q, options: &TimeOptions) -> Result<()>
where
P: AsRef<Path>,
Q: AsRef<Path>,
{
if options.retain_modification_time || options.retain_access_time {
match from.as_ref().metadata() {
Ok(metadata) => {
let mtime = FileTime::from_last_modification_time(&metadata);
let atime = FileTime::from_last_access_time(&metadata);
if options.retain_modification_time {
set_file_mtime(to.as_ref(), mtime);
}
if options.retain_access_time {
set_file_atime(to.as_ref(), atime);
}
}
Err(_) => {
err!("Could not read metadata", ErrorKind::Other);
}
}
}
Ok(())
}
Loading