// Copyright 2026 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT //go:build windows package filelock import ( "fmt" "os" "time" "golang.org/x/sys/windows" ) // lockFile acquires an exclusive lock on the file using LockFileEx. // It polls with non-blocking LockFileEx until timeout. func lockFile(file *os.File, timeout time.Duration) error { deadline := time.Now().Add(timeout) handle := windows.Handle(file.Fd()) // LOCKFILE_EXCLUSIVE_LOCK | LOCKFILE_FAIL_IMMEDIATELY const flags = windows.LOCKFILE_EXCLUSIVE_LOCK | windows.LOCKFILE_FAIL_IMMEDIATELY for { // Lock the first byte (advisory lock) var overlapped windows.Overlapped err := windows.LockFileEx(handle, flags, 0, 1, 0, &overlapped) if err == nil { return nil } if err != windows.ERROR_LOCK_VIOLATION { return fmt.Errorf("LockFileEx failed: %w", err) } if time.Now().After(deadline) { return fmt.Errorf("timeout waiting for file lock") } time.Sleep(FileLockPollInterval) } } // unlockFile releases the lock on the file. func unlockFile(file *os.File) error { handle := windows.Handle(file.Fd()) var overlapped windows.Overlapped return windows.UnlockFileEx(handle, 0, 1, 0, &overlapped) }