Merge pull request #957 from saschagrunert/panic-fix

Fix runtime panic for opening lockfile if parent dir got removed
This commit is contained in:
Daniel J Walsh 2021-07-09 06:39:19 -04:00 committed by GitHub
commit 33b3369a7f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 88 additions and 3 deletions

View File

@ -5,6 +5,7 @@ package lockfile
import (
"fmt"
"os"
"path/filepath"
"sync"
"time"
@ -33,11 +34,30 @@ type lockfile struct {
// descriptor. Note that the path is opened read-only when ro is set. If ro
// is unset, openLock will open the path read-write and create the file if
// necessary.
func openLock(path string, ro bool) (int, error) {
func openLock(path string, ro bool) (fd int, err error) {
if ro {
return unix.Open(path, os.O_RDONLY|unix.O_CLOEXEC, 0)
fd, err = unix.Open(path, os.O_RDONLY|unix.O_CLOEXEC, 0)
} else {
fd, err = unix.Open(path,
os.O_RDWR|unix.O_CLOEXEC|os.O_CREATE,
unix.S_IRUSR|unix.S_IWUSR|unix.S_IRGRP|unix.S_IROTH,
)
}
return unix.Open(path, os.O_RDWR|unix.O_CLOEXEC|os.O_CREATE, unix.S_IRUSR|unix.S_IWUSR|unix.S_IRGRP|unix.S_IROTH)
if err == nil {
return
}
// the directory of the lockfile seems to be removed, try to create it
if os.IsNotExist(err) {
if err := os.MkdirAll(filepath.Dir(path), 0700); err != nil {
return fd, errors.Wrap(err, "creating locker directory")
}
return openLock(path, ro)
}
return
}
// createLockerForPath returns a Locker object, possibly (depending on the platform)

View File

@ -0,0 +1,65 @@
// +build linux solaris darwin freebsd
package lockfile
import (
"io/ioutil"
"os"
"path/filepath"
"testing"
"github.com/stretchr/testify/require"
)
func TestOpenLock(t *testing.T) {
t.Parallel()
for _, tc := range []struct {
name string
prepare func() (path string, readOnly bool)
}{
{
name: "file exists (read/write)",
prepare: func() (string, bool) {
tempFile, err := ioutil.TempFile("", "lock-")
require.NoError(t, err)
return tempFile.Name(), false
},
},
{
name: "file exists readonly (readonly)",
prepare: func() (string, bool) {
tempFile, err := ioutil.TempFile("", "lock-")
require.NoError(t, err)
return tempFile.Name(), true
},
},
{
name: "base dir exists (read/write)",
prepare: func() (string, bool) {
tempDir := os.TempDir()
require.DirExists(t, tempDir)
return filepath.Join(tempDir, "test-1.lock"), false
},
},
{
name: "base dir not exists (read/write)",
prepare: func() (string, bool) {
tempDir, err := ioutil.TempDir("", "lock-")
require.NoError(t, err)
return filepath.Join(tempDir, "subdir", "test-1.lock"), false
},
},
} {
path, readOnly := tc.prepare()
_, err := openLock(path, readOnly)
require.NoError(t, err, tc.name)
_, err = openLock(path, readOnly)
require.NoError(t, err)
require.Nil(t, os.RemoveAll(path))
}
}