github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/sentry/fsimpl/ext/disklayout/inode.go (about)

     1  // Copyright 2019 The gVisor Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package disklayout
    16  
    17  import (
    18  	"github.com/SagerNet/gvisor/pkg/abi/linux"
    19  	"github.com/SagerNet/gvisor/pkg/marshal"
    20  	"github.com/SagerNet/gvisor/pkg/sentry/kernel/auth"
    21  	"github.com/SagerNet/gvisor/pkg/sentry/kernel/time"
    22  )
    23  
    24  // Special inodes. See https://www.kernel.org/doc/html/latest/filesystems/ext4/overview.html#special-inodes.
    25  const (
    26  	// RootDirInode is the inode number of the root directory inode.
    27  	RootDirInode = 2
    28  )
    29  
    30  // The Inode interface must be implemented by structs representing ext inodes.
    31  // The inode stores all the metadata pertaining to the file (except for the
    32  // file name which is held by the directory entry). It does NOT expose all
    33  // fields and should be extended if need be.
    34  //
    35  // Some file systems (e.g. FAT) use the directory entry to store all this
    36  // information. Ext file systems do not so that they can support hard links.
    37  // However, ext4 cheats a little bit and duplicates the file type in the
    38  // directory entry for performance gains.
    39  //
    40  // See https://www.kernel.org/doc/html/latest/filesystems/ext4/dynamic.html#index-nodes.
    41  type Inode interface {
    42  	marshal.Marshallable
    43  
    44  	// Mode returns the linux file mode which is majorly used to extract
    45  	// information like:
    46  	// - File permissions (read/write/execute by user/group/others).
    47  	// - Sticky, set UID and GID bits.
    48  	// - File type.
    49  	//
    50  	// Masks to extract this information are provided in pkg/abi/linux/file.go.
    51  	Mode() linux.FileMode
    52  
    53  	// UID returns the owner UID.
    54  	UID() auth.KUID
    55  
    56  	// GID returns the owner GID.
    57  	GID() auth.KGID
    58  
    59  	// Size returns the size of the file in bytes.
    60  	Size() uint64
    61  
    62  	// InodeSize returns the size of this inode struct in bytes.
    63  	// In ext2 and ext3, the inode struct and inode disk record size was fixed at
    64  	// 128 bytes. Ext4 makes it possible for the inode struct to be bigger.
    65  	// However, accessing any field beyond the 128 bytes marker must be verified
    66  	// using this method.
    67  	InodeSize() uint16
    68  
    69  	// AccessTime returns the last access time. Shows when the file was last read.
    70  	//
    71  	// If InExtendedAttr is set, then this should NOT be used because the
    72  	// underlying field is used to store the extended attribute value checksum.
    73  	AccessTime() time.Time
    74  
    75  	// ChangeTime returns the last change time. Shows when the file meta data
    76  	// (like permissions) was last changed.
    77  	//
    78  	// If InExtendedAttr is set, then this should NOT be used because the
    79  	// underlying field is used to store the lower 32 bits of the attribute
    80  	// value’s reference count.
    81  	ChangeTime() time.Time
    82  
    83  	// ModificationTime returns the last modification time. Shows when the file
    84  	// content was last modified.
    85  	//
    86  	// If InExtendedAttr is set, then this should NOT be used because
    87  	// the underlying field contains the number of the inode that owns the
    88  	// extended attribute.
    89  	ModificationTime() time.Time
    90  
    91  	// DeletionTime returns the deletion time. Inodes are marked as deleted by
    92  	// writing to the underlying field. FS tools can restore files until they are
    93  	// actually overwritten.
    94  	DeletionTime() time.Time
    95  
    96  	// LinksCount returns the number of hard links to this inode.
    97  	//
    98  	// Normally there is an upper limit on the number of hard links:
    99  	//   - ext2/ext3 = 32,000
   100  	//   - ext4      = 65,000
   101  	//
   102  	// This implies that an ext4 directory cannot have more than 64,998
   103  	// subdirectories because each subdirectory will have a hard link to the
   104  	// directory via the `..` entry. The directory has hard link via the `.` entry
   105  	// of its own. And finally the inode is initiated with 1 hard link (itself).
   106  	//
   107  	// The underlying value is reset to 1 if all the following hold:
   108  	//     - Inode is a directory.
   109  	//     - SbDirNlink is enabled.
   110  	//     - Number of hard links is incremented past 64,999.
   111  	// Hard link value of 1 for a directory would indicate that the number of hard
   112  	// links is unknown because a directory can have minimum 2 hard links (itself
   113  	// and `.` entry).
   114  	LinksCount() uint16
   115  
   116  	// Flags returns InodeFlags which represents the inode flags.
   117  	Flags() InodeFlags
   118  
   119  	// Data returns the underlying inode.i_block array as a slice so it's
   120  	// modifiable. This field is special and is used to store various kinds of
   121  	// things depending on the filesystem version and inode type. The underlying
   122  	// field name in Linux is a little misleading.
   123  	//   - In ext2/ext3, it contains the block map.
   124  	//   - In ext4, it contains the extent tree root node.
   125  	//   - For inline files, it contains the file contents.
   126  	//   - For symlinks, it contains the link path (if it fits here).
   127  	//
   128  	// See https://www.kernel.org/doc/html/latest/filesystems/ext4/dynamic.html#the-contents-of-inode-i-block.
   129  	Data() []byte
   130  }
   131  
   132  // Inode flags. This is not comprehensive and flags which were not used in
   133  // the Linux kernel have been excluded.
   134  const (
   135  	// InSync indicates that all writes to the file must be synchronous.
   136  	InSync = 0x8
   137  
   138  	// InImmutable indicates that this file is immutable.
   139  	InImmutable = 0x10
   140  
   141  	// InAppend indicates that this file can only be appended to.
   142  	InAppend = 0x20
   143  
   144  	// InNoDump indicates that teh dump(1) utility should not dump this file.
   145  	InNoDump = 0x40
   146  
   147  	// InNoAccessTime indicates that the access time of this inode must not be
   148  	// updated.
   149  	InNoAccessTime = 0x80
   150  
   151  	// InIndex indicates that this directory has hashed indexes.
   152  	InIndex = 0x1000
   153  
   154  	// InJournalData indicates that file data must always be written through a
   155  	// journal device.
   156  	InJournalData = 0x4000
   157  
   158  	// InDirSync indicates that all the directory entiry data must be written
   159  	// synchronously.
   160  	InDirSync = 0x10000
   161  
   162  	// InTopDir indicates that this inode is at the top of the directory hierarchy.
   163  	InTopDir = 0x20000
   164  
   165  	// InHugeFile indicates that this is a huge file.
   166  	InHugeFile = 0x40000
   167  
   168  	// InExtents indicates that this inode uses extents.
   169  	InExtents = 0x80000
   170  
   171  	// InExtendedAttr indicates that this inode stores a large extended attribute
   172  	// value in its data blocks.
   173  	InExtendedAttr = 0x200000
   174  
   175  	// InInline indicates that this inode has inline data.
   176  	InInline = 0x10000000
   177  
   178  	// InReserved indicates that this inode is reserved for the ext4 library.
   179  	InReserved = 0x80000000
   180  )
   181  
   182  // InodeFlags represents all possible combinations of inode flags. It aims to
   183  // cover the bit masks and provide a more user-friendly interface.
   184  type InodeFlags struct {
   185  	Sync         bool
   186  	Immutable    bool
   187  	Append       bool
   188  	NoDump       bool
   189  	NoAccessTime bool
   190  	Index        bool
   191  	JournalData  bool
   192  	DirSync      bool
   193  	TopDir       bool
   194  	HugeFile     bool
   195  	Extents      bool
   196  	ExtendedAttr bool
   197  	Inline       bool
   198  	Reserved     bool
   199  }
   200  
   201  // ToInt converts inode flags back to its 32-bit rep.
   202  func (f InodeFlags) ToInt() uint32 {
   203  	var res uint32
   204  
   205  	if f.Sync {
   206  		res |= InSync
   207  	}
   208  	if f.Immutable {
   209  		res |= InImmutable
   210  	}
   211  	if f.Append {
   212  		res |= InAppend
   213  	}
   214  	if f.NoDump {
   215  		res |= InNoDump
   216  	}
   217  	if f.NoAccessTime {
   218  		res |= InNoAccessTime
   219  	}
   220  	if f.Index {
   221  		res |= InIndex
   222  	}
   223  	if f.JournalData {
   224  		res |= InJournalData
   225  	}
   226  	if f.DirSync {
   227  		res |= InDirSync
   228  	}
   229  	if f.TopDir {
   230  		res |= InTopDir
   231  	}
   232  	if f.HugeFile {
   233  		res |= InHugeFile
   234  	}
   235  	if f.Extents {
   236  		res |= InExtents
   237  	}
   238  	if f.ExtendedAttr {
   239  		res |= InExtendedAttr
   240  	}
   241  	if f.Inline {
   242  		res |= InInline
   243  	}
   244  	if f.Reserved {
   245  		res |= InReserved
   246  	}
   247  
   248  	return res
   249  }
   250  
   251  // InodeFlagsFromInt converts the integer representation of inode flags to
   252  // a InodeFlags struct.
   253  func InodeFlagsFromInt(f uint32) InodeFlags {
   254  	return InodeFlags{
   255  		Sync:         f&InSync > 0,
   256  		Immutable:    f&InImmutable > 0,
   257  		Append:       f&InAppend > 0,
   258  		NoDump:       f&InNoDump > 0,
   259  		NoAccessTime: f&InNoAccessTime > 0,
   260  		Index:        f&InIndex > 0,
   261  		JournalData:  f&InJournalData > 0,
   262  		DirSync:      f&InDirSync > 0,
   263  		TopDir:       f&InTopDir > 0,
   264  		HugeFile:     f&InHugeFile > 0,
   265  		Extents:      f&InExtents > 0,
   266  		ExtendedAttr: f&InExtendedAttr > 0,
   267  		Inline:       f&InInline > 0,
   268  		Reserved:     f&InReserved > 0,
   269  	}
   270  }
   271  
   272  // These masks define how users can view/modify inode flags. The rest of the
   273  // flags are for internal kernel usage only.
   274  const (
   275  	InUserReadFlagMask  = 0x4BDFFF
   276  	InUserWriteFlagMask = 0x4B80FF
   277  )