github.com/openshift/installer@v1.4.17/pkg/asset/agent/image/cpio.go (about) 1 package image 2 3 import ( 4 "bytes" 5 "compress/gzip" 6 "fmt" 7 "io" 8 "os" 9 "path/filepath" 10 11 "github.com/cavaliercoder/go-cpio" 12 ) 13 14 // CpioArchive simplifies the creation of a compressed cpio archive. 15 type CpioArchive struct { 16 buffer *bytes.Buffer 17 gzipWriter *gzip.Writer 18 cpioWriter *cpio.Writer 19 } 20 21 // NewCpioArchive creates a new CpioArchive instance. 22 func NewCpioArchive() *CpioArchive { 23 buf := new(bytes.Buffer) 24 gw := gzip.NewWriter(buf) 25 cw := cpio.NewWriter(gw) 26 27 return &CpioArchive{ 28 buffer: buf, 29 gzipWriter: gw, 30 cpioWriter: cw, 31 } 32 } 33 34 // StoreBytes appends to the current archive the given content using 35 // the specified filename. 36 func (ca *CpioArchive) StoreBytes(filename string, content []byte, mode int) error { 37 header := cpio.Header{ 38 Name: filename, 39 Mode: cpio.FileMode(mode), 40 Size: int64(len(content)), 41 } 42 43 err := ca.cpioWriter.WriteHeader(&header) 44 if err != nil { 45 return err 46 } 47 48 _, err = ca.cpioWriter.Write(content) 49 if err != nil { 50 return err 51 } 52 53 return nil 54 } 55 56 // StorePath adds a new path in the archive. 57 func (ca *CpioArchive) StorePath(path string) error { 58 header := cpio.Header{ 59 Name: path, 60 Mode: cpio.ModeDir | 0o755, 61 Size: 0, 62 } 63 64 err := ca.cpioWriter.WriteHeader(&header) 65 if err != nil { 66 return err 67 } 68 69 return nil 70 } 71 72 // StoreFile appends to the current archive the specified file. 73 func (ca *CpioArchive) StoreFile(filename string, dstPath string) error { 74 fileInfo, err := os.Lstat(filename) 75 if err != nil { 76 return err 77 } 78 79 header, err := cpio.FileInfoHeader(fileInfo, "") 80 if err != nil { 81 return err 82 } 83 header.Name = filepath.Join(dstPath, header.Name) 84 85 if err := ca.cpioWriter.WriteHeader(header); err != nil { 86 return err 87 } 88 89 fm := fileInfo.Mode() 90 switch { 91 case fm.IsRegular(): 92 // Copy the file content 93 f, err := os.Open(filename) 94 if err != nil { 95 return err 96 } 97 defer f.Close() 98 99 _, err = io.Copy(ca.cpioWriter, f) 100 if err != nil { 101 return err 102 } 103 case fm&os.ModeSymlink != 0: 104 // In case of a symbolic link, copy the link text 105 s, err := os.Readlink(filename) 106 if err != nil { 107 return err 108 } 109 _, err = ca.cpioWriter.Write([]byte(s)) 110 if err != nil { 111 return err 112 } 113 default: 114 return fmt.Errorf("unsupported file mode %v for file %s", fm, filename) 115 } 116 117 return nil 118 } 119 120 // SaveBuffer saves the content of the current archive and returns 121 // the buffer content. 122 func (ca *CpioArchive) SaveBuffer() ([]byte, error) { 123 err := ca.cpioWriter.Close() 124 if err != nil { 125 return nil, err 126 } 127 128 err = ca.gzipWriter.Close() 129 if err != nil { 130 return nil, err 131 } 132 133 return ca.buffer.Bytes(), nil 134 } 135 136 // Save the content of the current archive on the disk. 137 func (ca *CpioArchive) Save(archivePath string) error { 138 out, err := os.Create(archivePath) 139 if err != nil { 140 return err 141 } 142 defer out.Close() 143 144 bs, err := ca.SaveBuffer() 145 if err != nil { 146 return err 147 } 148 149 _, err = out.Write(bs) 150 if err != nil { 151 return err 152 } 153 154 return nil 155 }