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 }