Skip to main content

hadris_ntfs/
error.rs

1//! Error types for the hadris-ntfs crate.
2
3use core::fmt;
4
5/// Errors that can occur when working with NTFS filesystems.
6#[derive(Debug)]
7pub enum NtfsError {
8    /// Invalid boot sector signature (expected 0xAA55)
9    InvalidBootSignature {
10        /// The signature that was found
11        found: u16,
12    },
13    /// Invalid OEM ID in boot sector (expected "NTFS    ")
14    InvalidOemId,
15    /// Invalid logical sector size in the boot sector
16    InvalidSectorSize {
17        /// Sector size that was found
18        found: u16,
19    },
20    /// Invalid sectors-per-cluster value in the boot sector
21    InvalidSectorsPerCluster {
22        /// Cluster factor that was found
23        found: u8,
24    },
25    /// Invalid volume extent or MFT location in the boot sector
26    InvalidVolumeGeometry,
27    /// Invalid MFT record magic (expected "FILE")
28    InvalidMftMagic,
29    /// Invalid index record magic (expected "INDX")
30    InvalidIndexMagic,
31    /// Invalid or corrupt update sequence (fixup) array
32    InvalidFixup,
33    /// Update sequence entry does not match the expected value
34    FixupMismatch {
35        /// Expected update sequence number
36        expected: u16,
37        /// Value found at sector boundary
38        found: u16,
39    },
40    /// Invalid MFT record size in boot sector
41    InvalidRecordSize,
42    /// MFT record index is beyond the MFT data extent
43    MftRecordOutOfBounds {
44        /// The record index that was requested
45        index: u64,
46    },
47    /// A file reference points to a reused MFT record
48    StaleFileReference {
49        /// Referenced MFT record
50        index: u64,
51        /// Sequence number stored in the file reference
52        expected: u16,
53        /// Current sequence number in the MFT record
54        found: u16,
55    },
56    /// Required attribute was not found in the MFT record
57    AttributeNotFound {
58        /// The attribute type that was expected
59        attr_type: u32,
60    },
61    /// Malformed attribute header or value
62    InvalidAttribute,
63    /// Malformed non-resident attribute data run
64    InvalidDataRun,
65    /// Could not decode a UTF-16LE filename
66    InvalidFileName,
67    /// The `$UpCase` system file is missing or malformed
68    InvalidUpcaseTable,
69    /// Malformed index entry
70    InvalidIndexEntry,
71    /// Entry is not a regular file
72    NotAFile,
73    /// Entry is not a directory
74    NotADirectory,
75    /// Entry not found in directory
76    EntryNotFound,
77    /// Path is invalid (empty or malformed)
78    InvalidPath,
79    /// Compressed data streams are not supported
80    UnsupportedCompression,
81    /// Encrypted data streams are not supported
82    UnsupportedEncryption,
83    /// Data read went past the end of the available data runs
84    UnexpectedEndOfData,
85    /// I/O error from the underlying storage
86    Io(hadris_io::Error),
87}
88
89impl fmt::Display for NtfsError {
90    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
91        match self {
92            Self::InvalidBootSignature { found } => {
93                write!(
94                    f,
95                    "invalid boot signature: expected 0xAA55, found {found:#06x}"
96                )
97            }
98            Self::InvalidOemId => write!(f, "invalid OEM ID (expected \"NTFS    \")"),
99            Self::InvalidSectorSize { found } => {
100                write!(f, "invalid NTFS sector size: {found}")
101            }
102            Self::InvalidSectorsPerCluster { found } => {
103                write!(f, "invalid NTFS sectors per cluster: {found}")
104            }
105            Self::InvalidVolumeGeometry => write!(f, "invalid NTFS volume geometry"),
106            Self::InvalidMftMagic => write!(f, "invalid MFT record magic (expected \"FILE\")"),
107            Self::InvalidIndexMagic => {
108                write!(f, "invalid index record magic (expected \"INDX\")")
109            }
110            Self::InvalidFixup => write!(f, "invalid or corrupt update sequence array"),
111            Self::FixupMismatch { expected, found } => {
112                write!(
113                    f,
114                    "fixup mismatch: expected {expected:#06x}, found {found:#06x}"
115                )
116            }
117            Self::InvalidRecordSize => write!(f, "invalid record size in boot sector"),
118            Self::MftRecordOutOfBounds { index } => {
119                write!(f, "MFT record index {index} is out of bounds")
120            }
121            Self::StaleFileReference {
122                index,
123                expected,
124                found,
125            } => write!(
126                f,
127                "stale reference to MFT record {index}: expected sequence {expected}, found {found}"
128            ),
129            Self::AttributeNotFound { attr_type } => {
130                write!(f, "attribute type {attr_type:#06x} not found")
131            }
132            Self::InvalidAttribute => write!(f, "malformed attribute header or value"),
133            Self::InvalidDataRun => write!(f, "malformed non-resident attribute data run"),
134            Self::InvalidFileName => write!(f, "could not decode UTF-16LE filename"),
135            Self::InvalidUpcaseTable => write!(f, "missing or malformed NTFS $UpCase table"),
136            Self::InvalidIndexEntry => write!(f, "malformed index entry"),
137            Self::NotAFile => write!(f, "entry is not a file"),
138            Self::NotADirectory => write!(f, "entry is not a directory"),
139            Self::EntryNotFound => write!(f, "entry not found in directory"),
140            Self::InvalidPath => write!(f, "path is invalid (empty or malformed)"),
141            Self::UnsupportedCompression => {
142                write!(f, "compressed data streams are not supported")
143            }
144            Self::UnsupportedEncryption => {
145                write!(f, "encrypted data streams are not supported")
146            }
147            Self::UnexpectedEndOfData => write!(f, "unexpected end of data runs"),
148            Self::Io(e) => write!(f, "I/O error: {e:?}"),
149        }
150    }
151}
152
153#[cfg(feature = "std")]
154impl std::error::Error for NtfsError {}
155
156impl<E: hadris_io::IoError> From<hadris_io::Error<E>> for NtfsError {
157    fn from(e: hadris_io::Error<E>) -> Self {
158        Self::Io(e.erase())
159    }
160}
161
162/// Result type alias for NTFS operations.
163pub type Result<T> = core::result::Result<T, NtfsError>;