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  }