Skip to content

Commit 7536726

Browse files
authored
Merge pull request #28 from jplatte/snafu
superblock: Convert to snafu and split up the Error type
2 parents 63deb2f + 437299f commit 7536726

File tree

11 files changed

+123
-77
lines changed

11 files changed

+123
-77
lines changed

Cargo.lock

Lines changed: 28 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ nix = { version = "0.30.1", features = ["fs", "mount"] }
2020
phf = "0.11"
2121
serde = { version = "1.0" }
2222
serde_json = "1.0"
23+
snafu = "0.8.5"
2324
test-log = "0.2.17"
2425
thiserror = "2.0.3"
2526
uuid = { version = "1.12.1", features = ["v8"] }

crates/superblock/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ edition = "2021"
88
[dependencies]
99
serde = { workspace = true, features = ["derive"] }
1010
serde_json.workspace = true
11-
thiserror.workspace = true
11+
snafu.workspace = true
1212
uuid = { workspace = true, features = ["v8"] }
1313
zerocopy = { workspace = true, features = ["derive", "std"] }
1414

crates/superblock/src/btrfs.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
//! This module provides functionality for reading and parsing BTRFS filesystem superblocks,
88
//! which contain critical metadata about the filesystem including UUIDs and labels.
99
10-
use crate::{Detection, Error};
10+
use crate::{Detection, UnicodeError};
1111
use uuid::Uuid;
1212
use zerocopy::*;
1313

@@ -117,12 +117,12 @@ impl Detection for Btrfs {
117117

118118
impl Btrfs {
119119
/// Return the encoded UUID for this superblock as a string
120-
pub fn uuid(&self) -> Result<String, Error> {
120+
pub fn uuid(&self) -> Result<String, UnicodeError> {
121121
Ok(Uuid::from_bytes(self.fsid).hyphenated().to_string())
122122
}
123123

124124
/// Return the volume label as a string
125-
pub fn label(&self) -> Result<String, Error> {
125+
pub fn label(&self) -> Result<String, UnicodeError> {
126126
Ok(str::from_utf8(&self.label)?.trim_end_matches('\0').to_owned())
127127
}
128128
}

crates/superblock/src/ext4.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
//! The superblock contains critical metadata about the filesystem including UUID, volume label,
99
//! and various configuration parameters.
1010
11-
use crate::{Detection, Error};
11+
use crate::{Detection, UnicodeError};
1212
use uuid::Uuid;
1313
use zerocopy::*;
1414

@@ -209,12 +209,12 @@ impl Detection for Ext4 {
209209

210210
impl Ext4 {
211211
/// Return the encoded UUID for this superblock
212-
pub fn uuid(&self) -> Result<String, Error> {
212+
pub fn uuid(&self) -> Result<String, UnicodeError> {
213213
Ok(Uuid::from_bytes(self.uuid).hyphenated().to_string())
214214
}
215215

216216
/// Return the volume label as valid utf8
217-
pub fn label(&self) -> Result<String, super::Error> {
217+
pub fn label(&self) -> Result<String, UnicodeError> {
218218
Ok(str::from_utf8(&self.volume_name)?.into())
219219
}
220220
}

crates/superblock/src/f2fs.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
//! - Encryption settings
1414
//! - Device information
1515
16-
use crate::{Detection, Error};
16+
use crate::{Detection, UnicodeError};
1717
use uuid::Uuid;
1818
use zerocopy::*;
1919

@@ -163,14 +163,14 @@ pub const START_POSITION: u64 = 1024;
163163

164164
impl F2FS {
165165
/// Returns the filesystem UUID as a hyphenated string
166-
pub fn uuid(&self) -> Result<String, Error> {
166+
pub fn uuid(&self) -> Result<String, UnicodeError> {
167167
Ok(Uuid::from_bytes(self.uuid).hyphenated().to_string())
168168
}
169169

170170
/// Returns the volume label as a UTF-16 decoded string
171171
///
172172
/// Handles null termination and invalid UTF-16 sequences
173-
pub fn label(&self) -> Result<String, Error> {
173+
pub fn label(&self) -> Result<String, UnicodeError> {
174174
// Convert the array of U16<LittleEndian> to u16
175175
let vol = self.volume_name.map(|x| x.get());
176176
let prelim_label = String::from_utf16(&vol)?;

crates/superblock/src/fat.rs

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
//! - Volume name and UUID
1111
//! - Encryption settings
1212
13-
use crate::{Detection, Error};
13+
use crate::{Detection, UnicodeError};
1414
use zerocopy::*;
1515

1616
/// Starting position of superblock in bytes
@@ -120,26 +120,26 @@ pub enum FatType {
120120
}
121121

122122
impl Fat {
123-
pub fn fat_type(&self) -> Result<FatType, Error> {
123+
pub fn fat_type(&self) -> FatType {
124124
// this is how the linux kernel does it in https://github.com/torvalds/linux/blob/master/fs/fat/inode.c
125125
if self.fat_length == 0 && self.fat32().fat32_length != 0 {
126-
Ok(FatType::Fat32)
126+
FatType::Fat32
127127
} else {
128-
Ok(FatType::Fat16)
128+
FatType::Fat16
129129
}
130130
}
131131

132132
/// Returns the filesystem id
133-
pub fn uuid(&self) -> Result<String, Error> {
134-
match self.fat_type()? {
133+
pub fn uuid(&self) -> Result<String, UnicodeError> {
134+
Ok(match self.fat_type() {
135135
FatType::Fat16 => vol_id(self.fat16().common.vol_id),
136136
FatType::Fat32 => vol_id(self.fat32().common.vol_id),
137-
}
137+
})
138138
}
139139

140140
/// Returns the volume label
141-
pub fn label(&self) -> Result<String, Error> {
142-
match self.fat_type()? {
141+
pub fn label(&self) -> Result<String, UnicodeError> {
142+
match self.fat_type() {
143143
FatType::Fat16 => vol_label(&self.fat16().common.vol_label),
144144
FatType::Fat32 => vol_label(&self.fat32().common.vol_label),
145145
}
@@ -163,10 +163,10 @@ fn first_n_bytes<const N: usize, const M: usize>(arr: &[u8; M]) -> &[u8; N] {
163163
<&[u8; N]>::try_from(&arr[..N]).unwrap()
164164
}
165165

166-
fn vol_label(vol_label: &[u8; 11]) -> Result<String, Error> {
166+
fn vol_label(vol_label: &[u8; 11]) -> Result<String, UnicodeError> {
167167
Ok(String::from_utf8_lossy(vol_label).trim_end_matches(' ').to_string())
168168
}
169169

170-
fn vol_id(vol_id: U32<LittleEndian>) -> Result<String, Error> {
171-
Ok(format!("{:04X}-{:04X}", vol_id >> 16, vol_id & 0xFFFF))
170+
fn vol_id(vol_id: U32<LittleEndian>) -> String {
171+
format!("{:04X}-{:04X}", vol_id >> 16, vol_id & 0xFFFF)
172172
}

crates/superblock/src/lib.rs

Lines changed: 35 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
1010
use std::io::{self, BufRead, Cursor, Read, Seek};
1111

12-
use thiserror::Error;
12+
use snafu::{ResultExt, Snafu};
1313
use zerocopy::FromBytes;
1414

1515
pub mod btrfs;
@@ -38,35 +38,31 @@ pub trait Detection: Sized + FromBytes {
3838
}
3939

4040
/// Errors that can occur when reading superblocks
41-
#[derive(Debug, Error)]
41+
#[derive(Debug, Snafu)]
4242
pub enum Error {
43+
/// An I/O error occurred
44+
#[snafu(display("io"))]
45+
Io { source: io::Error },
46+
4347
/// No known filesystem superblock was detected
44-
#[error("unknown superblock")]
48+
#[snafu(display("unknown superblock"))]
4549
UnknownSuperblock,
50+
}
4651

47-
/// Invalid JSON
48-
#[error("invalid json")]
49-
InvalidJson(#[from] serde_json::Error),
50-
51-
/// The requested feature is not implemented for this filesystem type
52-
#[error("unsupported feature")]
53-
UnsupportedFeature,
54-
52+
/// Errors that can occur when decoding strings from FS metadata
53+
#[derive(Debug, Snafu)]
54+
pub enum UnicodeError {
5555
/// Error decoding UTF-8 string data
56-
#[error("invalid utf8 in decode: {0}")]
57-
Utf8Decoding(#[from] std::str::Utf8Error),
56+
#[snafu(display("{source}"), context(false))]
57+
InvalidUtf8 { source: std::str::Utf8Error },
5858

5959
/// Error decoding UTF-16 string data
60-
#[error("invalid utf16 in decode: {0}")]
61-
Utf16Decoding(#[from] std::string::FromUtf16Error),
62-
63-
/// An I/O error occurred
64-
#[error("io: {0}")]
65-
IO(#[from] io::Error),
60+
#[snafu(display("{source}"), context(false))]
61+
InvalidUtf16 { source: std::string::FromUtf16Error },
6662
}
6763

6864
/// Attempts to detect a superblock of the given type from the reader
69-
pub fn detect_superblock<T: Detection, R: BufRead + Seek>(reader: &mut R) -> Result<Option<T>, Error> {
65+
pub fn detect_superblock<T: Detection, R: BufRead + Seek>(reader: &mut R) -> io::Result<Option<T>> {
7066
reader.seek(io::SeekFrom::Start(T::MAGIC_OFFSET))?;
7167
let mut magic_buf = vec![0u8; std::mem::size_of::<T::Magic>()];
7268
reader.read_exact(&mut magic_buf)?;
@@ -139,7 +135,7 @@ impl Superblock {
139135
}
140136

141137
/// Returns the filesystem UUID if available
142-
pub fn uuid(&self) -> Result<String, Error> {
138+
pub fn uuid(&self) -> Result<String, UnicodeError> {
143139
match self {
144140
Superblock::Btrfs(block) => block.uuid(),
145141
Superblock::Ext4(block) => block.uuid(),
@@ -151,7 +147,7 @@ impl Superblock {
151147
}
152148

153149
/// Returns the volume label if available
154-
pub fn label(&self) -> Result<String, Error> {
150+
pub fn label(&self) -> Result<String, UnicodeError> {
155151
match self {
156152
Superblock::Btrfs(block) => block.label(),
157153
Superblock::Ext4(block) => block.label(),
@@ -170,25 +166,22 @@ impl Superblock {
170166
pub fn from_bytes(bytes: &[u8]) -> Result<Self, Error> {
171167
let mut cursor = Cursor::new(bytes);
172168

173-
// Try each filesystem type in order of likelihood
174-
if let Some(sb) = detect_superblock::<ext4::Ext4, _>(&mut cursor)? {
175-
return Ok(Self::Ext4(Box::new(sb)));
176-
}
177-
if let Some(sb) = detect_superblock::<btrfs::Btrfs, _>(&mut cursor)? {
178-
return Ok(Self::Btrfs(Box::new(sb)));
179-
}
180-
if let Some(sb) = detect_superblock::<f2fs::F2FS, _>(&mut cursor)? {
181-
return Ok(Self::F2FS(Box::new(sb)));
182-
}
183-
if let Some(sb) = detect_superblock::<xfs::Xfs, _>(&mut cursor)? {
184-
return Ok(Self::Xfs(Box::new(sb)));
185-
}
186-
if let Some(sb) = detect_superblock::<luks2::Luks2, _>(&mut cursor)? {
187-
return Ok(Self::Luks2(Box::new(sb)));
188-
}
189-
if let Some(sb) = detect_superblock::<fat::Fat, _>(&mut cursor)? {
190-
return Ok(Self::Fat(Box::new(sb)));
169+
macro_rules! try_detect {
170+
($variant:ident, $ty:ty) => {
171+
if let Some(sb) = detect_superblock::<$ty, _>(&mut cursor).context(IoSnafu)? {
172+
return Ok(Self::$variant(Box::new(sb)));
173+
}
174+
};
191175
}
176+
177+
// Try each filesystem type in order of likelihood
178+
try_detect!(Ext4, ext4::Ext4);
179+
try_detect!(Btrfs, btrfs::Btrfs);
180+
try_detect!(F2FS, f2fs::F2FS);
181+
try_detect!(Xfs, xfs::Xfs);
182+
try_detect!(Luks2, luks2::Luks2);
183+
try_detect!(Fat, fat::Fat);
184+
192185
Err(Error::UnknownSuperblock)
193186
}
194187

@@ -199,8 +192,8 @@ impl Superblock {
199192
pub fn from_reader<R: Read + Seek>(reader: &mut R) -> Result<Self, Error> {
200193
// Preallocate a fixed buffer for the largest superblock we need to read
201194
let mut bytes = vec![0u8; 128 * 1024]; // 128KB covers all superblock offsets
202-
reader.rewind()?;
203-
reader.read_exact(&mut bytes)?;
195+
reader.rewind().context(IoSnafu)?;
196+
reader.read_exact(&mut bytes).context(IoSnafu)?;
204197

205198
Self::from_bytes(&bytes)
206199
}

crates/superblock/src/luks2.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,28 @@
1111
//! like encryption parameters, key slots and segment information in JSON format.
1212
//!
1313
14+
use std::io;
15+
16+
use snafu::Snafu;
17+
1418
mod config;
1519
mod superblock;
1620

1721
pub use config::*;
1822
pub use superblock::*;
23+
24+
/// Errors that can occur when parsing LUKS config
25+
#[derive(Debug, Snafu)]
26+
pub enum ConfigError {
27+
/// An I/O error occurred
28+
#[snafu(display("io"))]
29+
Io { source: io::Error },
30+
31+
/// Invalid JSON
32+
#[snafu(display("invalid json"))]
33+
InvalidJson { source: serde_json::Error },
34+
35+
/// Error decoding UTF-8 string data
36+
#[snafu(display("invalid utf8 in decode"))]
37+
InvalidUtf8 { source: std::str::Utf8Error },
38+
}

0 commit comments

Comments
 (0)