gitlab.com/apertussolutions/u-root@v7.0.0+incompatible/pkg/cpio/cpio.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 implements utilities for reading and writing cpio archives.
     6  //
     7  // Currently, only newc-formatted cpio archives are supported through cpio.Newc.
     8  //
     9  // Reading from or writing to a file:
    10  //
    11  //    f, err := os.Open(...)
    12  //    if err ...
    13  //    recReader := cpio.Newc.Reader(f)
    14  //    err := ForEachRecord(recReader, func(r cpio.Record) error {
    15  //
    16  //    })
    17  //
    18  //    // Or...
    19  //    recWriter := cpio.Newc.Writer(f)
    20  //
    21  //
    22  // Reading from or writing to an in-memory archive:
    23  //
    24  //    a := cpio.InMemArchive()
    25  //    err := a.WriteRecord(...)
    26  //
    27  //    recReader := a.Reader() // Reads from the "beginning."
    28  //
    29  //    if a.Contains("bar/foo") {
    30  //
    31  //    }
    32  package cpio
    33  
    34  import (
    35  	"fmt"
    36  	"io"
    37  	"os"
    38  	"time"
    39  
    40  	"github.com/u-root/u-root/pkg/ls"
    41  )
    42  
    43  var (
    44  	formatMap = make(map[string]RecordFormat)
    45  
    46  	// Debug can be set e.g. to log.Printf to enable debug prints from
    47  	// marshaling/unmarshaling cpio archives.
    48  	Debug = func(string, ...interface{}) {}
    49  )
    50  
    51  // Record represents a CPIO record, which represents a Unix file.
    52  type Record struct {
    53  	// ReaderAt contains the content of this CPIO record.
    54  	io.ReaderAt
    55  
    56  	// Info is metadata describing the CPIO record.
    57  	Info
    58  
    59  	// metadata about this item's place in the file
    60  	RecPos  int64  // Where in the file this record is
    61  	RecLen  uint64 // How big the record is.
    62  	FilePos int64  // Where in the CPIO the file's contents are.
    63  }
    64  
    65  // String implements a fmt.Stringer for Record.
    66  //
    67  // String returns a string long-formatted like `ls` would format it.
    68  func (r Record) String() string {
    69  	s := ls.LongStringer{
    70  		Human: true,
    71  		Name:  ls.NameStringer{},
    72  	}
    73  	return s.FileString(LSInfoFromRecord(r))
    74  }
    75  
    76  // Info holds metadata about files.
    77  type Info struct {
    78  	Ino      uint64
    79  	Mode     uint64
    80  	UID      uint64
    81  	GID      uint64
    82  	NLink    uint64
    83  	MTime    uint64
    84  	FileSize uint64
    85  	Dev      uint64
    86  	Major    uint64
    87  	Minor    uint64
    88  	Rmajor   uint64
    89  	Rminor   uint64
    90  	Name     string
    91  }
    92  
    93  func (i Info) String() string {
    94  	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",
    95  		i.Name,
    96  		i.Ino,
    97  		i.Mode,
    98  		i.UID,
    99  		i.GID,
   100  		i.NLink,
   101  		time.Unix(int64(i.MTime), 0).UTC(),
   102  		i.FileSize,
   103  		i.Major,
   104  		i.Minor,
   105  		i.Rmajor,
   106  		i.Rminor)
   107  }
   108  
   109  // A RecordReader reads one record from an archive.
   110  type RecordReader interface {
   111  	ReadRecord() (Record, error)
   112  }
   113  
   114  // A RecordWriter writes one record to an archive.
   115  type RecordWriter interface {
   116  	WriteRecord(Record) error
   117  }
   118  
   119  // A RecordFormat gives readers and writers for dealing with archives from io
   120  // objects.
   121  //
   122  // CPIO files have a number of records, of which newc is the most widely used
   123  // today.
   124  type RecordFormat interface {
   125  	Reader(r io.ReaderAt) RecordReader
   126  	Writer(w io.Writer) RecordWriter
   127  }
   128  
   129  // Format returns the RecordFormat with that name, if it exists.
   130  func Format(name string) (RecordFormat, error) {
   131  	op, ok := formatMap[name]
   132  	if !ok {
   133  		return nil, fmt.Errorf("%q is not in cpio format map %v", name, formatMap)
   134  	}
   135  	return op, nil
   136  }
   137  
   138  func modeFromLinux(mode uint64) os.FileMode {
   139  	m := os.FileMode(mode & 0777)
   140  	switch mode & S_IFMT {
   141  	case S_IFBLK:
   142  		m |= os.ModeDevice
   143  	case S_IFCHR:
   144  		m |= os.ModeDevice | os.ModeCharDevice
   145  	case S_IFDIR:
   146  		m |= os.ModeDir
   147  	case S_IFIFO:
   148  		m |= os.ModeNamedPipe
   149  	case S_IFLNK:
   150  		m |= os.ModeSymlink
   151  	case S_IFREG:
   152  		// nothing to do
   153  	case S_IFSOCK:
   154  		m |= os.ModeSocket
   155  	}
   156  	if mode&S_ISGID != 0 {
   157  		m |= os.ModeSetgid
   158  	}
   159  	if mode&S_ISUID != 0 {
   160  		m |= os.ModeSetuid
   161  	}
   162  	if mode&S_ISVTX != 0 {
   163  		m |= os.ModeSticky
   164  	}
   165  	return m
   166  }