github.com/jlowellwofford/u-root@v1.0.0/pkg/cpio/types.go (about)

     1  // Copyright 2013-2017 the u-root Authors. All rights reserved
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package cpio
     6  
     7  import (
     8  	"bytes"
     9  	"fmt"
    10  	"io"
    11  	"os"
    12  	"strings"
    13  	"time"
    14  
    15  	"github.com/u-root/u-root/pkg/uio"
    16  	"golang.org/x/sys/unix"
    17  )
    18  
    19  // Record represents a CPIO record, which represents a Unix file.
    20  type Record struct {
    21  	// ReaderAt contains the content of this CPIO record.
    22  	io.ReaderAt
    23  
    24  	// Info is metadata describing the CPIO record.
    25  	Info
    26  }
    27  
    28  // Trailer is the name of the trailer record.
    29  const Trailer = "TRAILER!!!"
    30  
    31  // TrailerRecord is the last record in any CPIO archive.
    32  var TrailerRecord = StaticRecord(nil, Info{Name: Trailer})
    33  
    34  func StaticRecord(contents []byte, info Info) Record {
    35  	info.FileSize = uint64(len(contents))
    36  	return Record{
    37  		ReaderAt: bytes.NewReader(contents),
    38  		Info:     info,
    39  	}
    40  }
    41  
    42  func StaticFile(name string, content string, perm uint64) Record {
    43  	return StaticRecord([]byte(content), Info{
    44  		Name: name,
    45  		Mode: unix.S_IFREG | perm,
    46  	})
    47  }
    48  
    49  // Symlink returns a symlink record at name pointing to target.
    50  func Symlink(name string, target string) Record {
    51  	return Record{
    52  		ReaderAt: strings.NewReader(target),
    53  		Info: Info{
    54  			FileSize: uint64(len(target)),
    55  			Mode:     unix.S_IFLNK | 0777,
    56  			Name:     name,
    57  		},
    58  	}
    59  }
    60  
    61  // Directory returns a directory record at name.
    62  func Directory(name string, mode uint64) Record {
    63  	return Record{
    64  		Info: Info{
    65  			Name: name,
    66  			Mode: unix.S_IFDIR | mode&^unix.S_IFMT,
    67  		},
    68  	}
    69  }
    70  
    71  // CharDev returns a character device record at name.
    72  func CharDev(name string, perm uint64, rmajor, rminor uint64) Record {
    73  	return Record{
    74  		Info: Info{
    75  			Name:   name,
    76  			Mode:   unix.S_IFCHR | perm,
    77  			Rmajor: rmajor,
    78  			Rminor: rminor,
    79  		},
    80  	}
    81  }
    82  
    83  func NewLazyFile(name string) io.ReaderAt {
    84  	return uio.NewLazyOpenerAt(func() (io.ReaderAt, error) {
    85  		return os.Open(name)
    86  	})
    87  }
    88  
    89  // Info holds metadata about files.
    90  type Info struct {
    91  	Ino      uint64
    92  	Mode     uint64
    93  	UID      uint64
    94  	GID      uint64
    95  	NLink    uint64
    96  	MTime    uint64
    97  	FileSize uint64
    98  	Dev      uint64
    99  	Major    uint64
   100  	Minor    uint64
   101  	Rmajor   uint64
   102  	Rminor   uint64
   103  	Name     string
   104  }
   105  
   106  func (i Info) String() string {
   107  	return fmt.Sprintf("%s: Ino %d Mode %#o UID %d GID %d NLink %d MTime %v FileSize %d Major %d Minor %d Rmajor %d Rminor %d",
   108  		i.Name,
   109  		i.Ino,
   110  		i.Mode,
   111  		i.UID,
   112  		i.GID,
   113  		i.NLink,
   114  		time.Unix(int64(i.MTime), 0).UTC(),
   115  		i.FileSize,
   116  		i.Major,
   117  		i.Minor,
   118  		i.Rmajor,
   119  		i.Rminor)
   120  }
   121  
   122  func AllEqual(r []Record, s []Record) bool {
   123  	if len(r) != len(s) {
   124  		return false
   125  	}
   126  	for i := range r {
   127  		if !Equal(r[i], s[i]) {
   128  			return false
   129  		}
   130  	}
   131  	return true
   132  }
   133  
   134  func Equal(r Record, s Record) bool {
   135  	if r.Info != s.Info {
   136  		return false
   137  	}
   138  	return ReaderAtEqual(r.ReaderAt, s.ReaderAt)
   139  }
   140  
   141  func ReaderAtEqual(r1, r2 io.ReaderAt) bool {
   142  	var c, d []byte
   143  	var err error
   144  	if r1 != nil {
   145  		c, err = uio.ReadAll(r1)
   146  		if err != nil {
   147  			return false
   148  		}
   149  	}
   150  
   151  	if r2 != nil {
   152  		d, err = uio.ReadAll(r2)
   153  		if err != nil {
   154  			return false
   155  		}
   156  	}
   157  	return bytes.Equal(c, d)
   158  }