2 use std
::collections
::{HashMap, HashSet}
;
3 use std
::fs
::{create_dir, create_dir_all, read_dir, remove_dir_all, Metadata}
;
4 use std
::path
::{Path, PathBuf}
;
5 use std
::time
::SystemTime
;
7 /// Options and flags which can be used to configure how a file will be copied or moved.
9 pub struct CopyOptions
{
10 /// Sets the option true for overwrite existing files.
12 /// Sets the option true for skipe existing files.
14 /// Sets buffer size for copy/move work only with receipt information about process work.
15 pub buffer_size
: usize,
16 /// Sets the option true for recursively copying a directory with a new name or place it inside the destination.(same behaviors like cp -r in Unix)
17 pub copy_inside
: bool
,
18 /// Sets the option true, for copy only content without a created folder in the destination folder
19 pub content_only
: bool
,
20 /// Sets levels reading. Set 0 for read all directory folder. By default 0.
22 /// Warrning: Work only for copy operations!
27 /// Initialize struct CopyOptions with default value.
34 /// buffer_size: 64000 //64kb
36 /// copy_inside: false
38 pub fn new() -> CopyOptions
{
42 buffer_size
: 64000, //64kb
50 impl Default
for CopyOptions
{
51 fn default() -> Self {
56 /// Options and flags which can be used to configure how read a directory.
57 #[derive(Clone, Default)]
58 pub struct DirOptions
{
59 /// Sets levels reading. Set value 0 for read all directory folder. By default 0.
64 /// Initialize struct DirOptions with default value.
65 pub fn new() -> DirOptions
{
70 /// A structure which imclude information about directory
71 pub struct DirContent
{
74 /// List all files directory and sub directories.
75 pub files
: Vec
<String
>,
76 /// List all folders and sub folders directory.
77 pub directories
: Vec
<String
>,
80 /// A structure which include information about the current status of the copy or move directory.
81 pub struct TransitProcess
{
82 /// Copied bytes on this time for folder
83 pub copied_bytes
: u64,
84 /// All the bytes which should to copy or move (dir size).
86 /// Copied bytes on this time for file.
87 pub file_bytes_copied
: u64,
88 /// Size current copied file.
89 pub file_total_bytes
: u64,
90 /// Name current copied file.
91 pub file_name
: String
,
93 pub state
: TransitState
,
97 #[derive(Hash, Eq, PartialEq, Clone)]
98 pub enum TransitState
{
101 /// Pause state when destination path is exist.
103 /// Pause state when current process does not have the permission rights to acess from or to
108 /// Available returns codes for user decide
109 pub enum TransitProcessResult
{
110 /// Rewrite exist file or directory.
112 /// Rewrite for all exist files or directories.
114 /// Skip current problem file or directory.
116 /// Skip for all problems file or directory.
118 /// Retry current operation.
120 /// Abort current operation.
122 /// Continue execute process if process not have error and abort if process content error.
126 impl Clone
for TransitProcess
{
127 fn clone(&self) -> TransitProcess
{
129 copied_bytes
: self.copied_bytes
,
130 total_bytes
: self.total_bytes
,
131 file_bytes_copied
: self.file_bytes_copied
,
132 file_total_bytes
: self.file_total_bytes
,
133 file_name
: self.file_name
.clone(),
134 state
: self.state
.clone(),
139 /// Available attributes for get information about directory entry.
140 #[derive(Hash, Eq, PartialEq, Clone)]
141 pub enum DirEntryAttr
{
142 /// Folder name or file name without extension.
146 /// Folder name or file name with extention.
148 /// Path to file or directory.
150 /// Dos path to file or directory.
152 /// File size in bytes.
154 /// Size file or directory in bytes.
156 /// `Attention!`: This operation very expensive and sometimes required additional rights.
158 /// Return whether entry is directory or not.
160 /// Return whether entry is file or not.
162 /// Last modification time for directory entry.
164 /// Last access time for directory entry.
166 /// Created time for directory entry.
168 /// `Attention!`: Not supported UNIX platform.
170 /// Return or not return base information target folder.
174 /// Available types for directory entry.
175 pub enum DirEntryValue
{
181 SystemTime(SystemTime
),
186 /// Result returned by the `ls` function.
187 pub struct LsResult
{
188 /// Base folder target path
189 pub base
: HashMap
<DirEntryAttr
, DirEntryValue
>,
190 /// Collection directory entry with information.
191 pub items
: Vec
<HashMap
<DirEntryAttr
, DirEntryValue
>>,
194 /// Returned information about directory entry with information which you choose in config.
196 /// This function takes to arguments:
198 /// * `path` - Path to directory.
200 /// * `config` - Set attributes which you want see inside return data.
204 /// This function will return an error in the following situations, but is not limited to just
207 /// * This `path` does not exist.
208 /// * Invalid `path`.
209 /// * The current process does not have the permission rights to access `path`.
214 /// extern crate fs_extra;
215 /// use fs_extra::dir::{get_details_entry, DirEntryAttr};
216 /// use std::collections::{HashMap, HashSet};
218 /// let mut config = HashSet::new();
219 /// config.insert(DirEntryAttr::Name);
220 /// config.insert(DirEntryAttr::Size);
222 /// let entry_info = get_details_entry("test", &config);
223 /// assert_eq!(2, entry_info.len());
225 pub fn get_details_entry
<P
>(
227 config
: &HashSet
<DirEntryAttr
>,
228 ) -> Result
<HashMap
<DirEntryAttr
, DirEntryValue
>>
232 let path
= path
.as_ref();
233 let metadata
= path
.metadata()?
;
234 get_details_entry_with_meta(path
, config
, metadata
)
236 fn get_details_entry_with_meta
<P
>(
238 config
: &HashSet
<DirEntryAttr
>,
240 ) -> Result
<HashMap
<DirEntryAttr
, DirEntryValue
>>
244 let path
= path
.as_ref();
245 let mut item
= HashMap
::new();
246 if config
.contains(&DirEntryAttr
::Name
) {
247 if metadata
.is_dir() {
248 if let Some(file_name
) = path
.file_name() {
251 DirEntryValue
::String(file_name
.to_os_string().into_string()?
),
254 item
.insert(DirEntryAttr
::Name
, DirEntryValue
::String(String
::new()));
257 if let Some(file_stem
) = path
.file_stem() {
260 DirEntryValue
::String(file_stem
.to_os_string().into_string()?
),
263 item
.insert(DirEntryAttr
::Name
, DirEntryValue
::String(String
::new()));
267 if config
.contains(&DirEntryAttr
::Ext
) {
268 if let Some(value
) = path
.extension() {
271 DirEntryValue
::String(value
.to_os_string().into_string()?
),
274 item
.insert(DirEntryAttr
::Ext
, DirEntryValue
::String(String
::from("")));
277 if config
.contains(&DirEntryAttr
::FullName
) {
278 if let Some(file_name
) = path
.file_name() {
280 DirEntryAttr
::FullName
,
281 DirEntryValue
::String(file_name
.to_os_string().into_string()?
),
284 item
.insert(DirEntryAttr
::FullName
, DirEntryValue
::String(String
::new()));
287 if config
.contains(&DirEntryAttr
::Path
) {
288 let mut result_path
: PathBuf
;
289 match path
.canonicalize() {
291 result_path
= new_path
;
294 if let Some(parent_path
) = path
.parent() {
295 if let Some(name
) = path
.file_name() {
296 result_path
= parent_path
.canonicalize()?
;
297 result_path
.push(name
);
299 err
!("Error get part name path", ErrorKind
::Other
);
302 err
!("Error get parent path", ErrorKind
::Other
);
306 let mut path
= result_path
.as_os_str().to_os_string().into_string()?
;
307 if path
.find("\\\\?\\") == Some(0) {
308 path
= path
[4..].to_string();
310 item
.insert(DirEntryAttr
::Path
, DirEntryValue
::String(path
));
312 if config
.contains(&DirEntryAttr
::DosPath
) {
313 let mut result_path
: PathBuf
;
314 match path
.canonicalize() {
316 result_path
= new_path
;
319 if let Some(parent_path
) = path
.parent() {
320 if let Some(name
) = path
.file_name() {
321 result_path
= parent_path
.canonicalize()?
;
322 result_path
.push(name
);
324 err
!("Error get part name path", ErrorKind
::Other
);
327 err
!("Error get parent path", ErrorKind
::Other
);
331 let path
= result_path
.as_os_str().to_os_string().into_string()?
;
332 item
.insert(DirEntryAttr
::DosPath
, DirEntryValue
::String(path
));
334 if config
.contains(&DirEntryAttr
::Size
) {
335 item
.insert(DirEntryAttr
::Size
, DirEntryValue
::U64(get_size(&path
)?
));
337 if config
.contains(&DirEntryAttr
::FileSize
) {
338 item
.insert(DirEntryAttr
::FileSize
, DirEntryValue
::U64(metadata
.len()));
340 if config
.contains(&DirEntryAttr
::IsDir
) {
343 DirEntryValue
::Boolean(metadata
.is_dir()),
346 if config
.contains(&DirEntryAttr
::IsFile
) {
348 DirEntryAttr
::IsFile
,
349 DirEntryValue
::Boolean(metadata
.is_file()),
352 if config
.contains(&DirEntryAttr
::Modified
) {
354 DirEntryAttr
::Modified
,
355 DirEntryValue
::SystemTime(metadata
.modified()?
),
358 if config
.contains(&DirEntryAttr
::Accessed
) {
360 DirEntryAttr
::Accessed
,
361 DirEntryValue
::SystemTime(metadata
.accessed()?
),
364 if config
.contains(&DirEntryAttr
::Created
) {
366 DirEntryAttr
::Created
,
367 DirEntryValue
::SystemTime(metadata
.created()?
),
373 /// Returned collection directory entries with information which you choose in config.
375 /// This function takes to arguments:
377 /// * `path` - Path to directory.
379 /// * `config` - Set attributes which you want see inside return data.
383 /// This function will return an error in the following situations, but is not limited to just
386 /// * This `path` directory does not exist.
387 /// * Invalid `path`.
388 /// * The current process does not have the permission rights to access `path`.
393 /// extern crate fs_extra;
394 /// use fs_extra::dir::{ls, DirEntryAttr, LsResult};
395 /// use std::collections::HashSet;
397 /// let mut config = HashSet::new();
398 /// config.insert(DirEntryAttr::Name);
399 /// config.insert(DirEntryAttr::Size);
400 /// config.insert(DirEntryAttr::BaseInfo);
402 /// let result = ls("test", &config);
403 /// assert_eq!(2, ls_result.items.len());
404 /// assert_eq!(2, ls_result.base.len());
406 pub fn ls
<P
>(path
: P
, config
: &HashSet
<DirEntryAttr
>) -> Result
<LsResult
>
410 let mut items
= Vec
::new();
411 let path
= path
.as_ref();
413 err
!("Path does not directory", ErrorKind
::InvalidFolder
);
415 for entry
in read_dir(&path
)?
{
417 let path
= entry
.path();
418 let metadata
= entry
.metadata()?
;
419 let item
= get_details_entry_with_meta(path
, &config
, metadata
)?
;
422 let mut base
= HashMap
::new();
423 if config
.contains(&DirEntryAttr
::BaseInfo
) {
424 base
= get_details_entry(&path
, &config
)?
;
432 /// Creates a new, empty directory at the provided path.
434 /// This function takes to arguments:
436 /// * `path` - Path to new directory.
438 /// * `erase` - If set true and folder exist, then folder will be erased.
442 /// This function will return an error in the following situations,
443 /// but is not limited to just these cases:
445 /// * User lacks permissions to create directory at `path`.
447 /// * `path` already exists if `erase` set false.
452 /// extern crate fs_extra;
453 /// use fs_extra::dir::create;
455 /// create("dir", false); // create directory
457 pub fn create
<P
>(path
: P
, erase
: bool
) -> Result
<()>
461 if erase
&& path
.as_ref().exists() {
464 Ok(create_dir(&path
)?
)
467 /// Recursively create a directory and all of its parent components if they are missing.
469 /// This function takes to arguments:
471 /// * `path` - Path to new directory.
473 /// * `erase` - If set true and folder exist, then folder will be erased.
477 /// This function will return an error in the following situations,
478 /// but is not limited to just these cases:
480 /// * User lacks permissions to create directory at `path`.
482 /// * `path` already exists if `erase` set false.
487 /// extern crate fs_extra;
488 /// use fs_extra::dir::create_all;
490 /// create_all("/some/dir", false); // create directory some and dir
491 pub fn create_all
<P
>(path
: P
, erase
: bool
) -> Result
<()>
495 if erase
&& path
.as_ref().exists() {
498 Ok(create_dir_all(&path
)?
)
501 /// Copies the directory contents from one place to another using recursive method.
502 /// This function will also copy the permission bits of the original files to
503 /// destionation files (not for directories).
507 /// This function will return an error in the following situations, but is not limited to just
510 /// * This `from` path is not a directory.
511 /// * This `from` directory does not exist.
512 /// * Invalid folder name for `from` or `to`.
513 /// * The current process does not have the permission rights to access `from` or write `to`.
517 /// extern crate fs_extra;
518 /// use fs_extra::dir::copy;
520 /// let options = CopyOptions::new(); //Initialize default values for CopyOptions
521 /// // options.mirror_copy = true; // To mirror copy the whole structure of the source directory
524 /// // copy source/dir1 to target/dir1
525 /// copy("source/dir1", "target/dir1", &options)?;
528 pub fn copy
<P
, Q
>(from
: P
, to
: Q
, options
: &CopyOptions
) -> Result
<u64>
533 let from
= from
.as_ref();
536 if let Some(msg
) = from
.to_str() {
537 let msg
= format
!("Path \"{}\" does not exist or you don't have access!", msg
);
538 err
!(&msg
, ErrorKind
::NotFound
);
541 "Path does not exist Or you don't have access!",
546 if let Some(msg
) = from
.to_str() {
547 let msg
= format
!("Path \"{}\" is not a directory!", msg
);
548 err
!(&msg
, ErrorKind
::InvalidFolder
);
550 err
!("Path is not a directory!", ErrorKind
::InvalidFolder
);
553 if let Some(val
) = from
.components().last() {
554 dir_name
= val
.as_os_str();
556 err
!("Invalid folder from", ErrorKind
::InvalidFolder
);
558 let mut to
: PathBuf
= to
.as_ref().to_path_buf();
559 if !options
.content_only
&& ((options
.copy_inside
&& to
.exists()) || !options
.copy_inside
) {
563 let mut read_options
= DirOptions
::new();
564 if options
.depth
> 0 {
565 read_options
.depth
= options
.depth
;
568 let dir_content
= get_dir_content2(from
, &read_options
)?
;
569 for directory
in dir_content
.directories
{
570 let tmp_to
= Path
::new(&directory
).strip_prefix(from
)?
;
571 let dir
= to
.join(&tmp_to
);
573 if options
.copy_inside
{
574 create_all(dir
, false)?
;
580 let mut result
: u64 = 0;
581 for file
in dir_content
.files
{
582 let to
= to
.to_path_buf();
583 let tp
= Path
::new(&file
).strip_prefix(from
)?
;
584 let path
= to
.join(&tp
);
586 let file_options
= super::file
::CopyOptions
{
587 overwrite
: options
.overwrite
,
588 skip_exist
: options
.skip_exist
,
589 buffer_size
: options
.buffer_size
,
591 let mut result_copy
: Result
<u64>;
595 result_copy
= super::file
::copy(&file
, &path
, &file_options
);
602 let err_msg
= err
.to_string();
603 err
!(err_msg
.as_str(), err
.kind
)
611 /// Return DirContent which containt information about directory:
613 /// * Size directory.
614 /// * List all files source directory(files subdirectories included too).
615 /// * List all directory and subdirectories source path.
619 /// This function will return an error in the following situations, but is not limited to just
622 /// * This `path` directory does not exist.
623 /// * Invalid `path`.
624 /// * The current process does not have the permission rights to access `path`.
628 /// extern crate fs_extra;
629 /// use fs_extra::dir::get_dir_content;
631 /// let dir_content = get_dir_content("dir")?;
632 /// for directory in dir_content.directories {
633 /// println!("{}", directory); // print directory path
637 pub fn get_dir_content
<P
>(path
: P
) -> Result
<DirContent
>
641 let options
= DirOptions
::new();
642 get_dir_content2(path
, &options
)
645 /// Return DirContent which containt information about directory:
647 /// * Size directory.
648 /// * List all files source directory(files subdirectories included too).
649 /// * List all directory and subdirectories source path.
653 /// This function will return an error in the following situations, but is not limited to just
656 /// * This `path` directory does not exist.
657 /// * Invalid `path`.
658 /// * The current process does not have the permission rights to access `path`.
662 /// extern crate fs_extra;
663 /// use fs_extra::dir::get_dir_content2;
665 /// let options = DirOptions::new();
666 /// options.depth = 3; // Get 3 levels of folder.
667 /// let dir_content = get_dir_content2("dir", &options)?;
668 /// for directory in dir_content.directories {
669 /// println!("{}", directory); // print directory path
673 pub fn get_dir_content2
<P
>(path
: P
, options
: &DirOptions
) -> Result
<DirContent
>
678 if options
.depth
!= 0 {
679 depth
= options
.depth
+ 1;
681 _get_dir_content(path
, depth
)
684 fn _get_dir_content
<P
>(path
: P
, mut depth
: u64) -> Result
<DirContent
>
688 let mut directories
= Vec
::new();
689 let mut files
= Vec
::new();
690 let mut dir_size
= 0;
691 let item
= path
.as_ref().to_str();
693 err
!("Invalid path", ErrorKind
::InvalidPath
);
695 let item
= item
.unwrap().to_string();
697 if path
.as_ref().is_dir() {
698 directories
.push(item
);
699 if depth
== 0 || depth
> 1 {
703 for entry
in read_dir(&path
)?
{
704 let _path
= entry?
.path();
706 match _get_dir_content(_path
, depth
) {
708 let mut _files
= items
.files
;
709 let mut _dirrectories
= items
.directories
;
710 dir_size
+= items
.dir_size
;
711 files
.append(&mut _files
);
712 directories
.append(&mut _dirrectories
);
714 Err(err
) => return Err(err
),
719 dir_size
= path
.as_ref().metadata()?
.len();
725 directories
: directories
,
729 /// Returns the size of the file or directory
733 /// This function will return an error in the following situations, but is not limited to just
736 /// * This `path` directory does not exist.
737 /// * Invalid `path`.
738 /// * The current process does not have the permission rights to access `path`.
742 /// extern crate fs_extra;
743 /// use fs_extra::dir::get_size;
745 /// let folder_size = get_size("dir")?;
746 /// println!("{}", folder_size); // print directory sile in bytes
748 pub fn get_size
<P
>(path
: P
) -> Result
<u64>
754 if path
.as_ref().is_dir() {
755 for entry
in read_dir(&path
)?
{
756 let _path
= entry?
.path();
758 result
+= _path
.metadata()?
.len();
760 result
+= get_size(_path
)?
;
764 result
= path
.as_ref().metadata()?
.len();
769 /// Copies the directory contents from one place to another using recursive method,
770 /// with recept information about process. This function will also copy the
771 /// permission bits of the original files to destionation files (not for directories).
775 /// This function will return an error in the following situations, but is not limited to just
778 /// * This `from` path is not a directory.
779 /// * This `from` directory does not exist.
780 /// * Invalid folder name for `from` or `to`.
781 /// * The current process does not have the permission rights to access `from` or write `to`.
785 /// extern crate fs_extra;
786 /// use fs_extra::dir::copy;
788 /// let options = CopyOptions::new(); //Initialize default values for CopyOptions
789 /// let handle = |process_info: TransitProcess| {
790 /// println!("{}", process_info.total_bytes);
791 /// fs_extra::dir::TransitProcessResult::ContinueOrAbort
793 /// // copy source/dir1 to target/dir1
794 /// copy_with_progress("source/dir1", "target/dir1", &options, handle)?;
797 pub fn copy_with_progress
<P
, Q
, F
>(
800 options
: &CopyOptions
,
801 mut progress_handler
: F
,
806 F
: FnMut(TransitProcess
) -> TransitProcessResult
,
808 let from
= from
.as_ref();
811 if let Some(msg
) = from
.to_str() {
812 let msg
= format
!("Path \"{}\" does not exist or you don't have access!", msg
);
813 err
!(&msg
, ErrorKind
::NotFound
);
816 "Path does not exist or you don't have access!",
821 let mut to
: PathBuf
= to
.as_ref().to_path_buf();
823 if let Some(msg
) = from
.to_str() {
824 let msg
= format
!("Path \"{}\" is not a directory!", msg
);
825 err
!(&msg
, ErrorKind
::InvalidFolder
);
827 err
!("Path is not a directory!", ErrorKind
::InvalidFolder
);
831 if let Some(val
) = from
.components().last() {
832 dir_name
= val
.as_os_str();
834 err
!("Invalid folder from", ErrorKind
::InvalidFolder
);
836 if !options
.content_only
&& ((options
.copy_inside
&& to
.exists()) || !options
.copy_inside
) {
840 let mut read_options
= DirOptions
::new();
841 if options
.depth
> 0 {
842 read_options
.depth
= options
.depth
;
845 let dir_content
= get_dir_content2(from
, &read_options
)?
;
846 for directory
in dir_content
.directories
{
847 let tmp_to
= Path
::new(&directory
).strip_prefix(from
)?
;
848 let dir
= to
.join(&tmp_to
);
850 if options
.copy_inside
{
851 create_all(dir
, false)?
;
858 let mut result
: u64 = 0;
859 let mut info_process
= TransitProcess
{
861 total_bytes
: dir_content
.dir_size
,
862 file_bytes_copied
: 0,
864 file_name
: String
::new(),
865 state
: TransitState
::Normal
,
868 let mut options
= options
.clone();
869 for file
in dir_content
.files
{
870 let mut to
= to
.to_path_buf();
871 let tp
= Path
::new(&file
).strip_prefix(from
)?
;
872 let path
= to
.join(&tp
);
874 let file_name
= path
.file_name();
875 if !file_name
.is_some() {
876 err
!("No file name");
878 let file_name
= file_name
.unwrap();
881 let mut file_options
= super::file
::CopyOptions
{
882 overwrite
: options
.overwrite
,
883 skip_exist
: options
.skip_exist
,
884 buffer_size
: options
.buffer_size
,
887 if let Some(file_name
) = file_name
.to_str() {
888 info_process
.file_name
= file_name
.to_string();
890 err
!("Invalid file name", ErrorKind
::InvalidFileName
);
893 info_process
.file_bytes_copied
= 0;
894 info_process
.file_total_bytes
= Path
::new(&file
).metadata()?
.len();
896 let mut result_copy
: Result
<u64>;
898 let copied_bytes
= result
;
901 let _progress_handler
= |info
: super::file
::TransitProcess
| {
902 info_process
.copied_bytes
= copied_bytes
+ info
.copied_bytes
;
903 info_process
.file_bytes_copied
= info
.copied_bytes
;
904 progress_handler(info_process
.clone());
908 super::file
::copy_with_progress(&file
, &path
, &file_options
, _progress_handler
);
915 Err(err
) => match err
.kind
{
916 ErrorKind
::AlreadyExists
=> {
917 let mut info_process
= info_process
.clone();
918 info_process
.state
= TransitState
::Exists
;
919 let user_decide
= progress_handler(info_process
);
921 TransitProcessResult
::Overwrite
=> {
922 file_options
.overwrite
= true;
924 TransitProcessResult
::OverwriteAll
=> {
925 file_options
.overwrite
= true;
926 options
.overwrite
= true;
928 TransitProcessResult
::Skip
=> {
929 file_options
.skip_exist
= true;
931 TransitProcessResult
::SkipAll
=> {
932 file_options
.skip_exist
= true;
933 options
.skip_exist
= true;
935 TransitProcessResult
::Retry
=> {}
936 TransitProcessResult
::ContinueOrAbort
=> {
937 let err_msg
= err
.to_string();
938 err
!(err_msg
.as_str(), err
.kind
)
940 TransitProcessResult
::Abort
=> {
941 let err_msg
= err
.to_string();
942 err
!(err_msg
.as_str(), err
.kind
)
946 ErrorKind
::PermissionDenied
=> {
947 let mut info_process
= info_process
.clone();
948 info_process
.state
= TransitState
::Exists
;
949 let user_decide
= progress_handler(info_process
);
951 TransitProcessResult
::Overwrite
=> {
952 err
!("Overwrite denied for this situation!", ErrorKind
::Other
);
954 TransitProcessResult
::OverwriteAll
=> {
955 err
!("Overwrite denied for this situation!", ErrorKind
::Other
);
957 TransitProcessResult
::Skip
=> {
958 file_options
.skip_exist
= true;
960 TransitProcessResult
::SkipAll
=> {
961 file_options
.skip_exist
= true;
962 options
.skip_exist
= true;
964 TransitProcessResult
::Retry
=> {}
965 TransitProcessResult
::ContinueOrAbort
=> {
966 let err_msg
= err
.to_string();
967 err
!(err_msg
.as_str(), err
.kind
)
969 TransitProcessResult
::Abort
=> {
970 let err_msg
= err
.to_string();
971 err
!(err_msg
.as_str(), err
.kind
)
976 let err_msg
= err
.to_string();
977 err
!(err_msg
.as_str(), err
.kind
)
987 /// Moves the directory contents from one place to another.
988 /// This function will also copy the permission bits of the original files to
989 /// destionation files (not for directories).
993 /// This function will return an error in the following situations, but is not limited to just
996 /// * This `from` path is not a directory.
997 /// * This `from` directory does not exist.
998 /// * Invalid folder name for `from` or `to`.
999 /// * The current process does not have the permission rights to access `from` or write `to`.
1003 /// extern crate fs_extra;
1004 /// use fs_extra::dir::move_dir;
1006 /// let options = CopyOptions::new(); //Initialize default values for CopyOptions
1008 /// // move source/dir1 to target/dir1
1009 /// move_dir("source/dir1", "target/dir1", &options)?;
1012 pub fn move_dir
<P
, Q
>(from
: P
, to
: Q
, options
: &CopyOptions
) -> Result
<u64>
1017 let mut is_remove
= true;
1018 if options
.skip_exist
&& to
.as_ref().exists() && !options
.overwrite
{
1021 let from
= from
.as_ref();
1024 if let Some(msg
) = from
.to_str() {
1025 let msg
= format
!("Path \"{}\" does not exist", msg
);
1026 err
!(&msg
, ErrorKind
::NotFound
);
1029 "Path does not exist or you don't have access!",
1034 let mut to
: PathBuf
= to
.as_ref().to_path_buf();
1036 if let Some(msg
) = from
.to_str() {
1038 "Path \"{}\" is not a directory or you don't have access!",
1041 err
!(&msg
, ErrorKind
::InvalidFolder
);
1044 "Path is not a directory or you don't have access!",
1045 ErrorKind
::InvalidFolder
1049 if let Some(val
) = from
.components().last() {
1050 dir_name
= val
.as_os_str();
1052 err
!("Invalid folder from", ErrorKind
::InvalidFolder
);
1055 if !options
.content_only
&& ((options
.copy_inside
&& to
.exists()) || !options
.copy_inside
) {
1058 let dir_content
= get_dir_content(from
)?
;
1059 for directory
in dir_content
.directories
{
1060 let tmp_to
= Path
::new(&directory
).strip_prefix(from
)?
;
1061 let dir
= to
.join(&tmp_to
);
1063 if options
.copy_inside
{
1064 create_all(dir
, false)?
;
1066 create(dir
, false)?
;
1070 let mut result
: u64 = 0;
1071 for file
in dir_content
.files
{
1072 let to
= to
.to_path_buf();
1073 let tp
= Path
::new(&file
).strip_prefix(from
)?
;
1074 let path
= to
.join(&tp
);
1076 let file_options
= super::file
::CopyOptions
{
1077 overwrite
: options
.overwrite
,
1078 skip_exist
: options
.skip_exist
,
1079 buffer_size
: options
.buffer_size
,
1082 let mut result_copy
: Result
<u64>;
1083 let mut work
= true;
1086 result_copy
= super::file
::move_file(&file
, &path
, &file_options
);
1093 let err_msg
= err
.to_string();
1094 err
!(err_msg
.as_str(), err
.kind
)
1107 /// Moves the directory contents from one place to another with recept information about process.
1108 /// This function will also copy the permission bits of the original files to
1109 /// destionation files (not for directories).
1113 /// This function will return an error in the following situations, but is not limited to just
1116 /// * This `from` path is not a directory.
1117 /// * This `from` directory does not exist.
1118 /// * Invalid folder name for `from` or `to`.
1119 /// * The current process does not have the permission rights to access `from` or write `to`.
1123 /// extern crate fs_extra;
1124 /// use fs_extra::dir::move_dir_with_progress;
1126 /// let options = CopyOptions::new(); //Initialize default values for CopyOptions
1127 /// let handle = |process_info: TransitProcess| {
1128 /// println!("{}", process_info.total_bytes);
1129 /// fs_extra::dir::TransitProcessResult::ContinueOrAbort
1132 /// // move source/dir1 to target/dir1
1133 /// move_dir_with_progress("source/dir1", "target/dir1", &options, handle)?;
1136 pub fn move_dir_with_progress
<P
, Q
, F
>(
1139 options
: &CopyOptions
,
1140 mut progress_handler
: F
,
1145 F
: FnMut(TransitProcess
) -> TransitProcessResult
,
1147 let mut is_remove
= true;
1148 if options
.skip_exist
&& to
.as_ref().exists() && !options
.overwrite
{
1151 let from
= from
.as_ref();
1154 if let Some(msg
) = from
.to_str() {
1155 let msg
= format
!("Path \"{}\" does not exist or you don't have access!", msg
);
1156 err
!(&msg
, ErrorKind
::NotFound
);
1159 "Path does not exist or you don't have access!",
1164 let mut to
: PathBuf
= to
.as_ref().to_path_buf();
1166 if let Some(msg
) = from
.to_str() {
1167 let msg
= format
!("Path \"{}\" is not a directory!", msg
);
1168 err
!(&msg
, ErrorKind
::InvalidFolder
);
1170 err
!("Path is not a directory!", ErrorKind
::InvalidFolder
);
1173 if let Some(val
) = from
.components().last() {
1174 dir_name
= val
.as_os_str();
1176 err
!("Invalid folder from", ErrorKind
::InvalidFolder
);
1178 if !options
.content_only
&& ((options
.copy_inside
&& to
.exists()) || !options
.copy_inside
) {
1182 let dir_content
= get_dir_content(from
)?
;
1183 for directory
in dir_content
.directories
{
1184 let tmp_to
= Path
::new(&directory
).strip_prefix(from
)?
;
1185 let dir
= to
.join(&tmp_to
);
1187 if options
.copy_inside
{
1188 create_all(dir
, false)?
;
1190 create(dir
, false)?
;
1195 let mut result
: u64 = 0;
1196 let mut info_process
= TransitProcess
{
1198 total_bytes
: dir_content
.dir_size
,
1199 file_bytes_copied
: 0,
1200 file_total_bytes
: 0,
1201 file_name
: String
::new(),
1202 state
: TransitState
::Normal
,
1205 let mut options
= options
.clone();
1206 for file
in dir_content
.files
{
1207 let mut to
= to
.to_path_buf();
1208 let tp
= Path
::new(&file
).strip_prefix(from
)?
;
1209 let path
= to
.join(&tp
);
1211 let file_name
= path
.file_name();
1212 if !file_name
.is_some() {
1213 err
!("No file name");
1215 let file_name
= file_name
.unwrap();
1218 let mut file_options
= super::file
::CopyOptions
{
1219 overwrite
: options
.overwrite
,
1220 skip_exist
: options
.skip_exist
,
1221 buffer_size
: options
.buffer_size
,
1224 if let Some(file_name
) = file_name
.to_str() {
1225 info_process
.file_name
= file_name
.to_string();
1227 err
!("Invalid file name", ErrorKind
::InvalidFileName
);
1230 info_process
.file_bytes_copied
= 0;
1231 info_process
.file_total_bytes
= Path
::new(&file
).metadata()?
.len();
1233 let mut result_copy
: Result
<u64>;
1234 let mut work
= true;
1235 let copied_bytes
= result
;
1238 let _progress_handler
= |info
: super::file
::TransitProcess
| {
1239 info_process
.copied_bytes
= copied_bytes
+ info
.copied_bytes
;
1240 info_process
.file_bytes_copied
= info
.copied_bytes
;
1241 progress_handler(info_process
.clone());
1244 result_copy
= super::file
::move_file_with_progress(
1256 Err(err
) => match err
.kind
{
1257 ErrorKind
::AlreadyExists
=> {
1258 let mut info_process
= info_process
.clone();
1259 info_process
.state
= TransitState
::Exists
;
1260 let user_decide
= progress_handler(info_process
);
1262 TransitProcessResult
::Overwrite
=> {
1263 file_options
.overwrite
= true;
1265 TransitProcessResult
::OverwriteAll
=> {
1266 file_options
.overwrite
= true;
1267 options
.overwrite
= true;
1269 TransitProcessResult
::Skip
=> {
1271 file_options
.skip_exist
= true;
1273 TransitProcessResult
::SkipAll
=> {
1275 file_options
.skip_exist
= true;
1276 options
.skip_exist
= true;
1278 TransitProcessResult
::Retry
=> {}
1279 TransitProcessResult
::ContinueOrAbort
=> {
1280 let err_msg
= err
.to_string();
1281 err
!(err_msg
.as_str(), err
.kind
)
1283 TransitProcessResult
::Abort
=> {
1284 let err_msg
= err
.to_string();
1285 err
!(err_msg
.as_str(), err
.kind
)
1289 ErrorKind
::PermissionDenied
=> {
1290 let mut info_process
= info_process
.clone();
1291 info_process
.state
= TransitState
::Exists
;
1292 let user_decide
= progress_handler(info_process
);
1294 TransitProcessResult
::Overwrite
=> {
1295 err
!("Overwrite denied for this situation!", ErrorKind
::Other
);
1297 TransitProcessResult
::OverwriteAll
=> {
1298 err
!("Overwrite denied for this situation!", ErrorKind
::Other
);
1300 TransitProcessResult
::Skip
=> {
1302 file_options
.skip_exist
= true;
1304 TransitProcessResult
::SkipAll
=> {
1305 file_options
.skip_exist
= true;
1306 options
.skip_exist
= true;
1308 TransitProcessResult
::Retry
=> {}
1309 TransitProcessResult
::ContinueOrAbort
=> {
1310 let err_msg
= err
.to_string();
1311 err
!(err_msg
.as_str(), err
.kind
)
1313 TransitProcessResult
::Abort
=> {
1314 let err_msg
= err
.to_string();
1315 err
!(err_msg
.as_str(), err
.kind
)
1320 let err_msg
= err
.to_string();
1321 err
!(err_msg
.as_str(), err
.kind
)
1334 /// Removes directory.
1338 /// extern crate fs_extra;
1339 /// use fs_extra::dir::remove;
1341 /// remove("source/dir1"); // remove dir1
1343 pub fn remove
<P
: AsRef
<Path
>>(path
: P
) -> Result
<()> {
1344 if path
.as_ref().exists() {
1345 Ok(remove_dir_all(path
)?
)