Skip to main content

nydus_rafs/metadata/
inode.rs

1// Copyright 2020 Ant Group. All rights reserved.
2// Copyright (C) 2021-2022 Alibaba Cloud. All rights reserved.
3//
4// SPDX-License-Identifier: Apache-2.0
5
6use std::fmt::{Debug, Formatter};
7use std::mem::size_of;
8use std::ops::Deref;
9use std::sync::Arc;
10
11use nydus_utils::digest::RafsDigest;
12
13use crate::metadata::cached_v5::CachedInodeV5;
14use crate::metadata::chunk::ChunkWrapper;
15use crate::metadata::direct_v5::OndiskInodeWrapper as OndiskInodeWrapperV5;
16use crate::metadata::direct_v6::OndiskInodeWrapper as OndiskInodeWrapperV6;
17use crate::metadata::layout::v5::{RafsV5ChunkInfo, RafsV5Inode};
18use crate::metadata::layout::v6::{RafsV6InodeCompact, RafsV6InodeExtended};
19use crate::metadata::layout::RafsXAttrs;
20use crate::metadata::RafsVersion;
21use crate::RafsInodeExt;
22use nydus_utils::metrics::Inode;
23
24/// An inode object wrapper for different RAFS versions.
25#[derive(Clone)]
26pub enum InodeWrapper {
27    /// Inode info structure for RAFS v5.
28    V5(RafsV5Inode),
29    /// Inode info structure for RAFS v6, reuse `RafsV5Inode` as IR for v6.
30    V6(RafsV6Inode),
31    /// A reference to a `RafsInodeExt` object.
32    Ref(Arc<dyn RafsInodeExt>),
33}
34
35impl Debug for InodeWrapper {
36    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
37        match self {
38            Self::V5(i) => write!(f, "{:?}", i),
39            Self::V6(i) => write!(f, "{:?}", i),
40            Self::Ref(i) => {
41                let i = RafsV5Inode::from(i.deref());
42                write!(f, "{:?}", i)
43            }
44        }
45    }
46}
47
48impl InodeWrapper {
49    /// Create a new instance of `InodeWrapper` with default value.
50    pub fn new(version: RafsVersion) -> Self {
51        match version {
52            RafsVersion::V5 => InodeWrapper::V5(RafsV5Inode::new()),
53            RafsVersion::V6 => InodeWrapper::V6(RafsV6Inode::new()),
54        }
55    }
56
57    /// Create an `InodeWrapper` object from a `RafsInodeExt` trait object.
58    pub fn from_inode_info(inode: Arc<dyn RafsInodeExt>) -> Self {
59        Self::Ref(inode)
60    }
61
62    /// Check whether is a RAFS V5 inode.
63    pub fn is_v5(&self) -> bool {
64        match self {
65            InodeWrapper::V5(_i) => true,
66            InodeWrapper::V6(_i) => false,
67            InodeWrapper::Ref(inode) => {
68                if let Some(_inode) = inode.as_any().downcast_ref::<CachedInodeV5>() {
69                    true
70                } else {
71                    inode
72                        .as_any()
73                        .downcast_ref::<OndiskInodeWrapperV5>()
74                        .is_some()
75                }
76            }
77        }
78    }
79
80    /// Check whether is a RAFS V6 inode.
81    pub fn is_v6(&self) -> bool {
82        match self {
83            InodeWrapper::V5(_i) => false,
84            InodeWrapper::V6(_i) => true,
85            InodeWrapper::Ref(inode) => inode
86                .as_any()
87                .downcast_ref::<OndiskInodeWrapperV6>()
88                .is_some(),
89        }
90    }
91
92    /// Get file content size of the inode.
93    pub fn inode_size(&self) -> usize {
94        match self {
95            InodeWrapper::V5(i) => i.size(),
96            _ => panic!("should only be called for RAFS v5 inode"),
97        }
98    }
99
100    /// Get access permission/mode for the inode.
101    pub fn mode(&self) -> u32 {
102        match self {
103            InodeWrapper::V5(i) => i.mode(),
104            InodeWrapper::V6(i) => i.mode(),
105            InodeWrapper::Ref(i) => i.get_attr().mode,
106        }
107    }
108
109    /// Set access permission/mode for the inode.
110    pub fn set_mode(&mut self, mode: u32) {
111        self.ensure_owned();
112        match self {
113            InodeWrapper::V5(i) => i.i_mode = mode,
114            InodeWrapper::V6(i) => i.i_mode = mode,
115            InodeWrapper::Ref(_i) => panic!("unexpected"),
116        }
117    }
118
119    /// Check whether the inode is a directory.
120    pub fn is_dir(&self) -> bool {
121        match self {
122            InodeWrapper::V5(i) => i.is_dir(),
123            InodeWrapper::V6(i) => i.is_dir(),
124            InodeWrapper::Ref(i) => i.is_dir(),
125        }
126    }
127
128    /// Check whether the inode is a regular file.
129    pub fn is_reg(&self) -> bool {
130        match self {
131            InodeWrapper::V5(i) => i.is_reg(),
132            InodeWrapper::V6(i) => i.is_reg(),
133            InodeWrapper::Ref(i) => i.is_reg(),
134        }
135    }
136
137    /// Check whether the inode is a hardlink.
138    pub fn is_hardlink(&self) -> bool {
139        match self {
140            InodeWrapper::V5(i) => i.is_hardlink(),
141            InodeWrapper::V6(i) => i.is_hardlink(),
142            InodeWrapper::Ref(i) => i.is_hardlink(),
143        }
144    }
145
146    /// Check whether the inode is a symlink.
147    pub fn is_symlink(&self) -> bool {
148        match self {
149            InodeWrapper::V5(i) => i.is_symlink(),
150            InodeWrapper::V6(i) => i.is_symlink(),
151            InodeWrapper::Ref(i) => i.is_symlink(),
152        }
153    }
154
155    /// Check whether the inode is a char device node.
156    pub fn is_chrdev(&self) -> bool {
157        match self {
158            InodeWrapper::V5(i) => i.is_chrdev(),
159            InodeWrapper::V6(i) => i.is_chrdev(),
160            InodeWrapper::Ref(i) => i.as_inode().is_chrdev(),
161        }
162    }
163
164    /// Check whether the inode is a block device node.
165    pub fn is_blkdev(&self) -> bool {
166        match self {
167            InodeWrapper::V5(i) => i.is_blkdev(),
168            InodeWrapper::V6(i) => i.is_blkdev(),
169            InodeWrapper::Ref(_i) => unimplemented!(),
170        }
171    }
172
173    /// Check whether the inode is a FIFO.
174    pub fn is_fifo(&self) -> bool {
175        match self {
176            InodeWrapper::V5(i) => i.is_fifo(),
177            InodeWrapper::V6(i) => i.is_fifo(),
178            InodeWrapper::Ref(_i) => unimplemented!(),
179        }
180    }
181
182    /// Check whether the inode is a socket.
183    pub fn is_sock(&self) -> bool {
184        match self {
185            InodeWrapper::V5(i) => i.is_sock(),
186            InodeWrapper::V6(i) => i.is_sock(),
187            InodeWrapper::Ref(i) => i.as_inode().is_sock(),
188        }
189    }
190
191    /// Check whether the inode is a special file, such chardev, blkdev, FIFO and socket.
192    pub fn is_special(&self) -> bool {
193        self.is_chrdev() || self.is_blkdev() || self.is_fifo() || self.is_sock()
194    }
195
196    /// Get inode flags.
197    pub fn has_hardlink(&self) -> bool {
198        match self {
199            InodeWrapper::V5(i) => i.has_hardlink(),
200            InodeWrapper::V6(i) => i.has_hardlink(),
201            InodeWrapper::Ref(_i) => unimplemented!(),
202        }
203    }
204
205    /// Set whether the inode has HARDLINK flag set.
206    pub fn set_has_hardlink(&mut self, enable: bool) {
207        self.ensure_owned();
208        match self {
209            InodeWrapper::V5(i) => {
210                if enable {
211                    i.i_flags |= RafsInodeFlags::HARDLINK;
212                } else {
213                    i.i_flags &= !RafsInodeFlags::HARDLINK;
214                }
215            }
216            InodeWrapper::V6(i) => {
217                if enable {
218                    i.i_flags |= RafsInodeFlags::HARDLINK;
219                } else {
220                    i.i_flags &= !RafsInodeFlags::HARDLINK;
221                }
222            }
223            InodeWrapper::Ref(_i) => unimplemented!(),
224        }
225    }
226
227    /// Check whether the inode has associated xattrs.
228    pub fn has_xattr(&self) -> bool {
229        match self {
230            InodeWrapper::V5(i) => i.has_xattr(),
231            InodeWrapper::V6(i) => i.has_xattr(),
232            InodeWrapper::Ref(i) => i.has_xattr(),
233        }
234    }
235
236    /// Set whether the inode has associated xattrs.
237    pub fn set_has_xattr(&mut self, enable: bool) {
238        self.ensure_owned();
239        match self {
240            InodeWrapper::V5(i) => {
241                if enable {
242                    i.i_flags |= RafsInodeFlags::XATTR;
243                } else {
244                    i.i_flags &= !RafsInodeFlags::XATTR;
245                }
246            }
247            InodeWrapper::V6(i) => {
248                if enable {
249                    i.i_flags |= RafsInodeFlags::XATTR;
250                } else {
251                    i.i_flags &= !RafsInodeFlags::XATTR;
252                }
253            }
254            InodeWrapper::Ref(_i) => unimplemented!(),
255        }
256    }
257
258    /// Get inode number.
259    pub fn ino(&self) -> Inode {
260        match self {
261            InodeWrapper::V5(i) => i.i_ino,
262            InodeWrapper::V6(i) => i.i_ino,
263            InodeWrapper::Ref(i) => i.ino(),
264        }
265    }
266
267    /// Set inode number.
268    pub fn set_ino(&mut self, ino: Inode) {
269        self.ensure_owned();
270        match self {
271            InodeWrapper::V5(i) => i.i_ino = ino,
272            InodeWrapper::V6(i) => i.i_ino = ino,
273            InodeWrapper::Ref(_i) => panic!("unexpected"),
274        }
275    }
276
277    /// Get parent inode number, only for RAFS v5.
278    pub fn parent(&self) -> Inode {
279        match self {
280            InodeWrapper::V5(i) => i.i_parent,
281            InodeWrapper::V6(_i) => unimplemented!(),
282            InodeWrapper::Ref(i) => {
283                if self.is_v5() {
284                    i.parent()
285                } else {
286                    unimplemented!()
287                }
288            }
289        }
290    }
291
292    /// Set parent inode number, only for RAFS v5.
293    pub fn set_parent(&mut self, parent: Inode) {
294        self.ensure_owned();
295        match self {
296            InodeWrapper::V5(i) => i.i_parent = parent,
297            InodeWrapper::V6(_i) => unimplemented!(),
298            InodeWrapper::Ref(_i) => panic!("unexpected"),
299        }
300    }
301
302    /// Get inode content size of regular file, directory and symlink.
303    pub fn size(&self) -> u64 {
304        match self {
305            InodeWrapper::V5(i) => i.i_size,
306            InodeWrapper::V6(i) => i.i_size,
307            InodeWrapper::Ref(i) => i.size(),
308        }
309    }
310
311    /// Set inode content size.
312    pub fn set_size(&mut self, size: u64) {
313        self.ensure_owned();
314        match self {
315            InodeWrapper::V5(i) => i.i_size = size,
316            InodeWrapper::V6(i) => i.i_size = size,
317            InodeWrapper::Ref(_i) => panic!("unexpected"),
318        }
319    }
320
321    /// Get user id associated with the inode.
322    pub fn uid(&self) -> u32 {
323        match self {
324            InodeWrapper::V5(i) => i.i_uid,
325            InodeWrapper::V6(i) => i.i_uid,
326            InodeWrapper::Ref(i) => i.as_inode().get_attr().uid,
327        }
328    }
329
330    /// Set user id associated with the inode.
331    pub fn set_uid(&mut self, uid: u32) {
332        self.ensure_owned();
333        match self {
334            InodeWrapper::V5(i) => i.i_uid = uid,
335            InodeWrapper::V6(i) => i.i_uid = uid,
336            InodeWrapper::Ref(_i) => panic!("unexpected"),
337        }
338    }
339
340    /// Get group id associated with the inode.
341    pub fn gid(&self) -> u32 {
342        match self {
343            InodeWrapper::V5(i) => i.i_gid,
344            InodeWrapper::V6(i) => i.i_gid,
345            InodeWrapper::Ref(i) => i.as_inode().get_attr().gid,
346        }
347    }
348
349    /// Set group id associated with the inode.
350    pub fn set_gid(&mut self, gid: u32) {
351        self.ensure_owned();
352        match self {
353            InodeWrapper::V5(i) => i.i_gid = gid,
354            InodeWrapper::V6(i) => i.i_gid = gid,
355            InodeWrapper::Ref(_i) => panic!("unexpected"),
356        }
357    }
358
359    /// Get modified time.
360    pub fn mtime(&self) -> u64 {
361        match self {
362            InodeWrapper::V5(i) => i.i_mtime,
363            InodeWrapper::V6(i) => i.i_mtime,
364            InodeWrapper::Ref(i) => i.get_attr().mtime,
365        }
366    }
367
368    /// Set modified time.
369    pub fn set_mtime(&mut self, mtime: u64) {
370        self.ensure_owned();
371        match self {
372            InodeWrapper::V5(i) => i.i_mtime = mtime,
373            InodeWrapper::V6(i) => i.i_mtime = mtime,
374            InodeWrapper::Ref(_i) => panic!("unexpected"),
375        }
376    }
377
378    /// Get nsec part of modified time.
379    pub fn mtime_nsec(&self) -> u32 {
380        match self {
381            InodeWrapper::V5(i) => i.i_mtime_nsec,
382            InodeWrapper::V6(i) => i.i_mtime_nsec,
383            InodeWrapper::Ref(i) => i.get_attr().mtimensec,
384        }
385    }
386
387    /// Set nsec part of modified time.
388    pub fn set_mtime_nsec(&mut self, mtime_nsec: u32) {
389        self.ensure_owned();
390        match self {
391            InodeWrapper::V5(i) => i.i_mtime_nsec = mtime_nsec,
392            InodeWrapper::V6(i) => i.i_mtime_nsec = mtime_nsec,
393            InodeWrapper::Ref(_i) => panic!("unexpected"),
394        }
395    }
396
397    /// Get data blocks of file content, in unit of 512 bytes.
398    pub fn blocks(&self) -> u64 {
399        match self {
400            InodeWrapper::V5(i) => i.i_blocks,
401            InodeWrapper::V6(i) => i.i_blocks,
402            InodeWrapper::Ref(i) => i.get_attr().blocks,
403        }
404    }
405
406    /// Set data blocks of file content, in unit of 512 bytes.
407    pub fn set_blocks(&mut self, blocks: u64) {
408        self.ensure_owned();
409        match self {
410            InodeWrapper::V5(i) => i.i_blocks = blocks,
411            InodeWrapper::V6(i) => i.i_blocks = blocks,
412            InodeWrapper::Ref(_i) => panic!("unexpected"),
413        }
414    }
415
416    /// Get real device id associated with the inode.
417    pub fn rdev(&self) -> u32 {
418        match self {
419            InodeWrapper::V5(i) => i.i_rdev,
420            InodeWrapper::V6(i) => i.i_rdev,
421            InodeWrapper::Ref(i) => i.rdev(),
422        }
423    }
424
425    /// Set real device id associated with the inode.
426    pub fn set_rdev(&mut self, rdev: u32) {
427        self.ensure_owned();
428        match self {
429            InodeWrapper::V5(i) => i.i_rdev = rdev,
430            InodeWrapper::V6(i) => i.i_rdev = rdev,
431            InodeWrapper::Ref(_i) => panic!("unexpected"),
432        }
433    }
434
435    /// Set project ID associated with the inode.
436    pub fn set_projid(&mut self, projid: u32) {
437        self.ensure_owned();
438        match self {
439            InodeWrapper::V5(i) => i.i_projid = projid,
440            InodeWrapper::V6(i) => i.i_projid = projid,
441            InodeWrapper::Ref(_i) => panic!("unexpected"),
442        }
443    }
444
445    /// Get number of hardlinks.
446    pub fn nlink(&self) -> u32 {
447        match self {
448            InodeWrapper::V5(i) => i.i_nlink,
449            InodeWrapper::V6(i) => i.i_nlink,
450            InodeWrapper::Ref(i) => i.get_attr().nlink,
451        }
452    }
453
454    /// Set number of hardlinks.
455    pub fn set_nlink(&mut self, nlink: u32) {
456        self.ensure_owned();
457        match self {
458            InodeWrapper::V5(i) => i.i_nlink = nlink,
459            InodeWrapper::V6(i) => i.i_nlink = nlink,
460            InodeWrapper::Ref(_i) => panic!("unexpected"),
461        }
462    }
463
464    /// Get digest of inode metadata, RAFS v5 only.
465    pub fn digest(&self) -> &RafsDigest {
466        if let InodeWrapper::V5(i) = self {
467            &i.i_digest
468        } else {
469            unimplemented!()
470        }
471    }
472
473    /// Set digest of inode metadata, RAFS v5 only.
474    pub fn set_digest(&mut self, digest: RafsDigest) {
475        self.ensure_owned();
476        if let InodeWrapper::V5(i) = self {
477            i.i_digest = digest;
478        }
479    }
480
481    /// Get size of inode name.
482    pub fn name_size(&self) -> u16 {
483        match self {
484            InodeWrapper::V5(i) => i.i_name_size,
485            InodeWrapper::V6(i) => i.i_name_size,
486            InodeWrapper::Ref(i) => i.get_name_size(),
487        }
488    }
489
490    /// Set size of inode name.
491    pub fn set_name_size(&mut self, size: usize) {
492        debug_assert!(size < u16::MAX as usize);
493        self.ensure_owned();
494        match self {
495            InodeWrapper::V5(i) => i.i_name_size = size as u16,
496            InodeWrapper::V6(i) => i.i_name_size = size as u16,
497            InodeWrapper::Ref(_i) => panic!("unexpected"),
498        }
499    }
500
501    /// Get size of symlink.
502    pub fn symlink_size(&self) -> u16 {
503        match self {
504            InodeWrapper::V5(i) => i.i_symlink_size,
505            InodeWrapper::V6(i) => i.i_symlink_size,
506            InodeWrapper::Ref(i) => i.get_symlink_size(),
507        }
508    }
509
510    /// Set size of symlink.
511    pub fn set_symlink_size(&mut self, size: usize) {
512        debug_assert!(size <= u16::MAX as usize);
513        self.ensure_owned();
514        match self {
515            InodeWrapper::V5(i) => {
516                i.i_flags |= RafsInodeFlags::SYMLINK;
517                i.i_symlink_size = size as u16;
518            }
519            InodeWrapper::V6(i) => {
520                i.i_flags |= RafsInodeFlags::SYMLINK;
521                i.i_symlink_size = size as u16;
522            }
523            InodeWrapper::Ref(_i) => panic!("unexpected"),
524        }
525    }
526
527    /// Get child inode index, only valid for RAFS v5.
528    pub fn child_index(&self) -> u32 {
529        match self {
530            InodeWrapper::V5(i) => i.i_child_index,
531            InodeWrapper::V6(_i) => u32::MAX,
532            InodeWrapper::Ref(i) => i.get_child_index().unwrap_or(u32::MAX),
533        }
534    }
535
536    /// Set child inode index, only fro RAFS v5.
537    pub fn set_child_index(&mut self, index: u32) {
538        self.ensure_owned();
539        if let InodeWrapper::V5(i) = self {
540            i.i_child_index = index;
541        }
542    }
543
544    /// Get child/chunk count.
545    pub fn child_count(&self) -> u32 {
546        match self {
547            InodeWrapper::V5(i) => i.i_child_count,
548            InodeWrapper::V6(i) => i.i_child_count,
549            InodeWrapper::Ref(i) => i.get_child_count(),
550        }
551    }
552
553    /// Set child/chunk count.
554    pub fn set_child_count(&mut self, count: u32) {
555        self.ensure_owned();
556        match self {
557            InodeWrapper::V5(i) => i.i_child_count = count,
558            InodeWrapper::V6(i) => i.i_child_count = count,
559            InodeWrapper::Ref(_i) => panic!("unexpected"),
560        }
561    }
562
563    /// Create a `ChunkWrapper` object to be associated with the inode.
564    pub fn create_chunk(&self) -> ChunkWrapper {
565        match self {
566            InodeWrapper::V5(_) => ChunkWrapper::V5(RafsV5ChunkInfo::new()),
567            InodeWrapper::V6(_) => ChunkWrapper::V6(RafsV5ChunkInfo::new()),
568            InodeWrapper::Ref(_i) => unimplemented!(),
569        }
570    }
571
572    /// Get memory/disk space occupied by the inode structure, including xattrs.
573    pub fn get_inode_size_with_xattr(&self, xattrs: &RafsXAttrs, v6_compact: bool) -> usize {
574        assert!(matches!(self, InodeWrapper::V6(_)));
575        let inode_size = if v6_compact {
576            size_of::<RafsV6InodeCompact>()
577        } else {
578            size_of::<RafsV6InodeExtended>()
579        };
580        inode_size + xattrs.aligned_size_v6()
581    }
582
583    fn ensure_owned(&mut self) {
584        if let Self::Ref(i) = self {
585            let i = i.clone();
586            if self.is_v6() {
587                *self = Self::V6(RafsV6Inode::from(i.deref()));
588            } else {
589                assert!(self.is_v5());
590                *self = Self::V5(RafsV5Inode::from(i.deref()));
591            }
592        }
593    }
594}
595
596#[derive(Clone, Copy, Default, Debug)]
597pub struct RafsV6Inode {
598    /// Artifact inode number set by the nydus image builder. Start from RAFS_ROOT_INODE = 1.
599    pub i_ino: u64,
600    pub i_uid: u32,
601    pub i_gid: u32,
602    pub i_projid: u32,
603    pub i_mode: u32, // 64
604    pub i_size: u64,
605    pub i_blocks: u64,
606    pub i_flags: RafsInodeFlags,
607    pub i_nlink: u32,
608    /// for dir, means child count.
609    /// for regular file, means chunk info count.
610    pub i_child_count: u32,
611    /// file name size, [char; i_name_size]
612    pub i_name_size: u16,
613    /// symlink path size, [char; i_symlink_size]
614    pub i_symlink_size: u16, // 104
615    // inode device block number, ignored for non-special files
616    pub i_rdev: u32,
617    // for alignment reason, we put nsec first
618    pub i_mtime_nsec: u32,
619    pub i_mtime: u64, // 120
620}
621
622impl RafsV6Inode {
623    /// Create a new instance of `RafsV5Inode`.
624    pub fn new() -> Self {
625        Self::default()
626    }
627
628    /// Set size of the file name.
629    #[inline]
630    pub fn set_name_size(&mut self, name_len: usize) {
631        self.i_name_size = name_len as u16;
632    }
633
634    /// Mark the inode as a symlink.
635    #[inline]
636    pub fn set_symlink_size(&mut self, symlink_len: usize) {
637        self.i_symlink_size = symlink_len as u16;
638    }
639
640    /// Get the uid and the gid of the inode.
641    #[inline]
642    pub fn uidgid(&self) -> (u32, u32) {
643        (self.i_uid, self.i_gid)
644    }
645
646    /// Get the uid and the gid of the inode.
647    #[inline]
648    pub fn mtime(&self) -> (u64, u32) {
649        (self.i_mtime, self.i_mtime_nsec)
650    }
651
652    /// Get the mode of the inode.
653    #[inline]
654    pub fn mode(&self) -> u32 {
655        self.i_mode
656    }
657
658    /// Check whether the inode is a directory.
659    #[inline]
660    pub fn is_dir(&self) -> bool {
661        self.i_mode & libc::S_IFMT as u32 == libc::S_IFDIR as u32
662    }
663
664    /// Check whether the inode is a symlink.
665    #[inline]
666    pub fn is_symlink(&self) -> bool {
667        self.i_mode & libc::S_IFMT as u32 == libc::S_IFLNK as u32
668    }
669
670    /// Check whether the inode is a regular file.
671    #[inline]
672    pub fn is_reg(&self) -> bool {
673        self.i_mode & libc::S_IFMT as u32 == libc::S_IFREG as u32
674    }
675
676    /// Check whether the inode is a char device node.
677    pub fn is_chrdev(&self) -> bool {
678        self.i_mode & libc::S_IFMT as u32 == libc::S_IFCHR as u32
679    }
680
681    /// Check whether the inode is a block device node.
682    pub fn is_blkdev(&self) -> bool {
683        self.i_mode & libc::S_IFMT as u32 == libc::S_IFBLK as u32
684    }
685
686    /// Check whether the inode is a FIFO.
687    pub fn is_fifo(&self) -> bool {
688        self.i_mode & libc::S_IFMT as u32 == libc::S_IFIFO as u32
689    }
690
691    /// Check whether the inode is a socket.
692    pub fn is_sock(&self) -> bool {
693        self.i_mode & libc::S_IFMT as u32 == libc::S_IFSOCK as u32
694    }
695
696    /// Check whether the inode is a hardlink.
697    #[inline]
698    pub fn is_hardlink(&self) -> bool {
699        self.is_reg() && self.i_nlink > 1
700    }
701
702    /// Get inode flags
703    pub fn has_hardlink(&self) -> bool {
704        self.i_flags.contains(RafsInodeFlags::HARDLINK)
705    }
706
707    /// Mark the inode as having extended attributes.
708    #[inline]
709    pub fn has_xattr(&self) -> bool {
710        self.i_flags.contains(RafsInodeFlags::XATTR)
711    }
712
713    /// Mark the inode as having hole chunks.
714    #[inline]
715    pub fn has_hole(&self) -> bool {
716        self.i_flags.contains(RafsInodeFlags::HAS_HOLE)
717    }
718}
719
720impl From<&dyn RafsInodeExt> for RafsV6Inode {
721    fn from(inode: &dyn RafsInodeExt) -> Self {
722        let attr = inode.get_attr();
723        RafsV6Inode {
724            i_ino: attr.ino,
725            i_uid: attr.uid,
726            i_gid: attr.gid,
727            i_projid: inode.projid(),
728            i_mode: attr.mode,
729            i_size: attr.size,
730            i_blocks: attr.blocks,
731            i_flags: RafsInodeFlags::from_bits_truncate(inode.flags()),
732            i_nlink: attr.nlink,
733            i_child_count: inode.get_child_count(),
734            i_name_size: inode.get_name_size(),
735            i_symlink_size: inode.get_symlink_size(),
736            i_rdev: attr.rdev,
737            i_mtime_nsec: attr.mtimensec,
738            i_mtime: attr.mtime,
739        }
740    }
741}
742
743bitflags! {
744    /// Rafs v5 inode flags.
745    pub struct RafsInodeFlags: u64 {
746        /// Inode is a symlink.
747        const SYMLINK = 0x0000_0001;
748        /// Inode has hardlinks.
749        const HARDLINK = 0x0000_0002;
750        /// Inode has extended attributes.
751        const XATTR = 0x0000_0004;
752        /// Inode chunks has holes.
753        const HAS_HOLE = 0x0000_0008;
754   }
755}
756
757impl Default for RafsInodeFlags {
758    fn default() -> Self {
759        RafsInodeFlags::empty()
760    }
761}
762
763#[cfg(test)]
764mod tests {
765    use super::*;
766    use crate::{
767        metadata::{direct_v5::DirectSuperBlockV5, RafsSuperMeta},
768        mock::MockInode,
769    };
770
771    #[test]
772    fn test_inode_wrapper() {
773        let mut wrapper_v5 = InodeWrapper::new(RafsVersion::V5);
774        let mut wrapper_v6 = InodeWrapper::new(RafsVersion::V6);
775        let mut wrapper_cache_v5 =
776            InodeWrapper::from_inode_info(Arc::new(CachedInodeV5::default()));
777        let wrapper_ondisk_v5 = InodeWrapper::from_inode_info(Arc::new(OndiskInodeWrapperV5 {
778            mapping: DirectSuperBlockV5::new(&RafsSuperMeta::default(), false),
779            offset: 0,
780        }));
781
782        assert!(wrapper_v5.is_v5());
783        assert!(!wrapper_v6.is_v5());
784        assert!(wrapper_cache_v5.is_v5());
785        assert!(wrapper_ondisk_v5.is_v5());
786        assert!(!wrapper_v5.is_v6());
787        assert!(wrapper_v6.is_v6());
788        assert!(!wrapper_cache_v5.is_v6());
789        assert!(!wrapper_ondisk_v5.is_v6());
790        assert_eq!(wrapper_v5.inode_size(), 128);
791
792        wrapper_v5.set_mode(0x0000_0001);
793        wrapper_v6.set_mode(0x0000_0002);
794        assert_eq!(wrapper_v5.mode(), 0x0000_0001);
795        assert_eq!(wrapper_v6.mode(), 0x0000_0002);
796
797        assert!(!wrapper_v5.is_hardlink());
798        assert!(!wrapper_v6.is_hardlink());
799        assert!(!wrapper_cache_v5.is_hardlink());
800        assert!(!wrapper_v5.is_symlink());
801        assert!(!wrapper_v6.is_symlink());
802        assert!(!wrapper_cache_v5.is_symlink());
803        assert!(!wrapper_v5.is_chrdev());
804        assert!(!wrapper_v6.is_chrdev());
805        assert!(!wrapper_cache_v5.is_chrdev());
806        assert!(!wrapper_v5.is_blkdev());
807        assert!(!wrapper_v6.is_blkdev());
808        assert!(!wrapper_v5.is_fifo());
809        assert!(!wrapper_v6.is_fifo());
810        assert!(!wrapper_v5.is_sock());
811        assert!(!wrapper_v6.is_sock());
812        assert!(!wrapper_cache_v5.is_sock());
813        assert!(!wrapper_v5.has_hardlink());
814        assert!(!wrapper_v6.has_hardlink());
815        wrapper_v5.set_has_hardlink(true);
816        wrapper_v6.set_has_hardlink(true);
817        assert!(wrapper_v5.has_hardlink());
818        assert!(wrapper_v6.has_hardlink());
819        wrapper_v5.set_has_hardlink(false);
820        wrapper_v6.set_has_hardlink(false);
821        assert!(!wrapper_v5.has_hardlink());
822        assert!(!wrapper_v6.has_hardlink());
823        assert!(!wrapper_v5.has_xattr());
824        assert!(!wrapper_v6.has_xattr());
825        assert!(!wrapper_cache_v5.has_xattr());
826        wrapper_v5.set_has_xattr(true);
827        wrapper_v6.set_has_xattr(true);
828        assert!(wrapper_v5.has_xattr());
829        assert!(wrapper_v6.has_xattr());
830        wrapper_v5.set_has_xattr(false);
831        wrapper_v6.set_has_xattr(false);
832        assert!(!wrapper_v5.has_xattr());
833        assert!(!wrapper_v6.has_xattr());
834        wrapper_v5.set_ino(0x0000_0001);
835        wrapper_v6.set_ino(0x0000_0002);
836        assert_eq!(wrapper_v5.ino(), 0x0000_0001);
837        assert_eq!(wrapper_v6.ino(), 0x0000_0002);
838        wrapper_v5.set_parent(0x0000_0004);
839        assert_eq!(wrapper_v5.parent(), 0x0000_0004);
840        assert_eq!(wrapper_cache_v5.size(), 0);
841        wrapper_v5.set_uid(0x0000_0001);
842        wrapper_v6.set_uid(0x0000_0002);
843        assert_eq!(wrapper_v5.uid(), 0x0000_0001);
844        assert_eq!(wrapper_v6.uid(), 0x0000_0002);
845        wrapper_v5.set_gid(0x0000_0001);
846        wrapper_v6.set_gid(0x0000_0002);
847        assert_eq!(wrapper_v5.gid(), 0x0000_0001);
848        assert_eq!(wrapper_v6.gid(), 0x0000_0002);
849        wrapper_v5.set_mtime(0x0000_0004);
850        wrapper_v6.set_mtime(0x0000_0008);
851        assert_eq!(wrapper_v5.mtime(), 0x0000_0004);
852        assert_eq!(wrapper_v6.mtime(), 0x0000_0008);
853        assert_eq!(wrapper_cache_v5.mtime(), 0x0000_0000);
854        wrapper_v5.set_mtime_nsec(0x0000_0004);
855        wrapper_v6.set_mtime_nsec(0x0000_0008);
856        assert_eq!(wrapper_v5.mtime_nsec(), 0x0000_0004);
857        assert_eq!(wrapper_v6.mtime_nsec(), 0x0000_0008);
858        assert_eq!(wrapper_cache_v5.mtime_nsec(), 0x0000_0000);
859        wrapper_v5.set_blocks(0x0000_0010);
860        wrapper_v6.set_blocks(0x0000_0020);
861        assert_eq!(wrapper_v5.blocks(), 0x0000_0010);
862        assert_eq!(wrapper_v6.blocks(), 0x0000_0020);
863        assert_eq!(wrapper_cache_v5.blocks(), 0x0000_0000);
864        wrapper_v5.set_rdev(0x0000_0010);
865        wrapper_v6.set_rdev(0x0000_0020);
866        assert_eq!(wrapper_v5.rdev(), 0x0000_0010);
867        assert_eq!(wrapper_v6.rdev(), 0x0000_0020);
868        assert_eq!(wrapper_cache_v5.rdev(), 0x0000_0000);
869        wrapper_v5.set_projid(0x0000_0100);
870        wrapper_v6.set_projid(0x0000_0200);
871        wrapper_v5.set_nlink(0x0000_0010);
872        wrapper_v6.set_nlink(0x0000_0020);
873        assert_eq!(wrapper_v5.nlink(), 0x0000_0010);
874        assert_eq!(wrapper_v6.nlink(), 0x0000_0020);
875        assert_eq!(wrapper_cache_v5.nlink(), 0x0000_0000);
876        wrapper_v5.set_name_size(0x0000_0010);
877        wrapper_v6.set_name_size(0x0000_0020);
878        assert_eq!(wrapper_v5.name_size(), 0x0000_0010);
879        assert_eq!(wrapper_v6.name_size(), 0x0000_0020);
880        assert_eq!(wrapper_cache_v5.name_size(), 0x0000_0000);
881        wrapper_v5.set_symlink_size(0x0000_0010);
882        wrapper_v6.set_symlink_size(0x0000_0020);
883        assert_eq!(wrapper_v5.symlink_size(), 0x0000_0010);
884        assert_eq!(wrapper_v6.symlink_size(), 0x0000_0020);
885        assert_eq!(wrapper_cache_v5.symlink_size(), 0x0000_0000);
886        wrapper_v5.set_child_index(0x0000_0010);
887        wrapper_v6.set_child_index(0x0000_0020);
888        wrapper_cache_v5.set_child_index(0x0000_0008);
889        assert_eq!(wrapper_v5.child_index(), 0x0000_0010);
890        assert_eq!(wrapper_v6.child_index(), u32::MAX);
891        assert_eq!(wrapper_cache_v5.child_index(), 0x0000_0008);
892        wrapper_v5.set_child_count(0x0000_0010);
893        wrapper_v6.set_child_count(0x0000_0020);
894        assert_eq!(wrapper_v5.child_count(), 0x0000_0010);
895        assert_eq!(wrapper_v6.child_count(), 0x0000_0020);
896        assert_eq!(wrapper_cache_v5.child_count(), 0x0000_0000);
897        wrapper_v5.create_chunk();
898        wrapper_v6.create_chunk();
899    }
900
901    #[test]
902    #[should_panic]
903    fn test_inode_size_v6() {
904        let wrapper_v6 = InodeWrapper::new(RafsVersion::V6);
905        wrapper_v6.inode_size();
906    }
907
908    #[test]
909    #[should_panic]
910    fn test_inode_size_ref() {
911        let wrapper_cache_v5 = InodeWrapper::from_inode_info(Arc::new(CachedInodeV5::default()));
912        wrapper_cache_v5.inode_size();
913    }
914
915    #[test]
916    #[should_panic]
917    fn test_set_mode_ref() {
918        let mut wrapper_mock = InodeWrapper::from_inode_info(Arc::new(MockInode::default()));
919        wrapper_mock.set_mode(0x0000_0001);
920    }
921
922    #[test]
923    #[should_panic]
924    fn test_is_blk_dev_ref() {
925        let wrapper_mock = InodeWrapper::from_inode_info(Arc::new(MockInode::default()));
926        wrapper_mock.is_blkdev();
927    }
928
929    #[test]
930    #[should_panic]
931    fn test_is_fifo_ref() {
932        let wrapper_mock = InodeWrapper::from_inode_info(Arc::new(MockInode::default()));
933        wrapper_mock.is_fifo();
934    }
935
936    #[test]
937    #[should_panic]
938    fn test_has_hardlink_ref() {
939        let wrapper_mock = InodeWrapper::from_inode_info(Arc::new(MockInode::default()));
940        wrapper_mock.has_hardlink();
941    }
942
943    #[test]
944    #[should_panic]
945    fn test_set_has_hardlink_ref() {
946        let mut wrapper_mock = InodeWrapper::from_inode_info(Arc::new(MockInode::default()));
947        wrapper_mock.set_has_hardlink(true);
948    }
949
950    #[test]
951    #[should_panic]
952    fn test_set_has_xattr_ref() {
953        let mut wrapper_mock = InodeWrapper::from_inode_info(Arc::new(MockInode::default()));
954        wrapper_mock.set_has_xattr(true);
955    }
956
957    #[test]
958    #[should_panic]
959    fn test_set_ino_ref() {
960        let mut wrapper_mock = InodeWrapper::from_inode_info(Arc::new(MockInode::default()));
961        wrapper_mock.set_ino(Inode::default());
962    }
963
964    #[test]
965    #[should_panic]
966    fn test_set_parent_v6() {
967        let mut wrapper_v6 = InodeWrapper::new(RafsVersion::V6);
968        wrapper_v6.set_parent(Inode::default());
969    }
970
971    #[test]
972    #[should_panic]
973    fn test_set_parent_ref() {
974        let mut wrapper_mock = InodeWrapper::from_inode_info(Arc::new(MockInode::default()));
975        wrapper_mock.set_parent(Inode::default());
976    }
977
978    #[test]
979    #[should_panic]
980    fn test_get_parent_v6() {
981        let wrapper_v6 = InodeWrapper::new(RafsVersion::V6);
982        wrapper_v6.parent();
983    }
984
985    #[test]
986    #[should_panic]
987    fn test_get_parent_ref() {
988        let wrapper_mock = InodeWrapper::from_inode_info(Arc::new(MockInode::default()));
989        wrapper_mock.parent();
990    }
991
992    #[test]
993    #[should_panic]
994    fn test_set_size_ref() {
995        let mut wrapper_mock = InodeWrapper::from_inode_info(Arc::new(MockInode::default()));
996        wrapper_mock.set_size(0x0000_0001);
997    }
998
999    #[test]
1000    #[should_panic]
1001    fn test_set_uid_ref() {
1002        let mut wrapper_mock = InodeWrapper::from_inode_info(Arc::new(MockInode::default()));
1003        wrapper_mock.set_uid(0x0000_0000_0001);
1004    }
1005
1006    #[test]
1007    #[should_panic]
1008    fn test_set_gid_ref() {
1009        let mut wrapper_mock = InodeWrapper::from_inode_info(Arc::new(MockInode::default()));
1010        wrapper_mock.set_gid(0x0000_0001);
1011    }
1012
1013    #[test]
1014    #[should_panic]
1015    fn test_set_mtime_ref() {
1016        let mut wrapper_mock = InodeWrapper::from_inode_info(Arc::new(MockInode::default()));
1017        wrapper_mock.set_mtime(0x0000_0001);
1018    }
1019
1020    #[test]
1021    #[should_panic]
1022    fn test_set_mtime_nsec_ref() {
1023        let mut wrapper_mock = InodeWrapper::from_inode_info(Arc::new(MockInode::default()));
1024        wrapper_mock.set_mtime_nsec(0x0000_0001);
1025    }
1026
1027    #[test]
1028    #[should_panic]
1029    fn test_set_blocks_ref() {
1030        let mut wrapper_mock = InodeWrapper::from_inode_info(Arc::new(MockInode::default()));
1031        wrapper_mock.set_blocks(0x0000_0001);
1032    }
1033
1034    #[test]
1035    #[should_panic]
1036    fn test_set_rdev_ref() {
1037        let mut wrapper_mock = InodeWrapper::from_inode_info(Arc::new(MockInode::default()));
1038        wrapper_mock.set_rdev(0x0000_0001);
1039    }
1040
1041    #[test]
1042    #[should_panic]
1043    fn test_set_projid_ref() {
1044        let mut wrapper_mock = InodeWrapper::from_inode_info(Arc::new(MockInode::default()));
1045        wrapper_mock.set_projid(0x0000_0001);
1046    }
1047
1048    #[test]
1049    #[should_panic]
1050    fn test_set_digest_ref() {
1051        let mut wrapper_mock = InodeWrapper::from_inode_info(Arc::new(MockInode::default()));
1052        wrapper_mock.set_digest(RafsDigest::default());
1053    }
1054
1055    #[test]
1056    #[should_panic]
1057    fn test_get_digest_v6() {
1058        let wrapper_v6 = InodeWrapper::new(RafsVersion::V6);
1059        wrapper_v6.digest();
1060    }
1061
1062    #[test]
1063    #[should_panic]
1064    fn test_set_namesize_ref() {
1065        let mut wrapper_mock = InodeWrapper::from_inode_info(Arc::new(MockInode::default()));
1066        wrapper_mock.set_name_size(0x0000_0000);
1067    }
1068
1069    #[test]
1070    #[should_panic]
1071    fn test_set_symlink_size_ref() {
1072        let mut wrapper_mock = InodeWrapper::from_inode_info(Arc::new(MockInode::default()));
1073        wrapper_mock.set_symlink_size(0x0000_0000);
1074    }
1075
1076    #[test]
1077    #[should_panic]
1078    fn test_set_child_count_ref() {
1079        let mut wrapper_mock = InodeWrapper::from_inode_info(Arc::new(MockInode::default()));
1080        wrapper_mock.set_child_count(0x0000_0000);
1081    }
1082
1083    #[test]
1084    #[should_panic]
1085    fn test_create_chunk_ref() {
1086        let wrapper_mock = InodeWrapper::from_inode_info(Arc::new(MockInode::default()));
1087        wrapper_mock.create_chunk();
1088    }
1089
1090    #[test]
1091    fn test_rafs_v6_inode() {
1092        let mut inode = RafsV6Inode {
1093            i_ino: 0x0000_0000,
1094            i_uid: 0x0000_0001,
1095            i_gid: 0x0000_0002,
1096            i_projid: 0x0000_0003,
1097            i_mode: 0x0000_0000,
1098            i_size: 0x0000_0005,
1099            i_blocks: 0x0000_0006,
1100            i_flags: RafsInodeFlags::default(),
1101            i_nlink: 0x0000_0007,
1102            i_child_count: 0x0000_0008,
1103            i_name_size: 0x0000_0010,
1104            i_symlink_size: 0x0000_0011,
1105            i_rdev: 0x0000_0012,
1106            i_mtime_nsec: 0x0000_0013,
1107            i_mtime: 0x0000_0014,
1108        };
1109
1110        inode.set_name_size(0x0000_0001);
1111        inode.set_symlink_size(0x0000_0002);
1112
1113        assert_eq!(inode.i_name_size, 0x0000_0001);
1114        assert_eq!(inode.i_symlink_size, 0x0000_0002);
1115        assert_eq!(inode.uidgid(), (0x0000_0001, 0x0000_0002));
1116        assert_eq!(inode.mtime(), (0x0000_0014 as u64, 0x0000_0013));
1117        assert_eq!(inode.mode(), 0x0000_0000);
1118        assert!(!inode.is_chrdev());
1119        assert!(!inode.is_blkdev());
1120        assert!(!inode.is_fifo());
1121        assert!(!inode.is_sock());
1122        assert!(!inode.is_hardlink());
1123        assert!(!inode.has_hardlink());
1124        assert!(!inode.has_xattr());
1125        assert!(!inode.has_hole());
1126    }
1127}