##// END OF EJS Templates
dirstate-v2: Add a zero-size error type for dirstate v2 parse errors...
Simon Sapin -
r48125:18b3060f default
parent child Browse files
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, _) = Header::from_bytes(on_disk)
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>, HgError> {
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>>, HgError> {
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.entry.state.try_into()?,
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>, HgError> {
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, HgError> {
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