1use std::cell::{RefCell, RefMut};
20use std::ffi::OsString;
21use std::os::unix::ffi::OsStrExt;
22use std::path::{Path, PathBuf};
23use std::rc::Rc;
24use std::sync::Arc;
25
26use anyhow::{bail, Result};
27use nydus_rafs::metadata::chunk::ChunkWrapper;
28use nydus_rafs::metadata::inode::InodeWrapper;
29use nydus_rafs::metadata::layout::{bytes_to_os_str, RafsXAttrs};
30use nydus_rafs::metadata::{Inode, RafsInodeExt, RafsSuper};
31use nydus_utils::{lazy_drop, root_tracer, timing_tracer};
32
33use super::node::{ChunkSource, Node, NodeChunk, NodeInfo};
34use super::overlay::{Overlay, WhiteoutType};
35use crate::core::overlay::OVERLAYFS_WHITEOUT_OPAQUE;
36use crate::{BuildContext, ChunkDict};
37
38pub type TreeNode = Rc<RefCell<Node>>;
40
41#[derive(Clone)]
43pub struct Tree {
44 pub node: TreeNode,
46 name: Vec<u8>,
48 pub children: Vec<Tree>,
50}
51
52impl Tree {
53 pub fn new(node: Node) -> Self {
55 let name = node.name().as_bytes().to_vec();
56 Tree {
57 node: Rc::new(RefCell::new(node)),
58 name,
59 children: Vec::new(),
60 }
61 }
62
63 pub fn from_bootstrap<T: ChunkDict>(rs: &RafsSuper, chunk_dict: &mut T) -> Result<Self> {
65 let tree_builder = MetadataTreeBuilder::new(rs);
66 let root_ino = rs.superblock.root_ino();
67 let root_inode = rs.get_extended_inode(root_ino, true)?;
68 let root_node = MetadataTreeBuilder::parse_node(rs, root_inode, PathBuf::from("/"))?;
69 let mut tree = Tree::new(root_node);
70
71 tree.children = timing_tracer!(
72 { tree_builder.load_children(root_ino, Option::<PathBuf>::None, chunk_dict, true,) },
73 "load_tree_from_bootstrap"
74 )?;
75
76 Ok(tree)
77 }
78
79 pub fn name(&self) -> &[u8] {
81 &self.name
82 }
83
84 pub fn set_node(&mut self, node: Node) {
86 self.node.replace(node);
87 }
88
89 pub fn borrow_mut_node(&self) -> RefMut<'_, Node> {
91 self.node.as_ref().borrow_mut()
92 }
93
94 pub fn walk_dfs<F1, F2>(&self, pre: &mut F1, post: &mut F2) -> Result<()>
96 where
97 F1: FnMut(&Tree) -> Result<()>,
98 F2: FnMut(&Tree) -> Result<()>,
99 {
100 pre(self)?;
101 for child in &self.children {
102 child.walk_dfs(pre, post)?;
103 }
104 post(self)?;
105
106 Ok(())
107 }
108
109 pub fn walk_dfs_pre<F>(&self, cb: &mut F) -> Result<()>
111 where
112 F: FnMut(&Tree) -> Result<()>,
113 {
114 self.walk_dfs(cb, &mut |_t| Ok(()))
115 }
116
117 pub fn walk_dfs_post<F>(&self, cb: &mut F) -> Result<()>
119 where
120 F: FnMut(&Tree) -> Result<()>,
121 {
122 self.walk_dfs(&mut |_t| Ok(()), cb)
123 }
124
125 pub fn walk_bfs<F>(&self, handle_self: bool, cb: &mut F) -> Result<()>
127 where
128 F: FnMut(&Tree) -> Result<()>,
129 {
130 if handle_self {
131 cb(self)?;
132 }
133
134 let mut dirs = Vec::with_capacity(32);
135 for child in &self.children {
136 cb(child)?;
137 if child.borrow_mut_node().is_dir() {
138 dirs.push(child);
139 }
140 }
141 for dir in dirs {
142 dir.walk_bfs(false, cb)?;
143 }
144
145 Ok(())
146 }
147
148 pub fn insert_child(&mut self, child: Tree) {
150 if let Err(idx) = self
151 .children
152 .binary_search_by_key(&&child.name, |n| &n.name)
153 {
154 self.children.insert(idx, child);
155 }
156 }
157
158 pub fn get_child_idx(&self, name: &[u8]) -> Option<usize> {
160 self.children.binary_search_by_key(&name, |n| &n.name).ok()
161 }
162
163 pub fn get_node(&self, path: &Path) -> Option<&Tree> {
165 let target_vec = Node::generate_target_vec(path);
166 assert!(!target_vec.is_empty());
167 let mut tree = self;
168 for name in &target_vec[1..] {
169 match tree.get_child_idx(name.as_bytes()) {
170 Some(idx) => tree = &tree.children[idx],
171 None => return None,
172 }
173 }
174 Some(tree)
175 }
176
177 pub fn get_node_mut(&mut self, path: &Path) -> Option<&mut Tree> {
179 let target_vec = Node::generate_target_vec(path);
180 assert!(!target_vec.is_empty());
181 let mut tree = self;
182
183 let last_idx = target_vec.len() - 1;
184 for name in &target_vec[1..last_idx] {
185 match tree.get_child_idx(name.as_bytes()) {
186 Some(idx) => tree = &mut tree.children[idx],
187 None => return None,
188 }
189 }
190
191 if let Some(last_name) = target_vec.last() {
192 match tree.get_child_idx(last_name.as_bytes()) {
193 Some(idx) => Some(&mut tree.children[idx]),
194 None => None,
195 }
196 } else {
197 Some(tree)
198 }
199 }
200
201 pub fn merge_overaly(&mut self, ctx: &BuildContext, upper: Tree) -> Result<()> {
203 assert_eq!(self.name, "/".as_bytes());
204 assert_eq!(upper.name, "/".as_bytes());
205
206 upper.borrow_mut_node().overlay = Overlay::UpperModification;
208 self.node = upper.node.clone();
209 self.merge_children(ctx, &upper)?;
210 lazy_drop(upper);
211
212 Ok(())
213 }
214
215 fn merge_children(&mut self, ctx: &BuildContext, upper: &Tree) -> Result<()> {
216 let mut modified = Vec::with_capacity(upper.children.len());
218 for u in upper.children.iter() {
219 let mut u_node = u.borrow_mut_node();
220 match u_node.whiteout_type(ctx.whiteout_spec) {
221 Some(WhiteoutType::OciRemoval) => {
222 if let Some(origin_name) = u_node.origin_name(WhiteoutType::OciRemoval) {
223 if let Some(idx) = self.get_child_idx(origin_name.as_bytes()) {
224 self.children.remove(idx);
225 }
226 }
227 }
228 Some(WhiteoutType::OciOpaque) => {
229 self.children.clear();
230 }
231 Some(WhiteoutType::OverlayFsRemoval) => {
232 if let Some(idx) = self.get_child_idx(&u.name) {
233 self.children.remove(idx);
234 }
235 }
236 Some(WhiteoutType::OverlayFsOpaque) => {
237 if let Some(idx) = self.get_child_idx(&u.name) {
238 self.children[idx].children.clear();
239 }
240 u_node.remove_xattr(&OsString::from(OVERLAYFS_WHITEOUT_OPAQUE));
241 modified.push(u);
242 }
243 None => modified.push(u),
244 }
245 }
246
247 let mut dirs = Vec::new();
248 for u in modified {
249 let mut u_node = u.borrow_mut_node();
250 if let Some(idx) = self.get_child_idx(&u.name) {
251 u_node.overlay = Overlay::UpperModification;
252 self.children[idx].node = u.node.clone();
253 } else {
254 u_node.overlay = Overlay::UpperAddition;
255 self.insert_child(Tree {
256 node: u.node.clone(),
257 name: u.name.clone(),
258 children: vec![],
259 });
260 }
261 if u_node.is_dir() {
262 dirs.push(u);
263 }
264 }
265 for dir in dirs {
266 if let Some(idx) = self.get_child_idx(&dir.name) {
267 self.children[idx].merge_children(ctx, dir)?;
268 } else {
269 bail!("builder: can not find directory in merged tree");
270 }
271 }
272
273 Ok(())
274 }
275}
276
277pub struct MetadataTreeBuilder<'a> {
278 rs: &'a RafsSuper,
279}
280
281impl<'a> MetadataTreeBuilder<'a> {
282 fn new(rs: &'a RafsSuper) -> Self {
283 Self { rs }
284 }
285
286 fn load_children<T: ChunkDict, P: AsRef<Path>>(
288 &self,
289 ino: Inode,
290 parent: Option<P>,
291 chunk_dict: &mut T,
292 validate_digest: bool,
293 ) -> Result<Vec<Tree>> {
294 let inode = self.rs.get_extended_inode(ino, validate_digest)?;
295 if !inode.is_dir() {
296 return Ok(Vec::new());
297 }
298
299 let parent_path = if let Some(parent) = parent {
300 parent.as_ref().join(inode.name())
301 } else {
302 PathBuf::from("/")
303 };
304
305 let blobs = self.rs.superblock.get_blob_infos();
306 let child_count = inode.get_child_count();
307 let mut children = Vec::with_capacity(child_count as usize);
308 for idx in 0..child_count {
309 let child = inode.get_child_by_index(idx)?;
310 let child_path = parent_path.join(child.name());
311 let child = Self::parse_node(self.rs, child.clone(), child_path)?;
312
313 if child.is_reg() {
314 for chunk in &child.chunks {
315 let blob_idx = chunk.inner.blob_index();
316 if let Some(blob) = blobs.get(blob_idx as usize) {
317 chunk_dict.add_chunk(chunk.inner.clone(), blob.digester());
318 }
319 }
320 }
321
322 let child = Tree::new(child);
323 children.push(child);
324 }
325 children.sort_unstable_by(|a, b| a.name.cmp(&b.name));
326
327 for child in children.iter_mut() {
328 let child_node = child.borrow_mut_node();
329 if child_node.is_dir() {
330 let child_ino = child_node.inode.ino();
331 drop(child_node);
332 child.children =
333 self.load_children(child_ino, Some(&parent_path), chunk_dict, validate_digest)?;
334 }
335 }
336
337 Ok(children)
338 }
339
340 pub fn parse_node(rs: &RafsSuper, inode: Arc<dyn RafsInodeExt>, path: PathBuf) -> Result<Node> {
342 let chunks = if inode.is_reg() {
343 let chunk_count = inode.get_chunk_count();
344 let mut chunks = Vec::with_capacity(chunk_count as usize);
345 for i in 0..chunk_count {
346 let cki = inode.get_chunk_info(i)?;
347 chunks.push(NodeChunk {
348 source: ChunkSource::Parent,
349 inner: Arc::new(ChunkWrapper::from_chunk_info(cki)),
350 });
351 }
352 chunks
353 } else {
354 Vec::new()
355 };
356
357 let symlink = if inode.is_symlink() {
358 Some(inode.get_symlink()?)
359 } else {
360 None
361 };
362
363 let mut xattrs = RafsXAttrs::new();
364 for name in inode.get_xattrs()? {
365 let name = bytes_to_os_str(&name);
366 let value = inode.get_xattr(name)?;
367 xattrs.add(name.to_os_string(), value.unwrap_or_default())?;
368 }
369
370 let src_dev = u64::MAX;
373 let rdev = inode.rdev() as u64;
374 let inode = InodeWrapper::from_inode_info(inode.clone());
375 let source = PathBuf::from("/");
376 let target = Node::generate_target(&path, &source);
377 let target_vec = Node::generate_target_vec(&target);
378 let info = NodeInfo {
379 explicit_uidgid: rs.meta.explicit_uidgid(),
380 src_ino: inode.ino(),
381 src_dev,
382 rdev,
383 path,
384 source,
385 target,
386 target_vec,
387 symlink,
388 xattrs,
389 v6_force_extended_inode: false,
390 };
391
392 Ok(Node {
393 info: Arc::new(info),
394 index: 0,
395 layer_idx: 0,
396 overlay: Overlay::Lower,
397 inode,
398 chunks,
399 v6_offset: 0,
400 v6_dirents: Vec::new(),
401 v6_datalayout: 0,
402 v6_compact_inode: false,
403 v6_dirents_offset: 0,
404 })
405 }
406}
407
408#[cfg(test)]
409mod tests {
410 use super::*;
411 use nydus_rafs::metadata::RafsVersion;
412 use nydus_storage::RAFS_DEFAULT_CHUNK_SIZE;
413 use vmm_sys_util::tempdir::TempDir;
414 use vmm_sys_util::tempfile::TempFile;
415
416 #[test]
417 fn test_set_lock_node() {
418 let tmpdir = TempDir::new().unwrap();
419 let tmpfile = TempFile::new_in(tmpdir.as_path()).unwrap();
420 let node = Node::from_fs_object(
421 RafsVersion::V6,
422 tmpdir.as_path().to_path_buf(),
423 tmpfile.as_path().to_path_buf(),
424 Overlay::UpperAddition,
425 RAFS_DEFAULT_CHUNK_SIZE as u32,
426 0,
427 true,
428 false,
429 )
430 .unwrap();
431 let mut tree = Tree::new(node);
432 assert_eq!(tree.name, tmpfile.as_path().file_name().unwrap().as_bytes());
433 let node1 = tree.borrow_mut_node();
434 drop(node1);
435
436 let tmpfile = TempFile::new_in(tmpdir.as_path()).unwrap();
437 let node = Node::from_fs_object(
438 RafsVersion::V6,
439 tmpdir.as_path().to_path_buf(),
440 tmpfile.as_path().to_path_buf(),
441 Overlay::UpperAddition,
442 RAFS_DEFAULT_CHUNK_SIZE as u32,
443 0,
444 true,
445 false,
446 )
447 .unwrap();
448 tree.set_node(node);
449 let node2 = tree.borrow_mut_node();
450 assert_eq!(node2.name(), tmpfile.as_path().file_name().unwrap());
451 }
452
453 #[test]
454 fn test_walk_tree() {
455 let tmpdir = TempDir::new().unwrap();
456 let tmpfile = TempFile::new_in(tmpdir.as_path()).unwrap();
457 let node = Node::from_fs_object(
458 RafsVersion::V6,
459 tmpdir.as_path().to_path_buf(),
460 tmpfile.as_path().to_path_buf(),
461 Overlay::UpperAddition,
462 RAFS_DEFAULT_CHUNK_SIZE as u32,
463 0,
464 true,
465 false,
466 )
467 .unwrap();
468 let mut tree = Tree::new(node);
469
470 let tmpfile2 = TempFile::new_in(tmpdir.as_path()).unwrap();
471 let node = Node::from_fs_object(
472 RafsVersion::V6,
473 tmpdir.as_path().to_path_buf(),
474 tmpfile2.as_path().to_path_buf(),
475 Overlay::UpperAddition,
476 RAFS_DEFAULT_CHUNK_SIZE as u32,
477 0,
478 true,
479 false,
480 )
481 .unwrap();
482 let tree2 = Tree::new(node);
483 tree.insert_child(tree2);
484
485 let tmpfile3 = TempFile::new_in(tmpdir.as_path()).unwrap();
486 let node = Node::from_fs_object(
487 RafsVersion::V6,
488 tmpdir.as_path().to_path_buf(),
489 tmpfile3.as_path().to_path_buf(),
490 Overlay::UpperAddition,
491 RAFS_DEFAULT_CHUNK_SIZE as u32,
492 0,
493 true,
494 false,
495 )
496 .unwrap();
497 let tree3 = Tree::new(node);
498 tree.insert_child(tree3);
499
500 let mut count = 0;
501 tree.walk_bfs(true, &mut |_n| -> Result<()> {
502 count += 1;
503 Ok(())
504 })
505 .unwrap();
506 assert_eq!(count, 3);
507
508 let mut count = 0;
509 tree.walk_bfs(false, &mut |_n| -> Result<()> {
510 count += 1;
511 Ok(())
512 })
513 .unwrap();
514 assert_eq!(count, 2);
515
516 let mut count = 0;
517 tree.walk_bfs(true, &mut |_n| -> Result<()> {
518 count += 1;
519 bail!("test")
520 })
521 .unwrap_err();
522 assert_eq!(count, 1);
523
524 let idx = tree
525 .get_child_idx(tmpfile2.as_path().file_name().unwrap().as_bytes())
526 .unwrap();
527 assert!(idx == 0 || idx == 1);
528 let idx = tree
529 .get_child_idx(tmpfile3.as_path().file_name().unwrap().as_bytes())
530 .unwrap();
531 assert!(idx == 0 || idx == 1);
532 }
533}