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