Absorb functionality

This commit is contained in:
Andy Dixon
2026-10-02 16:43:19 +01:00
parent 92ff8546fd
commit 55af82f95f
14 changed files with 291 additions and 13 deletions
+75
View File
@@ -0,0 +1,75 @@
// 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
}