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
,
20 pub entry
: CaFormatEntry
,
23 // This one needs Read+Seek
24 pub struct Decoder
<'a
, R
: Read
+ Seek
> {
25 inner
: SequentialDecoder
<'a
, R
>,
30 const HEADER_SIZE
: u64 = std
::mem
::size_of
::<CaFormatHeader
>() as u64;
32 impl <'a
, R
: Read
+ Seek
> Decoder
<'a
, R
> {
34 pub fn new(reader
: &'a
mut R
) -> Result
<Self, Error
> {
36 let root_end
= reader
.seek(SeekFrom
::End(0))?
;
37 let no_xattrs
= false;
41 inner
: SequentialDecoder
::new(reader
, no_xattrs
, no_fcaps
),
47 pub fn root(&self) -> CaDirectoryEntry
{
49 start
: self.root_start
,
51 filename
: OsString
::new(), // Empty
52 entry
: CaFormatEntry
{
62 fn seek(&mut self, pos
: SeekFrom
) -> Result
<u64, Error
> {
63 let pos
= self.inner
.get_reader_mut().seek(pos
)?
;
69 dir
: &CaDirectoryEntry
,
72 ) -> Result
<(), Error
>
73 where F
: Fn(&Path
) -> Result
<(), Error
>
75 let start
= dir
.start
;
77 self.seek(SeekFrom
::Start(start
))?
;
79 self.inner
.restore(path
, &callback
)?
;
84 fn read_directory_entry(&mut self, start
: u64, end
: u64) -> Result
<CaDirectoryEntry
, Error
> {
86 self.seek(SeekFrom
::Start(start
))?
;
88 let head
: CaFormatHeader
= self.inner
.read_item()?
;
90 if head
.htype
!= CA_FORMAT_FILENAME
{
91 bail
!("wrong filename header type for object [{}..{}]", start
, end
);
94 let entry_start
= start
+ head
.size
;
96 let filename
= self.inner
.read_filename(head
.size
)?
;
98 let head
: CaFormatHeader
= self.inner
.read_item()?
;
99 check_ca_header
::<CaFormatEntry
>(&head
, CA_FORMAT_ENTRY
)?
;
100 let entry
: CaFormatEntry
= self.inner
.read_item()?
;
102 Ok(CaDirectoryEntry
{
110 pub fn list_dir(&mut self, dir
: &CaDirectoryEntry
) -> Result
<Vec
<CaDirectoryEntry
>, Error
> {
112 const GOODBYE_ITEM_SIZE
: u64 = std
::mem
::size_of
::<CaFormatGoodbyeItem
>() as u64;
114 let start
= dir
.start
;
117 //println!("list_dir1: {} {}", start, end);
119 if (end
- start
) < (HEADER_SIZE
+ GOODBYE_ITEM_SIZE
) {
120 bail
!("detected short object [{}..{}]", start
, end
);
123 self.seek(SeekFrom
::Start(end
- GOODBYE_ITEM_SIZE
))?
;
125 let item
: CaFormatGoodbyeItem
= self.inner
.read_item()?
;
127 if item
.hash
!= CA_FORMAT_GOODBYE_TAIL_MARKER
{
128 bail
!("missing goodbye tail marker for object [{}..{}]", start
, end
);
131 let goodbye_table_size
= item
.size
;
132 if goodbye_table_size
< (HEADER_SIZE
+ GOODBYE_ITEM_SIZE
) {
133 bail
!("short goodbye table size for object [{}..{}]", start
, end
);
136 let goodbye_inner_size
= goodbye_table_size
- HEADER_SIZE
- GOODBYE_ITEM_SIZE
;
137 if (goodbye_inner_size
% GOODBYE_ITEM_SIZE
) != 0 {
138 bail
!("wrong goodbye inner table size for entry [{}..{}]", start
, end
);
141 let goodbye_start
= end
- goodbye_table_size
;
143 if item
.offset
!= (goodbye_start
- start
) {
144 println
!("DEBUG: {} {}", u64::from_le(item
.offset
), goodbye_start
- start
);
145 bail
!("wrong offset in goodbye tail marker for entry [{}..{}]", start
, end
);
148 self.seek(SeekFrom
::Start(goodbye_start
))?
;
149 let head
: CaFormatHeader
= self.inner
.read_item()?
;
151 if head
.htype
!= CA_FORMAT_GOODBYE
{
152 bail
!("wrong goodbye table header type for entry [{}..{}]", start
, end
);
155 if head
.size
!= goodbye_table_size
{
156 bail
!("wrong goodbye table size for entry [{}..{}]", start
, end
);
159 let mut range_list
= Vec
::new();
161 for i
in 0..goodbye_inner_size
/GOODBYE_ITEM_SIZE
{
162 let item
: CaFormatGoodbyeItem
= self.inner
.read_item()?
;
164 if item
.offset
> (goodbye_start
- start
) {
165 bail
!("goodbye entry {} offset out of range [{}..{}] {} {} {}",
166 i
, start
, end
, item
.offset
, goodbye_start
, start
);
168 let item_start
= goodbye_start
- item
.offset
;
169 let item_end
= item_start
+ item
.size
;
170 if item_end
> goodbye_start
{
171 bail
!("goodbye entry {} end out of range [{}..{}]",
175 range_list
.push((item_start
, item_end
));
178 let mut result
= vec
![];
180 for (item_start
, item_end
) in range_list
{
181 let entry
= self.read_directory_entry(item_start
, item_end
)?
;
182 //println!("ENTRY: {} {} {:?}", item_start, item_end, entry.filename);
189 pub fn print_filenames
<W
: std
::io
::Write
>(
192 prefix
: &mut PathBuf
,
193 dir
: &CaDirectoryEntry
,
194 ) -> Result
<(), Error
> {
196 let mut list
= self.list_dir(dir
)?
;
198 list
.sort_unstable_by(|a
, b
| a
.filename
.cmp(&b
.filename
));
202 prefix
.push(item
.filename
.clone());
204 let mode
= item
.entry
.mode
as u32;
206 let ifmt
= mode
& libc
::S_IFMT
;
208 writeln
!(output
, "{:?}", prefix
)?
;
210 if ifmt
== libc
::S_IFDIR
{
211 self.print_filenames(output
, prefix
, item
)?
;
212 } else if ifmt
== libc
::S_IFREG
{
213 } else if ifmt
== libc
::S_IFLNK
{
214 } else if ifmt
== libc
::S_IFBLK
{
215 } else if ifmt
== libc
::S_IFCHR
{
217 bail
!("unknown item mode/type for {:?}", prefix
);