package upload import ( "archive/tar" "bytes" "compress/gzip" "fmt" "io" "os" "path/filepath" "time" "gitea.maximumdirect.net/eric/distributor/pkg/bundle" ) func archiveBundle(root string, manifest bundle.Manifest) ([]byte, error) { var output bytes.Buffer gzipWriter := gzip.NewWriter(&output) tarWriter := tar.NewWriter(gzipWriter) manifestData, err := bundle.MarshalManifest(manifest) if err != nil { return nil, err } if err := writeTarEntry(tarWriter, bundle.ManifestName, manifestData, 0o600, manifest.Created); err != nil { _ = tarWriter.Close() _ = gzipWriter.Close() return nil, err } for _, manifestFile := range manifest.Files { fullPath := filepath.Join(root, filepath.FromSlash(manifestFile.Path)) info, err := os.Lstat(fullPath) if err != nil { _ = tarWriter.Close() _ = gzipWriter.Close() return nil, fmt.Errorf("file %q stat: %w", manifestFile.Path, err) } if !info.Mode().IsRegular() { _ = tarWriter.Close() _ = gzipWriter.Close() return nil, fmt.Errorf("file %q must be a regular file", manifestFile.Path) } file, err := os.Open(fullPath) if err != nil { _ = tarWriter.Close() _ = gzipWriter.Close() return nil, fmt.Errorf("file %q open: %w", manifestFile.Path, err) } if err := writeTarFile(tarWriter, manifestFile.Path, file, info.Mode().Perm(), info.ModTime(), info.Size()); err != nil { _ = file.Close() _ = tarWriter.Close() _ = gzipWriter.Close() return nil, err } if err := file.Close(); err != nil { _ = tarWriter.Close() _ = gzipWriter.Close() return nil, fmt.Errorf("file %q close: %w", manifestFile.Path, err) } } if err := tarWriter.Close(); err != nil { _ = gzipWriter.Close() return nil, fmt.Errorf("close tar archive: %w", err) } if err := gzipWriter.Close(); err != nil { return nil, fmt.Errorf("close gzip archive: %w", err) } return output.Bytes(), nil } func writeTarEntry(writer *tar.Writer, name string, data []byte, mode int64, modTime time.Time) error { header := &tar.Header{ Name: name, Mode: mode, Size: int64(len(data)), ModTime: modTime, } if err := writer.WriteHeader(header); err != nil { return fmt.Errorf("write tar header %q: %w", name, err) } if _, err := writer.Write(data); err != nil { return fmt.Errorf("write tar entry %q: %w", name, err) } return nil } func writeTarFile(writer *tar.Writer, name string, file *os.File, mode os.FileMode, modTime time.Time, size int64) error { if mode == 0 { mode = 0o600 } header := &tar.Header{ Name: name, Mode: int64(mode), Size: size, ModTime: modTime, } if err := writer.WriteHeader(header); err != nil { return fmt.Errorf("write tar header %q: %w", name, err) } if _, err := io.Copy(writer, file); err != nil { return fmt.Errorf("write tar entry %q: %w", name, err) } return nil }