1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118
|
package cpio
import (
"io"
"fmt"
)
// A writer enables sequential writing of cpio archives.
// A call to WriteHeader begins a new file. Every call to
// write afterwards appends to that file, writing at most
// hdr.Size bytes in total.
type Writer struct {
w io.Writer
inode int64
length int64
remaining_bytes int
}
func NewWriter(w io.Writer) *Writer {
return &Writer{
w: w,
inode: 721,
}
}
func assemble(mode, typev int64) int64 {
return mode&0xFFF | ((typev & 0xF) << 12)
}
func (w *Writer) WriteHeader(hdr *Header) error {
// Bring last file to the defined length
e := w.zeros(int64(w.remaining_bytes))
if e != nil {
return e
}
e = w.pad(4)
if e != nil {
return e
}
bname := []byte(hdr.Name)
nlinks := 1
if hdr.Type == TYPE_DIR {
nlinks = 2
}
shdr := fmt.Sprintf("%s%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x",
"070701",
w.inode,
assemble(hdr.Mode, hdr.Type),
hdr.Uid,
hdr.Gid,
nlinks,
hdr.Mtime,
hdr.Size,
3, // major
1, // minor
hdr.Devmajor,
hdr.Devminor,
len(bname)+1, // +1 for terminating zero
0) // check
_, e = w.countedWrite([]byte(shdr))
if e != nil {
return e
}
_, e = w.countedWrite(bname)
if e != nil {
return e
}
_, e = w.countedWrite([]byte{0})
if e != nil {
return e
}
w.inode++
w.remaining_bytes = int(hdr.Size)
return w.pad(4)
}
func (w *Writer) zeros(num int64) error {
for ; num > 0; num-- {
_, e := w.countedWrite([]byte{0})
if e != nil {
return e
}
}
return nil
}
// Brings the length of the file to a multiple of mod
func (w *Writer) pad(mod int64) error {
return w.zeros((mod - (w.length % mod)) % mod)
}
func (w *Writer) Write(b []byte) (n int, e error) {
if len(b) > w.remaining_bytes {
b = b[0:w.remaining_bytes]
}
n, e = w.countedWrite(b)
w.remaining_bytes -= n
return
}
func (w *Writer) countedWrite(b []byte) (n int, e error) {
n, e = w.w.Write(b)
w.length += int64(n)
return n, e
}
// Writes trailer
// Does not close underlying writer
func (w *Writer) Close() error {
e := w.WriteHeader(&trailer)
if e != nil {
return e
}
return w.pad(512)
}
|