mirror of
https://github.com/Twigpine/zero.git
synced 2026-11-10 05:01:28 -10:00
* feat(tools): retain bounded structured file diffs * feat(acp): emit structured file changes in tool updates * fix(acp): harden structured file diff transport * fix(tools): reject unsafe rich diff previews * fix(acp): preserve safe rich diff semantics * fix(tools): bind structured diffs to committed changes * fix(acp): preserve structured diff identity * fix(tools): close rich diff race gaps * fix(tools): report partial patch paths from workspace * fix(tools): finalize structured diff evidence * fix(tools): separate unverified patch writes * test(tools): cover failed formatter recovery * fix(acp): serialize file deletions as nullable diffs * fix(tools): recreate files after formatter failure * test(acp): require nullable diff fields on wire
44 lines
1.1 KiB
Go
44 lines
1.1 KiB
Go
package tools
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
)
|
|
|
|
// readRootedFile returns bytes and identity from the same opened object, and
|
|
// verifies that the rooted path still names that object after the read. Root.Open
|
|
// binds symlink containment to use rather than relying on a pathname pre-check.
|
|
func readRootedFile(root *os.Root, relativePath string) ([]byte, os.FileInfo, error) {
|
|
file, err := root.Open(relativePath)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
closed := false
|
|
defer func() {
|
|
if !closed {
|
|
_ = file.Close()
|
|
}
|
|
}()
|
|
openedInfo, err := file.Stat()
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
if !openedInfo.Mode().IsRegular() {
|
|
return nil, nil, fmt.Errorf("%s is not a regular file", relativePath)
|
|
}
|
|
content, err := io.ReadAll(file)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
pathInfo, err := root.Stat(relativePath)
|
|
if err != nil || !os.SameFile(openedInfo, pathInfo) {
|
|
return nil, nil, fmt.Errorf("%w: path identity changed", errFileChangedDuringWrite)
|
|
}
|
|
if err := file.Close(); err != nil {
|
|
return nil, nil, err
|
|
}
|
|
closed = true
|
|
return content, openedInfo, nil
|
|
}
|