Absorb functionality
This commit is contained in:
@@ -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
|
||||
}
|
||||
Reference in New Issue
Block a user