vendor
This commit is contained in:
3
vendor/github.com/cavaliercoder/go-cpio/.gitignore
generated
vendored
Normal file
3
vendor/github.com/cavaliercoder/go-cpio/.gitignore
generated
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
.fuzz/
|
||||
*.zip
|
||||
|
10
vendor/github.com/cavaliercoder/go-cpio/.travis.yml
generated
vendored
Normal file
10
vendor/github.com/cavaliercoder/go-cpio/.travis.yml
generated
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
language: go
|
||||
|
||||
go:
|
||||
- 1.4.3
|
||||
- 1.5.4
|
||||
- 1.6.4
|
||||
- 1.7.6
|
||||
- 1.8.3
|
||||
|
||||
script: make check
|
26
vendor/github.com/cavaliercoder/go-cpio/LICENSE
generated
vendored
Normal file
26
vendor/github.com/cavaliercoder/go-cpio/LICENSE
generated
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
Copyright (c) 2017 Ryan Armstrong. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
18
vendor/github.com/cavaliercoder/go-cpio/Makefile
generated
vendored
Normal file
18
vendor/github.com/cavaliercoder/go-cpio/Makefile
generated
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
PACKAGE = github.com/cavaliercoder/go-cpio
|
||||
|
||||
all: check
|
||||
|
||||
check:
|
||||
go test -v
|
||||
|
||||
cpio-fuzz.zip: *.go
|
||||
go-fuzz-build $(PACKAGE)
|
||||
|
||||
fuzz: cpio-fuzz.zip
|
||||
go-fuzz -bin=./cpio-fuzz.zip -workdir=.fuzz/
|
||||
|
||||
clean-fuzz:
|
||||
rm -rf cpio-fuzz.zip .fuzz/crashers/* .fuzz/suppressions/*
|
||||
|
||||
|
||||
.PHONY: all check
|
62
vendor/github.com/cavaliercoder/go-cpio/README.md
generated
vendored
Normal file
62
vendor/github.com/cavaliercoder/go-cpio/README.md
generated
vendored
Normal file
@ -0,0 +1,62 @@
|
||||
# go-cpio [](https://godoc.org/github.com/cavaliercoder/go-cpio) [](https://travis-ci.org/cavaliercoder/go-cpio) [](https://goreportcard.com/report/github.com/cavaliercoder/go-cpio)
|
||||
|
||||
This package provides a Go native implementation of the CPIO archive file
|
||||
format.
|
||||
|
||||
Currently, only the SVR4 (New ASCII) format is supported, both with and without
|
||||
checksums.
|
||||
|
||||
```go
|
||||
// Create a buffer to write our archive to.
|
||||
buf := new(bytes.Buffer)
|
||||
|
||||
// Create a new cpio archive.
|
||||
w := cpio.NewWriter(buf)
|
||||
|
||||
// Add some files to the archive.
|
||||
var files = []struct {
|
||||
Name, Body string
|
||||
}{
|
||||
{"readme.txt", "This archive contains some text files."},
|
||||
{"gopher.txt", "Gopher names:\nGeorge\nGeoffrey\nGonzo"},
|
||||
{"todo.txt", "Get animal handling license."},
|
||||
}
|
||||
for _, file := range files {
|
||||
hdr := &cpio.Header{
|
||||
Name: file.Name,
|
||||
Mode: 0600,
|
||||
Size: int64(len(file.Body)),
|
||||
}
|
||||
if err := w.WriteHeader(hdr); err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
if _, err := w.Write([]byte(file.Body)); err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
}
|
||||
// Make sure to check the error on Close.
|
||||
if err := w.Close(); err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
|
||||
// Open the cpio archive for reading.
|
||||
b := bytes.NewReader(buf.Bytes())
|
||||
r := cpio.NewReader(b)
|
||||
|
||||
// Iterate through the files in the archive.
|
||||
for {
|
||||
hdr, err := r.Next()
|
||||
if err == io.EOF {
|
||||
// end of cpio archive
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
fmt.Printf("Contents of %s:\n", hdr.Name)
|
||||
if _, err := io.Copy(os.Stdout, r); err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
fmt.Println()
|
||||
}
|
||||
```
|
8
vendor/github.com/cavaliercoder/go-cpio/cpio.go
generated
vendored
Normal file
8
vendor/github.com/cavaliercoder/go-cpio/cpio.go
generated
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
/*
|
||||
Package cpio implements access to CPIO archives. Currently, only the SVR4 (New
|
||||
ASCII) format is supported, both with and without checksums.
|
||||
|
||||
References:
|
||||
https://www.freebsd.org/cgi/man.cgi?query=cpio&sektion=5
|
||||
*/
|
||||
package cpio
|
77
vendor/github.com/cavaliercoder/go-cpio/example_test.go
generated
vendored
Normal file
77
vendor/github.com/cavaliercoder/go-cpio/example_test.go
generated
vendored
Normal file
@ -0,0 +1,77 @@
|
||||
package cpio_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/cavaliercoder/go-cpio"
|
||||
)
|
||||
|
||||
func Example() {
|
||||
// Create a buffer to write our archive to.
|
||||
buf := new(bytes.Buffer)
|
||||
|
||||
// Create a new cpio archive.
|
||||
w := cpio.NewWriter(buf)
|
||||
|
||||
// Add some files to the archive.
|
||||
var files = []struct {
|
||||
Name, Body string
|
||||
}{
|
||||
{"readme.txt", "This archive contains some text files."},
|
||||
{"gopher.txt", "Gopher names:\nGeorge\nGeoffrey\nGonzo"},
|
||||
{"todo.txt", "Get animal handling license."},
|
||||
}
|
||||
for _, file := range files {
|
||||
hdr := &cpio.Header{
|
||||
Name: file.Name,
|
||||
Mode: 0600,
|
||||
Size: int64(len(file.Body)),
|
||||
}
|
||||
if err := w.WriteHeader(hdr); err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
if _, err := w.Write([]byte(file.Body)); err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
}
|
||||
// Make sure to check the error on Close.
|
||||
if err := w.Close(); err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
|
||||
// Open the cpio archive for reading.
|
||||
b := bytes.NewReader(buf.Bytes())
|
||||
r := cpio.NewReader(b)
|
||||
|
||||
// Iterate through the files in the archive.
|
||||
for {
|
||||
hdr, err := r.Next()
|
||||
if err == io.EOF {
|
||||
// end of cpio archive
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
fmt.Printf("Contents of %s:\n", hdr.Name)
|
||||
if _, err := io.Copy(os.Stdout, r); err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// Output:
|
||||
// Contents of readme.txt:
|
||||
// This archive contains some text files.
|
||||
// Contents of gopher.txt:
|
||||
// Gopher names:
|
||||
// George
|
||||
// Geoffrey
|
||||
// Gonzo
|
||||
// Contents of todo.txt:
|
||||
// Get animal handling license.
|
||||
}
|
75
vendor/github.com/cavaliercoder/go-cpio/fileinfo.go
generated
vendored
Normal file
75
vendor/github.com/cavaliercoder/go-cpio/fileinfo.go
generated
vendored
Normal file
@ -0,0 +1,75 @@
|
||||
package cpio
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path"
|
||||
"time"
|
||||
)
|
||||
|
||||
// headerFileInfo implements os.FileInfo.
|
||||
type headerFileInfo struct {
|
||||
h *Header
|
||||
}
|
||||
|
||||
// Name returns the base name of the file.
|
||||
func (fi headerFileInfo) Name() string {
|
||||
if fi.IsDir() {
|
||||
return path.Base(path.Clean(fi.h.Name))
|
||||
}
|
||||
return path.Base(fi.h.Name)
|
||||
}
|
||||
|
||||
func (fi headerFileInfo) Size() int64 { return fi.h.Size }
|
||||
func (fi headerFileInfo) IsDir() bool { return fi.Mode().IsDir() }
|
||||
func (fi headerFileInfo) ModTime() time.Time { return fi.h.ModTime }
|
||||
func (fi headerFileInfo) Sys() interface{} { return fi.h }
|
||||
|
||||
func (fi headerFileInfo) Mode() (mode os.FileMode) {
|
||||
// Set file permission bits.
|
||||
mode = os.FileMode(fi.h.Mode).Perm()
|
||||
|
||||
// Set setuid, setgid and sticky bits.
|
||||
if fi.h.Mode&ModeSetuid != 0 {
|
||||
// setuid
|
||||
mode |= os.ModeSetuid
|
||||
}
|
||||
if fi.h.Mode&ModeSetgid != 0 {
|
||||
// setgid
|
||||
mode |= os.ModeSetgid
|
||||
}
|
||||
if fi.h.Mode&ModeSticky != 0 {
|
||||
// sticky
|
||||
mode |= os.ModeSticky
|
||||
}
|
||||
|
||||
// Set file mode bits.
|
||||
// clear perm, setuid, setgid and sticky bits.
|
||||
m := os.FileMode(fi.h.Mode) & 0170000
|
||||
if m == ModeDir {
|
||||
// directory
|
||||
mode |= os.ModeDir
|
||||
}
|
||||
if m == ModeNamedPipe {
|
||||
// named pipe (FIFO)
|
||||
mode |= os.ModeNamedPipe
|
||||
}
|
||||
if m == ModeSymlink {
|
||||
// symbolic link
|
||||
mode |= os.ModeSymlink
|
||||
}
|
||||
if m == ModeDevice {
|
||||
// device file
|
||||
mode |= os.ModeDevice
|
||||
}
|
||||
if m == ModeCharDevice {
|
||||
// Unix character device
|
||||
mode |= os.ModeDevice
|
||||
mode |= os.ModeCharDevice
|
||||
}
|
||||
if m == ModeSocket {
|
||||
// Unix domain socket
|
||||
mode |= os.ModeSocket
|
||||
}
|
||||
|
||||
return mode
|
||||
}
|
35
vendor/github.com/cavaliercoder/go-cpio/fuzz.go
generated
vendored
Normal file
35
vendor/github.com/cavaliercoder/go-cpio/fuzz.go
generated
vendored
Normal file
@ -0,0 +1,35 @@
|
||||
// +build gofuzz
|
||||
|
||||
package cpio
|
||||
|
||||
import "bytes"
|
||||
import "io"
|
||||
|
||||
// Fuzz tests the parsing and error handling of random byte arrays using
|
||||
// https://github.com/dvyukov/go-fuzz.
|
||||
func Fuzz(data []byte) int {
|
||||
r := NewReader(bytes.NewReader(data))
|
||||
h := NewHash()
|
||||
for {
|
||||
hdr, err := r.Next()
|
||||
if err != nil {
|
||||
if hdr != nil {
|
||||
panic("hdr != nil on error")
|
||||
}
|
||||
if err == io.EOF {
|
||||
// everything worked with random input... interesting
|
||||
return 1
|
||||
}
|
||||
// error returned for random input. Good!
|
||||
return -1
|
||||
}
|
||||
|
||||
// hash file
|
||||
h.Reset()
|
||||
io.CopyN(h, r, hdr.Size)
|
||||
h.Sum32()
|
||||
|
||||
// convert file header
|
||||
FileInfoHeader(hdr.FileInfo())
|
||||
}
|
||||
}
|
45
vendor/github.com/cavaliercoder/go-cpio/hash.go
generated
vendored
Normal file
45
vendor/github.com/cavaliercoder/go-cpio/hash.go
generated
vendored
Normal file
@ -0,0 +1,45 @@
|
||||
package cpio
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"hash"
|
||||
)
|
||||
|
||||
type digest struct {
|
||||
sum uint32
|
||||
}
|
||||
|
||||
// NewHash returns a new hash.Hash32 computing the SVR4 checksum.
|
||||
func NewHash() hash.Hash32 {
|
||||
return &digest{}
|
||||
}
|
||||
|
||||
func (d *digest) Write(p []byte) (n int, err error) {
|
||||
for _, b := range p {
|
||||
d.sum += uint32(b & 0xFF)
|
||||
}
|
||||
|
||||
return len(p), nil
|
||||
}
|
||||
|
||||
func (d *digest) Sum(b []byte) []byte {
|
||||
out := [4]byte{}
|
||||
binary.LittleEndian.PutUint32(out[:], d.sum)
|
||||
return append(b, out[:]...)
|
||||
}
|
||||
|
||||
func (d *digest) Sum32() uint32 {
|
||||
return d.sum
|
||||
}
|
||||
|
||||
func (d *digest) Reset() {
|
||||
d.sum = 0
|
||||
}
|
||||
|
||||
func (d *digest) Size() int {
|
||||
return 4
|
||||
}
|
||||
|
||||
func (d *digest) BlockSize() int {
|
||||
return 1
|
||||
}
|
152
vendor/github.com/cavaliercoder/go-cpio/header.go
generated
vendored
Normal file
152
vendor/github.com/cavaliercoder/go-cpio/header.go
generated
vendored
Normal file
@ -0,0 +1,152 @@
|
||||
package cpio
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Mode constants from the cpio spec.
|
||||
const (
|
||||
ModeSetuid = 04000 // Set uid
|
||||
ModeSetgid = 02000 // Set gid
|
||||
ModeSticky = 01000 // Save text (sticky bit)
|
||||
ModeDir = 040000 // Directory
|
||||
ModeNamedPipe = 010000 // FIFO
|
||||
ModeRegular = 0100000 // Regular file
|
||||
ModeSymlink = 0120000 // Symbolic link
|
||||
ModeDevice = 060000 // Block special file
|
||||
ModeCharDevice = 020000 // Character special file
|
||||
ModeSocket = 0140000 // Socket
|
||||
|
||||
ModeType = 0170000 // Mask for the type bits
|
||||
ModePerm = 0777 // Unix permission bits
|
||||
)
|
||||
|
||||
const (
|
||||
// headerEOF is the value of the filename of the last header in a CPIO archive.
|
||||
headerEOF = "TRAILER!!!"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrHeader = errors.New("cpio: invalid cpio header")
|
||||
)
|
||||
|
||||
// A FileMode represents a file's mode and permission bits.
|
||||
type FileMode int64
|
||||
|
||||
func (m FileMode) String() string {
|
||||
return fmt.Sprintf("%#o", m)
|
||||
}
|
||||
|
||||
// IsDir reports whether m describes a directory. That is, it tests for the
|
||||
// ModeDir bit being set in m.
|
||||
func (m FileMode) IsDir() bool {
|
||||
return m&ModeDir != 0
|
||||
}
|
||||
|
||||
// IsRegular reports whether m describes a regular file. That is, it tests for
|
||||
// the ModeRegular bit being set in m.
|
||||
func (m FileMode) IsRegular() bool {
|
||||
return m&^ModePerm == ModeRegular
|
||||
}
|
||||
|
||||
// Perm returns the Unix permission bits in m.
|
||||
func (m FileMode) Perm() FileMode {
|
||||
return m & ModePerm
|
||||
}
|
||||
|
||||
// Checksum is the sum of all bytes in the file data. This sum is computed
|
||||
// treating all bytes as unsigned values and using unsigned arithmetic. Only
|
||||
// the least-significant 32 bits of the sum are stored. Use NewHash to compute
|
||||
// the actual checksum of an archived file.
|
||||
type Checksum uint32
|
||||
|
||||
func (c Checksum) String() string {
|
||||
return fmt.Sprintf("%08X", uint32(c))
|
||||
}
|
||||
|
||||
// A Header represents a single header in a CPIO archive.
|
||||
type Header struct {
|
||||
DeviceID int
|
||||
Inode int64 // inode number
|
||||
Mode FileMode // permission and mode bits
|
||||
UID int // user id of the owner
|
||||
GID int // group id of the owner
|
||||
Links int // number of inbound links
|
||||
ModTime time.Time // modified time
|
||||
Size int64 // size in bytes
|
||||
Name string // filename
|
||||
Linkname string // target name of link
|
||||
Checksum Checksum // computed checksum
|
||||
|
||||
pad int64 // bytes to pad before next header
|
||||
}
|
||||
|
||||
// FileInfo returns an os.FileInfo for the Header.
|
||||
func (h *Header) FileInfo() os.FileInfo {
|
||||
return headerFileInfo{h}
|
||||
}
|
||||
|
||||
// FileInfoHeader creates a partially-populated Header from fi.
|
||||
// If fi describes a symlink, FileInfoHeader records link as the link target.
|
||||
// If fi describes a directory, a slash is appended to the name.
|
||||
// Because os.FileInfo's Name method returns only the base name of
|
||||
// the file it describes, it may be necessary to modify the Name field
|
||||
// of the returned header to provide the full path name of the file.
|
||||
func FileInfoHeader(fi os.FileInfo, link string) (*Header, error) {
|
||||
if fi == nil {
|
||||
return nil, errors.New("cpio: FileInfo is nil")
|
||||
}
|
||||
|
||||
if sys, ok := fi.Sys().(*Header); ok {
|
||||
// This FileInfo came from a Header (not the OS). Return a copy of the
|
||||
// original Header.
|
||||
h := &Header{}
|
||||
*h = *sys
|
||||
return h, nil
|
||||
}
|
||||
|
||||
fm := fi.Mode()
|
||||
h := &Header{
|
||||
Name: fi.Name(),
|
||||
Mode: FileMode(fi.Mode().Perm()), // or'd with Mode* constants later
|
||||
ModTime: fi.ModTime(),
|
||||
Size: fi.Size(),
|
||||
}
|
||||
|
||||
switch {
|
||||
case fm.IsRegular():
|
||||
h.Mode |= ModeRegular
|
||||
case fi.IsDir():
|
||||
h.Mode |= ModeDir
|
||||
h.Name += "/"
|
||||
case fm&os.ModeSymlink != 0:
|
||||
h.Mode |= ModeSymlink
|
||||
h.Linkname = link
|
||||
case fm&os.ModeDevice != 0:
|
||||
if fm&os.ModeCharDevice != 0 {
|
||||
h.Mode |= ModeCharDevice
|
||||
} else {
|
||||
h.Mode |= ModeDevice
|
||||
}
|
||||
case fm&os.ModeNamedPipe != 0:
|
||||
h.Mode |= ModeNamedPipe
|
||||
case fm&os.ModeSocket != 0:
|
||||
h.Mode |= ModeSocket
|
||||
default:
|
||||
return nil, fmt.Errorf("cpio: unknown file mode %v", fm)
|
||||
}
|
||||
if fm&os.ModeSetuid != 0 {
|
||||
h.Mode |= ModeSetuid
|
||||
}
|
||||
if fm&os.ModeSetgid != 0 {
|
||||
h.Mode |= ModeSetgid
|
||||
}
|
||||
if fm&os.ModeSticky != 0 {
|
||||
h.Mode |= ModeSticky
|
||||
}
|
||||
|
||||
return h, nil
|
||||
}
|
72
vendor/github.com/cavaliercoder/go-cpio/reader.go
generated
vendored
Normal file
72
vendor/github.com/cavaliercoder/go-cpio/reader.go
generated
vendored
Normal file
@ -0,0 +1,72 @@
|
||||
package cpio
|
||||
|
||||
import (
|
||||
"io"
|
||||
"io/ioutil"
|
||||
)
|
||||
|
||||
// A Reader provides sequential access to the contents of a CPIO archive. A CPIO
|
||||
// archive consists of a sequence of files. The Next method advances to the next
|
||||
// file in the archive (including the first), and then it can be treated as an
|
||||
// io.Reader to access the file's data.
|
||||
type Reader struct {
|
||||
r io.Reader // underlying file reader
|
||||
hdr *Header // current Header
|
||||
eof int64 // bytes until the end of the current file
|
||||
}
|
||||
|
||||
// NewReader creates a new Reader reading from r.
|
||||
func NewReader(r io.Reader) *Reader {
|
||||
return &Reader{
|
||||
r: r,
|
||||
}
|
||||
}
|
||||
|
||||
// Read reads from the current entry in the CPIO archive. It returns 0, io.EOF
|
||||
// when it reaches the end of that entry, until Next is called to advance to the
|
||||
// next entry.
|
||||
func (r *Reader) Read(p []byte) (n int, err error) {
|
||||
if r.hdr == nil || r.eof == 0 {
|
||||
return 0, io.EOF
|
||||
}
|
||||
rn := len(p)
|
||||
if r.eof < int64(rn) {
|
||||
rn = int(r.eof)
|
||||
}
|
||||
n, err = r.r.Read(p[0:rn])
|
||||
r.eof -= int64(n)
|
||||
return
|
||||
}
|
||||
|
||||
// Next advances to the next entry in the CPIO archive.
|
||||
// io.EOF is returned at the end of the input.
|
||||
func (r *Reader) Next() (*Header, error) {
|
||||
if r.hdr == nil {
|
||||
return r.next()
|
||||
}
|
||||
skp := r.eof + r.hdr.pad
|
||||
if skp > 0 {
|
||||
_, err := io.CopyN(ioutil.Discard, r.r, skp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return r.next()
|
||||
}
|
||||
|
||||
func (r *Reader) next() (*Header, error) {
|
||||
r.eof = 0
|
||||
hdr, err := readHeader(r.r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
r.hdr = hdr
|
||||
r.eof = hdr.Size
|
||||
return hdr, nil
|
||||
}
|
||||
|
||||
// ReadHeader creates a new Header, reading from r.
|
||||
func readHeader(r io.Reader) (*Header, error) {
|
||||
// currently only SVR4 format is supported
|
||||
return readSVR4Header(r)
|
||||
}
|
145
vendor/github.com/cavaliercoder/go-cpio/svr4.go
generated
vendored
Normal file
145
vendor/github.com/cavaliercoder/go-cpio/svr4.go
generated
vendored
Normal file
@ -0,0 +1,145 @@
|
||||
package cpio
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
svr4MaxNameSize = 4096 // MAX_PATH
|
||||
svr4MaxFileSize = 4294967295
|
||||
)
|
||||
|
||||
var svr4Magic = []byte{0x30, 0x37, 0x30, 0x37, 0x30, 0x31} // 07070
|
||||
|
||||
func readHex(s string) int64 {
|
||||
// errors are ignored and 0 returned
|
||||
i, _ := strconv.ParseInt(s, 16, 64)
|
||||
return i
|
||||
}
|
||||
|
||||
func writeHex(b []byte, i int64) {
|
||||
// i needs to be in range of uint32
|
||||
copy(b, fmt.Sprintf("%08X", i))
|
||||
}
|
||||
|
||||
func readSVR4Header(r io.Reader) (*Header, error) {
|
||||
var buf [110]byte
|
||||
if _, err := io.ReadFull(r, buf[:]); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// TODO: check endianness
|
||||
|
||||
// check magic
|
||||
hasCRC := false
|
||||
if !bytes.HasPrefix(buf[:], svr4Magic[:5]) {
|
||||
return nil, ErrHeader
|
||||
}
|
||||
if buf[5] == 0x32 { // '2'
|
||||
hasCRC = true
|
||||
} else if buf[5] != 0x31 { // '1'
|
||||
return nil, ErrHeader
|
||||
}
|
||||
|
||||
asc := string(buf[:])
|
||||
hdr := &Header{}
|
||||
|
||||
hdr.Inode = readHex(asc[6:14])
|
||||
hdr.Mode = FileMode(readHex(asc[14:22]))
|
||||
hdr.UID = int(readHex(asc[22:30]))
|
||||
hdr.GID = int(readHex(asc[30:38]))
|
||||
hdr.Links = int(readHex(asc[38:46]))
|
||||
hdr.ModTime = time.Unix(readHex(asc[46:54]), 0)
|
||||
hdr.Size = readHex(asc[54:62])
|
||||
if hdr.Size > svr4MaxFileSize {
|
||||
return nil, ErrHeader
|
||||
}
|
||||
nameSize := readHex(asc[94:102])
|
||||
if nameSize < 1 || nameSize > svr4MaxNameSize {
|
||||
return nil, ErrHeader
|
||||
}
|
||||
hdr.Checksum = Checksum(readHex(asc[102:110]))
|
||||
if !hasCRC && hdr.Checksum != 0 {
|
||||
return nil, ErrHeader
|
||||
}
|
||||
|
||||
name := make([]byte, nameSize)
|
||||
if _, err := io.ReadFull(r, name); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
hdr.Name = string(name[:nameSize-1])
|
||||
if hdr.Name == headerEOF {
|
||||
return nil, io.EOF
|
||||
}
|
||||
|
||||
// store padding between end of file and next header
|
||||
hdr.pad = (4 - (hdr.Size % 4)) % 4
|
||||
|
||||
// skip to end of header/start of file
|
||||
pad := (4 - (len(buf)+len(name))%4) % 4
|
||||
if pad > 0 {
|
||||
if _, err := io.ReadFull(r, buf[:pad]); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// read link name
|
||||
if hdr.Mode&^ModePerm == ModeSymlink {
|
||||
if hdr.Size < 1 || hdr.Size > svr4MaxNameSize {
|
||||
return nil, ErrHeader
|
||||
}
|
||||
b := make([]byte, hdr.Size)
|
||||
if _, err := io.ReadFull(r, b); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
hdr.Linkname = string(b)
|
||||
hdr.Size = 0
|
||||
}
|
||||
|
||||
return hdr, nil
|
||||
}
|
||||
|
||||
func writeSVR4Header(w io.Writer, hdr *Header) (pad int64, err error) {
|
||||
var hdrBuf [110]byte
|
||||
for i := 0; i < len(hdrBuf); i++ {
|
||||
hdrBuf[i] = '0'
|
||||
}
|
||||
copy(hdrBuf[:], svr4Magic)
|
||||
writeHex(hdrBuf[6:14], hdr.Inode)
|
||||
writeHex(hdrBuf[14:22], int64(hdr.Mode))
|
||||
writeHex(hdrBuf[22:30], int64(hdr.UID))
|
||||
writeHex(hdrBuf[30:38], int64(hdr.GID))
|
||||
writeHex(hdrBuf[38:46], int64(hdr.Links))
|
||||
if !hdr.ModTime.IsZero() {
|
||||
writeHex(hdrBuf[46:54], hdr.ModTime.Unix())
|
||||
}
|
||||
writeHex(hdrBuf[54:62], hdr.Size)
|
||||
writeHex(hdrBuf[94:102], int64(len(hdr.Name)+1))
|
||||
|
||||
// write header
|
||||
_, err = w.Write(hdrBuf[:])
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// write filename
|
||||
_, err = io.WriteString(w, hdr.Name+"\x00")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// pad to end of filename
|
||||
npad := (4 - ((len(hdrBuf) + len(hdr.Name) + 1) % 4)) % 4
|
||||
_, err = w.Write(zeroBlock[:npad])
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// compute padding to end of file
|
||||
pad = (4 - (hdr.Size % 4)) % 4
|
||||
return
|
||||
}
|
121
vendor/github.com/cavaliercoder/go-cpio/svr4_test.go
generated
vendored
Normal file
121
vendor/github.com/cavaliercoder/go-cpio/svr4_test.go
generated
vendored
Normal file
@ -0,0 +1,121 @@
|
||||
package cpio
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var files = []struct {
|
||||
Name, Body string
|
||||
}{
|
||||
{"./gophers.txt", "Gopher names:\nGeorge\nGeoffrey\nGonzo"},
|
||||
{"./readme.txt", "This archive contains some text files."},
|
||||
{"./todo.txt", "Get animal handling license."},
|
||||
}
|
||||
|
||||
func TestRead(t *testing.T) {
|
||||
f, err := os.Open("testdata/test_svr4_crc.cpio")
|
||||
if err != nil {
|
||||
t.Fatalf("error opening test file: %v", err)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
r := NewReader(f)
|
||||
for {
|
||||
_, err := r.Next()
|
||||
if err == io.EOF {
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
t.Errorf("error moving to next header: %v", err)
|
||||
return
|
||||
}
|
||||
// TODO: validate header fields
|
||||
}
|
||||
}
|
||||
|
||||
func TestSVR4CRC(t *testing.T) {
|
||||
f, err := os.Open("testdata/test_svr4_crc.cpio")
|
||||
if err != nil {
|
||||
t.Fatalf("error opening test file: %v", err)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
w := NewHash()
|
||||
r := NewReader(f)
|
||||
for {
|
||||
hdr, err := r.Next()
|
||||
if err != nil {
|
||||
if err != io.EOF {
|
||||
t.Errorf("error moving to next header: %v", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if hdr.Mode.IsRegular() {
|
||||
w.Reset()
|
||||
_, err = io.CopyN(w, r, hdr.Size)
|
||||
if err != nil {
|
||||
t.Fatalf("error writing to checksum hash: %v", err)
|
||||
}
|
||||
|
||||
sum := Checksum(w.Sum32())
|
||||
if sum != hdr.Checksum {
|
||||
t.Errorf("expected checksum %v, got %v for %v", hdr.Checksum, sum, hdr.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func ExampleNewHash() {
|
||||
// Open the cpio archive for reading.
|
||||
f, err := os.Open("testdata/test_svr4_crc.cpio")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer f.Close()
|
||||
r := NewReader(f)
|
||||
|
||||
// create a Hash
|
||||
h := NewHash()
|
||||
|
||||
// Iterate through the files in the archive.
|
||||
for {
|
||||
hdr, err := r.Next()
|
||||
if err == io.EOF {
|
||||
// end of cpio archive
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// skip symlinks, directories, etc.
|
||||
if !hdr.Mode.IsRegular() {
|
||||
continue
|
||||
}
|
||||
|
||||
// read file into hash
|
||||
h.Reset()
|
||||
_, err = io.CopyN(h, r, hdr.Size)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// check hash matches header checksum
|
||||
sum := Checksum(h.Sum32())
|
||||
if sum == hdr.Checksum {
|
||||
fmt.Printf("Checksum OK: %v (%v)\n", hdr.Name, hdr.Checksum)
|
||||
} else {
|
||||
fmt.Printf("Checksum FAIL: %v - expected %v, got %v\n", hdr.Name, hdr.Checksum, sum)
|
||||
}
|
||||
}
|
||||
|
||||
// Output:
|
||||
// Checksum OK: gophers.txt (00000C98)
|
||||
// Checksum OK: readme.txt (00000E3D)
|
||||
// Checksum OK: todo.txt (00000A52)
|
||||
}
|
26
vendor/github.com/cavaliercoder/go-cpio/testdata/Makefile
generated
vendored
Normal file
26
vendor/github.com/cavaliercoder/go-cpio/testdata/Makefile
generated
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
SOURCES = \
|
||||
gophers.txt \
|
||||
readme.txt \
|
||||
todo.txt \
|
||||
checklist.txt
|
||||
|
||||
ARCHIVES = \
|
||||
test_odc.cpio \
|
||||
test_svr4.cpio \
|
||||
test_svr4_crc.cpio
|
||||
|
||||
all: $(ARCHIVES)
|
||||
|
||||
test_odc.cpio: $(SOURCES)
|
||||
echo $(SOURCES) | tr " " "\n" | cpio -o --owner=0:0 --format=odc > $@
|
||||
|
||||
test_svr4.cpio: $(SOURCES)
|
||||
echo $(SOURCES) | tr " " "\n" | cpio -o --owner=0:0 --format=newc > $@
|
||||
|
||||
test_svr4_crc.cpio: $(SOURCES)
|
||||
echo $(SOURCES) | tr " " "\n" | cpio -o --owner=0:0 --format=crc > $@
|
||||
|
||||
clean:
|
||||
rm -f $(ARCHIVES) version.txt
|
||||
|
||||
.PHONY: all clean
|
1
vendor/github.com/cavaliercoder/go-cpio/testdata/checklist.txt
generated
vendored
Normal file
1
vendor/github.com/cavaliercoder/go-cpio/testdata/checklist.txt
generated
vendored
Normal file
@ -0,0 +1 @@
|
||||
todo.txt
|
4
vendor/github.com/cavaliercoder/go-cpio/testdata/gophers.txt
generated
vendored
Normal file
4
vendor/github.com/cavaliercoder/go-cpio/testdata/gophers.txt
generated
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
Gopher names:
|
||||
George
|
||||
Geoffrey
|
||||
Gonzo
|
1
vendor/github.com/cavaliercoder/go-cpio/testdata/readme.txt
generated
vendored
Normal file
1
vendor/github.com/cavaliercoder/go-cpio/testdata/readme.txt
generated
vendored
Normal file
@ -0,0 +1 @@
|
||||
This archive contains some text files.
|
BIN
vendor/github.com/cavaliercoder/go-cpio/testdata/test_odc.cpio
generated
vendored
Normal file
BIN
vendor/github.com/cavaliercoder/go-cpio/testdata/test_odc.cpio
generated
vendored
Normal file
Binary file not shown.
BIN
vendor/github.com/cavaliercoder/go-cpio/testdata/test_svr4.cpio
generated
vendored
Normal file
BIN
vendor/github.com/cavaliercoder/go-cpio/testdata/test_svr4.cpio
generated
vendored
Normal file
Binary file not shown.
BIN
vendor/github.com/cavaliercoder/go-cpio/testdata/test_svr4_crc.cpio
generated
vendored
Normal file
BIN
vendor/github.com/cavaliercoder/go-cpio/testdata/test_svr4_crc.cpio
generated
vendored
Normal file
Binary file not shown.
1
vendor/github.com/cavaliercoder/go-cpio/testdata/todo.txt
generated
vendored
Normal file
1
vendor/github.com/cavaliercoder/go-cpio/testdata/todo.txt
generated
vendored
Normal file
@ -0,0 +1 @@
|
||||
Get animal handling license.
|
128
vendor/github.com/cavaliercoder/go-cpio/writer.go
generated
vendored
Normal file
128
vendor/github.com/cavaliercoder/go-cpio/writer.go
generated
vendored
Normal file
@ -0,0 +1,128 @@
|
||||
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
|
||||
}
|
Reference in New Issue
Block a user