From 89a8ebecc88d3276594d6deab614fe4d6567113c Mon Sep 17 00:00:00 2001 From: Nuno Cruces Date: Tue, 7 Feb 2023 03:11:59 +0000 Subject: [PATCH] Unix locks. --- const.go | 1 - error.go | 10 +- init_test.go | 3 + tests/db_test.go | 75 +++++++++++ tests/dir_test.go | 25 ++++ sqlite3_test.go => tests/parallel_test.go | 88 +----------- vfs.go | 4 +- vfs_files.go | 26 ++-- vfs_lock.go | 157 ++++++++++------------ vfs_lock_test.go | 14 +- vfs_unix.go | 58 ++++---- vfs_windows.go | 18 +-- 12 files changed, 250 insertions(+), 229 deletions(-) create mode 100644 init_test.go create mode 100644 tests/db_test.go create mode 100644 tests/dir_test.go rename sqlite3_test.go => tests/parallel_test.go (50%) diff --git a/const.go b/const.go index e45d76a..f437bdb 100644 --- a/const.go +++ b/const.go @@ -9,7 +9,6 @@ const ( _MAX_PATHNAME = 512 - assert = true ptrlen = 4 ) diff --git a/error.go b/error.go index 24463b9..61fc68f 100644 --- a/error.go +++ b/error.go @@ -1,6 +1,7 @@ package sqlite3 import ( + "runtime" "strconv" "strings" ) @@ -42,5 +43,12 @@ const ( noNulErr = errorString("sqlite3: missing NUL terminator") noGlobalErr = errorString("sqlite3: could not find global: ") noFuncErr = errorString("sqlite3: could not find function: ") - assertErr = errorString("sqlite3: assertion failed") ) + +func assertErr() errorString { + msg := "sqlite3: assertion failed" + if _, file, line, ok := runtime.Caller(1); ok { + msg += " (" + file + ":" + strconv.Itoa(line) + ")" + } + return errorString(msg) +} diff --git a/init_test.go b/init_test.go new file mode 100644 index 0000000..72e9c6b --- /dev/null +++ b/init_test.go @@ -0,0 +1,3 @@ +package sqlite3_test + +import _ "github.com/ncruces/go-sqlite3/embed" diff --git a/tests/db_test.go b/tests/db_test.go new file mode 100644 index 0000000..14a697b --- /dev/null +++ b/tests/db_test.go @@ -0,0 +1,75 @@ +package tests + +import ( + "os" + "path/filepath" + "testing" + + "github.com/ncruces/go-sqlite3" + _ "github.com/ncruces/go-sqlite3/embed" +) + +func TestDB_memory(t *testing.T) { + testDB(t, ":memory:") +} + +func TestDB_file(t *testing.T) { + dir, err := os.MkdirTemp("", "sqlite3-") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(dir) + + testDB(t, filepath.Join(dir, "test.db")) +} + +func testDB(t *testing.T, name string) { + db, err := sqlite3.Open(name) + if err != nil { + t.Fatal(err) + } + defer db.Close() + + err = db.Exec(`CREATE TABLE IF NOT EXISTS users (id INT, name VARCHAR(10))`) + if err != nil { + t.Fatal(err) + } + + err = db.Exec(`INSERT INTO users(id, name) VALUES(0, 'go'), (1, 'zig'), (2, 'whatever')`) + if err != nil { + t.Fatal(err) + } + + stmt, _, err := db.Prepare(`SELECT id, name FROM users`) + if err != nil { + t.Fatal(err) + } + + row := 0 + ids := []int{0, 1, 2} + names := []string{"go", "zig", "whatever"} + for ; stmt.Step(); row++ { + if ids[row] != stmt.ColumnInt(0) { + t.Errorf("got %d, want %d", stmt.ColumnInt(0), ids[row]) + } + if names[row] != stmt.ColumnText(1) { + t.Errorf("got %q, want %q", stmt.ColumnText(1), names[row]) + } + } + if err := stmt.Err(); err != nil { + t.Fatal(err) + } + if row != 3 { + t.Errorf("got %d rows, want %d", row, len(ids)) + } + + err = stmt.Close() + if err != nil { + t.Fatal(err) + } + + err = db.Close() + if err != nil { + t.Fatal(err) + } +} diff --git a/tests/dir_test.go b/tests/dir_test.go new file mode 100644 index 0000000..dd9b71d --- /dev/null +++ b/tests/dir_test.go @@ -0,0 +1,25 @@ +package tests + +import ( + "errors" + "testing" + + "github.com/ncruces/go-sqlite3" +) + +func TestDir(t *testing.T) { + _, err := sqlite3.Open(".") + if err == nil { + t.Fatal("want error") + } + var serr *sqlite3.Error + if !errors.As(err, &serr) { + t.Fatal("want sqlite3.Error") + } + if serr.Code != sqlite3.CANTOPEN { + t.Error("want sqlite3.CANTOPEN") + } + if got := err.Error(); got != "sqlite3: unable to open database file" { + t.Error("got message: ", got) + } +} diff --git a/sqlite3_test.go b/tests/parallel_test.go similarity index 50% rename from sqlite3_test.go rename to tests/parallel_test.go index fc455fb..e3c36f6 100644 --- a/sqlite3_test.go +++ b/tests/parallel_test.go @@ -1,9 +1,9 @@ -package sqlite3_test +package tests import ( - "errors" "os" "path/filepath" + "runtime" "testing" "time" @@ -13,72 +13,11 @@ import ( _ "github.com/ncruces/go-sqlite3/embed" ) -func TestDB_memory(t *testing.T) { - testDB(t, ":memory:") -} - -func TestDB_file(t *testing.T) { - dir, err := os.MkdirTemp("", "sqlite3-") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(dir) - - testDB(t, filepath.Join(dir, "test.db")) -} - -func testDB(t *testing.T, name string) { - db, err := sqlite3.Open(name) - if err != nil { - t.Fatal(err) - } - defer db.Close() - - err = db.Exec(`CREATE TABLE IF NOT EXISTS users (id INT, name VARCHAR(10))`) - if err != nil { - t.Fatal(err) +func TestParallel(t *testing.T) { + if runtime.GOOS == "windows" { + t.Skip() } - err = db.Exec(`INSERT INTO users(id, name) VALUES(0, 'go'), (1, 'zig'), (2, 'whatever')`) - if err != nil { - t.Fatal(err) - } - - stmt, _, err := db.Prepare(`SELECT id, name FROM users`) - if err != nil { - t.Fatal(err) - } - - row := 0 - ids := []int{0, 1, 2} - names := []string{"go", "zig", "whatever"} - for ; stmt.Step(); row++ { - if ids[row] != stmt.ColumnInt(0) { - t.Errorf("got %d, want %d", stmt.ColumnInt(0), ids[row]) - } - if names[row] != stmt.ColumnText(1) { - t.Errorf("got %q, want %q", stmt.ColumnText(1), names[row]) - } - } - if err := stmt.Err(); err != nil { - t.Fatal(err) - } - if row != 3 { - t.Errorf("got %d rows, want %d", row, len(ids)) - } - - err = stmt.Close() - if err != nil { - t.Fatal(err) - } - - err = db.Close() - if err != nil { - t.Fatal(err) - } -} - -func TestDB_parallel(t *testing.T) { dir, err := os.MkdirTemp("", "sqlite3-") if err != nil { t.Fatal(err) @@ -172,20 +111,3 @@ func TestDB_parallel(t *testing.T) { t.Fatal(err) } } - -func TestOpen_dir(t *testing.T) { - _, err := sqlite3.Open(".") - if err == nil { - t.Fatal("want error") - } - var serr *sqlite3.Error - if !errors.As(err, &serr) { - t.Fatal("want sqlite3.Error") - } - if serr.Code != sqlite3.CANTOPEN { - t.Error("want sqlite3.CANTOPEN") - } - if got := err.Error(); got != "sqlite3: unable to open database file" { - t.Error("got message: ", got) - } -} diff --git a/vfs.go b/vfs.go index 90185ea..6d5d647 100644 --- a/vfs.go +++ b/vfs.go @@ -292,8 +292,8 @@ func vfsSync(ctx context.Context, mod api.Module, pFile, flags uint32) uint32 { } func vfsFileSize(ctx context.Context, mod api.Module, pFile, pSize uint32) uint32 { - // This uses [file.Seek] because we don't care about the offset for reading/writing. - // But consider using [file.Stat] instead (as other VFSes do). + // This uses [os.File.Seek] because we don't care about the offset for reading/writing. + // But consider using [os.File.Stat] instead (as other VFSes do). file := vfsFilePtr{mod, pFile}.OSFile() off, err := file.Seek(0, io.SeekEnd) diff --git a/vfs_files.go b/vfs_files.go index 7bba934..af4a71a 100644 --- a/vfs_files.go +++ b/vfs_files.go @@ -8,12 +8,10 @@ import ( ) type vfsOpenFile struct { - file *os.File - info os.FileInfo - nref int - - shared int - vfsLocker + file *os.File + info os.FileInfo + nref int + locker vfsFileLocker } var ( @@ -38,11 +36,10 @@ func vfsGetOpenFileID(file *os.File, info os.FileInfo) uint32 { } of := &vfsOpenFile{ - file: file, - info: info, - nref: 1, - - vfsLocker: &vfsFileLocker{file, _NO_LOCK}, + file: file, + info: info, + nref: 1, + locker: vfsFileLocker{file: file}, } // Find an empty slot. @@ -84,6 +81,13 @@ func (p vfsFilePtr) OSFile() *os.File { return vfsOpenFiles[id].file } +func (p vfsFilePtr) Locker() *vfsFileLocker { + id := p.ID() + vfsOpenFilesMtx.Lock() + defer vfsOpenFilesMtx.Unlock() + return &vfsOpenFiles[id].locker +} + func (p vfsFilePtr) ID() uint32 { return memory{p}.readUint32(p.ptr + ptrlen) } diff --git a/vfs_lock.go b/vfs_lock.go index 0bcbcb0..1fac05d 100644 --- a/vfs_lock.go +++ b/vfs_lock.go @@ -3,6 +3,7 @@ package sqlite3 import ( "context" "os" + "sync" "github.com/tetratelabs/wazero/api" ) @@ -53,32 +54,18 @@ const ( _SHARED_SIZE = 510 ) -type ( - vfsLockState uint32 - xErrorCode = ExtendedErrorCode -) - -type vfsLocker interface { - LockState() vfsLockState - - LockShared() xErrorCode // UNLOCKED -> SHARED - LockReserved() xErrorCode // SHARED -> RESERVED - LockPending() xErrorCode // SHARED|RESERVED -> PENDING - LockExclusive() xErrorCode // PENDING -> EXCLUSIVE - DowngradeLock() xErrorCode // SHARED <- EXCLUSIVE|PENDING|RESERVED - Unlock() xErrorCode // UNLOCKED <- EXCLUSIVE|PENDING|RESERVED|SHARED - - CheckReservedLock() (bool, xErrorCode) -} +type vfsLockState uint32 type vfsFileLocker struct { - *os.File - state vfsLockState + sync.Mutex + file *os.File + state vfsLockState + shared int } func vfsLock(ctx context.Context, mod api.Module, pFile uint32, eLock vfsLockState) uint32 { - if assert && (eLock == _NO_LOCK || eLock == _PENDING_LOCK) { - panic(assertErr + " [d4oxww]") + if eLock != _SHARED_LOCK && eLock != _RESERVED_LOCK && eLock != _EXCLUSIVE_LOCK { + panic(assertErr()) } ptr := vfsFilePtr{mod, pFile} @@ -89,86 +76,89 @@ func vfsLock(ctx context.Context, mod api.Module, pFile uint32, eLock vfsLockSta return _OK } - if assert { - switch { - case cLock == _NO_LOCK && eLock > _SHARED_LOCK: - // We never move from unlocked to anything higher than shared lock. - panic(assertErr + " [pfa77m]") - case cLock != _SHARED_LOCK && eLock == _RESERVED_LOCK: - // A shared lock is always held when a reserved lock is requested. - panic(assertErr + " [5cfmsp]") - } + switch { + case cLock == _NO_LOCK && eLock > _SHARED_LOCK: + // We never move from unlocked to anything higher than a shared lock. + panic(assertErr()) + case cLock != _SHARED_LOCK && eLock == _RESERVED_LOCK: + // A shared lock is always held when a reserved lock is requested. + panic(assertErr()) } - vfsOpenFilesMtx.Lock() - defer vfsOpenFilesMtx.Unlock() - of := vfsOpenFiles[ptr.ID()] - fLock := of.LockState() + fLock := ptr.Locker() + fLock.Lock() + defer fLock.Unlock() // If some other connection has a lock that precludes the requested lock, return BUSY. - if cLock != fLock && (eLock > _SHARED_LOCK || fLock >= _PENDING_LOCK) { + if cLock != fLock.state && (eLock > _SHARED_LOCK || fLock.state >= _PENDING_LOCK) { return uint32(BUSY) } - if eLock == _EXCLUSIVE_LOCK && of.shared > 1 { - // We are trying for an exclusive lock but another connection in this - // same process is still holding a shared lock. + // We are trying for an exclusive lock but another connection is still holding a shared lock. + if eLock == _EXCLUSIVE_LOCK && fLock.shared > 1 { return uint32(BUSY) } // If a SHARED lock is requested, and some other connection has a SHARED or RESERVED lock, // then increment the reference count and return OK. - if eLock == _SHARED_LOCK && (fLock == _SHARED_LOCK || fLock == _RESERVED_LOCK) { - if assert && !(cLock == _NO_LOCK && of.shared > 0) { - panic(assertErr + " [k7coz6]") + if eLock == _SHARED_LOCK && (fLock.state == _SHARED_LOCK || fLock.state == _RESERVED_LOCK) { + if cLock != _NO_LOCK || fLock.shared <= 0 { + panic(assertErr()) } ptr.SetLock(_SHARED_LOCK) - of.shared++ + fLock.shared++ return _OK } + // Get PENDING lock before acquiring an EXCLUSIVE lock. + if eLock == _EXCLUSIVE_LOCK && cLock == _RESERVED_LOCK { + if rc := fLock.GetPending(); rc != _OK { + return uint32(rc) + } + ptr.SetLock(_PENDING_LOCK) + } + // If control gets to this point, then actually go ahead and make // operating system calls for the specified lock. switch eLock { case _SHARED_LOCK: - if assert && !(fLock == _NO_LOCK && of.shared == 0) { - panic(assertErr + " [jsyttq]") + if !(fLock.state == _NO_LOCK && fLock.shared == 0) { + panic(assertErr()) } - if rc := of.LockShared(); rc != _OK { + if rc := fLock.GetShared(); rc != _OK { return uint32(rc) } - of.shared = 1 ptr.SetLock(_SHARED_LOCK) + fLock.shared = 1 return _OK case _RESERVED_LOCK: - if rc := of.LockReserved(); rc != _OK { + if !(fLock.state == _SHARED_LOCK && fLock.shared > 0) { + panic(assertErr()) + } + if rc := fLock.GetReserved(); rc != _OK { return uint32(rc) } ptr.SetLock(_RESERVED_LOCK) return _OK case _EXCLUSIVE_LOCK: - // A PENDING lock is needed before acquiring an EXCLUSIVE lock. - if cLock < _PENDING_LOCK { - if rc := of.LockPending(); rc != _OK { - return uint32(rc) - } - ptr.SetLock(_PENDING_LOCK) + if !(fLock.state != _NO_LOCK && fLock.shared > 0) { + panic(assertErr()) } - if rc := of.LockExclusive(); rc != _OK { + if rc := fLock.GetExclusive(); rc != _OK { return uint32(rc) } ptr.SetLock(_EXCLUSIVE_LOCK) return _OK default: - panic(assertErr + " [56ng2l]") + panic(assertErr()) } } func vfsUnlock(ctx context.Context, mod api.Module, pFile uint32, eLock vfsLockState) uint32 { - if assert && (eLock != _NO_LOCK && eLock != _SHARED_LOCK) { - panic(assertErr + " [7i4jw3]") + if eLock != _NO_LOCK && eLock != _SHARED_LOCK { + panic(assertErr()) } ptr := vfsFilePtr{mod, pFile} @@ -179,20 +169,19 @@ func vfsUnlock(ctx context.Context, mod api.Module, pFile uint32, eLock vfsLockS return _OK } - vfsOpenFilesMtx.Lock() - defer vfsOpenFilesMtx.Unlock() - of := vfsOpenFiles[ptr.ID()] - fLock := of.LockState() + fLock := ptr.Locker() + fLock.Lock() + defer fLock.Unlock() - if assert && of.shared <= 0 { - panic(assertErr + " [2bhkwg]") + if fLock.shared <= 0 { + panic(assertErr()) } if cLock > _SHARED_LOCK { - if assert && cLock != fLock { - panic(assertErr + " [6pmjqf]") + if cLock != fLock.state { + panic(assertErr()) } if eLock == _SHARED_LOCK { - if rc := of.DowngradeLock(); rc != _OK { + if rc := fLock.Downgrade(); rc != _OK { return uint32(rc) } ptr.SetLock(_SHARED_LOCK) @@ -200,27 +189,25 @@ func vfsUnlock(ctx context.Context, mod api.Module, pFile uint32, eLock vfsLockS } } - if assert && eLock != _NO_LOCK { - panic(assertErr + " [gilo9p]") + if eLock != _NO_LOCK { + panic(assertErr()) } - // Decrement the shared lock counter. Release the file lock - // only when all connections have released the lock. + // Release the file lock only when all connections have released the lock. + // Decrement the shared lock counter. switch { - case of.shared > 1: - ptr.SetLock(_NO_LOCK) - of.shared-- - return _OK - - case of.shared == 1: - if rc := of.Unlock(); rc != _OK { + case fLock.shared == 1: + if rc := fLock.Release(); rc != _OK { return uint32(rc) } + fallthrough + + case fLock.shared > 1: ptr.SetLock(_NO_LOCK) - of.shared = 0 + fLock.shared-- return _OK default: - panic(assertErr + " [50gw51]") + panic(assertErr()) } } @@ -228,15 +215,15 @@ func vfsCheckReservedLock(ctx context.Context, mod api.Module, pFile, pResOut ui ptr := vfsFilePtr{mod, pFile} cLock := ptr.Lock() - if assert && cLock > _SHARED_LOCK { - panic(assertErr + " [zarygt]") + if cLock > _SHARED_LOCK { + panic(assertErr()) } - vfsOpenFilesMtx.Lock() - defer vfsOpenFilesMtx.Unlock() - of := vfsOpenFiles[ptr.ID()] + fLock := ptr.Locker() + fLock.Lock() + defer fLock.Unlock() - locked, rc := of.CheckReservedLock() + locked, rc := fLock.CheckReserved() if rc != _OK { return uint32(IOERR_CHECKRESERVEDLOCK) } diff --git a/vfs_lock_test.go b/vfs_lock_test.go index afac3d3..d032e2d 100644 --- a/vfs_lock_test.go +++ b/vfs_lock_test.go @@ -31,13 +31,13 @@ func Test_vfsLock(t *testing.T) { defer file2.Close() vfsOpenFiles = append(vfsOpenFiles, &vfsOpenFile{ - file: file1, - nref: 1, - vfsLocker: &vfsFileLocker{file1, _NO_LOCK}, + file: file1, + nref: 1, + locker: vfsFileLocker{file: file1}, }, &vfsOpenFile{ - file: file2, - nref: 1, - vfsLocker: &vfsFileLocker{file2, _NO_LOCK}, + file: file2, + nref: 1, + locker: vfsFileLocker{file: file2}, }) mem := newMemory(128) @@ -65,7 +65,7 @@ func Test_vfsLock(t *testing.T) { t.Error("file was locked") } - rc = vfsLock(context.TODO(), mem.mod, 16, _EXCLUSIVE_LOCK) + rc = vfsLock(context.TODO(), mem.mod, 16, _RESERVED_LOCK) if rc != _OK { t.Fatal("returned", rc) } diff --git a/vfs_unix.go b/vfs_unix.go index c770e17..896c77c 100644 --- a/vfs_unix.go +++ b/vfs_unix.go @@ -12,13 +12,9 @@ func deleteOnClose(f *os.File) { _ = os.Remove(f.Name()) } -func (l *vfsFileLocker) LockState() vfsLockState { - return l.state -} - -func (l *vfsFileLocker) LockShared() xErrorCode { - if assert && !(l.state == _NO_LOCK) { - panic(assertErr + " [wz9dcw]") +func (l *vfsFileLocker) GetShared() ExtendedErrorCode { + if l.state != _NO_LOCK { + panic(assertErr()) } // A PENDING lock is needed before acquiring a SHARED lock. @@ -52,9 +48,9 @@ func (l *vfsFileLocker) LockShared() xErrorCode { return _OK } -func (l *vfsFileLocker) LockReserved() xErrorCode { - if assert && !(l.state == _SHARED_LOCK) { - panic(assertErr + " [m9hcil]") +func (l *vfsFileLocker) GetReserved() ExtendedErrorCode { + if l.state != _SHARED_LOCK { + panic(assertErr()) } // Acquire the RESERVED lock. @@ -69,9 +65,9 @@ func (l *vfsFileLocker) LockReserved() xErrorCode { return _OK } -func (l *vfsFileLocker) LockPending() xErrorCode { - if assert && !(l.state == _SHARED_LOCK || l.state == _RESERVED_LOCK) { - panic(assertErr + " [wx8nk2]") +func (l *vfsFileLocker) GetPending() ExtendedErrorCode { + if l.state != _RESERVED_LOCK { + panic(assertErr()) } // Acquire the PENDING lock. @@ -86,9 +82,9 @@ func (l *vfsFileLocker) LockPending() xErrorCode { return _OK } -func (l *vfsFileLocker) LockExclusive() xErrorCode { - if assert && !(l.state == _PENDING_LOCK) { - panic(assertErr + " [84nbax]") +func (l *vfsFileLocker) GetExclusive() ExtendedErrorCode { + if l.state != _SHARED_LOCK && l.state != _PENDING_LOCK { + panic(assertErr()) } // Acquire the EXCLUSIVE lock. @@ -103,9 +99,9 @@ func (l *vfsFileLocker) LockExclusive() xErrorCode { return _OK } -func (l *vfsFileLocker) DowngradeLock() xErrorCode { - if assert && !(l.state > _SHARED_LOCK) { - panic(assertErr + " [je31i3]") +func (l *vfsFileLocker) Downgrade() ExtendedErrorCode { + if l.state <= _SHARED_LOCK { + panic(assertErr()) } // Downgrade to a SHARED lock. @@ -134,7 +130,11 @@ func (l *vfsFileLocker) DowngradeLock() xErrorCode { return _OK } -func (l *vfsFileLocker) Unlock() xErrorCode { +func (l *vfsFileLocker) Release() ExtendedErrorCode { + if l.state <= _NO_LOCK { + panic(assertErr()) + } + // Release all locks. if err := l.fcntlSetLock(&syscall.Flock_t{ Type: syscall.F_UNLCK, @@ -145,13 +145,15 @@ func (l *vfsFileLocker) Unlock() xErrorCode { return _OK } -func (l *vfsFileLocker) CheckReservedLock() (bool, xErrorCode) { +func (l *vfsFileLocker) CheckReserved() (bool, ExtendedErrorCode) { if l.state >= _RESERVED_LOCK { return true, _OK } - // Test all write locks. + // Test the RESERVED lock. lock := syscall.Flock_t{ - Type: syscall.F_RDLCK, + Type: syscall.F_RDLCK, + Start: _RESERVED_BYTE, + Len: 1, } if l.fcntlGetLock(&lock) != nil { return false, IOERR_CHECKRESERVEDLOCK @@ -169,7 +171,7 @@ func (l *vfsFileLocker) fcntlGetLock(lock *syscall.Flock_t) error { // https://github.com/apple/darwin-xnu/blob/main/bsd/sys/fcntl.h F_GETLK = 92 // F_OFD_GETLK } - return syscall.FcntlFlock(l.Fd(), F_GETLK, lock) + return syscall.FcntlFlock(l.file.Fd(), F_GETLK, lock) } func (l *vfsFileLocker) fcntlSetLock(lock *syscall.Flock_t) error { @@ -182,10 +184,10 @@ func (l *vfsFileLocker) fcntlSetLock(lock *syscall.Flock_t) error { // https://github.com/apple/darwin-xnu/blob/main/bsd/sys/fcntl.h F_SETLK = 90 // F_OFD_SETLK } - return syscall.FcntlFlock(l.Fd(), F_SETLK, lock) + return syscall.FcntlFlock(l.file.Fd(), F_SETLK, lock) } -func (vfsFileLocker) errorCode(err error, def xErrorCode) xErrorCode { +func (*vfsFileLocker) errorCode(err error, def ExtendedErrorCode) ExtendedErrorCode { if errno, ok := err.(syscall.Errno); ok { switch errno { case syscall.EACCES: @@ -195,9 +197,9 @@ func (vfsFileLocker) errorCode(err error, def xErrorCode) xErrorCode { case syscall.ENOLCK: case syscall.EDEADLK: case syscall.ETIMEDOUT: - return xErrorCode(BUSY) + return ExtendedErrorCode(BUSY) case syscall.EPERM: - return xErrorCode(PERM) + return ExtendedErrorCode(PERM) } } return def diff --git a/vfs_windows.go b/vfs_windows.go index 320a851..e532245 100644 --- a/vfs_windows.go +++ b/vfs_windows.go @@ -4,41 +4,37 @@ import "os" func deleteOnClose(f *os.File) {} -func (l *vfsFileLocker) LockState() vfsLockState { - return l.state -} - -func (l *vfsFileLocker) LockShared() xErrorCode { +func (l *vfsFileLocker) GetShared() ExtendedErrorCode { l.state = _SHARED_LOCK return _OK } -func (l *vfsFileLocker) LockReserved() xErrorCode { +func (l *vfsFileLocker) GetReserved() ExtendedErrorCode { l.state = _RESERVED_LOCK return _OK } -func (l *vfsFileLocker) LockPending() xErrorCode { +func (l *vfsFileLocker) GetPending() ExtendedErrorCode { l.state = _PENDING_LOCK return _OK } -func (l *vfsFileLocker) LockExclusive() xErrorCode { +func (l *vfsFileLocker) GetExclusive() ExtendedErrorCode { l.state = _EXCLUSIVE_LOCK return _OK } -func (l *vfsFileLocker) DowngradeLock() xErrorCode { +func (l *vfsFileLocker) Downgrade() ExtendedErrorCode { l.state = _SHARED_LOCK return _OK } -func (l *vfsFileLocker) Unlock() xErrorCode { +func (l *vfsFileLocker) Release() ExtendedErrorCode { l.state = _NO_LOCK return _OK } -func (l *vfsFileLocker) CheckReservedLock() (bool, xErrorCode) { +func (l *vfsFileLocker) CheckReserved() (bool, ExtendedErrorCode) { if l.state >= _RESERVED_LOCK { return true, _OK }