]>
git.proxmox.com Git - proxmox-backup.git/blob - src/pxar/decoder.rs
1 //! *pxar* format decoder for seekable files
3 //! This module contain the code to decode *pxar* archive files.
7 use super::format_definition
::*;
8 use super::sequential_decoder
::*;
10 use std
::io
::{Read, Seek, SeekFrom}
;
11 use std
::path
::{Path, PathBuf}
;
13 use std
::ffi
::OsString
;
16 pub struct CaDirectoryEntry
{
19 pub filename
: OsString
,
23 // This one needs Read+Seek
24 pub struct Decoder
<'a
, R
: Read
+ Seek
, F
: Fn(&Path
) -> Result
<(), Error
>> {
25 inner
: SequentialDecoder
<'a
, R
, F
>,
30 const HEADER_SIZE
: u64 = std
::mem
::size_of
::<PxarHeader
>() as u64;
32 impl <'a
, R
: Read
+ Seek
, F
: Fn(&Path
) -> Result
<(), Error
>> Decoder
<'a
, R
, F
> {
34 pub fn new(reader
: &'a
mut R
, callback
: F
) -> Result
<Self, Error
> {
36 let root_end
= reader
.seek(SeekFrom
::End(0))?
;
39 inner
: SequentialDecoder
::new(reader
, super::flags
::DEFAULT
, callback
),
45 pub fn root(&self) -> CaDirectoryEntry
{
47 start
: self.root_start
,
49 filename
: OsString
::new(), // Empty
60 fn seek(&mut self, pos
: SeekFrom
) -> Result
<u64, Error
> {
61 let pos
= self.inner
.get_reader_mut().seek(pos
)?
;
67 dir
: &CaDirectoryEntry
,
69 ) -> Result
<(), Error
> {
70 let start
= dir
.start
;
72 self.seek(SeekFrom
::Start(start
))?
;
74 self.inner
.restore(path
, &Vec
::new())?
;
79 fn read_directory_entry(&mut self, start
: u64, end
: u64) -> Result
<CaDirectoryEntry
, Error
> {
81 self.seek(SeekFrom
::Start(start
))?
;
83 let head
: PxarHeader
= self.inner
.read_item()?
;
85 if head
.htype
!= PXAR_FILENAME
{
86 bail
!("wrong filename header type for object [{}..{}]", start
, end
);
89 let entry_start
= start
+ head
.size
;
91 let filename
= self.inner
.read_filename(head
.size
)?
;
93 let head
: PxarHeader
= self.inner
.read_item()?
;
94 check_ca_header
::<PxarEntry
>(&head
, PXAR_ENTRY
)?
;
95 let entry
: PxarEntry
= self.inner
.read_item()?
;
105 pub fn list_dir(&mut self, dir
: &CaDirectoryEntry
) -> Result
<Vec
<CaDirectoryEntry
>, Error
> {
107 const GOODBYE_ITEM_SIZE
: u64 = std
::mem
::size_of
::<PxarGoodbyeItem
>() as u64;
109 let start
= dir
.start
;
112 //println!("list_dir1: {} {}", start, end);
114 if (end
- start
) < (HEADER_SIZE
+ GOODBYE_ITEM_SIZE
) {
115 bail
!("detected short object [{}..{}]", start
, end
);
118 self.seek(SeekFrom
::Start(end
- GOODBYE_ITEM_SIZE
))?
;
120 let item
: PxarGoodbyeItem
= self.inner
.read_item()?
;
122 if item
.hash
!= PXAR_GOODBYE_TAIL_MARKER
{
123 bail
!("missing goodbye tail marker for object [{}..{}]", start
, end
);
126 let goodbye_table_size
= item
.size
;
127 if goodbye_table_size
< (HEADER_SIZE
+ GOODBYE_ITEM_SIZE
) {
128 bail
!("short goodbye table size for object [{}..{}]", start
, end
);
131 let goodbye_inner_size
= goodbye_table_size
- HEADER_SIZE
- GOODBYE_ITEM_SIZE
;
132 if (goodbye_inner_size
% GOODBYE_ITEM_SIZE
) != 0 {
133 bail
!("wrong goodbye inner table size for entry [{}..{}]", start
, end
);
136 let goodbye_start
= end
- goodbye_table_size
;
138 if item
.offset
!= (goodbye_start
- start
) {
139 println
!("DEBUG: {} {}", u64::from_le(item
.offset
), goodbye_start
- start
);
140 bail
!("wrong offset in goodbye tail marker for entry [{}..{}]", start
, end
);
143 self.seek(SeekFrom
::Start(goodbye_start
))?
;
144 let head
: PxarHeader
= self.inner
.read_item()?
;
146 if head
.htype
!= PXAR_GOODBYE
{
147 bail
!("wrong goodbye table header type for entry [{}..{}]", start
, end
);
150 if head
.size
!= goodbye_table_size
{
151 bail
!("wrong goodbye table size for entry [{}..{}]", start
, end
);
154 let mut range_list
= Vec
::new();
156 for i
in 0..goodbye_inner_size
/GOODBYE_ITEM_SIZE
{
157 let item
: PxarGoodbyeItem
= self.inner
.read_item()?
;
159 if item
.offset
> (goodbye_start
- start
) {
160 bail
!("goodbye entry {} offset out of range [{}..{}] {} {} {}",
161 i
, start
, end
, item
.offset
, goodbye_start
, start
);
163 let item_start
= goodbye_start
- item
.offset
;
164 let item_end
= item_start
+ item
.size
;
165 if item_end
> goodbye_start
{
166 bail
!("goodbye entry {} end out of range [{}..{}]",
170 range_list
.push((item_start
, item_end
));
173 let mut result
= vec
![];
175 for (item_start
, item_end
) in range_list
{
176 let entry
= self.read_directory_entry(item_start
, item_end
)?
;
177 //println!("ENTRY: {} {} {:?}", item_start, item_end, entry.filename);
184 pub fn print_filenames
<W
: std
::io
::Write
>(
187 prefix
: &mut PathBuf
,
188 dir
: &CaDirectoryEntry
,
189 ) -> Result
<(), Error
> {
191 let mut list
= self.list_dir(dir
)?
;
193 list
.sort_unstable_by(|a
, b
| a
.filename
.cmp(&b
.filename
));
197 prefix
.push(item
.filename
.clone());
199 let mode
= item
.entry
.mode
as u32;
201 let ifmt
= mode
& libc
::S_IFMT
;
203 writeln
!(output
, "{:?}", prefix
)?
;
205 if ifmt
== libc
::S_IFDIR
{
206 self.print_filenames(output
, prefix
, item
)?
;
207 } else if ifmt
== libc
::S_IFREG
{
208 } else if ifmt
== libc
::S_IFLNK
{
209 } else if ifmt
== libc
::S_IFBLK
{
210 } else if ifmt
== libc
::S_IFCHR
{
212 bail
!("unknown item mode/type for {:?}", prefix
);