76 lines
1.8 KiB
Go
76 lines
1.8 KiB
Go
// Copyright 2026 The vault Authors.
|
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
package main
|
|
|
|
import (
|
|
"archive/tar"
|
|
"bufio"
|
|
"bytes"
|
|
"compress/gzip"
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"path"
|
|
"strings"
|
|
)
|
|
|
|
// absorb reads a tar archive, gzipped or not, from r and adds every regular
|
|
// file in it beneath dest, streaming each straight into the vault so no
|
|
// plaintext touches the disk. Other entries, and names that would escape
|
|
// dest, are reported and skipped.
|
|
func absorb(s *store, cat map[string][]*record, r io.Reader, dest string) error {
|
|
br := bufio.NewReader(r)
|
|
if magic, _ := br.Peek(2); bytes.Equal(magic, []byte{0x1f, 0x8b}) {
|
|
zr, err := gzip.NewReader(br)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer zr.Close()
|
|
r = zr
|
|
} else {
|
|
r = br
|
|
}
|
|
tr := tar.NewReader(r)
|
|
n := 0
|
|
for {
|
|
hdr, err := tr.Next()
|
|
if err == io.EOF {
|
|
break
|
|
}
|
|
if err != nil {
|
|
return fmt.Errorf("reading archive: %w", err)
|
|
}
|
|
if hdr.Typeflag != tar.TypeReg {
|
|
if hdr.Typeflag != tar.TypeDir {
|
|
fmt.Fprintf(os.Stderr, "skipping %s: not a regular file\n", hdr.Name)
|
|
}
|
|
continue
|
|
}
|
|
name := strings.TrimPrefix(path.Clean("/"+hdr.Name), "/")
|
|
if strings.Contains(hdr.Name, "\\") || name == "" || name != path.Clean(strings.TrimPrefix(strings.TrimPrefix(hdr.Name, "./"), "/")) {
|
|
fmt.Fprintf(os.Stderr, "skipping %s: unsafe name\n", hdr.Name)
|
|
continue
|
|
}
|
|
name = path.Join(dest, name)
|
|
replaced, err := s.addReader(cat, tr, hdr.Size, hdr.FileInfo().Mode(), hdr.ModTime, name)
|
|
if errors.Is(err, io.ErrUnexpectedEOF) || errors.Is(err, io.EOF) {
|
|
err = fmt.Errorf("%s: archive ends early", hdr.Name)
|
|
}
|
|
if err != nil {
|
|
return err
|
|
}
|
|
verb := "added"
|
|
if replaced {
|
|
verb = "replaced"
|
|
}
|
|
fmt.Fprintf(os.Stderr, "%s %s\n", verb, name)
|
|
n++
|
|
}
|
|
if n == 0 {
|
|
return errors.New("no files in archive")
|
|
}
|
|
return nil
|
|
}
|