Documentation
¶
Overview ¶
Package entiredir owns access to the repository's .entire directory.
Every non-test read and write under .entire goes through the single *os.Root this package hands out, rather than through an absolute path assembled by the caller. Two properties follow from that, and neither survives if a call site reverts to os.ReadFile/os.WriteFile on a joined path:
- Containment. .entire holds paths named from agent-supplied session IDs, tool-use IDs, and tree paths. A root confines every open to the directory at the kernel level, so a crafted name cannot escape it, and a symlink swapped in between resolution and open (TOCTOU) surfaces as an error rather than a redirected write.
- One directory handle per worktree. The root is opened once and memoized, so the hot hook paths stop paying an OpenRoot per state file, and every consumer observes the same directory even if .entire is renamed or replaced underneath a long-running process.
Creation is deliberately lazy and split across two entry points. Open creates .entire because its callers are about to write; OpenForRead never creates, because a command that only looks must leave an untouched repo untouched. That distinction is load-bearing for logging in particular: the log file is created by the first line actually written, so a command that logs nothing (completion, version, help) must not leave an .entire behind.
Reset exists for the paths that delete the directory (entire disable, entire clean) and for tests. A cached root that outlives its directory is a handle to an unlinked inode: writes through it succeed and land nowhere.
Index ¶
- func MustName(repoRelPath string) string
- func Name(repoRelPath string) (string, error)
- func Open(ctx context.Context) (*os.Root, error)
- func OpenAt(worktreeRoot string) (*os.Root, error)
- func OpenAtForRead(worktreeRoot string) (*os.Root, error)
- func OpenForRead(ctx context.Context) (*os.Root, error)
- func OpenPath(p string) (root *os.Root, name string, err error)
- func OpenPathForRead(p string) (root *os.Root, name string, err error)
- func Opener(ctx context.Context) func() (*os.Root, error)
- func OpenerAt(worktreeRoot string) func() (*os.Root, error)
- func Path(ctx context.Context) (string, error)
- func PathTo(ctx context.Context, repoRelPath string) (string, error)
- func ReadFile(root *os.Root, name string) ([]byte, error)
- func Reset()
- func Split(p string) (entireDir, name string, ok bool)
- func WriteFile(root *os.Root, name string, data []byte, perm os.FileMode) error
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func MustName ¶
MustName is Name for package-level constants that are known to be under .entire. It panics on a path that is not, which can only be a programming error in a literal.
func Name ¶
Name converts a repo-relative path under .entire (for example paths.EntireTmpDir) to a name relative to the .entire root. The repo-relative constants stay as they are because git paths, settings display, and gitignore entries all need them; this is the one-line bridge to root-relative I/O.
A path outside .entire is an error rather than a silent passthrough: the alternative is a name that resolves inside .entire but means something else.
func Open ¶
Open returns the shared *os.Root for the current worktree's .entire directory, creating the directory if it does not exist. Use it from write paths; read-only callers want OpenForRead.
The returned root is owned by this package and shared with every other caller. Do not close it.
func OpenAt ¶
OpenAt is Open for an explicit worktree root, for the callers that already resolved one (or that act on a worktree other than the current directory).
func OpenAtForRead ¶
OpenAtForRead is OpenForRead for an explicit worktree root.
func OpenForRead ¶
OpenForRead is Open without creating .entire. A missing directory is reported as fs.ErrNotExist, which callers classify with errors.Is.
func OpenPath ¶
OpenPath returns the shared root for the .entire directory containing p, together with p's name within it, creating the directory if needed. OpenPathForRead is the same without creation.
These exist for the consumers that already carry an absolute path — settings resolves one per layer, and hands it back to callers that print it — so those APIs keep their shape while the open itself still goes through the one root. A path not under a .entire directory yields ok=false from Split and an error here; callers that legitimately handle both (settings also reads clone preferences out of .git) branch on that rather than guessing.
func OpenPathForRead ¶
OpenPathForRead is OpenPath without creating .entire.
func Opener ¶
Opener returns a thunk that calls Open when invoked, for consumers that are handed their storage up front but must not touch the disk until they first write (see logging.Config.Root).
func Path ¶
Path returns the absolute path of the current worktree's .entire directory. It is for messages and for the few consumers that must hand a path to an external process; it is not an invitation to do I/O on the result.
func PathTo ¶
PathTo returns the absolute path of repoRelPath, which must name something under .entire. It exists for the consumers that carry an absolute path in their own API — settings resolves one per layer and hands it back to callers that print it — so those resolve through this package's anchor rather than paths.AbsPath, whose relative fallback is the thing anchor exists to avoid.
func Reset ¶
func Reset()
Reset closes and forgets every cached root. Call it after deleting .entire: a root cached across the deletion refers to an unlinked directory, so writes through it succeed and land nowhere.
The registry is shared with the other anchors, so this clears them too. That is the behaviour teardown wants — a repo whose .entire just went away is not a repo whose .git root is worth keeping — and tests get one reset to call.
func Split ¶
Split splits a path that lies under a .entire directory into that directory and the name of the path within it. It is lexical: the path is cleaned and the innermost ".entire" component wins, which is the directory that actually contains the file if a repo is ever checked out inside another repo's .entire.
A relative path is accepted, because paths.AbsPath still falls back to one when it cannot resolve a worktree root and callers hand that value straight through. The walk is component-by-component with filepath rather than a split on separators so a Windows volume name survives being rejoined.
Types ¶
This section is empty.