github.com/ratrocket/u-root@v0.0.0-20180201221235-1cf9f48ee2cf/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 "io/ioutil" 12 "os" 13 "time" 14 15 "golang.org/x/sys/unix" 16 ) 17 18 const Trailer = "TRAILER!!!" 19 20 type Record struct { 21 io.ReadCloser 22 Info 23 } 24 25 var TrailerRecord = StaticRecord(nil, Info{Name: Trailer}) 26 27 type RecordReader interface { 28 ReadRecord() (Record, error) 29 } 30 31 type RecordWriter interface { 32 WriteRecord(Record) error 33 } 34 35 type RecordFormat interface { 36 Reader(r io.ReaderAt) RecordReader 37 Writer(w io.Writer) RecordWriter 38 } 39 40 func StaticRecord(contents []byte, info Info) Record { 41 info.FileSize = uint64(len(contents)) 42 return Record{ 43 ReadCloser: ioutil.NopCloser(bytes.NewReader(contents)), 44 Info: info, 45 } 46 } 47 48 func StaticFile(name string, content string, perm uint64) Record { 49 return StaticRecord([]byte(content), Info{ 50 Name: name, 51 Mode: unix.S_IFREG | perm, 52 }) 53 } 54 55 // Symlink returns a symlink record at name pointing to target. 56 func Symlink(name string, target string) Record { 57 return Record{ 58 ReadCloser: ioutil.NopCloser(bytes.NewReader([]byte(target))), 59 Info: Info{ 60 FileSize: uint64(len(target)), 61 Mode: unix.S_IFLNK | 0777, 62 Name: name, 63 }, 64 } 65 } 66 67 // Directory returns a directory record at `name`. 68 func Directory(name string, mode uint64) Record { 69 return Record{ 70 Info: Info{ 71 Name: name, 72 Mode: unix.S_IFDIR | mode&^unix.S_IFMT, 73 }, 74 } 75 } 76 77 // CharDev returns a character device record at `name`. 78 func CharDev(name string, perm uint64, rmajor, rminor uint64) Record { 79 return Record{ 80 Info: Info{ 81 Name: name, 82 Mode: unix.S_IFCHR | perm, 83 Rmajor: rmajor, 84 Rminor: rminor, 85 }, 86 } 87 } 88 89 func NewBytesReadCloser(contents []byte) io.ReadCloser { 90 return ioutil.NopCloser(bytes.NewReader(contents)) 91 } 92 93 func NewReadCloser(r io.Reader) io.ReadCloser { 94 return ioutil.NopCloser(r) 95 } 96 97 type LazyOpen struct { 98 Name string 99 File *os.File 100 } 101 102 func (r *LazyOpen) Read(p []byte) (int, error) { 103 if r.File == nil { 104 f, err := os.Open(r.Name) 105 if err != nil { 106 return -1, err 107 } 108 r.File = f 109 } 110 return r.File.Read(p) 111 } 112 113 func (r *LazyOpen) Close() error { 114 return r.File.Close() 115 } 116 117 func NewDeferReadCloser(name string) io.ReadCloser { 118 return &LazyOpen{Name: name} 119 } 120 121 // Info holds metadata about files. 122 type Info struct { 123 Ino uint64 124 Mode uint64 125 UID uint64 126 GID uint64 127 NLink uint64 128 MTime uint64 129 FileSize uint64 130 Dev uint64 131 Major uint64 132 Minor uint64 133 Rmajor uint64 134 Rminor uint64 135 Name string 136 } 137 138 func Equal(r Record, s Record) bool { 139 if r.Info != s.Info { 140 return false 141 } 142 return ReadCloserEqual(r.ReadCloser, s.ReadCloser) 143 } 144 145 func ReadCloserEqual(r1, r2 io.ReadCloser) bool { 146 var c, d []byte 147 var err error 148 if r1 != nil { 149 c, err = ioutil.ReadAll(r1) 150 if err != nil { 151 return false 152 } 153 } 154 155 if r2 != nil { 156 d, err = ioutil.ReadAll(r2) 157 if err != nil { 158 return false 159 } 160 } 161 return bytes.Equal(c, d) 162 } 163 164 func (i Info) String() string { 165 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", 166 i.Name, 167 i.Ino, 168 i.Mode, 169 i.UID, 170 i.GID, 171 i.NLink, 172 time.Unix(int64(i.MTime), 0).UTC(), 173 i.FileSize, 174 i.Major, 175 i.Minor, 176 i.Rmajor, 177 i.Rminor) 178 }