github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/sentry/fsimpl/ext/utils.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 ext 16 17 import ( 18 "io" 19 20 "github.com/SagerNet/gvisor/pkg/marshal" 21 "github.com/SagerNet/gvisor/pkg/sentry/fsimpl/ext/disklayout" 22 "github.com/SagerNet/gvisor/pkg/syserror" 23 ) 24 25 // readFromDisk performs a binary read from disk into the given struct from 26 // the absolute offset provided. 27 func readFromDisk(dev io.ReaderAt, abOff int64, v marshal.Marshallable) error { 28 n := v.SizeBytes() 29 buf := make([]byte, n) 30 if read, _ := dev.ReadAt(buf, abOff); read < int(n) { 31 return syserror.EIO 32 } 33 34 v.UnmarshalBytes(buf) 35 return nil 36 } 37 38 // readSuperBlock reads the SuperBlock from block group 0 in the underlying 39 // device. There are three versions of the superblock. This function identifies 40 // and returns the correct version. 41 func readSuperBlock(dev io.ReaderAt) (disklayout.SuperBlock, error) { 42 var sb disklayout.SuperBlock = &disklayout.SuperBlockOld{} 43 if err := readFromDisk(dev, disklayout.SbOffset, sb); err != nil { 44 return nil, err 45 } 46 if sb.Revision() == disklayout.OldRev { 47 return sb, nil 48 } 49 50 sb = &disklayout.SuperBlock32Bit{} 51 if err := readFromDisk(dev, disklayout.SbOffset, sb); err != nil { 52 return nil, err 53 } 54 if !sb.IncompatibleFeatures().Is64Bit { 55 return sb, nil 56 } 57 58 sb = &disklayout.SuperBlock64Bit{} 59 if err := readFromDisk(dev, disklayout.SbOffset, sb); err != nil { 60 return nil, err 61 } 62 return sb, nil 63 } 64 65 // blockGroupsCount returns the number of block groups in the ext fs. 66 func blockGroupsCount(sb disklayout.SuperBlock) uint64 { 67 blocksCount := sb.BlocksCount() 68 blocksPerGroup := uint64(sb.BlocksPerGroup()) 69 70 // Round up the result. float64 can compromise precision so do it manually. 71 return (blocksCount + blocksPerGroup - 1) / blocksPerGroup 72 } 73 74 // readBlockGroups reads the block group descriptor table from block group 0 in 75 // the underlying device. 76 func readBlockGroups(dev io.ReaderAt, sb disklayout.SuperBlock) ([]disklayout.BlockGroup, error) { 77 bgCount := blockGroupsCount(sb) 78 bgdSize := uint64(sb.BgDescSize()) 79 is64Bit := sb.IncompatibleFeatures().Is64Bit 80 bgds := make([]disklayout.BlockGroup, bgCount) 81 82 for i, off := uint64(0), uint64(sb.FirstDataBlock()+1)*sb.BlockSize(); i < bgCount; i, off = i+1, off+bgdSize { 83 if is64Bit { 84 bgds[i] = &disklayout.BlockGroup64Bit{} 85 } else { 86 bgds[i] = &disklayout.BlockGroup32Bit{} 87 } 88 89 if err := readFromDisk(dev, int64(off), bgds[i]); err != nil { 90 return nil, err 91 } 92 } 93 return bgds, nil 94 }