github.com/oweisse/u-root@v0.0.0-20181109060735-d005ad25fef1/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/ls"
    16  	"github.com/u-root/u-root/pkg/uio"
    17  	"golang.org/x/sys/unix"
    18  )
    19  
    20  // Record represents a CPIO record, which represents a Unix file.
    21  type Record struct {
    22  	// ReaderAt contains the content of this CPIO record.
    23  	io.ReaderAt
    24  
    25  	// Info is metadata describing the CPIO record.
    26  	Info
    27  
    28  	// metadata about this item's place in the file
    29  	RecPos  int64  // Where in the file this record is
    30  	RecLen  uint64 // How big the record is.
    31  	FilePos int64  // Where in the CPIO the file's contents are.
    32  }
    33  
    34  // String implements a fmt.Stringer for Record.
    35  //
    36  // String returns a string formatted like `ls` would format it.
    37  func (r Record) String() string {
    38  	s := ls.LongStringer{
    39  		Human: true,
    40  		Name:  ls.NameStringer{},
    41  	}
    42  	return s.FileString(LSInfoFromRecord(r))
    43  }
    44  
    45  // Trailer is the name of the trailer record.
    46  const Trailer = "TRAILER!!!"
    47  
    48  // TrailerRecord is the last record in any CPIO archive.
    49  var TrailerRecord = StaticRecord(nil, Info{Name: Trailer})
    50  
    51  func StaticRecord(contents []byte, info Info) Record {
    52  	info.FileSize = uint64(len(contents))
    53  	return Record{
    54  		ReaderAt: bytes.NewReader(contents),
    55  		Info:     info,
    56  	}
    57  }
    58  
    59  func StaticFile(name string, content string, perm uint64) Record {
    60  	return StaticRecord([]byte(content), Info{
    61  		Name: name,
    62  		Mode: unix.S_IFREG | perm,
    63  	})
    64  }
    65  
    66  // Symlink returns a symlink record at name pointing to target.
    67  func Symlink(name string, target string) Record {
    68  	return Record{
    69  		ReaderAt: strings.NewReader(target),
    70  		Info: Info{
    71  			FileSize: uint64(len(target)),
    72  			Mode:     unix.S_IFLNK | 0777,
    73  			Name:     name,
    74  		},
    75  	}
    76  }
    77  
    78  // Directory returns a directory record at name.
    79  func Directory(name string, mode uint64) Record {
    80  	return Record{
    81  		Info: Info{
    82  			Name: name,
    83  			Mode: unix.S_IFDIR | mode&^unix.S_IFMT,
    84  		},
    85  	}
    86  }
    87  
    88  // CharDev returns a character device record at name.
    89  func CharDev(name string, perm uint64, rmajor, rminor uint64) Record {
    90  	return Record{
    91  		Info: Info{
    92  			Name:   name,
    93  			Mode:   unix.S_IFCHR | perm,
    94  			Rmajor: rmajor,
    95  			Rminor: rminor,
    96  		},
    97  	}
    98  }
    99  
   100  func NewLazyFile(name string) io.ReaderAt {
   101  	return uio.NewLazyOpenerAt(func() (io.ReaderAt, error) {
   102  		return os.Open(name)
   103  	})
   104  }
   105  
   106  // Info holds metadata about files.
   107  type Info struct {
   108  	Ino      uint64
   109  	Mode     uint64
   110  	UID      uint64
   111  	GID      uint64
   112  	NLink    uint64
   113  	MTime    uint64
   114  	FileSize uint64
   115  	Dev      uint64
   116  	Major    uint64
   117  	Minor    uint64
   118  	Rmajor   uint64
   119  	Rminor   uint64
   120  	Name     string
   121  }
   122  
   123  func (i Info) String() string {
   124  	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",
   125  		i.Name,
   126  		i.Ino,
   127  		i.Mode,
   128  		i.UID,
   129  		i.GID,
   130  		i.NLink,
   131  		time.Unix(int64(i.MTime), 0).UTC(),
   132  		i.FileSize,
   133  		i.Major,
   134  		i.Minor,
   135  		i.Rmajor,
   136  		i.Rminor)
   137  }
   138  
   139  func AllEqual(r []Record, s []Record) bool {
   140  	if len(r) != len(s) {
   141  		return false
   142  	}
   143  	for i := range r {
   144  		if !Equal(r[i], s[i]) {
   145  			return false
   146  		}
   147  	}
   148  	return true
   149  }
   150  
   151  func Equal(r Record, s Record) bool {
   152  	if r.Info != s.Info {
   153  		return false
   154  	}
   155  	return ReaderAtEqual(r.ReaderAt, s.ReaderAt)
   156  }
   157  
   158  func ReaderAtEqual(r1, r2 io.ReaderAt) bool {
   159  	var c, d []byte
   160  	var err error
   161  	if r1 != nil {
   162  		c, err = uio.ReadAll(r1)
   163  		if err != nil {
   164  			return false
   165  		}
   166  	}
   167  
   168  	if r2 != nil {
   169  		d, err = uio.ReadAll(r2)
   170  		if err != nil {
   171  			return false
   172  		}
   173  	}
   174  	return bytes.Equal(c, d)
   175  }