Skip to content

Commit 0399f10

Browse files
committed
VFS improvements.
1 parent 75c6744 commit 0399f10

File tree

8 files changed

+171
-148
lines changed

8 files changed

+171
-148
lines changed

ext/serdes/serdes.go

Lines changed: 6 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,8 @@
22
package serdes
33

44
import (
5-
"io"
6-
75
"github.com/ncruces/go-sqlite3"
6+
"github.com/ncruces/go-sqlite3/util/vfsutil"
87
"github.com/ncruces/go-sqlite3/vfs"
98
)
109

@@ -14,16 +13,16 @@ func init() {
1413
vfs.Register(vfsName, sliceVFS{})
1514
}
1615

17-
var fileToOpen = make(chan *sliceFile, 1)
16+
var fileToOpen = make(chan *[]byte, 1)
1817

1918
// Serialize backs up a database into a byte slice.
2019
//
2120
// https://sqlite.org/c3ref/serialize.html
2221
func Serialize(db *sqlite3.Conn, schema string) ([]byte, error) {
23-
var file sliceFile
22+
var file []byte
2423
fileToOpen <- &file
2524
err := db.Backup(schema, "file:serdes.db?vfs="+vfsName)
26-
return file.data, err
25+
return file, err
2726
}
2827

2928
// Deserialize restores a database from a byte slice,
@@ -41,7 +40,7 @@ func Serialize(db *sqlite3.Conn, schema string) ([]byte, error) {
4140
// ["memdb"]: https://pkg.go.dev/github.com/ncruces/go-sqlite3/vfs/memdb
4241
// ["reader"]: https://pkg.go.dev/github.com/ncruces/go-sqlite3/vfs/readervfs
4342
func Deserialize(db *sqlite3.Conn, schema string, data []byte) error {
44-
fileToOpen <- &sliceFile{data}
43+
fileToOpen <- &data
4544
return db.Restore(schema, "file:serdes.db?vfs="+vfsName)
4645
}
4746

@@ -53,7 +52,7 @@ func (sliceVFS) Open(name string, flags vfs.OpenFlag) (vfs.File, vfs.OpenFlag, e
5352
}
5453
select {
5554
case file := <-fileToOpen:
56-
return file, flags | vfs.OPEN_MEMORY, nil
55+
return (*vfsutil.SliceFile)(file), flags | vfs.OPEN_MEMORY, nil
5756
default:
5857
return nil, flags, sqlite3.MISUSE
5958
}
@@ -71,70 +70,3 @@ func (sliceVFS) Access(name string, flag vfs.AccessFlag) (bool, error) {
7170
func (sliceVFS) FullPathname(name string) (string, error) {
7271
return name, nil
7372
}
74-
75-
type sliceFile struct{ data []byte }
76-
77-
func (f *sliceFile) ReadAt(b []byte, off int64) (n int, err error) {
78-
if d := f.data; off < int64(len(d)) {
79-
n = copy(b, d[off:])
80-
}
81-
if n == 0 {
82-
err = io.EOF
83-
}
84-
return
85-
}
86-
87-
func (f *sliceFile) WriteAt(b []byte, off int64) (n int, err error) {
88-
if d := f.data; off > int64(len(d)) {
89-
f.data = append(d, make([]byte, off-int64(len(d)))...)
90-
}
91-
d := append(f.data[:off], b...)
92-
if len(d) > len(f.data) {
93-
f.data = d
94-
}
95-
return len(b), nil
96-
}
97-
98-
func (f *sliceFile) Size() (int64, error) {
99-
return int64(len(f.data)), nil
100-
}
101-
102-
func (f *sliceFile) Truncate(size int64) error {
103-
if d := f.data; size < int64(len(d)) {
104-
f.data = d[:size]
105-
}
106-
return nil
107-
}
108-
109-
func (f *sliceFile) SizeHint(size int64) error {
110-
if d := f.data; size > int64(len(d)) {
111-
f.data = append(d, make([]byte, size-int64(len(d)))...)
112-
}
113-
return nil
114-
}
115-
116-
func (*sliceFile) Close() error { return nil }
117-
118-
func (*sliceFile) Sync(flag vfs.SyncFlag) error { return nil }
119-
120-
func (*sliceFile) Lock(lock vfs.LockLevel) error { return nil }
121-
122-
func (*sliceFile) Unlock(lock vfs.LockLevel) error { return nil }
123-
124-
func (*sliceFile) CheckReservedLock() (bool, error) {
125-
// notest // OPEN_MEMORY
126-
return false, nil
127-
}
128-
129-
func (*sliceFile) SectorSize() int {
130-
// notest // IOCAP_POWERSAFE_OVERWRITE
131-
return 0
132-
}
133-
134-
func (*sliceFile) DeviceCharacteristics() vfs.DeviceCharacteristic {
135-
return vfs.IOCAP_ATOMIC |
136-
vfs.IOCAP_SAFE_APPEND |
137-
vfs.IOCAP_SEQUENTIAL |
138-
vfs.IOCAP_POWERSAFE_OVERWRITE |
139-
vfs.IOCAP_SUBPAGE_READ
140-
}

util/vfsutil/slice.go

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
package vfsutil
2+
3+
import (
4+
"io"
5+
6+
"github.com/ncruces/go-sqlite3"
7+
"github.com/ncruces/go-sqlite3/vfs"
8+
)
9+
10+
// SliceFile implements [vfs.File] with a byte slice.
11+
// It is suitable for temporary files (such as [vfs.OPEN_TEMP_JOURNAL]),
12+
// but not concurrency safe.
13+
type SliceFile []byte
14+
15+
var (
16+
// Ensure these interfaces are implemented:
17+
_ vfs.FileSizeHint = &SliceFile{}
18+
)
19+
20+
// ReadAt implements [io.ReaderAt].
21+
func (f *SliceFile) ReadAt(b []byte, off int64) (n int, err error) {
22+
if d := *f; off < int64(len(d)) {
23+
n = copy(b, d[off:])
24+
}
25+
if n < len(b) {
26+
err = io.EOF
27+
}
28+
return
29+
}
30+
31+
// WriteAt implements [io.WriterAt].
32+
func (f *SliceFile) WriteAt(b []byte, off int64) (n int, err error) {
33+
d := *f
34+
if off > int64(len(d)) {
35+
d = append(d, make([]byte, off-int64(len(d)))...)
36+
}
37+
d = append(d[:off], b...)
38+
if len(d) > len(*f) {
39+
*f = d
40+
}
41+
return len(b), nil
42+
}
43+
44+
// Size implements [vfs.File].
45+
func (f *SliceFile) Size() (int64, error) {
46+
return int64(len(*f)), nil
47+
}
48+
49+
// Truncate implements [vfs.File].
50+
func (f *SliceFile) Truncate(size int64) error {
51+
if d := *f; size < int64(len(d)) {
52+
*f = d[:size]
53+
}
54+
return nil
55+
}
56+
57+
// SizeHint implements [vfs.FileSizeHint].
58+
func (f *SliceFile) SizeHint(size int64) error {
59+
if d := *f; size > int64(len(d)) {
60+
*f = append(d, make([]byte, size-int64(len(d)))...)
61+
}
62+
return nil
63+
}
64+
65+
// Close implements [io.Closer].
66+
func (*SliceFile) Close() error { return nil }
67+
68+
// Sync implements [vfs.File].
69+
func (*SliceFile) Sync(flags vfs.SyncFlag) error { return nil }
70+
71+
// Lock implements [vfs.File].
72+
func (*SliceFile) Lock(lock vfs.LockLevel) error { return nil }
73+
74+
// Unlock implements [vfs.File].
75+
func (*SliceFile) Unlock(lock vfs.LockLevel) error { return nil }
76+
77+
// CheckReservedLock implements [vfs.File].
78+
func (*SliceFile) CheckReservedLock() (bool, error) {
79+
// notest // OPEN_MEMORY
80+
return false, sqlite3.IOERR_CHECKRESERVEDLOCK
81+
}
82+
83+
// SectorSize implements [vfs.File].
84+
func (*SliceFile) SectorSize() int {
85+
// notest // IOCAP_POWERSAFE_OVERWRITE
86+
return 0
87+
}
88+
89+
// DeviceCharacteristics implements [vfs.File].
90+
func (*SliceFile) DeviceCharacteristics() vfs.DeviceCharacteristic {
91+
return vfs.IOCAP_ATOMIC |
92+
vfs.IOCAP_SEQUENTIAL |
93+
vfs.IOCAP_SAFE_APPEND |
94+
vfs.IOCAP_POWERSAFE_OVERWRITE |
95+
vfs.IOCAP_SUBPAGE_READ
96+
}

vfs/adiantum/hbsh.go

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -160,19 +160,18 @@ func (h *hbshFile) WriteAt(p []byte, off int64) (n int, err error) {
160160
if off > min || len(p[n:]) < blockSize {
161161
// Partial block write: read-update-write.
162162
m, err := h.File.ReadAt(h.block[:], min)
163-
if m != blockSize {
164-
if err != io.EOF {
165-
return n, err
166-
}
163+
if m == blockSize {
164+
data = h.hbsh.Decrypt(h.block[:], h.tweak[:])
165+
} else if err != io.EOF {
166+
return n, err
167+
} else {
167168
// Writing past the EOF.
168169
// We're either appending an entirely new block,
169170
// or the final block was only partially written.
170171
// A partially written block can't be decrypted,
171172
// and is as good as corrupt.
172173
// Either way, zero pad the file to the next block size.
173174
clear(data)
174-
} else {
175-
data = h.hbsh.Decrypt(h.block[:], h.tweak[:])
176175
}
177176
if off > min {
178177
data = data[off-min:]
@@ -223,16 +222,16 @@ func (h *hbshFile) SizeHint(size int64) error {
223222
return vfsutil.WrapSizeHint(h.File, roundUp(size))
224223
}
225224

225+
// Wrap optional methods.
226+
226227
func (h *hbshFile) Unwrap() vfs.File {
227-
return h.File
228+
return h.File // notest
228229
}
229230

230231
func (h *hbshFile) SharedMemory() vfs.SharedMemory {
231-
return vfsutil.WrapSharedMemory(h.File)
232+
return vfsutil.WrapSharedMemory(h.File) // notest
232233
}
233234

234-
// Wrap optional methods.
235-
236235
func (h *hbshFile) LockState() vfs.LockLevel {
237236
return vfsutil.WrapLockState(h.File) // notest
238237
}

vfs/api.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,9 @@ type VFSFilename interface {
3636
//
3737
// https://sqlite.org/c3ref/io_methods.html
3838
type File interface {
39-
Close() error
40-
ReadAt(p []byte, off int64) (n int, err error)
41-
WriteAt(p []byte, off int64) (n int, err error)
39+
io.Closer
40+
io.ReaderAt
41+
io.WriterAt
4242
Truncate(size int64) error
4343
Sync(flags SyncFlag) error
4444
Size() (int64, error)

0 commit comments

Comments
 (0)