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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
use std::cell::{Cell, RefCell};
use std::fs;
use std::io::{self, Cursor, ErrorKind, Read, Seek, SeekFrom};
use std::path::Path;
use flate2::read::GzDecoder;
use tar_::Archive;
use crate::index::Index;
use crate::store::Store;
use crate::{Entries, Entry};
pub struct TarFs<F: Read + Seek> {
gzip: Cell<bool>,
inner: RefCell<F>,
index: Option<Index<SeekFrom>>,
}
pub struct TarFsFile {
inner: Cursor<Box<[u8]>>,
}
impl Read for TarFsFile {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.inner.read(buf)
}
}
impl Seek for TarFsFile {
#[inline]
fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
self.inner.seek(pos)
}
}
impl<T: Read + Seek> Store for TarFs<T> {
type File = TarFsFile;
fn open_path(&self, path: &Path) -> io::Result<Self::File> {
if self.gzip.get() {
let mut file = self.inner.borrow_mut();
file.seek(SeekFrom::Start(0))?;
self.open_read(path, GzDecoder::new(&mut *file))
} else {
let mut file = self.inner.borrow_mut();
file.seek(SeekFrom::Start(0))?;
match self.open_read(path, &mut *file) {
Ok(entry) => Ok(entry),
Err(ref e) if e.kind() == ErrorKind::NotFound => {
Err(io::Error::from(ErrorKind::NotFound))
}
Err(_) => {
self.gzip.set(true);
drop(file);
self.open_path(path)
}
}
}
}
fn entries_path(&self, path: &Path) -> io::Result<Entries> {
if let Some(ref idx) = self.index {
Ok(Entries::new(idx.entries(path).map(|ent| {
let name = ent.name.to_os_string();
let kind = ent.kind;
Ok(Entry { name, kind })
})))
} else {
panic!("You have to call the `Zip::index` method on this zip archive before you can list its entries.")
}
}
}
impl TarFs<fs::File> {
pub fn open<P: AsRef<Path>>(path: P) -> io::Result<Self> {
let file = fs::OpenOptions::new()
.read(true)
.write(false)
.create(false)
.open(path)?;
Ok(Self::new(file))
}
}
impl<T: Read + Seek> TarFs<T> {
pub fn new(inner: T) -> Self {
Self {
inner: RefCell::new(inner),
gzip: Cell::new(false),
index: None,
}
}
fn open_read<R: Read>(&self, path: &Path, read: R) -> io::Result<TarFsFile> {
let mut archive = Archive::new(read);
for entry in archive.entries()? {
let mut entry = entry?;
if path == entry.path()? {
let mut data = Vec::new();
entry.read_to_end(&mut data)?;
return Ok(TarFsFile {
inner: Cursor::new(data.into()),
});
}
}
Err(io::Error::from(ErrorKind::NotFound))
}
pub fn index(self) -> io::Result<Self> {
unimplemented!("TarFs indexing hasn't been implemented yet.");
}
}