github.com/oweisse/u-root@v0.0.0-20181109060735-d005ad25fef1/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 "os" 12 "strings" 13 "time" 14 15 "github.com/u-root/u-root/pkg/ls" 16 "github.com/u-root/u-root/pkg/uio" 17 "golang.org/x/sys/unix" 18 ) 19 20 // Record represents a CPIO record, which represents a Unix file. 21 type Record struct { 22 // ReaderAt contains the content of this CPIO record. 23 io.ReaderAt 24 25 // Info is metadata describing the CPIO record. 26 Info 27 28 // metadata about this item's place in the file 29 RecPos int64 // Where in the file this record is 30 RecLen uint64 // How big the record is. 31 FilePos int64 // Where in the CPIO the file's contents are. 32 } 33 34 // String implements a fmt.Stringer for Record. 35 // 36 // String returns a string formatted like `ls` would format it. 37 func (r Record) String() string { 38 s := ls.LongStringer{ 39 Human: true, 40 Name: ls.NameStringer{}, 41 } 42 return s.FileString(LSInfoFromRecord(r)) 43 } 44 45 // Trailer is the name of the trailer record. 46 const Trailer = "TRAILER!!!" 47 48 // TrailerRecord is the last record in any CPIO archive. 49 var TrailerRecord = StaticRecord(nil, Info{Name: Trailer}) 50 51 func StaticRecord(contents []byte, info Info) Record { 52 info.FileSize = uint64(len(contents)) 53 return Record{ 54 ReaderAt: bytes.NewReader(contents), 55 Info: info, 56 } 57 } 58 59 func StaticFile(name string, content string, perm uint64) Record { 60 return StaticRecord([]byte(content), Info{ 61 Name: name, 62 Mode: unix.S_IFREG | perm, 63 }) 64 } 65 66 // Symlink returns a symlink record at name pointing to target. 67 func Symlink(name string, target string) Record { 68 return Record{ 69 ReaderAt: strings.NewReader(target), 70 Info: Info{ 71 FileSize: uint64(len(target)), 72 Mode: unix.S_IFLNK | 0777, 73 Name: name, 74 }, 75 } 76 } 77 78 // Directory returns a directory record at name. 79 func Directory(name string, mode uint64) Record { 80 return Record{ 81 Info: Info{ 82 Name: name, 83 Mode: unix.S_IFDIR | mode&^unix.S_IFMT, 84 }, 85 } 86 } 87 88 // CharDev returns a character device record at name. 89 func CharDev(name string, perm uint64, rmajor, rminor uint64) Record { 90 return Record{ 91 Info: Info{ 92 Name: name, 93 Mode: unix.S_IFCHR | perm, 94 Rmajor: rmajor, 95 Rminor: rminor, 96 }, 97 } 98 } 99 100 func NewLazyFile(name string) io.ReaderAt { 101 return uio.NewLazyOpenerAt(func() (io.ReaderAt, error) { 102 return os.Open(name) 103 }) 104 } 105 106 // Info holds metadata about files. 107 type Info struct { 108 Ino uint64 109 Mode uint64 110 UID uint64 111 GID uint64 112 NLink uint64 113 MTime uint64 114 FileSize uint64 115 Dev uint64 116 Major uint64 117 Minor uint64 118 Rmajor uint64 119 Rminor uint64 120 Name string 121 } 122 123 func (i Info) String() string { 124 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", 125 i.Name, 126 i.Ino, 127 i.Mode, 128 i.UID, 129 i.GID, 130 i.NLink, 131 time.Unix(int64(i.MTime), 0).UTC(), 132 i.FileSize, 133 i.Major, 134 i.Minor, 135 i.Rmajor, 136 i.Rminor) 137 } 138 139 func AllEqual(r []Record, s []Record) bool { 140 if len(r) != len(s) { 141 return false 142 } 143 for i := range r { 144 if !Equal(r[i], s[i]) { 145 return false 146 } 147 } 148 return true 149 } 150 151 func Equal(r Record, s Record) bool { 152 if r.Info != s.Info { 153 return false 154 } 155 return ReaderAtEqual(r.ReaderAt, s.ReaderAt) 156 } 157 158 func ReaderAtEqual(r1, r2 io.ReaderAt) bool { 159 var c, d []byte 160 var err error 161 if r1 != nil { 162 c, err = uio.ReadAll(r1) 163 if err != nil { 164 return false 165 } 166 } 167 168 if r2 != nil { 169 d, err = uio.ReadAll(r2) 170 if err != nil { 171 return false 172 } 173 } 174 return bytes.Equal(c, d) 175 }