Show More
@@ -70,15 +70,21 b' impl Revlog {' | |||||
70 | data_path: Option<&Path>, |
|
70 | data_path: Option<&Path>, | |
71 | ) -> Result<Self, HgError> { |
|
71 | ) -> Result<Self, HgError> { | |
72 | let index_path = index_path.as_ref(); |
|
72 | let index_path = index_path.as_ref(); | |
73 | let index_mmap = repo.store_vfs().mmap_open(&index_path)?; |
|
73 | let index = { | |
|
74 | match repo.store_vfs().mmap_open_opt(&index_path)? { | |||
|
75 | None => Index::new(Box::new(vec![])), | |||
|
76 | Some(index_mmap) => { | |||
|
77 | let version = get_version(&index_mmap)?; | |||
|
78 | if version != 1 { | |||
|
79 | // A proper new version should have had a repo/store requirement. | |||
|
80 | return Err(HgError::corrupted("corrupted revlog")); | |||
|
81 | } | |||
74 |
|
82 | |||
75 | let version = get_version(&index_mmap)?; |
|
83 | let index = Index::new(Box::new(index_mmap))?; | |
76 | if version != 1 { |
|
84 | Ok(index) | |
77 | // A proper new version should have had a repo/store requirement. |
|
85 | } | |
78 | return Err(HgError::corrupted("corrupted revlog")); |
|
86 | } | |
79 | } |
|
87 | }?; | |
80 |
|
||||
81 | let index = Index::new(Box::new(index_mmap))?; |
|
|||
82 |
|
88 | |||
83 | let default_data_path = index_path.with_extension("d"); |
|
89 | let default_data_path = index_path.with_extension("d"); | |
84 |
|
90 | |||
@@ -418,6 +424,6 b' mod tests {' | |||||
418 | .with_version(1) |
|
424 | .with_version(1) | |
419 | .build(); |
|
425 | .build(); | |
420 |
|
426 | |||
421 | assert_eq!(get_version(&bytes), 1) |
|
427 | assert_eq!(get_version(&bytes).map_err(|_err|()), Ok(1)) | |
422 | } |
|
428 | } | |
423 | } |
|
429 | } |
@@ -9,6 +9,8 b" pub struct Vfs<'a> {" | |||||
9 | pub(crate) base: &'a Path, |
|
9 | pub(crate) base: &'a Path, | |
10 | } |
|
10 | } | |
11 |
|
11 | |||
|
12 | struct FileNotFound(std::io::Error, PathBuf); | |||
|
13 | ||||
12 | impl Vfs<'_> { |
|
14 | impl Vfs<'_> { | |
13 | pub fn join(&self, relative_path: impl AsRef<Path>) -> PathBuf { |
|
15 | pub fn join(&self, relative_path: impl AsRef<Path>) -> PathBuf { | |
14 | self.base.join(relative_path) |
|
16 | self.base.join(relative_path) | |
@@ -22,16 +24,41 b" impl Vfs<'_> {" | |||||
22 | std::fs::read(&path).when_reading_file(&path) |
|
24 | std::fs::read(&path).when_reading_file(&path) | |
23 | } |
|
25 | } | |
24 |
|
26 | |||
|
27 | fn mmap_open_gen( | |||
|
28 | &self, | |||
|
29 | relative_path: impl AsRef<Path>, | |||
|
30 | ) -> Result<Result<Mmap, FileNotFound>, HgError> { | |||
|
31 | let path = self.join(relative_path); | |||
|
32 | let file = match std::fs::File::open(&path) { | |||
|
33 | Err(err) => { | |||
|
34 | if let ErrorKind::NotFound = err.kind() { | |||
|
35 | return Ok(Err(FileNotFound(err, path))); | |||
|
36 | }; | |||
|
37 | return (Err(err)).when_reading_file(&path); | |||
|
38 | } | |||
|
39 | Ok(file) => file, | |||
|
40 | }; | |||
|
41 | // TODO: what are the safety requirements here? | |||
|
42 | let mmap = unsafe { MmapOptions::new().map(&file) } | |||
|
43 | .when_reading_file(&path)?; | |||
|
44 | Ok(Ok(mmap)) | |||
|
45 | } | |||
|
46 | ||||
|
47 | pub fn mmap_open_opt( | |||
|
48 | &self, | |||
|
49 | relative_path: impl AsRef<Path>, | |||
|
50 | ) -> Result<Option<Mmap>, HgError> { | |||
|
51 | self.mmap_open_gen(relative_path).map(|res| res.ok()) | |||
|
52 | } | |||
|
53 | ||||
25 | pub fn mmap_open( |
|
54 | pub fn mmap_open( | |
26 | &self, |
|
55 | &self, | |
27 | relative_path: impl AsRef<Path>, |
|
56 | relative_path: impl AsRef<Path>, | |
28 | ) -> Result<Mmap, HgError> { |
|
57 | ) -> Result<Mmap, HgError> { | |
29 |
|
|
58 | match self.mmap_open_gen(relative_path)? { | |
30 |
let |
|
59 | Err(FileNotFound(err, path)) => Err(err).when_reading_file(&path), | |
31 | // TODO: what are the safety requirements here? |
|
60 | Ok(res) => Ok(res), | |
32 | let mmap = unsafe { MmapOptions::new().map(&file) } |
|
61 | } | |
33 | .when_reading_file(&path)?; |
|
|||
34 | Ok(mmap) |
|
|||
35 | } |
|
62 | } | |
36 |
|
63 | |||
37 | pub fn rename( |
|
64 | pub fn rename( |
@@ -1,23 +1,27 b'' | |||||
1 | Create a repo such that the changelog entry refers to a null manifest node: |
|
1 | Test null revisions (node 0000000000000000000000000000000000000000, aka rev -1) | |
|
2 | in various circumstances. | |||
|
3 | ||||
|
4 | Make an empty repo: | |||
2 |
|
5 | |||
3 | $ hg init a |
|
6 | $ hg init a | |
4 | $ cd a |
|
7 | $ cd a | |
5 | $ hg log |
|
|||
6 | $ touch x |
|
|||
7 | $ hg add x |
|
|||
8 | $ hg commit -m "init" |
|
|||
9 | $ hg rm x |
|
|||
10 | $ hg commit -q --amend |
|
|||
11 |
|
8 | |||
12 | $ wc -c < .hg/store/00manifest.i |
|
9 | $ hg files -r 0000000000000000000000000000000000000000 | |
13 | 0 |
|
10 | [1] | |
14 |
|
11 | $ hg files -r . | ||
15 | Make sure that the manifest can be read (and is empty): |
|
|||
16 |
|
||||
17 | $ hg --config rhg.on-unsupported=abort files -r . |
|
|||
18 | [1] |
|
12 | [1] | |
19 |
|
13 | |||
20 | Test a null changelog rev, too: |
|
14 | Add an empty commit (this makes the changelog refer to a null manifest node): | |
|
15 | ||||
|
16 | ||||
|
17 | $ hg commit -m "init" --config ui.allowemptycommit=true | |||
21 |
|
18 | |||
22 | $ hg --config rhg.on-unsupported=abort files -r 0000000000000000000000000000000000000000 |
|
19 | $ hg files -r . | |
23 | [1] |
|
20 | [1] | |
|
21 | ||||
|
22 | Strip that empty commit (this makes the changelog file empty, as opposed to missing): | |||
|
23 | ||||
|
24 | $ hg --config 'extensions.strip=' strip . > /dev/null | |||
|
25 | ||||
|
26 | $ hg files -r . | |||
|
27 | [1] |
General Comments 0
You need to be logged in to leave comments.
Login now