cpio

package module
v1.0.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 28, 2021 License: BSD-3-Clause Imports: 11 Imported by: 22

README

cpio

Go Reference Build Status Go Report Card

Package cpio provides readers and writers for the CPIO archive file format.

Currently, only the SVR4 (New ASCII) format is supported, both with and without checksums.

Copyright 2021, Ryan Armstrong ryan@cavaliercoder.com

Documentation

Overview

Package cpio providers readers and writers for CPIO archives. Currently, only the SVR4 (New ASCII) format is supported, both with and without checksums.

This package aims to be feel like Go's archive/tar package.

See the CPIO man page: https://www.freebsd.org/cgi/man.cgi?query=cpio&sektion=5

Example
package main

import (
	"bytes"
	"fmt"
	"io"
	"log"
	"os"

	"github.com/cavaliergopher/cpio"
)

func main() {
	// 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.
	r := cpio.NewReader(buf)

	// 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.

Index

Examples

Constants

View Source
const (
	// TypeReg indicates a regular file
	TypeReg = 0100000

	// The following are header-only flags and may not have a data body.
	TypeSocket  = 0140000 // Socket
	TypeSymlink = 0120000 // Symbolic link
	TypeBlock   = 060000  // Block device node
	TypeDir     = 040000  // Directory
	TypeChar    = 020000  // Character device node
	TypeFifo    = 010000  // FIFO node
)
View Source
const (
	ModeSetuid = 04000 // Set uid
	ModeSetgid = 02000 // Set gid
	ModeSticky = 01000 // Save text (sticky bit)

	ModeType = 0170000 // Mask for the type bits
	ModePerm = 0777    // Unix permission bits
)

Variables

View Source
var (
	// ErrWriteTooLong indicates that an attempt was made to write more than
	// Header.Size bytes to the current file.
	ErrWriteTooLong = errors.New("cpio: write too long")

	// ErrWriteAfterClose indicates that an attempt was made to write to the
	// CPIO archive after it was closed.
	ErrWriteAfterClose = errors.New("cpio: write after close")
)
View Source
var (
	// ErrHeader indicates there was an error decoding a CPIO header entry.
	ErrHeader = errors.New("cpio: invalid cpio header")
)

Functions

func NewHash

func NewHash() hash.Hash32

NewHash returns a new hash.Hash32 for computing SVR4 checksums.

Example
// 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)

// 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 := NewHash()
	_, err = io.CopyN(h, r, hdr.Size)
	if err != nil {
		log.Fatal(err)
	}

	// check hash matches header checksum
	sum := h.Sum32()
	if sum == hdr.Checksum {
		fmt.Printf("Checksum OK: %s (%08X)\n", hdr.Name, hdr.Checksum)
	} else {
		fmt.Printf("Checksum FAIL: %s - expected %08X, got %08X\n", hdr.Name, hdr.Checksum, sum)
	}
}
Output:

Checksum OK: gophers.txt (00000C98)
Checksum OK: readme.txt (00000E3D)
Checksum OK: todo.txt (00000A52)

Types

type FileMode

type FileMode uint32

A FileMode represents a file's mode and permission bits.

func (FileMode) IsDir

func (m FileMode) IsDir() bool

IsDir reports whether m describes a directory. That is, it tests for the TypeDir bit being set in m.

func (FileMode) IsRegular

func (m FileMode) IsRegular() bool

IsRegular reports whether m describes a regular file. That is, it tests for the TypeReg bit being set in m.

func (FileMode) Perm

func (m FileMode) Perm() FileMode

Perm returns the Unix permission bits in m.

func (FileMode) String

func (m FileMode) String() string
type Header struct {
	Name     string // Name of the file entry
	Linkname string // Target name of link (valid for TypeLink or TypeSymlink)
	Links    int    // Number of inbound links

	Size int64    // Size in bytes
	Mode FileMode // Permission and mode bits
	Uid  int      // User id of the owner
	Guid int      // Group id of the owner

	ModTime time.Time // Modification time

	Checksum uint32 // Computed checksum

	DeviceID int
	Inode    int64 // Inode number
	// contains filtered or unexported fields
}

A Header represents a single header in a CPIO archive. Some fields may not be populated.

For forward compatibility, users that retrieve a Header from Reader.Next, mutate it in some ways, and then pass it back to Writer.WriteHeader should do so by creating a new Header and copying the fields that they are interested in preserving.

func FileInfoHeader

func FileInfoHeader(fi os.FileInfo, link string) (*Header, error)

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.

Since fs.FileInfo's Name method returns only the base name of the file it describes, it may be necessary to modify Header.Name to provide the full path name of the file.

func (*Header) FileInfo

func (h *Header) FileInfo() os.FileInfo

FileInfo returns an fs.FileInfo for the Header.

type Reader

type Reader struct {
	// contains filtered or unexported fields
}

Reader provides sequential access to the contents of a CPIO archive. Reader.Next advances to the next file in the archive (including the first), and then Reader can be treated as an io.Reader to access the file's data.

func NewReader

func NewReader(r io.Reader) *Reader

NewReader creates a new Reader reading from r.

func (*Reader) Next

func (r *Reader) Next() (*Header, error)

Next advances to the next entry in the CPIO archive. The Header.Size determines how many bytes can be read for the next file. Any remaining data in the current file is automatically discarded.

io.EOF is returned at the end of the input.

func (*Reader) Read

func (r *Reader) Read(p []byte) (n int, err error)

Read reads from the current file in the CPIO archive. It returns (0, io.EOF) when it reaches the end of that file, until Next is called to advance to the next file.

Calling Read on special types like TypeLink, TypeSymlink, TypeChar, TypeBlock, TypeDir, and TypeFifo returns (0, io.EOF) regardless of what the Header.Size claims.

type Writer

type Writer struct {
	// contains filtered or unexported fields
}

Writer provides sequential writing of a CPIO archive. Write.WriteHeader begins a new file with the provided Header, and then Writer can be treated as an io.Writer to supply that file's data.

func NewWriter

func NewWriter(w io.Writer) *Writer

NewWriter creates a new Writer writing to w.

func (*Writer) Close

func (w *Writer) Close() error

Close closes the CPIO archive by flushing the padding, and writing the footer. If the current file (from a prior call to WriteHeader) is not fully written, then this returns an error.

func (*Writer) Flush

func (w *Writer) Flush() error

Flush finishes writing the current file's block padding. The current file must be fully written before Flush can be called.

This is unnecessary as the next call to WriteHeader or Close will implicitly flush out the file's padding.

func (*Writer) Write

func (w *Writer) Write(p []byte) (n int, err error)

Write writes to the current file in the CPIO archive. Write returns the error ErrWriteTooLong if more than Header.Size bytes are written after WriteHeader.

Calling Write on special types like TypeLink, TypeSymlink, TypeChar, TypeBlock, TypeDir, and TypeFifo returns (0, ErrWriteTooLong) regardless of what the Header.Size claims.

func (*Writer) WriteHeader

func (w *Writer) WriteHeader(hdr *Header) (err error)

WriteHeader writes hdr and prepares to accept the file's contents. The Header.Size determines how many bytes can be written for the next file. If the current file is not fully written, then this returns an error. This implicitly flushes any padding necessary before writing the header.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL