diff --git a/rafs/src/builder/core/bootstrap.rs b/rafs/src/builder/core/bootstrap.rs index f889a812fc7..7e873adcc94 100644 --- a/rafs/src/builder/core/bootstrap.rs +++ b/rafs/src/builder/core/bootstrap.rs @@ -160,9 +160,10 @@ impl Bootstrap { // binary search. tree.children .sort_by_key(|child| child.node.name().to_os_string()); - parent.inode.set_child_index(index); parent.inode.set_child_count(tree.children.len() as u32); - if ctx.fs_version.is_v6() { + if ctx.fs_version.is_v5() { + parent.inode.set_child_index(index); + } else if ctx.fs_version.is_v6() { let d_size = tree.node.v6_dirent_size(ctx, tree)?; parent.v6_set_dir_offset(bootstrap_ctx, d_size, block_size)?; } @@ -177,7 +178,9 @@ impl Bootstrap { for child in tree.children.iter_mut() { let index = nodes.len() as u64 + 1; child.node.index = index; - child.node.inode.set_parent(parent_ino); + if ctx.fs_version.is_v5() { + child.node.inode.set_parent(parent_ino); + } // Handle hardlink. // All hardlink nodes' ino and nlink should be the same. diff --git a/rafs/src/builder/core/node.rs b/rafs/src/builder/core/node.rs index c9450fad890..f895c83dfbb 100644 --- a/rafs/src/builder/core/node.rs +++ b/rafs/src/builder/core/node.rs @@ -173,13 +173,12 @@ impl Display for Node { fn fmt(&self, f: &mut Formatter) -> fmt::Result { write!( f, - "{} {:?}: index {} ino {} real_ino {} i_parent {} child_index {} child_count {} i_nlink {} i_size {} i_blocks {} i_name_size {} i_symlink_size {} has_xattr {} link {:?} i_mtime {} i_mtime_nsec {}", + "{} {:?}: index {} ino {} real_ino {} child_index {} child_count {} i_nlink {} i_size {} i_blocks {} i_name_size {} i_symlink_size {} has_xattr {} link {:?} i_mtime {} i_mtime_nsec {}", self.file_type(), self.target(), self.index, self.inode.ino(), self.info.src_ino, - self.inode.parent(), self.inode.child_index(), self.inode.child_count(), self.inode.nlink(), @@ -609,7 +608,15 @@ impl Node { } fn build_inode(&mut self, chunk_size: u32) -> Result<()> { - self.inode.set_name_size(self.name().byte_size()); + let size = self.name().byte_size(); + if size > u16::MAX as usize { + bail!( + "file name length 0x{:x} is too big, max 0x{:x}", + size, + u16::MAX + ); + } + self.inode.set_name_size(size); // NOTE: Always retrieve xattr before attr so that we can know the size of xattr pairs. self.build_inode_xattr() @@ -631,6 +638,9 @@ impl Node { })?; let symlink: OsString = target_path.into(); let size = symlink.byte_size(); + if size > u16::MAX as usize { + bail!("symlink content size 0x{:x} is too big", size); + } self.inode.set_symlink_size(size); self.set_symlink(symlink); } diff --git a/rafs/src/builder/core/v6.rs b/rafs/src/builder/core/v6.rs index 6cc8a921e6a..d485ec3c79a 100644 --- a/rafs/src/builder/core/v6.rs +++ b/rafs/src/builder/core/v6.rs @@ -18,13 +18,12 @@ use super::chunk_dict::DigestWithBlobIndex; use super::node::Node; use crate::builder::{Bootstrap, BootstrapContext, BuildContext, ConversionType, Tree}; use crate::metadata::chunk::ChunkWrapper; -use crate::metadata::inode::new_v6_inode; use crate::metadata::layout::v6::{ - align_offset, calculate_nid, RafsV6BlobTable, RafsV6Device, RafsV6Dirent, RafsV6InodeChunkAddr, - RafsV6InodeChunkHeader, RafsV6OndiskInode, RafsV6SuperBlock, RafsV6SuperBlockExt, - EROFS_BLOCK_BITS_9, EROFS_BLOCK_SIZE_4096, EROFS_BLOCK_SIZE_512, EROFS_DEVTABLE_OFFSET, - EROFS_INODE_CHUNK_BASED, EROFS_INODE_FLAT_INLINE, EROFS_INODE_FLAT_PLAIN, - EROFS_INODE_SLOT_SIZE, EROFS_SUPER_BLOCK_SIZE, EROFS_SUPER_OFFSET, + align_offset, calculate_nid, new_v6_inode, RafsV6BlobTable, RafsV6Device, RafsV6Dirent, + RafsV6InodeChunkAddr, RafsV6InodeChunkHeader, RafsV6OndiskInode, RafsV6SuperBlock, + RafsV6SuperBlockExt, EROFS_BLOCK_BITS_9, EROFS_BLOCK_SIZE_4096, EROFS_BLOCK_SIZE_512, + EROFS_DEVTABLE_OFFSET, EROFS_INODE_CHUNK_BASED, EROFS_INODE_FLAT_INLINE, + EROFS_INODE_FLAT_PLAIN, EROFS_INODE_SLOT_SIZE, EROFS_SUPER_BLOCK_SIZE, EROFS_SUPER_OFFSET, }; use crate::metadata::RafsStore; use crate::RafsIoWrite; diff --git a/rafs/src/builder/stargz.rs b/rafs/src/builder/stargz.rs index 3dce73b54e9..694aad2ecd0 100644 --- a/rafs/src/builder/stargz.rs +++ b/rafs/src/builder/stargz.rs @@ -33,8 +33,8 @@ use super::core::overlay::Overlay; use super::core::tree::Tree; use super::{build_bootstrap, Builder}; use crate::metadata::chunk::ChunkWrapper; -use crate::metadata::inode::InodeWrapper; -use crate::metadata::layout::v5::{RafsV5ChunkInfo, RafsV5Inode, RafsV5InodeFlags}; +use crate::metadata::inode::{InodeWrapper, RafsInodeFlags, RafsV6Inode}; +use crate::metadata::layout::v5::{RafsV5ChunkInfo, RafsV5Inode}; use crate::metadata::layout::RafsXAttrs; use crate::metadata::{Inode, RafsVersion}; @@ -543,8 +543,8 @@ impl StargzTreeBuilder { let entry_path = entry.path()?; let mut file_size = entry.size; let mut flags = match version { - RafsVersion::V5 => RafsV5InodeFlags::default(), - RafsVersion::V6 => RafsV5InodeFlags::default(), + RafsVersion::V5 => RafsInodeFlags::default(), + RafsVersion::V6 => RafsInodeFlags::default(), }; // Parse symlink @@ -552,7 +552,7 @@ impl StargzTreeBuilder { let symlink_link_path = entry.symlink_link_path(); let symlink_size = symlink_link_path.byte_size() as u16; file_size = symlink_size.into(); - flags |= RafsV5InodeFlags::SYMLINK; + flags |= RafsInodeFlags::SYMLINK; (Some(symlink_link_path.as_os_str().to_owned()), symlink_size) } else { (None, 0) @@ -562,7 +562,7 @@ impl StargzTreeBuilder { let mut xattrs = RafsXAttrs::new(); if entry.has_xattr() { for (name, value) in entry.xattrs.iter() { - flags |= RafsV5InodeFlags::XATTR; + flags |= RafsInodeFlags::XATTR; let value = base64::decode(value).with_context(|| { format!( "parse xattr name {:?} of file {:?} failed", @@ -576,7 +576,7 @@ impl StargzTreeBuilder { // Handle hardlink ino let mut ino = (self.path_inode_map.len() + 1) as Inode; if entry.is_hardlink() { - flags |= RafsV5InodeFlags::HARDLINK; + flags |= RafsInodeFlags::HARDLINK; if let Some(_ino) = self.path_inode_map.get(&entry.hardlink_link_path()) { ino = *_ino; } else { @@ -591,32 +591,47 @@ impl StargzTreeBuilder { let uid = if explicit_uidgid { entry.uid } else { 0 }; let gid = if explicit_uidgid { entry.gid } else { 0 }; - // Parse inode info - let v5_inode = RafsV5Inode { - i_digest: RafsDigest::default(), - i_parent: 0, - i_ino: ino, - i_projid: 0, - i_uid: uid, - i_gid: gid, - i_mode: entry.mode(), - i_size: file_size, - i_nlink: entry.num_link, - i_blocks: 0, - i_flags: flags, - i_child_index: 0, - i_child_count: 0, - i_name_size: name_size, - i_symlink_size: symlink_size, - i_rdev: entry.rdev(), - // TODO: add mtime from entry.ModTime() - i_mtime: 0, - i_mtime_nsec: 0, - i_reserved: [0; 8], - }; let inode = match version { - RafsVersion::V5 => InodeWrapper::V5(v5_inode), - RafsVersion::V6 => InodeWrapper::V6(v5_inode), + RafsVersion::V5 => InodeWrapper::V5(RafsV5Inode { + i_digest: RafsDigest::default(), + i_parent: 0, + i_ino: ino, + i_projid: 0, + i_uid: uid, + i_gid: gid, + i_mode: entry.mode(), + i_size: file_size, + i_nlink: entry.num_link, + i_blocks: 0, + i_flags: flags, + i_child_index: 0, + i_child_count: 0, + i_name_size: name_size, + i_symlink_size: symlink_size, + i_rdev: entry.rdev(), + // TODO: add mtime from entry.ModTime() + i_mtime: 0, + i_mtime_nsec: 0, + i_reserved: [0; 8], + }), + RafsVersion::V6 => InodeWrapper::V6(RafsV6Inode { + i_ino: ino, + i_projid: 0, + i_uid: uid, + i_gid: gid, + i_mode: entry.mode(), + i_size: file_size, + i_nlink: entry.num_link, + i_blocks: 0, + i_flags: flags, + i_child_count: 0, + i_name_size: name_size, + i_symlink_size: symlink_size, + i_rdev: entry.rdev(), + // TODO: add mtime from entry.ModTime() + i_mtime: 0, + i_mtime_nsec: 0, + }), }; let path = entry.path()?; diff --git a/rafs/src/builder/tarball.rs b/rafs/src/builder/tarball.rs index a9558740426..e9f94aac3b6 100644 --- a/rafs/src/builder/tarball.rs +++ b/rafs/src/builder/tarball.rs @@ -43,8 +43,8 @@ use super::core::node::{Node, NodeInfo}; use super::core::overlay::Overlay; use super::core::tree::Tree; use super::{build_bootstrap, dump_bootstrap, finalize_blob, Builder}; -use crate::metadata::inode::InodeWrapper; -use crate::metadata::layout::v5::{RafsV5Inode, RafsV5InodeFlags}; +use crate::metadata::inode::{InodeWrapper, RafsInodeFlags, RafsV6Inode}; +use crate::metadata::layout::v5::RafsV5Inode; use crate::metadata::layout::RafsXAttrs; use crate::metadata::{Inode, RafsVersion}; @@ -229,8 +229,8 @@ impl<'a> TarballTreeBuilder<'a> { let (uid, gid) = Self::get_uid_gid(self.ctx, header)?; let mtime = header.mtime().unwrap_or_default(); let mut flags = match self.ctx.fs_version { - RafsVersion::V5 => RafsV5InodeFlags::default(), - RafsVersion::V6 => RafsV5InodeFlags::default(), + RafsVersion::V5 => RafsInodeFlags::default(), + RafsVersion::V6 => RafsInodeFlags::default(), }; // Parse special files @@ -262,7 +262,7 @@ impl<'a> TarballTreeBuilder<'a> { bail!("tarball: symlink target from tar entry is too big"); } file_size = symlink_size as u64; - flags |= RafsV5InodeFlags::SYMLINK; + flags |= RafsInodeFlags::SYMLINK; ( Some(symlink_link_path.as_os_str().to_owned()), symlink_size as u16, @@ -299,7 +299,7 @@ impl<'a> TarballTreeBuilder<'a> { path.as_ref().display() ); } - flags |= RafsV5InodeFlags::HARDLINK; + flags |= RafsInodeFlags::HARDLINK; } else { self.path_inode_map .insert(path.as_ref().to_path_buf(), (ino, nodes.len())); @@ -328,30 +328,45 @@ impl<'a> TarballTreeBuilder<'a> { } } - let v5_inode = RafsV5Inode { - i_digest: RafsDigest::default(), - i_parent: 0, - i_ino: ino, - i_projid: 0, - i_uid: uid, - i_gid: gid, - i_mode: mode, - i_size: file_size, - i_nlink: 1, - i_blocks: 0, - i_flags: flags, - i_child_index: 0, - i_child_count: child_count as u32, - i_name_size: name.len() as u16, - i_symlink_size: symlink_size, - i_rdev: rdev, - i_mtime: mtime, - i_mtime_nsec: 0, - i_reserved: [0; 8], - }; let mut inode = match self.ctx.fs_version { - RafsVersion::V5 => InodeWrapper::V5(v5_inode), - RafsVersion::V6 => InodeWrapper::V6(v5_inode), + RafsVersion::V5 => InodeWrapper::V5(RafsV5Inode { + i_digest: RafsDigest::default(), + i_parent: 0, + i_ino: ino, + i_projid: 0, + i_uid: uid, + i_gid: gid, + i_mode: mode, + i_size: file_size, + i_nlink: 1, + i_blocks: 0, + i_flags: flags, + i_child_index: 0, + i_child_count: child_count as u32, + i_name_size: name.len() as u16, + i_symlink_size: symlink_size, + i_rdev: rdev, + i_mtime: mtime, + i_mtime_nsec: 0, + i_reserved: [0; 8], + }), + RafsVersion::V6 => InodeWrapper::V6(RafsV6Inode { + i_ino: ino, + i_projid: 0, + i_uid: uid, + i_gid: gid, + i_mode: mode, + i_size: file_size, + i_nlink: 1, + i_blocks: 0, + i_flags: flags, + i_child_count: child_count as u32, + i_name_size: name.len() as u16, + i_symlink_size: symlink_size, + i_rdev: rdev, + i_mtime: mtime, + i_mtime_nsec: 0, + }), }; inode.set_has_xattr(!xattrs.is_empty()); @@ -391,7 +406,9 @@ impl<'a> TarballTreeBuilder<'a> { // the associated regular file. if entry_type.is_hard_link() { let n = &nodes[index]; - node.inode.set_digest(*n.inode.digest()); + if n.inode.is_v5() { + node.inode.set_digest(*n.inode.digest()); + } node.inode.set_size(n.inode.size()); node.inode.set_child_count(n.inode.child_count()); node.chunks = n.chunks.clone(); diff --git a/rafs/src/metadata/cached_v5.rs b/rafs/src/metadata/cached_v5.rs index d63126ebcde..3c9e5e3b683 100644 --- a/rafs/src/metadata/cached_v5.rs +++ b/rafs/src/metadata/cached_v5.rs @@ -26,9 +26,10 @@ use nydus_storage::device::{BlobChunkFlags, BlobChunkInfo, BlobDevice, BlobInfo} use nydus_utils::digest::RafsDigest; use nydus_utils::ByteSize; +use crate::metadata::inode::RafsInodeFlags; use crate::metadata::layout::v5::{ rafsv5_alloc_bio_vecs, rafsv5_validate_inode, RafsV5BlobTable, RafsV5ChunkInfo, RafsV5Inode, - RafsV5InodeChunkOps, RafsV5InodeFlags, RafsV5InodeOps, RafsV5XAttrsTable, RAFSV5_ALIGNMENT, + RafsV5InodeChunkOps, RafsV5InodeOps, RafsV5XAttrsTable, RAFSV5_ALIGNMENT, }; use crate::metadata::layout::{bytes_to_os_str, parse_xattr, RAFS_V5_ROOT_INODE}; use crate::metadata::{ @@ -236,7 +237,7 @@ pub struct CachedInodeV5 { i_projid: u32, i_uid: u32, i_gid: u32, - i_flags: RafsV5InodeFlags, + i_flags: RafsInodeFlags, i_size: u64, i_blocks: u64, i_nlink: u32, @@ -481,7 +482,7 @@ impl RafsInode for CachedInodeV5 { #[inline] fn has_xattr(&self) -> bool { - self.i_flags.contains(RafsV5InodeFlags::XATTR) + self.i_flags.contains(RafsInodeFlags::XATTR) } #[inline] @@ -664,7 +665,7 @@ impl RafsV5InodeOps for CachedInodeV5 { } fn has_hole(&self) -> bool { - self.i_flags.contains(RafsV5InodeFlags::HAS_HOLE) + self.i_flags.contains(RafsInodeFlags::HAS_HOLE) } } diff --git a/rafs/src/metadata/inode.rs b/rafs/src/metadata/inode.rs index f19b935ed25..bd6cbc9df32 100644 --- a/rafs/src/metadata/inode.rs +++ b/rafs/src/metadata/inode.rs @@ -14,8 +14,8 @@ use crate::metadata::cached_v5::CachedInodeV5; use crate::metadata::chunk::ChunkWrapper; use crate::metadata::direct_v5::OndiskInodeWrapper as OndiskInodeWrapperV5; use crate::metadata::direct_v6::OndiskInodeWrapper as OndiskInodeWrapperV6; -use crate::metadata::layout::v5::{RafsV5ChunkInfo, RafsV5Inode, RafsV5InodeFlags}; -use crate::metadata::layout::v6::{RafsV6InodeCompact, RafsV6InodeExtended, RafsV6OndiskInode}; +use crate::metadata::layout::v5::{RafsV5ChunkInfo, RafsV5Inode}; +use crate::metadata::layout::v6::{RafsV6InodeCompact, RafsV6InodeExtended}; use crate::metadata::layout::RafsXAttrs; use crate::metadata::{Inode, RafsVersion}; use crate::RafsInodeExt; @@ -26,7 +26,7 @@ pub enum InodeWrapper { /// Inode info structure for RAFS v5. V5(RafsV5Inode), /// Inode info structure for RAFS v6, reuse `RafsV5Inode` as IR for v6. - V6(RafsV5Inode), + V6(RafsV6Inode), /// A reference to a `RafsInodeExt` object. Ref(Arc), } @@ -37,7 +37,7 @@ impl Debug for InodeWrapper { Self::V5(i) => write!(f, "{:?}", i), Self::V6(i) => write!(f, "{:?}", i), Self::Ref(i) => { - let i = to_rafsv5_inode(i.deref()); + let i = RafsV5Inode::from(i.deref()); write!(f, "{:?}", i) } } @@ -49,7 +49,7 @@ impl InodeWrapper { pub fn new(version: RafsVersion) -> Self { match version { RafsVersion::V5 => InodeWrapper::V5(RafsV5Inode::new()), - RafsVersion::V6 => InodeWrapper::V6(RafsV5Inode::new()), + RafsVersion::V6 => InodeWrapper::V6(RafsV6Inode::new()), } } @@ -79,8 +79,8 @@ impl InodeWrapper { /// Check whether is a RAFS V6 inode. pub fn is_v6(&self) -> bool { match self { - InodeWrapper::V5(_i) => true, - InodeWrapper::V6(_i) => false, + InodeWrapper::V5(_i) => false, + InodeWrapper::V6(_i) => true, InodeWrapper::Ref(inode) => inode .as_any() .downcast_ref::() @@ -92,7 +92,7 @@ impl InodeWrapper { pub fn inode_size(&self) -> usize { match self { InodeWrapper::V5(i) => i.size(), - _ => panic!("only available for RAFS v5 inode"), + _ => panic!("should only be called for RAFS v5 inode"), } } @@ -216,19 +216,19 @@ impl InodeWrapper { match self { InodeWrapper::V5(i) => { if enable { - i.i_flags |= RafsV5InodeFlags::XATTR; + i.i_flags |= RafsInodeFlags::XATTR; } else { - i.i_flags &= !RafsV5InodeFlags::XATTR; + i.i_flags &= !RafsInodeFlags::XATTR; } } InodeWrapper::V6(i) => { if enable { - i.i_flags |= RafsV5InodeFlags::XATTR; + i.i_flags |= RafsInodeFlags::XATTR; } else { - i.i_flags &= !RafsV5InodeFlags::XATTR; + i.i_flags &= !RafsInodeFlags::XATTR; } } - InodeWrapper::Ref(_i) => panic!("unexpected"), + InodeWrapper::Ref(_i) => unimplemented!(), } } @@ -251,21 +251,27 @@ impl InodeWrapper { } } - /// Get parent inode number. + /// Get parent inode number, only for RAFS v5. pub fn parent(&self) -> Inode { match self { InodeWrapper::V5(i) => i.i_parent, - InodeWrapper::V6(i) => i.i_parent, - InodeWrapper::Ref(i) => i.parent(), + InodeWrapper::V6(_i) => unimplemented!(), + InodeWrapper::Ref(i) => { + if self.is_v5() { + i.parent() + } else { + unimplemented!() + } + } } } - /// Set parent inode number. + /// Set parent inode number, only for RAFS v5. pub fn set_parent(&mut self, parent: Inode) { self.ensure_owned(); match self { InodeWrapper::V5(i) => i.i_parent = parent, - InodeWrapper::V6(i) => i.i_parent = parent, + InodeWrapper::V6(_i) => unimplemented!(), InodeWrapper::Ref(_i) => panic!("unexpected"), } } @@ -434,20 +440,18 @@ impl InodeWrapper { /// Get digest of inode metadata, RAFS v5 only. pub fn digest(&self) -> &RafsDigest { - match self { - InodeWrapper::V5(i) => &i.i_digest, - InodeWrapper::V6(i) => &i.i_digest, - InodeWrapper::Ref(_i) => unimplemented!(), + if let InodeWrapper::V5(i) = self { + &i.i_digest + } else { + unimplemented!() } } /// Set digest of inode metadata, RAFS v5 only. pub fn set_digest(&mut self, digest: RafsDigest) { self.ensure_owned(); - match self { - InodeWrapper::V5(i) => i.i_digest = digest, - InodeWrapper::V6(i) => i.i_digest = digest, - InodeWrapper::Ref(_i) => panic!("unexpected"), + if let InodeWrapper::V5(i) = self { + i.i_digest = digest; } } @@ -462,8 +466,8 @@ impl InodeWrapper { /// Set size of inode name. pub fn set_name_size(&mut self, size: usize) { - self.ensure_owned(); debug_assert!(size < u16::MAX as usize); + self.ensure_owned(); match self { InodeWrapper::V5(i) => i.i_name_size = size as u16, InodeWrapper::V6(i) => i.i_name_size = size as u16, @@ -486,33 +490,31 @@ impl InodeWrapper { self.ensure_owned(); match self { InodeWrapper::V5(i) => { - i.i_flags |= RafsV5InodeFlags::SYMLINK; + i.i_flags |= RafsInodeFlags::SYMLINK; i.i_symlink_size = size as u16; } InodeWrapper::V6(i) => { - i.i_flags |= RafsV5InodeFlags::SYMLINK; + i.i_flags |= RafsInodeFlags::SYMLINK; i.i_symlink_size = size as u16; } InodeWrapper::Ref(_i) => panic!("unexpected"), } } - /// Get child inode index. + /// Get child inode index, only valid for RAFS v5. pub fn child_index(&self) -> u32 { match self { InodeWrapper::V5(i) => i.i_child_index, - InodeWrapper::V6(i) => i.i_child_index, + InodeWrapper::V6(_i) => u32::MAX, InodeWrapper::Ref(_i) => unimplemented!(), } } - /// Set child inode index. + /// Set child inode index, only fro RAFS v5. pub fn set_child_index(&mut self, index: u32) { self.ensure_owned(); - match self { - InodeWrapper::V5(i) => i.i_child_index = index, - InodeWrapper::V6(i) => i.i_child_index = index, - InodeWrapper::Ref(_i) => panic!("unexpected"), + if let InodeWrapper::V5(i) = self { + i.i_child_index = index; } } @@ -546,85 +548,191 @@ impl InodeWrapper { /// Get memory/disk space occupied by the inode structure, including xattrs. pub fn get_inode_size_with_xattr(&self, xattrs: &RafsXAttrs, v6_compact: bool) -> usize { - match self { - InodeWrapper::V5(_i) => size_of::() + xattrs.aligned_size_v5(), - InodeWrapper::V6(_i) => { - let inode_size = if v6_compact { - size_of::() - } else { - size_of::() - }; - inode_size + xattrs.aligned_size_v6() - } - InodeWrapper::Ref(_i) => unimplemented!(), - } + assert!(matches!(self, InodeWrapper::V6(_))); + let inode_size = if v6_compact { + size_of::() + } else { + size_of::() + }; + inode_size + xattrs.aligned_size_v6() } fn ensure_owned(&mut self) { if let Self::Ref(i) = self { let i = i.clone(); if self.is_v6() { - *self = Self::V6(to_rafsv5_inode(i.deref().deref())); - } else if self.is_v5() { - *self = Self::V5(to_rafsv5_inode(i.deref().deref())); + *self = Self::V6(RafsV6Inode::from(i.deref().deref())); } else { - panic!("inode is neither v5 nor v6"); + assert!(self.is_v5()); + *self = Self::V5(RafsV5Inode::from(i.deref().deref())); } } } } -/// Construct a `RafsV5Inode` object from a `Arc` object. -fn to_rafsv5_inode(inode: &dyn RafsInodeExt) -> RafsV5Inode { - let attr = inode.get_attr(); - - RafsV5Inode { - i_digest: inode.get_digest(), - i_parent: inode.parent(), - i_ino: attr.ino, - i_uid: attr.uid, - i_gid: attr.gid, - i_projid: inode.projid(), - i_mode: attr.mode, - i_size: attr.size, - i_blocks: attr.blocks, - i_flags: RafsV5InodeFlags::from_bits_truncate(inode.flags()), - i_nlink: attr.nlink, - i_child_index: inode.get_child_index().unwrap_or(0), - i_child_count: inode.get_child_count(), - i_name_size: inode.get_name_size(), - i_symlink_size: inode.get_symlink_size(), - i_rdev: attr.rdev, - i_mtime_nsec: attr.mtimensec, - i_mtime: attr.mtime, - i_reserved: [0u8; 8], +#[derive(Clone, Copy, Default, Debug)] +pub struct RafsV6Inode { + /// Artifact inode number set by the nydus image builder. Start from RAFS_ROOT_INODE = 1. + pub i_ino: u64, + pub i_uid: u32, + pub i_gid: u32, + pub i_projid: u32, + pub i_mode: u32, // 64 + pub i_size: u64, + pub i_blocks: u64, + pub i_flags: RafsInodeFlags, + pub i_nlink: u32, + /// for dir, means child count. + /// for regular file, means chunk info count. + pub i_child_count: u32, + /// file name size, [char; i_name_size] + pub i_name_size: u16, + /// symlink path size, [char; i_symlink_size] + pub i_symlink_size: u16, // 104 + // inode device block number, ignored for non-special files + pub i_rdev: u32, + // for alignment reason, we put nsec first + pub i_mtime_nsec: u32, + pub i_mtime: u64, // 120 +} + +impl RafsV6Inode { + /// Create a new instance of `RafsV5Inode`. + pub fn new() -> Self { + Self::default() + } + + /// Set size of the file name. + #[inline] + pub fn set_name_size(&mut self, name_len: usize) { + self.i_name_size = name_len as u16; + } + + /// Mark the inode as a symlink. + #[inline] + pub fn set_symlink_size(&mut self, symlink_len: usize) { + self.i_symlink_size = symlink_len as u16; + } + + /// Get the uid and the gid of the inode. + #[inline] + pub fn uidgid(&self) -> (u32, u32) { + (self.i_uid, self.i_gid) + } + + /// Get the uid and the gid of the inode. + #[inline] + pub fn mtime(&self) -> (u64, u32) { + (self.i_mtime, self.i_mtime_nsec) + } + + /// Get the mode of the inode. + #[inline] + pub fn mode(&self) -> u32 { + self.i_mode + } + + /// Check whether the inode is a directory. + #[inline] + pub fn is_dir(&self) -> bool { + self.i_mode & libc::S_IFMT as u32 == libc::S_IFDIR as u32 + } + + /// Check whether the inode is a symlink. + #[inline] + pub fn is_symlink(&self) -> bool { + self.i_mode & libc::S_IFMT as u32 == libc::S_IFLNK as u32 + } + + /// Check whether the inode is a regular file. + #[inline] + pub fn is_reg(&self) -> bool { + self.i_mode & libc::S_IFMT as u32 == libc::S_IFREG as u32 + } + + /// Check whether the inode is a char device node. + pub fn is_chrdev(&self) -> bool { + self.i_mode & libc::S_IFMT as u32 == libc::S_IFCHR as u32 + } + + /// Check whether the inode is a block device node. + pub fn is_blkdev(&self) -> bool { + self.i_mode & libc::S_IFMT as u32 == libc::S_IFBLK as u32 + } + + /// Check whether the inode is a FIFO. + pub fn is_fifo(&self) -> bool { + self.i_mode & libc::S_IFMT as u32 == libc::S_IFIFO as u32 + } + + /// Check whether the inode is a socket. + pub fn is_sock(&self) -> bool { + self.i_mode & libc::S_IFMT as u32 == libc::S_IFSOCK as u32 + } + + /// Check whether the inode is a hardlink. + #[inline] + pub fn is_hardlink(&self) -> bool { + self.is_reg() && self.i_nlink > 1 + } + + /// Get inode flags + pub fn has_hardlink(&self) -> bool { + self.i_flags.contains(RafsInodeFlags::HARDLINK) + } + + /// Mark the inode as having extended attributes. + #[inline] + pub fn has_xattr(&self) -> bool { + self.i_flags.contains(RafsInodeFlags::XATTR) + } + + /// Mark the inode as having hole chunks. + #[inline] + pub fn has_hole(&self) -> bool { + self.i_flags.contains(RafsInodeFlags::HAS_HOLE) + } +} + +impl From<&dyn RafsInodeExt> for RafsV6Inode { + fn from(inode: &dyn RafsInodeExt) -> Self { + let attr = inode.get_attr(); + RafsV6Inode { + i_ino: attr.ino, + i_uid: attr.uid, + i_gid: attr.gid, + i_projid: inode.projid(), + i_mode: attr.mode, + i_size: attr.size, + i_blocks: attr.blocks, + i_flags: RafsInodeFlags::from_bits_truncate(inode.flags()), + i_nlink: attr.nlink, + i_child_count: inode.get_child_count(), + i_name_size: inode.get_name_size(), + i_symlink_size: inode.get_symlink_size(), + i_rdev: attr.rdev, + i_mtime_nsec: attr.mtimensec, + i_mtime: attr.mtime, + } } } -/// Create RAFS v6 on-disk inode object. -pub fn new_v6_inode( - inode: &InodeWrapper, - datalayout: u16, - xattr_inline_count: u16, - compact: bool, -) -> Box { - let mut i: Box = match compact { - true => Box::new(RafsV6InodeCompact::new()), - false => Box::new(RafsV6InodeExtended::new()), - }; - - assert!(inode.ino() <= i32::MAX as Inode); - i.set_ino(inode.ino() as u32); - i.set_size(inode.size()); - i.set_uidgid(inode.uid(), inode.gid()); - i.set_mtime(inode.mtime(), inode.mtime_nsec()); - i.set_nlink(inode.nlink()); - i.set_mode(inode.mode() as u16); - i.set_data_layout(datalayout); - i.set_xattr_inline_count(xattr_inline_count); - if inode.is_special() { - i.set_rdev(inode.rdev() as u32); - } - - i +bitflags! { + /// Rafs v5 inode flags. + pub struct RafsInodeFlags: u64 { + /// Inode is a symlink. + const SYMLINK = 0x0000_0001; + /// Inode has hardlinks. + const HARDLINK = 0x0000_0002; + /// Inode has extended attributes. + const XATTR = 0x0000_0004; + /// Inode chunks has holes. + const HAS_HOLE = 0x0000_0008; + } +} + +impl Default for RafsInodeFlags { + fn default() -> Self { + RafsInodeFlags::empty() + } } diff --git a/rafs/src/metadata/layout/v5.rs b/rafs/src/metadata/layout/v5.rs index 9a9d1ef047a..7167b64ae48 100644 --- a/rafs/src/metadata/layout/v5.rs +++ b/rafs/src/metadata/layout/v5.rs @@ -54,6 +54,7 @@ use nydus_storage::device::{ BlobChunkFlags, BlobChunkInfo, BlobFeatures, BlobInfo, BlobIoDesc, BlobIoVec, }; +use crate::metadata::inode::RafsInodeFlags; use crate::metadata::layout::{bytes_to_os_str, MetaRange, RafsXAttrs, RAFS_SUPER_VERSION_V5}; use crate::metadata::md_v5::V5IoChunk; use crate::metadata::{ @@ -860,26 +861,6 @@ impl RafsStore for RafsV5ExtBlobTable { } } -bitflags! { - /// Rafs v5 inode flags. - pub struct RafsV5InodeFlags: u64 { - /// Inode is a symlink. - const SYMLINK = 0x0000_0001; - /// Inode has hardlinks. - const HARDLINK = 0x0000_0002; - /// Inode has extended attributes. - const XATTR = 0x0000_0004; - /// Inode chunks has holes. - const HAS_HOLE = 0x0000_0008; - } -} - -impl Default for RafsV5InodeFlags { - fn default() -> Self { - RafsV5InodeFlags::empty() - } -} - /// Rafs v5 inode on disk metadata. #[repr(C)] #[derive(Clone, Copy, Default, Debug)] @@ -896,7 +877,7 @@ pub struct RafsV5Inode { pub i_mode: u32, // 64 pub i_size: u64, pub i_blocks: u64, - pub i_flags: RafsV5InodeFlags, + pub i_flags: RafsInodeFlags, pub i_nlink: u32, /// for dir, child start index pub i_child_index: u32, // 96 @@ -1005,19 +986,19 @@ impl RafsV5Inode { /// Get inode flags pub fn has_hardlink(&self) -> bool { - self.i_flags.contains(RafsV5InodeFlags::HARDLINK) + self.i_flags.contains(RafsInodeFlags::HARDLINK) } /// Mark the inode as having extended attributes. #[inline] pub fn has_xattr(&self) -> bool { - self.i_flags.contains(RafsV5InodeFlags::XATTR) + self.i_flags.contains(RafsInodeFlags::XATTR) } /// Mark the inode as having hole chunks. #[inline] pub fn has_hole(&self) -> bool { - self.i_flags.contains(RafsV5InodeFlags::HAS_HOLE) + self.i_flags.contains(RafsInodeFlags::HAS_HOLE) } /// Load an inode from a reader. @@ -1036,6 +1017,34 @@ impl RafsV5Inode { impl_bootstrap_converter!(RafsV5Inode); +impl From<&dyn RafsInodeExt> for RafsV5Inode { + fn from(inode: &dyn RafsInodeExt) -> Self { + let attr = inode.get_attr(); + + RafsV5Inode { + i_digest: inode.get_digest(), + i_parent: inode.parent(), + i_ino: attr.ino, + i_uid: attr.uid, + i_gid: attr.gid, + i_projid: inode.projid(), + i_mode: attr.mode, + i_size: attr.size, + i_blocks: attr.blocks, + i_flags: RafsInodeFlags::from_bits_truncate(inode.flags()), + i_nlink: attr.nlink, + i_child_index: inode.get_child_index().unwrap_or(0), + i_child_count: inode.get_child_count(), + i_name_size: inode.get_name_size(), + i_symlink_size: inode.get_symlink_size(), + i_rdev: attr.rdev, + i_mtime_nsec: attr.mtimensec, + i_mtime: attr.mtime, + i_reserved: [0u8; 8], + } + } +} + /// A in-memory wrapper of a Rafs v5 inode. pub struct RafsV5InodeWrapper<'a> { pub name: &'a OsStr, @@ -1881,7 +1890,7 @@ pub mod tests { inode.i_child_index = 20; inode.set_name_size(4); inode.set_symlink_size(6); - inode.i_flags = RafsV5InodeFlags::SYMLINK; + inode.i_flags = RafsInodeFlags::SYMLINK; let name = OsString::from_str("test").unwrap(); let symlink = OsString::from_str("/test12").unwrap(); diff --git a/rafs/src/metadata/layout/v6.rs b/rafs/src/metadata/layout/v6.rs index e2b54afaecd..777a8dee04f 100644 --- a/rafs/src/metadata/layout/v6.rs +++ b/rafs/src/metadata/layout/v6.rs @@ -21,9 +21,10 @@ use nydus_storage::meta::{ use nydus_storage::{RAFS_MAX_CHUNKS_PER_BLOB, RAFS_MAX_CHUNK_SIZE}; use nydus_utils::{compress, digest, round_up, ByteSize}; +use crate::metadata::inode::InodeWrapper; use crate::metadata::layout::v5::RafsV5ChunkInfo; use crate::metadata::layout::{MetaRange, RafsXAttrs}; -use crate::metadata::{RafsBlobExtraInfo, RafsStore, RafsSuperFlags, RafsSuperMeta}; +use crate::metadata::{Inode, RafsBlobExtraInfo, RafsStore, RafsSuperFlags, RafsSuperMeta}; use crate::{impl_bootstrap_converter, impl_pub_getter_setter, RafsIoReader, RafsIoWrite}; /// EROFS metadata slot size. @@ -1026,6 +1027,34 @@ impl RafsStore for RafsV6InodeExtended { } } +/// Create RAFS v6 on-disk inode object. +pub fn new_v6_inode( + inode: &InodeWrapper, + datalayout: u16, + xattr_inline_count: u16, + compact: bool, +) -> Box { + let mut i: Box = match compact { + true => Box::new(RafsV6InodeCompact::new()), + false => Box::new(RafsV6InodeExtended::new()), + }; + + assert!(inode.ino() <= i32::MAX as Inode); + i.set_ino(inode.ino() as u32); + i.set_size(inode.size()); + i.set_uidgid(inode.uid(), inode.gid()); + i.set_mtime(inode.mtime(), inode.mtime_nsec()); + i.set_nlink(inode.nlink()); + i.set_mode(inode.mode() as u16); + i.set_data_layout(datalayout); + i.set_xattr_inline_count(xattr_inline_count); + if inode.is_special() { + i.set_rdev(inode.rdev() as u32); + } + + i +} + /// Dirent sorted in alphabet order to improve performance by binary search. #[repr(C, packed(2))] #[derive(Default, Clone, Copy, Debug)] diff --git a/rafs/src/mock/mock_inode.rs b/rafs/src/mock/mock_inode.rs index 54accd2ea1a..6db91fb2d70 100644 --- a/rafs/src/mock/mock_inode.rs +++ b/rafs/src/mock/mock_inode.rs @@ -18,8 +18,9 @@ use nydus_utils::{digest::RafsDigest, ByteSize}; use super::mock_chunk::MockChunkInfo; use super::mock_super::CHUNK_SIZE; +use crate::metadata::inode::RafsInodeFlags; use crate::metadata::layout::v5::{ - rafsv5_alloc_bio_vecs, RafsV5BlobTable, RafsV5InodeChunkOps, RafsV5InodeFlags, RafsV5InodeOps, + rafsv5_alloc_bio_vecs, RafsV5BlobTable, RafsV5InodeChunkOps, RafsV5InodeOps, }; use crate::metadata::{ layout::{XattrName, XattrValue}, @@ -38,7 +39,7 @@ pub struct MockInode { i_projid: u32, i_uid: u32, i_gid: u32, - i_flags: RafsV5InodeFlags, + i_flags: RafsInodeFlags, i_size: u64, i_blocks: u64, i_nlink: u32, @@ -158,7 +159,7 @@ impl RafsInode for MockInode { } fn has_xattr(&self) -> bool { - self.i_flags.contains(RafsV5InodeFlags::XATTR) + self.i_flags.contains(RafsInodeFlags::XATTR) } #[inline]