github.hscsec.cn/u-root/u-root@v7.0.0+incompatible/cmds/core/cpio/cpio.go (about)

     1  // Copyright 2013-2020 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  // cpio operates on cpio files using a cpio package
     6  // It only implements basic cpio options.
     7  //
     8  //
     9  // Synopsis:
    10  //     cpio
    11  //
    12  // Description:
    13  //
    14  // Options:
    15  //     o: output an archive to stdout given a pattern
    16  //     i: output files from a stdin stream
    17  //     t: print table of contents
    18  //     -v: debug prints
    19  //
    20  // Bugs: in i mode, it can't use non-seekable stdin, i.e. a pipe. Yep, this sucks.
    21  // But if we implement seek on such things, we have to do it by reading, which
    22  // really sucks. It's doable, we'll do it if we have to, but for now I'd like
    23  // to avoid the complexity. cpio is a 40 year old concept. If you want something
    24  // better, see ../archive which has a VTOC and separates data from metadata (unlike cpio).
    25  // We could test for ESPIPE and fix it that way ... later.
    26  package main
    27  
    28  import (
    29  	"bufio"
    30  	"flag"
    31  	"fmt"
    32  	"io"
    33  	"log"
    34  	"os"
    35  
    36  	"github.com/u-root/u-root/pkg/cpio"
    37  )
    38  
    39  var (
    40  	debug  = func(string, ...interface{}) {}
    41  	d      = flag.Bool("v", false, "Debug prints")
    42  	format = flag.String("H", "newc", "format")
    43  )
    44  
    45  func usage() {
    46  	log.Fatalf("Usage: cpio")
    47  }
    48  
    49  func main() {
    50  	flag.Parse()
    51  	if *d {
    52  		debug = log.Printf
    53  	}
    54  
    55  	a := flag.Args()
    56  	debug("Args %v", a)
    57  	if len(a) < 1 {
    58  		usage()
    59  	}
    60  	op := a[0]
    61  
    62  	archiver, err := cpio.Format(*format)
    63  	if err != nil {
    64  		log.Fatalf("Format %q not supported: %v", *format, err)
    65  	}
    66  
    67  	switch op {
    68  	case "i":
    69  		var inums map[uint64]string
    70  		inums = make(map[uint64]string)
    71  
    72  		rr := archiver.Reader(os.Stdin)
    73  		for {
    74  			rec, err := rr.ReadRecord()
    75  			if err == io.EOF {
    76  				break
    77  			}
    78  			if err != nil {
    79  				log.Fatalf("error reading records: %v", err)
    80  			}
    81  			debug("Creating %s\n", rec)
    82  
    83  			// A file with zero size could be a hard link to another file
    84  			// in the archive. The file with contents always comes first.
    85  			if rec.Info.FileSize == 0 {
    86  				if _, ok := inums[rec.Info.Ino]; ok {
    87  					err := os.Link(inums[rec.Info.Ino], rec.Name)
    88  					if err != nil {
    89  						log.Fatal(err)
    90  					}
    91  					continue
    92  				}
    93  			}
    94  			inums[rec.Info.Ino] = rec.Name
    95  			if err := cpio.CreateFile(rec); err != nil {
    96  				log.Printf("Creating %q failed: %v", rec.Name, err)
    97  			}
    98  		}
    99  
   100  	case "o":
   101  		rw := archiver.Writer(os.Stdout)
   102  		cr := cpio.NewRecorder()
   103  		scanner := bufio.NewScanner(os.Stdin)
   104  
   105  		for scanner.Scan() {
   106  			name := scanner.Text()
   107  			rec, err := cr.GetRecord(name)
   108  			if err != nil {
   109  				log.Fatalf("Getting record of %q failed: %v", name, err)
   110  			}
   111  			if err := rw.WriteRecord(rec); err != nil {
   112  				log.Fatalf("Writing record %q failed: %v", name, err)
   113  			}
   114  		}
   115  
   116  		if err := scanner.Err(); err != nil {
   117  			log.Fatalf("Error reading stdin: %v", err)
   118  		}
   119  		if err := cpio.WriteTrailer(rw); err != nil {
   120  			log.Fatalf("Error writing trailer record: %v", err)
   121  		}
   122  
   123  	case "t":
   124  		rr := archiver.Reader(os.Stdin)
   125  		for {
   126  			rec, err := rr.ReadRecord()
   127  			if err == io.EOF {
   128  				break
   129  			}
   130  			if err != nil {
   131  				log.Fatalf("error reading records: %v", err)
   132  			}
   133  			fmt.Println(rec)
   134  		}
   135  
   136  	default:
   137  		usage()
   138  	}
   139  }