mesh/merge-gate head d237dee4c9e3 merged into trunk cd13f7726ef0 — pass: builds mesh-host → ace, g14, novox, shanks; no bus step; every machine composes wi…
mesh/repo-check head d237dee4c9e3 merged into trunk cd13f7726ef0 — fail: its merge-check.sh failed: --- FAIL: TestAMoveOutDirectoryKeepsOnlyWhatItKnows (0.…
mesh/delivery superseded: a newer head of the same pull request
A directory or archive resource carries `unknown` (move-out, module, program) and `knows`. For move-out under a home, every look moves each path the declaration does not know into ~/.local/state/mesh-moved/<module>/<time>/, the list written before each move, without following a link, a young path waiting, a socket or pipe left and reported, nothing made when nothing moved, and another file system refused. Reviewed in two rounds.
62 lines
1.7 KiB
Go
62 lines
1.7 KiB
Go
//go:build linux
|
|
|
|
package apply
|
|
|
|
import (
|
|
"fmt"
|
|
"path/filepath"
|
|
"syscall"
|
|
|
|
"golang.org/x/sys/unix"
|
|
)
|
|
|
|
// deviceOf is the device a path lives on; a variable so a test can name another file system. Below a home it is
|
|
// read through a descriptor opened without following a link (issue 1024).
|
|
var deviceOf = func(path string) (uint64, error) {
|
|
var st unix.Stat_t
|
|
if home := homeAbove(path); home != "" {
|
|
fd, err := openDirUnder(home, path)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
defer unix.Close(fd)
|
|
if err := unix.Fstat(fd, &st); err != nil {
|
|
return 0, err
|
|
}
|
|
return uint64(st.Dev), nil
|
|
}
|
|
if err := unix.Stat(path, &st); err != nil {
|
|
return 0, err
|
|
}
|
|
return uint64(st.Dev), nil
|
|
}
|
|
|
|
// renameUnder moves from to to, both below home, through descriptors of their parents opened without following a
|
|
// link, and never over something that is there: an account that owns the folders cannot point either at another
|
|
// place between the look and the move (issue 1024, novox/hq ADR 0266).
|
|
func renameUnder(home, from, to string) error {
|
|
fromDir, err := openDirUnder(home, filepath.Dir(from))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer unix.Close(fromDir)
|
|
toDir, err := openDirUnder(home, filepath.Dir(to))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer unix.Close(toDir)
|
|
if err := unix.Renameat2(fromDir, filepath.Base(from), toDir, filepath.Base(to), unix.RENAME_NOREPLACE); err != nil {
|
|
return fmt.Errorf("rename %s to %s: %w", from, to, err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// ownerIDs is the user and group of a path, without following a link.
|
|
func ownerIDs(path string) (uid, gid int, ok bool) {
|
|
var st syscall.Stat_t
|
|
if err := syscall.Lstat(path, &st); err != nil {
|
|
return 0, 0, false
|
|
}
|
|
return int(st.Uid), int(st.Gid), true
|
|
}
|