2011-07-16 01:30:46 +00:00
|
|
|
package sqlite
|
|
|
|
|
2011-07-17 23:58:53 +00:00
|
|
|
/*
|
2011-07-18 00:24:15 +00:00
|
|
|
#include <string.h>
|
|
|
|
|
2011-07-17 23:58:53 +00:00
|
|
|
#define SKIP_SQLITE_VERSION
|
|
|
|
#include "sqlite3.h"
|
|
|
|
*/
|
2011-07-16 01:30:46 +00:00
|
|
|
import "C"
|
2011-07-17 23:58:53 +00:00
|
|
|
|
|
|
|
import (
|
|
|
|
"os"
|
|
|
|
"sync"
|
2011-07-18 00:24:15 +00:00
|
|
|
"unsafe"
|
2011-07-17 23:58:53 +00:00
|
|
|
)
|
2011-07-17 23:12:02 +00:00
|
|
|
|
|
|
|
var file_map_mutex sync.Mutex
|
|
|
|
var file_map = make(map[int]*os.File)
|
|
|
|
|
|
|
|
func GetFile(fd int) (file *os.File) {
|
|
|
|
file_map_mutex.Lock()
|
|
|
|
defer file_map_mutex.Unlock()
|
|
|
|
return file_map[fd]
|
|
|
|
}
|
|
|
|
|
|
|
|
//export GoFileClose
|
2011-07-18 00:24:15 +00:00
|
|
|
// Returns 0 on success and -1 on error.
|
2011-07-17 23:12:02 +00:00
|
|
|
func GoFileClose(fd C.int) (int) {
|
|
|
|
file := GetFile(int(fd))
|
|
|
|
if file.Close() != nil {
|
2011-07-18 00:24:15 +00:00
|
|
|
return -1
|
|
|
|
}
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
|
|
|
//export GoFileRead
|
2011-07-19 22:24:58 +00:00
|
|
|
// Returns SQLite error codes to be returned by xRead:
|
|
|
|
// SQLITE_OK: read n bytes
|
|
|
|
// SQLITE_IOERR_READ: got error while reading
|
|
|
|
// SQLITE_IOERR_SHORT_READ: read fewer than n bytes; rest will be zeroed
|
2011-07-18 00:49:54 +00:00
|
|
|
func GoFileRead(fd C.int, dst *C.char, n C.int, offset C.long) (rv int) {
|
2011-07-18 00:24:15 +00:00
|
|
|
println("reading", n, "bytes at offset", offset, "from fd", fd);
|
|
|
|
defer func() {
|
|
|
|
println("read returning", rv);
|
|
|
|
}()
|
|
|
|
|
|
|
|
file := GetFile(int(fd))
|
|
|
|
if file == nil {
|
2011-07-19 22:24:58 +00:00
|
|
|
return C.SQLITE_IOERR_READ
|
2011-07-18 00:24:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
buf := make([]byte, n)
|
|
|
|
curbuf := buf
|
|
|
|
for n > 0 {
|
|
|
|
read, err := file.ReadAt(curbuf, int64(offset))
|
|
|
|
curbuf = curbuf[read:]
|
|
|
|
n -= C.int(read)
|
|
|
|
if err == os.EOF {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
if err != nil {
|
2011-07-19 22:24:58 +00:00
|
|
|
return C.SQLITE_IOERR_READ
|
2011-07-18 00:24:15 +00:00
|
|
|
}
|
2011-07-17 23:12:02 +00:00
|
|
|
}
|
2011-07-18 00:24:15 +00:00
|
|
|
|
2011-07-19 22:24:58 +00:00
|
|
|
C.memcpy(unsafe.Pointer(dst), unsafe.Pointer(&buf[0]), C.size_t(len(buf)))
|
|
|
|
|
2011-07-18 00:24:15 +00:00
|
|
|
if n != 0 {
|
2011-07-19 22:24:58 +00:00
|
|
|
return C.SQLITE_IOERR_SHORT_READ
|
2011-07-18 00:24:15 +00:00
|
|
|
}
|
2011-07-19 22:24:58 +00:00
|
|
|
return C.SQLITE_OK
|
2011-07-17 23:12:02 +00:00
|
|
|
}
|
2011-07-16 01:30:46 +00:00
|
|
|
|
2011-07-18 00:49:54 +00:00
|
|
|
//export GoFileFileSize
|
2011-07-18 14:39:48 +00:00
|
|
|
// return[0]: 0 on success and -1 on error.
|
|
|
|
// return[1]: size
|
|
|
|
func GoFileFileSize(fd C.int) (rv int, size C.long) {
|
2011-07-18 00:49:54 +00:00
|
|
|
println("getting file size for fd", fd);
|
|
|
|
defer func() {
|
|
|
|
println("returning", rv, "with size", size);
|
|
|
|
}()
|
|
|
|
|
|
|
|
file := GetFile(int(fd))
|
|
|
|
if file == nil {
|
|
|
|
return -1, 0
|
|
|
|
}
|
|
|
|
|
|
|
|
info, err := file.Stat()
|
|
|
|
if err != nil {
|
|
|
|
return -1, 0
|
|
|
|
}
|
2011-07-18 14:39:48 +00:00
|
|
|
return 0, C.long(info.Size)
|
2011-07-18 00:49:54 +00:00
|
|
|
}
|
|
|
|
|
2011-07-16 01:30:46 +00:00
|
|
|
//export GoVFSOpen
|
|
|
|
// fd is -1 on error.
|
2011-07-17 23:58:53 +00:00
|
|
|
func GoVFSOpen(filename *C.char, flags C.int) (fd int) {
|
|
|
|
println("opening", C.GoString(filename), "with flags", int(flags))
|
|
|
|
|
|
|
|
goflags := 0
|
|
|
|
if flags & C.SQLITE_OPEN_READONLY != 0 {
|
|
|
|
goflags |= os.O_RDONLY
|
|
|
|
}
|
|
|
|
if flags & C.SQLITE_OPEN_READWRITE != 0 {
|
|
|
|
goflags |= os.O_RDWR
|
|
|
|
}
|
|
|
|
if flags & C.SQLITE_OPEN_CREATE != 0 {
|
|
|
|
goflags |= os.O_RDWR | os.O_CREATE | os.O_TRUNC
|
|
|
|
}
|
|
|
|
if flags & C.SQLITE_OPEN_DELETEONCLOSE != 0 {
|
|
|
|
// TODO: Do something.
|
|
|
|
}
|
|
|
|
if flags & C.SQLITE_OPEN_EXCLUSIVE != 0{
|
|
|
|
goflags |= os.O_EXCL
|
|
|
|
}
|
|
|
|
|
|
|
|
file, err := os.OpenFile(C.GoString(filename), goflags, 0666)
|
|
|
|
defer func() {
|
|
|
|
if err != nil {
|
|
|
|
println("got error:", err.String())
|
|
|
|
}
|
|
|
|
println("returning fd", fd);
|
|
|
|
}()
|
2011-07-17 23:12:02 +00:00
|
|
|
if err != nil {
|
|
|
|
return -1
|
|
|
|
}
|
|
|
|
|
|
|
|
file_map_mutex.Lock()
|
|
|
|
defer file_map_mutex.Unlock()
|
|
|
|
file_map[file.Fd()] = file
|
|
|
|
return file.Fd()
|
2011-07-16 01:30:46 +00:00
|
|
|
}
|
2011-07-19 22:39:30 +00:00
|
|
|
|
|
|
|
//export GoVFSAccess
|
|
|
|
func GoVFSAccess(filename *C.char, flags C.int) (rv int) {
|
|
|
|
fi, err := os.Stat(C.GoString(filename))
|
|
|
|
if err != nil {
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
switch flags {
|
|
|
|
case C.SQLITE_ACCESS_EXISTS:
|
|
|
|
if fi.Size != 0 {
|
|
|
|
return 1
|
|
|
|
} else {
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
case C.SQLITE_ACCESS_READWRITE:
|
|
|
|
// TODO: compute read/writeability in a manner similar to access()
|
|
|
|
return 1
|
|
|
|
case C.SQLITE_ACCESS_READ:
|
|
|
|
return 1
|
|
|
|
}
|
|
|
|
return 0
|
|
|
|
}
|