github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/sentry/fsimpl/ext/disklayout/inode_test.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  	"fmt"
    19  	"strconv"
    20  	"testing"
    21  
    22  	"github.com/SagerNet/gvisor/pkg/sentry/kernel/time"
    23  )
    24  
    25  // TestInodeSize tests that the inode structs are of the correct size.
    26  func TestInodeSize(t *testing.T) {
    27  	var iOld InodeOld
    28  	assertSize(t, &iOld, OldInodeSize)
    29  
    30  	// This was updated from 156 bytes to 160 bytes in Oct 2015.
    31  	var iNew InodeNew
    32  	assertSize(t, &iNew, 160)
    33  }
    34  
    35  // TestTimestampSeconds tests that the seconds part of [a/c/m] timestamps in
    36  // ext4 inode structs are decoded correctly.
    37  //
    38  // These tests are derived from the table under https://www.kernel.org/doc/html/latest/filesystems/ext4/dynamic.html#inode-timestamps.
    39  func TestTimestampSeconds(t *testing.T) {
    40  	type timestampTest struct {
    41  		// msbSet tells if the most significant bit of InodeOld.[X]TimeRaw is set.
    42  		// If this is set then the 32-bit time is negative.
    43  		msbSet bool
    44  
    45  		// lowerBound tells if we should take the lowest possible value of
    46  		// InodeOld.[X]TimeRaw while satisfying test.msbSet condition. If set to
    47  		// false it tells to take the highest possible value.
    48  		lowerBound bool
    49  
    50  		// extraBits is InodeNew.[X]TimeExtra.
    51  		extraBits uint32
    52  
    53  		// want is the kernel time struct that is expected.
    54  		want time.Time
    55  	}
    56  
    57  	tests := []timestampTest{
    58  		// 1901-12-13
    59  		{
    60  			msbSet:     true,
    61  			lowerBound: true,
    62  			extraBits:  0,
    63  			want:       time.FromUnix(int64(-0x80000000), 0),
    64  		},
    65  
    66  		// 1969-12-31
    67  		{
    68  			msbSet:     true,
    69  			lowerBound: false,
    70  			extraBits:  0,
    71  			want:       time.FromUnix(int64(-1), 0),
    72  		},
    73  
    74  		// 1970-01-01
    75  		{
    76  			msbSet:     false,
    77  			lowerBound: true,
    78  			extraBits:  0,
    79  			want:       time.FromUnix(int64(0), 0),
    80  		},
    81  
    82  		// 2038-01-19
    83  		{
    84  			msbSet:     false,
    85  			lowerBound: false,
    86  			extraBits:  0,
    87  			want:       time.FromUnix(int64(0x7fffffff), 0),
    88  		},
    89  
    90  		// 2038-01-19
    91  		{
    92  			msbSet:     true,
    93  			lowerBound: true,
    94  			extraBits:  1,
    95  			want:       time.FromUnix(int64(0x80000000), 0),
    96  		},
    97  
    98  		// 2106-02-07
    99  		{
   100  			msbSet:     true,
   101  			lowerBound: false,
   102  			extraBits:  1,
   103  			want:       time.FromUnix(int64(0xffffffff), 0),
   104  		},
   105  
   106  		// 2106-02-07
   107  		{
   108  			msbSet:     false,
   109  			lowerBound: true,
   110  			extraBits:  1,
   111  			want:       time.FromUnix(int64(0x100000000), 0),
   112  		},
   113  
   114  		// 2174-02-25
   115  		{
   116  			msbSet:     false,
   117  			lowerBound: false,
   118  			extraBits:  1,
   119  			want:       time.FromUnix(int64(0x17fffffff), 0),
   120  		},
   121  
   122  		// 2174-02-25
   123  		{
   124  			msbSet:     true,
   125  			lowerBound: true,
   126  			extraBits:  2,
   127  			want:       time.FromUnix(int64(0x180000000), 0),
   128  		},
   129  
   130  		// 2242-03-16
   131  		{
   132  			msbSet:     true,
   133  			lowerBound: false,
   134  			extraBits:  2,
   135  			want:       time.FromUnix(int64(0x1ffffffff), 0),
   136  		},
   137  
   138  		// 2242-03-16
   139  		{
   140  			msbSet:     false,
   141  			lowerBound: true,
   142  			extraBits:  2,
   143  			want:       time.FromUnix(int64(0x200000000), 0),
   144  		},
   145  
   146  		// 2310-04-04
   147  		{
   148  			msbSet:     false,
   149  			lowerBound: false,
   150  			extraBits:  2,
   151  			want:       time.FromUnix(int64(0x27fffffff), 0),
   152  		},
   153  
   154  		// 2310-04-04
   155  		{
   156  			msbSet:     true,
   157  			lowerBound: true,
   158  			extraBits:  3,
   159  			want:       time.FromUnix(int64(0x280000000), 0),
   160  		},
   161  
   162  		// 2378-04-22
   163  		{
   164  			msbSet:     true,
   165  			lowerBound: false,
   166  			extraBits:  3,
   167  			want:       time.FromUnix(int64(0x2ffffffff), 0),
   168  		},
   169  
   170  		// 2378-04-22
   171  		{
   172  			msbSet:     false,
   173  			lowerBound: true,
   174  			extraBits:  3,
   175  			want:       time.FromUnix(int64(0x300000000), 0),
   176  		},
   177  
   178  		// 2446-05-10
   179  		{
   180  			msbSet:     false,
   181  			lowerBound: false,
   182  			extraBits:  3,
   183  			want:       time.FromUnix(int64(0x37fffffff), 0),
   184  		},
   185  	}
   186  
   187  	lowerMSB0 := int32(0)           // binary: 00000000 00000000 00000000 00000000
   188  	upperMSB0 := int32(0x7fffffff)  // binary: 01111111 11111111 11111111 11111111
   189  	lowerMSB1 := int32(-0x80000000) // binary: 10000000 00000000 00000000 00000000
   190  	upperMSB1 := int32(-1)          // binary: 11111111 11111111 11111111 11111111
   191  
   192  	get32BitTime := func(test timestampTest) int32 {
   193  		if test.msbSet {
   194  			if test.lowerBound {
   195  				return lowerMSB1
   196  			}
   197  
   198  			return upperMSB1
   199  		}
   200  
   201  		if test.lowerBound {
   202  			return lowerMSB0
   203  		}
   204  
   205  		return upperMSB0
   206  	}
   207  
   208  	getTestName := func(test timestampTest) string {
   209  		return fmt.Sprintf(
   210  			"Tests time decoding with epoch bits 0b%s and 32-bit raw time: MSB set=%t, lower bound=%t",
   211  			strconv.FormatInt(int64(test.extraBits), 2),
   212  			test.msbSet,
   213  			test.lowerBound,
   214  		)
   215  	}
   216  
   217  	for _, test := range tests {
   218  		t.Run(getTestName(test), func(t *testing.T) {
   219  			if got := fromExtraTime(get32BitTime(test), test.extraBits); got != test.want {
   220  				t.Errorf("Expected: %v, Got: %v", test.want, got)
   221  			}
   222  		})
   223  	}
   224  }