Show More
@@ -35,6 +35,9 b' pub enum IoErrorContext {' | |||||
35 |
|
35 | |||
36 | impl HgError { |
|
36 | impl HgError { | |
37 | pub fn corrupted(explanation: impl Into<String>) -> Self { |
|
37 | pub fn corrupted(explanation: impl Into<String>) -> Self { | |
|
38 | // TODO: capture a backtrace here and keep it in the error value | |||
|
39 | // to aid debugging? | |||
|
40 | // https://doc.rust-lang.org/std/backtrace/struct.Backtrace.html | |||
38 | HgError::CorruptedRepository(explanation.into()) |
|
41 | HgError::CorruptedRepository(explanation.into()) | |
39 | } |
|
42 | } | |
40 | } |
|
43 | } |
@@ -3,6 +3,7 b'' | |||||
3 | // |
|
3 | // | |
4 | // This software may be used and distributed according to the terms of the |
|
4 | // This software may be used and distributed according to the terms of the | |
5 | // GNU General Public License version 2 or any later version. |
|
5 | // GNU General Public License version 2 or any later version. | |
|
6 | ||||
6 | mod ancestors; |
|
7 | mod ancestors; | |
7 | pub mod dagops; |
|
8 | pub mod dagops; | |
8 | pub mod errors; |
|
9 | pub mod errors; |
@@ -33,8 +33,8 b' pub fn cat(' | |||||
33 | let changelog = Changelog::open(repo)?; |
|
33 | let changelog = Changelog::open(repo)?; | |
34 | let manifest = Manifest::open(repo)?; |
|
34 | let manifest = Manifest::open(repo)?; | |
35 | let changelog_entry = changelog.get_rev(rev)?; |
|
35 | let changelog_entry = changelog.get_rev(rev)?; | |
36 | let manifest_node = Node::from_hex(&changelog_entry.manifest_node()?) |
|
36 | let manifest_node = | |
37 | .map_err(|_| RevlogError::Corrupted)?; |
|
37 | Node::from_hex_for_repo(&changelog_entry.manifest_node()?)?; | |
38 | let manifest_entry = manifest.get_node(manifest_node.into())?; |
|
38 | let manifest_entry = manifest.get_node(manifest_node.into())?; | |
39 | let mut bytes = vec![]; |
|
39 | let mut bytes = vec![]; | |
40 |
|
40 | |||
@@ -46,8 +46,7 b' pub fn cat(' | |||||
46 |
|
46 | |||
47 | let file_log = |
|
47 | let file_log = | |
48 | Revlog::open(repo, &index_path, Some(&data_path))?; |
|
48 | Revlog::open(repo, &index_path, Some(&data_path))?; | |
49 | let file_node = Node::from_hex(node_bytes) |
|
49 | let file_node = Node::from_hex_for_repo(node_bytes)?; | |
50 | .map_err(|_| RevlogError::Corrupted)?; |
|
|||
51 | let file_rev = file_log.get_node_rev(file_node.into())?; |
|
50 | let file_rev = file_log.get_node_rev(file_node.into())?; | |
52 | let data = file_log.get_rev_data(file_rev)?; |
|
51 | let data = file_log.get_rev_data(file_rev)?; | |
53 | if data.starts_with(&METADATA_DELIMITER) { |
|
52 | if data.starts_with(&METADATA_DELIMITER) { |
@@ -6,7 +6,7 b'' | |||||
6 | // GNU General Public License version 2 or any later version. |
|
6 | // GNU General Public License version 2 or any later version. | |
7 |
|
7 | |||
8 | use crate::dirstate::parsers::parse_dirstate; |
|
8 | use crate::dirstate::parsers::parse_dirstate; | |
9 |
use crate::errors:: |
|
9 | use crate::errors::HgError; | |
10 | use crate::repo::Repo; |
|
10 | use crate::repo::Repo; | |
11 | use crate::revlog::changelog::Changelog; |
|
11 | use crate::revlog::changelog::Changelog; | |
12 | use crate::revlog::manifest::{Manifest, ManifestEntry}; |
|
12 | use crate::revlog::manifest::{Manifest, ManifestEntry}; | |
@@ -25,12 +25,7 b' pub struct Dirstate {' | |||||
25 |
|
25 | |||
26 | impl Dirstate { |
|
26 | impl Dirstate { | |
27 | pub fn new(repo: &Repo) -> Result<Self, HgError> { |
|
27 | pub fn new(repo: &Repo) -> Result<Self, HgError> { | |
28 | let content = repo |
|
28 | let content = repo.hg_vfs().read("dirstate")?; | |
29 | .hg_vfs() |
|
|||
30 | .read("dirstate") |
|
|||
31 | // TODO: this will be more accurate when we use `HgError` in |
|
|||
32 | // `Vfs::read`. |
|
|||
33 | .for_file("dirstate".as_ref())?; |
|
|||
34 | Ok(Self { content }) |
|
29 | Ok(Self { content }) | |
35 | } |
|
30 | } | |
36 |
|
31 | |||
@@ -57,8 +52,8 b' pub fn list_rev_tracked_files(' | |||||
57 | let changelog = Changelog::open(repo)?; |
|
52 | let changelog = Changelog::open(repo)?; | |
58 | let manifest = Manifest::open(repo)?; |
|
53 | let manifest = Manifest::open(repo)?; | |
59 | let changelog_entry = changelog.get_rev(rev)?; |
|
54 | let changelog_entry = changelog.get_rev(rev)?; | |
60 | let manifest_node = Node::from_hex(&changelog_entry.manifest_node()?) |
|
55 | let manifest_node = | |
61 | .map_err(|_| RevlogError::Corrupted)?; |
|
56 | Node::from_hex_for_repo(&changelog_entry.manifest_node()?)?; | |
62 | let manifest_entry = manifest.get_node(manifest_node.into())?; |
|
57 | let manifest_entry = manifest.get_node(manifest_node.into())?; | |
63 | Ok(FilesForRev(manifest_entry)) |
|
58 | Ok(FilesForRev(manifest_entry)) | |
64 | } |
|
59 | } |
@@ -1,4 +1,4 b'' | |||||
1 | use crate::errors::HgError; |
|
1 | use crate::errors::{HgError, IoResultExt}; | |
2 | use crate::operations::{find_root, FindRootError}; |
|
2 | use crate::operations::{find_root, FindRootError}; | |
3 | use crate::requirements; |
|
3 | use crate::requirements; | |
4 | use memmap::{Mmap, MmapOptions}; |
|
4 | use memmap::{Mmap, MmapOptions}; | |
@@ -68,24 +68,19 b" impl Vfs<'_> {" | |||||
68 | pub(crate) fn read( |
|
68 | pub(crate) fn read( | |
69 | &self, |
|
69 | &self, | |
70 | relative_path: impl AsRef<Path>, |
|
70 | relative_path: impl AsRef<Path>, | |
71 |
) -> |
|
71 | ) -> Result<Vec<u8>, HgError> { | |
72 |
|
|
72 | let path = self.base.join(relative_path); | |
73 | } |
|
73 | std::fs::read(&path).for_file(&path) | |
74 |
|
||||
75 | pub(crate) fn open( |
|
|||
76 | &self, |
|
|||
77 | relative_path: impl AsRef<Path>, |
|
|||
78 | ) -> std::io::Result<std::fs::File> { |
|
|||
79 | std::fs::File::open(self.base.join(relative_path)) |
|
|||
80 | } |
|
74 | } | |
81 |
|
75 | |||
82 | pub(crate) fn mmap_open( |
|
76 | pub(crate) fn mmap_open( | |
83 | &self, |
|
77 | &self, | |
84 | relative_path: impl AsRef<Path>, |
|
78 | relative_path: impl AsRef<Path>, | |
85 |
) -> |
|
79 | ) -> Result<Mmap, HgError> { | |
86 |
let |
|
80 | let path = self.base.join(relative_path); | |
|
81 | let file = std::fs::File::open(&path).for_file(&path)?; | |||
87 | // TODO: what are the safety requirements here? |
|
82 | // TODO: what are the safety requirements here? | |
88 | let mmap = unsafe { MmapOptions::new().map(&file) }?; |
|
83 | let mmap = unsafe { MmapOptions::new().map(&file) }.for_file(&path)?; | |
89 | Ok(mmap) |
|
84 | Ok(mmap) | |
90 | } |
|
85 | } | |
91 | } |
|
86 | } |
@@ -1,4 +1,4 b'' | |||||
1 |
use crate::errors::{HgError, HgResultExt |
|
1 | use crate::errors::{HgError, HgResultExt}; | |
2 | use crate::repo::Repo; |
|
2 | use crate::repo::Repo; | |
3 |
|
3 | |||
4 | fn parse(bytes: &[u8]) -> Result<Vec<String>, HgError> { |
|
4 | fn parse(bytes: &[u8]) -> Result<Vec<String>, HgError> { | |
@@ -22,11 +22,8 b' fn parse(bytes: &[u8]) -> Result<Vec<Str' | |||||
22 | } |
|
22 | } | |
23 |
|
23 | |||
24 | pub fn load(repo: &Repo) -> Result<Vec<String>, HgError> { |
|
24 | pub fn load(repo: &Repo) -> Result<Vec<String>, HgError> { | |
25 |
if let Some(bytes) = |
|
25 | if let Some(bytes) = | |
26 | .hg_vfs() |
|
26 | repo.hg_vfs().read("requires").io_not_found_as_none()? | |
27 | .read("requires") |
|
|||
28 | .for_file("requires".as_ref()) |
|
|||
29 | .io_not_found_as_none()? |
|
|||
30 | { |
|
27 | { | |
31 | parse(&bytes) |
|
28 | parse(&bytes) | |
32 | } else { |
|
29 | } else { |
@@ -1,3 +1,4 b'' | |||||
|
1 | use crate::errors::HgError; | |||
1 | use crate::repo::Repo; |
|
2 | use crate::repo::Repo; | |
2 | use crate::revlog::revlog::{Revlog, RevlogError}; |
|
3 | use crate::revlog::revlog::{Revlog, RevlogError}; | |
3 | use crate::revlog::NodePrefix; |
|
4 | use crate::revlog::NodePrefix; | |
@@ -53,6 +54,8 b' impl ChangelogEntry {' | |||||
53 | /// Return the node id of the `manifest` referenced by this `changelog` |
|
54 | /// Return the node id of the `manifest` referenced by this `changelog` | |
54 | /// entry. |
|
55 | /// entry. | |
55 | pub fn manifest_node(&self) -> Result<&[u8], RevlogError> { |
|
56 | pub fn manifest_node(&self) -> Result<&[u8], RevlogError> { | |
56 | self.lines().next().ok_or(RevlogError::Corrupted) |
|
57 | self.lines() | |
|
58 | .next() | |||
|
59 | .ok_or_else(|| HgError::corrupted("empty changelog entry").into()) | |||
57 | } |
|
60 | } | |
58 | } |
|
61 | } |
@@ -3,6 +3,7 b' use std::ops::Deref;' | |||||
3 |
|
3 | |||
4 | use byteorder::{BigEndian, ByteOrder}; |
|
4 | use byteorder::{BigEndian, ByteOrder}; | |
5 |
|
5 | |||
|
6 | use crate::errors::HgError; | |||
6 | use crate::revlog::node::Node; |
|
7 | use crate::revlog::node::Node; | |
7 | use crate::revlog::revlog::RevlogError; |
|
8 | use crate::revlog::revlog::RevlogError; | |
8 | use crate::revlog::{Revision, NULL_REVISION}; |
|
9 | use crate::revlog::{Revision, NULL_REVISION}; | |
@@ -44,7 +45,8 b' impl Index {' | |||||
44 | offsets: Some(offsets), |
|
45 | offsets: Some(offsets), | |
45 | }) |
|
46 | }) | |
46 | } else { |
|
47 | } else { | |
47 |
Err( |
|
48 | Err(HgError::corrupted("unexpected inline revlog length") | |
|
49 | .into()) | |||
48 | } |
|
50 | } | |
49 | } else { |
|
51 | } else { | |
50 | Ok(Self { |
|
52 | Ok(Self { |
@@ -8,6 +8,7 b'' | |||||
8 | //! In Mercurial code base, it is customary to call "a node" the binary SHA |
|
8 | //! In Mercurial code base, it is customary to call "a node" the binary SHA | |
9 | //! of a revision. |
|
9 | //! of a revision. | |
10 |
|
10 | |||
|
11 | use crate::errors::HgError; | |||
11 | use bytes_cast::BytesCast; |
|
12 | use bytes_cast::BytesCast; | |
12 | use std::convert::{TryFrom, TryInto}; |
|
13 | use std::convert::{TryFrom, TryInto}; | |
13 | use std::fmt; |
|
14 | use std::fmt; | |
@@ -136,6 +137,19 b' impl Node {' | |||||
136 | } |
|
137 | } | |
137 | } |
|
138 | } | |
138 |
|
139 | |||
|
140 | /// `from_hex`, but for input from an internal file of the repository such | |||
|
141 | /// as a changelog or manifest entry. | |||
|
142 | /// | |||
|
143 | /// An error is treated as repository corruption. | |||
|
144 | pub fn from_hex_for_repo(hex: impl AsRef<[u8]>) -> Result<Node, HgError> { | |||
|
145 | Self::from_hex(hex.as_ref()).map_err(|FromHexError| { | |||
|
146 | HgError::CorruptedRepository(format!( | |||
|
147 | "Expected a full hexadecimal node ID, found {}", | |||
|
148 | String::from_utf8_lossy(hex.as_ref()) | |||
|
149 | )) | |||
|
150 | }) | |||
|
151 | } | |||
|
152 | ||||
139 | /// Provide access to binary data |
|
153 | /// Provide access to binary data | |
140 | /// |
|
154 | /// | |
141 | /// This is needed by FFI layers, for instance to return expected |
|
155 | /// This is needed by FFI layers, for instance to return expected |
@@ -1,3 +1,4 b'' | |||||
|
1 | use crate::errors::{HgError, HgResultExt}; | |||
1 | use bytes_cast::{unaligned, BytesCast}; |
|
2 | use bytes_cast::{unaligned, BytesCast}; | |
2 | use memmap::Mmap; |
|
3 | use memmap::Mmap; | |
3 | use std::path::{Path, PathBuf}; |
|
4 | use std::path::{Path, PathBuf}; | |
@@ -38,12 +39,12 b' impl NodeMapDocket {' | |||||
38 | index_path: &Path, |
|
39 | index_path: &Path, | |
39 | ) -> Result<Option<(Self, Mmap)>, RevlogError> { |
|
40 | ) -> Result<Option<(Self, Mmap)>, RevlogError> { | |
40 | let docket_path = index_path.with_extension("n"); |
|
41 | let docket_path = index_path.with_extension("n"); | |
41 | let docket_bytes = match repo.store_vfs().read(&docket_path) { |
|
42 | let docket_bytes = if let Some(bytes) = | |
42 | Err(e) if e.kind() == std::io::ErrorKind::NotFound => { |
|
43 | repo.store_vfs().read(&docket_path).io_not_found_as_none()? | |
43 | return Ok(None) |
|
44 | { | |
44 |
|
|
45 | bytes | |
45 | Err(e) => return Err(RevlogError::IoError(e)), |
|
46 | } else { | |
46 | Ok(bytes) => bytes, |
|
47 | return Ok(None); | |
47 | }; |
|
48 | }; | |
48 |
|
49 | |||
49 | let input = if let Some((&ONDISK_VERSION, rest)) = |
|
50 | let input = if let Some((&ONDISK_VERSION, rest)) = | |
@@ -54,36 +55,40 b' impl NodeMapDocket {' | |||||
54 | return Ok(None); |
|
55 | return Ok(None); | |
55 | }; |
|
56 | }; | |
56 |
|
57 | |||
57 | let (header, rest) = DocketHeader::from_bytes(input)?; |
|
58 | /// Treat any error as a parse error | |
|
59 | fn parse<T, E>(result: Result<T, E>) -> Result<T, RevlogError> { | |||
|
60 | result.map_err(|_| { | |||
|
61 | HgError::corrupted("nodemap docket parse error").into() | |||
|
62 | }) | |||
|
63 | } | |||
|
64 | ||||
|
65 | let (header, rest) = parse(DocketHeader::from_bytes(input))?; | |||
58 | let uid_size = header.uid_size as usize; |
|
66 | let uid_size = header.uid_size as usize; | |
59 | // TODO: do we care about overflow for 4 GB+ nodemap files on 32-bit |
|
67 | // TODO: do we care about overflow for 4 GB+ nodemap files on 32-bit | |
60 | // systems? |
|
68 | // systems? | |
61 | let tip_node_size = header.tip_node_size.get() as usize; |
|
69 | let tip_node_size = header.tip_node_size.get() as usize; | |
62 | let data_length = header.data_length.get() as usize; |
|
70 | let data_length = header.data_length.get() as usize; | |
63 | let (uid, rest) = u8::slice_from_bytes(rest, uid_size)?; |
|
71 | let (uid, rest) = parse(u8::slice_from_bytes(rest, uid_size))?; | |
64 | let (_tip_node, _rest) = u8::slice_from_bytes(rest, tip_node_size)?; |
|
72 | let (_tip_node, _rest) = | |
65 | let uid = |
|
73 | parse(u8::slice_from_bytes(rest, tip_node_size))?; | |
66 |
|
|
74 | let uid = parse(std::str::from_utf8(uid))?; | |
67 | let docket = NodeMapDocket { data_length }; |
|
75 | let docket = NodeMapDocket { data_length }; | |
68 |
|
76 | |||
69 | let data_path = rawdata_path(&docket_path, uid); |
|
77 | let data_path = rawdata_path(&docket_path, uid); | |
70 |
// TODO: use ` |
|
78 | // TODO: use `vfs.read()` here when the `persistent-nodemap.mmap` | |
71 | // config is false? |
|
79 | // config is false? | |
72 | match repo.store_vfs().mmap_open(&data_path) { |
|
80 | if let Some(mmap) = repo | |
73 | Ok(mmap) => { |
|
81 | .store_vfs() | |
74 |
|
|
82 | .mmap_open(&data_path) | |
75 | Ok(Some((docket, mmap))) |
|
83 | .io_not_found_as_none()? | |
76 | } else { |
|
84 | { | |
77 | Err(RevlogError::Corrupted) |
|
85 | if mmap.len() >= data_length { | |
78 | } |
|
86 | Ok(Some((docket, mmap))) | |
|
87 | } else { | |||
|
88 | Err(HgError::corrupted("persistent nodemap too short").into()) | |||
79 | } |
|
89 | } | |
80 | Err(error) => { |
|
90 | } else { | |
81 | if error.kind() == std::io::ErrorKind::NotFound { |
|
91 | Ok(None) | |
82 | Ok(None) |
|
|||
83 | } else { |
|
|||
84 | Err(RevlogError::IoError(error)) |
|
|||
85 | } |
|
|||
86 | } |
|
|||
87 | } |
|
92 | } | |
88 | } |
|
93 | } | |
89 | } |
|
94 | } |
@@ -13,25 +13,34 b' use zstd;' | |||||
13 | use super::index::Index; |
|
13 | use super::index::Index; | |
14 | use super::node::{NodePrefix, NODE_BYTES_LENGTH, NULL_NODE}; |
|
14 | use super::node::{NodePrefix, NODE_BYTES_LENGTH, NULL_NODE}; | |
15 | use super::nodemap; |
|
15 | use super::nodemap; | |
16 | use super::nodemap::NodeMap; |
|
16 | use super::nodemap::{NodeMap, NodeMapError}; | |
17 | use super::nodemap_docket::NodeMapDocket; |
|
17 | use super::nodemap_docket::NodeMapDocket; | |
18 | use super::patch; |
|
18 | use super::patch; | |
|
19 | use crate::errors::HgError; | |||
19 | use crate::repo::Repo; |
|
20 | use crate::repo::Repo; | |
20 | use crate::revlog::Revision; |
|
21 | use crate::revlog::Revision; | |
21 |
|
22 | |||
|
23 | #[derive(derive_more::From)] | |||
22 | pub enum RevlogError { |
|
24 | pub enum RevlogError { | |
23 | IoError(std::io::Error), |
|
|||
24 | UnsuportedVersion(u16), |
|
|||
25 | InvalidRevision, |
|
25 | InvalidRevision, | |
26 | /// Found more than one entry whose ID match the requested prefix |
|
26 | /// Found more than one entry whose ID match the requested prefix | |
27 | AmbiguousPrefix, |
|
27 | AmbiguousPrefix, | |
28 | Corrupted, |
|
28 | #[from] | |
29 | UnknowDataFormat(u8), |
|
29 | Other(HgError), | |
30 | } |
|
30 | } | |
31 |
|
31 | |||
32 |
impl From< |
|
32 | impl From<NodeMapError> for RevlogError { | |
33 |
fn from( |
|
33 | fn from(error: NodeMapError) -> Self { | |
34 | RevlogError::Corrupted |
|
34 | match error { | |
|
35 | NodeMapError::MultipleResults => RevlogError::AmbiguousPrefix, | |||
|
36 | NodeMapError::RevisionNotInIndex(_) => RevlogError::corrupted(), | |||
|
37 | } | |||
|
38 | } | |||
|
39 | } | |||
|
40 | ||||
|
41 | impl RevlogError { | |||
|
42 | fn corrupted() -> Self { | |||
|
43 | RevlogError::Other(HgError::corrupted("corrupted revlog")) | |||
35 | } |
|
44 | } | |
36 | } |
|
45 | } | |
37 |
|
46 | |||
@@ -59,14 +68,12 b' impl Revlog {' | |||||
59 | data_path: Option<&Path>, |
|
68 | data_path: Option<&Path>, | |
60 | ) -> Result<Self, RevlogError> { |
|
69 | ) -> Result<Self, RevlogError> { | |
61 | let index_path = index_path.as_ref(); |
|
70 | let index_path = index_path.as_ref(); | |
62 | let index_mmap = repo |
|
71 | let index_mmap = repo.store_vfs().mmap_open(&index_path)?; | |
63 | .store_vfs() |
|
|||
64 | .mmap_open(&index_path) |
|
|||
65 | .map_err(RevlogError::IoError)?; |
|
|||
66 |
|
72 | |||
67 | let version = get_version(&index_mmap); |
|
73 | let version = get_version(&index_mmap); | |
68 | if version != 1 { |
|
74 | if version != 1 { | |
69 | return Err(RevlogError::UnsuportedVersion(version)); |
|
75 | // A proper new version should have had a repo/store requirement. | |
|
76 | return Err(RevlogError::corrupted()); | |||
70 | } |
|
77 | } | |
71 |
|
78 | |||
72 | let index = Index::new(Box::new(index_mmap))?; |
|
79 | let index = Index::new(Box::new(index_mmap))?; | |
@@ -80,10 +87,7 b' impl Revlog {' | |||||
80 | None |
|
87 | None | |
81 | } else { |
|
88 | } else { | |
82 | let data_path = data_path.unwrap_or(&default_data_path); |
|
89 | let data_path = data_path.unwrap_or(&default_data_path); | |
83 | let data_mmap = repo |
|
90 | let data_mmap = repo.store_vfs().mmap_open(data_path)?; | |
84 | .store_vfs() |
|
|||
85 | .mmap_open(data_path) |
|
|||
86 | .map_err(RevlogError::IoError)?; |
|
|||
87 | Some(Box::new(data_mmap)) |
|
91 | Some(Box::new(data_mmap)) | |
88 | }; |
|
92 | }; | |
89 |
|
93 | |||
@@ -121,9 +125,7 b' impl Revlog {' | |||||
121 | ) -> Result<Revision, RevlogError> { |
|
125 | ) -> Result<Revision, RevlogError> { | |
122 | if let Some(nodemap) = &self.nodemap { |
|
126 | if let Some(nodemap) = &self.nodemap { | |
123 | return nodemap |
|
127 | return nodemap | |
124 | .find_bin(&self.index, node) |
|
128 | .find_bin(&self.index, node)? | |
125 | // TODO: propagate details of this error: |
|
|||
126 | .map_err(|_| RevlogError::Corrupted)? |
|
|||
127 | .ok_or(RevlogError::InvalidRevision); |
|
129 | .ok_or(RevlogError::InvalidRevision); | |
128 | } |
|
130 | } | |
129 |
|
131 | |||
@@ -136,7 +138,9 b' impl Revlog {' | |||||
136 | let mut found_by_prefix = None; |
|
138 | let mut found_by_prefix = None; | |
137 | for rev in (0..self.len() as Revision).rev() { |
|
139 | for rev in (0..self.len() as Revision).rev() { | |
138 | let index_entry = |
|
140 | let index_entry = | |
139 |
self.index.get_entry(rev).ok_or( |
|
141 | self.index.get_entry(rev).ok_or(HgError::corrupted( | |
|
142 | "revlog references a revision not in the index", | |||
|
143 | ))?; | |||
140 | if node == *index_entry.hash() { |
|
144 | if node == *index_entry.hash() { | |
141 | return Ok(rev); |
|
145 | return Ok(rev); | |
142 | } |
|
146 | } | |
@@ -167,8 +171,9 b' impl Revlog {' | |||||
167 | let mut delta_chain = vec![]; |
|
171 | let mut delta_chain = vec![]; | |
168 | while let Some(base_rev) = entry.base_rev { |
|
172 | while let Some(base_rev) = entry.base_rev { | |
169 | delta_chain.push(entry); |
|
173 | delta_chain.push(entry); | |
170 | entry = |
|
174 | entry = self | |
171 |
|
|
175 | .get_entry(base_rev) | |
|
176 | .map_err(|_| RevlogError::corrupted())?; | |||
172 | } |
|
177 | } | |
173 |
|
178 | |||
174 | // TODO do not look twice in the index |
|
179 | // TODO do not look twice in the index | |
@@ -191,7 +196,7 b' impl Revlog {' | |||||
191 | ) { |
|
196 | ) { | |
192 | Ok(data) |
|
197 | Ok(data) | |
193 | } else { |
|
198 | } else { | |
194 |
Err(RevlogError:: |
|
199 | Err(RevlogError::corrupted()) | |
195 | } |
|
200 | } | |
196 | } |
|
201 | } | |
197 |
|
202 | |||
@@ -301,7 +306,8 b" impl<'a> RevlogEntry<'a> {" | |||||
301 | b'x' => Ok(Cow::Owned(self.uncompressed_zlib_data()?)), |
|
306 | b'x' => Ok(Cow::Owned(self.uncompressed_zlib_data()?)), | |
302 | // zstd data. |
|
307 | // zstd data. | |
303 | b'\x28' => Ok(Cow::Owned(self.uncompressed_zstd_data()?)), |
|
308 | b'\x28' => Ok(Cow::Owned(self.uncompressed_zstd_data()?)), | |
304 | format_type => Err(RevlogError::UnknowDataFormat(format_type)), |
|
309 | // A proper new format should have had a repo/store requirement. | |
|
310 | _format_type => Err(RevlogError::corrupted()), | |||
305 | } |
|
311 | } | |
306 | } |
|
312 | } | |
307 |
|
313 | |||
@@ -311,13 +317,13 b" impl<'a> RevlogEntry<'a> {" | |||||
311 | let mut buf = Vec::with_capacity(self.compressed_len); |
|
317 | let mut buf = Vec::with_capacity(self.compressed_len); | |
312 | decoder |
|
318 | decoder | |
313 | .read_to_end(&mut buf) |
|
319 | .read_to_end(&mut buf) | |
314 |
. |
|
320 | .map_err(|_| RevlogError::corrupted())?; | |
315 | Ok(buf) |
|
321 | Ok(buf) | |
316 | } else { |
|
322 | } else { | |
317 | let mut buf = vec![0; self.uncompressed_len]; |
|
323 | let mut buf = vec![0; self.uncompressed_len]; | |
318 | decoder |
|
324 | decoder | |
319 | .read_exact(&mut buf) |
|
325 | .read_exact(&mut buf) | |
320 |
. |
|
326 | .map_err(|_| RevlogError::corrupted())?; | |
321 | Ok(buf) |
|
327 | Ok(buf) | |
322 | } |
|
328 | } | |
323 | } |
|
329 | } | |
@@ -326,14 +332,14 b" impl<'a> RevlogEntry<'a> {" | |||||
326 | if self.is_delta() { |
|
332 | if self.is_delta() { | |
327 | let mut buf = Vec::with_capacity(self.compressed_len); |
|
333 | let mut buf = Vec::with_capacity(self.compressed_len); | |
328 | zstd::stream::copy_decode(self.bytes, &mut buf) |
|
334 | zstd::stream::copy_decode(self.bytes, &mut buf) | |
329 |
. |
|
335 | .map_err(|_| RevlogError::corrupted())?; | |
330 | Ok(buf) |
|
336 | Ok(buf) | |
331 | } else { |
|
337 | } else { | |
332 | let mut buf = vec![0; self.uncompressed_len]; |
|
338 | let mut buf = vec![0; self.uncompressed_len]; | |
333 | let len = zstd::block::decompress_to_buffer(self.bytes, &mut buf) |
|
339 | let len = zstd::block::decompress_to_buffer(self.bytes, &mut buf) | |
334 |
. |
|
340 | .map_err(|_| RevlogError::corrupted())?; | |
335 | if len != self.uncompressed_len { |
|
341 | if len != self.uncompressed_len { | |
336 |
Err(RevlogError:: |
|
342 | Err(RevlogError::corrupted()) | |
337 | } else { |
|
343 | } else { | |
338 | Ok(buf) |
|
344 | Ok(buf) | |
339 | } |
|
345 | } |
@@ -103,9 +103,6 b' impl From<FindRootError> for CommandErro' | |||||
103 | impl From<(RevlogError, &str)> for CommandError { |
|
103 | impl From<(RevlogError, &str)> for CommandError { | |
104 | fn from((err, rev): (RevlogError, &str)) -> CommandError { |
|
104 | fn from((err, rev): (RevlogError, &str)) -> CommandError { | |
105 | match err { |
|
105 | match err { | |
106 | RevlogError::IoError(err) => CommandError::Abort(Some( |
|
|||
107 | utf8_to_local(&format!("abort: {}\n", err)).into(), |
|
|||
108 | )), |
|
|||
109 | RevlogError::InvalidRevision => CommandError::Abort(Some( |
|
106 | RevlogError::InvalidRevision => CommandError::Abort(Some( | |
110 | utf8_to_local(&format!( |
|
107 | utf8_to_local(&format!( | |
111 | "abort: invalid revision identifier {}\n", |
|
108 | "abort: invalid revision identifier {}\n", | |
@@ -120,27 +117,7 b' impl From<(RevlogError, &str)> for Comma' | |||||
120 | )) |
|
117 | )) | |
121 | .into(), |
|
118 | .into(), | |
122 | )), |
|
119 | )), | |
123 |
RevlogError:: |
|
120 | RevlogError::Other(err) => CommandError::Other(err), | |
124 | CommandError::Abort(Some( |
|
|||
125 | utf8_to_local(&format!( |
|
|||
126 | "abort: unsupported revlog version {}\n", |
|
|||
127 | version |
|
|||
128 | )) |
|
|||
129 | .into(), |
|
|||
130 | )) |
|
|||
131 | } |
|
|||
132 | RevlogError::Corrupted => { |
|
|||
133 | CommandError::Abort(Some("abort: corrupted revlog\n".into())) |
|
|||
134 | } |
|
|||
135 | RevlogError::UnknowDataFormat(format) => { |
|
|||
136 | CommandError::Abort(Some( |
|
|||
137 | utf8_to_local(&format!( |
|
|||
138 | "abort: unknow revlog dataformat {:?}\n", |
|
|||
139 | format |
|
|||
140 | )) |
|
|||
141 | .into(), |
|
|||
142 | )) |
|
|||
143 | } |
|
|||
144 | } |
|
121 | } | |
145 | } |
|
122 | } | |
146 | } |
|
123 | } |
General Comments 0
You need to be logged in to leave comments.
Login now