github.com/mvdan/u-root-coreutils@v0.0.0-20230122170626-c2eef2898555/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 // Reading from or writing to an in-memory archive: 22 // 23 // a := cpio.InMemArchive() 24 // err := a.WriteRecord(...) 25 // 26 // recReader := a.Reader() // Reads from the "beginning." 27 // 28 // if a.Contains("bar/foo") { 29 // 30 // } 31 package cpio 32 33 import ( 34 "fmt" 35 "io" 36 "os" 37 "time" 38 39 "github.com/mvdan/u-root-coreutils/pkg/ls" 40 ) 41 42 var ( 43 formatMap = make(map[string]RecordFormat) 44 45 // Debug can be set e.g. to log.Printf to enable debug prints from 46 // marshaling/unmarshaling cpio archives. 47 Debug = func(string, ...interface{}) {} 48 ) 49 50 // Record represents a CPIO record, which represents a Unix file. 51 type Record struct { 52 // ReaderAt contains the content of this CPIO record. 53 io.ReaderAt 54 55 // Info is metadata describing the CPIO record. 56 Info 57 58 // metadata about this item's place in the file 59 RecPos int64 // Where in the file this record is 60 RecLen uint64 // How big the record is. 61 FilePos int64 // Where in the CPIO the file's contents are. 62 } 63 64 // String implements a fmt.Stringer for Record. 65 // 66 // String returns a string long-formatted like `ls` would format it. 67 func (r Record) String() string { 68 s := ls.LongStringer{ 69 Human: true, 70 Name: ls.NameStringer{}, 71 } 72 return s.FileString(LSInfoFromRecord(r)) 73 } 74 75 // Info holds metadata about files. 76 type Info struct { 77 Ino uint64 78 Mode uint64 79 UID uint64 80 GID uint64 81 NLink uint64 82 MTime uint64 83 FileSize uint64 84 Dev uint64 85 Major uint64 86 Minor uint64 87 Rmajor uint64 88 Rminor uint64 89 Name string 90 } 91 92 func (i Info) String() string { 93 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", 94 i.Name, 95 i.Ino, 96 i.Mode, 97 i.UID, 98 i.GID, 99 i.NLink, 100 time.Unix(int64(i.MTime), 0).UTC(), 101 i.FileSize, 102 i.Major, 103 i.Minor, 104 i.Rmajor, 105 i.Rminor) 106 } 107 108 // A RecordReader reads one record from an archive. 109 type RecordReader interface { 110 ReadRecord() (Record, error) 111 } 112 113 // A RecordWriter writes one record to an archive. 114 type RecordWriter interface { 115 WriteRecord(Record) error 116 } 117 118 // A RecordFormat gives readers and writers for dealing with archives from io 119 // objects. 120 // 121 // CPIO files have a number of records, of which newc is the most widely used 122 // today. 123 type RecordFormat interface { 124 Reader(r io.ReaderAt) RecordReader 125 NewFileReader(*os.File) (RecordReader, error) 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 & 0o777) 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 }