github.com/usbarmory/armory-boot@v0.0.0-20240307133412-208c66a380b9/disk/ext4.go (about) 1 // https://github.com/usbarmory/armory-boot 2 // 3 // Copyright (c) WithSecure Corporation 4 // https://foundry.withsecure.com 5 // 6 // Use of this source code is governed by the license 7 // that can be found in the LICENSE file. 8 9 // Package disk provides support for SD/MMC card partition access, only ext4 10 // filesystems are currently supported. 11 // 12 // This package is only meant to be used with `GOOS=tamago GOARCH=arm` as 13 // supported by the TamaGo framework for bare metal Go on ARM SoCs, see 14 // https://github.com/usbarmory/tamago. 15 package disk 16 17 import ( 18 "errors" 19 "fmt" 20 "io" 21 "io/ioutil" 22 "strings" 23 24 "github.com/dsoprea/go-ext4" 25 26 "github.com/usbarmory/tamago/soc/nxp/usdhc" 27 ) 28 29 // Partition represents an SD/MMC card partition, only ext4 filesystems are 30 // currently supported. 31 type Partition struct { 32 Card *usdhc.USDHC 33 Offset int64 34 _offset int64 35 } 36 37 func (part *Partition) getBlockGroupDescriptor(inode int) (bgd *ext4.BlockGroupDescriptor, err error) { 38 _, err = part.Seek(ext4.Superblock0Offset, io.SeekStart) 39 40 if err != nil { 41 return 42 } 43 44 sb, err := ext4.NewSuperblockWithReader(part) 45 46 if err != nil { 47 return 48 } 49 50 bgdl, err := ext4.NewBlockGroupDescriptorListWithReadSeeker(part, sb) 51 52 if err != nil { 53 return 54 } 55 56 return bgdl.GetWithAbsoluteInode(inode) 57 } 58 59 func (part *Partition) Read(p []byte) (n int, err error) { 60 buf, err := part.Card.Read(part._offset, int64(len(p))) 61 62 if err != nil { 63 return 64 } 65 66 n = copy(p, buf) 67 _, err = part.Seek(int64(n), io.SeekCurrent) 68 69 return 70 } 71 72 func (part *Partition) Seek(offset int64, whence int) (int64, error) { 73 info := part.Card.Info() 74 end := int64(info.Blocks) * int64(info.BlockSize) 75 76 switch whence { 77 case io.SeekStart: 78 part._offset = part.Offset + offset 79 case io.SeekCurrent: 80 part._offset += offset 81 case io.SeekEnd: 82 part._offset = end + part.Offset + offset 83 default: 84 return 0, fmt.Errorf("invalid whence %d", whence) 85 } 86 87 if part._offset > end { 88 return 0, fmt.Errorf("invalid offset %d (%d)", part._offset, offset) 89 } 90 91 if part._offset < part.Offset { 92 return 0, fmt.Errorf("invalid offset %d (%d)", part._offset, offset) 93 } 94 95 return part._offset, nil 96 } 97 98 func (part *Partition) ReadAll(fullPath string) (buf []byte, err error) { 99 fullPath = strings.TrimPrefix(fullPath, "/") 100 path := strings.Split(fullPath, "/") 101 102 bgd, err := part.getBlockGroupDescriptor(ext4.InodeRootDirectory) 103 104 if err != nil { 105 return 106 } 107 108 dw, err := ext4.NewDirectoryWalk(part, bgd, ext4.InodeRootDirectory) 109 110 var i int 111 var inodeNumber int 112 113 for { 114 if err != nil { 115 return 116 } 117 118 p, de, err := dw.Next() 119 120 if err == io.EOF { 121 break 122 } else if err != nil { 123 return nil, err 124 } 125 126 deInode := int(de.Data().Inode) 127 128 bgd, err = part.getBlockGroupDescriptor(deInode) 129 130 if err != nil { 131 return nil, err 132 } 133 134 if p == path[i] { 135 if i == len(path)-1 { 136 inodeNumber = deInode 137 break 138 } else { 139 dw, err = ext4.NewDirectoryWalk(part, bgd, deInode) 140 141 if err != nil { 142 return nil, err 143 } 144 145 i += 1 146 } 147 } 148 } 149 150 if inodeNumber == 0 { 151 return nil, errors.New("file not found") 152 } 153 154 inode, err := ext4.NewInodeWithReadSeeker(bgd, part, inodeNumber) 155 156 if err != nil { 157 return 158 } 159 160 en := ext4.NewExtentNavigatorWithReadSeeker(part, inode) 161 r := ext4.NewInodeReader(en) 162 163 return ioutil.ReadAll(r) 164 }