Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP Add checksum VFS shim as an opt-in feature #1310

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions error.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ var (
ErrIoErrMMap = ErrIoErr.Extend(24)
ErrIoErrGetTempPath = ErrIoErr.Extend(25)
ErrIoErrConvPath = ErrIoErr.Extend(26)
ErrIoErrData = ErrIoErr.Extend(32)
ErrLockedSharedCache = ErrLocked.Extend(1)
ErrBusyRecovery = ErrBusy.Extend(1)
ErrBusySnapshot = ErrBusy.Extend(2)
Expand Down
9,311 changes: 6,503 additions & 2,808 deletions sqlite3-binding.c

Large diffs are not rendered by default.

202 changes: 180 additions & 22 deletions sqlite3-binding.h

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions sqlite3.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ package sqlite3
#cgo CFLAGS: -DSQLITE_OMIT_DEPRECATED
#cgo CFLAGS: -DSQLITE_DEFAULT_WAL_SYNCHRONOUS=1
#cgo CFLAGS: -DSQLITE_ENABLE_UPDATE_DELETE_LIMIT
#cgo CFLAGS: -DSQLITE_CKSUMVFS_STATIC
#cgo CFLAGS: -Wno-deprecated-declarations
#cgo openbsd CFLAGS: -I/usr/local/include
#cgo openbsd LDFLAGS: -L/usr/local/lib
Expand Down
11 changes: 11 additions & 0 deletions sqlite3_opt_cksumvfs.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
//go:build cksumvfs
// +build cksumvfs

package sqlite3

//extern int sqlite3_register_cksumvfs(const char*);
import "C"

func InitCksumVFS() {
C.sqlite3_register_cksumvfs(nil)
}
96 changes: 96 additions & 0 deletions sqlite3_opt_cksumvfs_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
//go:build cksumvfs
// +build cksumvfs

package sqlite3

import (
"testing"
"os"
"database/sql"
"io/ioutil"
"bytes"
"errors"
)

func TestCksumVfs(t *testing.T) {
tempFilename := TempFilename(t)
defer os.Remove(tempFilename)

sql.Register("sqlite3_with_reserved_bytes", &SQLiteDriver{
ConnectHook: func(conn *SQLiteConn) error {
return conn.SetFileControlInt("", SQLITE_FCNTL_RESERVE_BYTES, 8)
},
})

db, err := sql.Open("sqlite3_with_reserved_bytes", tempFilename)
if err != nil {
t.Fatal("Failed to open database:", err)
}

InitCksumVFS()

_, err = db.Exec(`create table foo (v string)`)
if err != nil {
t.Fatal("Failed to create table:", err)
}

stmt, err := db.Prepare("insert into foo(v) values(?)")
if err != nil {
t.Fatal("Failed to prepare insert:", err)
}

for _, v := range []string{"this-is-the-target-string", "foo", "bar", "baz"} {
_, err = stmt.Exec(v)
if err != nil {
t.Fatal("Failed to insert value:", err)
}
}

stmt.Close()
db.Close()

// Corrupt the file by replacing one of the column's values
data, err := ioutil.ReadFile(tempFilename)
if err != nil {
t.Fatal("Failed to read database file as bytes:", err)
}

newData := bytes.Replace(data, []byte("this-is-the-target-string"), []byte("This-is-the-target-string"), 1)
if err := ioutil.WriteFile(tempFilename, newData, 0); err != nil {
t.Fatal("Failed to write database file as new bytes:", err)
}

db, err = sql.Open("sqlite3_with_reserved_bytes", tempFilename)
if err != nil {
t.Fatal("Failed to open database:", err)
}

InitCksumVFS()

rows, err := db.Query("SELECT * FROM foo")
if err != nil {
t.Fatal("Failed to query database:", err)
}

for rows.Next() {
var s string
if err := rows.Scan(&s); err != nil {
t.Fatal("Failed to scan row:", err)
}
}

if err := rows.Close(); err != nil {
t.Fatal("Failed to close rows:", err)
}

err = rows.Err()

var sqliteErr Error
if !errors.As(err, &sqliteErr) {
t.Fatal("Failed to get close error as SQLite error:", err)
}

if sqliteErr.ExtendedCode != ErrIoErrData {
t.Fatal("Expected extended error of ERR_IO_ERR_DATA, but got:", int(sqliteErr.ExtendedCode))
}
}
34 changes: 27 additions & 7 deletions upgrade/upgrade.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,15 @@ import (
"os"
"path"
"path/filepath"
"regexp"
"strings"
"time"

"github.com/PuerkitoBio/goquery"
)

var includeRE = regexp.MustCompile(`^\s*#\s*include\s+"sqlite3.h"\s*$`)

func download(prefix string) (url string, content []byte, err error) {
year := time.Now().Year()

Expand Down Expand Up @@ -76,20 +79,32 @@ func mergeFile(src string, dst string) error {
}
defer fdst.Close()

// Read source content
content, err := ioutil.ReadFile(src)
if err != nil {
// Add Additional newline
if _, err := fdst.WriteString("\n"); err != nil {
return err
}

// Add Additional newline
if _, err := fdst.WriteString("\n"); err != nil {
fsrc, err := os.OpenFile(src, os.O_RDONLY, 0)
if err != nil {
return err
}
defer fsrc.Close()

fmt.Printf("Merging: %s into %s\n", src, dst)
if _, err = fdst.Write(content); err != nil {
return err
scanner := bufio.NewScanner(fsrc)
for scanner.Scan() {
text := scanner.Text()
if includeRE.Match([]byte(text)) {
text = `#include "sqlite3-binding.h"`
}
_, err = fmt.Fprintln(fdst, text)
if err != nil {
break
}
}
err = scanner.Err()
if err != nil {
log.Fatal(err)
}

return nil
Expand Down Expand Up @@ -198,6 +213,8 @@ func main() {
f, err = os.Create("../userauth.c")
case "sqlite3userauth.h":
f, err = os.Create("../userauth.h")
case "cksumvfs.c":
f, err = os.Create("../cksumvfs.c")
default:
continue
}
Expand Down Expand Up @@ -226,6 +243,9 @@ func main() {
if err := mergeFile("../userauth.h", "../sqlite3-binding.h"); err != nil {
log.Fatal(err)
}
if err := mergeFile("../cksumvfs.c", "../sqlite3-binding.c"); err != nil {
log.Fatal(err)
}

os.Exit(0)
}