pax_global_header00006660000000000000000000000064142173633220014515gustar00rootroot0000000000000052 comment=860d6b2a69198646830f4139ce6ba140135c4421 golang-github-u-root-uio-0.0~git20220204.dac05f7/000077500000000000000000000000001421736332200207665ustar00rootroot00000000000000golang-github-u-root-uio-0.0~git20220204.dac05f7/.circleci/000077500000000000000000000000001421736332200226215ustar00rootroot00000000000000golang-github-u-root-uio-0.0~git20220204.dac05f7/.circleci/config.yml000066400000000000000000000024061421736332200246130ustar00rootroot00000000000000version: 2 templates: gomod-template: &gomod-template working_directory: /home/circleci/uio environment: - CGO_ENABLED: 0 - GO111MODULE: "on" go116-template: &go116-template docker: - image: circleci/golang:1.16 workflows: version: 2 build: jobs: - clean - build: requires: - clean jobs: clean: <<: [*go116-template, *gomod-template] steps: - checkout - run: name: vet command: go vet ./... - run: name: gofmt command: | test -z "$(gofmt -s -l $(find -name '*.go' | grep -v /vendor/))" - run: name: go mod tidy command: | go mod tidy git status if [[ -n "$(git status --porcelain .)" ]]; then echo 'go.mod/go.sum is out-of-date: run `go mod tidy` and then check in the changes' echo 'If `go mod tidy` results in no changes, make sure you are using the latest relase of Go' git status --porcelain . exit 1 fi build: <<: [*go116-template, *gomod-template] steps: - checkout - run: go env - run: go build ./... - run: go test ./... - run: ./cross-compile.sh golang-github-u-root-uio-0.0~git20220204.dac05f7/.gitignore000066400000000000000000000004151421736332200227560ustar00rootroot00000000000000# Binaries for programs and plugins *.exe *.exe~ *.dll *.so *.dylib # Test binary, built with `go test -c` *.test # Output of the go coverage tool, specifically when used with LiteIDE *.out # Dependency directories (remove the comment below to include it) # vendor/ golang-github-u-root-uio-0.0~git20220204.dac05f7/LICENSE000066400000000000000000000027571421736332200220060ustar00rootroot00000000000000BSD 3-Clause License Copyright (c) 2012-2021, u-root Authors All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * 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. * 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. golang-github-u-root-uio-0.0~git20220204.dac05f7/cp/000077500000000000000000000000001421736332200213705ustar00rootroot00000000000000golang-github-u-root-uio-0.0~git20220204.dac05f7/cp/cmp/000077500000000000000000000000001421736332200221475ustar00rootroot00000000000000golang-github-u-root-uio-0.0~git20220204.dac05f7/cp/cmp/cmp.go000066400000000000000000000052621421736332200232620ustar00rootroot00000000000000// Copyright 2018 the u-root Authors. All rights reserved // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // Package cmp compares trees of files. // // cmp is an internal package for pkg/cp's and cmds/core/cp's tests. package cmp import ( "fmt" "io/ioutil" "os" "path/filepath" "reflect" "github.com/u-root/uio/cp" "github.com/u-root/uio/uio" ) // isEqualFile compare two files by checksum func isEqualFile(fpath1, fpath2 string) error { file1, err := os.Open(fpath1) if err != nil { return err } defer file1.Close() file2, err := os.Open(fpath2) if err != nil { return err } defer file2.Close() if !uio.ReaderAtEqual(file1, file2) { return fmt.Errorf("%q and %q do not have equal content", fpath1, fpath2) } return nil } func readDirNames(path string) ([]string, error) { entries, err := ioutil.ReadDir(path) if err != nil { return nil, err } var basenames []string for _, entry := range entries { basenames = append(basenames, entry.Name()) } return basenames, nil } func stat(o cp.Options, path string) (os.FileInfo, error) { if o.NoFollowSymlinks { return os.Lstat(path) } return os.Stat(path) } // IsEqualTree compare the content in the file trees in src and dst paths func IsEqualTree(o cp.Options, src, dst string) error { srcInfo, err := stat(o, src) if err != nil { return err } dstInfo, err := stat(o, dst) if err != nil { return err } if sm, dm := srcInfo.Mode()&os.ModeType, dstInfo.Mode()&os.ModeType; sm != dm { return fmt.Errorf("mismatched mode: %q has mode %s while %q has mode %s", src, sm, dst, dm) } switch { case srcInfo.Mode().IsDir(): srcEntries, err := readDirNames(src) if err != nil { return err } dstEntries, err := readDirNames(dst) if err != nil { return err } // ioutil.ReadDir guarantees these are sorted. if !reflect.DeepEqual(srcEntries, dstEntries) { return fmt.Errorf("directory contents did not match:\n%q had %v\n%q had %v", src, srcEntries, dst, dstEntries) } for _, basename := range srcEntries { if err := IsEqualTree(o, filepath.Join(src, basename), filepath.Join(dst, basename)); err != nil { return err } } return nil case srcInfo.Mode().IsRegular(): return isEqualFile(src, dst) case srcInfo.Mode()&os.ModeSymlink == os.ModeSymlink: srcTarget, err := os.Readlink(src) if err != nil { return err } dstTarget, err := os.Readlink(dst) if err != nil { return err } if srcTarget != dstTarget { return fmt.Errorf("target mismatch: symlink %q had target %q, while %q had target %q", src, srcTarget, dst, dstTarget) } return nil default: return fmt.Errorf("unsupported mode: %s", srcInfo.Mode()) } } golang-github-u-root-uio-0.0~git20220204.dac05f7/cp/cp.go000066400000000000000000000070011421736332200223170ustar00rootroot00000000000000// Copyright 2018 the u-root Authors. All rights reserved // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // Package cp implements routines to copy files. // // CopyTree in particular copies entire trees of files. // // Only directories, symlinks, and regular files are currently supported. package cp import ( "errors" "fmt" "io" "os" "path/filepath" ) // ErrSkip can be returned by PreCallback to skip a file. var ErrSkip = errors.New("skip") // Options are configuration options for how copying files should behave. type Options struct { // If NoFollowSymlinks is set, Copy copies the symlink itself rather // than following the symlink and copying the file it points to. NoFollowSymlinks bool // PreCallback is called on each file to be copied before it is copied // if specified. // // If PreCallback returns ErrSkip, the file is skipped and Copy returns // nil. // // If PreCallback returns another non-nil error, the file is not copied // and Copy returns the error. PreCallback func(src, dst string, srcfi os.FileInfo) error // PostCallback is called on each file after it is copied if specified. PostCallback func(src, dst string) } // Default are the default options. Default follows symlinks. var Default = Options{} // NoFollowSymlinks is the default options with following symlinks turned off. var NoFollowSymlinks = Options{ NoFollowSymlinks: true, } func (o Options) stat(path string) (os.FileInfo, error) { if o.NoFollowSymlinks { return os.Lstat(path) } return os.Stat(path) } // Copy copies a file at src to dst. func (o Options) Copy(src, dst string) error { srcInfo, err := o.stat(src) if err != nil { return err } if o.PreCallback != nil { if err := o.PreCallback(src, dst, srcInfo); err == ErrSkip { return nil } else if err != nil { return err } } if err := copyFile(src, dst, srcInfo); err != nil { return err } if o.PostCallback != nil { o.PostCallback(src, dst) } return nil } // CopyTree recursively copies all files in the src tree to dst. func (o Options) CopyTree(src, dst string) error { return filepath.Walk(src, func(path string, fi os.FileInfo, err error) error { if err != nil { return err } rel, err := filepath.Rel(src, path) if err != nil { return err } return o.Copy(path, filepath.Join(dst, rel)) }) } // Copy src file to dst file using Default's config. func Copy(src, dst string) error { return Default.Copy(src, dst) } // CopyTree recursively copies all files in the src tree to dst using Default's // config. func CopyTree(src, dst string) error { return Default.CopyTree(src, dst) } func copyFile(src, dst string, srcInfo os.FileInfo) error { m := srcInfo.Mode() switch { case m.IsDir(): return os.MkdirAll(dst, srcInfo.Mode().Perm()) case m.IsRegular(): return copyRegularFile(src, dst, srcInfo) case m&os.ModeSymlink == os.ModeSymlink: // Yeah, this may not make any sense logically. But this is how // cp does it. target, err := os.Readlink(src) if err != nil { return err } return os.Symlink(target, dst) default: return &os.PathError{ Op: "copy", Path: src, Err: fmt.Errorf("unsupported file mode %s", m), } } } func copyRegularFile(src, dst string, srcfi os.FileInfo) error { srcf, err := os.Open(src) if err != nil { return err } defer srcf.Close() dstf, err := os.OpenFile(dst, os.O_RDWR|os.O_CREATE|os.O_TRUNC, srcfi.Mode().Perm()) if err != nil { return err } defer dstf.Close() _, err = io.Copy(dstf, srcf) return err } golang-github-u-root-uio-0.0~git20220204.dac05f7/cp/cp_test.go000066400000000000000000000033261421736332200233640ustar00rootroot00000000000000// Copyright 2019 the u-root Authors. All rights reserved // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package cp_test import ( "io/ioutil" "os" "path/filepath" "testing" "github.com/u-root/uio/cp" "github.com/u-root/uio/cp/cmp" ) func copyAndTest(t *testing.T, o cp.Options, src, dst string) { if err := o.Copy(src, dst); err != nil { t.Fatalf("Copy(%q -> %q) = %v, want %v", src, dst, err, nil) } if err := cmp.IsEqualTree(o, src, dst); err != nil { t.Fatalf("Expected %q and %q to be same, got %v", src, dst, err) } } func TestSimpleCopy(t *testing.T) { tmpDir, err := ioutil.TempDir("", "u-root-pkg-cp-") if err != nil { t.Fatal(err) } defer os.RemoveAll(tmpDir) // Copy a directory. origd := filepath.Join(tmpDir, "directory") if err := os.Mkdir(origd, 0744); err != nil { t.Fatal(err) } copyAndTest(t, cp.Default, origd, filepath.Join(tmpDir, "directory-copied")) copyAndTest(t, cp.NoFollowSymlinks, origd, filepath.Join(tmpDir, "directory-copied-2")) // Copy a file. origf := filepath.Join(tmpDir, "normal-file") if err := ioutil.WriteFile(origf, []byte("F is for fire that burns down the whole town"), 0766); err != nil { t.Fatal(err) } copyAndTest(t, cp.Default, origf, filepath.Join(tmpDir, "normal-file-copied")) copyAndTest(t, cp.NoFollowSymlinks, origf, filepath.Join(tmpDir, "normal-file-copied-2")) // Copy a symlink. origs := filepath.Join(tmpDir, "foobar") // foobar -> normal-file if err := os.Symlink(origf, origs); err != nil { t.Fatal(err) } copyAndTest(t, cp.Default, origf, filepath.Join(tmpDir, "foobar-copied")) copyAndTest(t, cp.NoFollowSymlinks, origf, filepath.Join(tmpDir, "foobar-copied-just-symlink")) } golang-github-u-root-uio-0.0~git20220204.dac05f7/cross-compile.sh000077500000000000000000000011341421736332200241030ustar00rootroot00000000000000#!/bin/bash set -eu GO="go" if [ -v GOROOT ]; then GO="$GOROOT/bin/go" fi function buildem() { for GOOS in $1 do for GOARCH in $2 do echo "Building $GOOS/$GOARCH..." GOOS=$GOOS GOARCH=$GOARCH $GO build ./... done done } GOARCHES="386 amd64 arm arm64 ppc64 ppc64le s390x mips mipsle mips64 mips64le" buildem "linux" "$GOARCHES" GOARCHES_BSD="386 amd64 arm arm64" GOOSES_BSD="freebsd netbsd openbsd" buildem "$GOOSES_BSD" "$GOARCHES_BSD" GOOSES_AMD64="solaris windows" buildem "$GOOSES_AMD64" "amd64" GOARCHES_DARWIN="arm64 amd64" buildem "darwin" "$GOARCHES_DARWIN" golang-github-u-root-uio-0.0~git20220204.dac05f7/go.mod000066400000000000000000000001431421736332200220720ustar00rootroot00000000000000module github.com/u-root/uio go 1.15 require golang.org/x/sys v0.0.0-20210525143221-35b2ab0089ea golang-github-u-root-uio-0.0~git20220204.dac05f7/go.sum000066400000000000000000000003171421736332200221220ustar00rootroot00000000000000golang.org/x/sys v0.0.0-20210525143221-35b2ab0089ea h1:+WiDlPBBaO+h9vPNZi8uJ3k4BkKQB7Iow3aqwHVA5hI= golang.org/x/sys v0.0.0-20210525143221-35b2ab0089ea/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang-github-u-root-uio-0.0~git20220204.dac05f7/rand/000077500000000000000000000000001421736332200217125ustar00rootroot00000000000000golang-github-u-root-uio-0.0~git20220204.dac05f7/rand/random.go000066400000000000000000000033361421736332200235260ustar00rootroot00000000000000// Copyright 2019 the u-root Authors. All rights reserved // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // Package rand implements cancelable reads from a cryptographically safe // random number source. package rand import ( "context" ) // Reader is a cryptographically safe random number source. var Reader = DefaultReaderWithContext(context.Background()) // Read blockingly reads from a random number source. func Read(b []byte) (int, error) { return Reader.Read(b) } // ReadContext is a context-aware reader for random numbers. func ReadContext(ctx context.Context, b []byte) (int, error) { return Reader.ReadContext(ctx, b) } // ContextReader is a cancelable io.Reader. type ContextReader interface { // Read behaves like a blocking io.Reader.Read. // // Read wraps ReadContext with a background context. Read(b []byte) (n int, err error) // ReadContext is an io.Reader that blocks until data is available or // until ctx is done. ReadContext(ctx context.Context, b []byte) (n int, err error) } // contextReader is a cancelable io.Reader. type contextReader interface { ReadContext(context.Context, []byte) (int, error) } // ctxReader takes a contextReader and turns it into a ContextReader. type ctxReader struct { contextReader ctx context.Context } func (cr ctxReader) Read(b []byte) (int, error) { return cr.contextReader.ReadContext(cr.ctx, b) } // DefaultReaderWithContext returns a context-aware io.Reader. // // Because this stores the context, only use this in situations where an // io.Reader is unavoidable. func DefaultReaderWithContext(ctx context.Context) ContextReader { return ctxReader{ ctx: ctx, contextReader: defaultContextReader, } } golang-github-u-root-uio-0.0~git20220204.dac05f7/rand/random_linux.go000066400000000000000000000035331421736332200247440ustar00rootroot00000000000000// Copyright 2019 the u-root Authors. All rights reserved // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package rand import ( "context" "log" "os" "sync" "syscall" "time" "golang.org/x/sys/unix" ) var defaultContextReader = &getrandomReader{} var backupReader = &urandomReader{} type getrandomReader struct { once sync.Once backup bool } // ReadContext implements a cancelable read from /dev/urandom. func (r *getrandomReader) ReadContext(ctx context.Context, b []byte) (int, error) { r.once.Do(func() { if os.Getenv("UROOT_NOHWRNG") != "" { r.backup = true return } if _, err := unix.Getrandom(b, unix.GRND_NONBLOCK); err == syscall.ENOSYS { r.backup = true } }) if r.backup { return backupReader.ReadContext(ctx, b) } for { // getrandom(2) with GRND_NONBLOCK uses the urandom number // source, but only returns numbers if the crng has been // initialized. // // This is preferrable to /dev/urandom, as /dev/urandom will // make up fake random numbers until the crng has been // initialized. n, err := unix.Getrandom(b, unix.GRND_NONBLOCK) if err == nil { return n, err } select { case <-ctx.Done(): return 0, ctx.Err() default: if err != syscall.EAGAIN && err != syscall.EINTR { return n, err } } } } // ReadContextWithSlowLogs logs a helpful message if it takes a significant // amount of time (>2s) to produce random data. func (r *getrandomReader) ReadContextWithSlowLogs(ctx context.Context, b []byte) (int, error) { d := 2 * time.Second t := time.AfterFunc(d, func() { log.Printf("getrandom is taking a long time (>%v). "+ "If running on hardware, consider enabling Linux's CONFIG_RANDOM_TRUST_CPU=y. "+ "If running in a VM/emulator, try setting up virtio-rng.", d) }) defer t.Stop() return r.ReadContext(ctx, b) } golang-github-u-root-uio-0.0~git20220204.dac05f7/rand/random_std.go000066400000000000000000000011651421736332200243760ustar00rootroot00000000000000// Copyright 2020 the u-root Authors. All rights reserved // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // +build plan9 windows package rand import ( "context" "crypto/rand" ) var defaultContextReader = &cryptoRandReader{} type cryptoRandReader struct{} // ReadContext implements a cancelable read. func (r *cryptoRandReader) ReadContext(ctx context.Context, b []byte) (n int, err error) { ch := make(chan struct{}) go func() { n, err = rand.Reader.Read(b) close(ch) }() select { case <-ctx.Done(): return 0, ctx.Err() case <-ch: return n, err } } golang-github-u-root-uio-0.0~git20220204.dac05f7/rand/random_test.go000066400000000000000000000013471421736332200245650ustar00rootroot00000000000000// Copyright 2019 the u-root Authors. All rights reserved // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package rand import ( "context" "testing" "time" ) func TestRandomRead(t *testing.T) { b := make([]byte, 5) n, err := Read(b) if err != nil { t.Fatalf("got %v, expected nil err", err) } if n != 5 { t.Fatalf("got %d bytes, expected 5 bytes", n) } } func TestRandomReadContext(t *testing.T) { ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() b := make([]byte, 5) n, err := ReadContext(ctx, b) if err != nil { t.Fatalf("got %v, expected nil err", err) } if n != 5 { t.Fatalf("got %d bytes, expected 5 bytes", n) } } golang-github-u-root-uio-0.0~git20220204.dac05f7/rand/random_unix.go000066400000000000000000000004411421736332200245630ustar00rootroot00000000000000// Copyright 2019 the u-root Authors. All rights reserved // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // +build aix darwin dragonfly freebsd nacl netbsd openbsd solaris package rand var defaultContextReader = &urandomReader{} golang-github-u-root-uio-0.0~git20220204.dac05f7/rand/random_urandom.go000066400000000000000000000023311421736332200252450ustar00rootroot00000000000000// Copyright 2019 the u-root Authors. All rights reserved // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. //go:build aix || darwin || dragonfly || freebsd || nacl || netbsd || openbsd || solaris || linux // +build aix darwin dragonfly freebsd nacl netbsd openbsd solaris linux package rand import ( "context" "fmt" "sync" "syscall" "golang.org/x/sys/unix" ) // urandomReader is a contextReader. type urandomReader struct { once sync.Once // fd is expected to be non-blocking. fd int } func (r *urandomReader) init() error { var realErr error r.once.Do(func() { fd, err := unix.Open("/dev/urandom", unix.O_RDONLY, 0) if err != nil { realErr = fmt.Errorf("open(/dev/urandom): %v", err) return } r.fd = fd }) return realErr } // ReadContext implements a cancelable read from /dev/urandom. func (r *urandomReader) ReadContext(ctx context.Context, b []byte) (int, error) { if err := r.init(); err != nil { return 0, err } for { n, err := unix.Read(r.fd, b) if err == nil { return n, err } select { case <-ctx.Done(): return 0, ctx.Err() default: if err != syscall.EAGAIN && err != syscall.EINTR { return n, err } } } } golang-github-u-root-uio-0.0~git20220204.dac05f7/ubinary/000077500000000000000000000000001421736332200224375ustar00rootroot00000000000000golang-github-u-root-uio-0.0~git20220204.dac05f7/ubinary/big_endian.go000066400000000000000000000005251421736332200250470ustar00rootroot00000000000000// Copyright 2018 the u-root Authors. All rights reserved // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // +build mips mips64 ppc64 s390x package ubinary import ( "encoding/binary" ) // NativeEndian is $GOARCH's implementation of byte order. var NativeEndian = binary.BigEndian golang-github-u-root-uio-0.0~git20220204.dac05f7/ubinary/doc.go000066400000000000000000000003611421736332200235330ustar00rootroot00000000000000// Copyright 2018 the u-root Authors. All rights reserved // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // Package ubinary provides a native endian binary.ByteOrder. package ubinary golang-github-u-root-uio-0.0~git20220204.dac05f7/ubinary/little_endian.go000066400000000000000000000005721421736332200256050ustar00rootroot00000000000000// Copyright 2018 the u-root Authors. All rights reserved // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // +build 386 amd64 arm arm64 mipsle mips64le ppc64le riscv riscv64 package ubinary import ( "encoding/binary" ) // NativeEndian is $GOARCH's implementation of byte order. var NativeEndian = binary.LittleEndian golang-github-u-root-uio-0.0~git20220204.dac05f7/uio/000077500000000000000000000000001421736332200215625ustar00rootroot00000000000000golang-github-u-root-uio-0.0~git20220204.dac05f7/uio/alignreader.go000066400000000000000000000016701421736332200243720ustar00rootroot00000000000000// Copyright 2019 the u-root Authors. All rights reserved // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package uio import ( "io" ) // AlignReader keeps track of how many bytes were read so the reader can be // aligned at a future time. type AlignReader struct { R io.Reader N int } // Read reads from the underlying io.Reader. func (r *AlignReader) Read(b []byte) (int, error) { n, err := r.R.Read(b) r.N += n return n, err } // ReadByte reads one byte from the underlying io.Reader. func (r *AlignReader) ReadByte() (byte, error) { b := make([]byte, 1) _, err := io.ReadFull(r, b) return b[0], err } // Align aligns the reader to the given number of bytes and returns the // bytes read to pad it. func (r *AlignReader) Align(n int) ([]byte, error) { if r.N%n == 0 { return []byte{}, nil } pad := make([]byte, n-r.N%n) m, err := io.ReadFull(r, pad) return pad[:m], err } golang-github-u-root-uio-0.0~git20220204.dac05f7/uio/alignwriter.go000066400000000000000000000013571421736332200244460ustar00rootroot00000000000000// Copyright 2019 the u-root Authors. All rights reserved // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package uio import ( "bytes" "io" ) // AlignWriter keeps track of how many bytes were written so the writer can be // aligned at a future time. type AlignWriter struct { W io.Writer N int } // Write writes to the underlying io.Writew. func (w *AlignWriter) Write(b []byte) (int, error) { n, err := w.W.Write(b) w.N += n return n, err } // Align aligns the writer to the given number of bytes using the given pad // value. func (w *AlignWriter) Align(n int, pad byte) error { if w.N%n == 0 { return nil } _, err := w.Write(bytes.Repeat([]byte{pad}, n-w.N%n)) return err } golang-github-u-root-uio-0.0~git20220204.dac05f7/uio/buffer.go000066400000000000000000000211541421736332200233650ustar00rootroot00000000000000// Copyright 2018 the u-root Authors. All rights reserved // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package uio import ( "encoding/binary" "fmt" "github.com/u-root/uio/ubinary" ) // Marshaler is the interface implemented by an object that can marshal itself // into binary form. // // Marshal appends data to the buffer b. type Marshaler interface { Marshal(l *Lexer) } // Unmarshaler is the interface implemented by an object that can unmarshal a // binary representation of itself. // // Unmarshal Consumes data from the buffer b. type Unmarshaler interface { Unmarshal(l *Lexer) error } // ToBytes marshals m in the given byte order. func ToBytes(m Marshaler, order binary.ByteOrder) []byte { l := NewLexer(NewBuffer(nil), order) m.Marshal(l) return l.Data() } // FromBytes unmarshals b into obj in the given byte order. func FromBytes(obj Unmarshaler, b []byte, order binary.ByteOrder) error { l := NewLexer(NewBuffer(b), order) return obj.Unmarshal(l) } // ToBigEndian marshals m to big endian byte order. func ToBigEndian(m Marshaler) []byte { l := NewBigEndianBuffer(nil) m.Marshal(l) return l.Data() } // FromBigEndian unmarshals b into obj in big endian byte order. func FromBigEndian(obj Unmarshaler, b []byte) error { l := NewBigEndianBuffer(b) return obj.Unmarshal(l) } // ToLittleEndian marshals m to little endian byte order. func ToLittleEndian(m Marshaler) []byte { l := NewLittleEndianBuffer(nil) m.Marshal(l) return l.Data() } // FromLittleEndian unmarshals b into obj in little endian byte order. func FromLittleEndian(obj Unmarshaler, b []byte) error { l := NewLittleEndianBuffer(b) return obj.Unmarshal(l) } // Buffer implements functions to manipulate byte slices in a zero-copy way. type Buffer struct { // data is the underlying data. data []byte // byteCount keeps track of how many bytes have been consumed for // debugging. byteCount int } // NewBuffer Consumes b for marshaling or unmarshaling in the given byte order. func NewBuffer(b []byte) *Buffer { return &Buffer{data: b} } // Preallocate increases the capacity of the buffer by n bytes. func (b *Buffer) Preallocate(n int) { b.data = append(b.data, make([]byte, 0, n)...) } // WriteN appends n bytes to the Buffer and returns a slice pointing to the // newly appended bytes. func (b *Buffer) WriteN(n int) []byte { b.data = append(b.data, make([]byte, n)...) return b.data[len(b.data)-n:] } // ReadN consumes n bytes from the Buffer. It returns nil, false if there // aren't enough bytes left. func (b *Buffer) ReadN(n int) ([]byte, error) { if !b.Has(n) { return nil, fmt.Errorf("buffer too short at position %d: have %d bytes, want %d bytes", b.byteCount, b.Len(), n) } rval := b.data[:n] b.data = b.data[n:] b.byteCount += n return rval, nil } // Data is unConsumed data remaining in the Buffer. func (b *Buffer) Data() []byte { return b.data } // Has returns true if n bytes are available. func (b *Buffer) Has(n int) bool { return len(b.data) >= n } // Len returns the length of the remaining bytes. func (b *Buffer) Len() int { return len(b.data) } // Cap returns the available capacity. func (b *Buffer) Cap() int { return cap(b.data) } // Lexer is a convenient encoder/decoder for buffers. // // Use: // // func (s *something) Unmarshal(l *Lexer) { // s.Foo = l.Read8() // s.Bar = l.Read8() // s.Baz = l.Read16() // return l.Error() // } type Lexer struct { *Buffer // order is the byte order to write in / read in. order binary.ByteOrder // err err error } // NewLexer returns a new coder for buffers. func NewLexer(b *Buffer, order binary.ByteOrder) *Lexer { return &Lexer{ Buffer: b, order: order, } } // NewLittleEndianBuffer returns a new little endian coder for a new buffer. func NewLittleEndianBuffer(b []byte) *Lexer { return &Lexer{ Buffer: NewBuffer(b), order: binary.LittleEndian, } } // NewBigEndianBuffer returns a new big endian coder for a new buffer. func NewBigEndianBuffer(b []byte) *Lexer { return &Lexer{ Buffer: NewBuffer(b), order: binary.BigEndian, } } // NewNativeEndianBuffer returns a new native endian coder for a new buffer. func NewNativeEndianBuffer(b []byte) *Lexer { return &Lexer{ Buffer: NewBuffer(b), order: ubinary.NativeEndian, } } func (l *Lexer) setError(err error) { if l.err == nil { l.err = err } } // Consume returns a slice of the next n bytes from the buffer. // // Consume gives direct access to the underlying data. func (l *Lexer) Consume(n int) []byte { v, err := l.Buffer.ReadN(n) if err != nil { l.setError(err) return nil } return v } func (l *Lexer) append(n int) []byte { return l.Buffer.WriteN(n) } // Error returns an error if an error occurred reading from the buffer. func (l *Lexer) Error() error { return l.err } // FinError returns an error if an error occurred or if there is more data left // to read in the buffer. func (l *Lexer) FinError() error { if l.err != nil { return l.err } if l.Buffer.Len() > 0 { return fmt.Errorf("buffer contains more bytes than it should") } return nil } // Read8 reads a byte from the Buffer. // // If an error occurred, Error() will return a non-nil error. func (l *Lexer) Read8() uint8 { v := l.Consume(1) if v == nil { return 0 } return uint8(v[0]) } // Read16 reads a 16-bit value from the Buffer. // // If an error occurred, Error() will return a non-nil error. func (l *Lexer) Read16() uint16 { v := l.Consume(2) if v == nil { return 0 } return l.order.Uint16(v) } // Read32 reads a 32-bit value from the Buffer. // // If an error occurred, Error() will return a non-nil error. func (l *Lexer) Read32() uint32 { v := l.Consume(4) if v == nil { return 0 } return l.order.Uint32(v) } // Read64 reads a 64-bit value from the Buffer. // // If an error occurred, Error() will return a non-nil error. func (l *Lexer) Read64() uint64 { v := l.Consume(8) if v == nil { return 0 } return l.order.Uint64(v) } // CopyN returns a copy of the next n bytes. // // If an error occurred, Error() will return a non-nil error. func (l *Lexer) CopyN(n int) []byte { v := l.Consume(n) if v == nil { return nil } p := make([]byte, n) m := copy(p, v) return p[:m] } // ReadAll Consumes and returns a copy of all remaining bytes in the Buffer. // // If an error occurred, Error() will return a non-nil error. func (l *Lexer) ReadAll() []byte { return l.CopyN(l.Len()) } // ReadBytes reads exactly len(p) values from the Buffer. // // If an error occurred, Error() will return a non-nil error. func (l *Lexer) ReadBytes(p []byte) { copy(p, l.Consume(len(p))) } // Read implements io.Reader.Read. func (l *Lexer) Read(p []byte) (int, error) { v := l.Consume(len(p)) if v == nil { return 0, l.Error() } return copy(p, v), nil } // ReadData reads the binary representation of data from the buffer. // // See binary.Read. // // If an error occurred, Error() will return a non-nil error. func (l *Lexer) ReadData(data interface{}) { l.setError(binary.Read(l, l.order, data)) } // WriteData writes a binary representation of data to the buffer. // // See binary.Write. // // If an error occurred, Error() will return a non-nil error. func (l *Lexer) WriteData(data interface{}) { l.setError(binary.Write(l, l.order, data)) } // Write8 writes a byte to the Buffer. // // If an error occurred, Error() will return a non-nil error. func (l *Lexer) Write8(v uint8) { l.append(1)[0] = byte(v) } // Write16 writes a 16-bit value to the Buffer. // // If an error occurred, Error() will return a non-nil error. func (l *Lexer) Write16(v uint16) { l.order.PutUint16(l.append(2), v) } // Write32 writes a 32-bit value to the Buffer. // // If an error occurred, Error() will return a non-nil error. func (l *Lexer) Write32(v uint32) { l.order.PutUint32(l.append(4), v) } // Write64 writes a 64-bit value to the Buffer. // // If an error occurred, Error() will return a non-nil error. func (l *Lexer) Write64(v uint64) { l.order.PutUint64(l.append(8), v) } // Append returns a newly appended n-size Buffer to write to. // // If an error occurred, Error() will return a non-nil error. func (l *Lexer) Append(n int) []byte { return l.append(n) } // WriteBytes writes p to the Buffer. // // If an error occurred, Error() will return a non-nil error. func (l *Lexer) WriteBytes(p []byte) { copy(l.append(len(p)), p) } // Write implements io.Writer.Write. // // If an error occurred, Error() will return a non-nil error. func (l *Lexer) Write(p []byte) (int, error) { return copy(l.append(len(p)), p), nil } // Align appends bytes to align the length of the buffer to be divisible by n. func (l *Lexer) Align(n int) { pad := ((l.Len() + n - 1) &^ (n - 1)) - l.Len() l.Append(pad) } golang-github-u-root-uio-0.0~git20220204.dac05f7/uio/cached.go000066400000000000000000000041701421736332200233220ustar00rootroot00000000000000// Copyright 2018 the u-root Authors. All rights reserved // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package uio import ( "bytes" "io" ) // CachingReader is a lazily caching wrapper of an io.Reader. // // The wrapped io.Reader is only read from on demand, not upfront. type CachingReader struct { buf bytes.Buffer r io.Reader pos int eof bool } // NewCachingReader buffers reads from r. // // r is only read from when Read() is called. func NewCachingReader(r io.Reader) *CachingReader { return &CachingReader{ r: r, } } func (cr *CachingReader) read(p []byte) (int, error) { n, err := cr.r.Read(p) cr.buf.Write(p[:n]) if err == io.EOF || (n == 0 && err == nil) { cr.eof = true return n, io.EOF } return n, err } // NewReader returns a new io.Reader that reads cr from offset 0. func (cr *CachingReader) NewReader() io.Reader { return Reader(cr) } // Read reads from cr; implementing io.Reader. // // TODO(chrisko): Decide whether to keep this or only keep NewReader(). func (cr *CachingReader) Read(p []byte) (int, error) { n, err := cr.ReadAt(p, int64(cr.pos)) cr.pos += n return n, err } // ReadAt reads from cr; implementing io.ReaderAt. func (cr *CachingReader) ReadAt(p []byte, off int64) (int, error) { if len(p) == 0 { return 0, nil } end := int(off) + len(p) // Is the caller asking for some uncached bytes? unread := end - cr.buf.Len() if unread > 0 { // Avoiding allocations: use `p` to read more bytes. for unread > 0 { toRead := unread % len(p) if toRead == 0 { toRead = len(p) } m, err := cr.read(p[:toRead]) unread -= m if err == io.EOF { break } if err != nil { return 0, err } } } // If this is true, the entire file was read just to find out, but the // offset is beyond the end of the file. if off > int64(cr.buf.Len()) { return 0, io.EOF } var err error // Did the caller ask for more than was available? // // Note that any io.ReaderAt implementation *must* return an error for // short reads. if cr.eof && unread > 0 { err = io.EOF } return copy(p, cr.buf.Bytes()[off:]), err } golang-github-u-root-uio-0.0~git20220204.dac05f7/uio/cached_test.go000066400000000000000000000107361421736332200243660ustar00rootroot00000000000000// Copyright 2018 the u-root Authors. All rights reserved // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package uio import ( "bytes" "fmt" "io" "testing" ) func TestCachingReaderRead(t *testing.T) { type read struct { // Buffer sizes to call Read with. size int // Buffer value corresponding Read(size) we want. want []byte // Error corresponding to Read(size) we want. err error } for i, tt := range []struct { // Content of the underlying io.Reader. content []byte // Read calls to make in order. reads []read }{ { content: []byte{0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99}, reads: []read{ { size: 0, }, { size: 1, want: []byte{0x11}, }, { size: 2, want: []byte{0x22, 0x33}, }, { size: 0, }, { size: 3, want: []byte{0x44, 0x55, 0x66}, }, { size: 4, want: []byte{0x77, 0x88, 0x99}, err: io.EOF, }, }, }, { content: []byte{0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99}, reads: []read{ { size: 11, want: []byte{0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99}, err: io.EOF, }, }, }, { content: nil, reads: []read{ { size: 2, err: io.EOF, }, { size: 0, }, }, }, { content: []byte{0x33, 0x22, 0x11}, reads: []read{ { size: 3, want: []byte{0x33, 0x22, 0x11}, err: nil, }, { size: 0, }, { size: 1, err: io.EOF, }, }, }, } { t.Run(fmt.Sprintf("Test [%02d]", i), func(t *testing.T) { buf := NewCachingReader(bytes.NewBuffer(tt.content)) for j, r := range tt.reads { p := make([]byte, r.size) m, err := buf.Read(p) if err != r.err { t.Errorf("Read#%d(%d) = %v, want %v", j, r.size, err, r.err) } if m != len(r.want) { t.Errorf("Read#%d(%d) = %d, want %d", j, r.size, m, len(r.want)) } if !bytes.Equal(r.want, p[:m]) { t.Errorf("Read#%d(%d) = %v, want %v", j, r.size, p[:m], r.want) } } }) } } func TestCachingReaderReadAt(t *testing.T) { type readAt struct { // Buffer sizes to call Read with. size int // Offset to read from. off int64 // Buffer value corresponding Read(size) we want. want []byte // Error corresponding to Read(size) we want. err error } for i, tt := range []struct { // Content of the underlying io.Reader. content []byte // Read calls to make in order. reads []readAt }{ { content: []byte{0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99}, reads: []readAt{ { off: 0, size: 0, }, { off: 0, size: 1, want: []byte{0x11}, }, { off: 1, size: 2, want: []byte{0x22, 0x33}, }, { off: 0, size: 0, }, { off: 3, size: 3, want: []byte{0x44, 0x55, 0x66}, }, { off: 6, size: 4, want: []byte{0x77, 0x88, 0x99}, err: io.EOF, }, { off: 0, size: 9, want: []byte{0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99}, }, { off: 0, size: 10, want: []byte{0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99}, err: io.EOF, }, { off: 0, size: 8, want: []byte{0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88}, }, }, }, { content: []byte{0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99}, reads: []readAt{ { off: 10, size: 10, err: io.EOF, }, { off: 5, size: 4, want: []byte{0x66, 0x77, 0x88, 0x99}, }, }, }, { content: []byte{0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99}, reads: []readAt{ { size: 9, want: []byte{0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99}, }, { off: 5, size: 4, want: []byte{0x66, 0x77, 0x88, 0x99}, }, { off: 9, size: 1, err: io.EOF, }, }, }, } { t.Run(fmt.Sprintf("Test [%02d]", i), func(t *testing.T) { buf := NewCachingReader(bytes.NewBuffer(tt.content)) for j, r := range tt.reads { p := make([]byte, r.size) m, err := buf.ReadAt(p, r.off) if err != r.err { t.Errorf("Read#%d(%d) = %v, want %v", j, r.size, err, r.err) } if m != len(r.want) { t.Errorf("Read#%d(%d) = %d, want %d", j, r.size, m, len(r.want)) } if !bytes.Equal(r.want, p[:m]) { t.Errorf("Read#%d(%d) = %v, want %v", j, r.size, p[:m], r.want) } } }) } } golang-github-u-root-uio-0.0~git20220204.dac05f7/uio/lazy.go000066400000000000000000000045611421736332200230760ustar00rootroot00000000000000// Copyright 2018 the u-root Authors. All rights reserved // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package uio import ( "fmt" "io" "os" ) // LazyOpener is a lazy io.Reader. // // LazyOpener will use a given open function to derive an io.Reader when Read // is first called on the LazyOpener. type LazyOpener struct { r io.Reader err error open func() (io.Reader, error) } // NewLazyOpener returns a lazy io.Reader based on `open`. func NewLazyOpener(open func() (io.Reader, error)) io.ReadCloser { return &LazyOpener{open: open} } // Read implements io.Reader.Read lazily. // // If called for the first time, the underlying reader will be obtained and // then used for the first and subsequent calls to Read. func (lr *LazyOpener) Read(p []byte) (int, error) { if lr.r == nil && lr.err == nil { lr.r, lr.err = lr.open() } if lr.err != nil { return 0, lr.err } return lr.r.Read(p) } // Close implements io.Closer.Close. func (lr *LazyOpener) Close() error { if c, ok := lr.r.(io.Closer); ok { return c.Close() } return nil } // LazyOpenerAt is a lazy io.ReaderAt. // // LazyOpenerAt will use a given open function to derive an io.ReaderAt when // ReadAt is first called. type LazyOpenerAt struct { r io.ReaderAt s string err error open func() (io.ReaderAt, error) } // NewLazyFile returns a lazy ReaderAt opened from path. func NewLazyFile(path string) *LazyOpenerAt { if len(path) == 0 { return nil } return NewLazyOpenerAt(path, func() (io.ReaderAt, error) { return os.Open(path) }) } // NewLazyOpenerAt returns a lazy io.ReaderAt based on `open`. func NewLazyOpenerAt(filename string, open func() (io.ReaderAt, error)) *LazyOpenerAt { return &LazyOpenerAt{s: filename, open: open} } // String implements fmt.Stringer. func (loa *LazyOpenerAt) String() string { if len(loa.s) > 0 { return loa.s } if loa.r != nil { return fmt.Sprintf("%v", loa.r) } return "unopened mystery file" } // ReadAt implements io.ReaderAt.ReadAt. func (loa *LazyOpenerAt) ReadAt(p []byte, off int64) (int, error) { if loa.r == nil && loa.err == nil { loa.r, loa.err = loa.open() } if loa.err != nil { return 0, loa.err } return loa.r.ReadAt(p, off) } // Close implements io.Closer.Close. func (loa *LazyOpenerAt) Close() error { if c, ok := loa.r.(io.Closer); ok { return c.Close() } return nil } golang-github-u-root-uio-0.0~git20220204.dac05f7/uio/lazy_test.go000066400000000000000000000030231421736332200241250ustar00rootroot00000000000000// Copyright 2018 the u-root Authors. All rights reserved // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package uio import ( "fmt" "io" "testing" ) type mockReader struct { // called is whether Read has been called. called bool // err is the error to return on Read. err error } func (m *mockReader) Read([]byte) (int, error) { m.called = true return 0, m.err } func TestLazyOpenerRead(t *testing.T) { for i, tt := range []struct { openErr error openReader *mockReader wantCalled bool }{ { openErr: nil, openReader: &mockReader{}, wantCalled: true, }, { openErr: io.EOF, openReader: nil, wantCalled: false, }, { openErr: nil, openReader: &mockReader{ err: io.ErrUnexpectedEOF, }, wantCalled: true, }, } { t.Run(fmt.Sprintf("Test #%02d", i), func(t *testing.T) { var opened bool lr := NewLazyOpener(func() (io.Reader, error) { opened = true return tt.openReader, tt.openErr }) _, err := lr.Read([]byte{}) if !opened { t.Fatalf("Read(): Reader was not opened") } if tt.openErr != nil && err != tt.openErr { t.Errorf("Read() = %v, want %v", err, tt.openErr) } if tt.openReader != nil { if got, want := tt.openReader.called, tt.wantCalled; got != want { t.Errorf("mockReader.Read() called is %v, want %v", got, want) } if tt.openReader.err != nil && err != tt.openReader.err { t.Errorf("Read() = %v, want %v", err, tt.openReader.err) } } }) } } golang-github-u-root-uio-0.0~git20220204.dac05f7/uio/linewriter.go000066400000000000000000000024631421736332200243020ustar00rootroot00000000000000// Copyright 2019 the u-root Authors. All rights reserved // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package uio import ( "bytes" "io" ) // LineWriter processes one line of log output at a time. type LineWriter interface { // OneLine is always called with exactly one line of output. OneLine(b []byte) } // FullLineWriter returns an io.Writer that waits for a full line of prints // before calling w.Write on one line each. func FullLineWriter(w LineWriter) io.WriteCloser { return &fullLineWriter{w: w} } type fullLineWriter struct { w LineWriter buffer []byte } func (fsw *fullLineWriter) printBuf() { bufs := bytes.Split(fsw.buffer, []byte{'\n'}) for _, buf := range bufs { if len(buf) != 0 { fsw.w.OneLine(buf) } } fsw.buffer = nil } // Write implements io.Writer and buffers p until at least one full line is // received. func (fsw *fullLineWriter) Write(p []byte) (int, error) { i := bytes.LastIndexByte(p, '\n') if i == -1 { fsw.buffer = append(fsw.buffer, p...) } else { fsw.buffer = append(fsw.buffer, p[:i]...) fsw.printBuf() fsw.buffer = append([]byte{}, p[i:]...) } return len(p), nil } // Close implements io.Closer and flushes the buffer. func (fsw *fullLineWriter) Close() error { fsw.printBuf() return nil } golang-github-u-root-uio-0.0~git20220204.dac05f7/uio/multiwriter.go000066400000000000000000000014451421736332200245040ustar00rootroot00000000000000// Copyright 2019 the u-root Authors. All rights reserved // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package uio import ( "io" ) type multiCloser struct { io.Writer writers []io.Writer } // Close implements io.Closer and closes any io.Writers that are also // io.Closers. func (mc *multiCloser) Close() error { var allErr error for _, w := range mc.writers { if c, ok := w.(io.Closer); ok { if err := c.Close(); err != nil { allErr = err } } } return allErr } // MultiWriteCloser is an io.MultiWriter that has an io.Closer and attempts to // close those w's that have optional io.Closers. func MultiWriteCloser(w ...io.Writer) io.WriteCloser { return &multiCloser{ Writer: io.MultiWriter(w...), writers: w, } } golang-github-u-root-uio-0.0~git20220204.dac05f7/uio/null.go000066400000000000000000000027241421736332200230700ustar00rootroot00000000000000// Copyright 2012-2019 the u-root Authors. All rights reserved // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // Discard implementation copied from the Go project: // https://golang.org/src/io/ioutil/ioutil.go. // Copyright 2009 The Go Authors. All rights reserved. package uio import ( "io" "sync" ) type devNull int // devNull implements ReaderFrom as an optimization so io.Copy to // ioutil.Discard can avoid doing unnecessary work. var _ io.ReaderFrom = devNull(0) func (devNull) Write(p []byte) (int, error) { return len(p), nil } func (devNull) Name() string { return "null" } func (devNull) WriteString(s string) (int, error) { return len(s), nil } var blackHolePool = sync.Pool{ New: func() interface{} { b := make([]byte, 8192) return &b }, } func (devNull) ReadFrom(r io.Reader) (n int64, err error) { bufp := blackHolePool.Get().(*[]byte) readSize := 0 for { readSize, err = r.Read(*bufp) n += int64(readSize) if err != nil { blackHolePool.Put(bufp) if err == io.EOF { return n, nil } return } } } func (devNull) Close() error { return nil } // WriteNameCloser is the interface that groups Write, Close, and Name methods. type WriteNameCloser interface { io.Writer io.Closer Name() string } // Discard is a WriteNameCloser on which all Write and Close calls succeed // without doing anything, and the Name call returns "null". var Discard WriteNameCloser = devNull(0) golang-github-u-root-uio-0.0~git20220204.dac05f7/uio/progress.go000066400000000000000000000017411421736332200237600ustar00rootroot00000000000000// Copyright 2019 the u-root Authors. All rights reserved // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package uio import ( "io" "strings" ) // ProgressReadCloser implements io.ReadCloser and prints Symbol to W after every // Interval bytes passes through RC. type ProgressReadCloser struct { RC io.ReadCloser Symbol string Interval int W io.Writer counter int written bool } // Read implements io.Reader for ProgressReadCloser. func (rc *ProgressReadCloser) Read(p []byte) (n int, err error) { defer func() { numSymbols := (rc.counter%rc.Interval + n) / rc.Interval rc.W.Write([]byte(strings.Repeat(rc.Symbol, numSymbols))) rc.counter += n rc.written = (rc.written || numSymbols > 0) if err == io.EOF && rc.written { rc.W.Write([]byte("\n")) } }() return rc.RC.Read(p) } // Close implements io.Closer for ProgressReader. func (rc *ProgressReadCloser) Close() error { return rc.RC.Close() } golang-github-u-root-uio-0.0~git20220204.dac05f7/uio/progress_test.go000066400000000000000000000030111421736332200250070ustar00rootroot00000000000000// Copyright 2019 the u-root Authors. All rights reserved // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package uio import ( "bytes" "io/ioutil" "testing" ) func TestProgressReadCloser(t *testing.T) { input := ioutil.NopCloser(bytes.NewBufferString("01234567890123456789")) stdout := &bytes.Buffer{} prc := ProgressReadCloser{ RC: input, Symbol: "#", Interval: 4, W: stdout, } // Read one byte at a time. output := make([]byte, 1) prc.Read(output) prc.Read(output) prc.Read(output) if len(stdout.Bytes()) != 0 { t.Errorf("found %q, but expected no bytes to be written", stdout) } prc.Read(output) if stdout.String() != "#" { t.Errorf("found %q, expected %q to be written", stdout.String(), "#") } // Read 9 bytes all at once. output = make([]byte, 9) prc.Read(output) if stdout.String() != "###" { t.Errorf("found %q, expected %q to be written", stdout.String(), "###") } if string(output) != "456789012" { t.Errorf("found %q, expected %q to be written", string(output), "456789012") } // Read until EOF output, err := ioutil.ReadAll(&prc) if err != nil { t.Errorf("got %v, expected nil error", err) } if stdout.String() != "#####\n" { t.Errorf("found %q, expected %q to be written", stdout.String(), "#####\n") } if string(output) != "3456789" { t.Errorf("found %q, expected %q to be written", string(output), "3456789") } err = prc.Close() if err != nil { t.Errorf("got %v, expected nil error", err) } } golang-github-u-root-uio-0.0~git20220204.dac05f7/uio/reader.go000066400000000000000000000021011421736332200233450ustar00rootroot00000000000000// Copyright 2018 the u-root Authors. All rights reserved // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package uio import ( "bytes" "io" "io/ioutil" "math" "reflect" ) type inMemReaderAt interface { Bytes() []byte } // ReadAll reads everything that r contains. // // Callers *must* not modify bytes in the returned byte slice. // // If r is an in-memory representation, ReadAll will attempt to return a // pointer to those bytes directly. func ReadAll(r io.ReaderAt) ([]byte, error) { if imra, ok := r.(inMemReaderAt); ok { return imra.Bytes(), nil } return ioutil.ReadAll(Reader(r)) } // Reader generates a Reader from a ReaderAt. func Reader(r io.ReaderAt) io.Reader { return io.NewSectionReader(r, 0, math.MaxInt64) } // ReaderAtEqual compares the contents of r1 and r2. func ReaderAtEqual(r1, r2 io.ReaderAt) bool { var c, d []byte var r1err, r2err error if r1 != nil { c, r1err = ReadAll(r1) } if r2 != nil { d, r2err = ReadAll(r2) } return bytes.Equal(c, d) && reflect.DeepEqual(r1err, r2err) } golang-github-u-root-uio-0.0~git20220204.dac05f7/uio/uio.go000066400000000000000000000005611421736332200227070ustar00rootroot00000000000000// Copyright 2018 the u-root Authors. All rights reserved // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // Package uio unifies commonly used io utilities for u-root. // // uio's most used feature is the Buffer/Lexer combination to parse binary data // of arbitrary endianness into data structures. package uio golang-github-u-root-uio-0.0~git20220204.dac05f7/uio/uiotest/000077500000000000000000000000001421736332200232565ustar00rootroot00000000000000golang-github-u-root-uio-0.0~git20220204.dac05f7/uio/uiotest/uiotest.go000066400000000000000000000023051421736332200253010ustar00rootroot00000000000000// Copyright 2020 the u-root Authors. All rights reserved // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // Package uiotest contains tests for uio functions. package uiotest import ( "io" "testing" "time" "github.com/u-root/uio/uio" ) // NowLog returns the current time formatted like the standard log package's // timestamp. func NowLog() string { return time.Now().Format("2006/01/02 15:04:05") } // TestLineWriter is an io.Writer that logs full lines of serial to tb. func TestLineWriter(tb testing.TB, prefix string) io.WriteCloser { if len(prefix) > 0 { return uio.FullLineWriter(&testLinePrefixWriter{tb: tb, prefix: prefix}) } return uio.FullLineWriter(&testLineWriter{tb: tb}) } // testLinePrefixWriter is an io.Writer that logs full lines of serial to tb. type testLinePrefixWriter struct { tb testing.TB prefix string } func (tsw *testLinePrefixWriter) OneLine(p []byte) { tsw.tb.Logf("%s %s: %s", NowLog(), tsw.prefix, p) } // testLineWriter is an io.Writer that logs full lines of serial to tb. type testLineWriter struct { tb testing.TB } func (tsw *testLineWriter) OneLine(p []byte) { tsw.tb.Logf("%s: %s", NowLog(), p) } golang-github-u-root-uio-0.0~git20220204.dac05f7/ulog/000077500000000000000000000000001421736332200217345ustar00rootroot00000000000000golang-github-u-root-uio-0.0~git20220204.dac05f7/ulog/log.go000066400000000000000000000017551421736332200230540ustar00rootroot00000000000000// Copyright 2019 the u-root Authors. All rights reserved // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // Package ulog exposes logging via a Go interface. // // ulog has three implementations of the Logger interface: a Go standard // library "log" package Logger and a test Logger that logs via a test's // testing.TB.Logf. To use the test logger import "ulog/ulogtest". package ulog import ( "log" "os" ) // Logger is a log receptacle. // // It puts your information somewhere for safekeeping. type Logger interface { Printf(format string, v ...interface{}) Print(v ...interface{}) } // Log is a Logger that prints to stderr, like the default log package. var Log Logger = log.New(os.Stderr, "", log.LstdFlags) type emptyLogger struct{} func (emptyLogger) Printf(format string, v ...interface{}) {} func (emptyLogger) Print(v ...interface{}) {} // Null is a logger that prints nothing. var Null Logger = emptyLogger{} golang-github-u-root-uio-0.0~git20220204.dac05f7/ulog/ulogtest/000077500000000000000000000000001421736332200236025ustar00rootroot00000000000000golang-github-u-root-uio-0.0~git20220204.dac05f7/ulog/ulogtest/log.go000066400000000000000000000013101421736332200247050ustar00rootroot00000000000000// Copyright 2019 the u-root Authors. All rights reserved // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // Package ulogtest implement the Logger interface via a test's testing.TB.Logf. package ulogtest import ( "testing" ) // Logger is a Logger implementation that logs to testing.TB.Logf. type Logger struct { TB testing.TB } // Printf formats according to the format specifier and prints to a unit test's log. func (tl Logger) Printf(format string, v ...interface{}) { tl.TB.Logf(format, v...) } // Print formats according the default formats for v and prints to a unit test's log. func (tl Logger) Print(v ...interface{}) { tl.TB.Log(v...) }