Show More
@@ -228,7 +228,7 b" impl<'on_disk> DirstateMap<'on_disk> {" | |||||
228 | pub fn new_v2( |
|
228 | pub fn new_v2( | |
229 | on_disk: &'on_disk [u8], |
|
229 | on_disk: &'on_disk [u8], | |
230 | ) -> Result<(Self, Option<DirstateParents>), DirstateError> { |
|
230 | ) -> Result<(Self, Option<DirstateParents>), DirstateError> { | |
231 | on_disk::read(on_disk) |
|
231 | Ok(on_disk::read(on_disk)?) | |
232 | } |
|
232 | } | |
233 |
|
233 | |||
234 | #[timed] |
|
234 | #[timed] |
@@ -108,14 +108,32 b' fn _static_assert_size_of() {' | |||||
108 | let _ = std::mem::transmute::<Node, [u8; 57]>; |
|
108 | let _ = std::mem::transmute::<Node, [u8; 57]>; | |
109 | } |
|
109 | } | |
110 |
|
110 | |||
|
111 | /// Unexpected file format found in `.hg/dirstate` with the "v2" format. | |||
|
112 | pub(crate) struct DirstateV2ParseError; | |||
|
113 | ||||
|
114 | impl From<DirstateV2ParseError> for HgError { | |||
|
115 | fn from(_: DirstateV2ParseError) -> Self { | |||
|
116 | HgError::corrupted("dirstate-v2 parse error") | |||
|
117 | } | |||
|
118 | } | |||
|
119 | ||||
|
120 | impl From<DirstateV2ParseError> for crate::DirstateError { | |||
|
121 | fn from(error: DirstateV2ParseError) -> Self { | |||
|
122 | HgError::from(error).into() | |||
|
123 | } | |||
|
124 | } | |||
|
125 | ||||
111 | pub(super) fn read<'on_disk>( |
|
126 | pub(super) fn read<'on_disk>( | |
112 | on_disk: &'on_disk [u8], |
|
127 | on_disk: &'on_disk [u8], | |
113 | ) -> Result<(DirstateMap<'on_disk>, Option<DirstateParents>), DirstateError> { |
|
128 | ) -> Result< | |
|
129 | (DirstateMap<'on_disk>, Option<DirstateParents>), | |||
|
130 | DirstateV2ParseError, | |||
|
131 | > { | |||
114 | if on_disk.is_empty() { |
|
132 | if on_disk.is_empty() { | |
115 | return Ok((DirstateMap::empty(on_disk), None)); |
|
133 | return Ok((DirstateMap::empty(on_disk), None)); | |
116 | } |
|
134 | } | |
117 |
let (header, _) = |
|
135 | let (header, _) = | |
118 | .map_err(|_| HgError::corrupted("truncated dirstate-v2"))?; |
|
136 | Header::from_bytes(on_disk).map_err(|_| DirstateV2ParseError)?; | |
119 | let Header { |
|
137 | let Header { | |
120 | marker, |
|
138 | marker, | |
121 | parents, |
|
139 | parents, | |
@@ -124,7 +142,7 b" pub(super) fn read<'on_disk>(" | |||||
124 | nodes_with_copy_source_count, |
|
142 | nodes_with_copy_source_count, | |
125 | } = header; |
|
143 | } = header; | |
126 | if marker != V2_FORMAT_MARKER { |
|
144 | if marker != V2_FORMAT_MARKER { | |
127 | return Err(HgError::corrupted("missing dirstated-v2 marker").into()); |
|
145 | return Err(DirstateV2ParseError); | |
128 | } |
|
146 | } | |
129 | let dirstate_map = DirstateMap { |
|
147 | let dirstate_map = DirstateMap { | |
130 | on_disk, |
|
148 | on_disk, | |
@@ -140,7 +158,7 b' impl Node {' | |||||
140 | pub(super) fn path<'on_disk>( |
|
158 | pub(super) fn path<'on_disk>( | |
141 | &self, |
|
159 | &self, | |
142 | on_disk: &'on_disk [u8], |
|
160 | on_disk: &'on_disk [u8], | |
143 |
) -> Result<dirstate_map::NodeKey<'on_disk>, |
|
161 | ) -> Result<dirstate_map::NodeKey<'on_disk>, DirstateV2ParseError> { | |
144 | let full_path = read_hg_path(on_disk, self.full_path)?; |
|
162 | let full_path = read_hg_path(on_disk, self.full_path)?; | |
145 | let base_name_start = usize::try_from(self.base_name_start.get()) |
|
163 | let base_name_start = usize::try_from(self.base_name_start.get()) | |
146 | // u32 -> usize, could only panic on a 16-bit CPU |
|
164 | // u32 -> usize, could only panic on a 16-bit CPU | |
@@ -148,16 +166,14 b' impl Node {' | |||||
148 | if base_name_start < full_path.len() { |
|
166 | if base_name_start < full_path.len() { | |
149 | Ok(WithBasename::from_raw_parts(full_path, base_name_start)) |
|
167 | Ok(WithBasename::from_raw_parts(full_path, base_name_start)) | |
150 | } else { |
|
168 | } else { | |
151 | Err(HgError::corrupted( |
|
169 | Err(DirstateV2ParseError) | |
152 | "dirstate-v2 base_name_start out of bounds", |
|
|||
153 | )) |
|
|||
154 | } |
|
170 | } | |
155 | } |
|
171 | } | |
156 |
|
172 | |||
157 | pub(super) fn copy_source<'on_disk>( |
|
173 | pub(super) fn copy_source<'on_disk>( | |
158 | &self, |
|
174 | &self, | |
159 | on_disk: &'on_disk [u8], |
|
175 | on_disk: &'on_disk [u8], | |
160 |
) -> Result<Option<Cow<'on_disk, HgPath>>, |
|
176 | ) -> Result<Option<Cow<'on_disk, HgPath>>, DirstateV2ParseError> { | |
161 | Ok(if self.copy_source.start.get() != 0 { |
|
177 | Ok(if self.copy_source.start.get() != 0 { | |
162 | Some(read_hg_path(on_disk, self.copy_source)?) |
|
178 | Some(read_hg_path(on_disk, self.copy_source)?) | |
163 | } else { |
|
179 | } else { | |
@@ -165,10 +181,16 b' impl Node {' | |||||
165 | }) |
|
181 | }) | |
166 | } |
|
182 | } | |
167 |
|
183 | |||
168 | pub(super) fn entry(&self) -> Result<Option<DirstateEntry>, HgError> { |
|
184 | pub(super) fn entry( | |
|
185 | &self, | |||
|
186 | ) -> Result<Option<DirstateEntry>, DirstateV2ParseError> { | |||
169 | Ok(if self.entry.state != b'\0' { |
|
187 | Ok(if self.entry.state != b'\0' { | |
170 | Some(DirstateEntry { |
|
188 | Some(DirstateEntry { | |
171 |
state: self |
|
189 | state: self | |
|
190 | .entry | |||
|
191 | .state | |||
|
192 | .try_into() | |||
|
193 | .map_err(|_| DirstateV2ParseError)?, | |||
172 | mode: self.entry.mode.get(), |
|
194 | mode: self.entry.mode.get(), | |
173 | mtime: self.entry.mtime.get(), |
|
195 | mtime: self.entry.mtime.get(), | |
174 | size: self.entry.size.get(), |
|
196 | size: self.entry.size.get(), | |
@@ -181,7 +203,7 b' impl Node {' | |||||
181 | pub(super) fn to_in_memory_node<'on_disk>( |
|
203 | pub(super) fn to_in_memory_node<'on_disk>( | |
182 | &self, |
|
204 | &self, | |
183 | on_disk: &'on_disk [u8], |
|
205 | on_disk: &'on_disk [u8], | |
184 |
) -> Result<dirstate_map::Node<'on_disk>, |
|
206 | ) -> Result<dirstate_map::Node<'on_disk>, DirstateV2ParseError> { | |
185 | Ok(dirstate_map::Node { |
|
207 | Ok(dirstate_map::Node { | |
186 | children: read_nodes(on_disk, self.children)?, |
|
208 | children: read_nodes(on_disk, self.children)?, | |
187 | copy_source: self.copy_source(on_disk)?, |
|
209 | copy_source: self.copy_source(on_disk)?, | |
@@ -194,7 +216,7 b' impl Node {' | |||||
194 | fn read_nodes( |
|
216 | fn read_nodes( | |
195 | on_disk: &[u8], |
|
217 | on_disk: &[u8], | |
196 | slice: ChildNodes, |
|
218 | slice: ChildNodes, | |
197 |
) -> Result<dirstate_map::ChildNodes, |
|
219 | ) -> Result<dirstate_map::ChildNodes, DirstateV2ParseError> { | |
198 | read_slice::<Node>(on_disk, slice)? |
|
220 | read_slice::<Node>(on_disk, slice)? | |
199 | .iter() |
|
221 | .iter() | |
200 | .map(|node| { |
|
222 | .map(|node| { | |
@@ -204,12 +226,18 b' fn read_nodes(' | |||||
204 | .map(dirstate_map::ChildNodes::InMemory) |
|
226 | .map(dirstate_map::ChildNodes::InMemory) | |
205 | } |
|
227 | } | |
206 |
|
228 | |||
207 | fn read_hg_path(on_disk: &[u8], slice: Slice) -> Result<Cow<HgPath>, HgError> { |
|
229 | fn read_hg_path( | |
|
230 | on_disk: &[u8], | |||
|
231 | slice: Slice, | |||
|
232 | ) -> Result<Cow<HgPath>, DirstateV2ParseError> { | |||
208 | let bytes = read_slice::<u8>(on_disk, slice)?; |
|
233 | let bytes = read_slice::<u8>(on_disk, slice)?; | |
209 | Ok(Cow::Borrowed(HgPath::new(bytes))) |
|
234 | Ok(Cow::Borrowed(HgPath::new(bytes))) | |
210 | } |
|
235 | } | |
211 |
|
236 | |||
212 | fn read_slice<T>(on_disk: &[u8], slice: Slice) -> Result<&[T], HgError> |
|
237 | fn read_slice<T>( | |
|
238 | on_disk: &[u8], | |||
|
239 | slice: Slice, | |||
|
240 | ) -> Result<&[T], DirstateV2ParseError> | |||
213 | where |
|
241 | where | |
214 | T: BytesCast, |
|
242 | T: BytesCast, | |
215 | { |
|
243 | { | |
@@ -221,9 +249,7 b' where' | |||||
221 | .get(start..) |
|
249 | .get(start..) | |
222 | .and_then(|bytes| T::slice_from_bytes(bytes, len).ok()) |
|
250 | .and_then(|bytes| T::slice_from_bytes(bytes, len).ok()) | |
223 | .map(|(slice, _rest)| slice) |
|
251 | .map(|(slice, _rest)| slice) | |
224 |
.ok_or_else(|| |
|
252 | .ok_or_else(|| DirstateV2ParseError) | |
225 | HgError::corrupted("dirstate v2 slice is out of bounds") |
|
|||
226 | }) |
|
|||
227 | } |
|
253 | } | |
228 |
|
254 | |||
229 | pub(super) fn write( |
|
255 | pub(super) fn write( |
General Comments 0
You need to be logged in to leave comments.
Login now