1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
use async_std::fs::File;
#[cfg(feature = "unstable")]
use futures::io::Sink;
use std::fs;
use std::net::SocketAddr;
use std::path::Component;
use std::path::{Path, PathBuf};
use crate::error::{Error, Result};
use crate::packet;
pub struct DirRoHandler {
dir: PathBuf,
}
impl DirRoHandler {
pub fn new<P>(dir: P) -> Result<Self>
where
P: AsRef<Path>,
{
let dir = fs::canonicalize(dir.as_ref())?;
if !dir.is_dir() {
return Err(Error::NotDir(dir));
}
log!("TFTP directory: {}", dir.display());
Ok(DirRoHandler {
dir,
})
}
}
#[crate::async_trait]
impl crate::server::Handler for DirRoHandler {
type Reader = File;
#[cfg(feature = "unstable")]
type Writer = Sink;
async fn read_req_open(
&mut self,
_client: &SocketAddr,
path: &Path,
) -> Result<(Self::Reader, Option<u64>), packet::Error> {
let path = path
.strip_prefix("/")
.or_else(|_| path.strip_prefix("./"))
.unwrap_or(path);
if path.components().any(|x| x == Component::ParentDir) {
return Err(packet::Error::FileNotFound);
}
match path.components().next() {
Some(Component::Normal(_)) => {}
_ => return Err(packet::Error::FileNotFound),
}
let path = self.dir.join(path);
if !path.is_file() {
return Err(packet::Error::FileNotFound);
}
let file = File::open(&path).await?;
let len = file.metadata().await.ok().map(|m| m.len());
log!("TFTP sending file: {}", path.display());
Ok((file, len))
}
#[cfg(feature = "unstable")]
async fn write_open(
&mut self,
_client: &SocketAddr,
_path: &Path,
_size: Option<u64>,
) -> Result<Self::Writer, packet::Error> {
Err(packet::Error::IllegalOperation)
}
}