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
//! ## About
//! This crate provides some functionality to read and write __basic/classic oldstyle__ tar archives
//! and some extensions for `io::Read` and `io::Write` to make it easier to work with tar streams.
//!
//! _Note: It is not intended as an high-level allround (un-)packer but as a building block of you
//! want to use the tar format for your own applications – for a high-level solution, take a look
//! at_ [`tar`](https://crates.io/crates/tar)
//!
//! ## How to read a stream
//! To read a tar record from an archive stream, you need to read
//!  1. the header for the next record
//!  2. the payload
//!  3. the padding bytes which pad the payload to a multiple of the block size (512 byte)
//!
//! ### Example:
//! ```
//! # use std::{ convert::TryFrom, error::Error, io::Read };
//! use basic_tar::{
//! 	ReadExt, U64Ext, Header,
//! 	raw::{ self, BLOCK_LEN }
//! };
//!
//! /// Reads the next record from `stream`
//! fn read_next(mut stream: impl Read) -> Result<(Header, Vec<u8>), Box<dyn Error + 'static>> {
//! 	// Read the header
//! 	let mut header_raw = raw::header::raw();
//! 	stream.read_exact(&mut header_raw)?;
//!
//! 	// Parse the header and get the payload lengths
//! 	let header = Header::parse(header_raw)?;
//! 	let payload_len = header.size;
//! 	let payload_total_len = payload_len.ceil_to_multiple_of(BLOCK_LEN as u64);
//!
//! 	// Read the payload
//! 	let mut payload = vec![0; usize::try_from(payload_len)?];
//! 	stream.read_exact(&mut payload)?;
//!
//! 	// Drain the padding and return the record
//! 	let padding_len = usize::try_from(payload_total_len - payload_len)?;
//! 	stream.try_drain(padding_len, |_| {})?;
//! 	Ok((header, payload))
//! }
//! ```
//!
//! ## How to write a stream
//! To write a tar record to an archive archive, you need to write
//!  1. your header
//!  2. your payload
//!  3. the padding bytes to pad your payload to a multiple of the block size (512 byte)
//!
//! ### Example:
//! ```
//! # use std::{ convert::TryFrom, error::Error, io::Write };
//! use basic_tar::{ WriteExt, U64Ext, Header, raw::BLOCK_LEN };
//!
//! /// Writes `header` and `payload` to `stream`
//! fn write_next(header: Header, payload: &[u8], mut stream: impl Write)
//! 	-> Result<(), Box<dyn Error + 'static>>
//! {
//! 	// Serialize the header and write it and the payload
//! 	let header_raw = header.serialize()?;
//! 	stream.write_all(&header_raw)?;
//! 	stream.write_all(payload)?;
//!
//! 	// Write the padding
//! 	let payload_len = payload.len() as u64;
//! 	let padding_len = payload_len.ceil_to_multiple_of(BLOCK_LEN as u64) - payload_len;
//! 	stream.try_fill(usize::try_from(padding_len)?, |_| {})?;
//!
//! 	Ok(())
//! }
//! ```

mod header;
mod helpers;

use std::{
	error::Error,
	fmt::{ self, Display, Formatter }
};
pub use crate::{
	header::{ Header, raw },
	helpers::{ ReadExt, WriteExt, U64Ext }
};


/// A `basic_tar`-related error
#[derive(Debug, Eq, PartialEq, Copy, Clone)]
pub enum BasicTarError {
	/// An API misuse occurred
	ApiMisuse(&'static str),
	/// The tar header contains invalid data
	InvalidData(&'static str),
	/// The tar header field might be valid but contains an unsupported value
	Unsupported(&'static str),
	/// An empty (all zero) header was found (which is usually part of an end of archive indicator)
	EmptyHeader
}
impl Display for BasicTarError {
	fn fmt(&self, f: &mut Formatter) -> fmt::Result {
		write!(f, "{:?}", self)
	}
}
impl Error for BasicTarError {}