diff --git a/src/backup/catalog_shell.rs b/src/backup/catalog_shell.rs index b79a3a7c..3c146899 100644 --- a/src/backup/catalog_shell.rs +++ b/src/backup/catalog_shell.rs @@ -309,12 +309,12 @@ fn stat_command(path: String) -> Result<(), Error> { // This is done by calling canonical_path(), which returns the full path // if it exists, error otherwise. let path = ctx.canonical_path(&path)?; - let (item, _attr, size) = ctx.lookup(&path)?; + let item = ctx.lookup(&path)?; let mut out = std::io::stdout(); out.write_all(b"File: ")?; out.write_all(item.filename.as_bytes())?; out.write_all(&[b'\n'])?; - out.write_all(format!("Size: {}\n", size).as_bytes())?; + out.write_all(format!("Size: {}\n", item.size).as_bytes())?; out.write_all(b"Type: ")?; match item.entry.mode as u32 & libc::S_IFMT { libc::S_IFDIR => out.write_all(b"directory\n")?, @@ -463,8 +463,7 @@ fn restore_command(target: String, pattern: Option) -> Result<(), Error> // Get the directory corresponding to the working directory from the // archive. let cwd = ctx.current.clone(); - let (dir, _, _) = ctx.lookup(&cwd)?; - dir + ctx.lookup(&cwd)? }; ctx.decoder @@ -681,27 +680,19 @@ impl Context { /// /// This will actively navigate the archive by calling the corresponding /// decoder functionalities and is therefore very expensive. - fn lookup( - &mut self, - absolute_path: &[DirEntry], - ) -> Result<(DirectoryEntry, PxarAttributes, u64), Error> { + fn lookup(&mut self, absolute_path: &[DirEntry]) -> Result { let mut current = self.decoder.root()?; - let (_, _, mut attr, mut size) = self.decoder.attributes(0)?; // Ignore the archive root, don't need it. for item in absolute_path.iter().skip(1) { match self .decoder .lookup(¤t, &OsStr::from_bytes(&item.name))? { - Some((item, item_attr, item_size)) => { - current = item; - attr = item_attr; - size = item_size; - } + Some(item) => current = item, // This should not happen if catalog an archive are consistent. None => bail!("no such file or directory in archive - inconsistent catalog"), } } - Ok((current, attr, size)) + Ok(current) } } diff --git a/src/pxar/decoder.rs b/src/pxar/decoder.rs index 9b07aed7..a71627c4 100644 --- a/src/pxar/decoder.rs +++ b/src/pxar/decoder.rs @@ -23,8 +23,14 @@ pub struct DirectoryEntry { start: u64, /// Points past the goodbye table tail end: u64, + /// Filename of entry pub filename: OsString, + /// Entry (mode, permissions) pub entry: PxarEntry, + /// Extended attributes + pub xattr: PxarAttributes, + /// Payload size + pub size: u64, } /// Trait to create ReadSeek Decoder trait objects. @@ -59,11 +65,19 @@ impl Decoder { let header: PxarHeader = self.inner.read_item()?; check_ca_header::(&header, PXAR_ENTRY)?; let entry: PxarEntry = self.inner.read_item()?; + let (header, xattr) = self.inner.read_attributes()?; + let size = match header.htype { + PXAR_PAYLOAD => header.size - HEADER_SIZE, + _ => 0, + }; + Ok(DirectoryEntry { start: self.root_start, end: self.root_end, filename: OsString::new(), // Empty entry, + xattr, + size, }) } @@ -116,12 +130,19 @@ impl Decoder { } check_ca_header::(&head, PXAR_ENTRY)?; let entry: PxarEntry = self.inner.read_item()?; + let (header, xattr) = self.inner.read_attributes()?; + let size = match header.htype { + PXAR_PAYLOAD => header.size - HEADER_SIZE, + _ => 0, + }; Ok(DirectoryEntry { start: entry_start, end, filename, entry, + xattr, + size, }) } @@ -273,7 +294,7 @@ impl Decoder { &mut self, dir: &DirectoryEntry, filename: &OsStr, - ) -> Result, Error> { + ) -> Result, Error> { let gbt = self.goodbye_table(Some(dir.start), dir.end)?; let hash = compute_goodbye_hash(filename.as_bytes()); @@ -298,7 +319,7 @@ impl Decoder { // the start of an item (PXAR_FILENAME) or the GOODBYE_TAIL_MARKER in // case of directories, so the use of start offset is fine for both // cases. - let (entry_name, entry, attr, payload_size) = self.attributes(*start)?; + let (entry_name, entry, xattr, size) = self.attributes(*start)?; // Possible hash collision, need to check if the found entry is indeed // the filename to lookup. @@ -308,8 +329,10 @@ impl Decoder { end: *end, filename: entry_name, entry, + xattr, + size, }; - return Ok(Some((dir_entry, attr, payload_size))); + return Ok(Some(dir_entry)); } // Hash collision, check the next entry in the goodbye table by starting // from given index but skipping one more match (so hash at index itself).