1pub mod cp437;
2mod crc32;
3
4pub use crc32::{Crc32Checker, Crc32Writer};
5
6use std::{fmt, io, time::SystemTime};
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq)]
10pub enum FileType {
11 File,
13 Directory,
15 Symlink,
17}
18
19impl FileType {
20 #[inline]
22 pub fn is_file(&self) -> bool {
23 matches!(self, FileType::File)
24 }
25
26 #[inline]
28 pub fn is_directory(&self) -> bool {
29 matches!(self, FileType::Directory)
30 }
31
32 #[inline]
34 pub fn is_symlink(&self) -> bool {
35 matches!(self, FileType::Symlink)
36 }
37}
38
39#[derive(Clone, Copy)]
43pub struct Timestamp(u64);
44
45impl Timestamp {
46 #[inline]
48 pub fn now() -> Self {
49 Self::from_std(SystemTime::now())
50 }
51
52 pub fn from_ntfs(time: u64) -> Self {
56 const NT_EPOCH: u64 = 11_644_473_600;
58
59 let time = time.saturating_sub(NT_EPOCH * 10_000_000);
60
61 Self(time / 10_000_000)
62 }
63
64 #[inline]
66 pub fn from_unix(time: u64) -> Self {
67 Self(time)
68 }
69
70 #[inline]
74 pub fn from_std(t: SystemTime) -> Self {
75 Self(t.duration_since(SystemTime::UNIX_EPOCH).unwrap().as_secs())
76 }
77
78 #[inline]
80 pub fn to_unix(self) -> u64 {
81 self.0
82 }
83
84 #[inline]
86 pub fn to_std(self) -> SystemTime {
87 SystemTime::UNIX_EPOCH + std::time::Duration::from_secs(self.0)
88 }
89}
90
91impl fmt::Debug for Timestamp {
92 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
93 write!(f, "Timestamp({})", self.0)
94 }
95}
96
97#[derive(Default)]
98pub(crate) struct Counter<T> {
99 pub amt: u64,
100 pub inner: T,
101}
102
103impl<T> Counter<T> {
104 #[inline]
105 pub const fn new(inner: T) -> Self {
106 Self { amt: 0, inner }
107 }
108
109 pub(crate) fn advance(&mut self, amt: u64) -> io::Result<()>
110 where
111 T: io::Seek,
112 {
113 #[cold]
114 fn out_of_range() -> io::Error {
115 io::Error::new(io::ErrorKind::InvalidInput, "seek out of range")
116 }
117
118 let offset = amt.try_into().map_err(|_| out_of_range())?;
119 self.amt = self.amt.checked_add(amt).ok_or_else(out_of_range)?;
120 self.inner.seek_relative(offset)
121 }
122}
123
124impl<R: io::Read> io::Read for Counter<R> {
125 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
126 let n = self.inner.read(buf)?;
127 self.amt += n as u64;
128 Ok(n)
129 }
130}
131
132impl<R: io::BufRead> io::BufRead for Counter<R> {
133 #[inline]
134 fn fill_buf(&mut self) -> io::Result<&[u8]> {
135 self.inner.fill_buf()
136 }
137
138 #[inline]
139 fn consume(&mut self, amount: usize) {
140 self.amt += amount as u64;
141 self.inner.consume(amount);
142 }
143}
144
145impl<W: io::Write> io::Write for Counter<W> {
146 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
147 let n = self.inner.write(buf)?;
148 self.amt += n as u64;
149 Ok(n)
150 }
151
152 #[inline]
153 fn flush(&mut self) -> io::Result<()> {
154 self.inner.flush()
155 }
156}
157
158#[cold]
159fn bad_length() -> io::Error {
160 io::Error::new(io::ErrorKind::InvalidData, "unexpected file length")
161}
162
163pub(crate) struct LengthChecker<R> {
164 expected: u64,
165 reader: R,
166}
167
168impl<R> LengthChecker<R> {
169 #[inline]
170 pub fn new(reader: R, expected: u64) -> Self {
171 Self { expected, reader }
172 }
173}
174
175impl<R: io::Read> io::Read for LengthChecker<R> {
176 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
177 let n = self.reader.read(buf)?;
178 if n == 0 && self.expected != 0 {
179 return Err(bad_length());
180 }
181 self.expected = self.expected.checked_sub(n as u64).ok_or_else(bad_length)?;
182 Ok(n)
183 }
184
185 fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
186 let size = self
187 .expected
188 .try_into()
189 .map_err(|_| io::ErrorKind::OutOfMemory)?;
190 buf.try_reserve(size)?;
191
192 let initial_len = buf.len();
193 buf.extend((0..size).map(|_| 0));
194 self.read_exact(&mut buf[initial_len..])?;
195
196 self.read(&mut [0])?;
198
199 Ok(size)
200 }
201
202 fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> {
203 let size = self
204 .expected
205 .try_into()
206 .map_err(|_| io::ErrorKind::OutOfMemory)?;
207 buf.try_reserve(size)?;
208
209 struct Reader<R>(R);
212 impl<R: io::Read> io::Read for Reader<R> {
213 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
214 self.0.read(buf)
215 }
216 fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
217 self.0.read_to_end(buf)
218 }
219 }
220
221 Reader(self).read_to_string(buf)
222 }
223}