github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/sentry/fsimpl/ext/disklayout/inode_new.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 "github.com/SagerNet/gvisor/pkg/sentry/kernel/time" 18 19 // InodeNew represents ext4 inode structure which can be bigger than 20 // OldInodeSize. The actual size of this struct should be determined using 21 // inode.ExtraInodeSize. Accessing any field here should be verified with the 22 // actual size. The extra space between the end of the inode struct and end of 23 // the inode record can be used to store extended attr. 24 // 25 // If the TimeExtra fields are in scope, the lower 2 bits of those are used 26 // to extend their counter part to be 34 bits wide; the rest (upper) 30 bits 27 // are used to provide nanoscond precision. Hence, these timestamps will now 28 // overflow in May 2446. 29 // See https://www.kernel.org/doc/html/latest/filesystems/ext4/dynamic.html#inode-timestamps. 30 // 31 // +marshal 32 type InodeNew struct { 33 InodeOld 34 35 ExtraInodeSize uint16 36 ChecksumHi uint16 37 ChangeTimeExtra uint32 38 ModificationTimeExtra uint32 39 AccessTimeExtra uint32 40 CreationTime uint32 41 CreationTimeExtra uint32 42 VersionHi uint32 43 ProjectID uint32 44 } 45 46 // Compiles only if InodeNew implements Inode. 47 var _ Inode = (*InodeNew)(nil) 48 49 // fromExtraTime decodes the extra time and constructs the kernel time struct 50 // with nanosecond precision. 51 func fromExtraTime(lo int32, extra uint32) time.Time { 52 // See description above InodeNew for format. 53 seconds := (int64(extra&0x3) << 32) + int64(lo) 54 nanoseconds := int64(extra >> 2) 55 return time.FromUnix(seconds, nanoseconds) 56 } 57 58 // Only override methods which change due to ext4 specific fields. 59 60 // Size implements Inode.Size. 61 func (in *InodeNew) Size() uint64 { 62 return (uint64(in.SizeHi) << 32) | uint64(in.SizeLo) 63 } 64 65 // InodeSize implements Inode.InodeSize. 66 func (in *InodeNew) InodeSize() uint16 { 67 return OldInodeSize + in.ExtraInodeSize 68 } 69 70 // ChangeTime implements Inode.ChangeTime. 71 func (in *InodeNew) ChangeTime() time.Time { 72 // Apply new timestamp logic if inode.ChangeTimeExtra is in scope. 73 if in.ExtraInodeSize >= 8 { 74 return fromExtraTime(in.ChangeTimeRaw, in.ChangeTimeExtra) 75 } 76 77 return in.InodeOld.ChangeTime() 78 } 79 80 // ModificationTime implements Inode.ModificationTime. 81 func (in *InodeNew) ModificationTime() time.Time { 82 // Apply new timestamp logic if inode.ModificationTimeExtra is in scope. 83 if in.ExtraInodeSize >= 12 { 84 return fromExtraTime(in.ModificationTimeRaw, in.ModificationTimeExtra) 85 } 86 87 return in.InodeOld.ModificationTime() 88 } 89 90 // AccessTime implements Inode.AccessTime. 91 func (in *InodeNew) AccessTime() time.Time { 92 // Apply new timestamp logic if inode.AccessTimeExtra is in scope. 93 if in.ExtraInodeSize >= 16 { 94 return fromExtraTime(in.AccessTimeRaw, in.AccessTimeExtra) 95 } 96 97 return in.InodeOld.AccessTime() 98 }