go-vise

Constrained Size Output Virtual Machine
Info | Log | Files | Refs | README | LICENSE

fs.go (3295B)


      1 package fs
      2 
      3 import (
      4 	"context"
      5 	"errors"
      6 	"io/fs"
      7 	"io/ioutil"
      8 	"os"
      9 	"path"
     10 
     11 	"git.defalsify.org/vise.git/db"
     12 )
     13 
     14 // holds string (filepath) versions of LookupKey
     15 type fsLookupKey struct {
     16 	Default string
     17 	Translation string
     18 }
     19 
     20 // pure filesystem backend implementation if the Db interface.
     21 type fsDb struct {
     22 	*db.DbBase
     23 	dir string
     24 }
     25 
     26 
     27 // NewFsDb creates a filesystem backed Db implementation.
     28 func NewFsDb() *fsDb {
     29 	db := &fsDb{
     30 		DbBase: db.NewDbBase(),
     31 	}
     32 	return db
     33 }
     34 
     35 // String implements the string interface.
     36 func(fdb *fsDb) String() string {
     37 	return "fsdb: " + fdb.dir
     38 }
     39 
     40 // Connect implements the Db interface.
     41 func(fdb *fsDb) Connect(ctx context.Context, connStr string) error {
     42 	if fdb.dir != "" {
     43 		logg.WarnCtxf(ctx, "already connected", "conn", fdb.dir)
     44 		return nil
     45 	}
     46 	err := os.MkdirAll(connStr, 0700)
     47 	if err != nil {
     48 		return err
     49 	}
     50 	fdb.dir = connStr
     51 	return nil
     52 }
     53 
     54 // Get implements the Db interface.
     55 func(fdb *fsDb) Get(ctx context.Context, key []byte) ([]byte, error) {
     56 	var f *os.File
     57 	lk, err := fdb.ToKey(ctx, key)
     58 	if err != nil {
     59 		return nil, err
     60 	}
     61 	flk, err := fdb.pathFor(ctx, &lk)
     62 	if err != nil {
     63 		return nil, err
     64 	}
     65 	flka, err := fdb.altPathFor(ctx, &lk)
     66 	if err != nil {
     67 		return nil, err
     68 	}
     69 	for i, fp := range([]string{flk.Translation, flka.Translation, flk.Default, flka.Default}) {
     70 		if fp == "" {
     71 			logg.TraceCtxf(ctx, "fs get skip missing", "i", i)
     72 			continue
     73 		}
     74 		logg.TraceCtxf(ctx, "trying fs get", "i", i, "key", key, "path", fp)
     75 		f, err = os.Open(fp)
     76 		if err == nil {
     77 			break
     78 		}
     79 		if !errors.Is(err, fs.ErrNotExist) {
     80 			return nil, err
     81 		}
     82 	}
     83 	if f == nil {
     84 		return nil, db.NewErrNotFound(key)
     85 	}
     86 	defer f.Close()
     87 	b, err := ioutil.ReadAll(f)
     88 	if err != nil {
     89 		return nil, err
     90 	}
     91 	return b, nil
     92 }
     93 
     94 // Put implements the Db interface.
     95 func(fdb *fsDb) Put(ctx context.Context, key []byte, val []byte) error {
     96 	if !fdb.CheckPut() {
     97 		return errors.New("unsafe put and safety set")
     98 	}
     99 	lk, err := fdb.ToKey(ctx, key)
    100 	if err != nil {
    101 		return err
    102 	}
    103 	flk, err := fdb.pathFor(ctx, &lk)
    104 	if err != nil {
    105 		return err
    106 	}
    107 	logg.TraceCtxf(ctx, "fs put", "key", key, "lk", lk, "flk", flk, "val", val)
    108 	if flk.Translation != "" {
    109 		err = ioutil.WriteFile(flk.Translation, val, 0600)
    110 		if err != nil {
    111 			return err
    112 		}
    113 		return nil
    114 	}
    115 	return ioutil.WriteFile(flk.Default, val, 0600)
    116 }
    117 
    118 // Close implements the Db interface.
    119 func(fdb *fsDb) Close() error {
    120 	return nil
    121 }
    122 
    123 // create a key safe for the filesystem.
    124 func(fdb *fsDb) pathFor(ctx context.Context, lk *db.LookupKey) (fsLookupKey, error) {
    125 	var flk fsLookupKey
    126 	lk.Default[0] += 0x30
    127 	flk.Default = path.Join(fdb.dir, string(lk.Default))
    128 	if lk.Translation != nil {
    129 		lk.Translation[0] += 0x30
    130 		flk.Translation = path.Join(fdb.dir, string(lk.Translation))
    131 	}
    132 	return flk, nil
    133 }
    134 
    135 // create a key safe for the filesystem, matching legacy resource.FsResource name.
    136 func(fdb *fsDb) altPathFor(ctx context.Context, lk *db.LookupKey) (fsLookupKey, error) {
    137 	var flk fsLookupKey
    138 	fb := string(lk.Default[1:])
    139 	if fdb.Prefix() == db.DATATYPE_BIN {
    140 		fb += ".bin"
    141 	}
    142 	flk.Default = path.Join(fdb.dir, fb)
    143 
    144 	if lk.Translation != nil {
    145 		fb = string(lk.Translation[1:])
    146 		if fdb.Prefix() == db.DATATYPE_BIN {
    147 			fb += ".bin"
    148 		}
    149 		flk.Translation = path.Join(fdb.dir, fb)
    150 	}
    151 
    152 	return flk, nil
    153 }