Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve ArchiveError information #7

Merged
merged 2 commits into from
Oct 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ path = "src/lib.rs"
[dependencies]
chrono = "0.4.30"
flate2 = "1.0.27"
thiserror = "1.0.49"

[dev-dependencies]
hex-literal = "0.4.1"
25 changes: 16 additions & 9 deletions src/archive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,9 @@ impl Archive {
let mut buffer = vec![0; 5];
f.read_exact(buffer.as_mut_slice())?;
if buffer != "PGDMP".as_bytes() {
return Err(ArchiveError::InvalidData);
return Err(ArchiveError::InvalidData(
"file does not start with PGDMP".into(),
));
}

let mut io_config = ReadConfig::new();
Expand All @@ -105,24 +107,27 @@ impl Archive {

if io_config.read_byte(f)? != 1 {
// 1 = archCustom
return Err(ArchiveError::IOError(io::Error::new(
io::ErrorKind::Other,
"wrong file format",
)));
return Err(ArchiveError::InvalidData(
"file format must be 1 (custom)".into(),
));
}

let compression_method = if version >= (1, 15, 0) {
io_config
.read_byte(f)?
.try_into()
.or(Err(ArchiveError::InvalidData))?
.or(Err(ArchiveError::InvalidData(
"invalid compression method".into(),
)))?
} else {
let compression = io_config.read_int(f)?;
match compression {
-1 => Ok(CompressionMethod::ZSTD),
0 => Ok(CompressionMethod::None),
1..=9 => Ok(CompressionMethod::Gzip(compression)),
_ => Err(ArchiveError::InvalidData),
_ => Err(ArchiveError::InvalidData(
"invalid compression method".into(),
)),
}?
};

Expand All @@ -139,9 +144,11 @@ impl Archive {
created_mon as u32,
created_mday as u32,
)
.ok_or(ArchiveError::InvalidData)?
.ok_or(ArchiveError::InvalidData("invalid creation date".into()))?
.and_hms_opt(created_hour as u32, created_min as u32, created_sec as u32)
.ok_or(ArchiveError::InvalidData)?;
.ok_or(ArchiveError::InvalidData(
"invalid time in creation date".into(),
))?;

let database_name = io_config.read_string(f)?;
let server_version = io_config.read_string(f)?;
Expand Down
2 changes: 1 addition & 1 deletion src/io.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ impl ReadConfig {
let block_type: BlockType = self
.read_byte(f)?
.try_into()
.or(Err(ArchiveError::InvalidData))?;
.or(Err(ArchiveError::InvalidData("invalid block type".into())))?;
let _id = self.read_int(f)?;
match block_type {
BlockType::Blob => Err(ArchiveError::BlobNotSupported),
Expand Down
15 changes: 10 additions & 5 deletions src/toc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ impl TocEntry {
pub fn parse(f: &mut (impl Read + ?Sized), cfg: &ReadConfig) -> Result<TocEntry, ArchiveError> {
let id: ID = cfg.read_int(f)?;
if id < 0 {
return Err(ArchiveError::InvalidData);
return Err(ArchiveError::InvalidData("negative TOC id".into()));
}
let had_dumper = cfg.read_int_bool(f)?;
let table_oid = cfg.read_oid(f)?;
Expand All @@ -59,7 +59,9 @@ impl TocEntry {
let section: Section = cfg
.read_int(f)?
.try_into()
.or(Err(ArchiveError::InvalidData))?;
.or(Err(ArchiveError::InvalidData(
"invalid section type".into(),
)))?;
let defn = cfg.read_string(f)?;
let drop_stmt = cfg.read_string(f)?;
let copy_stmt = cfg.read_string(f)?;
Expand All @@ -69,16 +71,19 @@ impl TocEntry {
let owner = cfg.read_string(f)?;
if cfg.read_string_bool(f)? {
// This *must* be false
return Err(ArchiveError::InvalidData);
return Err(ArchiveError::InvalidData(
"mysterious value must be false".into(),
));
}
let mut dependencies = Vec::new();
loop {
let dep_id = cfg.read_string(f)?;
if dep_id.is_empty() {
break;
}
dependencies
.push(ID::from_str_radix(dep_id.as_str(), 10).or(Err(ArchiveError::InvalidData))?);
dependencies.push(ID::from_str_radix(dep_id.as_str(), 10).or(Err(
ArchiveError::InvalidData("invalid dependency id".into()),
))?);
}
let offset = cfg.read_offset(f)?;

Expand Down
19 changes: 10 additions & 9 deletions src/types.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use std::fmt;
use std::io;
use thiserror::Error;

/// Type used for PostgreSQL version numbers
pub type Version = (u8, u8, u8);
Expand All @@ -8,31 +9,31 @@ pub type Version = (u8, u8, u8);
///
/// Errors can be caused by underlying IO errors, unsupported features or
/// invalid data.
#[derive(Debug)]
#[derive(Error, Debug)]
pub enum ArchiveError {
/// An IO errors occured while reading data.
IOError(io::Error),
#[error("IO error reading data")]
IOError(#[from] io::Error),
/// Invalid data was found. This should only happen of the archive is
/// corrupted (or pgarchive has a bug).
InvalidData,
#[error("format error: {0}")]
InvalidData(String),
/// Returned when you try to read the data for a
/// [`TocEntry`](crate::TocEntry), but it has no data.
#[error("TOC entry has no data")]
NoDataPresent,
/// pgarchive does not support reading blob data.
#[error("reading BLOB data is not supported")]
BlobNotSupported,
/// The archive was made by a pg_dump version that is not supported by this
/// crate.
#[error("archive format {}.{}.{} is not supported", (.0).0, (.0).1, (.0).2)]
UnsupportedVersionError(Version),
/// An unsupported compression method was used for table data.
#[error("compression method {0} is not supported")]
CompressionMethodNotSupported(CompressionMethod),
}

impl From<io::Error> for ArchiveError {
fn from(e: io::Error) -> ArchiveError {
ArchiveError::IOError(e)
}
}

pub type Oid = u64;

#[derive(Clone, Copy, PartialEq, Debug)]
Expand Down