97 lines
3.2 KiB
Go
97 lines
3.2 KiB
Go
// 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/sentry/kernel/time"
|
|
|
|
// InodeNew represents ext4 inode structure which can be bigger than
|
|
// OldInodeSize. The actual size of this struct should be determined using
|
|
// inode.ExtraInodeSize. Accessing any field here should be verified with the
|
|
// actual size. The extra space between the end of the inode struct and end of
|
|
// the inode record can be used to store extended attr.
|
|
//
|
|
// If the TimeExtra fields are in scope, the lower 2 bits of those are used
|
|
// to extend their counter part to be 34 bits wide; the rest (upper) 30 bits
|
|
// are used to provide nanoscond precision. Hence, these timestamps will now
|
|
// overflow in May 2446.
|
|
// See https://www.kernel.org/doc/html/latest/filesystems/ext4/dynamic.html#inode-timestamps.
|
|
type InodeNew struct {
|
|
InodeOld
|
|
|
|
ExtraInodeSize uint16
|
|
ChecksumHi uint16
|
|
ChangeTimeExtra uint32
|
|
ModificationTimeExtra uint32
|
|
AccessTimeExtra uint32
|
|
CreationTime uint32
|
|
CreationTimeExtra uint32
|
|
VersionHi uint32
|
|
ProjectID uint32
|
|
}
|
|
|
|
// Compiles only if InodeNew implements Inode.
|
|
var _ Inode = (*InodeNew)(nil)
|
|
|
|
// fromExtraTime decodes the extra time and constructs the kernel time struct
|
|
// with nanosecond precision.
|
|
func fromExtraTime(lo int32, extra uint32) time.Time {
|
|
// See description above InodeNew for format.
|
|
seconds := (int64(extra&0x3) << 32) + int64(lo)
|
|
nanoseconds := int64(extra >> 2)
|
|
return time.FromUnix(seconds, nanoseconds)
|
|
}
|
|
|
|
// Only override methods which change due to ext4 specific fields.
|
|
|
|
// Size implements Inode.Size.
|
|
func (in *InodeNew) Size() uint64 {
|
|
return (uint64(in.SizeHi) << 32) | uint64(in.SizeLo)
|
|
}
|
|
|
|
// InodeSize implements Inode.InodeSize.
|
|
func (in *InodeNew) InodeSize() uint16 {
|
|
return OldInodeSize + in.ExtraInodeSize
|
|
}
|
|
|
|
// ChangeTime implements Inode.ChangeTime.
|
|
func (in *InodeNew) ChangeTime() time.Time {
|
|
// Apply new timestamp logic if inode.ChangeTimeExtra is in scope.
|
|
if in.ExtraInodeSize >= 8 {
|
|
return fromExtraTime(in.ChangeTimeRaw, in.ChangeTimeExtra)
|
|
}
|
|
|
|
return in.InodeOld.ChangeTime()
|
|
}
|
|
|
|
// ModificationTime implements Inode.ModificationTime.
|
|
func (in *InodeNew) ModificationTime() time.Time {
|
|
// Apply new timestamp logic if inode.ModificationTimeExtra is in scope.
|
|
if in.ExtraInodeSize >= 12 {
|
|
return fromExtraTime(in.ModificationTimeRaw, in.ModificationTimeExtra)
|
|
}
|
|
|
|
return in.InodeOld.ModificationTime()
|
|
}
|
|
|
|
// AccessTime implements Inode.AccessTime.
|
|
func (in *InodeNew) AccessTime() time.Time {
|
|
// Apply new timestamp logic if inode.AccessTimeExtra is in scope.
|
|
if in.ExtraInodeSize >= 16 {
|
|
return fromExtraTime(in.AccessTimeRaw, in.AccessTimeExtra)
|
|
}
|
|
|
|
return in.InodeOld.AccessTime()
|
|
}
|