Files
wehub-resource-sync f99010fae1
CI / lint (push) Failing after 1s
CI / frontend (push) Failing after 1s
CI / scripts (push) Failing after 1s
CI / Go Test (ubuntu-latest) (push) Failing after 0s
CI / frontend-node-25 (push) Failing after 1s
CI / docs (push) Failing after 0s
CI / coverage (push) Failing after 0s
CI / e2e (push) Failing after 0s
Docker / build-and-push (push) Failing after 1s
CI / integration (push) Failing after 4m43s
CI / Go Test (windows-latest) (push) Has been cancelled
CI / Desktop Unit Tests (Windows) (push) Has been cancelled
Desktop Artifacts / Desktop Build (Linux (arm64)) (push) Has been cancelled
Desktop Artifacts / Desktop Build (Linux) (push) Has been cancelled
Desktop Artifacts / Desktop Build (Windows) (push) Has been cancelled
Desktop Artifacts (macOS) / Desktop Build (macOS (aarch64)) (push) Has been cancelled
Desktop Artifacts (macOS) / Desktop Build (macOS (x86_64)) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:30:36 +08:00

262 lines
7.0 KiB
Go

package remotesync
import (
"archive/tar"
"context"
"errors"
"fmt"
"io"
"os"
"path/filepath"
"strings"
)
const (
extractDirPerm = 0o755
extractFilePerm = 0o644
)
// ExtractTarStream reads a tar stream from r and writes its entries
// under dst. Extraction is fail-closed: it tolerates exactly one
// anomaly, self-referential hardlinks (an entry whose link target is
// itself, which macOS bsdtar emits for some Antigravity data and which
// carries no content), and treats every other problem as fatal so a
// truncated or corrupt transfer can never masquerade as a successful
// sync. Unexpected EOF, bad headers, paths escaping dst, and
// write/short-read errors all return an error. Returns the number of
// self-referential hardlinks skipped.
func ExtractTarStream(
ctx context.Context, r io.Reader, dst string,
) (int, error) {
return extractTarStream(ctx, r, dst)
}
func extractTarStream(
ctx context.Context, r io.Reader, dst string,
) (int, error) {
endMarkerReader := &tarEndMarkerReader{r: r}
tr := tar.NewReader(endMarkerReader)
skipped := 0
for {
if err := ctx.Err(); err != nil {
return skipped, err
}
beforeNext := endMarkerReader.total
hdr, err := tr.Next()
if errors.Is(err, io.EOF) {
trailerBytes := endMarkerReader.total - beforeNext
if _, drainErr := io.Copy(io.Discard, endMarkerReader); drainErr != nil {
return skipped, fmt.Errorf("read tar trailer: %w", drainErr)
}
if trailerBytes < tarEndMarkerSize || !endMarkerReader.hasEndMarker() {
return skipped, fmt.Errorf("missing tar end marker")
}
return skipped, nil
}
if err != nil {
return skipped, fmt.Errorf("read tar entry: %w", err)
}
selfLink, err := extractEntry(tr, dst, hdr)
if err != nil {
return skipped, err
}
if selfLink {
skipped++
}
}
}
type tarEndMarkerReader struct {
r io.Reader
tail []byte
total int
}
func (r *tarEndMarkerReader) Read(p []byte) (int, error) {
n, err := r.r.Read(p)
if n > 0 {
r.total += n
r.tail = append(r.tail, p[:n]...)
if len(r.tail) > tarEndMarkerSize {
r.tail = r.tail[len(r.tail)-tarEndMarkerSize:]
}
}
return n, err
}
func (r *tarEndMarkerReader) hasEndMarker() bool {
if r.total < tarEndMarkerSize || len(r.tail) < tarEndMarkerSize {
return false
}
for _, b := range r.tail[len(r.tail)-tarEndMarkerSize:] {
if b != 0 {
return false
}
}
return true
}
const tarEndMarkerSize = 1024
// extractEntry writes a single tar entry under dst. It reports whether
// the entry was a self-referential hardlink (skipped, no error).
func extractEntry(
tr *tar.Reader, dst string, hdr *tar.Header,
) (bool, error) {
target, err := safeJoin(dst, hdr.Name)
if err != nil {
return false, err
}
switch hdr.Typeflag {
case tar.TypeDir:
return false, mkdirAll(target, hdr.Name)
case tar.TypeReg:
return false, writeRegular(target, tr, hdr)
case tar.TypeSymlink:
// Symlinks are not session data, and a symlink restored from
// an archive can redirect later writes outside the extraction
// dir. Any regular file a symlink might alias is extracted on
// its own, so skip symlinks entirely.
return false, nil
case tar.TypeLink:
return writeHardlink(dst, target, hdr)
default:
// Char/block/fifo and similar special files do not appear
// in agent session directories; there is no content to lose
// by ignoring them.
return false, nil
}
}
// safeJoin resolves name against dst and rejects any path that escapes
// dst (via "..", an absolute component, or symlink-free traversal).
func safeJoin(dst, name string) (string, error) {
target, err := safeLocalArchivePath(dst, name)
if err != nil {
return "", fmt.Errorf("tar entry %q escapes extraction dir: %w", name, err)
}
return target, nil
}
// within reports whether p is dst itself or lies inside dst.
func within(dst, p string) bool {
rel, err := filepath.Rel(dst, p)
if err != nil {
return false
}
if rel == ".." {
return false
}
return !strings.HasPrefix(rel, ".."+string(filepath.Separator))
}
func mkdirAll(path, name string) error {
if err := os.MkdirAll(path, extractDirPerm); err != nil {
return fmt.Errorf("mkdir %q: %w", name, err)
}
return nil
}
// writeRegular extracts a regular file, failing on a short read so a
// truncated stream cannot leave a half-written file behind. On any
// failure the partial file is removed, so an aborted entry never looks
// complete.
func writeRegular(
target string, tr io.Reader, hdr *tar.Header,
) (err error) {
if e := mkdirAll(filepath.Dir(target), hdr.Name); e != nil {
return e
}
f, e := os.OpenFile(
target, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, extractFilePerm,
)
if e != nil {
return fmt.Errorf("create %q: %w", hdr.Name, e)
}
defer func() {
if err != nil {
_ = os.Remove(target)
}
}()
n, copyErr := io.Copy(f, tr)
closeErr := f.Close()
if copyErr == nil {
copyErr = closeErr
}
if copyErr != nil {
return fmt.Errorf("write %q: %w", hdr.Name, copyErr)
}
if n != hdr.Size {
return fmt.Errorf(
"short write %q: got %d of %d bytes",
hdr.Name, n, hdr.Size,
)
}
// Restore the archived mtime: the incremental skip cache keys on
// (path, mtime), so files must keep their remote mtime across
// syncs or nothing is ever skipped. Best-effort: a failure only
// forces a redundant resync, never data loss, so it must not
// discard an otherwise complete extraction.
if !hdr.ModTime.IsZero() {
_ = os.Chtimes(target, hdr.ModTime, hdr.ModTime)
}
return nil
}
// writeHardlink recreates a hardlink. A self-referential hardlink
// (target equals the entry itself) carries no content and is skipped;
// the bool return reports that case. Any other failure is fatal.
func writeHardlink(
dst, target string, hdr *tar.Header,
) (bool, error) {
linkTarget, err := safeJoin(dst, hdr.Linkname)
if err != nil {
return false, err
}
if linkTarget == target {
return true, nil
}
if err := mkdirAll(filepath.Dir(target), hdr.Name); err != nil {
return false, err
}
if err := os.Link(linkTarget, target); err != nil {
return false, fmt.Errorf(
"hardlink %q -> %q: %w", hdr.Name, hdr.Linkname, err,
)
}
return false, nil
}
// RemapToRemotePath converts a temp-dir path back to the original
// remote path. Strips the temp dir prefix so the remainder is the
// absolute path as it existed on the remote host.
//
// Example:
//
// tempDir="/tmp/sync-123"
// localPath="/tmp/sync-123/home/wes/.claude/foo.jsonl"
// result="/home/wes/.claude/foo.jsonl"
func RemapToRemotePath(tempDir, remoteDir, localPath string) string {
if remoteDir != "" {
if rel, ok := localPathRel(RemappedDir(tempDir, remoteDir), localPath); ok {
return joinRemoteRelative(remoteDir, rel)
}
}
rel, err := filepath.Rel(tempDir, localPath)
if err != nil {
return localPath
}
return "/" + filepath.ToSlash(rel)
}
// RemappedDir returns the temp-dir equivalent of a remote dir.
//
// Example:
//
// tempDir="/tmp/sync-123"
// remoteDir="/home/wes/.claude"
// result="/tmp/sync-123/home/wes/.claude"
func RemappedDir(tempDir, remoteDir string) string {
return remappedRemotePath(tempDir, remoteDir)
}