cli/filesystem/local/client.go

83 lines
2.1 KiB
Go

package local
import (
"fmt"
"os"
"path/filepath"
"strings"
)
// New creates a new instance of the local storage medium.
// It requires a root path to sandbox all file operations.
func New(rootPath string) (*Medium, error) {
if err := os.MkdirAll(rootPath, os.ModePerm); err != nil {
return nil, fmt.Errorf("could not create root directory at %s: %w", rootPath, err)
}
return &Medium{root: rootPath}, nil
}
// path returns a full, safe path within the medium's root.
func (m *Medium) path(subpath string) (string, error) {
if strings.Contains(subpath, "..") {
return "", fmt.Errorf("path traversal attempt detected")
}
return filepath.Join(m.root, subpath), nil
}
// Read retrieves the content of a file from the local disk.
func (m *Medium) Read(path string) (string, error) {
safePath, err := m.path(path)
if err != nil {
return "", err
}
data, err := os.ReadFile(safePath)
if err != nil {
return "", err
}
return string(data), nil
}
// Write saves the given content to a file on the local disk.
func (m *Medium) Write(path, content string) error {
safePath, err := m.path(path)
if err != nil {
return err
}
dir := filepath.Dir(safePath)
if err := os.MkdirAll(dir, os.ModePerm); err != nil {
return err
}
return os.WriteFile(safePath, []byte(content), 0644)
}
// EnsureDir makes sure a directory exists on the local disk.
func (m *Medium) EnsureDir(path string) error {
safePath, err := m.path(path)
if err != nil {
return err
}
return os.MkdirAll(safePath, os.ModePerm)
}
// IsFile checks if a path exists and is a regular file on the local disk.
func (m *Medium) IsFile(path string) bool {
safePath, err := m.path(path)
if err != nil {
return false
}
info, err := os.Stat(safePath)
if os.IsNotExist(err) {
return false
}
return !info.IsDir()
}
// FileGet is a convenience function that reads a file from the medium.
func (m *Medium) FileGet(path string) (string, error) {
return m.Read(path)
}
// FileSet is a convenience function that writes a file to the medium.
func (m *Medium) FileSet(path, content string) error {
return m.Write(path, content)
}