Files
sqlite3/.github/coverage.html
Nuno Cruces 606163010a More tests.
2023-01-26 12:15:34 +00:00

1717 lines
65 KiB
HTML

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>go-sqlite3: Go Coverage Report</title>
<style>
body {
background: black;
color: rgb(80, 80, 80);
}
body, pre, #legend span {
font-family: Menlo, monospace;
font-weight: bold;
}
#topbar {
background: black;
position: fixed;
top: 0; left: 0; right: 0;
height: 42px;
border-bottom: 1px solid rgb(80, 80, 80);
}
#content {
margin-top: 50px;
}
#nav, #legend {
float: left;
margin-left: 10px;
}
#legend {
margin-top: 12px;
}
#nav {
margin-top: 10px;
}
#legend span {
margin: 0 5px;
}
.cov0 { color: rgb(192, 0, 0) }
.cov1 { color: rgb(128, 128, 128) }
.cov2 { color: rgb(116, 140, 131) }
.cov3 { color: rgb(104, 152, 134) }
.cov4 { color: rgb(92, 164, 137) }
.cov5 { color: rgb(80, 176, 140) }
.cov6 { color: rgb(68, 188, 143) }
.cov7 { color: rgb(56, 200, 146) }
.cov8 { color: rgb(44, 212, 149) }
.cov9 { color: rgb(32, 224, 152) }
.cov10 { color: rgb(20, 236, 155) }
</style>
</head>
<body>
<div id="topbar">
<div id="nav">
<select id="files">
<option value="file0">github.com/ncruces/go-sqlite3/api.go (73.3%)</option>
<option value="file1">github.com/ncruces/go-sqlite3/compile.go (54.5%)</option>
<option value="file2">github.com/ncruces/go-sqlite3/conn.go (86.8%)</option>
<option value="file3">github.com/ncruces/go-sqlite3/error.go (54.5%)</option>
<option value="file4">github.com/ncruces/go-sqlite3/stmt.go (27.2%)</option>
<option value="file5">github.com/ncruces/go-sqlite3/vfs.go (74.7%)</option>
<option value="file6">github.com/ncruces/go-sqlite3/vfs_files.go (70.6%)</option>
<option value="file7">github.com/ncruces/go-sqlite3/vfs_lock.go (51.6%)</option>
<option value="file8">github.com/ncruces/go-sqlite3/vfs_lock_noop.go (0.0%)</option>
<option value="file9">github.com/ncruces/go-sqlite3/vfs_unix.go (54.3%)</option>
</select>
</div>
<div id="legend">
<span>not tracked</span>
<span class="cov0">not covered</span>
<span class="cov8">covered</span>
</div>
</div>
<div id="content">
<pre class="file" id="file0" style="display: none">package sqlite3
import "github.com/tetratelabs/wazero/api"
func newConn(module api.Module) *Conn <span class="cov8" title="1">{
getFun := func(name string) api.Function </span><span class="cov8" title="1">{
f := module.ExportedFunction(name)
if f == nil </span><span class="cov0" title="0">{
panic(noFuncErr + errorString(name))</span>
}
<span class="cov8" title="1">return f</span>
}
<span class="cov8" title="1">global := module.ExportedGlobal("malloc_destructor")
if global == nil </span><span class="cov0" title="0">{
panic(noGlobalErr + "malloc_destructor")</span>
}
<span class="cov8" title="1">destructor := uint32(global.Get())
if destructor == 0 </span><span class="cov0" title="0">{
panic(noGlobalErr + "malloc_destructor")</span>
}
<span class="cov8" title="1">destructor, ok := module.Memory().ReadUint32Le(destructor)
if !ok </span><span class="cov0" title="0">{
panic(noGlobalErr + "malloc_destructor")</span>
}
<span class="cov8" title="1">return &amp;Conn{
module: module,
memory: module.Memory(),
api: sqliteAPI{
malloc: getFun("malloc"),
free: getFun("free"),
destructor: uint64(destructor),
errcode: getFun("sqlite3_errcode"),
errstr: getFun("sqlite3_errstr"),
errmsg: getFun("sqlite3_errmsg"),
erroff: getFun("sqlite3_error_offset"),
open: getFun("sqlite3_open_v2"),
close: getFun("sqlite3_close"),
prepare: getFun("sqlite3_prepare_v3"),
finalize: getFun("sqlite3_finalize"),
reset: getFun("sqlite3_reset"),
step: getFun("sqlite3_step"),
exec: getFun("sqlite3_exec"),
clearBindings: getFun("sqlite3_clear_bindings"),
bindInteger: getFun("sqlite3_bind_int64"),
bindFloat: getFun("sqlite3_bind_double"),
bindText: getFun("sqlite3_bind_text64"),
bindBlob: getFun("sqlite3_bind_blob64"),
bindZeroBlob: getFun("sqlite3_bind_zeroblob64"),
bindNull: getFun("sqlite3_bind_null"),
columnInteger: getFun("sqlite3_column_int64"),
columnFloat: getFun("sqlite3_column_double"),
columnText: getFun("sqlite3_column_text"),
columnBlob: getFun("sqlite3_column_blob"),
columnBytes: getFun("sqlite3_column_bytes"),
columnType: getFun("sqlite3_column_type"),
},
}</span>
}
type sqliteAPI struct {
malloc api.Function
free api.Function
destructor uint64
errcode api.Function
errstr api.Function
errmsg api.Function
erroff api.Function
open api.Function
close api.Function
prepare api.Function
finalize api.Function
reset api.Function
step api.Function
exec api.Function
clearBindings api.Function
bindInteger api.Function
bindFloat api.Function
bindText api.Function
bindBlob api.Function
bindZeroBlob api.Function
bindNull api.Function
columnInteger api.Function
columnFloat api.Function
columnText api.Function
columnBlob api.Function
columnBytes api.Function
columnType api.Function
}
</pre>
<pre class="file" id="file1" style="display: none">package sqlite3
import (
"context"
"os"
"sync"
"sync/atomic"
"github.com/tetratelabs/wazero"
)
// Configure SQLite.
var (
Binary []byte // Binary to load.
Path string // Path to load the binary from.
)
var (
once sync.Once
wasm wazero.Runtime
module wazero.CompiledModule
counter atomic.Uint64
)
func compile() <span class="cov8" title="1">{
ctx := context.Background()
wasm = wazero.NewRuntime(ctx)
if err := vfsInstantiate(ctx, wasm); err != nil </span><span class="cov0" title="0">{
panic(err)</span>
}
<span class="cov8" title="1">if Binary == nil &amp;&amp; Path != "" </span><span class="cov0" title="0">{
if bin, err := os.ReadFile(Path); err != nil </span><span class="cov0" title="0">{
panic(err)</span>
} else<span class="cov0" title="0"> {
Binary = bin
}</span>
}
<span class="cov8" title="1">if m, err := wasm.CompileModule(ctx, Binary); err != nil </span><span class="cov0" title="0">{
panic(err)</span>
} else<span class="cov8" title="1"> {
module = m
}</span>
}
</pre>
<pre class="file" id="file2" style="display: none">package sqlite3
import (
"bytes"
"context"
"math"
"strconv"
"github.com/tetratelabs/wazero"
"github.com/tetratelabs/wazero/api"
)
type Conn struct {
ctx context.Context
handle uint32
module api.Module
memory api.Memory
api sqliteAPI
}
func Open(filename string) (conn *Conn, err error) <span class="cov8" title="1">{
return OpenFlags(filename, OPEN_READWRITE|OPEN_CREATE)
}</span>
func OpenFlags(filename string, flags OpenFlag) (conn *Conn, err error) <span class="cov8" title="1">{
once.Do(compile)
ctx := context.Background()
cfg := wazero.NewModuleConfig().
WithName("sqlite3-" + strconv.FormatUint(counter.Add(1), 10))
module, err := wasm.InstantiateModule(ctx, module, cfg)
if err != nil </span><span class="cov0" title="0">{
return nil, err
}</span>
<span class="cov8" title="1">defer func() </span><span class="cov8" title="1">{
if conn == nil </span><span class="cov8" title="1">{
module.Close(ctx)
}</span>
}()
<span class="cov8" title="1">c := newConn(module)
c.ctx = context.Background()
namePtr := c.newString(filename)
connPtr := c.new(ptrlen)
defer c.free(namePtr)
defer c.free(connPtr)
r, err := c.api.open.Call(c.ctx, uint64(namePtr), uint64(connPtr), uint64(flags), 0)
if err != nil </span><span class="cov0" title="0">{
return nil, err
}</span>
<span class="cov8" title="1">c.handle, _ = c.memory.ReadUint32Le(connPtr)
if err := c.error(r[0]); err != nil </span><span class="cov8" title="1">{
return nil, err
}</span>
<span class="cov8" title="1">return c, nil</span>
}
func (c *Conn) Close() error <span class="cov8" title="1">{
r, err := c.api.close.Call(c.ctx, uint64(c.handle))
if err != nil </span><span class="cov8" title="1">{
return err
}</span>
<span class="cov8" title="1">if err := c.error(r[0]); err != nil </span><span class="cov0" title="0">{
return err
}</span>
<span class="cov8" title="1">return c.module.Close(c.ctx)</span>
}
func (c *Conn) Exec(sql string) error <span class="cov8" title="1">{
sqlPtr := c.newString(sql)
defer c.free(sqlPtr)
r, err := c.api.exec.Call(c.ctx, uint64(c.handle), uint64(sqlPtr), 0, 0, 0)
if err != nil </span><span class="cov0" title="0">{
return err
}</span>
<span class="cov8" title="1">return c.error(r[0])</span>
}
func (c *Conn) Prepare(sql string) (stmt *Stmt, tail string, err error) <span class="cov8" title="1">{
return c.PrepareFlags(sql, 0)
}</span>
func (c *Conn) PrepareFlags(sql string, flags PrepareFlag) (stmt *Stmt, tail string, err error) <span class="cov8" title="1">{
sqlPtr := c.newString(sql)
stmtPtr := c.new(ptrlen)
tailPtr := c.new(ptrlen)
defer c.free(sqlPtr)
defer c.free(stmtPtr)
defer c.free(tailPtr)
r, err := c.api.prepare.Call(c.ctx, uint64(c.handle),
uint64(sqlPtr), uint64(len(sql)+1), uint64(flags),
uint64(stmtPtr), uint64(tailPtr))
if err != nil </span><span class="cov0" title="0">{
return nil, "", err
}</span>
<span class="cov8" title="1">stmt = &amp;Stmt{c: c}
stmt.handle, _ = c.memory.ReadUint32Le(stmtPtr)
i, _ := c.memory.ReadUint32Le(tailPtr)
tail = sql[i-sqlPtr:]
if err := c.error(r[0]); err != nil </span><span class="cov0" title="0">{
return nil, "", err
}</span>
<span class="cov8" title="1">if stmt.handle == 0 </span><span class="cov0" title="0">{
return nil, "", nil
}</span>
<span class="cov8" title="1">return</span>
}
func (c *Conn) error(rc uint64) error <span class="cov8" title="1">{
if rc == _OK </span><span class="cov8" title="1">{
return nil
}</span>
<span class="cov8" title="1">err := Error{
Code: ErrorCode(rc),
ExtendedCode: ExtendedErrorCode(rc),
}
if err.Code == NOMEM || err.ExtendedCode == IOERR_NOMEM </span><span class="cov0" title="0">{
panic(oomErr)</span>
}
<span class="cov8" title="1">var r []uint64
// Do this first, sqlite3_errmsg is guaranteed to never change the value of the error code.
r, _ = c.api.errmsg.Call(c.ctx, uint64(c.handle))
if r != nil </span><span class="cov8" title="1">{
err.msg = c.getString(uint32(r[0]), 512)
}</span>
<span class="cov8" title="1">r, _ = c.api.errstr.Call(c.ctx, rc)
if r != nil </span><span class="cov8" title="1">{
err.str = c.getString(uint32(r[0]), 512)
}</span>
<span class="cov8" title="1">if err.msg == err.str </span><span class="cov8" title="1">{
err.msg = ""
}</span>
<span class="cov8" title="1">return &amp;err</span>
}
func (c *Conn) free(ptr uint32) <span class="cov8" title="1">{
if ptr == 0 </span><span class="cov8" title="1">{
return
}</span>
<span class="cov8" title="1">_, err := c.api.free.Call(c.ctx, uint64(ptr))
if err != nil </span><span class="cov0" title="0">{
panic(err)</span>
}
}
func (c *Conn) new(len uint32) uint32 <span class="cov8" title="1">{
r, err := c.api.malloc.Call(c.ctx, uint64(len))
if err != nil </span><span class="cov0" title="0">{
panic(err)</span>
}
<span class="cov8" title="1">ptr := uint32(r[0])
if ptr == 0 || ptr &gt;= c.memory.Size() </span><span class="cov8" title="1">{
panic(oomErr)</span>
}
<span class="cov8" title="1">return ptr</span>
}
func (c *Conn) newBytes(s []byte) uint32 <span class="cov8" title="1">{
if s == nil </span><span class="cov8" title="1">{
return 0
}</span>
<span class="cov8" title="1">siz := uint32(len(s))
ptr := c.new(siz)
mem, ok := c.memory.Read(ptr, siz)
if !ok </span><span class="cov0" title="0">{
c.api.free.Call(c.ctx, uint64(ptr))
panic(rangeErr)</span>
}
<span class="cov8" title="1">copy(mem, s)
return ptr</span>
}
func (c *Conn) newString(s string) uint32 <span class="cov8" title="1">{
siz := uint32(len(s) + 1)
ptr := c.new(siz)
mem, ok := c.memory.Read(ptr, siz)
if !ok </span><span class="cov0" title="0">{
c.api.free.Call(c.ctx, uint64(ptr))
panic(rangeErr)</span>
}
<span class="cov8" title="1">mem[len(s)] = 0
copy(mem, s)
return ptr</span>
}
func (c *Conn) getString(ptr, maxlen uint32) string <span class="cov8" title="1">{
return getString(c.memory, ptr, maxlen)
}</span>
func getString(memory api.Memory, ptr, maxlen uint32) string <span class="cov8" title="1">{
if ptr == 0 </span><span class="cov8" title="1">{
panic(nilErr)</span>
}
<span class="cov8" title="1">switch maxlen </span>{
case 0:<span class="cov8" title="1">
return ""</span>
case math.MaxUint32:<span class="cov8" title="1"></span>
//
default:<span class="cov8" title="1">
maxlen = maxlen + 1</span>
}
<span class="cov8" title="1">mem, ok := memory.Read(ptr, maxlen)
if !ok </span><span class="cov8" title="1">{
mem, ok = memory.Read(ptr, memory.Size()-ptr)
if !ok </span><span class="cov0" title="0">{
panic(rangeErr)</span>
}
}
<span class="cov8" title="1">if i := bytes.IndexByte(mem, 0); i &lt; 0 </span><span class="cov8" title="1">{
panic(noNulErr)</span>
} else<span class="cov8" title="1"> {
return string(mem[:i])
}</span>
}
</pre>
<pre class="file" id="file3" style="display: none">package sqlite3
import (
"strconv"
"strings"
)
type Error struct {
Code ErrorCode
ExtendedCode ExtendedErrorCode
str string
msg string
}
func (e *Error) Error() string <span class="cov8" title="1">{
var b strings.Builder
b.WriteString("sqlite3: ")
if e.str != "" </span><span class="cov8" title="1">{
b.WriteString(e.str)
}</span> else<span class="cov0" title="0"> {
b.WriteString(strconv.Itoa(int(e.Code)))
}</span>
<span class="cov8" title="1">if e.msg != "" </span><span class="cov0" title="0">{
b.WriteByte(':')
b.WriteByte(' ')
b.WriteString(e.msg)
}</span>
<span class="cov8" title="1">return b.String()</span>
}
type errorString string
func (e errorString) Error() string <span class="cov0" title="0">{ return string(e) }</span>
const (
nilErr = errorString("sqlite3: invalid memory address or null pointer dereference")
oomErr = errorString("sqlite3: out of memory")
rangeErr = errorString("sqlite3: index out of range")
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")
)
</pre>
<pre class="file" id="file4" style="display: none">package sqlite3
import (
"math"
)
type Stmt struct {
c *Conn
handle uint32
err error
}
func (s *Stmt) Close() error <span class="cov8" title="1">{
r, err := s.c.api.finalize.Call(s.c.ctx, uint64(s.handle))
if err != nil </span><span class="cov0" title="0">{
return err
}</span>
<span class="cov8" title="1">s.handle = 0
return s.c.error(r[0])</span>
}
func (s *Stmt) Reset() error <span class="cov0" title="0">{
r, err := s.c.api.reset.Call(s.c.ctx, uint64(s.handle))
if err != nil </span><span class="cov0" title="0">{
return err
}</span>
<span class="cov0" title="0">return s.c.error(r[0])</span>
}
func (s *Stmt) Step() bool <span class="cov8" title="1">{
r, err := s.c.api.step.Call(s.c.ctx, uint64(s.handle))
if err != nil </span><span class="cov0" title="0">{
s.err = err
return false
}</span>
<span class="cov8" title="1">if r[0] == _ROW </span><span class="cov8" title="1">{
return true
}</span>
<span class="cov8" title="1">if r[0] == _DONE </span><span class="cov8" title="1">{
s.err = nil
}</span> else<span class="cov0" title="0"> {
s.err = s.c.error(r[0])
}</span>
<span class="cov8" title="1">return false</span>
}
func (s *Stmt) Err() error <span class="cov8" title="1">{
return s.err
}</span>
func (s *Stmt) BindBool(param int, value bool) error <span class="cov0" title="0">{
if value </span><span class="cov0" title="0">{
return s.BindInt64(param, 1)
}</span>
<span class="cov0" title="0">return s.BindInt64(param, 0)</span>
}
func (s *Stmt) BindInt(param int, value int) error <span class="cov0" title="0">{
return s.BindInt64(param, int64(value))
}</span>
func (s *Stmt) BindInt64(param int, value int64) error <span class="cov0" title="0">{
r, err := s.c.api.bindInteger.Call(s.c.ctx,
uint64(s.handle), uint64(param), uint64(value))
if err != nil </span><span class="cov0" title="0">{
return err
}</span>
<span class="cov0" title="0">return s.c.error(r[0])</span>
}
func (s *Stmt) BindFloat(param int, value float64) error <span class="cov0" title="0">{
r, err := s.c.api.bindFloat.Call(s.c.ctx,
uint64(s.handle), uint64(param), math.Float64bits(value))
if err != nil </span><span class="cov0" title="0">{
return err
}</span>
<span class="cov0" title="0">return s.c.error(r[0])</span>
}
func (s *Stmt) BindText(param int, value string) error <span class="cov0" title="0">{
ptr := s.c.newString(value)
r, err := s.c.api.bindText.Call(s.c.ctx,
uint64(s.handle), uint64(param),
uint64(ptr), uint64(len(value)),
s.c.api.destructor, _UTF8)
if err != nil </span><span class="cov0" title="0">{
return err
}</span>
<span class="cov0" title="0">return s.c.error(r[0])</span>
}
func (s *Stmt) BindBlob(param int, value []byte) error <span class="cov0" title="0">{
ptr := s.c.newBytes(value)
r, err := s.c.api.bindBlob.Call(s.c.ctx,
uint64(s.handle), uint64(param),
uint64(ptr), uint64(len(value)),
s.c.api.destructor)
if err != nil </span><span class="cov0" title="0">{
return err
}</span>
<span class="cov0" title="0">return s.c.error(r[0])</span>
}
func (s *Stmt) BindNull(param int) error <span class="cov0" title="0">{
r, err := s.c.api.bindNull.Call(s.c.ctx,
uint64(s.handle), uint64(param))
if err != nil </span><span class="cov0" title="0">{
return err
}</span>
<span class="cov0" title="0">return s.c.error(r[0])</span>
}
func (s *Stmt) ColumnBool(col int) bool <span class="cov0" title="0">{
if i := s.ColumnInt64(col); i != 0 </span><span class="cov0" title="0">{
return true
}</span>
<span class="cov0" title="0">return false</span>
}
func (s *Stmt) ColumnInt(col int) int <span class="cov8" title="1">{
return int(s.ColumnInt64(col))
}</span>
func (s *Stmt) ColumnInt64(col int) int64 <span class="cov8" title="1">{
r, err := s.c.api.columnInteger.Call(s.c.ctx,
uint64(s.handle), uint64(col))
if err != nil </span><span class="cov0" title="0">{
panic(err)</span>
}
<span class="cov8" title="1">return int64(r[0])</span>
}
func (s *Stmt) ColumnFloat(col int) float64 <span class="cov0" title="0">{
r, err := s.c.api.columnInteger.Call(s.c.ctx,
uint64(s.handle), uint64(col))
if err != nil </span><span class="cov0" title="0">{
panic(err)</span>
}
<span class="cov0" title="0">return math.Float64frombits(r[0])</span>
}
func (s *Stmt) ColumnText(col int) string <span class="cov8" title="1">{
r, err := s.c.api.columnText.Call(s.c.ctx,
uint64(s.handle), uint64(col))
if err != nil </span><span class="cov0" title="0">{
panic(err)</span>
}
<span class="cov8" title="1">ptr := uint32(r[0])
if ptr == 0 </span><span class="cov0" title="0">{
r, err = s.c.api.errcode.Call(s.c.ctx, uint64(s.handle))
if err != nil </span><span class="cov0" title="0">{
panic(err)</span>
}
<span class="cov0" title="0">s.err = s.c.error(r[0])
return ""</span>
}
<span class="cov8" title="1">r, err = s.c.api.columnBytes.Call(s.c.ctx,
uint64(s.handle), uint64(col))
if err != nil </span><span class="cov0" title="0">{
panic(err)</span>
}
<span class="cov8" title="1">mem, ok := s.c.memory.Read(ptr, uint32(r[0]))
if !ok </span><span class="cov0" title="0">{
panic(rangeErr)</span>
}
<span class="cov8" title="1">return string(mem)</span>
}
func (s *Stmt) ColumnBlob(col int, buf []byte) []byte <span class="cov0" title="0">{
r, err := s.c.api.columnBlob.Call(s.c.ctx,
uint64(s.handle), uint64(col))
if err != nil </span><span class="cov0" title="0">{
panic(err)</span>
}
<span class="cov0" title="0">ptr := uint32(r[0])
if ptr == 0 </span><span class="cov0" title="0">{
r, err = s.c.api.errcode.Call(s.c.ctx, uint64(s.handle))
if err != nil </span><span class="cov0" title="0">{
panic(err)</span>
}
<span class="cov0" title="0">s.err = s.c.error(r[0])
return nil</span>
}
<span class="cov0" title="0">r, err = s.c.api.columnBytes.Call(s.c.ctx,
uint64(s.handle), uint64(col))
if err != nil </span><span class="cov0" title="0">{
panic(err)</span>
}
<span class="cov0" title="0">mem, ok := s.c.memory.Read(ptr, uint32(r[0]))
if !ok </span><span class="cov0" title="0">{
panic(rangeErr)</span>
}
<span class="cov0" title="0">return append(buf[0:0], mem...)</span>
}
</pre>
<pre class="file" id="file5" style="display: none">package sqlite3
import (
"context"
"errors"
"io"
"io/fs"
"math/rand"
"os"
"path/filepath"
"syscall"
"time"
"github.com/ncruces/julianday"
"github.com/tetratelabs/wazero"
"github.com/tetratelabs/wazero/api"
"github.com/tetratelabs/wazero/sys"
)
func vfsInstantiate(ctx context.Context, r wazero.Runtime) (err error) <span class="cov8" title="1">{
wasi := r.NewHostModuleBuilder("wasi_snapshot_preview1")
wasi.NewFunctionBuilder().WithFunc(vfsExit).Export("proc_exit")
_, err = wasi.Instantiate(ctx)
if err != nil </span><span class="cov0" title="0">{
return err
}</span>
<span class="cov8" title="1">env := r.NewHostModuleBuilder("env")
env.NewFunctionBuilder().WithFunc(vfsLocaltime).Export("go_localtime")
env.NewFunctionBuilder().WithFunc(vfsRandomness).Export("go_randomness")
env.NewFunctionBuilder().WithFunc(vfsSleep).Export("go_sleep")
env.NewFunctionBuilder().WithFunc(vfsCurrentTime).Export("go_current_time")
env.NewFunctionBuilder().WithFunc(vfsCurrentTime64).Export("go_current_time_64")
env.NewFunctionBuilder().WithFunc(vfsFullPathname).Export("go_full_pathname")
env.NewFunctionBuilder().WithFunc(vfsDelete).Export("go_delete")
env.NewFunctionBuilder().WithFunc(vfsAccess).Export("go_access")
env.NewFunctionBuilder().WithFunc(vfsOpen).Export("go_open")
env.NewFunctionBuilder().WithFunc(vfsClose).Export("go_close")
env.NewFunctionBuilder().WithFunc(vfsRead).Export("go_read")
env.NewFunctionBuilder().WithFunc(vfsWrite).Export("go_write")
env.NewFunctionBuilder().WithFunc(vfsTruncate).Export("go_truncate")
env.NewFunctionBuilder().WithFunc(vfsSync).Export("go_sync")
env.NewFunctionBuilder().WithFunc(vfsFileSize).Export("go_file_size")
env.NewFunctionBuilder().WithFunc(vfsLock).Export("go_lock")
env.NewFunctionBuilder().WithFunc(vfsUnlock).Export("go_unlock")
env.NewFunctionBuilder().WithFunc(vfsCheckReservedLock).Export("go_check_reserved_lock")
_, err = env.Instantiate(ctx)
return err</span>
}
func vfsExit(ctx context.Context, mod api.Module, exitCode uint32) <span class="cov0" title="0">{
// Ensure other callers see the exit code.
_ = mod.CloseWithExitCode(ctx, exitCode)
// Prevent any code from executing after this function.
panic(sys.NewExitError(mod.Name(), exitCode))</span>
}
func vfsLocaltime(ctx context.Context, mod api.Module, t uint64, pTm uint32) uint32 <span class="cov8" title="1">{
tm := time.Unix(int64(t), 0)
var isdst int
if tm.IsDST() </span><span class="cov0" title="0">{
isdst = 1
}</span>
<span class="cov8" title="1">if pTm == 0 </span><span class="cov0" title="0">{
panic(nilErr)</span>
}
// https://pubs.opengroup.org/onlinepubs/7908799/xsh/time.h.html
<span class="cov8" title="1">if mem := mod.Memory(); true &amp;&amp;
mem.WriteUint32Le(pTm+0*ptrlen, uint32(tm.Second())) &amp;&amp;
mem.WriteUint32Le(pTm+1*ptrlen, uint32(tm.Minute())) &amp;&amp;
mem.WriteUint32Le(pTm+2*ptrlen, uint32(tm.Hour())) &amp;&amp;
mem.WriteUint32Le(pTm+3*ptrlen, uint32(tm.Day())) &amp;&amp;
mem.WriteUint32Le(pTm+4*ptrlen, uint32(tm.Month()-time.January)) &amp;&amp;
mem.WriteUint32Le(pTm+5*ptrlen, uint32(tm.Year()-1900)) &amp;&amp;
mem.WriteUint32Le(pTm+6*ptrlen, uint32(tm.Weekday()-time.Sunday)) &amp;&amp;
mem.WriteUint32Le(pTm+7*ptrlen, uint32(tm.YearDay()-1)) &amp;&amp;
mem.WriteUint32Le(pTm+8*ptrlen, uint32(isdst)) </span><span class="cov8" title="1">{
return _OK
}</span>
<span class="cov0" title="0">panic(rangeErr)</span>
}
func vfsRandomness(ctx context.Context, mod api.Module, pVfs, nByte, zByte uint32) uint32 <span class="cov8" title="1">{
if zByte == 0 </span><span class="cov0" title="0">{
panic(nilErr)</span>
}
<span class="cov8" title="1">mem, ok := mod.Memory().Read(zByte, nByte)
if !ok </span><span class="cov0" title="0">{
panic(rangeErr)</span>
}
<span class="cov8" title="1">n, _ := rand.Read(mem)
return uint32(n)</span>
}
func vfsSleep(ctx context.Context, pVfs, nMicro uint32) uint32 <span class="cov8" title="1">{
time.Sleep(time.Duration(nMicro) * time.Microsecond)
return _OK
}</span>
func vfsCurrentTime(ctx context.Context, mod api.Module, pVfs, prNow uint32) uint32 <span class="cov8" title="1">{
day := julianday.Float(time.Now())
if prNow == 0 </span><span class="cov0" title="0">{
panic(nilErr)</span>
}
<span class="cov8" title="1">if ok := mod.Memory().WriteFloat64Le(prNow, day); !ok </span><span class="cov0" title="0">{
panic(rangeErr)</span>
}
<span class="cov8" title="1">return _OK</span>
}
func vfsCurrentTime64(ctx context.Context, mod api.Module, pVfs, piNow uint32) uint32 <span class="cov8" title="1">{
day, nsec := julianday.Date(time.Now())
msec := day*86_400_000 + nsec/1_000_000
if piNow == 0 </span><span class="cov0" title="0">{
panic(nilErr)</span>
}
<span class="cov8" title="1">if ok := mod.Memory().WriteUint64Le(piNow, uint64(msec)); !ok </span><span class="cov0" title="0">{
panic(rangeErr)</span>
}
<span class="cov8" title="1">return _OK</span>
}
func vfsFullPathname(ctx context.Context, mod api.Module, pVfs, zRelative, nFull, zFull uint32) uint32 <span class="cov8" title="1">{
rel := getString(mod.Memory(), zRelative, _MAX_PATHNAME)
abs, err := filepath.Abs(rel)
if err != nil </span><span class="cov0" title="0">{
return uint32(IOERR)
}</span>
// Consider either using [filepath.EvalSymlinks] to canonicalize the path (as the Unix VFS does).
// Or using [os.Readlink] to resolve a symbolic link (as the Unix VFS did).
// This might be buggy on Windows (the Windows VFS doesn't try).
<span class="cov8" title="1">siz := uint32(len(abs) + 1)
if siz &gt; nFull </span><span class="cov8" title="1">{
return uint32(CANTOPEN_FULLPATH)
}</span>
<span class="cov8" title="1">if zFull == 0 </span><span class="cov0" title="0">{
panic(nilErr)</span>
}
<span class="cov8" title="1">mem, ok := mod.Memory().Read(zFull, siz)
if !ok </span><span class="cov0" title="0">{
panic(rangeErr)</span>
}
<span class="cov8" title="1">mem[len(abs)] = 0
copy(mem, abs)
return _OK</span>
}
func vfsDelete(ctx context.Context, mod api.Module, pVfs, zPath, syncDir uint32) uint32 <span class="cov8" title="1">{
path := getString(mod.Memory(), zPath, _MAX_PATHNAME)
err := os.Remove(path)
if errors.Is(err, fs.ErrNotExist) </span><span class="cov0" title="0">{
return _OK
}</span>
<span class="cov8" title="1">if err != nil </span><span class="cov0" title="0">{
return uint32(IOERR_DELETE)
}</span>
<span class="cov8" title="1">if syncDir != 0 </span><span class="cov8" title="1">{
f, err := os.Open(filepath.Dir(path))
if err == nil </span><span class="cov8" title="1">{
err = f.Sync()
f.Close()
}</span>
<span class="cov8" title="1">if err != nil </span><span class="cov0" title="0">{
return uint32(IOERR_DELETE)
}</span>
}
<span class="cov8" title="1">return _OK</span>
}
func vfsAccess(ctx context.Context, mod api.Module, pVfs, zPath uint32, flags AccessFlag, pResOut uint32) uint32 <span class="cov8" title="1">{
// Consider using [syscall.Access] for [ACCESS_READWRITE]/[ACCESS_READ]
// (as the Unix VFS does).
path := getString(mod.Memory(), zPath, _MAX_PATHNAME)
fi, err := os.Stat(path)
var res uint32
switch </span>{
case flags == ACCESS_EXISTS:<span class="cov8" title="1">
switch </span>{
case err == nil:<span class="cov8" title="1">
res = 1</span>
case errors.Is(err, fs.ErrNotExist):<span class="cov8" title="1">
res = 0</span>
default:<span class="cov0" title="0">
return uint32(IOERR_ACCESS)</span>
}
case err == nil:<span class="cov8" title="1">
var want fs.FileMode = syscall.S_IRUSR
if flags == ACCESS_READWRITE </span><span class="cov8" title="1">{
want |= syscall.S_IWUSR
}</span>
<span class="cov8" title="1">if fi.IsDir() </span><span class="cov8" title="1">{
want |= syscall.S_IXUSR
}</span>
<span class="cov8" title="1">if fi.Mode()&amp;want == want </span><span class="cov8" title="1">{
res = 1
}</span> else<span class="cov0" title="0"> {
res = 0
}</span>
case errors.Is(err, fs.ErrPermission):<span class="cov0" title="0">
res = 0</span>
default:<span class="cov0" title="0">
return uint32(IOERR_ACCESS)</span>
}
<span class="cov8" title="1">if pResOut == 0 </span><span class="cov0" title="0">{
panic(nilErr)</span>
}
<span class="cov8" title="1">if ok := mod.Memory().WriteUint32Le(pResOut, res); !ok </span><span class="cov0" title="0">{
panic(rangeErr)</span>
}
<span class="cov8" title="1">return _OK</span>
}
func vfsOpen(ctx context.Context, mod api.Module, pVfs, zName, pFile uint32, flags OpenFlag, pOutFlags uint32) uint32 <span class="cov8" title="1">{
var oflags int
if flags&amp;OPEN_EXCLUSIVE != 0 </span><span class="cov0" title="0">{
oflags |= os.O_EXCL
}</span>
<span class="cov8" title="1">if flags&amp;OPEN_CREATE != 0 </span><span class="cov8" title="1">{
oflags |= os.O_CREATE
}</span>
<span class="cov8" title="1">if flags&amp;OPEN_READONLY != 0 </span><span class="cov0" title="0">{
oflags |= os.O_RDONLY
}</span>
<span class="cov8" title="1">if flags&amp;OPEN_READWRITE != 0 </span><span class="cov8" title="1">{
oflags |= os.O_RDWR
}</span>
<span class="cov8" title="1">var err error
var file *os.File
if zName == 0 </span><span class="cov0" title="0">{
file, err = os.CreateTemp("", "*.db")
}</span> else<span class="cov8" title="1"> {
name := getString(mod.Memory(), zName, _MAX_PATHNAME)
file, err = os.OpenFile(name, oflags, 0600)
}</span>
<span class="cov8" title="1">if err != nil </span><span class="cov8" title="1">{
return uint32(CANTOPEN)
}</span>
<span class="cov8" title="1">if flags&amp;OPEN_DELETEONCLOSE != 0 </span><span class="cov0" title="0">{
deleteOnClose(file)
}</span>
<span class="cov8" title="1">info, err := file.Stat()
if err != nil </span><span class="cov0" title="0">{
return uint32(CANTOPEN)
}</span>
<span class="cov8" title="1">if info.IsDir() </span><span class="cov0" title="0">{
return uint32(CANTOPEN_ISDIR)
}</span>
<span class="cov8" title="1">id := vfsGetOpenFileID(file, info)
vfsFilePtr{mod, pFile}.SetID(id).SetLock(_NO_LOCK)
if pOutFlags == 0 </span><span class="cov8" title="1">{
return _OK
}</span>
<span class="cov8" title="1">if ok := mod.Memory().WriteUint32Le(pOutFlags, uint32(flags)); !ok </span><span class="cov0" title="0">{
panic(rangeErr)</span>
}
<span class="cov8" title="1">return _OK</span>
}
func vfsClose(ctx context.Context, mod api.Module, pFile uint32) uint32 <span class="cov8" title="1">{
id := vfsFilePtr{mod, pFile}.ID()
err := vfsReleaseOpenFile(id)
if err != nil </span><span class="cov0" title="0">{
return uint32(IOERR_CLOSE)
}</span>
<span class="cov8" title="1">return _OK</span>
}
func vfsRead(ctx context.Context, mod api.Module, pFile, zBuf, iAmt uint32, iOfst uint64) uint32 <span class="cov8" title="1">{
if zBuf == 0 </span><span class="cov0" title="0">{
panic(nilErr)</span>
}
<span class="cov8" title="1">buf, ok := mod.Memory().Read(zBuf, iAmt)
if !ok </span><span class="cov0" title="0">{
panic(rangeErr)</span>
}
<span class="cov8" title="1">file := vfsFilePtr{mod, pFile}.OSFile()
n, err := file.ReadAt(buf, int64(iOfst))
if n == int(iAmt) </span><span class="cov0" title="0">{
return _OK
}</span>
<span class="cov8" title="1">if n == 0 &amp;&amp; err != io.EOF </span><span class="cov0" title="0">{
return uint32(IOERR_READ)
}</span>
<span class="cov8" title="1">for i := range buf[n:] </span><span class="cov8" title="1">{
buf[i] = 0
}</span>
<span class="cov8" title="1">return uint32(IOERR_SHORT_READ)</span>
}
func vfsWrite(ctx context.Context, mod api.Module, pFile, zBuf, iAmt uint32, iOfst uint64) uint32 <span class="cov8" title="1">{
if zBuf == 0 </span><span class="cov0" title="0">{
panic(nilErr)</span>
}
<span class="cov8" title="1">buf, ok := mod.Memory().Read(zBuf, iAmt)
if !ok </span><span class="cov0" title="0">{
panic(rangeErr)</span>
}
<span class="cov8" title="1">file := vfsFilePtr{mod, pFile}.OSFile()
_, err := file.WriteAt(buf, int64(iOfst))
if err != nil </span><span class="cov0" title="0">{
return uint32(IOERR_WRITE)
}</span>
<span class="cov8" title="1">return _OK</span>
}
func vfsTruncate(ctx context.Context, mod api.Module, pFile uint32, nByte uint64) uint32 <span class="cov0" title="0">{
file := vfsFilePtr{mod, pFile}.OSFile()
err := file.Truncate(int64(nByte))
if err != nil </span><span class="cov0" title="0">{
return uint32(IOERR_TRUNCATE)
}</span>
<span class="cov0" title="0">return _OK</span>
}
func vfsSync(ctx context.Context, mod api.Module, pFile, flags uint32) uint32 <span class="cov8" title="1">{
file := vfsFilePtr{mod, pFile}.OSFile()
err := file.Sync()
if err != nil </span><span class="cov0" title="0">{
return uint32(IOERR_FSYNC)
}</span>
<span class="cov8" title="1">return _OK</span>
}
func vfsFileSize(ctx context.Context, mod api.Module, pFile, pSize uint32) uint32 <span class="cov8" title="1">{
// 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).
file := vfsFilePtr{mod, pFile}.OSFile()
off, err := file.Seek(0, io.SeekEnd)
if err != nil </span><span class="cov0" title="0">{
return uint32(IOERR_SEEK)
}</span>
<span class="cov8" title="1">if pSize == 0 </span><span class="cov0" title="0">{
panic(nilErr)</span>
}
<span class="cov8" title="1">if ok := mod.Memory().WriteUint64Le(pSize, uint64(off)); !ok </span><span class="cov0" title="0">{
panic(rangeErr)</span>
}
<span class="cov8" title="1">return _OK</span>
}
</pre>
<pre class="file" id="file6" style="display: none">package sqlite3
import (
"os"
"sync"
"github.com/tetratelabs/wazero/api"
)
type vfsOpenFile struct {
file *os.File
info os.FileInfo
nref int
shared int
vfsLocker
}
var (
vfsOpenFiles []*vfsOpenFile
vfsOpenFilesMtx sync.Mutex
)
func vfsGetOpenFileID(file *os.File, info os.FileInfo) uint32 <span class="cov8" title="1">{
vfsOpenFilesMtx.Lock()
defer vfsOpenFilesMtx.Unlock()
// Reuse an already opened file.
for id, of := range vfsOpenFiles </span><span class="cov8" title="1">{
if of == nil </span><span class="cov0" title="0">{
continue</span>
}
<span class="cov8" title="1">if os.SameFile(info, of.info) </span><span class="cov0" title="0">{
of.nref++
_ = file.Close()
return uint32(id)
}</span>
}
<span class="cov8" title="1">of := &amp;vfsOpenFile{
file: file,
info: info,
nref: 1,
vfsLocker: &amp;vfsFileLocker{file, _NO_LOCK},
}
// Find an empty slot.
for id, ptr := range vfsOpenFiles </span><span class="cov8" title="1">{
if ptr == nil </span><span class="cov0" title="0">{
vfsOpenFiles[id] = of
return uint32(id)
}</span>
}
// Add a new slot.
<span class="cov8" title="1">id := len(vfsOpenFiles)
vfsOpenFiles = append(vfsOpenFiles, of)
return uint32(id)</span>
}
func vfsReleaseOpenFile(id uint32) error <span class="cov8" title="1">{
vfsOpenFilesMtx.Lock()
defer vfsOpenFilesMtx.Unlock()
of := vfsOpenFiles[id]
if of.nref--; of.nref &gt; 0 </span><span class="cov0" title="0">{
return nil
}</span>
<span class="cov8" title="1">err := of.file.Close()
vfsOpenFiles[id] = nil
return err</span>
}
type vfsFilePtr struct {
api.Module
ptr uint32
}
func (p vfsFilePtr) OSFile() *os.File <span class="cov8" title="1">{
id := p.ID()
vfsOpenFilesMtx.Lock()
defer vfsOpenFilesMtx.Unlock()
return vfsOpenFiles[id].file
}</span>
func (p vfsFilePtr) ID() uint32 <span class="cov8" title="1">{
if p.ptr == 0 </span><span class="cov0" title="0">{
panic(nilErr)</span>
}
<span class="cov8" title="1">id, ok := p.Memory().ReadUint32Le(p.ptr + ptrlen)
if !ok </span><span class="cov0" title="0">{
panic(rangeErr)</span>
}
<span class="cov8" title="1">return id</span>
}
func (p vfsFilePtr) Lock() vfsLockState <span class="cov8" title="1">{
if p.ptr == 0 </span><span class="cov0" title="0">{
panic(nilErr)</span>
}
<span class="cov8" title="1">lk, ok := p.Memory().ReadUint32Le(p.ptr + 2*ptrlen)
if !ok </span><span class="cov0" title="0">{
panic(rangeErr)</span>
}
<span class="cov8" title="1">return vfsLockState(lk)</span>
}
func (p vfsFilePtr) SetID(id uint32) vfsFilePtr <span class="cov8" title="1">{
if p.ptr == 0 </span><span class="cov0" title="0">{
panic(nilErr)</span>
}
<span class="cov8" title="1">if ok := p.Memory().WriteUint32Le(p.ptr+ptrlen, id); !ok </span><span class="cov0" title="0">{
panic(rangeErr)</span>
}
<span class="cov8" title="1">return p</span>
}
func (p vfsFilePtr) SetLock(lock vfsLockState) vfsFilePtr <span class="cov8" title="1">{
if p.ptr == 0 </span><span class="cov0" title="0">{
panic(nilErr)</span>
}
<span class="cov8" title="1">if ok := p.Memory().WriteUint32Le(p.ptr+2*ptrlen, uint32(lock)); !ok </span><span class="cov0" title="0">{
panic(rangeErr)</span>
}
<span class="cov8" title="1">return p</span>
}
</pre>
<pre class="file" id="file7" style="display: none">package sqlite3
import (
"context"
"os"
"github.com/tetratelabs/wazero/api"
)
const (
// No locks are held on the database.
// The database may be neither read nor written.
// Any internally cached data is considered suspect and subject to
// verification against the database file before being used.
// Other processes can read or write the database as their own locking
// states permit.
// This is the default state.
_NO_LOCK = 0
// The database may be read but not written.
// Any number of processes can hold SHARED locks at the same time,
// hence there can be many simultaneous readers.
// But no other thread or process is allowed to write to the database file
// while one or more SHARED locks are active.
_SHARED_LOCK = 1
// A RESERVED lock means that the process is planning on writing to the
// database file at some point in the future but that it is currently just
// reading from the file.
// Only a single RESERVED lock may be active at one time,
// though multiple SHARED locks can coexist with a single RESERVED lock.
// RESERVED differs from PENDING in that new SHARED locks can be acquired
// while there is a RESERVED lock.
_RESERVED_LOCK = 2
// A PENDING lock means that the process holding the lock wants to write to
// the database as soon as possible and is just waiting on all current
// SHARED locks to clear so that it can get an EXCLUSIVE lock.
// No new SHARED locks are permitted against the database if a PENDING lock
// is active, though existing SHARED locks are allowed to continue.
_PENDING_LOCK = 3
// An EXCLUSIVE lock is needed in order to write to the database file.
// Only one EXCLUSIVE lock is allowed on the file and no other locks of any
// kind are allowed to coexist with an EXCLUSIVE lock.
// In order to maximize concurrency, SQLite works to minimize the amount of
// time that EXCLUSIVE locks are held.
_EXCLUSIVE_LOCK = 4
_PENDING_BYTE = 0x40000000
_RESERVED_BYTE = (_PENDING_BYTE + 1)
_SHARED_FIRST = (_PENDING_BYTE + 2)
_SHARED_SIZE = 510
)
type (
vfsLockState uint32
xErrorCode = ExtendedErrorCode
)
type vfsLocker interface {
LockState() vfsLockState
LockShared() xErrorCode // UNLOCKED -&gt; SHARED
LockReserved() xErrorCode // SHARED -&gt; RESERVED
LockPending() xErrorCode // SHARED|RESERVED -&gt; PENDING
LockExclusive() xErrorCode // PENDING -&gt; EXCLUSIVE
DowngradeLock() xErrorCode // SHARED &lt;- EXCLUSIVE|PENDING|RESERVED
Unlock() xErrorCode // UNLOCKED &lt;- EXCLUSIVE|PENDING|RESERVED|SHARED
CheckReservedLock() (bool, xErrorCode)
}
type vfsFileLocker struct {
*os.File
state vfsLockState
}
func vfsLock(ctx context.Context, mod api.Module, pFile uint32, eLock vfsLockState) uint32 <span class="cov8" title="1">{
if assert &amp;&amp; (eLock == _NO_LOCK || eLock == _PENDING_LOCK) </span><span class="cov0" title="0">{
panic(assertErr + " [d4oxww]")</span>
}
<span class="cov8" title="1">ptr := vfsFilePtr{mod, pFile}
cLock := ptr.Lock()
// If we already have an equal or more restrictive lock, do nothing.
if cLock &gt;= eLock </span><span class="cov0" title="0">{
return _OK
}</span>
<span class="cov8" title="1">if assert </span><span class="cov8" title="1">{
switch </span>{
case cLock == _NO_LOCK &amp;&amp; eLock &gt; _SHARED_LOCK:<span class="cov0" title="0">
// We never move from unlocked to anything higher than shared lock.
panic(assertErr + " [pfa77m]")</span>
case cLock != _SHARED_LOCK &amp;&amp; eLock == _RESERVED_LOCK:<span class="cov0" title="0">
// A shared lock is always held when a reserved lock is requested.
panic(assertErr + " [5cfmsp]")</span>
}
}
<span class="cov8" title="1">vfsOpenFilesMtx.Lock()
defer vfsOpenFilesMtx.Unlock()
of := vfsOpenFiles[ptr.ID()]
fLock := of.LockState()
// If some other connection has a lock that precludes the requested lock, return BUSY.
if cLock != fLock &amp;&amp; (eLock &gt; _SHARED_LOCK || fLock &gt;= _PENDING_LOCK) </span><span class="cov0" title="0">{
return uint32(BUSY)
}</span>
<span class="cov8" title="1">if eLock == _EXCLUSIVE_LOCK &amp;&amp; of.shared &gt; 1 </span><span class="cov0" title="0">{
// We are trying for an exclusive lock but another connection in this
// same process is still holding a shared lock.
return uint32(BUSY)
}</span>
// If a SHARED lock is requested, and some other connection has a SHARED or RESERVED lock,
// then increment the reference count and return OK.
<span class="cov8" title="1">if eLock == _SHARED_LOCK &amp;&amp; (fLock == _SHARED_LOCK || fLock == _RESERVED_LOCK) </span><span class="cov0" title="0">{
if assert &amp;&amp; !(cLock == _NO_LOCK &amp;&amp; of.shared &gt; 0) </span><span class="cov0" title="0">{
panic(assertErr + " [k7coz6]")</span>
}
<span class="cov0" title="0">ptr.SetLock(_SHARED_LOCK)
of.shared++
return _OK</span>
}
// If control gets to this point, then actually go ahead and make
// operating system calls for the specified lock.
<span class="cov8" title="1">switch eLock </span>{
case _SHARED_LOCK:<span class="cov8" title="1">
if assert &amp;&amp; !(fLock == _NO_LOCK &amp;&amp; of.shared == 0) </span><span class="cov0" title="0">{
panic(assertErr + " [jsyttq]")</span>
}
<span class="cov8" title="1">if rc := of.LockShared(); rc != _OK </span><span class="cov0" title="0">{
return uint32(rc)
}</span>
<span class="cov8" title="1">of.shared = 1
ptr.SetLock(_SHARED_LOCK)
return _OK</span>
case _RESERVED_LOCK:<span class="cov8" title="1">
if rc := of.LockReserved(); rc != _OK </span><span class="cov0" title="0">{
return uint32(rc)
}</span>
<span class="cov8" title="1">ptr.SetLock(_RESERVED_LOCK)
return _OK</span>
case _EXCLUSIVE_LOCK:<span class="cov8" title="1">
// A PENDING lock is needed before acquiring an EXCLUSIVE lock.
if cLock &lt; _PENDING_LOCK </span><span class="cov8" title="1">{
if rc := of.LockPending(); rc != _OK </span><span class="cov0" title="0">{
return uint32(rc)
}</span>
<span class="cov8" title="1">ptr.SetLock(_PENDING_LOCK)</span>
}
<span class="cov8" title="1">if rc := of.LockExclusive(); rc != _OK </span><span class="cov0" title="0">{
return uint32(rc)
}</span>
<span class="cov8" title="1">ptr.SetLock(_EXCLUSIVE_LOCK)
return _OK</span>
default:<span class="cov0" title="0">
panic(assertErr + " [56ng2l]")</span>
}
}
func vfsUnlock(ctx context.Context, mod api.Module, pFile uint32, eLock vfsLockState) uint32 <span class="cov8" title="1">{
if assert &amp;&amp; (eLock != _NO_LOCK &amp;&amp; eLock != _SHARED_LOCK) </span><span class="cov0" title="0">{
panic(assertErr + " [7i4jw3]")</span>
}
<span class="cov8" title="1">ptr := vfsFilePtr{mod, pFile}
cLock := ptr.Lock()
// If we don't have a more restrictive lock, do nothing.
if cLock &lt;= eLock </span><span class="cov0" title="0">{
return _OK
}</span>
<span class="cov8" title="1">vfsOpenFilesMtx.Lock()
defer vfsOpenFilesMtx.Unlock()
of := vfsOpenFiles[ptr.ID()]
fLock := of.LockState()
if assert &amp;&amp; of.shared &lt;= 0 </span><span class="cov0" title="0">{
panic(assertErr + " [2bhkwg]")</span>
}
<span class="cov8" title="1">if cLock &gt; _SHARED_LOCK </span><span class="cov8" title="1">{
if assert &amp;&amp; cLock != fLock </span><span class="cov0" title="0">{
panic(assertErr + " [6pmjqf]")</span>
}
<span class="cov8" title="1">if eLock == _SHARED_LOCK </span><span class="cov8" title="1">{
if rc := of.DowngradeLock(); rc != _OK </span><span class="cov0" title="0">{
// In theory, the downgrade to a SHARED cannot fail because another
// process is holding an incompatible lock. If it does, this
// indicates that the other process is not following the locking
// protocol. If this happens, return IOERR_RDLOCK. Returning
// BUSY would confuse the upper layer.
return uint32(IOERR_RDLOCK)
}</span>
<span class="cov8" title="1">ptr.SetLock(_SHARED_LOCK)
return _OK</span>
}
}
<span class="cov8" title="1">if assert &amp;&amp; eLock != _NO_LOCK </span><span class="cov0" title="0">{
panic(assertErr + " [gilo9p]")</span>
}
// Decrement the shared lock counter. Release the file lock
// only when all connections have released the lock.
<span class="cov8" title="1">switch </span>{
case of.shared &gt; 1:<span class="cov0" title="0">
ptr.SetLock(_NO_LOCK)
of.shared--
return _OK</span>
case of.shared == 1:<span class="cov8" title="1">
if rc := of.Unlock(); rc != _OK </span><span class="cov0" title="0">{
return uint32(IOERR_UNLOCK)
}</span>
<span class="cov8" title="1">ptr.SetLock(_NO_LOCK)
of.shared = 0
return _OK</span>
default:<span class="cov0" title="0">
panic(assertErr + " [50gw51]")</span>
}
}
func vfsCheckReservedLock(ctx context.Context, mod api.Module, pFile, pResOut uint32) uint32 <span class="cov0" title="0">{
ptr := vfsFilePtr{mod, pFile}
cLock := ptr.Lock()
if assert &amp;&amp; cLock &gt; _SHARED_LOCK </span><span class="cov0" title="0">{
panic(assertErr + " [zarygt]")</span>
}
<span class="cov0" title="0">vfsOpenFilesMtx.Lock()
defer vfsOpenFilesMtx.Unlock()
of := vfsOpenFiles[ptr.ID()]
locked, rc := of.CheckReservedLock()
if rc != _OK </span><span class="cov0" title="0">{
return uint32(IOERR_CHECKRESERVEDLOCK)
}</span>
<span class="cov0" title="0">var res uint32
if locked </span><span class="cov0" title="0">{
res = 1
}</span>
<span class="cov0" title="0">if pResOut == 0 </span><span class="cov0" title="0">{
panic(nilErr)</span>
}
<span class="cov0" title="0">if ok := mod.Memory().WriteUint32Le(pResOut, res); !ok </span><span class="cov0" title="0">{
panic(rangeErr)</span>
}
<span class="cov0" title="0">return _OK</span>
}
</pre>
<pre class="file" id="file8" style="display: none">package sqlite3
type vfsNoopLocker struct {
state vfsLockState
}
var _ vfsLocker = &amp;vfsNoopLocker{}
func (l *vfsNoopLocker) LockState() vfsLockState <span class="cov0" title="0">{
return l.state
}</span>
func (l *vfsNoopLocker) LockShared() xErrorCode <span class="cov0" title="0">{
if assert &amp;&amp; !(l.state == _NO_LOCK) </span><span class="cov0" title="0">{
panic(assertErr + " [wz9dcw]")</span>
}
<span class="cov0" title="0">l.state = _SHARED_LOCK
return _OK</span>
}
func (l *vfsNoopLocker) LockReserved() xErrorCode <span class="cov0" title="0">{
if assert &amp;&amp; !(l.state == _SHARED_LOCK) </span><span class="cov0" title="0">{
panic(assertErr + " [m9hcil]")</span>
}
<span class="cov0" title="0">l.state = _RESERVED_LOCK
return _OK</span>
}
func (l *vfsNoopLocker) LockPending() xErrorCode <span class="cov0" title="0">{
if assert &amp;&amp; !(l.state == _SHARED_LOCK || l.state == _RESERVED_LOCK) </span><span class="cov0" title="0">{
panic(assertErr + " [wx8nk2]")</span>
}
<span class="cov0" title="0">l.state = _PENDING_LOCK
return _OK</span>
}
func (l *vfsNoopLocker) LockExclusive() xErrorCode <span class="cov0" title="0">{
if assert &amp;&amp; !(l.state == _PENDING_LOCK) </span><span class="cov0" title="0">{
panic(assertErr + " [84nbax]")</span>
}
<span class="cov0" title="0">l.state = _EXCLUSIVE_LOCK
return _OK</span>
}
func (l *vfsNoopLocker) DowngradeLock() xErrorCode <span class="cov0" title="0">{
if assert &amp;&amp; !(l.state &gt; _SHARED_LOCK) </span><span class="cov0" title="0">{
panic(assertErr + " [je31i3]")</span>
}
<span class="cov0" title="0">l.state = _SHARED_LOCK
return _OK</span>
}
func (l *vfsNoopLocker) Unlock() xErrorCode <span class="cov0" title="0">{
if assert &amp;&amp; !(l.state &gt; _NO_LOCK) </span><span class="cov0" title="0">{
panic(assertErr + " [m6e9w5]")</span>
}
<span class="cov0" title="0">l.state = _NO_LOCK
return _OK</span>
}
func (l *vfsNoopLocker) CheckReservedLock() (bool, xErrorCode) <span class="cov0" title="0">{
if l.state &gt;= _RESERVED_LOCK </span><span class="cov0" title="0">{
return true, _OK
}</span>
<span class="cov0" title="0">return false, _OK</span>
}
</pre>
<pre class="file" id="file9" style="display: none">//go:build unix
package sqlite3
import (
"os"
"runtime"
"syscall"
)
func deleteOnClose(f *os.File) <span class="cov0" title="0">{
_ = os.Remove(f.Name())
}</span>
func (l *vfsFileLocker) LockState() vfsLockState <span class="cov8" title="1">{
return l.state
}</span>
func (l *vfsFileLocker) LockShared() xErrorCode <span class="cov8" title="1">{
// A PENDING lock is needed before acquiring a SHARED lock.
if !l.fcntlSetLock(&amp;syscall.Flock_t{
Type: syscall.F_RDLCK,
Start: _PENDING_BYTE,
Len: 1,
}) </span><span class="cov0" title="0">{
return IOERR_LOCK
}</span>
// Acquire the SHARED lock.
<span class="cov8" title="1">if !l.fcntlSetLock(&amp;syscall.Flock_t{
Type: syscall.F_RDLCK,
Start: _SHARED_FIRST,
Len: _SHARED_SIZE,
}) </span><span class="cov0" title="0">{
return IOERR_LOCK
}</span>
<span class="cov8" title="1">l.state = _SHARED_LOCK
// Relese the PENDING lock.
if !l.fcntlSetLock(&amp;syscall.Flock_t{
Type: syscall.F_UNLCK,
Start: _PENDING_BYTE,
Len: 1,
}) </span><span class="cov0" title="0">{
return IOERR_UNLOCK
}</span>
<span class="cov8" title="1">return _OK</span>
}
func (l *vfsFileLocker) LockReserved() xErrorCode <span class="cov8" title="1">{
// Acquire the RESERVED lock.
if !l.fcntlSetLock(&amp;syscall.Flock_t{
Type: syscall.F_WRLCK,
Start: _RESERVED_BYTE,
Len: 1,
}) </span><span class="cov0" title="0">{
return IOERR_LOCK
}</span>
<span class="cov8" title="1">l.state = _RESERVED_LOCK
return _OK</span>
}
func (l *vfsFileLocker) LockPending() xErrorCode <span class="cov8" title="1">{
// Acquire the PENDING lock.
if !l.fcntlSetLock(&amp;syscall.Flock_t{
Type: syscall.F_WRLCK,
Start: _PENDING_BYTE,
Len: 1,
}) </span><span class="cov0" title="0">{
return IOERR_LOCK
}</span>
<span class="cov8" title="1">l.state = _PENDING_LOCK
return _OK</span>
}
func (l *vfsFileLocker) LockExclusive() xErrorCode <span class="cov8" title="1">{
// Acquire the EXCLUSIVE lock.
if !l.fcntlSetLock(&amp;syscall.Flock_t{
Type: syscall.F_WRLCK,
Start: _SHARED_FIRST,
Len: _SHARED_SIZE,
}) </span><span class="cov0" title="0">{
return IOERR_LOCK
}</span>
<span class="cov8" title="1">l.state = _EXCLUSIVE_LOCK
return _OK</span>
}
func (l *vfsFileLocker) DowngradeLock() xErrorCode <span class="cov8" title="1">{
// Downgrade to a SHARED lock.
if !l.fcntlSetLock(&amp;syscall.Flock_t{
Type: syscall.F_RDLCK,
Start: _SHARED_FIRST,
Len: _SHARED_SIZE,
}) </span><span class="cov0" title="0">{
return IOERR_RDLOCK
}</span>
<span class="cov8" title="1">l.state = _SHARED_LOCK
// Release the PENDING and RESERVED locks.
if !l.fcntlSetLock(&amp;syscall.Flock_t{
Type: syscall.F_UNLCK,
Start: _PENDING_BYTE,
Len: 2,
}) </span><span class="cov0" title="0">{
return IOERR_UNLOCK
}</span>
<span class="cov8" title="1">return _OK</span>
}
func (l *vfsFileLocker) Unlock() xErrorCode <span class="cov8" title="1">{
// Release all locks.
if !l.fcntlSetLock(&amp;syscall.Flock_t{
Type: syscall.F_UNLCK,
}) </span><span class="cov0" title="0">{
return IOERR_UNLOCK
}</span>
<span class="cov8" title="1">l.state = _NO_LOCK
return _OK</span>
}
func (l *vfsFileLocker) CheckReservedLock() (bool, xErrorCode) <span class="cov0" title="0">{
if l.state &gt;= _RESERVED_LOCK </span><span class="cov0" title="0">{
return true, _OK
}</span>
// Test all write locks.
<span class="cov0" title="0">lock := syscall.Flock_t{
Type: syscall.F_RDLCK,
}
if !l.fcntlGetLock(&amp;lock) </span><span class="cov0" title="0">{
return false, IOERR_CHECKRESERVEDLOCK
}</span>
<span class="cov0" title="0">return lock.Type == syscall.F_UNLCK, _OK</span>
}
func (l *vfsFileLocker) fcntlGetLock(lock *syscall.Flock_t) bool <span class="cov0" title="0">{
F_GETLK := syscall.F_GETLK
if runtime.GOOS == "linux" </span><span class="cov0" title="0">{
F_GETLK = 36 // F_OFD_GETLK
}</span>
<span class="cov0" title="0">return syscall.FcntlFlock(l.Fd(), F_GETLK, lock) == nil</span>
}
func (l *vfsFileLocker) fcntlSetLock(lock *syscall.Flock_t) bool <span class="cov8" title="1">{
F_SETLK := syscall.F_SETLK
if runtime.GOOS == "linux" </span><span class="cov0" title="0">{
F_SETLK = 37 // F_OFD_SETLK
}</span>
<span class="cov8" title="1">return syscall.FcntlFlock(l.Fd(), F_SETLK, lock) == nil</span>
}
</pre>
</div>
</body>
<script>
(function() {
var files = document.getElementById('files');
var visible;
files.addEventListener('change', onChange, false);
function select(part) {
if (visible)
visible.style.display = 'none';
visible = document.getElementById(part);
if (!visible)
return;
files.value = part;
visible.style.display = 'block';
location.hash = part;
}
function onChange() {
select(files.value);
window.scrollTo(0, 0);
}
if (location.hash != "") {
select(location.hash.substr(1));
}
if (!visible) {
select("file0");
}
})();
</script>
</html>