github.com/google/trillian-examples@v0.0.0-20240520080811-0d40d35cef0e/binary_transparency/firmware/devices/usbarmory/bootloader/ext4.go (about) 1 // https://github.com/usbarmory/armory-boot 2 // 3 // Copyright (c) F-Secure Corporation 4 // https://foundry.f-secure.com 5 // 6 // Use of this source code is governed by the license 7 // that can be found in the LICENSE file. 8 9 //go:build armory 10 // +build armory 11 12 package main 13 14 import ( 15 "errors" 16 "fmt" 17 "io" 18 "strings" 19 20 "github.com/dsoprea/go-ext4" 21 22 "github.com/usbarmory/tamago/soc/nxp/usdhc" 23 ) 24 25 type Partition struct { 26 Card *usdhc.USDHC 27 Offset int64 28 _offset int64 29 } 30 31 // GetExt4FilesystemSize returns the size in bytes of the ext4 filesystem stored 32 // in the partition. 33 // Note that this may not be the same as the size of the disk partition which 34 // contains the filesystem. 35 func (d *Partition) GetExt4FilesystemSize() (uint64, error) { 36 _, err := d.Seek(ext4.Superblock0Offset, io.SeekStart) 37 if err != nil { 38 return 0, err 39 } 40 41 sb, err := ext4.NewSuperblockWithReader(d) 42 if err != nil { 43 return 0, err 44 } 45 46 return uint64(sb.BlockSize()) * sb.BlockCount(), nil 47 } 48 49 func (d *Partition) getBlockGroupDescriptor(inode int) (bgd *ext4.BlockGroupDescriptor, err error) { 50 _, err = d.Seek(ext4.Superblock0Offset, io.SeekStart) 51 52 if err != nil { 53 return 54 } 55 56 sb, err := ext4.NewSuperblockWithReader(d) 57 58 if err != nil { 59 return 60 } 61 62 bgdl, err := ext4.NewBlockGroupDescriptorListWithReadSeeker(d, sb) 63 64 if err != nil { 65 return 66 } 67 68 return bgdl.GetWithAbsoluteInode(inode) 69 } 70 71 func (d *Partition) Read(p []byte) (n int, err error) { 72 buf, err := d.Card.Read(d._offset, int64(len(p))) 73 74 if err != nil { 75 return 76 } 77 78 n = copy(p, buf) 79 _, err = d.Seek(int64(n), io.SeekCurrent) 80 81 return 82 } 83 84 func (d *Partition) Seek(offset int64, whence int) (int64, error) { 85 info := d.Card.Info() 86 end := int64(info.Blocks) * int64(info.BlockSize) 87 88 switch whence { 89 case io.SeekStart: 90 d._offset = d.Offset + offset 91 case io.SeekCurrent: 92 d._offset += offset 93 case io.SeekEnd: 94 d._offset = end + d.Offset + offset 95 default: 96 return 0, fmt.Errorf("invalid whence %d", whence) 97 } 98 99 if d._offset > end { 100 return 0, fmt.Errorf("invalid offset %d (%d)", d._offset, offset) 101 } 102 103 if d._offset < d.Offset { 104 return 0, fmt.Errorf("invalid offset %d (%d)", d._offset, offset) 105 } 106 107 return d._offset, nil 108 } 109 110 func (d *Partition) ReadAll(fullPath string) (buf []byte, err error) { 111 fullPath = strings.TrimPrefix(fullPath, "/") 112 path := strings.Split(fullPath, "/") 113 114 bgd, err := d.getBlockGroupDescriptor(ext4.InodeRootDirectory) 115 116 if err != nil { 117 return 118 } 119 120 dw, err := ext4.NewDirectoryWalk(d, bgd, ext4.InodeRootDirectory) 121 122 var i int 123 var inodeNumber int 124 125 for { 126 if err != nil { 127 return 128 } 129 130 p, de, err := dw.Next() 131 132 if err == io.EOF { 133 break 134 } else if err != nil { 135 return nil, err 136 } 137 138 deInode := int(de.Data().Inode) 139 140 bgd, err = d.getBlockGroupDescriptor(deInode) 141 142 if err != nil { 143 return nil, err 144 } 145 146 if p == path[i] { 147 if i == len(path)-1 { 148 inodeNumber = deInode 149 break 150 } else { 151 dw, err = ext4.NewDirectoryWalk(d, bgd, deInode) 152 153 if err != nil { 154 return nil, err 155 } 156 157 i += 1 158 } 159 } 160 } 161 162 if inodeNumber == 0 { 163 return nil, errors.New("file not found") 164 } 165 166 inode, err := ext4.NewInodeWithReadSeeker(bgd, d, inodeNumber) 167 168 if err != nil { 169 return 170 } 171 172 en := ext4.NewExtentNavigatorWithReadSeeker(d, inode) 173 r := ext4.NewInodeReader(en) 174 175 return io.ReadAll(r) 176 }