1use std::fs::{self, File};
18use std::hash::Hasher;
19use std::io;
20use std::path::{Path, PathBuf};
21
22use crate::error::AnnotatedError;
23
24pub fn copy_recursive(src: &Path, dest: &Path) -> io::Result<()> {
28 if fs::metadata(src)?.is_dir() {
29 copy_dir(src, dest)
30 } else {
31 copy_file(src, dest)
32 }
33}
34
35fn copy_file(src: &Path, dest: &Path) -> io::Result<()> {
36 io::copy(&mut File::open(src)?, &mut File::create(dest)?).map(|_| ())
37}
38
39fn copy_dir(src: &Path, dest: &Path) -> io::Result<()> {
40 fs::create_dir(dest)?;
41 for dir_entry in fs::read_dir(src)? {
42 let dir_entry = dir_entry?;
43 let file_name = dir_entry.file_name();
44 let from = src.join(&file_name);
45 let to = dest.join(&file_name);
46 if exists(&to)? {
47 return Err(io::Error::new(
48 io::ErrorKind::AlreadyExists,
49 "target path already exists",
50 ));
51 }
52
53 if dir_entry.file_type()?.is_dir() {
54 copy_dir(&from, &to)?;
55 } else {
56 copy_file(&from, &to)?;
57 }
58 }
59 Ok(())
60}
61
62pub fn exists(path: &Path) -> io::Result<bool> {
64 match fs::metadata(path) {
65 Ok(_) => Ok(true),
66 Err(e) => match e.kind() {
67 io::ErrorKind::NotFound => Ok(false),
68 _ => Err(e),
69 },
70 }
71}
72
73pub fn walk_sorted(path: &Path) -> io::Result<Vec<PathBuf>> {
75 let mut out = Vec::new();
76 walk_into(path, &mut out)?;
77 Ok(out)
78}
79
80fn walk_into(path: &Path, out: &mut Vec<PathBuf>) -> io::Result<()> {
81 let mut files = fs::read_dir(path)?
82 .map(|e| {
83 let e = e?;
84 Ok((e.path(), e.file_type()?.is_dir()))
85 })
86 .collect::<io::Result<Vec<_>>>()?;
87
88 files.sort_by(|a, b| a.0.file_name().unwrap().cmp(b.0.file_name().unwrap()));
90 for (path, is_dir) in files {
91 if is_dir {
92 walk_into(&path, out)?;
93 } else {
94 out.push(path);
95 }
96 }
97 Ok(())
98}
99
100pub struct StreamHasher<W, H> {
101 hash: H,
102 inner: W,
103}
104impl<W, H> StreamHasher<W, H>
105where
106 H: Hasher,
107 W: io::Write,
108{
109 pub fn new(inner: W) -> Self
110 where
111 H: Default,
112 {
113 StreamHasher {
114 hash: H::default(),
115 inner,
116 }
117 }
118 pub fn with_hasher(inner: W, hash: H) -> Self {
119 StreamHasher { hash, inner }
120 }
121 pub fn finish(&self) -> u64 {
122 self.hash.finish()
123 }
124}
125impl<W, H> io::Write for StreamHasher<W, H>
126where
127 W: io::Write,
128 H: Hasher,
129{
130 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
131 let size = self.inner.write(buf)?;
132 self.hash.write(&buf[..size]);
133 Ok(size)
134 }
135 fn flush(&mut self) -> io::Result<()> {
136 self.inner.flush()
137 }
138}
139
140pub fn concat<W, I>(paths: I, output: &mut W) -> Result<u64, AnnotatedError<io::Error>>
142where
143 W: io::Write,
144 I: IntoIterator,
145 I::Item: AsRef<Path>,
146{
147 let mut bytes = 0;
148 for p in paths {
149 let p = p.as_ref();
150 bytes += try_annotate!(io::copy(&mut try_annotate!(File::open(p), p), output), p)
151 }
152 Ok(bytes)
153}