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  }