Skip to content

Commit

Permalink
Implement mtime and atime copying
Browse files Browse the repository at this point in the history
  • Loading branch information
pczarn committed Dec 18, 2021
1 parent 752fc4d commit 7f2a90d
Show file tree
Hide file tree
Showing 7 changed files with 241 additions and 75 deletions.
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

0 comments on commit 7f2a90d

Please sign in to comment.