1use std::cell::{Cell, RefCell};
2use std::fs;
3use std::io::{self, Cursor, ErrorKind, Read, Seek, SeekFrom};
4use std::path::Path;
5
6use flate2::read::GzDecoder;
7use tar_::Archive;
8
9use crate::index::Index;
10use crate::store::Store;
11use crate::{Entries, Entry};
12
13pub struct TarFs<F: Read + Seek> {
20 gzip: Cell<bool>,
21 inner: RefCell<F>,
22 index: Option<Index<SeekFrom>>,
23}
24
25pub struct TarFsFile {
27 inner: Cursor<Box<[u8]>>,
28}
29
30impl Read for TarFsFile {
31 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
32 self.inner.read(buf)
33 }
34}
35
36impl Seek for TarFsFile {
37 #[inline]
38 fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
39 self.inner.seek(pos)
40 }
41}
42
43impl<T: Read + Seek> Store for TarFs<T> {
44 type File = TarFsFile;
45
46 fn open_path(&self, path: &Path) -> io::Result<Self::File> {
47 if self.gzip.get() {
48 let mut file = self.inner.borrow_mut();
49 file.seek(SeekFrom::Start(0))?;
50 self.open_read(path, GzDecoder::new(&mut *file))
51 } else {
52 let mut file = self.inner.borrow_mut();
53 file.seek(SeekFrom::Start(0))?;
54 match self.open_read(path, &mut *file) {
55 Ok(entry) => Ok(entry),
56 Err(ref e) if e.kind() == ErrorKind::NotFound => {
57 Err(io::Error::from(ErrorKind::NotFound))
58 }
59 Err(_) => {
60 self.gzip.set(true);
61 drop(file);
62 self.open_path(path)
63 }
64 }
65 }
66 }
67
68 fn entries_path(&self, path: &Path) -> io::Result<Entries> {
69 if let Some(ref idx) = self.index {
70 Ok(Entries::new(idx.entries(path).map(|ent| {
71 let name = ent.name.to_os_string();
72 let kind = ent.kind;
73 Ok(Entry { name, kind })
74 })))
75 } else {
76 panic!("You have to call the `Zip::index` method on this zip archive before you can list its entries.")
77 }
78 }
79}
80
81impl TarFs<fs::File> {
82 pub fn open<P: AsRef<Path>>(path: P) -> io::Result<Self> {
84 let file = fs::OpenOptions::new()
85 .read(true)
86 .write(false)
87 .create(false)
88 .open(path)?;
89 Ok(Self::new(file))
90 }
91}
92
93impl<T: Read + Seek> TarFs<T> {
94 pub fn new(inner: T) -> Self {
95 Self {
96 inner: RefCell::new(inner),
97 gzip: Cell::new(false),
98 index: None,
99 }
100 }
101
102 fn open_read<R: Read>(&self, path: &Path, read: R) -> io::Result<TarFsFile> {
103 let mut archive = Archive::new(read);
104 for entry in archive.entries()? {
105 let mut entry = entry?;
106 if path == entry.path()? {
107 let mut data = Vec::new();
108 entry.read_to_end(&mut data)?;
109 return Ok(TarFsFile {
110 inner: Cursor::new(data.into()),
111 });
112 }
113 }
114 Err(io::Error::from(ErrorKind::NotFound))
115 }
116
117 pub fn index(self) -> io::Result<Self> {
122 unimplemented!("TarFs indexing hasn't been implemented yet.");
123 }
124}