Files
EvoBGP/internal/bundle/extract.go
T
DenozordecandCursor f8e0520817 feat(httpapi): harden control plane and speed up prefix refresh
Очередь job получила lease и fencing, телеметрия и прогресс deploy сохраняются, ревизия пишет manifest входов. Обновление префиксов не переписывает неизменённый снимок, большие наборы идут через COPY, а устаревшая ревизия не попадает в deploy. Бандл ноды кэшируется, prune и постановка job больше не держат горячий путь.

Co-authored-by: Cursor <[email protected]>
2026-11-02 17:23:59 +07:00

113 lines
3.0 KiB
Go

package bundle
import (
"fmt"
"os"
"path/filepath"
"strings"
)
// WriteExtractedFiles writes payload files from a verified bundle under root (directories created as needed).
func WriteExtractedFiles(root string, v *VerifiedContents) error {
return WriteExtractedFilesWithLimits(root, v, Limits{})
}
// WriteExtractedFilesWithLimits confines all filesystem operations to an open
// directory handle. Replacing existing files uses unlink + exclusive creation,
// so existing hard links and symlinks cannot redirect writes outside the root.
func WriteExtractedFilesWithLimits(root string, v *VerifiedContents, limits Limits) error {
l, err := limits.Normalized()
if err != nil {
return err
}
if v == nil {
return fmt.Errorf("bundle: nil verified contents")
}
if len(v.Manifest.Files) > l.MaxEntries-2 {
return ErrLimit
}
seen := map[string]bool{}
var total int64
for _, fe := range v.Manifest.Files {
if err := validatePath(fe.Path, l.MaxPathBytes); err != nil {
return err
}
if seen[strings.ToLower(fe.Path)] {
return fmt.Errorf("bundle: duplicate path %q", fe.Path)
}
seen[strings.ToLower(fe.Path)] = true
data, ok := v.Files[fe.Path]
if !ok {
return fmt.Errorf("bundle: missing file %q", fe.Path)
}
if int64(len(data)) > l.MaxFileBytes || int64(len(data)) > l.MaxExpandedBytes-total {
return ErrLimit
}
total += int64(len(data))
}
root = filepath.Clean(root)
if err := os.MkdirAll(root, 0o755); err != nil {
return err
}
confined, err := os.OpenRoot(root)
if err != nil {
return err
}
defer func() { _ = confined.Close() }()
for _, fe := range v.Manifest.Files {
data, ok := v.Files[fe.Path]
if !ok {
return fmt.Errorf("bundle: missing file %q", fe.Path)
}
parts := strings.Split(fe.Path, "/")
for i := 1; i < len(parts); i++ {
dir := filepath.FromSlash(strings.Join(parts[:i], "/"))
if err := confined.Mkdir(dir, 0o755); err != nil && !os.IsExist(err) {
return err
}
info, err := confined.Lstat(dir)
if err != nil {
return err
}
if !info.IsDir() || info.Mode()&os.ModeSymlink != 0 {
return fmt.Errorf("bundle: unsafe directory %q", dir)
}
}
dest := filepath.FromSlash(fe.Path)
info, err := confined.Lstat(dest)
if err == nil {
if !info.Mode().IsRegular() {
return fmt.Errorf("bundle: unsafe destination %q", dest)
}
if err = confined.Remove(dest); err != nil {
return err
}
} else if !os.IsNotExist(err) {
return err
}
f, err := confined.OpenFile(dest, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0o644)
if err != nil {
return err
}
_, writeErr := f.Write(data)
closeErr := f.Close()
if writeErr != nil {
return writeErr
}
if closeErr != nil {
return closeErr
}
}
return nil
}
// FindMainBirdConf returns the first path ending with bird.conf from extracted manifest order.
func (v *VerifiedContents) FindMainBirdConf() string {
for _, fe := range v.Manifest.Files {
if strings.HasSuffix(fe.Path, "bird.conf") {
return fe.Path
}
}
return ""
}