gvisor/pkg/sentry/fsimpl/ext/disklayout/inode.go

275 lines
8.3 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Copyright 2019 The gVisor Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package disklayout
import (
"gvisor.dev/gvisor/pkg/abi/linux"
"gvisor.dev/gvisor/pkg/sentry/kernel/auth"
"gvisor.dev/gvisor/pkg/sentry/kernel/time"
)
// Special inodes. See https://www.kernel.org/doc/html/latest/filesystems/ext4/overview.html#special-inodes.
const (
// RootDirInode is the inode number of the root directory inode.
RootDirInode = 2
)
// The Inode interface must be implemented by structs representing ext inodes.
// The inode stores all the metadata pertaining to the file (except for the
// file name which is held by the directory entry). It does NOT expose all
// fields and should be extended if need be.
//
// Some file systems (e.g. FAT) use the directory entry to store all this
// information. Ext file systems do not so that they can support hard links.
// However, ext4 cheats a little bit and duplicates the file type in the
// directory entry for performance gains.
//
// See https://www.kernel.org/doc/html/latest/filesystems/ext4/dynamic.html#index-nodes.
type Inode interface {
// Mode returns the linux file mode which is majorly used to extract
// information like:
// - File permissions (read/write/execute by user/group/others).
// - Sticky, set UID and GID bits.
// - File type.
//
// Masks to extract this information are provided in pkg/abi/linux/file.go.
Mode() linux.FileMode
// UID returns the owner UID.
UID() auth.KUID
// GID returns the owner GID.
GID() auth.KGID
// Size returns the size of the file in bytes.
Size() uint64
// InodeSize returns the size of this inode struct in bytes.
// In ext2 and ext3, the inode struct and inode disk record size was fixed at
// 128 bytes. Ext4 makes it possible for the inode struct to be bigger.
// However, accessing any field beyond the 128 bytes marker must be verified
// using this method.
InodeSize() uint16
// AccessTime returns the last access time. Shows when the file was last read.
//
// If InExtendedAttr is set, then this should NOT be used because the
// underlying field is used to store the extended attribute value checksum.
AccessTime() time.Time
// ChangeTime returns the last change time. Shows when the file meta data
// (like permissions) was last changed.
//
// If InExtendedAttr is set, then this should NOT be used because the
// underlying field is used to store the lower 32 bits of the attribute
// values reference count.
ChangeTime() time.Time
// ModificationTime returns the last modification time. Shows when the file
// content was last modified.
//
// If InExtendedAttr is set, then this should NOT be used because
// the underlying field contains the number of the inode that owns the
// extended attribute.
ModificationTime() time.Time
// DeletionTime returns the deletion time. Inodes are marked as deleted by
// writing to the underlying field. FS tools can restore files until they are
// actually overwritten.
DeletionTime() time.Time
// LinksCount returns the number of hard links to this inode.
//
// Normally there is an upper limit on the number of hard links:
// - ext2/ext3 = 32,000
// - ext4 = 65,000
//
// This implies that an ext4 directory cannot have more than 64,998
// subdirectories because each subdirectory will have a hard link to the
// directory via the `..` entry. The directory has hard link via the `.` entry
// of its own. And finally the inode is initiated with 1 hard link (itself).
//
// The underlying value is reset to 1 if all the following hold:
// - Inode is a directory.
// - SbDirNlink is enabled.
// - Number of hard links is incremented past 64,999.
// Hard link value of 1 for a directory would indicate that the number of hard
// links is unknown because a directory can have minimum 2 hard links (itself
// and `.` entry).
LinksCount() uint16
// Flags returns InodeFlags which represents the inode flags.
Flags() InodeFlags
// Data returns the underlying inode.i_block array as a slice so it's
// modifiable. This field is special and is used to store various kinds of
// things depending on the filesystem version and inode type. The underlying
// field name in Linux is a little misleading.
// - In ext2/ext3, it contains the block map.
// - In ext4, it contains the extent tree root node.
// - For inline files, it contains the file contents.
// - For symlinks, it contains the link path (if it fits here).
//
// See https://www.kernel.org/doc/html/latest/filesystems/ext4/dynamic.html#the-contents-of-inode-i-block.
Data() []byte
}
// Inode flags. This is not comprehensive and flags which were not used in
// the Linux kernel have been excluded.
const (
// InSync indicates that all writes to the file must be synchronous.
InSync = 0x8
// InImmutable indicates that this file is immutable.
InImmutable = 0x10
// InAppend indicates that this file can only be appended to.
InAppend = 0x20
// InNoDump indicates that teh dump(1) utility should not dump this file.
InNoDump = 0x40
// InNoAccessTime indicates that the access time of this inode must not be
// updated.
InNoAccessTime = 0x80
// InIndex indicates that this directory has hashed indexes.
InIndex = 0x1000
// InJournalData indicates that file data must always be written through a
// journal device.
InJournalData = 0x4000
// InDirSync indicates that all the directory entiry data must be written
// synchronously.
InDirSync = 0x10000
// InTopDir indicates that this inode is at the top of the directory hierarchy.
InTopDir = 0x20000
// InHugeFile indicates that this is a huge file.
InHugeFile = 0x40000
// InExtents indicates that this inode uses extents.
InExtents = 0x80000
// InExtendedAttr indicates that this inode stores a large extended attribute
// value in its data blocks.
InExtendedAttr = 0x200000
// InInline indicates that this inode has inline data.
InInline = 0x10000000
// InReserved indicates that this inode is reserved for the ext4 library.
InReserved = 0x80000000
)
// InodeFlags represents all possible combinations of inode flags. It aims to
// cover the bit masks and provide a more user-friendly interface.
type InodeFlags struct {
Sync bool
Immutable bool
Append bool
NoDump bool
NoAccessTime bool
Index bool
JournalData bool
DirSync bool
TopDir bool
HugeFile bool
Extents bool
ExtendedAttr bool
Inline bool
Reserved bool
}
// ToInt converts inode flags back to its 32-bit rep.
func (f InodeFlags) ToInt() uint32 {
var res uint32
if f.Sync {
res |= InSync
}
if f.Immutable {
res |= InImmutable
}
if f.Append {
res |= InAppend
}
if f.NoDump {
res |= InNoDump
}
if f.NoAccessTime {
res |= InNoAccessTime
}
if f.Index {
res |= InIndex
}
if f.JournalData {
res |= InJournalData
}
if f.DirSync {
res |= InDirSync
}
if f.TopDir {
res |= InTopDir
}
if f.HugeFile {
res |= InHugeFile
}
if f.Extents {
res |= InExtents
}
if f.ExtendedAttr {
res |= InExtendedAttr
}
if f.Inline {
res |= InInline
}
if f.Reserved {
res |= InReserved
}
return res
}
// InodeFlagsFromInt converts the integer representation of inode flags to
// a InodeFlags struct.
func InodeFlagsFromInt(f uint32) InodeFlags {
return InodeFlags{
Sync: f&InSync > 0,
Immutable: f&InImmutable > 0,
Append: f&InAppend > 0,
NoDump: f&InNoDump > 0,
NoAccessTime: f&InNoAccessTime > 0,
Index: f&InIndex > 0,
JournalData: f&InJournalData > 0,
DirSync: f&InDirSync > 0,
TopDir: f&InTopDir > 0,
HugeFile: f&InHugeFile > 0,
Extents: f&InExtents > 0,
ExtendedAttr: f&InExtendedAttr > 0,
Inline: f&InInline > 0,
Reserved: f&InReserved > 0,
}
}
// These masks define how users can view/modify inode flags. The rest of the
// flags are for internal kernel usage only.
const (
InUserReadFlagMask = 0x4BDFFF
InUserWriteFlagMask = 0x4B80FF
)