nydus_builder/core/
bootstrap.rs1use anyhow::{Context, Error, Result};
7use nydus_utils::digest::{self, RafsDigest};
8use std::ops::Deref;
9
10use nydus_rafs::metadata::layout::{RafsBlobTable, RAFS_V5_ROOT_INODE};
11use nydus_rafs::metadata::{RafsSuper, RafsSuperConfig, RafsSuperFlags};
12
13use crate::{ArtifactStorage, BlobManager, BootstrapContext, BootstrapManager, BuildContext, Tree};
14
15pub struct Bootstrap {
17 pub(crate) tree: Tree,
18}
19
20impl Bootstrap {
21 pub fn new(tree: Tree) -> Result<Self> {
23 Ok(Self { tree })
24 }
25
26 pub fn build(
28 &mut self,
29 ctx: &mut BuildContext,
30 bootstrap_ctx: &mut BootstrapContext,
31 ) -> Result<()> {
32 let mut root_node = self.tree.borrow_mut_node();
34 assert!(root_node.is_dir());
35 let index = bootstrap_ctx.generate_next_ino();
36 assert_eq!(index, RAFS_V5_ROOT_INODE);
38 root_node.index = index;
39 root_node.inode.set_ino(index);
40 ctx.prefetch.insert(&self.tree.node, root_node.deref());
41 bootstrap_ctx.inode_map.insert(
42 (
43 root_node.layer_idx,
44 root_node.info.src_ino,
45 root_node.info.src_dev,
46 ),
47 vec![self.tree.node.clone()],
48 );
49 drop(root_node);
50
51 Self::build_rafs(ctx, bootstrap_ctx, &mut self.tree)?;
52 if ctx.fs_version.is_v6() {
53 let root_offset = self.tree.node.borrow().v6_offset;
54 Self::v6_update_dirents(&self.tree, root_offset);
55 }
56
57 Ok(())
58 }
59
60 pub fn dump(
62 &mut self,
63 ctx: &mut BuildContext,
64 bootstrap_storage: &mut Option<ArtifactStorage>,
65 bootstrap_ctx: &mut BootstrapContext,
66 blob_table: &RafsBlobTable,
67 ) -> Result<()> {
68 match blob_table {
69 RafsBlobTable::V5(table) => self.v5_dump(ctx, bootstrap_ctx, table)?,
70 RafsBlobTable::V6(table) => self.v6_dump(ctx, bootstrap_ctx, table)?,
71 }
72
73 if let Some(ArtifactStorage::FileDir(p)) = bootstrap_storage {
74 let bootstrap_data = bootstrap_ctx.writer.as_bytes()?;
75 let digest = RafsDigest::from_buf(&bootstrap_data, digest::Algorithm::Sha256);
76 let name = digest.to_string();
77 bootstrap_ctx.writer.finalize(Some(name.clone()))?;
78 let mut path = p.0.join(name);
79 path.set_extension(&p.1);
80 *bootstrap_storage = Some(ArtifactStorage::SingleFile(path));
81 Ok(())
82 } else {
83 bootstrap_ctx.writer.finalize(Some(String::default()))
84 }
85 }
86
87 fn build_rafs(
90 ctx: &mut BuildContext,
91 bootstrap_ctx: &mut BootstrapContext,
92 tree: &mut Tree,
93 ) -> Result<()> {
94 let parent_node = tree.node.clone();
95 let mut parent_node = parent_node.borrow_mut();
96 let parent_ino = parent_node.inode.ino();
97 let block_size = ctx.v6_block_size();
98
99 if parent_node.is_dir() {
101 parent_node
102 .inode
103 .set_child_count(tree.children.len() as u32);
104 if ctx.fs_version.is_v5() {
105 parent_node
106 .inode
107 .set_child_index(bootstrap_ctx.get_next_ino() as u32);
108 } else if ctx.fs_version.is_v6() {
109 let d_size = parent_node.v6_dirent_size(ctx, tree)?;
111 parent_node.v6_set_dir_offset(bootstrap_ctx, d_size, block_size)?;
112 }
113 }
114
115 let mut dirs: Vec<&mut Tree> = Vec::new();
116 for child in tree.children.iter_mut() {
117 let child_node = child.node.clone();
118 let mut child_node = child_node.borrow_mut();
119 let index = bootstrap_ctx.generate_next_ino();
120 child_node.index = index;
121 if ctx.fs_version.is_v5() {
122 child_node.inode.set_parent(parent_ino);
123 }
124
125 let mut v6_hardlink_offset: Option<u64> = None;
130 let key = (
131 child_node.layer_idx,
132 child_node.info.src_ino,
133 child_node.info.src_dev,
134 );
135 if let Some(indexes) = bootstrap_ctx.inode_map.get_mut(&key) {
136 let nlink = indexes.len() as u32 + 1;
137 for n in indexes.iter() {
139 n.borrow_mut().inode.set_nlink(nlink);
140 }
141
142 let (first_ino, first_offset) = {
143 let first_node = indexes[0].borrow_mut();
144 (first_node.inode.ino(), first_node.v6_offset)
145 };
146 v6_hardlink_offset = Some(first_offset);
148 child_node.inode.set_nlink(nlink);
149 child_node.inode.set_ino(first_ino);
150 indexes.push(child.node.clone());
151 } else {
152 child_node.inode.set_ino(index);
153 child_node.inode.set_nlink(1);
154 bootstrap_ctx
156 .inode_map
157 .insert(key, vec![child.node.clone()]);
158 }
159
160 if !child_node.is_dir() && ctx.fs_version.is_v6() {
162 child_node.v6_set_offset(bootstrap_ctx, v6_hardlink_offset, block_size)?;
163 }
164 ctx.prefetch.insert(&child.node, child_node.deref());
165 if child_node.is_dir() {
166 dirs.push(child);
167 }
168 }
169
170 if parent_node.is_dir() {
173 parent_node.inode.set_nlink((2 + dirs.len()) as u32);
174 }
175 for dir in dirs {
176 Self::build_rafs(ctx, bootstrap_ctx, dir)?;
177 }
178
179 Ok(())
180 }
181
182 pub fn load_parent_bootstrap(
184 ctx: &mut BuildContext,
185 bootstrap_mgr: &mut BootstrapManager,
186 blob_mgr: &mut BlobManager,
187 ) -> Result<Tree> {
188 let rs = if let Some(path) = bootstrap_mgr.f_parent_path.as_ref() {
189 RafsSuper::load_from_file(path, ctx.configuration.clone(), false).map(|(rs, _)| rs)?
190 } else {
191 return Err(Error::msg("bootstrap context's parent bootstrap is null"));
192 };
193
194 let config = RafsSuperConfig {
195 compressor: ctx.compressor,
196 digester: ctx.digester,
197 chunk_size: ctx.chunk_size,
198 batch_size: ctx.batch_size,
199 explicit_uidgid: ctx.explicit_uidgid,
200 version: ctx.fs_version,
201 is_tarfs_mode: rs.meta.flags.contains(RafsSuperFlags::TARTFS_MODE),
202 };
203 config.check_compatibility(&rs.meta)?;
204
205 blob_mgr.extend_from_blob_table(ctx, rs.superblock.get_blob_infos())?;
208
209 Tree::from_bootstrap(&rs, &mut blob_mgr.layered_chunk_dict)
212 .context("failed to build tree from bootstrap")
213 }
214}