99 "fmt"
1010 "os"
1111 "path/filepath"
12+ "runtime"
13+ "syscall"
1214 "time"
1315
1416 "github.com/AzureAD/microsoft-authentication-extensions-for-go/extensions/internal/flock"
@@ -51,15 +53,21 @@ func (l *Lock) Lock(ctx context.Context) error {
5153 ctx , cancel = context .WithTimeout (ctx , timeout )
5254 defer cancel ()
5355 }
54- locked , err := l .f .TryLockContext (ctx , l .retryDelay )
55- if err != nil {
56- return err
57- }
58- if locked {
59- _ , _ = l .f .Fh ().WriteString (fmt .Sprintf ("{%d} {%s}" , os .Getpid (), os .Args [0 ]))
60- return nil
56+ for {
57+ // flock opens the file before locking it and returns errors due to an existing
58+ // lock or one acquired by another process after this process has opened the
59+ // file. We ignore some errors here because in such cases we want to retry until
60+ // the deadline.
61+ locked , err := l .f .TryLockContext (ctx , l .retryDelay )
62+ if err != nil {
63+ if ! (errors .Is (err , os .ErrPermission ) || isWindowsSharingViolation (err )) {
64+ return err
65+ }
66+ } else if locked {
67+ _ , _ = l .f .Fh ().WriteString (fmt .Sprintf ("{%d} {%s}" , os .Getpid (), os .Args [0 ]))
68+ return nil
69+ }
6170 }
62- return errors .New ("couldn't acquire file lock" )
6371}
6472
6573// Unlock releases the lock and deletes the lock file.
@@ -68,8 +76,13 @@ func (l *Lock) Unlock() error {
6876 if err == nil {
6977 err = os .Remove (l .f .Path ())
7078 }
71- if errors .Is (err , os .ErrNotExist ) {
79+ // ignore errors caused by another process deleting the file or locking between the above Unlock and Remove
80+ if errors .Is (err , os .ErrNotExist ) || errors .Is (err , os .ErrPermission ) || isWindowsSharingViolation (err ) {
7281 return nil
7382 }
7483 return err
7584}
85+
86+ func isWindowsSharingViolation (err error ) bool {
87+ return runtime .GOOS == "windows" && errors .Is (err , syscall .Errno (32 ))
88+ }
0 commit comments