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 )