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  }