func LockFile(filename string) (*LockHandle, error) {
	absFilename, err := filepath.Abs(filename)
	if err != nil {
		return nil, fmt.Errorf("could not determine absolute path of %q: %w", filename, err)
	}
	MustMkdirAllForFile(filename)
	fp, err := os.Create(absFilename)
	if err != nil {
		return nil, fmt.Errorf("could not open file %q to lock: %w", absFilename, err)
	}
	zlog.Debug().Str("lockfile", absFilename).Msg("attempting exclusive lock")
	if err := syscall.Flock(int(fp.Fd()), syscall.LOCK_EX); err != nil {
		return nil, fmt.Errorf("could not flock file %q: %w", absFilename, err)
	}
	zlog.Debug().Str("lockfile", absFilename).Msg("acquired exclusive lock")
	return &LockHandle{
		filename: absFilename,
		osFile:   fp,
		locked:   true,
	}, nil
}
LockFile sets an exclusive provisional file lock on a file (creating it if needed).  It's basically a wrapper
around flock(, LOCK_EX), but hides the file descriptor from the caller since file descriptors aren't very Go-like.
Returns a non-nil lock handle which can be passed to lh.Unlock(). Note that "Unlock" will attempt to delete the file.
package util
import (
	"errors"
	"fmt"
	zlog "github.com/rs/zerolog/log"
	"os"
	"path/filepath"
	"syscall"
)
type LockHandle struct {
	filename string
	osFile   *os.File
	locked   bool
}