mirror of
https://github.com/ncruces/go-sqlite3.git
synced 2026-01-11 21:49:13 +00:00
VFS error handling.
This commit is contained in:
@@ -265,7 +265,7 @@ func traceCallback(ctx context.Context, mod api.Module, evt TraceEvent, pDB, pAr
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if arg1 != nil {
|
if arg1 != nil {
|
||||||
_, rc = errorCode(c.trace(evt, arg1, arg2), ERROR)
|
_ = c.trace(evt, arg1, arg2)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return rc
|
return rc
|
||||||
|
|||||||
@@ -198,14 +198,14 @@ func (ctx Context) ResultError(err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
msg, code := errorCode(err, _OK)
|
msg, code := errorCode(err, ERROR)
|
||||||
if msg != "" {
|
if msg != "" {
|
||||||
defer ctx.c.arena.mark()()
|
defer ctx.c.arena.mark()()
|
||||||
ptr := ctx.c.arena.string(msg)
|
ptr := ctx.c.arena.string(msg)
|
||||||
ctx.c.call("sqlite3_result_error",
|
ctx.c.call("sqlite3_result_error",
|
||||||
stk_t(ctx.handle), stk_t(ptr), stk_t(len(msg)))
|
stk_t(ctx.handle), stk_t(ptr), stk_t(len(msg)))
|
||||||
}
|
}
|
||||||
if code != _OK {
|
if code != res_t(ERROR) {
|
||||||
ctx.c.call("sqlite3_result_error_code",
|
ctx.c.call("sqlite3_result_error_code",
|
||||||
stk_t(ctx.handle), stk_t(code))
|
stk_t(ctx.handle), stk_t(code))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,8 +44,8 @@ func Test_Open_dir(t *testing.T) {
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatal("want error")
|
t.Fatal("want error")
|
||||||
}
|
}
|
||||||
if !errors.Is(err, sqlite3.CANTOPEN) {
|
if !errors.Is(err, sqlite3.CANTOPEN_ISDIR) {
|
||||||
t.Errorf("got %v, want sqlite3.CANTOPEN", err)
|
t.Errorf("got %v, want sqlite3.CANTOPEN_ISDIR", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
32
error.go
32
error.go
@@ -11,6 +11,7 @@ import (
|
|||||||
//
|
//
|
||||||
// https://sqlite.org/c3ref/errcode.html
|
// https://sqlite.org/c3ref/errcode.html
|
||||||
type Error struct {
|
type Error struct {
|
||||||
|
sys error
|
||||||
msg string
|
msg string
|
||||||
sql string
|
sql string
|
||||||
code res_t
|
code res_t
|
||||||
@@ -33,7 +34,7 @@ func (e *Error) ExtendedCode() ExtendedErrorCode {
|
|||||||
// Error implements the error interface.
|
// Error implements the error interface.
|
||||||
func (e *Error) Error() string {
|
func (e *Error) Error() string {
|
||||||
var b strings.Builder
|
var b strings.Builder
|
||||||
b.WriteString(util.ErrorCodeString(uint32(e.code)))
|
b.WriteString(util.ErrorCodeString(e.code))
|
||||||
|
|
||||||
if e.msg != "" {
|
if e.msg != "" {
|
||||||
b.WriteString(": ")
|
b.WriteString(": ")
|
||||||
@@ -43,6 +44,14 @@ func (e *Error) Error() string {
|
|||||||
return b.String()
|
return b.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Unwrap returns the underlying operating system error
|
||||||
|
// that caused the I/O error or failure to open a file.
|
||||||
|
//
|
||||||
|
// https://sqlite.org/c3ref/system_errno.html
|
||||||
|
func (e *Error) Unwrap() error {
|
||||||
|
return e.sys
|
||||||
|
}
|
||||||
|
|
||||||
// Is tests whether this error matches a given [ErrorCode] or [ExtendedErrorCode].
|
// Is tests whether this error matches a given [ErrorCode] or [ExtendedErrorCode].
|
||||||
//
|
//
|
||||||
// It makes it possible to do:
|
// It makes it possible to do:
|
||||||
@@ -90,7 +99,16 @@ func (e *Error) SQL() string {
|
|||||||
|
|
||||||
// Error implements the error interface.
|
// Error implements the error interface.
|
||||||
func (e ErrorCode) Error() string {
|
func (e ErrorCode) Error() string {
|
||||||
return util.ErrorCodeString(uint32(e))
|
return util.ErrorCodeString(e)
|
||||||
|
}
|
||||||
|
|
||||||
|
// As converts this error to an [ExtendedErrorCode].
|
||||||
|
func (e ErrorCode) As(err any) bool {
|
||||||
|
c, ok := err.(*xErrorCode)
|
||||||
|
if ok {
|
||||||
|
*c = xErrorCode(e)
|
||||||
|
}
|
||||||
|
return ok
|
||||||
}
|
}
|
||||||
|
|
||||||
// Temporary returns true for [BUSY] errors.
|
// Temporary returns true for [BUSY] errors.
|
||||||
@@ -105,7 +123,7 @@ func (e ErrorCode) ExtendedCode() ExtendedErrorCode {
|
|||||||
|
|
||||||
// Error implements the error interface.
|
// Error implements the error interface.
|
||||||
func (e ExtendedErrorCode) Error() string {
|
func (e ExtendedErrorCode) Error() string {
|
||||||
return util.ErrorCodeString(uint32(e))
|
return util.ErrorCodeString(e)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Is tests whether this error matches a given [ErrorCode].
|
// Is tests whether this error matches a given [ErrorCode].
|
||||||
@@ -150,14 +168,10 @@ func errorCode(err error, def ErrorCode) (msg string, code res_t) {
|
|||||||
return code.msg, res_t(code.code)
|
return code.msg, res_t(code.code)
|
||||||
}
|
}
|
||||||
|
|
||||||
var ecode ErrorCode
|
|
||||||
var xcode xErrorCode
|
var xcode xErrorCode
|
||||||
switch {
|
if errors.As(err, &xcode) {
|
||||||
case errors.As(err, &xcode):
|
|
||||||
code = res_t(xcode)
|
code = res_t(xcode)
|
||||||
case errors.As(err, &ecode):
|
} else {
|
||||||
code = res_t(ecode)
|
|
||||||
default:
|
|
||||||
code = res_t(def)
|
code = res_t(def)
|
||||||
}
|
}
|
||||||
return err.Error(), code
|
return err.Error(), code
|
||||||
|
|||||||
@@ -33,8 +33,12 @@ func AssertErr() ErrorString {
|
|||||||
return ErrorString(msg)
|
return ErrorString(msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
func ErrorCodeString(rc uint32) string {
|
type errorCode interface {
|
||||||
switch rc {
|
~uint8 | ~uint16 | ~uint32 | ~int32
|
||||||
|
}
|
||||||
|
|
||||||
|
func ErrorCodeString[T errorCode](rc T) string {
|
||||||
|
switch uint32(rc) {
|
||||||
case ABORT_ROLLBACK:
|
case ABORT_ROLLBACK:
|
||||||
return "sqlite3: abort due to ROLLBACK"
|
return "sqlite3: abort due to ROLLBACK"
|
||||||
case ROW:
|
case ROW:
|
||||||
@@ -42,7 +46,7 @@ func ErrorCodeString(rc uint32) string {
|
|||||||
case DONE:
|
case DONE:
|
||||||
return "sqlite3: no more rows available"
|
return "sqlite3: no more rows available"
|
||||||
}
|
}
|
||||||
switch rc & 0xff {
|
switch uint8(rc) {
|
||||||
case OK:
|
case OK:
|
||||||
return "sqlite3: not an error"
|
return "sqlite3: not an error"
|
||||||
case ERROR:
|
case ERROR:
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ type ConnKey struct{}
|
|||||||
|
|
||||||
type moduleKey struct{}
|
type moduleKey struct{}
|
||||||
type moduleState struct {
|
type moduleState struct {
|
||||||
|
sysError error
|
||||||
mmapState
|
mmapState
|
||||||
handleState
|
handleState
|
||||||
}
|
}
|
||||||
@@ -23,3 +24,15 @@ func NewContext(ctx context.Context) context.Context {
|
|||||||
ctx = context.WithValue(ctx, moduleKey{}, state)
|
ctx = context.WithValue(ctx, moduleKey{}, state)
|
||||||
return ctx
|
return ctx
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetSystemError(ctx context.Context) error {
|
||||||
|
s := ctx.Value(moduleKey{}).(*moduleState)
|
||||||
|
return s.sysError
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetSystemError(ctx context.Context, err error) {
|
||||||
|
s, ok := ctx.Value(moduleKey{}).(*moduleState)
|
||||||
|
if ok {
|
||||||
|
s.sysError = err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
19
sqlite.go
19
sqlite.go
@@ -125,14 +125,15 @@ func (sqlt *sqlite) error(rc res_t, handle ptr_t, sql ...string) error {
|
|||||||
panic(util.OOMErr)
|
panic(util.OOMErr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var msg, query string
|
||||||
if handle != 0 {
|
if handle != 0 {
|
||||||
var msg, query string
|
|
||||||
if ptr := ptr_t(sqlt.call("sqlite3_errmsg", stk_t(handle))); ptr != 0 {
|
if ptr := ptr_t(sqlt.call("sqlite3_errmsg", stk_t(handle))); ptr != 0 {
|
||||||
msg = util.ReadString(sqlt.mod, ptr, _MAX_LENGTH)
|
msg = util.ReadString(sqlt.mod, ptr, _MAX_LENGTH)
|
||||||
|
msg = strings.TrimPrefix(msg, "sqlite3: ")
|
||||||
|
msg = strings.TrimPrefix(msg, util.ErrorCodeString(rc)[len("sqlite3: "):])
|
||||||
|
msg = strings.TrimPrefix(msg, ": ")
|
||||||
if msg == "not an error" {
|
if msg == "not an error" {
|
||||||
msg = ""
|
msg = ""
|
||||||
} else {
|
|
||||||
msg = strings.TrimPrefix(msg, util.ErrorCodeString(uint32(rc))[len("sqlite3: "):])
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -141,10 +142,16 @@ func (sqlt *sqlite) error(rc res_t, handle ptr_t, sql ...string) error {
|
|||||||
query = sql[0][i:]
|
query = sql[0][i:]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if msg != "" || query != "" {
|
var sys error
|
||||||
return &Error{code: rc, msg: msg, sql: query}
|
switch ErrorCode(rc) {
|
||||||
}
|
case CANTOPEN, IOERR:
|
||||||
|
sys = util.GetSystemError(sqlt.ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
if sys != nil || msg != "" || query != "" {
|
||||||
|
return &Error{code: rc, sys: sys, msg: msg, sql: query}
|
||||||
}
|
}
|
||||||
return xErrorCode(rc)
|
return xErrorCode(rc)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,8 +22,8 @@ func TestConn_Open_dir(t *testing.T) {
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatal("want error")
|
t.Fatal("want error")
|
||||||
}
|
}
|
||||||
if !errors.Is(err, sqlite3.CANTOPEN) {
|
if !errors.Is(err, sqlite3.CANTOPEN_ISDIR) {
|
||||||
t.Errorf("got %v, want sqlite3.CANTOPEN", err)
|
t.Errorf("got %v, want sqlite3.CANTOPEN_ISDIR", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ to check if your build supports shared memory.
|
|||||||
|
|
||||||
### Blocking Locks
|
### Blocking Locks
|
||||||
|
|
||||||
On Windows and macOS, this package implements
|
On macOS, this package implements
|
||||||
[Wal-mode blocking locks](https://sqlite.org/src/doc/tip/doc/wal-lock.md).
|
[Wal-mode blocking locks](https://sqlite.org/src/doc/tip/doc/wal-lock.md).
|
||||||
|
|
||||||
### Batch-Atomic Write
|
### Batch-Atomic Write
|
||||||
|
|||||||
@@ -193,8 +193,8 @@ type FileSharedMemory interface {
|
|||||||
// SharedMemory is a shared-memory WAL-index implementation.
|
// SharedMemory is a shared-memory WAL-index implementation.
|
||||||
// Use [NewSharedMemory] to create a shared-memory.
|
// Use [NewSharedMemory] to create a shared-memory.
|
||||||
type SharedMemory interface {
|
type SharedMemory interface {
|
||||||
shmMap(context.Context, api.Module, int32, int32, bool) (ptr_t, _ErrorCode)
|
shmMap(context.Context, api.Module, int32, int32, bool) (ptr_t, error)
|
||||||
shmLock(int32, int32, _ShmFlag) _ErrorCode
|
shmLock(int32, int32, _ShmFlag) error
|
||||||
shmUnmap(bool)
|
shmUnmap(bool)
|
||||||
shmBarrier()
|
shmBarrier()
|
||||||
io.Closer
|
io.Closer
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ type (
|
|||||||
type _ErrorCode uint32
|
type _ErrorCode uint32
|
||||||
|
|
||||||
func (e _ErrorCode) Error() string {
|
func (e _ErrorCode) Error() string {
|
||||||
return util.ErrorCodeString(uint32(e))
|
return util.ErrorCodeString(e)
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|||||||
14
vfs/file.go
14
vfs/file.go
@@ -40,7 +40,7 @@ func evalSymlinks(path string) (string, error) {
|
|||||||
func (vfsOS) Delete(path string, syncDir bool) error {
|
func (vfsOS) Delete(path string, syncDir bool) error {
|
||||||
err := os.Remove(path)
|
err := os.Remove(path)
|
||||||
if errors.Is(err, fs.ErrNotExist) {
|
if errors.Is(err, fs.ErrNotExist) {
|
||||||
return _IOERR_DELETE_NOENT
|
return sysError{err, _IOERR_DELETE_NOENT}
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -53,7 +53,7 @@ func (vfsOS) Delete(path string, syncDir bool) error {
|
|||||||
defer f.Close()
|
defer f.Close()
|
||||||
err = osSync(f, 0, SYNC_FULL)
|
err = osSync(f, 0, SYNC_FULL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return _IOERR_DIR_FSYNC
|
return sysError{err, _IOERR_DIR_FSYNC}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@@ -108,14 +108,14 @@ func (vfsOS) OpenFilename(name *Filename, flags OpenFlag) (File, OpenFlag, error
|
|||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if name == nil {
|
if name == nil {
|
||||||
return nil, flags, _IOERR_GETTEMPPATH
|
return nil, flags, sysError{err, _IOERR_GETTEMPPATH}
|
||||||
}
|
}
|
||||||
if errors.Is(err, syscall.EISDIR) {
|
if errors.Is(err, syscall.EISDIR) {
|
||||||
return nil, flags, _CANTOPEN_ISDIR
|
return nil, flags, sysError{err, _CANTOPEN_ISDIR}
|
||||||
}
|
}
|
||||||
if isCreate && isJournl && errors.Is(err, fs.ErrPermission) &&
|
if isCreate && isJournl && errors.Is(err, fs.ErrPermission) &&
|
||||||
osAccess(name.String(), ACCESS_EXISTS) != nil {
|
osAccess(name.String(), ACCESS_EXISTS) != nil {
|
||||||
return nil, flags, _READONLY_DIRECTORY
|
return nil, flags, sysError{err, _READONLY_DIRECTORY}
|
||||||
}
|
}
|
||||||
return nil, flags, err
|
return nil, flags, err
|
||||||
}
|
}
|
||||||
@@ -123,7 +123,7 @@ func (vfsOS) OpenFilename(name *Filename, flags OpenFlag) (File, OpenFlag, error
|
|||||||
if modeof := name.URIParameter("modeof"); modeof != "" {
|
if modeof := name.URIParameter("modeof"); modeof != "" {
|
||||||
if err = osSetMode(f, modeof); err != nil {
|
if err = osSetMode(f, modeof); err != nil {
|
||||||
f.Close()
|
f.Close()
|
||||||
return nil, flags, _IOERR_FSTAT
|
return nil, flags, sysError{err, _IOERR_FSTAT}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if isUnix && flags&OPEN_DELETEONCLOSE != 0 {
|
if isUnix && flags&OPEN_DELETEONCLOSE != 0 {
|
||||||
@@ -193,7 +193,7 @@ func (f *vfsFile) Sync(flags SyncFlag) error {
|
|||||||
defer d.Close()
|
defer d.Close()
|
||||||
err = osSync(f.File, f.flags, flags)
|
err = osSync(f.File, f.flags, flags)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return _IOERR_DIR_FSYNC
|
return sysError{err, _IOERR_DIR_FSYNC}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ func osReadAt(file *os.File, p []byte, off int64) (int, error) {
|
|||||||
unix.ERANGE,
|
unix.ERANGE,
|
||||||
unix.EIO,
|
unix.EIO,
|
||||||
unix.ENXIO:
|
unix.ENXIO:
|
||||||
return n, _IOERR_CORRUPTFS
|
return n, sysError{err, _IOERR_CORRUPTFS}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return n, err
|
return n, err
|
||||||
@@ -42,7 +42,7 @@ func osReadAt(file *os.File, p []byte, off int64) (int, error) {
|
|||||||
func osWriteAt(file *os.File, p []byte, off int64) (int, error) {
|
func osWriteAt(file *os.File, p []byte, off int64) (int, error) {
|
||||||
n, err := file.WriteAt(p, off)
|
n, err := file.WriteAt(p, off)
|
||||||
if errno, ok := err.(unix.Errno); ok && errno == unix.ENOSPC {
|
if errno, ok := err.(unix.Errno); ok && errno == unix.ENOSPC {
|
||||||
return n, _FULL
|
return n, sysError{err, _FULL}
|
||||||
}
|
}
|
||||||
return n, err
|
return n, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ func osWriteAt(file *os.File, p []byte, off int64) (int, error) {
|
|||||||
case
|
case
|
||||||
windows.ERROR_HANDLE_DISK_FULL,
|
windows.ERROR_HANDLE_DISK_FULL,
|
||||||
windows.ERROR_DISK_FULL:
|
windows.ERROR_DISK_FULL:
|
||||||
return n, _FULL
|
return n, sysError{err, _FULL}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return n, err
|
return n, err
|
||||||
|
|||||||
@@ -141,7 +141,7 @@ func (s *vfsShm) shmOpen() (rc _ErrorCode) {
|
|||||||
return _OK
|
return _OK
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *vfsShm) shmMap(ctx context.Context, mod api.Module, id, size int32, extend bool) (ptr_t, _ErrorCode) {
|
func (s *vfsShm) shmMap(ctx context.Context, mod api.Module, id, size int32, extend bool) (ptr_t, error) {
|
||||||
// Ensure size is a multiple of the OS page size.
|
// Ensure size is a multiple of the OS page size.
|
||||||
if int(size)&(unix.Getpagesize()-1) != 0 {
|
if int(size)&(unix.Getpagesize()-1) != 0 {
|
||||||
return 0, _IOERR_SHMMAP
|
return 0, _IOERR_SHMMAP
|
||||||
@@ -154,26 +154,30 @@ func (s *vfsShm) shmMap(ctx context.Context, mod api.Module, id, size int32, ext
|
|||||||
// Check if file is big enough.
|
// Check if file is big enough.
|
||||||
o, err := s.Seek(0, io.SeekEnd)
|
o, err := s.Seek(0, io.SeekEnd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, _IOERR_SHMSIZE
|
return 0, sysError{err, _IOERR_SHMSIZE}
|
||||||
}
|
}
|
||||||
if n := (int64(id) + 1) * int64(size); n > o {
|
if n := (int64(id) + 1) * int64(size); n > o {
|
||||||
if !extend {
|
if !extend {
|
||||||
return 0, _OK
|
return 0, nil
|
||||||
}
|
}
|
||||||
if osAllocate(s.File, n) != nil {
|
if err := osAllocate(s.File, n); err != nil {
|
||||||
return 0, _IOERR_SHMSIZE
|
return 0, sysError{err, _IOERR_SHMSIZE}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
r, err := util.MapRegion(ctx, mod, s.File, int64(id)*int64(size), size, false)
|
r, err := util.MapRegion(ctx, mod, s.File, int64(id)*int64(size), size, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, _IOERR_SHMMAP
|
return 0, err
|
||||||
}
|
}
|
||||||
s.regions = append(s.regions, r)
|
s.regions = append(s.regions, r)
|
||||||
return r.Ptr, _OK
|
return r.Ptr, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *vfsShm) shmLock(offset, n int32, flags _ShmFlag) _ErrorCode {
|
func (s *vfsShm) shmLock(offset, n int32, flags _ShmFlag) error {
|
||||||
|
if s.vfsShmParent == nil {
|
||||||
|
return _IOERR_SHMLOCK
|
||||||
|
}
|
||||||
|
|
||||||
s.Lock()
|
s.Lock()
|
||||||
defer s.Unlock()
|
defer s.Unlock()
|
||||||
|
|
||||||
|
|||||||
@@ -31,8 +31,8 @@ const (
|
|||||||
//
|
//
|
||||||
// https://sqlite.org/walformat.html#the_wal_index_file_format
|
// https://sqlite.org/walformat.html#the_wal_index_file_format
|
||||||
|
|
||||||
func (s *vfsShm) shmAcquire(ptr *_ErrorCode) {
|
func (s *vfsShm) shmAcquire(errp *error) {
|
||||||
if ptr != nil && *ptr != _OK {
|
if errp != nil && *errp != _OK {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if len(s.ptrs) == 0 || shmEqual(s.shadow[0][:], s.shared[0][:]) {
|
if len(s.ptrs) == 0 || shmEqual(s.shadow[0][:], s.shared[0][:]) {
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ func (s *vfsShm) Close() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if err := dotlk.Unlock(s.path); err != nil {
|
if err := dotlk.Unlock(s.path); err != nil {
|
||||||
return _IOERR_UNLOCK
|
return sysError{err, _IOERR_UNLOCK}
|
||||||
}
|
}
|
||||||
delete(vfsShmList, s.path)
|
delete(vfsShmList, s.path)
|
||||||
s.vfsShmParent = nil
|
s.vfsShmParent = nil
|
||||||
@@ -96,7 +96,7 @@ func (s *vfsShm) shmOpen() _ErrorCode {
|
|||||||
return _OK
|
return _OK
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *vfsShm) shmMap(ctx context.Context, mod api.Module, id, size int32, extend bool) (ptr_t, _ErrorCode) {
|
func (s *vfsShm) shmMap(ctx context.Context, mod api.Module, id, size int32, extend bool) (ptr_t, error) {
|
||||||
if size != _WALINDEX_PGSZ {
|
if size != _WALINDEX_PGSZ {
|
||||||
return 0, _IOERR_SHMMAP
|
return 0, _IOERR_SHMMAP
|
||||||
}
|
}
|
||||||
@@ -116,7 +116,7 @@ func (s *vfsShm) shmMap(ctx context.Context, mod api.Module, id, size int32, ext
|
|||||||
// Extend shared memory.
|
// Extend shared memory.
|
||||||
if int(id) >= len(s.shared) {
|
if int(id) >= len(s.shared) {
|
||||||
if !extend {
|
if !extend {
|
||||||
return 0, _OK
|
return 0, nil
|
||||||
}
|
}
|
||||||
s.shared = append(s.shared, make([][_WALINDEX_PGSZ]byte, int(id)-len(s.shared)+1)...)
|
s.shared = append(s.shared, make([][_WALINDEX_PGSZ]byte, int(id)-len(s.shared)+1)...)
|
||||||
}
|
}
|
||||||
@@ -140,16 +140,20 @@ func (s *vfsShm) shmMap(ctx context.Context, mod api.Module, id, size int32, ext
|
|||||||
}
|
}
|
||||||
|
|
||||||
s.shadow[0][4] = 1
|
s.shadow[0][4] = 1
|
||||||
return s.ptrs[id], _OK
|
return s.ptrs[id], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *vfsShm) shmLock(offset, n int32, flags _ShmFlag) (rc _ErrorCode) {
|
func (s *vfsShm) shmLock(offset, n int32, flags _ShmFlag) (err error) {
|
||||||
|
if s.vfsShmParent == nil {
|
||||||
|
return _IOERR_SHMLOCK
|
||||||
|
}
|
||||||
|
|
||||||
s.Lock()
|
s.Lock()
|
||||||
defer s.Unlock()
|
defer s.Unlock()
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case flags&_SHM_LOCK != 0:
|
case flags&_SHM_LOCK != 0:
|
||||||
defer s.shmAcquire(&rc)
|
defer s.shmAcquire(&err)
|
||||||
case flags&_SHM_EXCLUSIVE != 0:
|
case flags&_SHM_EXCLUSIVE != 0:
|
||||||
s.shmRelease()
|
s.shmRelease()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ func (s *vfsShm) shmOpen() _ErrorCode {
|
|||||||
return rc
|
return rc
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *vfsShm) shmMap(ctx context.Context, mod api.Module, id, size int32, extend bool) (ptr_t, _ErrorCode) {
|
func (s *vfsShm) shmMap(ctx context.Context, mod api.Module, id, size int32, extend bool) (ptr_t, error) {
|
||||||
// Ensure size is a multiple of the OS page size.
|
// Ensure size is a multiple of the OS page size.
|
||||||
if int(size)&(unix.Getpagesize()-1) != 0 {
|
if int(size)&(unix.Getpagesize()-1) != 0 {
|
||||||
return 0, _IOERR_SHMMAP
|
return 0, _IOERR_SHMMAP
|
||||||
@@ -86,29 +86,32 @@ func (s *vfsShm) shmMap(ctx context.Context, mod api.Module, id, size int32, ext
|
|||||||
// Check if file is big enough.
|
// Check if file is big enough.
|
||||||
o, err := s.Seek(0, io.SeekEnd)
|
o, err := s.Seek(0, io.SeekEnd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, _IOERR_SHMSIZE
|
return 0, sysError{err, _IOERR_SHMSIZE}
|
||||||
}
|
}
|
||||||
if n := (int64(id) + 1) * int64(size); n > o {
|
if n := (int64(id) + 1) * int64(size); n > o {
|
||||||
if !extend {
|
if !extend {
|
||||||
return 0, _OK
|
return 0, nil
|
||||||
}
|
}
|
||||||
if s.readOnly || osAllocate(s.File, n) != nil {
|
if s.readOnly {
|
||||||
return 0, _IOERR_SHMSIZE
|
return 0, _IOERR_SHMSIZE
|
||||||
}
|
}
|
||||||
|
if err := osAllocate(s.File, n); err != nil {
|
||||||
|
return 0, sysError{err, _IOERR_SHMSIZE}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
r, err := util.MapRegion(ctx, mod, s.File, int64(id)*int64(size), size, s.readOnly)
|
r, err := util.MapRegion(ctx, mod, s.File, int64(id)*int64(size), size, s.readOnly)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, _IOERR_SHMMAP
|
return 0, err
|
||||||
}
|
}
|
||||||
s.regions = append(s.regions, r)
|
s.regions = append(s.regions, r)
|
||||||
if s.readOnly {
|
if s.readOnly {
|
||||||
return r.Ptr, _READONLY
|
return r.Ptr, _READONLY
|
||||||
}
|
}
|
||||||
return r.Ptr, _OK
|
return r.Ptr, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *vfsShm) shmLock(offset, n int32, flags _ShmFlag) _ErrorCode {
|
func (s *vfsShm) shmLock(offset, n int32, flags _ShmFlag) error {
|
||||||
// Argument check.
|
// Argument check.
|
||||||
switch {
|
switch {
|
||||||
case n <= 0:
|
case n <= 0:
|
||||||
@@ -129,6 +132,10 @@ func (s *vfsShm) shmLock(offset, n int32, flags _ShmFlag) _ErrorCode {
|
|||||||
panic(util.AssertErr())
|
panic(util.AssertErr())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if s.File == nil {
|
||||||
|
return _IOERR_SHMLOCK
|
||||||
|
}
|
||||||
|
|
||||||
var timeout time.Duration
|
var timeout time.Duration
|
||||||
if s.blocking {
|
if s.blocking {
|
||||||
timeout = time.Millisecond
|
timeout = time.Millisecond
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ func (s *vfsShm) shmOpen() _ErrorCode {
|
|||||||
return rc
|
return rc
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *vfsShm) shmMap(ctx context.Context, mod api.Module, id, size int32, extend bool) (_ ptr_t, rc _ErrorCode) {
|
func (s *vfsShm) shmMap(ctx context.Context, mod api.Module, id, size int32, extend bool) (_ ptr_t, err error) {
|
||||||
// Ensure size is a multiple of the OS page size.
|
// Ensure size is a multiple of the OS page size.
|
||||||
if size != _WALINDEX_PGSZ || (windows.Getpagesize()-1)&_WALINDEX_PGSZ != 0 {
|
if size != _WALINDEX_PGSZ || (windows.Getpagesize()-1)&_WALINDEX_PGSZ != 0 {
|
||||||
return 0, _IOERR_SHMMAP
|
return 0, _IOERR_SHMMAP
|
||||||
@@ -79,19 +79,19 @@ func (s *vfsShm) shmMap(ctx context.Context, mod api.Module, id, size int32, ext
|
|||||||
return 0, rc
|
return 0, rc
|
||||||
}
|
}
|
||||||
|
|
||||||
defer s.shmAcquire(&rc)
|
defer s.shmAcquire(&err)
|
||||||
|
|
||||||
// Check if file is big enough.
|
// Check if file is big enough.
|
||||||
o, err := s.Seek(0, io.SeekEnd)
|
o, err := s.Seek(0, io.SeekEnd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, _IOERR_SHMSIZE
|
return 0, sysError{err, _IOERR_SHMSIZE}
|
||||||
}
|
}
|
||||||
if n := (int64(id) + 1) * int64(size); n > o {
|
if n := (int64(id) + 1) * int64(size); n > o {
|
||||||
if !extend {
|
if !extend {
|
||||||
return 0, _OK
|
return 0, nil
|
||||||
}
|
}
|
||||||
if osAllocate(s.File, n) != nil {
|
if err := osAllocate(s.File, n); err != nil {
|
||||||
return 0, _IOERR_SHMSIZE
|
return 0, sysError{err, _IOERR_SHMSIZE}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -99,7 +99,7 @@ func (s *vfsShm) shmMap(ctx context.Context, mod api.Module, id, size int32, ext
|
|||||||
for int(id) >= len(s.shared) {
|
for int(id) >= len(s.shared) {
|
||||||
r, err := util.MapRegion(ctx, mod, s.File, int64(id)*int64(size), size)
|
r, err := util.MapRegion(ctx, mod, s.File, int64(id)*int64(size), size)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, _IOERR_SHMMAP
|
return 0, err
|
||||||
}
|
}
|
||||||
s.regions = append(s.regions, r)
|
s.regions = append(s.regions, r)
|
||||||
s.shared = append(s.shared, r.Data)
|
s.shared = append(s.shared, r.Data)
|
||||||
@@ -124,13 +124,17 @@ func (s *vfsShm) shmMap(ctx context.Context, mod api.Module, id, size int32, ext
|
|||||||
}
|
}
|
||||||
|
|
||||||
s.shadow[0][4] = 1
|
s.shadow[0][4] = 1
|
||||||
return s.ptrs[id], _OK
|
return s.ptrs[id], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *vfsShm) shmLock(offset, n int32, flags _ShmFlag) (rc _ErrorCode) {
|
func (s *vfsShm) shmLock(offset, n int32, flags _ShmFlag) (err error) {
|
||||||
|
if s.File == nil {
|
||||||
|
return _IOERR_SHMLOCK
|
||||||
|
}
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case flags&_SHM_LOCK != 0:
|
case flags&_SHM_LOCK != 0:
|
||||||
defer s.shmAcquire(&rc)
|
defer s.shmAcquire(&err)
|
||||||
case flags&_SHM_EXCLUSIVE != 0:
|
case flags&_SHM_EXCLUSIVE != 0:
|
||||||
s.shmRelease()
|
s.shmRelease()
|
||||||
}
|
}
|
||||||
|
|||||||
90
vfs/vfs.go
90
vfs/vfs.go
@@ -102,7 +102,7 @@ func vfsFullPathname(ctx context.Context, mod api.Module, pVfs, zRelative ptr_t,
|
|||||||
}
|
}
|
||||||
util.WriteString(mod, zFull, path)
|
util.WriteString(mod, zFull, path)
|
||||||
|
|
||||||
return vfsErrorCode(err, _CANTOPEN_FULLPATH)
|
return vfsErrorCode(ctx, err, _CANTOPEN_FULLPATH)
|
||||||
}
|
}
|
||||||
|
|
||||||
func vfsDelete(ctx context.Context, mod api.Module, pVfs, zPath ptr_t, syncDir int32) _ErrorCode {
|
func vfsDelete(ctx context.Context, mod api.Module, pVfs, zPath ptr_t, syncDir int32) _ErrorCode {
|
||||||
@@ -110,7 +110,7 @@ func vfsDelete(ctx context.Context, mod api.Module, pVfs, zPath ptr_t, syncDir i
|
|||||||
path := util.ReadString(mod, zPath, _MAX_PATHNAME)
|
path := util.ReadString(mod, zPath, _MAX_PATHNAME)
|
||||||
|
|
||||||
err := vfs.Delete(path, syncDir != 0)
|
err := vfs.Delete(path, syncDir != 0)
|
||||||
return vfsErrorCode(err, _IOERR_DELETE)
|
return vfsErrorCode(ctx, err, _IOERR_DELETE)
|
||||||
}
|
}
|
||||||
|
|
||||||
func vfsAccess(ctx context.Context, mod api.Module, pVfs, zPath ptr_t, flags AccessFlag, pResOut ptr_t) _ErrorCode {
|
func vfsAccess(ctx context.Context, mod api.Module, pVfs, zPath ptr_t, flags AccessFlag, pResOut ptr_t) _ErrorCode {
|
||||||
@@ -119,7 +119,7 @@ func vfsAccess(ctx context.Context, mod api.Module, pVfs, zPath ptr_t, flags Acc
|
|||||||
|
|
||||||
ok, err := vfs.Access(path, flags)
|
ok, err := vfs.Access(path, flags)
|
||||||
util.WriteBool(mod, pResOut, ok)
|
util.WriteBool(mod, pResOut, ok)
|
||||||
return vfsErrorCode(err, _IOERR_ACCESS)
|
return vfsErrorCode(ctx, err, _IOERR_ACCESS)
|
||||||
}
|
}
|
||||||
|
|
||||||
func vfsOpen(ctx context.Context, mod api.Module, pVfs, zPath, pFile ptr_t, flags OpenFlag, pOutFlags, pOutVFS ptr_t) _ErrorCode {
|
func vfsOpen(ctx context.Context, mod api.Module, pVfs, zPath, pFile ptr_t, flags OpenFlag, pOutFlags, pOutVFS ptr_t) _ErrorCode {
|
||||||
@@ -134,7 +134,7 @@ func vfsOpen(ctx context.Context, mod api.Module, pVfs, zPath, pFile ptr_t, flag
|
|||||||
file, flags, err = vfs.Open(name.String(), flags)
|
file, flags, err = vfs.Open(name.String(), flags)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return vfsErrorCode(err, _CANTOPEN)
|
return vfsErrorCode(ctx, err, _CANTOPEN)
|
||||||
}
|
}
|
||||||
|
|
||||||
if file, ok := file.(FilePowersafeOverwrite); ok {
|
if file, ok := file.(FilePowersafeOverwrite); ok {
|
||||||
@@ -155,7 +155,7 @@ func vfsOpen(ctx context.Context, mod api.Module, pVfs, zPath, pFile ptr_t, flag
|
|||||||
|
|
||||||
func vfsClose(ctx context.Context, mod api.Module, pFile ptr_t) _ErrorCode {
|
func vfsClose(ctx context.Context, mod api.Module, pFile ptr_t) _ErrorCode {
|
||||||
err := vfsFileClose(ctx, mod, pFile)
|
err := vfsFileClose(ctx, mod, pFile)
|
||||||
return vfsErrorCode(err, _IOERR_CLOSE)
|
return vfsErrorCode(ctx, err, _IOERR_CLOSE)
|
||||||
}
|
}
|
||||||
|
|
||||||
func vfsRead(ctx context.Context, mod api.Module, pFile, zBuf ptr_t, iAmt int32, iOfst int64) _ErrorCode {
|
func vfsRead(ctx context.Context, mod api.Module, pFile, zBuf ptr_t, iAmt int32, iOfst int64) _ErrorCode {
|
||||||
@@ -167,7 +167,7 @@ func vfsRead(ctx context.Context, mod api.Module, pFile, zBuf ptr_t, iAmt int32,
|
|||||||
return _OK
|
return _OK
|
||||||
}
|
}
|
||||||
if err != io.EOF {
|
if err != io.EOF {
|
||||||
return vfsErrorCode(err, _IOERR_READ)
|
return vfsErrorCode(ctx, err, _IOERR_READ)
|
||||||
}
|
}
|
||||||
clear(buf[n:])
|
clear(buf[n:])
|
||||||
return _IOERR_SHORT_READ
|
return _IOERR_SHORT_READ
|
||||||
@@ -178,45 +178,45 @@ func vfsWrite(ctx context.Context, mod api.Module, pFile, zBuf ptr_t, iAmt int32
|
|||||||
buf := util.View(mod, zBuf, int64(iAmt))
|
buf := util.View(mod, zBuf, int64(iAmt))
|
||||||
|
|
||||||
_, err := file.WriteAt(buf, iOfst)
|
_, err := file.WriteAt(buf, iOfst)
|
||||||
return vfsErrorCode(err, _IOERR_WRITE)
|
return vfsErrorCode(ctx, err, _IOERR_WRITE)
|
||||||
}
|
}
|
||||||
|
|
||||||
func vfsTruncate(ctx context.Context, mod api.Module, pFile ptr_t, nByte int64) _ErrorCode {
|
func vfsTruncate(ctx context.Context, mod api.Module, pFile ptr_t, nByte int64) _ErrorCode {
|
||||||
file := vfsFileGet(ctx, mod, pFile).(File)
|
file := vfsFileGet(ctx, mod, pFile).(File)
|
||||||
err := file.Truncate(nByte)
|
err := file.Truncate(nByte)
|
||||||
return vfsErrorCode(err, _IOERR_TRUNCATE)
|
return vfsErrorCode(ctx, err, _IOERR_TRUNCATE)
|
||||||
}
|
}
|
||||||
|
|
||||||
func vfsSync(ctx context.Context, mod api.Module, pFile ptr_t, flags SyncFlag) _ErrorCode {
|
func vfsSync(ctx context.Context, mod api.Module, pFile ptr_t, flags SyncFlag) _ErrorCode {
|
||||||
file := vfsFileGet(ctx, mod, pFile).(File)
|
file := vfsFileGet(ctx, mod, pFile).(File)
|
||||||
err := file.Sync(flags)
|
err := file.Sync(flags)
|
||||||
return vfsErrorCode(err, _IOERR_FSYNC)
|
return vfsErrorCode(ctx, err, _IOERR_FSYNC)
|
||||||
}
|
}
|
||||||
|
|
||||||
func vfsFileSize(ctx context.Context, mod api.Module, pFile, pSize ptr_t) _ErrorCode {
|
func vfsFileSize(ctx context.Context, mod api.Module, pFile, pSize ptr_t) _ErrorCode {
|
||||||
file := vfsFileGet(ctx, mod, pFile).(File)
|
file := vfsFileGet(ctx, mod, pFile).(File)
|
||||||
size, err := file.Size()
|
size, err := file.Size()
|
||||||
util.Write64(mod, pSize, size)
|
util.Write64(mod, pSize, size)
|
||||||
return vfsErrorCode(err, _IOERR_SEEK)
|
return vfsErrorCode(ctx, err, _IOERR_SEEK)
|
||||||
}
|
}
|
||||||
|
|
||||||
func vfsLock(ctx context.Context, mod api.Module, pFile ptr_t, eLock LockLevel) _ErrorCode {
|
func vfsLock(ctx context.Context, mod api.Module, pFile ptr_t, eLock LockLevel) _ErrorCode {
|
||||||
file := vfsFileGet(ctx, mod, pFile).(File)
|
file := vfsFileGet(ctx, mod, pFile).(File)
|
||||||
err := file.Lock(eLock)
|
err := file.Lock(eLock)
|
||||||
return vfsErrorCode(err, _IOERR_LOCK)
|
return vfsErrorCode(ctx, err, _IOERR_LOCK)
|
||||||
}
|
}
|
||||||
|
|
||||||
func vfsUnlock(ctx context.Context, mod api.Module, pFile ptr_t, eLock LockLevel) _ErrorCode {
|
func vfsUnlock(ctx context.Context, mod api.Module, pFile ptr_t, eLock LockLevel) _ErrorCode {
|
||||||
file := vfsFileGet(ctx, mod, pFile).(File)
|
file := vfsFileGet(ctx, mod, pFile).(File)
|
||||||
err := file.Unlock(eLock)
|
err := file.Unlock(eLock)
|
||||||
return vfsErrorCode(err, _IOERR_UNLOCK)
|
return vfsErrorCode(ctx, err, _IOERR_UNLOCK)
|
||||||
}
|
}
|
||||||
|
|
||||||
func vfsCheckReservedLock(ctx context.Context, mod api.Module, pFile, pResOut ptr_t) _ErrorCode {
|
func vfsCheckReservedLock(ctx context.Context, mod api.Module, pFile, pResOut ptr_t) _ErrorCode {
|
||||||
file := vfsFileGet(ctx, mod, pFile).(File)
|
file := vfsFileGet(ctx, mod, pFile).(File)
|
||||||
locked, err := file.CheckReservedLock()
|
locked, err := file.CheckReservedLock()
|
||||||
util.WriteBool(mod, pResOut, locked)
|
util.WriteBool(mod, pResOut, locked)
|
||||||
return vfsErrorCode(err, _IOERR_CHECKRESERVEDLOCK)
|
return vfsErrorCode(ctx, err, _IOERR_CHECKRESERVEDLOCK)
|
||||||
}
|
}
|
||||||
|
|
||||||
func vfsFileControl(ctx context.Context, mod api.Module, pFile ptr_t, op _FcntlOpcode, pArg ptr_t) _ErrorCode {
|
func vfsFileControl(ctx context.Context, mod api.Module, pFile ptr_t, op _FcntlOpcode, pArg ptr_t) _ErrorCode {
|
||||||
@@ -268,20 +268,20 @@ func vfsFileControlImpl(ctx context.Context, mod api.Module, file File, op _Fcnt
|
|||||||
if file, ok := file.(FileSizeHint); ok {
|
if file, ok := file.(FileSizeHint); ok {
|
||||||
size := util.Read64[int64](mod, pArg)
|
size := util.Read64[int64](mod, pArg)
|
||||||
err := file.SizeHint(size)
|
err := file.SizeHint(size)
|
||||||
return vfsErrorCode(err, _IOERR_TRUNCATE)
|
return vfsErrorCode(ctx, err, _IOERR_TRUNCATE)
|
||||||
}
|
}
|
||||||
|
|
||||||
case _FCNTL_HAS_MOVED:
|
case _FCNTL_HAS_MOVED:
|
||||||
if file, ok := file.(FileHasMoved); ok {
|
if file, ok := file.(FileHasMoved); ok {
|
||||||
moved, err := file.HasMoved()
|
moved, err := file.HasMoved()
|
||||||
util.WriteBool(mod, pArg, moved)
|
util.WriteBool(mod, pArg, moved)
|
||||||
return vfsErrorCode(err, _IOERR_FSTAT)
|
return vfsErrorCode(ctx, err, _IOERR_FSTAT)
|
||||||
}
|
}
|
||||||
|
|
||||||
case _FCNTL_OVERWRITE:
|
case _FCNTL_OVERWRITE:
|
||||||
if file, ok := file.(FileOverwrite); ok {
|
if file, ok := file.(FileOverwrite); ok {
|
||||||
err := file.Overwrite()
|
err := file.Overwrite()
|
||||||
return vfsErrorCode(err, _IOERR)
|
return vfsErrorCode(ctx, err, _IOERR)
|
||||||
}
|
}
|
||||||
|
|
||||||
case _FCNTL_SYNC:
|
case _FCNTL_SYNC:
|
||||||
@@ -291,29 +291,29 @@ func vfsFileControlImpl(ctx context.Context, mod api.Module, file File, op _Fcnt
|
|||||||
name = util.ReadString(mod, pArg, _MAX_PATHNAME)
|
name = util.ReadString(mod, pArg, _MAX_PATHNAME)
|
||||||
}
|
}
|
||||||
err := file.SyncSuper(name)
|
err := file.SyncSuper(name)
|
||||||
return vfsErrorCode(err, _IOERR)
|
return vfsErrorCode(ctx, err, _IOERR)
|
||||||
}
|
}
|
||||||
|
|
||||||
case _FCNTL_COMMIT_PHASETWO:
|
case _FCNTL_COMMIT_PHASETWO:
|
||||||
if file, ok := file.(FileCommitPhaseTwo); ok {
|
if file, ok := file.(FileCommitPhaseTwo); ok {
|
||||||
err := file.CommitPhaseTwo()
|
err := file.CommitPhaseTwo()
|
||||||
return vfsErrorCode(err, _IOERR)
|
return vfsErrorCode(ctx, err, _IOERR)
|
||||||
}
|
}
|
||||||
|
|
||||||
case _FCNTL_BEGIN_ATOMIC_WRITE:
|
case _FCNTL_BEGIN_ATOMIC_WRITE:
|
||||||
if file, ok := file.(FileBatchAtomicWrite); ok {
|
if file, ok := file.(FileBatchAtomicWrite); ok {
|
||||||
err := file.BeginAtomicWrite()
|
err := file.BeginAtomicWrite()
|
||||||
return vfsErrorCode(err, _IOERR_BEGIN_ATOMIC)
|
return vfsErrorCode(ctx, err, _IOERR_BEGIN_ATOMIC)
|
||||||
}
|
}
|
||||||
case _FCNTL_COMMIT_ATOMIC_WRITE:
|
case _FCNTL_COMMIT_ATOMIC_WRITE:
|
||||||
if file, ok := file.(FileBatchAtomicWrite); ok {
|
if file, ok := file.(FileBatchAtomicWrite); ok {
|
||||||
err := file.CommitAtomicWrite()
|
err := file.CommitAtomicWrite()
|
||||||
return vfsErrorCode(err, _IOERR_COMMIT_ATOMIC)
|
return vfsErrorCode(ctx, err, _IOERR_COMMIT_ATOMIC)
|
||||||
}
|
}
|
||||||
case _FCNTL_ROLLBACK_ATOMIC_WRITE:
|
case _FCNTL_ROLLBACK_ATOMIC_WRITE:
|
||||||
if file, ok := file.(FileBatchAtomicWrite); ok {
|
if file, ok := file.(FileBatchAtomicWrite); ok {
|
||||||
err := file.RollbackAtomicWrite()
|
err := file.RollbackAtomicWrite()
|
||||||
return vfsErrorCode(err, _IOERR_ROLLBACK_ATOMIC)
|
return vfsErrorCode(ctx, err, _IOERR_ROLLBACK_ATOMIC)
|
||||||
}
|
}
|
||||||
|
|
||||||
case _FCNTL_CKPT_START:
|
case _FCNTL_CKPT_START:
|
||||||
@@ -338,7 +338,7 @@ func vfsFileControlImpl(ctx context.Context, mod api.Module, file File, op _Fcnt
|
|||||||
|
|
||||||
out, err := file.Pragma(strings.ToLower(name), value)
|
out, err := file.Pragma(strings.ToLower(name), value)
|
||||||
|
|
||||||
ret := vfsErrorCode(err, _ERROR)
|
ret := vfsErrorCode(ctx, err, _ERROR)
|
||||||
if ret == _ERROR {
|
if ret == _ERROR {
|
||||||
out = err.Error()
|
out = err.Error()
|
||||||
}
|
}
|
||||||
@@ -407,14 +407,15 @@ func vfsShmBarrier(ctx context.Context, mod api.Module, pFile ptr_t) {
|
|||||||
|
|
||||||
func vfsShmMap(ctx context.Context, mod api.Module, pFile ptr_t, iRegion, szRegion, bExtend int32, pp ptr_t) _ErrorCode {
|
func vfsShmMap(ctx context.Context, mod api.Module, pFile ptr_t, iRegion, szRegion, bExtend int32, pp ptr_t) _ErrorCode {
|
||||||
shm := vfsFileGet(ctx, mod, pFile).(FileSharedMemory).SharedMemory()
|
shm := vfsFileGet(ctx, mod, pFile).(FileSharedMemory).SharedMemory()
|
||||||
p, rc := shm.shmMap(ctx, mod, iRegion, szRegion, bExtend != 0)
|
p, err := shm.shmMap(ctx, mod, iRegion, szRegion, bExtend != 0)
|
||||||
util.Write32(mod, pp, p)
|
util.Write32(mod, pp, p)
|
||||||
return rc
|
return vfsErrorCode(ctx, err, _IOERR_SHMMAP)
|
||||||
}
|
}
|
||||||
|
|
||||||
func vfsShmLock(ctx context.Context, mod api.Module, pFile ptr_t, offset, n int32, flags _ShmFlag) _ErrorCode {
|
func vfsShmLock(ctx context.Context, mod api.Module, pFile ptr_t, offset, n int32, flags _ShmFlag) _ErrorCode {
|
||||||
shm := vfsFileGet(ctx, mod, pFile).(FileSharedMemory).SharedMemory()
|
shm := vfsFileGet(ctx, mod, pFile).(FileSharedMemory).SharedMemory()
|
||||||
return shm.shmLock(offset, n, flags)
|
err := shm.shmLock(offset, n, flags)
|
||||||
|
return vfsErrorCode(ctx, err, _IOERR_SHMLOCK)
|
||||||
}
|
}
|
||||||
|
|
||||||
func vfsShmUnmap(ctx context.Context, mod api.Module, pFile ptr_t, bDelete int32) _ErrorCode {
|
func vfsShmUnmap(ctx context.Context, mod api.Module, pFile ptr_t, bDelete int32) _ErrorCode {
|
||||||
@@ -454,13 +455,36 @@ func vfsFileClose(ctx context.Context, mod api.Module, pFile ptr_t) error {
|
|||||||
return util.DelHandle(ctx, id)
|
return util.DelHandle(ctx, id)
|
||||||
}
|
}
|
||||||
|
|
||||||
func vfsErrorCode(err error, def _ErrorCode) _ErrorCode {
|
func vfsErrorCode(ctx context.Context, err error, code _ErrorCode) _ErrorCode {
|
||||||
if err == nil {
|
var sys error
|
||||||
return _OK
|
|
||||||
|
switch err := err.(type) {
|
||||||
|
case nil:
|
||||||
|
code = _OK
|
||||||
|
case _ErrorCode:
|
||||||
|
code = err
|
||||||
|
case sysError:
|
||||||
|
code = err.code
|
||||||
|
sys = err.error
|
||||||
|
default:
|
||||||
|
switch v := reflect.ValueOf(err); v.Kind() {
|
||||||
|
case reflect.Uint8, reflect.Uint16:
|
||||||
|
code = _ErrorCode(v.Uint())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
switch v := reflect.ValueOf(err); v.Kind() {
|
|
||||||
case reflect.Uint8, reflect.Uint16, reflect.Uint32:
|
util.SetSystemError(ctx, sys)
|
||||||
return _ErrorCode(v.Uint())
|
return code
|
||||||
}
|
}
|
||||||
return def
|
|
||||||
|
func SystemError[T interface{ ~uint8 | ~uint16 }](err error, code T) error {
|
||||||
|
if err == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return sysError{error: err, code: _ErrorCode(code)}
|
||||||
|
}
|
||||||
|
|
||||||
|
type sysError struct {
|
||||||
|
error
|
||||||
|
code _ErrorCode
|
||||||
}
|
}
|
||||||
|
|||||||
48
vtab.go
48
vtab.go
@@ -465,19 +465,19 @@ func vtabModuleCallback(i vtabConstructor) func(_ context.Context, _ api.Module,
|
|||||||
vtabPutHandle(ctx, mod, ppVTab, val[0].Interface())
|
vtabPutHandle(ctx, mod, ppVTab, val[0].Interface())
|
||||||
}
|
}
|
||||||
|
|
||||||
return vtabError(ctx, mod, pzErr, _PTR_ERROR, err)
|
return vtabError(ctx, mod, pzErr, _PTR_ERROR, err, ERROR)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func vtabDisconnectCallback(ctx context.Context, mod api.Module, pVTab ptr_t) res_t {
|
func vtabDisconnectCallback(ctx context.Context, mod api.Module, pVTab ptr_t) res_t {
|
||||||
err := vtabDelHandle(ctx, mod, pVTab)
|
err := vtabDelHandle(ctx, mod, pVTab)
|
||||||
return vtabError(ctx, mod, 0, _PTR_ERROR, err)
|
return vtabError(ctx, mod, 0, _PTR_ERROR, err, ERROR)
|
||||||
}
|
}
|
||||||
|
|
||||||
func vtabDestroyCallback(ctx context.Context, mod api.Module, pVTab ptr_t) res_t {
|
func vtabDestroyCallback(ctx context.Context, mod api.Module, pVTab ptr_t) res_t {
|
||||||
vtab := vtabGetHandle(ctx, mod, pVTab).(VTabDestroyer)
|
vtab := vtabGetHandle(ctx, mod, pVTab).(VTabDestroyer)
|
||||||
err := errors.Join(vtab.Destroy(), vtabDelHandle(ctx, mod, pVTab))
|
err := errors.Join(vtab.Destroy(), vtabDelHandle(ctx, mod, pVTab))
|
||||||
return vtabError(ctx, mod, 0, _PTR_ERROR, err)
|
return vtabError(ctx, mod, 0, _PTR_ERROR, err, ERROR)
|
||||||
}
|
}
|
||||||
|
|
||||||
func vtabBestIndexCallback(ctx context.Context, mod api.Module, pVTab, pIdxInfo ptr_t) res_t {
|
func vtabBestIndexCallback(ctx context.Context, mod api.Module, pVTab, pIdxInfo ptr_t) res_t {
|
||||||
@@ -490,7 +490,7 @@ func vtabBestIndexCallback(ctx context.Context, mod api.Module, pVTab, pIdxInfo
|
|||||||
err := vtab.BestIndex(&info)
|
err := vtab.BestIndex(&info)
|
||||||
|
|
||||||
info.save()
|
info.save()
|
||||||
return vtabError(ctx, mod, pVTab, _VTAB_ERROR, err)
|
return vtabError(ctx, mod, pVTab, _VTAB_ERROR, err, ERROR)
|
||||||
}
|
}
|
||||||
|
|
||||||
func vtabUpdateCallback(ctx context.Context, mod api.Module, pVTab ptr_t, nArg int32, pArg, pRowID ptr_t) res_t {
|
func vtabUpdateCallback(ctx context.Context, mod api.Module, pVTab ptr_t, nArg int32, pArg, pRowID ptr_t) res_t {
|
||||||
@@ -504,13 +504,13 @@ func vtabUpdateCallback(ctx context.Context, mod api.Module, pVTab ptr_t, nArg i
|
|||||||
util.Write64(mod, pRowID, rowID)
|
util.Write64(mod, pRowID, rowID)
|
||||||
}
|
}
|
||||||
|
|
||||||
return vtabError(ctx, mod, pVTab, _VTAB_ERROR, err)
|
return vtabError(ctx, mod, pVTab, _VTAB_ERROR, err, ERROR)
|
||||||
}
|
}
|
||||||
|
|
||||||
func vtabRenameCallback(ctx context.Context, mod api.Module, pVTab, zNew ptr_t) res_t {
|
func vtabRenameCallback(ctx context.Context, mod api.Module, pVTab, zNew ptr_t) res_t {
|
||||||
vtab := vtabGetHandle(ctx, mod, pVTab).(VTabRenamer)
|
vtab := vtabGetHandle(ctx, mod, pVTab).(VTabRenamer)
|
||||||
err := vtab.Rename(util.ReadString(mod, zNew, _MAX_NAME))
|
err := vtab.Rename(util.ReadString(mod, zNew, _MAX_NAME))
|
||||||
return vtabError(ctx, mod, pVTab, _VTAB_ERROR, err)
|
return vtabError(ctx, mod, pVTab, _VTAB_ERROR, err, ERROR)
|
||||||
}
|
}
|
||||||
|
|
||||||
func vtabFindFuncCallback(ctx context.Context, mod api.Module, pVTab ptr_t, nArg int32, zName, pxFunc ptr_t) int32 {
|
func vtabFindFuncCallback(ctx context.Context, mod api.Module, pVTab ptr_t, nArg int32, zName, pxFunc ptr_t) int32 {
|
||||||
@@ -534,51 +534,49 @@ func vtabIntegrityCallback(ctx context.Context, mod api.Module, pVTab, zSchema,
|
|||||||
err := vtab.Integrity(schema, table, int(mFlags))
|
err := vtab.Integrity(schema, table, int(mFlags))
|
||||||
// xIntegrity should return OK - even if it finds problems in the content of the virtual table.
|
// xIntegrity should return OK - even if it finds problems in the content of the virtual table.
|
||||||
// https://sqlite.org/vtab.html#xintegrity
|
// https://sqlite.org/vtab.html#xintegrity
|
||||||
vtabError(ctx, mod, pzErr, _PTR_ERROR, err)
|
return vtabError(ctx, mod, pzErr, _PTR_ERROR, err, _OK)
|
||||||
_, code := errorCode(err, _OK)
|
|
||||||
return code
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func vtabBeginCallback(ctx context.Context, mod api.Module, pVTab ptr_t) res_t {
|
func vtabBeginCallback(ctx context.Context, mod api.Module, pVTab ptr_t) res_t {
|
||||||
vtab := vtabGetHandle(ctx, mod, pVTab).(VTabTxn)
|
vtab := vtabGetHandle(ctx, mod, pVTab).(VTabTxn)
|
||||||
err := vtab.Begin()
|
err := vtab.Begin()
|
||||||
return vtabError(ctx, mod, pVTab, _VTAB_ERROR, err)
|
return vtabError(ctx, mod, pVTab, _VTAB_ERROR, err, ERROR)
|
||||||
}
|
}
|
||||||
|
|
||||||
func vtabSyncCallback(ctx context.Context, mod api.Module, pVTab ptr_t) res_t {
|
func vtabSyncCallback(ctx context.Context, mod api.Module, pVTab ptr_t) res_t {
|
||||||
vtab := vtabGetHandle(ctx, mod, pVTab).(VTabTxn)
|
vtab := vtabGetHandle(ctx, mod, pVTab).(VTabTxn)
|
||||||
err := vtab.Sync()
|
err := vtab.Sync()
|
||||||
return vtabError(ctx, mod, pVTab, _VTAB_ERROR, err)
|
return vtabError(ctx, mod, pVTab, _VTAB_ERROR, err, ERROR)
|
||||||
}
|
}
|
||||||
|
|
||||||
func vtabCommitCallback(ctx context.Context, mod api.Module, pVTab ptr_t) res_t {
|
func vtabCommitCallback(ctx context.Context, mod api.Module, pVTab ptr_t) res_t {
|
||||||
vtab := vtabGetHandle(ctx, mod, pVTab).(VTabTxn)
|
vtab := vtabGetHandle(ctx, mod, pVTab).(VTabTxn)
|
||||||
err := vtab.Commit()
|
err := vtab.Commit()
|
||||||
return vtabError(ctx, mod, pVTab, _VTAB_ERROR, err)
|
return vtabError(ctx, mod, pVTab, _VTAB_ERROR, err, ERROR)
|
||||||
}
|
}
|
||||||
|
|
||||||
func vtabRollbackCallback(ctx context.Context, mod api.Module, pVTab ptr_t) res_t {
|
func vtabRollbackCallback(ctx context.Context, mod api.Module, pVTab ptr_t) res_t {
|
||||||
vtab := vtabGetHandle(ctx, mod, pVTab).(VTabTxn)
|
vtab := vtabGetHandle(ctx, mod, pVTab).(VTabTxn)
|
||||||
err := vtab.Rollback()
|
err := vtab.Rollback()
|
||||||
return vtabError(ctx, mod, pVTab, _VTAB_ERROR, err)
|
return vtabError(ctx, mod, pVTab, _VTAB_ERROR, err, ERROR)
|
||||||
}
|
}
|
||||||
|
|
||||||
func vtabSavepointCallback(ctx context.Context, mod api.Module, pVTab ptr_t, id int32) res_t {
|
func vtabSavepointCallback(ctx context.Context, mod api.Module, pVTab ptr_t, id int32) res_t {
|
||||||
vtab := vtabGetHandle(ctx, mod, pVTab).(VTabSavepointer)
|
vtab := vtabGetHandle(ctx, mod, pVTab).(VTabSavepointer)
|
||||||
err := vtab.Savepoint(int(id))
|
err := vtab.Savepoint(int(id))
|
||||||
return vtabError(ctx, mod, pVTab, _VTAB_ERROR, err)
|
return vtabError(ctx, mod, pVTab, _VTAB_ERROR, err, ERROR)
|
||||||
}
|
}
|
||||||
|
|
||||||
func vtabReleaseCallback(ctx context.Context, mod api.Module, pVTab ptr_t, id int32) res_t {
|
func vtabReleaseCallback(ctx context.Context, mod api.Module, pVTab ptr_t, id int32) res_t {
|
||||||
vtab := vtabGetHandle(ctx, mod, pVTab).(VTabSavepointer)
|
vtab := vtabGetHandle(ctx, mod, pVTab).(VTabSavepointer)
|
||||||
err := vtab.Release(int(id))
|
err := vtab.Release(int(id))
|
||||||
return vtabError(ctx, mod, pVTab, _VTAB_ERROR, err)
|
return vtabError(ctx, mod, pVTab, _VTAB_ERROR, err, ERROR)
|
||||||
}
|
}
|
||||||
|
|
||||||
func vtabRollbackToCallback(ctx context.Context, mod api.Module, pVTab ptr_t, id int32) res_t {
|
func vtabRollbackToCallback(ctx context.Context, mod api.Module, pVTab ptr_t, id int32) res_t {
|
||||||
vtab := vtabGetHandle(ctx, mod, pVTab).(VTabSavepointer)
|
vtab := vtabGetHandle(ctx, mod, pVTab).(VTabSavepointer)
|
||||||
err := vtab.RollbackTo(int(id))
|
err := vtab.RollbackTo(int(id))
|
||||||
return vtabError(ctx, mod, pVTab, _VTAB_ERROR, err)
|
return vtabError(ctx, mod, pVTab, _VTAB_ERROR, err, ERROR)
|
||||||
}
|
}
|
||||||
|
|
||||||
func cursorOpenCallback(ctx context.Context, mod api.Module, pVTab, ppCur ptr_t) res_t {
|
func cursorOpenCallback(ctx context.Context, mod api.Module, pVTab, ppCur ptr_t) res_t {
|
||||||
@@ -589,12 +587,12 @@ func cursorOpenCallback(ctx context.Context, mod api.Module, pVTab, ppCur ptr_t)
|
|||||||
vtabPutHandle(ctx, mod, ppCur, cursor)
|
vtabPutHandle(ctx, mod, ppCur, cursor)
|
||||||
}
|
}
|
||||||
|
|
||||||
return vtabError(ctx, mod, pVTab, _VTAB_ERROR, err)
|
return vtabError(ctx, mod, pVTab, _VTAB_ERROR, err, ERROR)
|
||||||
}
|
}
|
||||||
|
|
||||||
func cursorCloseCallback(ctx context.Context, mod api.Module, pCur ptr_t) res_t {
|
func cursorCloseCallback(ctx context.Context, mod api.Module, pCur ptr_t) res_t {
|
||||||
err := vtabDelHandle(ctx, mod, pCur)
|
err := vtabDelHandle(ctx, mod, pCur)
|
||||||
return vtabError(ctx, mod, 0, _VTAB_ERROR, err)
|
return vtabError(ctx, mod, 0, _PTR_ERROR, err, ERROR)
|
||||||
}
|
}
|
||||||
|
|
||||||
func cursorFilterCallback(ctx context.Context, mod api.Module, pCur ptr_t, idxNum int32, idxStr ptr_t, nArg int32, pArg ptr_t) res_t {
|
func cursorFilterCallback(ctx context.Context, mod api.Module, pCur ptr_t, idxNum int32, idxStr ptr_t, nArg int32, pArg ptr_t) res_t {
|
||||||
@@ -609,7 +607,7 @@ func cursorFilterCallback(ctx context.Context, mod api.Module, pCur ptr_t, idxNu
|
|||||||
|
|
||||||
cursor := vtabGetHandle(ctx, mod, pCur).(VTabCursor)
|
cursor := vtabGetHandle(ctx, mod, pCur).(VTabCursor)
|
||||||
err := cursor.Filter(int(idxNum), idxName, *args...)
|
err := cursor.Filter(int(idxNum), idxName, *args...)
|
||||||
return vtabError(ctx, mod, pCur, _CURSOR_ERROR, err)
|
return vtabError(ctx, mod, pCur, _CURSOR_ERROR, err, ERROR)
|
||||||
}
|
}
|
||||||
|
|
||||||
func cursorEOFCallback(ctx context.Context, mod api.Module, pCur ptr_t) int32 {
|
func cursorEOFCallback(ctx context.Context, mod api.Module, pCur ptr_t) int32 {
|
||||||
@@ -623,14 +621,14 @@ func cursorEOFCallback(ctx context.Context, mod api.Module, pCur ptr_t) int32 {
|
|||||||
func cursorNextCallback(ctx context.Context, mod api.Module, pCur ptr_t) res_t {
|
func cursorNextCallback(ctx context.Context, mod api.Module, pCur ptr_t) res_t {
|
||||||
cursor := vtabGetHandle(ctx, mod, pCur).(VTabCursor)
|
cursor := vtabGetHandle(ctx, mod, pCur).(VTabCursor)
|
||||||
err := cursor.Next()
|
err := cursor.Next()
|
||||||
return vtabError(ctx, mod, pCur, _CURSOR_ERROR, err)
|
return vtabError(ctx, mod, pCur, _CURSOR_ERROR, err, ERROR)
|
||||||
}
|
}
|
||||||
|
|
||||||
func cursorColumnCallback(ctx context.Context, mod api.Module, pCur, pCtx ptr_t, n int32) res_t {
|
func cursorColumnCallback(ctx context.Context, mod api.Module, pCur, pCtx ptr_t, n int32) res_t {
|
||||||
cursor := vtabGetHandle(ctx, mod, pCur).(VTabCursor)
|
cursor := vtabGetHandle(ctx, mod, pCur).(VTabCursor)
|
||||||
db := ctx.Value(connKey{}).(*Conn)
|
db := ctx.Value(connKey{}).(*Conn)
|
||||||
err := cursor.Column(Context{db, pCtx}, int(n))
|
err := cursor.Column(Context{db, pCtx}, int(n))
|
||||||
return vtabError(ctx, mod, pCur, _CURSOR_ERROR, err)
|
return vtabError(ctx, mod, pCur, _CURSOR_ERROR, err, ERROR)
|
||||||
}
|
}
|
||||||
|
|
||||||
func cursorRowIDCallback(ctx context.Context, mod api.Module, pCur, pRowID ptr_t) res_t {
|
func cursorRowIDCallback(ctx context.Context, mod api.Module, pCur, pRowID ptr_t) res_t {
|
||||||
@@ -641,7 +639,7 @@ func cursorRowIDCallback(ctx context.Context, mod api.Module, pCur, pRowID ptr_t
|
|||||||
util.Write64(mod, pRowID, rowID)
|
util.Write64(mod, pRowID, rowID)
|
||||||
}
|
}
|
||||||
|
|
||||||
return vtabError(ctx, mod, pCur, _CURSOR_ERROR, err)
|
return vtabError(ctx, mod, pCur, _CURSOR_ERROR, err, ERROR)
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -650,10 +648,10 @@ const (
|
|||||||
_CURSOR_ERROR
|
_CURSOR_ERROR
|
||||||
)
|
)
|
||||||
|
|
||||||
func vtabError(ctx context.Context, mod api.Module, ptr ptr_t, kind uint32, err error) res_t {
|
func vtabError(ctx context.Context, mod api.Module, ptr ptr_t, kind uint32, err error, def ErrorCode) res_t {
|
||||||
const zErrMsgOffset = 8
|
const zErrMsgOffset = 8
|
||||||
msg, code := errorCode(err, ERROR)
|
msg, code := errorCode(err, def)
|
||||||
if msg != "" && ptr != 0 {
|
if ptr != 0 && msg != "" {
|
||||||
switch kind {
|
switch kind {
|
||||||
case _VTAB_ERROR:
|
case _VTAB_ERROR:
|
||||||
ptr = ptr + zErrMsgOffset // zErrMsg
|
ptr = ptr + zErrMsgOffset // zErrMsg
|
||||||
|
|||||||
Reference in New Issue
Block a user