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
90
91
92
93
94
95
96
97
98
99
100
101
102
use std::{
fs, io,
path::{Path, PathBuf},
};
#[derive(Debug)]
pub enum ErrorKind {
IO(io::Error),
ConversionError,
PathError,
}
type Result<T, E = ErrorKind> = std::result::Result<T, E>;
pub const PATH_LEN_LEN: usize = 32 / 8; pub const FILE_LEN_LEN: usize = 64 / 8; pub const HEADER_LEN: usize = PATH_LEN_LEN + FILE_LEN_LEN; pub struct FileHeader {
path: Option<PathBuf>,
path_len: u32,
file_len: u64,
}
impl FileHeader {
pub fn new<P1, P2>(file_path: P1, dir_path: P2) -> Result<FileHeader>
where
P1: AsRef<Path>,
P2: AsRef<Path>,
{
let path_str = file_path
.as_ref()
.strip_prefix(dir_path)
.map_err(|_| ErrorKind::PathError)?
.to_str()
.ok_or(ErrorKind::PathError)?;
let path_len =
u32::try_from(path_str.as_bytes().len()).map_err(|_| ErrorKind::ConversionError)?;
let file_len = fs::metadata(file_path.as_ref())
.map_err(|e| ErrorKind::IO(e))?
.len();
Ok(FileHeader {
path: Some(PathBuf::from(path_str)),
path_len,
file_len,
})
}
pub fn from_bytes(bytes: &[u8; 12]) -> Result<FileHeader> {
let path_len_bytes: [u8; PATH_LEN_LEN] = bytes[..PATH_LEN_LEN]
.try_into()
.map_err(|_| ErrorKind::ConversionError)?;
let file_len_bytes: [u8; FILE_LEN_LEN] = bytes[PATH_LEN_LEN..]
.try_into()
.map_err(|_| ErrorKind::ConversionError)?;
Ok(FileHeader {
path: None,
path_len: u32::from_be_bytes(path_len_bytes)
.try_into()
.map_err(|_| ErrorKind::ConversionError)?,
file_len: u64::from_be_bytes(file_len_bytes),
})
}
pub fn to_vec(&self) -> Result<Vec<u8>> {
Ok([
self.path_len.to_be_bytes().as_slice(),
self.file_len.to_be_bytes().as_slice(),
self.path
.as_ref()
.ok_or(ErrorKind::PathError)?
.to_str()
.ok_or(ErrorKind::PathError)?
.as_bytes(),
]
.concat())
}
pub fn path_len_usize(&self) -> Result<usize> {
Ok(usize::try_from(self.path_len).map_err(|_| ErrorKind::ConversionError)?)
}
pub fn file_len_u64(&self) -> u64 {
self.file_len
}
}