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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
//! Error types for the hadris-ntfs crate.
use core::fmt;
/// Errors that can occur when working with NTFS filesystems.
#[derive(Debug)]
pub enum NtfsError {
/// Invalid boot sector signature (expected 0xAA55)
InvalidBootSignature {
/// The signature that was found
found: u16,
},
/// Invalid OEM ID in boot sector (expected "NTFS ")
InvalidOemId,
/// Invalid logical sector size in the boot sector
InvalidSectorSize {
/// Sector size that was found
found: u16,
},
/// Invalid sectors-per-cluster value in the boot sector
InvalidSectorsPerCluster {
/// Cluster factor that was found
found: u8,
},
/// Invalid volume extent or MFT location in the boot sector
InvalidVolumeGeometry,
/// Invalid MFT record magic (expected "FILE")
InvalidMftMagic,
/// Invalid index record magic (expected "INDX")
InvalidIndexMagic,
/// Invalid or corrupt update sequence (fixup) array
InvalidFixup,
/// Update sequence entry does not match the expected value
FixupMismatch {
/// Expected update sequence number
expected: u16,
/// Value found at sector boundary
found: u16,
},
/// Invalid MFT record size in boot sector
InvalidRecordSize,
/// MFT record index is beyond the MFT data extent
MftRecordOutOfBounds {
/// The record index that was requested
index: u64,
},
/// A file reference points to a reused MFT record
StaleFileReference {
/// Referenced MFT record
index: u64,
/// Sequence number stored in the file reference
expected: u16,
/// Current sequence number in the MFT record
found: u16,
},
/// Required attribute was not found in the MFT record
AttributeNotFound {
/// The attribute type that was expected
attr_type: u32,
},
/// Malformed attribute header or value
InvalidAttribute,
/// Malformed non-resident attribute data run
InvalidDataRun,
/// Could not decode a UTF-16LE filename
InvalidFileName,
/// The `$UpCase` system file is missing or malformed
InvalidUpcaseTable,
/// Malformed index entry
InvalidIndexEntry,
/// Entry is not a regular file
NotAFile,
/// Entry is not a directory
NotADirectory,
/// Entry not found in directory
EntryNotFound,
/// Path is invalid (empty or malformed)
InvalidPath,
/// Compressed data streams are not supported
UnsupportedCompression,
/// Encrypted data streams are not supported
UnsupportedEncryption,
/// Data read went past the end of the available data runs
UnexpectedEndOfData,
/// I/O error from the underlying storage
Io(hadris_io::Error),
}
impl fmt::Display for NtfsError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::InvalidBootSignature { found } => {
write!(
f,
"invalid boot signature: expected 0xAA55, found {found:#06x}"
)
}
Self::InvalidOemId => write!(f, "invalid OEM ID (expected \"NTFS \")"),
Self::InvalidSectorSize { found } => {
write!(f, "invalid NTFS sector size: {found}")
}
Self::InvalidSectorsPerCluster { found } => {
write!(f, "invalid NTFS sectors per cluster: {found}")
}
Self::InvalidVolumeGeometry => write!(f, "invalid NTFS volume geometry"),
Self::InvalidMftMagic => write!(f, "invalid MFT record magic (expected \"FILE\")"),
Self::InvalidIndexMagic => {
write!(f, "invalid index record magic (expected \"INDX\")")
}
Self::InvalidFixup => write!(f, "invalid or corrupt update sequence array"),
Self::FixupMismatch { expected, found } => {
write!(
f,
"fixup mismatch: expected {expected:#06x}, found {found:#06x}"
)
}
Self::InvalidRecordSize => write!(f, "invalid record size in boot sector"),
Self::MftRecordOutOfBounds { index } => {
write!(f, "MFT record index {index} is out of bounds")
}
Self::StaleFileReference {
index,
expected,
found,
} => write!(
f,
"stale reference to MFT record {index}: expected sequence {expected}, found {found}"
),
Self::AttributeNotFound { attr_type } => {
write!(f, "attribute type {attr_type:#06x} not found")
}
Self::InvalidAttribute => write!(f, "malformed attribute header or value"),
Self::InvalidDataRun => write!(f, "malformed non-resident attribute data run"),
Self::InvalidFileName => write!(f, "could not decode UTF-16LE filename"),
Self::InvalidUpcaseTable => write!(f, "missing or malformed NTFS $UpCase table"),
Self::InvalidIndexEntry => write!(f, "malformed index entry"),
Self::NotAFile => write!(f, "entry is not a file"),
Self::NotADirectory => write!(f, "entry is not a directory"),
Self::EntryNotFound => write!(f, "entry not found in directory"),
Self::InvalidPath => write!(f, "path is invalid (empty or malformed)"),
Self::UnsupportedCompression => {
write!(f, "compressed data streams are not supported")
}
Self::UnsupportedEncryption => {
write!(f, "encrypted data streams are not supported")
}
Self::UnexpectedEndOfData => write!(f, "unexpected end of data runs"),
Self::Io(e) => write!(f, "I/O error: {e:?}"),
}
}
}
#[cfg(feature = "std")]
impl std::error::Error for NtfsError {}
impl<E: hadris_io::IoError> From<hadris_io::Error<E>> for NtfsError {
fn from(e: hadris_io::Error<E>) -> Self {
Self::Io(e.erase())
}
}
/// Result type alias for NTFS operations.
pub type Result<T> = core::result::Result<T, NtfsError>;