//go:build windows package appdata import ( "errors" "os" "golang.org/x/sys/windows" ) type bootstrapFileLock struct { file *os.File overlapped windows.Overlapped } func acquireBootstrapFileLock(path string) (*bootstrapFileLock, error) { file, err := os.OpenFile(path, os.O_CREATE|os.O_RDWR, 0o600) if err != nil { return nil, err } lock := &bootstrapFileLock{file: file} if err := windows.LockFileEx( windows.Handle(file.Fd()), windows.LOCKFILE_EXCLUSIVE_LOCK, 0, 1, 0, &lock.overlapped, ); err != nil { _ = file.Close() return nil, err } _ = file.Chmod(0o600) return lock, nil } func (lock *bootstrapFileLock) Close() error { if lock == nil || lock.file == nil { return nil } unlockErr := windows.UnlockFileEx( windows.Handle(lock.file.Fd()), 0, 1, 0, &lock.overlapped, ) closeErr := lock.file.Close() lock.file = nil return errors.Join(unlockErr, closeErr) } func atomicReplaceBootstrapFile(source string, target string) error { sourcePath, err := windows.UTF16PtrFromString(source) if err != nil { return err } targetPath, err := windows.UTF16PtrFromString(target) if err != nil { return err } return windows.MoveFileEx( sourcePath, targetPath, windows.MOVEFILE_REPLACE_EXISTING|windows.MOVEFILE_WRITE_THROUGH, ) }