New upstream version 1.1.0+git20160926.fcb6877

parents
*~
*.swp
/bin
/_obj
_go_.*
/cmd/cpio/cpio
This diff is collapsed.
`gocpio` is a simple library similar to Go’s `tar` or `zip` package for
accessing cpio archives. It’s not pretty and only implements the new ASCII
format. Maybe I’ll refactor and implement other formats some day.
Links
-----
* [Reference](http://people.freebsd.org/~kientzle/libarchive/man/cpio.5.txt)
-------
Version 1.1.0
\ No newline at end of file
// Package cpio implements access to cpio archives.
// Implementation of the new ASCII formate (SVR4) defined here:
// http://people.freebsd.org/~kientzle/libarchive/man/cpio.5.txt
package cpio
const (
VERSION = "1.1.0"
)
// Header represents file meta data in an archive.
// Some fields may not be populated.
type Header struct {
Mode int64 // permission and mode bits.
Uid int // user id of owner.
Gid int // group id of owner.
Mtime int64 // modified time; seconds since epoch.
Size int64 // length in bytes.
Devmajor int64 // major number of character or block device.
Devminor int64 // minor number of character or block device.
Type int64
Name string // name of header file entry.
}
func (h *Header) IsTrailer() bool {
return h.Name == trailer.Name &&
h.Uid == trailer.Uid &&
h.Gid == trailer.Gid &&
h.Mtime == trailer.Mtime
}
// File types
const (
TYPE_SOCK = 014
TYPE_SYMLINK = 012
TYPE_REG = 010
TYPE_BLK = 006
TYPE_DIR = 004
TYPE_CHAR = 002
TYPE_FIFO = 001
)
var (
trailer = Header{
Name: "TRAILER!!!",
}
)
package cpio
import (
"errors"
"io"
"strconv"
)
type Reader struct {
r io.Reader
pos int64
remaining_bytes int
}
func NewReader(r io.Reader) *Reader {
return &Reader{
r: r,
}
}
func disassemble(mode int64) (fmode int64, ftype int64) {
fmode = mode & 0xFFF
ftype = (mode >> 12) & 0xF
return
}
func getPrefix(buf *[]byte, len int) (pre []byte) {
pre, *buf = (*buf)[0:len], (*buf)[len:]
return
}
func Btoi(s string, base int) (int, error) {
i, e := strconv.ParseInt(s, base, 64)
return int(i), e
}
var (
ErrInvalidHeader = errors.New("Did not find valid magic number")
)
func parseHeader(buf []byte) (*Header, int64, error) {
magic := string(getPrefix(&buf, 6))
raw_inode := getPrefix(&buf, 8)
raw_mode := getPrefix(&buf, 8)
raw_uid := getPrefix(&buf, 8)
raw_gid := getPrefix(&buf, 8)
raw_nlinks := getPrefix(&buf, 8)
raw_mtime := getPrefix(&buf, 8)
raw_size := getPrefix(&buf, 8)
raw_major := getPrefix(&buf, 8)
raw_minor := getPrefix(&buf, 8)
raw_devmajor := getPrefix(&buf, 8)
raw_devminor := getPrefix(&buf, 8)
raw_namelen := getPrefix(&buf, 8)
raw_check := getPrefix(&buf, 8)
_, _, _, _, _ = raw_inode, raw_nlinks, raw_major, raw_minor, raw_check
if magic != "070701" {
return nil, 0, ErrInvalidHeader
}
hdr := &Header{}
mode, e := strconv.ParseInt(string(raw_mode), 16, 64)
if e != nil {
return nil, 0, e
}
hdr.Mode, hdr.Type = disassemble(mode)
hdr.Uid, e = Btoi(string(raw_uid), 16)
if e != nil {
return nil, 0, e
}
hdr.Gid, e = Btoi(string(raw_gid), 16)
if e != nil {
return nil, 0, e
}
hdr.Mtime, e = strconv.ParseInt(string(raw_mtime), 16, 64)
if e != nil {
return nil, 0, e
}
hdr.Size, e = strconv.ParseInt(string(raw_size), 16, 64)
if e != nil {
return nil, 0, e
}
hdr.Devmajor, e = strconv.ParseInt(string(raw_devmajor), 16, 64)
if e != nil {
return nil, 0, e
}
hdr.Devminor, e = strconv.ParseInt(string(raw_devminor), 16, 64)
if e != nil {
return nil, 0, e
}
namelen, e := strconv.ParseInt(string(raw_namelen), 16, 64)
if e != nil {
return nil, 0, e
}
return hdr, namelen, nil
}
func (r *Reader) Next() (*Header, error) {
e := r.skipRest()
if e != nil {
return nil, e
}
e = r.skipPadding(4)
if e != nil {
return nil, e
}
raw_hdr := make([]byte, 110)
_, e = r.countedRead(raw_hdr)
if e != nil {
return nil, e
}
hdr, namelen, e := parseHeader(raw_hdr)
if e != nil {
return nil, e
}
bname := make([]byte, namelen)
_, e = r.countedRead(bname)
if e != nil {
return nil, e
}
hdr.Name = string(bname[0 : namelen-1]) //Exclude terminating zero
r.remaining_bytes = int(hdr.Size)
return hdr, r.skipPadding(4)
}
func (r *Reader) skipRest() error {
buf := make([]byte, 1)
for ; r.remaining_bytes > 0; r.remaining_bytes-- {
_, e := r.countedRead(buf)
if e != nil {
return e
}
}
return nil
}
// Skips to the next position which is a multiple of mod.
func (r *Reader) skipPadding(mod int64) error {
numBytesToRead := ((mod - (r.pos % mod)) % mod)
buf := make([]byte, numBytesToRead)
_, e := r.countedRead(buf)
return e
}
func (r *Reader) Read(b []byte) (n int, e error) {
if r.remaining_bytes == 0 {
return 0, io.EOF
}
if len(b) > r.remaining_bytes {
b = b[0:r.remaining_bytes]
}
n, e = r.countedRead(b)
r.remaining_bytes -= n
return
}
func (r *Reader) countedRead(b []byte) (n int, e error) {
if len(b) == 0 {
return
}
n, e = r.r.Read(b)
r.pos += int64(n)
return
}
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)
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment