package cpiocat import ( "io" "os" "github.com/cavaliergopher/cpio" ) // Append: legacy append call. func Append(out io.Writer, in io.Reader, filesToAppend []string) (err error) { cat := New(out) cat.AppendArch(in) for _, file := range filesToAppend { cat.AppendFile(file, file) } return cat.Close() } type Cat struct { out io.Writer cout *cpio.Writer err error } func New(out io.Writer) *Cat { cout := cpio.NewWriter(out) return &Cat{out: out, cout: cout} } func (c *Cat) Err() error { return c.err } func (c *Cat) Close() error { err := c.cout.Close() if c.err != nil { return c.err } return err } func (c *Cat) AppendArchFile(srcPath string) (r *Cat) { r = c if c.err != nil { return } f, err := os.Open(srcPath) if err != nil { c.err = err return } defer f.Close() return c.AppendArch(f) } func (c *Cat) AppendArch(in io.Reader) (r *Cat) { r = c if c.err != nil { return } cin := cpio.NewReader(in) for { hdr, err := cin.Next() if err != nil { if err == io.EOF { break } c.err = err return } mode := hdr.FileInfo().Mode() if mode&os.ModeSymlink != 0 { // symlink target must be written after hdr.Size = int64(len(hdr.Linkname)) } err = c.cout.WriteHeader(hdr) if err != nil { c.err = err return } if mode.IsRegular() { _, err = io.Copy(c.cout, cin) } else if mode&os.ModeSymlink != 0 { _, err = c.cout.Write([]byte(hdr.Linkname)) } if err != nil { c.err = err return } } return } func (c *Cat) AppendFile(srcPath, archPath string) (r *Cat) { r = c if c.err != nil { return } var err error defer func() { c.err = err }() stat, err := os.Lstat(srcPath) if err != nil { return } link := "" if stat.Mode()&os.ModeSymlink != 0 { link, err = os.Readlink(srcPath) if err != nil { return } } hdr, err := cpio.FileInfoHeader(stat, link) if err != nil { return } hdr.Name = archPath c.cout.WriteHeader(hdr) if stat.Mode().IsRegular() { var f *os.File f, err = os.Open(srcPath) if err != nil { return } defer f.Close() _, err = io.Copy(c.cout, f) } else if stat.Mode()&os.ModeSymlink != 0 { _, err = c.cout.Write([]byte(link)) } return } func (c *Cat) AppendBytes(content []byte, archPath string, mode cpio.FileMode) (r *Cat) { r = c if c.err != nil { return } var err error defer func() { c.err = err }() err = c.cout.WriteHeader(&cpio.Header{ Name: archPath, Mode: mode, Size: int64(len(content)), }) if err != nil { return } _, err = c.cout.Write(content) return }