| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209 | //go:build mipsle// +build mipslepackage databaseimport (	"encoding/json"	"errors"	"io/ioutil"	"log"	"os"	"path/filepath"	"strings"	"sync")func newDatabase(dbfile string, readOnlyMode bool) (*Database, error) {	dbRootPath := filepath.ToSlash(filepath.Clean(dbfile))	dbRootPath = "fsdb/" + dbRootPath	err := os.MkdirAll(dbRootPath, 0755)	if err != nil {		return nil, err	}	tableMap := sync.Map{}	//build the table list from file system	files, err := filepath.Glob(filepath.Join(dbRootPath, "/*"))	if err != nil {		return nil, err	}	for _, file := range files {		if isDirectory(file) {			tableMap.Store(filepath.Base(file), "")		}	}	log.Println("Filesystem Emulated Key-value Database Service Started: " + dbRootPath)	return &Database{		Db:       dbRootPath,		Tables:   tableMap,		ReadOnly: readOnlyMode,	}, nil}func (d *Database) dump(filename string) ([]string, error) {	//Get all file objects from root	rootfiles, err := filepath.Glob(filepath.Join(d.Db.(string), "/*"))	if err != nil {		return []string{}, err	}	//Filter out the folders	rootFolders := []string{}	for _, file := range rootfiles {		if !isDirectory(file) {			rootFolders = append(rootFolders, filepath.Base(file))		}	}	return rootFolders, nil}func (d *Database) newTable(tableName string) error {	if d.ReadOnly {		return errors.New("Operation rejected in ReadOnly mode")	}	tablePath := filepath.Join(d.Db.(string), filepath.Base(tableName))	if !fileExists(tablePath) {		return os.MkdirAll(tablePath, 0755)	}	return nil}func (d *Database) tableExists(tableName string) bool {	tablePath := filepath.Join(d.Db.(string), filepath.Base(tableName))	if _, err := os.Stat(tablePath); errors.Is(err, os.ErrNotExist) {		return false	}	if !isDirectory(tablePath) {		return false	}	return true}func (d *Database) dropTable(tableName string) error {	if d.ReadOnly {		return errors.New("Operation rejected in ReadOnly mode")	}	tablePath := filepath.Join(d.Db.(string), filepath.Base(tableName))	if d.tableExists(tableName) {		return os.RemoveAll(tablePath)	} else {		return errors.New("table not exists")	}}func (d *Database) write(tableName string, key string, value interface{}) error {	if d.ReadOnly {		return errors.New("Operation rejected in ReadOnly mode")	}	tablePath := filepath.Join(d.Db.(string), filepath.Base(tableName))	js, err := json.Marshal(value)	if err != nil {		return err	}	key = strings.ReplaceAll(key, "/", "-SLASH_SIGN-")	return ioutil.WriteFile(filepath.Join(tablePath, key+".entry"), js, 0755)}func (d *Database) read(tableName string, key string, assignee interface{}) error {	if !d.keyExists(tableName, key) {		return errors.New("key not exists")	}	key = strings.ReplaceAll(key, "/", "-SLASH_SIGN-")	tablePath := filepath.Join(d.Db.(string), filepath.Base(tableName))	entryPath := filepath.Join(tablePath, key+".entry")	content, err := ioutil.ReadFile(entryPath)	if err != nil {		return err	}	err = json.Unmarshal(content, &assignee)	return err}func (d *Database) keyExists(tableName string, key string) bool {	key = strings.ReplaceAll(key, "/", "-SLASH_SIGN-")	tablePath := filepath.Join(d.Db.(string), filepath.Base(tableName))	entryPath := filepath.Join(tablePath, key+".entry")	return fileExists(entryPath)}func (d *Database) delete(tableName string, key string) error {	if d.ReadOnly {		return errors.New("Operation rejected in ReadOnly mode")	}	if !d.keyExists(tableName, key) {		return errors.New("key not exists")	}	key = strings.ReplaceAll(key, "/", "-SLASH_SIGN-")	tablePath := filepath.Join(d.Db.(string), filepath.Base(tableName))	entryPath := filepath.Join(tablePath, key+".entry")	return os.Remove(entryPath)}func (d *Database) listTable(tableName string) ([][][]byte, error) {	if !d.tableExists(tableName) {		return [][][]byte{}, errors.New("table not exists")	}	tablePath := filepath.Join(d.Db.(string), filepath.Base(tableName))	entries, err := filepath.Glob(filepath.Join(tablePath, "/*.entry"))	if err != nil {		return [][][]byte{}, err	}	var results [][][]byte = [][][]byte{}	for _, entry := range entries {		if !isDirectory(entry) {			//Read it			key := filepath.Base(entry)			key = strings.TrimSuffix(key, filepath.Ext(key))			key = strings.ReplaceAll(key, "-SLASH_SIGN-", "/")			bkey := []byte(key)			bval := []byte("")			c, err := ioutil.ReadFile(entry)			if err != nil {				break			}			bval = c			results = append(results, [][]byte{bkey, bval})		}	}	return results, nil}func (d *Database) close() {	//Nothing to close as it is file system}func isDirectory(path string) bool {	fileInfo, err := os.Stat(path)	if err != nil {		return false	}	return fileInfo.IsDir()}func fileExists(name string) bool {	_, err := os.Stat(name)	if err == nil {		return true	}	if errors.Is(err, os.ErrNotExist) {		return false	}	return false}
 |