diff --git a/mem.go b/mem.go index 9cf76a5..7fb6fa2 100644 --- a/mem.go +++ b/mem.go @@ -88,6 +88,22 @@ func (m memory) writeUint64(ptr uint32, v uint64) { } } +func (m memory) readBool8(ptr uint32) bool { + v := m.readUint8(ptr) + if v != 0 { + return true + } + return false +} + +func (m memory) writeBool8(ptr uint32, v bool) { + var b uint8 + if v { + b = 1 + } + m.writeUint8(ptr, b) +} + func (m memory) readFloat64(ptr uint32) float64 { return math.Float64frombits(m.readUint64(ptr)) } diff --git a/sqlite3/os.c b/sqlite3/os.c index c66f970..e76b498 100644 --- a/sqlite3/os.c +++ b/sqlite3/os.c @@ -21,6 +21,7 @@ struct os_file { char lock; char psow; char syncDir; + char readOnly; int lockTimeout; }; @@ -28,6 +29,7 @@ static_assert(offsetof(struct os_file, id) == 4, "Unexpected offset"); static_assert(offsetof(struct os_file, lock) == 8, "Unexpected offset"); static_assert(offsetof(struct os_file, psow) == 9, "Unexpected offset"); static_assert(offsetof(struct os_file, syncDir) == 10, "Unexpected offset"); +static_assert(offsetof(struct os_file, readOnly) == 11, "Unexpected offset"); static_assert(offsetof(struct os_file, lockTimeout) == 12, "Unexpected offset"); int os_close(sqlite3_file *); diff --git a/vfs.go b/vfs.go index 0e445c4..de0ff6c 100644 --- a/vfs.go +++ b/vfs.go @@ -236,6 +236,9 @@ func vfsOpen(ctx context.Context, mod api.Module, pVfs, zName, pFile uint32, fla vfsFile.Open(ctx, mod, pFile, file) + if flags&OPEN_READONLY != 0 { + vfsFile.SetReadOnly(ctx, mod, pFile, true) + } if runtime.GOOS != "windows" && flags&(OPEN_CREATE) != 0 && flags&(OPEN_MAIN_JOURNAL|OPEN_SUPER_JOURNAL|OPEN_WAL) != 0 { diff --git a/vfs_file.go b/vfs_file.go index e400b50..70f02be 100644 --- a/vfs_file.go +++ b/vfs_file.go @@ -13,6 +13,7 @@ const ( vfsFileIDOffset = 4 vfsFileLockOffset = 8 vfsFileSyncDirOffset = 10 + vfsFileReadOnlyOffset = 11 vfsFileLockTimeoutOffset = 12 ) @@ -71,17 +72,20 @@ func (vfsFileMethods) GetLockTimeout(ctx context.Context, mod api.Module, pFile func (vfsFileMethods) GetSyncDir(ctx context.Context, mod api.Module, pFile uint32) bool { mem := memory{mod} - if b := mem.readUint8(pFile + vfsFileSyncDirOffset); b != 0 { - return true - } - return false + return mem.readBool8(pFile + vfsFileSyncDirOffset) } -func (vfsFileMethods) SetSyncDir(ctx context.Context, mod api.Module, pFile uint32, state bool) { +func (vfsFileMethods) SetSyncDir(ctx context.Context, mod api.Module, pFile uint32, val bool) { mem := memory{mod} - var b uint8 - if state { - b = 1 - } - mem.writeUint8(pFile+vfsFileSyncDirOffset, b) + mem.writeBool8(pFile+vfsFileSyncDirOffset, val) +} + +func (vfsFileMethods) GetReadOnly(ctx context.Context, mod api.Module, pFile uint32) bool { + mem := memory{mod} + return mem.readBool8(pFile + vfsFileReadOnlyOffset) +} + +func (vfsFileMethods) SetReadOnly(ctx context.Context, mod api.Module, pFile uint32, val bool) { + mem := memory{mod} + mem.writeBool8(pFile+vfsFileReadOnlyOffset, val) } diff --git a/vfs_lock.go b/vfs_lock.go index a67cb92..4ccd3a3 100644 --- a/vfs_lock.go +++ b/vfs_lock.go @@ -65,6 +65,7 @@ func vfsLock(ctx context.Context, mod api.Module, pFile uint32, eLock vfsLockSta file := vfsFile.GetOS(ctx, mod, pFile) cLock := vfsFile.GetLock(ctx, mod, pFile) timeout := vfsFile.GetLockTimeout(ctx, mod, pFile) + readOnly := vfsFile.GetReadOnly(ctx, mod, pFile) switch { case cLock < _NO_LOCK || cLock > _EXCLUSIVE_LOCK: @@ -83,6 +84,11 @@ func vfsLock(ctx context.Context, mod api.Module, pFile uint32, eLock vfsLockSta return _OK } + // Do not allow any kind of write-lock on a read-only database. + if readOnly && eLock > _RESERVED_LOCK { + return uint32(IOERR_LOCK) + } + switch eLock { case _SHARED_LOCK: // Must be unlocked to get SHARED.