talos/pkg/archiver/tar_test.go
Andrey Smirnov f661d84877
fix: allow talosctl cp to handle special files in /proc
There is some refactoring to simplify things, but mostly handle files
which report size 0 in `stat`, but actually contain data when read.

We try to read up to the small buffer, if we read whole file, we use
that as contents, otherwise we still skip the file, as we need to write
tar header with size _before_ we read the whole file.

Signed-off-by: Andrey Smirnov <andrey.smirnov@talos-systems.com>
2023-04-24 15:07:30 +04:00

157 lines
3.2 KiB
Go

// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
package archiver_test
import (
"archive/tar"
"bytes"
"context"
"io"
"os"
"path/filepath"
"testing"
"github.com/stretchr/testify/suite"
"github.com/siderolabs/talos/pkg/archiver"
)
type TarSuite struct {
CommonSuite
}
func (suite *TarSuite) TestArchiveDir() {
ch, err := archiver.Walker(context.Background(), suite.tmpDir)
suite.Require().NoError(err)
var buf bytes.Buffer
err = archiver.Tar(context.Background(), ch, &buf)
suite.Require().NoError(err)
pathsSeen := map[string]struct{}{}
tr := tar.NewReader(&buf)
for {
hdr, err := tr.Next()
if err == io.EOF {
break
}
suite.Require().NoError(err)
if hdr.Typeflag == tar.TypeDir {
continue
}
contents, err := io.ReadAll(tr)
suite.Require().NoError(err)
found := false
for _, fi := range filesFixture {
if fi.Path[1:] == hdr.Name {
found = true
pathsSeen[fi.Path] = struct{}{}
switch {
case fi.Mode&os.ModeSymlink != 0:
suite.Require().Equal(string(fi.Contents), hdr.Linkname)
case fi.Size > 0:
suite.Require().Len(contents, fi.Size)
case fi.Contents != nil:
suite.Require().EqualValues(fi.Contents, contents)
default:
suite.Require().Len(contents, 0)
}
}
}
suite.Require().True(found, "file %q", hdr.Name)
}
for _, fi := range filesFixture {
_, ok := pathsSeen[fi.Path]
suite.Require().True(ok, "path %q", fi.Path)
}
}
func (suite *TarSuite) TestArchiveFile() {
ch, err := archiver.Walker(context.Background(), filepath.Join(suite.tmpDir, "/usr/bin/cp"))
suite.Require().NoError(err)
var buf bytes.Buffer
err = archiver.Tar(context.Background(), ch, &buf)
suite.Require().NoError(err)
tr := tar.NewReader(&buf)
for {
hdr, err := tr.Next()
if err == io.EOF {
break
}
suite.Require().NoError(err)
expectedContents := []byte("ELF EXECUTABLE IIRC")
suite.Require().EqualValues(hdr.Typeflag, tar.TypeReg)
suite.Require().EqualValues(hdr.Name, "cp")
suite.Require().EqualValues(hdr.Size, len(expectedContents))
contents, err := io.ReadAll(tr)
suite.Require().NoError(err)
suite.Require().Equal(expectedContents, contents)
}
}
func (suite *TarSuite) TestArchiveProcfs() {
ch, err := archiver.Walker(context.Background(), "/proc/self/", archiver.WithMaxRecurseDepth(0))
suite.Require().NoError(err)
var buf bytes.Buffer
// it's okay to have some errors here, as some files are not readable
archiver.Tar(context.Background(), ch, &buf) //nolint:errcheck
tr := tar.NewReader(&buf)
expectedNonZeroFiles := map[string]struct{}{
"cmdline": {},
"environ": {},
"limits": {},
"io": {},
"stat": {},
}
for {
hdr, err := tr.Next()
if err == io.EOF {
break
}
suite.Require().NoError(err)
if _, expected := expectedNonZeroFiles[hdr.Name]; !expected {
continue
}
suite.Assert().EqualValues(hdr.Typeflag, tar.TypeReg)
suite.Assert().NotZero(hdr.Size)
delete(expectedNonZeroFiles, hdr.Name)
}
suite.Assert().Empty(expectedNonZeroFiles)
}
func TestTarSuite(t *testing.T) {
suite.Run(t, new(TarSuite))
}