//go:build unix
package main
import (
"log"
"os"
"path/filepath"
"syscall"
)
// gitStoreLock is the file beside a Git mirror's store that a pull holds
// while it may write, and that the nightly backup takes before copying
// the store with zit's import files: zit's import map and an interrupted
// import's records must be copied together with the store, and only
// while no import is writing them.
const gitStoreLock = ".quarry-git.lock"
// lockGitStore takes that lock, waiting for a backup in progress, and
// answers the func that releases it. A lock that cannot be taken is
// logged and not fatal: the pull still runs under the forge's own lock,
// and only a concurrent backup is unprotected.
func lockGitStore(store string) func() {
f, err := os.OpenFile(filepath.Join(store, gitStoreLock), os.O_RDWR|os.O_CREATE, 0o600)
if err != nil {
log.Printf("git store lock %s: %v", store, err)
return func() {}
}
if err := syscall.Flock(int(f.Fd()), syscall.LOCK_EX); err != nil {
log.Printf("git store lock %s: %v", store, err)
f.Close()
return func() {}
}
return func() { f.Close() }
}
// freeBytes is the space free to this process on dir's file system.
func freeBytes(dir string) (uint64, bool) {
var st syscall.Statfs_t
if err := syscall.Statfs(dir, &st); err != nil {
return 0, false
}
return st.Bavail * uint64(st.Bsize), true
}