Skip to content

Commit 2ac8970

Browse files
committed
refactor: move HermitImageThinFile into hermit-image-reader
1 parent b4ae8c8 commit 2ac8970

File tree

5 files changed

+102
-78
lines changed

5 files changed

+102
-78
lines changed

hermit-image-reader/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,5 @@ mod tar_parser;
2121
pub use tar_parser::{ImageFile, ImageParser, ImageParserError};
2222

2323
pub mod config;
24+
25+
pub mod thin_tree;

hermit-image-reader/src/tar_parser.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Copyright (c) 2025 Hermit contributors
22
// SPDX-License-Identifier: MIT OR Apache-2.0
33

4-
use alloc::borrow::Cow;
4+
use alloc::{borrow::Cow, string::String, vec::Vec};
55
use core::ops::Range;
66

77
// taken from `tar-rs`
@@ -39,6 +39,8 @@ pub enum ImageParserError {
3939
ParseInt(core::num::ParseIntError),
4040
FromInt(core::num::TryFromIntError),
4141
Utf8(core::str::Utf8Error),
42+
43+
FileOverridenWithDirectory(Vec<String>),
4244
}
4345

4446
impl From<core::num::ParseIntError> for ImageParserError {
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
// Copyright (c) 2025 Hermit contributors
2+
// SPDX-License-Identifier: MIT OR Apache-2.0
3+
4+
use alloc::{
5+
collections::btree_map::BTreeMap,
6+
string::{String, ToString},
7+
vec::Vec,
8+
};
9+
use core::ops::Range;
10+
11+
use crate::{ImageParser, ImageParserError};
12+
13+
#[derive(Clone, Debug, PartialEq, Eq)]
14+
pub enum ThinTree {
15+
File(Range<usize>),
16+
Directory(BTreeMap<String, ThinTree>),
17+
}
18+
19+
impl ThinTree {
20+
/// Populate a thin directory tree, with `entry` pointing to `r`
21+
pub fn update(&mut self, entry: &[&str], r: Range<usize>) -> Result<(), ImageParserError> {
22+
let mut this = self;
23+
for (n, i) in entry.iter().copied().enumerate() {
24+
let dir = match this {
25+
Self::File(r) if r.start == r.end => {
26+
*this = Self::Directory(BTreeMap::new());
27+
if let Self::Directory(dir) = this {
28+
dir
29+
} else {
30+
unreachable!()
31+
}
32+
}
33+
Self::File(_) => {
34+
return Err(ImageParserError::FileOverridenWithDirectory(
35+
entry[..=n].iter().map(|i| i.to_string()).collect(),
36+
));
37+
}
38+
Self::Directory(dir) => dir,
39+
};
40+
this = dir.entry(i.to_string()).or_insert(ThinTree::File(0..0));
41+
}
42+
*this = Self::File(r);
43+
Ok(())
44+
}
45+
46+
pub fn try_from_image(image: &[u8]) -> Result<Self, ImageParserError> {
47+
let mut content = Self::File(0..0);
48+
for i in ImageParser::new(image) {
49+
let i = i?;
50+
let name = str::from_utf8(&i.name)?;
51+
// multiple entries with the same name might exist,
52+
// latest entry wins / overwrites existing ones
53+
content.update(&name.split('/').collect::<Vec<_>>(), i.value_range)?;
54+
}
55+
Ok(content)
56+
}
57+
58+
/// Remove an entry from a thin directory tree
59+
pub fn unlink(&mut self, entry: &[&str]) {
60+
if entry.is_empty() {
61+
// we can't remove ourselves.
62+
return;
63+
}
64+
let (lead, to_remove) = entry.split_at(entry.len() - 1);
65+
let this = self.resolve_mut(lead);
66+
if let Some(Self::Directory(this)) = this {
67+
this.remove(to_remove[0]);
68+
}
69+
}
70+
71+
pub fn resolve(&self, entry: &[&str]) -> Option<&ThinTree> {
72+
entry.iter().try_fold(self, |this, &i| {
73+
if let Self::Directory(dir) = this {
74+
dir.get(i)
75+
} else {
76+
None
77+
}
78+
})
79+
}
80+
81+
pub fn resolve_mut(&mut self, entry: &[&str]) -> Option<&mut ThinTree> {
82+
entry.iter().try_fold(self, |this, &i| {
83+
if let Self::Directory(dir) = this {
84+
dir.get_mut(i)
85+
} else {
86+
None
87+
}
88+
})
89+
}
90+
}

src/hypercall.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use clean_path::clean;
1313
use uhyve_interface::{GuestPhysAddr, Hypercall, HypercallAddress, MAX_ARGC_ENVC, parameters::*};
1414

1515
use crate::{
16-
isolation::filemap::{HermitImageThinFile, MappedFileMutRef, UhyveFileMap},
16+
isolation::filemap::{HermitImageThinTree, MappedFileMutRef, UhyveFileMap},
1717
mem::{MemoryError, MmapMemory},
1818
params::EnvVars,
1919
virt_to_phys,
@@ -167,7 +167,7 @@ pub fn open(mem: &MmapMemory, sysopen: &mut OpenParams, file_map: &mut UhyveFile
167167
}
168168
MappedFileMutRef::InImage {
169169
image,
170-
thin: HermitImageThinFile::File(r),
170+
thin: HermitImageThinTree::File(r),
171171
} => {
172172
// For simplicity, create a temporary files with these contents.
173173
debug!("Attempting to open a temp file for unpacked {guest_path:#?}...");

src/isolation/filemap.rs

Lines changed: 5 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use std::{
1010
};
1111

1212
use clean_path::clean;
13+
pub use hermit_image_reader::thin_tree::ThinTree as HermitImageThinTree;
1314
use tempfile::TempDir;
1415
use uuid::Uuid;
1516

@@ -39,76 +40,12 @@ impl core::ops::Index<Range<usize>> for HermitImage {
3940
}
4041
}
4142

42-
#[derive(Clone, Debug, PartialEq, Eq)]
43-
pub enum HermitImageThinFile {
44-
File(Range<usize>),
45-
Directory(HashMap<String, HermitImageThinFile>),
46-
}
47-
48-
impl HermitImageThinFile {
49-
/// Populate a thin directory tree, with `entry` pointing to `r`
50-
pub fn update(&mut self, entry: &[&str], r: Range<usize>) {
51-
let mut this = self;
52-
for i in entry {
53-
let dir = match this {
54-
Self::File(r) if r.start == r.end => {
55-
*this = Self::Directory(HashMap::new());
56-
if let Self::Directory(dir) = this {
57-
dir
58-
} else {
59-
unreachable!()
60-
}
61-
}
62-
Self::File(_) => panic!("file in hermit image got overridden"),
63-
Self::Directory(dir) => dir,
64-
};
65-
this = dir
66-
.entry(i.to_string())
67-
.or_insert(HermitImageThinFile::File(0..0));
68-
}
69-
*this = Self::File(r);
70-
}
71-
72-
/// Remove an entry from a thin directory tree
73-
pub fn unlink(&mut self, entry: &[&str]) {
74-
if entry.is_empty() {
75-
// we can't remove ourselves.
76-
return;
77-
}
78-
let (lead, to_remove) = entry.split_at(entry.len() - 1);
79-
let this = self.resolve_mut(lead);
80-
if let Some(Self::Directory(this)) = this {
81-
this.remove(to_remove[0]);
82-
}
83-
}
84-
85-
pub fn resolve(&self, entry: &[&str]) -> Option<&HermitImageThinFile> {
86-
entry.iter().try_fold(self, |this, &i| {
87-
if let Self::Directory(dir) = this {
88-
dir.get(i)
89-
} else {
90-
None
91-
}
92-
})
93-
}
94-
95-
pub fn resolve_mut(&mut self, entry: &[&str]) -> Option<&mut HermitImageThinFile> {
96-
entry.iter().try_fold(self, |this, &i| {
97-
if let Self::Directory(dir) = this {
98-
dir.get_mut(i)
99-
} else {
100-
None
101-
}
102-
})
103-
}
104-
}
105-
10643
#[derive(Clone, Debug)]
10744
pub enum MappedFile {
10845
OnHost(PathBuf),
10946
InImage {
11047
image: Arc<HermitImage>,
111-
thin: HermitImageThinFile,
48+
thin: HermitImageThinTree,
11249
},
11350
}
11451

@@ -117,7 +54,7 @@ pub enum MappedFileMutRef<'a> {
11754
OnHost(PathBuf),
11855
InImage {
11956
image: &'a Arc<HermitImage>,
120-
thin: &'a mut HermitImageThinFile,
57+
thin: &'a mut HermitImageThinTree,
12158
},
12259
}
12360

@@ -203,15 +140,8 @@ impl UhyveFileMap {
203140
let mmap = unsafe { MmapOptions::new().map(tmpf.as_file()) }
204141
.expect("unable to mmap decompressed hermit image file");
205142

206-
let mut content = HermitImageThinFile::File(0..0);
207-
for i in hermit_image_reader::ImageParser::new(&mmap[..]) {
208-
let i = i.expect("unable to read hermit image entry");
209-
if let Ok(name) = str::from_utf8(&i.name) {
210-
// multiple entries with the same name might exist,
211-
// latest entry wins / overwrites existing ones
212-
content.update(&name.split('/').collect::<Vec<_>>(), i.value_range);
213-
}
214-
}
143+
let content = HermitImageThinTree::try_from_image(&mmap[..])
144+
.expect("unable to parse hermit image file entry");
215145

216146
(
217147
Arc::new(HermitImage {

0 commit comments

Comments
 (0)