github.com/ratrocket/u-root@v0.0.0-20180201221235-1cf9f48ee2cf/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  	"io/ioutil"
    12  	"os"
    13  	"time"
    14  
    15  	"golang.org/x/sys/unix"
    16  )
    17  
    18  const Trailer = "TRAILER!!!"
    19  
    20  type Record struct {
    21  	io.ReadCloser
    22  	Info
    23  }
    24  
    25  var TrailerRecord = StaticRecord(nil, Info{Name: Trailer})
    26  
    27  type RecordReader interface {
    28  	ReadRecord() (Record, error)
    29  }
    30  
    31  type RecordWriter interface {
    32  	WriteRecord(Record) error
    33  }
    34  
    35  type RecordFormat interface {
    36  	Reader(r io.ReaderAt) RecordReader
    37  	Writer(w io.Writer) RecordWriter
    38  }
    39  
    40  func StaticRecord(contents []byte, info Info) Record {
    41  	info.FileSize = uint64(len(contents))
    42  	return Record{
    43  		ReadCloser: ioutil.NopCloser(bytes.NewReader(contents)),
    44  		Info:       info,
    45  	}
    46  }
    47  
    48  func StaticFile(name string, content string, perm uint64) Record {
    49  	return StaticRecord([]byte(content), Info{
    50  		Name: name,
    51  		Mode: unix.S_IFREG | perm,
    52  	})
    53  }
    54  
    55  // Symlink returns a symlink record at name pointing to target.
    56  func Symlink(name string, target string) Record {
    57  	return Record{
    58  		ReadCloser: ioutil.NopCloser(bytes.NewReader([]byte(target))),
    59  		Info: Info{
    60  			FileSize: uint64(len(target)),
    61  			Mode:     unix.S_IFLNK | 0777,
    62  			Name:     name,
    63  		},
    64  	}
    65  }
    66  
    67  // Directory returns a directory record at `name`.
    68  func Directory(name string, mode uint64) Record {
    69  	return Record{
    70  		Info: Info{
    71  			Name: name,
    72  			Mode: unix.S_IFDIR | mode&^unix.S_IFMT,
    73  		},
    74  	}
    75  }
    76  
    77  // CharDev returns a character device record at `name`.
    78  func CharDev(name string, perm uint64, rmajor, rminor uint64) Record {
    79  	return Record{
    80  		Info: Info{
    81  			Name:   name,
    82  			Mode:   unix.S_IFCHR | perm,
    83  			Rmajor: rmajor,
    84  			Rminor: rminor,
    85  		},
    86  	}
    87  }
    88  
    89  func NewBytesReadCloser(contents []byte) io.ReadCloser {
    90  	return ioutil.NopCloser(bytes.NewReader(contents))
    91  }
    92  
    93  func NewReadCloser(r io.Reader) io.ReadCloser {
    94  	return ioutil.NopCloser(r)
    95  }
    96  
    97  type LazyOpen struct {
    98  	Name string
    99  	File *os.File
   100  }
   101  
   102  func (r *LazyOpen) Read(p []byte) (int, error) {
   103  	if r.File == nil {
   104  		f, err := os.Open(r.Name)
   105  		if err != nil {
   106  			return -1, err
   107  		}
   108  		r.File = f
   109  	}
   110  	return r.File.Read(p)
   111  }
   112  
   113  func (r *LazyOpen) Close() error {
   114  	return r.File.Close()
   115  }
   116  
   117  func NewDeferReadCloser(name string) io.ReadCloser {
   118  	return &LazyOpen{Name: name}
   119  }
   120  
   121  // Info holds metadata about files.
   122  type Info struct {
   123  	Ino      uint64
   124  	Mode     uint64
   125  	UID      uint64
   126  	GID      uint64
   127  	NLink    uint64
   128  	MTime    uint64
   129  	FileSize uint64
   130  	Dev      uint64
   131  	Major    uint64
   132  	Minor    uint64
   133  	Rmajor   uint64
   134  	Rminor   uint64
   135  	Name     string
   136  }
   137  
   138  func Equal(r Record, s Record) bool {
   139  	if r.Info != s.Info {
   140  		return false
   141  	}
   142  	return ReadCloserEqual(r.ReadCloser, s.ReadCloser)
   143  }
   144  
   145  func ReadCloserEqual(r1, r2 io.ReadCloser) bool {
   146  	var c, d []byte
   147  	var err error
   148  	if r1 != nil {
   149  		c, err = ioutil.ReadAll(r1)
   150  		if err != nil {
   151  			return false
   152  		}
   153  	}
   154  
   155  	if r2 != nil {
   156  		d, err = ioutil.ReadAll(r2)
   157  		if err != nil {
   158  			return false
   159  		}
   160  	}
   161  	return bytes.Equal(c, d)
   162  }
   163  
   164  func (i Info) String() string {
   165  	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",
   166  		i.Name,
   167  		i.Ino,
   168  		i.Mode,
   169  		i.UID,
   170  		i.GID,
   171  		i.NLink,
   172  		time.Unix(int64(i.MTime), 0).UTC(),
   173  		i.FileSize,
   174  		i.Major,
   175  		i.Minor,
   176  		i.Rmajor,
   177  		i.Rminor)
   178  }