pkg/cpiocat/cpiocat.go
Mikaël Cluseau b1056c4365 cpiocat
2022-03-30 11:48:55 +02:00

182 lines
2.5 KiB
Go

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
}