mirror of
https://github.com/superseriousbusiness/gotosocial.git
synced 2025-11-01 22:22:24 -05:00
Update codeberg.org/gruf libraries and fix go-store issue (#347)
* update codeberg.org/gruf/ libraries Signed-off-by: kim <grufwub@gmail.com> * another update Signed-off-by: kim <grufwub@gmail.com>
This commit is contained in:
parent
86e8e7fd21
commit
635ad2a42f
15 changed files with 366 additions and 197 deletions
63
vendor/codeberg.org/gruf/go-store/kv/state.go
generated
vendored
63
vendor/codeberg.org/gruf/go-store/kv/state.go
generated
vendored
|
|
@ -2,6 +2,7 @@ package kv
|
|||
|
||||
import (
|
||||
"io"
|
||||
"sync"
|
||||
|
||||
"codeberg.org/gruf/go-errors"
|
||||
)
|
||||
|
|
@ -15,9 +16,14 @@ var ErrStateClosed = errors.New("store/kv: state closed")
|
|||
// then the state has zero guarantees
|
||||
type StateRO struct {
|
||||
store *KVStore
|
||||
mutex sync.RWMutex
|
||||
}
|
||||
|
||||
func (st *StateRO) Get(key string) ([]byte, error) {
|
||||
// Get state read lock
|
||||
st.mutex.RLock()
|
||||
defer st.mutex.RUnlock()
|
||||
|
||||
// Check not closed
|
||||
if st.store == nil {
|
||||
return nil, ErrStateClosed
|
||||
|
|
@ -28,6 +34,10 @@ func (st *StateRO) Get(key string) ([]byte, error) {
|
|||
}
|
||||
|
||||
func (st *StateRO) GetStream(key string) (io.ReadCloser, error) {
|
||||
// Get state read lock
|
||||
st.mutex.RLock()
|
||||
defer st.mutex.RUnlock()
|
||||
|
||||
// Check not closed
|
||||
if st.store == nil {
|
||||
return nil, ErrStateClosed
|
||||
|
|
@ -38,6 +48,10 @@ func (st *StateRO) GetStream(key string) (io.ReadCloser, error) {
|
|||
}
|
||||
|
||||
func (st *StateRO) Has(key string) (bool, error) {
|
||||
// Get state read lock
|
||||
st.mutex.RLock()
|
||||
defer st.mutex.RUnlock()
|
||||
|
||||
// Check not closed
|
||||
if st.store == nil {
|
||||
return false, ErrStateClosed
|
||||
|
|
@ -47,8 +61,16 @@ func (st *StateRO) Has(key string) (bool, error) {
|
|||
return st.store.has(key)
|
||||
}
|
||||
|
||||
func (st *StateRO) close() {
|
||||
st.store = nil
|
||||
func (st *StateRO) Release() {
|
||||
// Get state write lock
|
||||
st.mutex.Lock()
|
||||
defer st.mutex.Unlock()
|
||||
|
||||
// Release the store
|
||||
if st.store != nil {
|
||||
st.store.mutex.RUnlock()
|
||||
st.store = nil
|
||||
}
|
||||
}
|
||||
|
||||
// StateRW provides a read-write window to the store. While this
|
||||
|
|
@ -58,9 +80,14 @@ func (st *StateRO) close() {
|
|||
// then the state has zero guarantees
|
||||
type StateRW struct {
|
||||
store *KVStore
|
||||
mutex sync.RWMutex
|
||||
}
|
||||
|
||||
func (st *StateRW) Get(key string) ([]byte, error) {
|
||||
// Get state read lock
|
||||
st.mutex.RLock()
|
||||
defer st.mutex.RUnlock()
|
||||
|
||||
// Check not closed
|
||||
if st.store == nil {
|
||||
return nil, ErrStateClosed
|
||||
|
|
@ -71,6 +98,10 @@ func (st *StateRW) Get(key string) ([]byte, error) {
|
|||
}
|
||||
|
||||
func (st *StateRW) GetStream(key string) (io.ReadCloser, error) {
|
||||
// Get state read lock
|
||||
st.mutex.RLock()
|
||||
defer st.mutex.RUnlock()
|
||||
|
||||
// Check not closed
|
||||
if st.store == nil {
|
||||
return nil, ErrStateClosed
|
||||
|
|
@ -81,6 +112,10 @@ func (st *StateRW) GetStream(key string) (io.ReadCloser, error) {
|
|||
}
|
||||
|
||||
func (st *StateRW) Put(key string, value []byte) error {
|
||||
// Get state read lock
|
||||
st.mutex.RLock()
|
||||
defer st.mutex.RUnlock()
|
||||
|
||||
// Check not closed
|
||||
if st.store == nil {
|
||||
return ErrStateClosed
|
||||
|
|
@ -91,6 +126,10 @@ func (st *StateRW) Put(key string, value []byte) error {
|
|||
}
|
||||
|
||||
func (st *StateRW) PutStream(key string, r io.Reader) error {
|
||||
// Get state read lock
|
||||
st.mutex.RLock()
|
||||
defer st.mutex.RUnlock()
|
||||
|
||||
// Check not closed
|
||||
if st.store == nil {
|
||||
return ErrStateClosed
|
||||
|
|
@ -101,6 +140,10 @@ func (st *StateRW) PutStream(key string, r io.Reader) error {
|
|||
}
|
||||
|
||||
func (st *StateRW) Has(key string) (bool, error) {
|
||||
// Get state read lock
|
||||
st.mutex.RLock()
|
||||
defer st.mutex.RUnlock()
|
||||
|
||||
// Check not closed
|
||||
if st.store == nil {
|
||||
return false, ErrStateClosed
|
||||
|
|
@ -111,6 +154,10 @@ func (st *StateRW) Has(key string) (bool, error) {
|
|||
}
|
||||
|
||||
func (st *StateRW) Delete(key string) error {
|
||||
// Get state read lock
|
||||
st.mutex.RLock()
|
||||
defer st.mutex.RUnlock()
|
||||
|
||||
// Check not closed
|
||||
if st.store == nil {
|
||||
return ErrStateClosed
|
||||
|
|
@ -120,6 +167,14 @@ func (st *StateRW) Delete(key string) error {
|
|||
return st.store.delete(key)
|
||||
}
|
||||
|
||||
func (st *StateRW) close() {
|
||||
st.store = nil
|
||||
func (st *StateRW) Release() {
|
||||
// Get state write lock
|
||||
st.mutex.Lock()
|
||||
defer st.mutex.Unlock()
|
||||
|
||||
// Release the store
|
||||
if st.store != nil {
|
||||
st.store.mutex.Unlock()
|
||||
st.store = nil
|
||||
}
|
||||
}
|
||||
|
|
|
|||
50
vendor/codeberg.org/gruf/go-store/kv/store.go
generated
vendored
50
vendor/codeberg.org/gruf/go-store/kv/store.go
generated
vendored
|
|
@ -212,32 +212,34 @@ func (st *KVStore) Iterator(matchFn func(string) bool) (*KVIterator, error) {
|
|||
}, nil
|
||||
}
|
||||
|
||||
// Read provides a read-only window to the store, holding it in a read-locked state until
|
||||
// the supplied function returns
|
||||
func (st *KVStore) Read(do func(*StateRO)) {
|
||||
// Get store read lock
|
||||
// Read provides a read-only window to the store, holding it in a read-locked state until release
|
||||
func (st *KVStore) Read() *StateRO {
|
||||
st.mutex.RLock()
|
||||
defer st.mutex.RUnlock()
|
||||
|
||||
// Create new store state (defer close)
|
||||
state := &StateRO{store: st}
|
||||
defer state.close()
|
||||
|
||||
// Pass state
|
||||
do(state)
|
||||
return &StateRO{store: st}
|
||||
}
|
||||
|
||||
// Update provides a read-write window to the store, holding it in a read-write-locked state
|
||||
// until the supplied functions returns
|
||||
func (st *KVStore) Update(do func(*StateRW)) {
|
||||
// Get store lock
|
||||
// ReadFn provides a read-only window to the store, holding it in a read-locked state until fn return.
|
||||
func (st *KVStore) ReadFn(fn func(*StateRO)) {
|
||||
// Acquire read-only state
|
||||
state := st.Read()
|
||||
defer state.Release()
|
||||
|
||||
// Pass to fn
|
||||
fn(state)
|
||||
}
|
||||
|
||||
// Update provides a read-write window to the store, holding it in a write-locked state until release
|
||||
func (st *KVStore) Update() *StateRW {
|
||||
st.mutex.Lock()
|
||||
defer st.mutex.Unlock()
|
||||
|
||||
// Create new store state (defer close)
|
||||
state := &StateRW{store: st}
|
||||
defer state.close()
|
||||
|
||||
// Pass state
|
||||
do(state)
|
||||
return &StateRW{store: st}
|
||||
}
|
||||
|
||||
// UpdateFn provides a read-write window to the store, holding it in a write-locked state until fn return.
|
||||
func (st *KVStore) UpdateFn(fn func(*StateRW)) {
|
||||
// Acquire read-write state
|
||||
state := st.Update()
|
||||
defer state.Release()
|
||||
|
||||
// Pass to fn
|
||||
fn(state)
|
||||
}
|
||||
|
|
|
|||
8
vendor/codeberg.org/gruf/go-store/storage/block.go
generated
vendored
8
vendor/codeberg.org/gruf/go-store/storage/block.go
generated
vendored
|
|
@ -585,8 +585,8 @@ func (st *BlockStorage) WalkKeys(opts WalkKeysOptions) error {
|
|||
|
||||
// nodePathForKey calculates the node file path for supplied key
|
||||
func (st *BlockStorage) nodePathForKey(key string) (string, error) {
|
||||
// Path separators are illegal
|
||||
if strings.Contains(key, "/") {
|
||||
// Path separators are illegal, as directory paths
|
||||
if strings.Contains(key, "/") || key == "." || key == ".." {
|
||||
return "", ErrInvalidKey
|
||||
}
|
||||
|
||||
|
|
@ -594,6 +594,10 @@ func (st *BlockStorage) nodePathForKey(key string) (string, error) {
|
|||
pb := util.GetPathBuilder()
|
||||
defer util.PutPathBuilder(pb)
|
||||
|
||||
// Append the nodepath to key
|
||||
pb.AppendString(st.nodePath)
|
||||
pb.AppendString(key)
|
||||
|
||||
// Return joined + cleaned node-path
|
||||
return pb.Join(st.nodePath, key), nil
|
||||
}
|
||||
|
|
|
|||
8
vendor/codeberg.org/gruf/go-store/storage/disk.go
generated
vendored
8
vendor/codeberg.org/gruf/go-store/storage/disk.go
generated
vendored
|
|
@ -69,7 +69,6 @@ func getDiskConfig(cfg *DiskConfig) DiskConfig {
|
|||
// DiskStorage is a Storage implementation that stores directly to a filesystem
|
||||
type DiskStorage struct {
|
||||
path string // path is the root path of this store
|
||||
dots int // dots is the "dotdot" count for the root store path
|
||||
bufp pools.BufferPool // bufp is the buffer pool for this DiskStorage
|
||||
config DiskConfig // cfg is the supplied configuration for this store
|
||||
}
|
||||
|
|
@ -120,7 +119,6 @@ func OpenFile(path string, cfg *DiskConfig) (*DiskStorage, error) {
|
|||
// Return new DiskStorage
|
||||
return &DiskStorage{
|
||||
path: path,
|
||||
dots: util.CountDotdots(path),
|
||||
bufp: pools.NewBufferPool(config.WriteBufSize),
|
||||
config: config,
|
||||
}, nil
|
||||
|
|
@ -282,10 +280,10 @@ func (st *DiskStorage) filepath(key string) (string, error) {
|
|||
pb.AppendString(st.path)
|
||||
pb.AppendString(key)
|
||||
|
||||
// If path is dir traversal, and traverses FURTHER
|
||||
// than store root, this is an error
|
||||
if util.CountDotdots(pb.StringPtr()) > st.dots {
|
||||
// Check for dir traversal outside of root
|
||||
if util.IsDirTraversal(st.path, pb.StringPtr()) {
|
||||
return "", ErrInvalidKey
|
||||
}
|
||||
|
||||
return pb.String(), nil
|
||||
}
|
||||
|
|
|
|||
42
vendor/codeberg.org/gruf/go-store/storage/memory.go
generated
vendored
42
vendor/codeberg.org/gruf/go-store/storage/memory.go
generated
vendored
|
|
@ -2,7 +2,6 @@ package storage
|
|||
|
||||
import (
|
||||
"io"
|
||||
"sync"
|
||||
|
||||
"codeberg.org/gruf/go-bytes"
|
||||
"codeberg.org/gruf/go-store/util"
|
||||
|
|
@ -12,14 +11,12 @@ import (
|
|||
// pairs in a Go map in-memory. The map is protected by a mutex.
|
||||
type MemoryStorage struct {
|
||||
fs map[string][]byte
|
||||
mu sync.Mutex
|
||||
}
|
||||
|
||||
// OpenMemory opens a new MemoryStorage instance with internal map of 'size'.
|
||||
func OpenMemory(size int) *MemoryStorage {
|
||||
return &MemoryStorage{
|
||||
fs: make(map[string][]byte, size),
|
||||
mu: sync.Mutex{},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -30,33 +27,19 @@ func (st *MemoryStorage) Clean() error {
|
|||
|
||||
// ReadBytes implements Storage.ReadBytes().
|
||||
func (st *MemoryStorage) ReadBytes(key string) ([]byte, error) {
|
||||
// Safely check store
|
||||
st.mu.Lock()
|
||||
b, ok := st.fs[key]
|
||||
st.mu.Unlock()
|
||||
|
||||
// Return early if not exist
|
||||
if !ok {
|
||||
return nil, ErrNotFound
|
||||
}
|
||||
|
||||
// Create return copy
|
||||
return bytes.Copy(b), nil
|
||||
}
|
||||
|
||||
// ReadStream implements Storage.ReadStream().
|
||||
func (st *MemoryStorage) ReadStream(key string) (io.ReadCloser, error) {
|
||||
// Safely check store
|
||||
st.mu.Lock()
|
||||
b, ok := st.fs[key]
|
||||
st.mu.Unlock()
|
||||
|
||||
// Return early if not exist
|
||||
if !ok {
|
||||
return nil, ErrNotFound
|
||||
}
|
||||
|
||||
// Create io.ReadCloser from 'b' copy
|
||||
b = bytes.Copy(b)
|
||||
r := bytes.NewReader(b)
|
||||
return util.NopReadCloser(r), nil
|
||||
|
|
@ -64,68 +47,43 @@ func (st *MemoryStorage) ReadStream(key string) (io.ReadCloser, error) {
|
|||
|
||||
// WriteBytes implements Storage.WriteBytes().
|
||||
func (st *MemoryStorage) WriteBytes(key string, b []byte) error {
|
||||
// Safely check store
|
||||
st.mu.Lock()
|
||||
_, ok := st.fs[key]
|
||||
|
||||
// Check for already exist
|
||||
if ok {
|
||||
st.mu.Unlock()
|
||||
return ErrAlreadyExists
|
||||
}
|
||||
|
||||
// Write + unlock
|
||||
st.fs[key] = bytes.Copy(b)
|
||||
st.mu.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
// WriteStream implements Storage.WriteStream().
|
||||
func (st *MemoryStorage) WriteStream(key string, r io.Reader) error {
|
||||
// Read all from reader
|
||||
b, err := io.ReadAll(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Write to storage
|
||||
return st.WriteBytes(key, b)
|
||||
}
|
||||
|
||||
// Stat implements Storage.Stat().
|
||||
func (st *MemoryStorage) Stat(key string) (bool, error) {
|
||||
st.mu.Lock()
|
||||
_, ok := st.fs[key]
|
||||
st.mu.Unlock()
|
||||
return ok, nil
|
||||
}
|
||||
|
||||
// Remove implements Storage.Remove().
|
||||
func (st *MemoryStorage) Remove(key string) error {
|
||||
// Safely check store
|
||||
st.mu.Lock()
|
||||
_, ok := st.fs[key]
|
||||
|
||||
// Check in store
|
||||
if !ok {
|
||||
st.mu.Unlock()
|
||||
return ErrNotFound
|
||||
}
|
||||
|
||||
// Delete + unlock
|
||||
delete(st.fs, key)
|
||||
st.mu.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
// WalkKeys implements Storage.WalkKeys().
|
||||
func (st *MemoryStorage) WalkKeys(opts WalkKeysOptions) error {
|
||||
// Safely walk storage keys
|
||||
st.mu.Lock()
|
||||
for key := range st.fs {
|
||||
opts.WalkFn(entry(key))
|
||||
}
|
||||
st.mu.Unlock()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
20
vendor/codeberg.org/gruf/go-store/util/fs.go
generated
vendored
20
vendor/codeberg.org/gruf/go-store/util/fs.go
generated
vendored
|
|
@ -9,14 +9,22 @@ import (
|
|||
"codeberg.org/gruf/go-fastpath"
|
||||
)
|
||||
|
||||
var dotdot = "../"
|
||||
// IsDirTraversal will check if rootPlusPath is a dir traversal outside of root,
|
||||
// assuming that both are cleaned and that rootPlusPath is path.Join(root, somePath)
|
||||
func IsDirTraversal(root string, rootPlusPath string) bool {
|
||||
switch {
|
||||
// Root is $PWD, check for traversal out of
|
||||
case root == ".":
|
||||
return strings.HasPrefix(rootPlusPath, "../")
|
||||
|
||||
// CountDotdots returns the number of "dot-dots" (../) in a cleaned filesystem path
|
||||
func CountDotdots(path string) int {
|
||||
if !strings.HasSuffix(path, dotdot) {
|
||||
return 0
|
||||
// The path MUST be prefixed by root
|
||||
case !strings.HasPrefix(rootPlusPath, root):
|
||||
return true
|
||||
|
||||
// In all other cases, check not equal
|
||||
default:
|
||||
return len(root) == len(rootPlusPath)
|
||||
}
|
||||
return strings.Count(path, dotdot)
|
||||
}
|
||||
|
||||
// WalkDir traverses the dir tree of the supplied path, performing the supplied walkFn on each entry
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue