99
1010use std:: io:: { self , BufRead , Cursor , Read , Seek } ;
1111
12- use thiserror :: Error ;
12+ use snafu :: { ResultExt , Snafu } ;
1313use zerocopy:: FromBytes ;
1414
1515pub 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 ) ]
4242pub 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 }
0 commit comments