iperf3exporter/vendor/github.com/cavaliercoder/go-cpio/writer.go
Marvin Preuss 2343c9588a
Some checks failed
continuous-integration/drone/push Build is passing
continuous-integration/drone/tag Build is failing
first commit
2021-10-20 10:08:56 +02:00

129 lines
2.7 KiB
Go

package cpio
import (
"errors"
"fmt"
"io"
)
var (
ErrWriteTooLong = errors.New("cpio: write too long")
ErrWriteAfterClose = errors.New("cpio: write after close")
)
var trailer = &Header{
Name: string(headerEOF),
Links: 1,
}
var zeroBlock [4]byte
// A Writer provides sequential writing of a CPIO archive. A CPIO archive
// consists of a sequence of files. Call WriteHeader to begin a new file, and
// then call Write to supply that file's data, writing at most hdr.Size bytes in
// total.
type Writer struct {
w io.Writer
nb int64 // number of unwritten bytes for current file entry
pad int64 // amount of padding to write after current file entry
inode int64
err error
closed bool
}
// NewWriter creates a new Writer writing to w.
func NewWriter(w io.Writer) *Writer {
return &Writer{w: w}
}
// Flush finishes writing the current file (optional).
func (w *Writer) Flush() error {
if w.nb > 0 {
w.err = fmt.Errorf("cpio: missed writing %d bytes", w.nb)
return w.err
}
_, w.err = w.w.Write(zeroBlock[:w.pad])
if w.err != nil {
return w.err
}
w.nb = 0
w.pad = 0
return w.err
}
// WriteHeader writes hdr and prepares to accept the file's contents.
// WriteHeader calls Flush if it is not the first header. Calling after a Close
// will return ErrWriteAfterClose.
func (w *Writer) WriteHeader(hdr *Header) (err error) {
if w.closed {
return ErrWriteAfterClose
}
if w.err == nil {
w.Flush()
}
if w.err != nil {
return w.err
}
if hdr.Name != headerEOF {
// TODO: should we be mutating hdr here?
// ensure all inodes are unique
w.inode++
if hdr.Inode == 0 {
hdr.Inode = w.inode
}
// ensure file type is set
if hdr.Mode&^ModePerm == 0 {
hdr.Mode |= ModeRegular
}
// ensure regular files have at least 1 inbound link
if hdr.Links < 1 && hdr.Mode.IsRegular() {
hdr.Links = 1
}
}
w.nb = hdr.Size
w.pad, w.err = writeSVR4Header(w.w, hdr)
return
}
// Write writes to the current entry in the CPIO archive. Write returns the
// error ErrWriteTooLong if more than hdr.Size bytes are written after
// WriteHeader.
func (w *Writer) Write(p []byte) (n int, err error) {
if w.closed {
err = ErrWriteAfterClose
return
}
overwrite := false
if int64(len(p)) > w.nb {
p = p[0:w.nb]
overwrite = true
}
n, err = w.w.Write(p)
w.nb -= int64(n)
if err == nil && overwrite {
err = ErrWriteTooLong
return
}
w.err = err
return
}
// Close closes the CPIO archive, flushing any unwritten data to the underlying
// writer.
func (w *Writer) Close() error {
if w.err != nil || w.closed {
return w.err
}
w.err = w.WriteHeader(trailer)
if w.err != nil {
return w.err
}
w.Flush()
w.closed = true
return w.err
}