Files
sqlite3/ext/fileio/fsdir.go

171 lines
2.9 KiB
Go
Raw Normal View History

2023-12-11 14:48:15 +00:00
package fileio
import (
"io/fs"
"os"
2023-12-12 01:00:13 +00:00
"path"
2023-12-11 14:48:15 +00:00
"path/filepath"
"strings"
"github.com/ncruces/go-sqlite3"
)
2024-09-22 12:09:23 +01:00
const (
_COL_NAME = 0
_COL_MODE = 1
_COL_TIME = 2
_COL_DATA = 3
_COL_ROOT = 4
_COL_BASE = 5
)
2023-12-12 14:06:54 +00:00
type fsdir struct{ fsys fs.FS }
2023-12-11 14:48:15 +00:00
func (d fsdir) BestIndex(idx *sqlite3.IndexInfo) error {
2023-12-12 01:00:13 +00:00
var root, base bool
2023-12-11 14:48:15 +00:00
for i, cst := range idx.Constraint {
switch cst.Column {
2024-09-22 12:09:23 +01:00
case _COL_ROOT:
2023-12-11 14:48:15 +00:00
if !cst.Usable || cst.Op != sqlite3.INDEX_CONSTRAINT_EQ {
return sqlite3.CONSTRAINT
}
idx.ConstraintUsage[i] = sqlite3.IndexConstraintUsage{
Omit: true,
ArgvIndex: 1,
}
2023-12-12 01:00:13 +00:00
root = true
2024-09-22 12:09:23 +01:00
case _COL_BASE:
2023-12-11 14:48:15 +00:00
if !cst.Usable || cst.Op != sqlite3.INDEX_CONSTRAINT_EQ {
return sqlite3.CONSTRAINT
}
idx.ConstraintUsage[i] = sqlite3.IndexConstraintUsage{
Omit: true,
ArgvIndex: 2,
}
2023-12-12 01:00:13 +00:00
base = true
2023-12-11 14:48:15 +00:00
}
}
2023-12-12 14:06:54 +00:00
if !root {
return sqlite3.CONSTRAINT
2023-12-11 14:48:15 +00:00
}
2023-12-12 01:00:13 +00:00
if base {
2023-12-11 14:48:15 +00:00
idx.EstimatedCost = 10
2023-12-12 14:06:54 +00:00
} else {
idx.EstimatedCost = 100
2023-12-11 14:48:15 +00:00
}
return nil
}
func (d fsdir) Open() (sqlite3.VTabCursor, error) {
2024-01-03 00:54:30 +00:00
return &cursor{fsdir: d}, nil
2023-12-11 14:48:15 +00:00
}
type cursor struct {
2024-01-03 00:54:30 +00:00
fsdir
2024-04-16 01:04:32 +01:00
base string
2024-07-09 15:21:19 +01:00
resume resume
2024-04-16 01:04:32 +01:00
cancel func()
curr entry
eof bool
rowID int64
2023-12-11 14:48:15 +00:00
}
type entry struct {
2023-12-12 01:00:13 +00:00
fs.DirEntry
2023-12-27 14:06:44 +00:00
err error
path string
2023-12-11 14:48:15 +00:00
}
func (c *cursor) Close() error {
2024-04-16 01:04:32 +01:00
if c.cancel != nil {
c.cancel()
2023-12-11 14:48:15 +00:00
}
return nil
}
func (c *cursor) Filter(idxNum int, idxStr string, arg ...sqlite3.Value) error {
if err := c.Close(); err != nil {
return err
}
2023-12-12 01:00:13 +00:00
root := arg[0].Text()
2023-12-11 14:48:15 +00:00
if len(arg) > 1 {
2023-12-12 01:00:13 +00:00
base := arg[1].Text()
2023-12-12 14:06:54 +00:00
if c.fsys != nil {
2023-12-12 01:00:13 +00:00
root = path.Join(base, root)
base = path.Clean(base) + "/"
2023-12-11 14:48:15 +00:00
} else {
2023-12-12 01:00:13 +00:00
root = filepath.Join(base, root)
base = filepath.Clean(base) + string(filepath.Separator)
2023-12-11 14:48:15 +00:00
}
2023-12-12 01:00:13 +00:00
c.base = base
2023-12-11 14:48:15 +00:00
}
2024-07-09 15:21:19 +01:00
c.resume, c.cancel = pull(c, root)
2023-12-11 14:48:15 +00:00
c.eof = false
2024-04-16 01:04:32 +01:00
c.rowID = 0
2023-12-11 14:48:15 +00:00
return c.Next()
}
func (c *cursor) Next() error {
2024-07-09 15:21:19 +01:00
curr, ok := next(c)
2023-12-11 14:48:15 +00:00
c.curr = curr
c.eof = !ok
c.rowID++
return c.curr.err
}
func (c *cursor) EOF() bool {
return c.eof
}
func (c *cursor) RowID() (int64, error) {
return c.rowID, nil
}
2024-07-26 12:25:15 +01:00
func (c *cursor) Column(ctx sqlite3.Context, n int) error {
2023-12-11 14:48:15 +00:00
switch n {
2024-09-22 12:09:23 +01:00
case _COL_NAME:
2023-12-12 01:00:13 +00:00
name := strings.TrimPrefix(c.curr.path, c.base)
2023-12-11 14:48:15 +00:00
ctx.ResultText(name)
2024-09-22 12:09:23 +01:00
case _COL_MODE:
2023-12-12 01:00:13 +00:00
i, err := c.curr.Info()
2023-12-11 14:48:15 +00:00
if err != nil {
return err
}
ctx.ResultInt64(int64(i.Mode()))
2024-09-22 12:09:23 +01:00
case _COL_TIME:
2023-12-12 01:00:13 +00:00
i, err := c.curr.Info()
2023-12-11 14:48:15 +00:00
if err != nil {
return err
}
ctx.ResultTime(i.ModTime(), sqlite3.TimeFormatUnixFrac)
2024-09-22 12:09:23 +01:00
case _COL_DATA:
2023-12-12 01:00:13 +00:00
switch typ := c.curr.Type(); {
2023-12-11 14:48:15 +00:00
case typ.IsRegular():
var data []byte
var err error
2023-12-12 14:06:54 +00:00
if c.fsys != nil {
data, err = fs.ReadFile(c.fsys, c.curr.path)
2023-12-11 14:48:15 +00:00
} else {
2023-12-12 01:00:13 +00:00
data, err = os.ReadFile(c.curr.path)
2023-12-11 14:48:15 +00:00
}
if err != nil {
return err
}
ctx.ResultBlob(data)
2023-12-12 14:06:54 +00:00
case typ&fs.ModeSymlink != 0 && c.fsys == nil:
2023-12-12 01:00:13 +00:00
t, err := os.Readlink(c.curr.path)
2023-12-11 14:48:15 +00:00
if err != nil {
return err
}
ctx.ResultText(t)
}
}
return nil
}