532 lines
12 KiB
Go
532 lines
12 KiB
Go
package filesystem
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"io/fs"
|
|
"os"
|
|
"os/user"
|
|
"path/filepath"
|
|
"runtime"
|
|
"sort"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
// ObrimFilesystemResult represents the standardized utility response.
|
|
type ObrimFilesystemResult struct {
|
|
Status bool `json:"status"`
|
|
Code string `json:"code"`
|
|
Payload any `json:"payload"`
|
|
}
|
|
|
|
// obrimFilesystemEntry represents a filesystem listing entry.
|
|
type obrimFilesystemEntry struct {
|
|
Name string `json:"name"`
|
|
Path string `json:"path"`
|
|
Entity string `json:"entity"`
|
|
Size int64 `json:"size"`
|
|
ModifiedTime time.Time `json:"modified_time"`
|
|
}
|
|
|
|
// ObrimFilesystem executes a filesystem operation and returns a structured result.
|
|
func ObrimFilesystem(operationType string, config map[string]any) map[string]any {
|
|
if config == nil {
|
|
config = map[string]any{}
|
|
}
|
|
|
|
if err := obrimFilesystemValidate(operationType, config); err != nil {
|
|
return ObrimStatus(false, "FAILED_VALIDATION", nil)
|
|
}
|
|
|
|
switch operationType {
|
|
case "list":
|
|
return obrimFilesystemList(config)
|
|
|
|
case "check":
|
|
return obrimFilesystemCheck(config)
|
|
|
|
case "create":
|
|
return obrimFilesystemCreate(config)
|
|
|
|
case "delete":
|
|
return obrimFilesystemDelete(config)
|
|
|
|
case "permission":
|
|
return obrimFilesystemPermission(config)
|
|
|
|
default:
|
|
return ObrimStatus(false, "FAILED_UNSUPPORTED_TYPE", nil)
|
|
}
|
|
}
|
|
|
|
// obrimFilesystemValidate validates operation type and configuration.
|
|
func obrimFilesystemValidate(operationType string, config map[string]any) error {
|
|
allowedTypes := map[string]bool{
|
|
"list": true,
|
|
"check": true,
|
|
"create": true,
|
|
"delete": true,
|
|
"permission": true,
|
|
}
|
|
|
|
if !allowedTypes[operationType] {
|
|
return errors.New("unsupported type")
|
|
}
|
|
|
|
switch operationType {
|
|
case "create", "delete":
|
|
entity := strings.TrimSpace(fmt.Sprintf("%v", config["entity"]))
|
|
if entity != "file" && entity != "directory" {
|
|
return errors.New("invalid entity")
|
|
}
|
|
}
|
|
|
|
if strategy, ok := config["strategy"]; ok {
|
|
value := fmt.Sprintf("%v", strategy)
|
|
|
|
if value != "user" && value != "custom" {
|
|
return errors.New("invalid strategy")
|
|
}
|
|
|
|
if value == "custom" {
|
|
if strings.TrimSpace(fmt.Sprintf("%v", config["base"])) == "" {
|
|
return errors.New("missing base")
|
|
}
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// obrimFilesystemResolve resolves and normalizes filesystem paths.
|
|
func obrimFilesystemResolve(config map[string]any) (string, error) {
|
|
base := "."
|
|
|
|
if strategy, ok := config["strategy"]; ok {
|
|
switch fmt.Sprintf("%v", strategy) {
|
|
case "user":
|
|
currentUser, err := user.Current()
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
base = currentUser.HomeDir
|
|
|
|
case "custom":
|
|
base = fmt.Sprintf("%v", config["base"])
|
|
}
|
|
}
|
|
|
|
name := strings.TrimSpace(fmt.Sprintf("%v", config["name"]))
|
|
|
|
resolved := filepath.Join(base, name)
|
|
|
|
absolute, err := filepath.Abs(filepath.Clean(resolved))
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
return absolute, nil
|
|
}
|
|
|
|
// obrimFilesystemPayload builds standardized payload structures.
|
|
func obrimFilesystemPayload(payload map[string]any) map[string]any {
|
|
return payload
|
|
}
|
|
|
|
// obrimFilesystemEntityType determines filesystem entity type.
|
|
func obrimFilesystemEntityType(path string) string {
|
|
info, err := os.Stat(path)
|
|
if err != nil {
|
|
return "unknown"
|
|
}
|
|
|
|
if info.IsDir() {
|
|
return "directory"
|
|
}
|
|
|
|
return "file"
|
|
}
|
|
|
|
// obrimFilesystemPermissionValidate validates permission specifications.
|
|
func obrimFilesystemPermissionValidate(permission string) error {
|
|
if permission == "" {
|
|
return errors.New("permission required")
|
|
}
|
|
|
|
_, err := fs.FileMode(0).String(), error(nil)
|
|
return err
|
|
}
|
|
|
|
// obrimFilesystemList executes filesystem listing operations.
|
|
func obrimFilesystemList(config map[string]any) map[string]any {
|
|
basePath, err := obrimFilesystemResolve(config)
|
|
if err != nil {
|
|
return ObrimStatus(false, "FAILED_PATH_RESOLUTION", nil)
|
|
}
|
|
|
|
entries, err := obrimFilesystemListTraverse(basePath, config)
|
|
if err != nil {
|
|
return ObrimStatus(false, "FAILED_EXECUTION", nil)
|
|
}
|
|
|
|
entries = obrimFilesystemListFilter(entries, config)
|
|
entries = obrimFilesystemListSort(entries, config)
|
|
|
|
payload := obrimFilesystemPayload(map[string]any{
|
|
"entries": entries,
|
|
"total": len(entries),
|
|
"recursive": getBool(config, "recursive"),
|
|
"base_path": basePath,
|
|
})
|
|
|
|
return ObrimStatus(true, "SUCCESS_LIST", payload)
|
|
}
|
|
|
|
// obrimFilesystemListTraverse traverses filesystem entities according to listing configuration.
|
|
func obrimFilesystemListTraverse(basePath string, config map[string]any) ([]obrimFilesystemEntry, error) {
|
|
var entries []obrimFilesystemEntry
|
|
|
|
recursive := getBool(config, "recursive")
|
|
|
|
if recursive {
|
|
err := filepath.Walk(basePath, func(path string, info os.FileInfo, err error) error {
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if path == basePath {
|
|
return nil
|
|
}
|
|
|
|
entries = append(entries, obrimFilesystemEntry{
|
|
Name: info.Name(),
|
|
Path: path,
|
|
Entity: obrimFilesystemEntityType(path),
|
|
Size: info.Size(),
|
|
ModifiedTime: info.ModTime(),
|
|
})
|
|
|
|
return nil
|
|
})
|
|
|
|
return entries, err
|
|
}
|
|
|
|
list, err := os.ReadDir(basePath)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
for _, item := range list {
|
|
info, _ := item.Info()
|
|
|
|
entries = append(entries, obrimFilesystemEntry{
|
|
Name: item.Name(),
|
|
Path: filepath.Join(basePath, item.Name()),
|
|
Entity: map[bool]string{true: "directory", false: "file"}[item.IsDir()],
|
|
Size: info.Size(),
|
|
ModifiedTime: info.ModTime(),
|
|
})
|
|
}
|
|
|
|
return entries, nil
|
|
}
|
|
|
|
// obrimFilesystemListFilter applies entity and pattern filtering.
|
|
func obrimFilesystemListFilter(entries []obrimFilesystemEntry, config map[string]any) []obrimFilesystemEntry {
|
|
var filtered []obrimFilesystemEntry
|
|
|
|
entity := strings.TrimSpace(fmt.Sprintf("%v", config["entity"]))
|
|
pattern := strings.TrimSpace(fmt.Sprintf("%v", config["filter_pattern"]))
|
|
includeHidden := getBool(config, "include_hidden")
|
|
|
|
for _, entry := range entries {
|
|
if !includeHidden && strings.HasPrefix(entry.Name, ".") {
|
|
continue
|
|
}
|
|
|
|
if entity != "" && entry.Entity != entity {
|
|
continue
|
|
}
|
|
|
|
if pattern != "" {
|
|
match, _ := filepath.Match(pattern, entry.Name)
|
|
if !match {
|
|
continue
|
|
}
|
|
}
|
|
|
|
filtered = append(filtered, entry)
|
|
}
|
|
|
|
return filtered
|
|
}
|
|
|
|
// obrimFilesystemListSort applies result sorting behavior.
|
|
func obrimFilesystemListSort(entries []obrimFilesystemEntry, config map[string]any) []obrimFilesystemEntry {
|
|
sortBy := strings.TrimSpace(fmt.Sprintf("%v", config["sort_by"]))
|
|
order := strings.TrimSpace(fmt.Sprintf("%v", config["sort_order"]))
|
|
|
|
sort.Slice(entries, func(i, j int) bool {
|
|
var result bool
|
|
|
|
switch sortBy {
|
|
case "size":
|
|
result = entries[i].Size < entries[j].Size
|
|
|
|
case "modified":
|
|
result = entries[i].ModifiedTime.Before(entries[j].ModifiedTime)
|
|
|
|
default:
|
|
result = entries[i].Name < entries[j].Name
|
|
}
|
|
|
|
if order == "desc" {
|
|
return !result
|
|
}
|
|
|
|
return result
|
|
})
|
|
|
|
return entries
|
|
}
|
|
|
|
// obrimFilesystemCheck executes filesystem validation operations.
|
|
func obrimFilesystemCheck(config map[string]any) map[string]any {
|
|
path, err := obrimFilesystemResolve(config)
|
|
if err != nil {
|
|
return ObrimStatus(false, "FAILED_PATH_RESOLUTION", nil)
|
|
}
|
|
|
|
_, err = os.Stat(path)
|
|
|
|
exists := err == nil
|
|
|
|
readable, writable := obrimFilesystemCheckAccess(path)
|
|
|
|
payload := obrimFilesystemPayload(map[string]any{
|
|
"path": path,
|
|
"exists": exists,
|
|
"entity": obrimFilesystemEntityType(path),
|
|
"readable": readable,
|
|
"writable": writable,
|
|
})
|
|
|
|
return ObrimStatus(true, "SUCCESS_CHECK", payload)
|
|
}
|
|
|
|
// obrimFilesystemCheckAccess verifies filesystem accessibility requirements.
|
|
func obrimFilesystemCheckAccess(path string) (bool, bool) {
|
|
readable := true
|
|
writable := true
|
|
|
|
file, err := os.Open(path)
|
|
if err != nil {
|
|
readable = false
|
|
} else {
|
|
_ = file.Close()
|
|
}
|
|
|
|
file, err = os.OpenFile(path, os.O_WRONLY, 0)
|
|
if err != nil {
|
|
writable = false
|
|
} else {
|
|
_ = file.Close()
|
|
}
|
|
|
|
return readable, writable
|
|
}
|
|
|
|
// obrimFilesystemCreate executes filesystem entity creation operations.
|
|
func obrimFilesystemCreate(config map[string]any) map[string]any {
|
|
path, err := obrimFilesystemResolve(config)
|
|
if err != nil {
|
|
return ObrimStatus(false, "FAILED_PATH_RESOLUTION", nil)
|
|
}
|
|
|
|
entity := fmt.Sprintf("%v", config["entity"])
|
|
|
|
if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil {
|
|
return ObrimStatus(false, "FAILED_EXECUTION", nil)
|
|
}
|
|
|
|
switch entity {
|
|
case "file":
|
|
err = obrimFilesystemCreateFile(path)
|
|
|
|
case "directory":
|
|
err = obrimFilesystemCreateDirectory(path)
|
|
}
|
|
|
|
if err != nil {
|
|
return ObrimStatus(false, "FAILED_EXECUTION", nil)
|
|
}
|
|
|
|
hidden := getBool(config, "hidden")
|
|
|
|
payload := obrimFilesystemPayload(map[string]any{
|
|
"path": path,
|
|
"entity": entity,
|
|
"hidden": hidden,
|
|
"created": true,
|
|
})
|
|
|
|
return ObrimStatus(true, "SUCCESS_CREATE", payload)
|
|
}
|
|
|
|
// obrimFilesystemCreateFile creates a filesystem file.
|
|
func obrimFilesystemCreateFile(path string) error {
|
|
file, err := os.Create(path)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return file.Close()
|
|
}
|
|
|
|
// obrimFilesystemCreateDirectory creates a filesystem directory.
|
|
func obrimFilesystemCreateDirectory(path string) error {
|
|
return os.MkdirAll(path, 0755)
|
|
}
|
|
|
|
// obrimFilesystemDelete executes filesystem entity deletion operations.
|
|
func obrimFilesystemDelete(config map[string]any) map[string]any {
|
|
path, err := obrimFilesystemResolve(config)
|
|
if err != nil {
|
|
return ObrimStatus(false, "FAILED_PATH_RESOLUTION", nil)
|
|
}
|
|
|
|
entity := fmt.Sprintf("%v", config["entity"])
|
|
|
|
switch entity {
|
|
case "file":
|
|
err = obrimFilesystemDeleteFile(path)
|
|
|
|
case "directory":
|
|
err = obrimFilesystemDeleteDirectory(path, getBool(config, "recursive"))
|
|
}
|
|
|
|
if err != nil {
|
|
return ObrimStatus(false, "FAILED_EXECUTION", nil)
|
|
}
|
|
|
|
payload := obrimFilesystemPayload(map[string]any{
|
|
"path": path,
|
|
"entity": entity,
|
|
"deleted": true,
|
|
})
|
|
|
|
return ObrimStatus(true, "SUCCESS_DELETE", payload)
|
|
}
|
|
|
|
// obrimFilesystemDeleteFile deletes a filesystem file.
|
|
func obrimFilesystemDeleteFile(path string) error {
|
|
return os.Remove(path)
|
|
}
|
|
|
|
// obrimFilesystemDeleteDirectory deletes a filesystem directory.
|
|
func obrimFilesystemDeleteDirectory(path string, recursive bool) error {
|
|
if recursive {
|
|
return os.RemoveAll(path)
|
|
}
|
|
|
|
return os.Remove(path)
|
|
}
|
|
|
|
// obrimFilesystemPermission executes filesystem permission operations.
|
|
func obrimFilesystemPermission(config map[string]any) map[string]any {
|
|
mode := strings.TrimSpace(fmt.Sprintf("%v", config["mode"]))
|
|
|
|
switch mode {
|
|
case "write":
|
|
return obrimFilesystemPermissionWrite(config)
|
|
|
|
default:
|
|
return obrimFilesystemPermissionRead(config)
|
|
}
|
|
}
|
|
|
|
// obrimFilesystemPermissionRead retrieves filesystem permissions.
|
|
func obrimFilesystemPermissionRead(config map[string]any) map[string]any {
|
|
path, err := obrimFilesystemResolve(config)
|
|
if err != nil {
|
|
return ObrimStatus(false, "FAILED_PATH_RESOLUTION", nil)
|
|
}
|
|
|
|
info, err := os.Stat(path)
|
|
if err != nil {
|
|
return ObrimStatus(false, "FAILED_EXECUTION", nil)
|
|
}
|
|
|
|
payload := obrimFilesystemPayload(map[string]any{
|
|
"path": path,
|
|
"permission": info.Mode().Perm().String(),
|
|
"mode": "read",
|
|
"updated": false,
|
|
})
|
|
|
|
return ObrimStatus(true, "SUCCESS_PERMISSION", payload)
|
|
}
|
|
|
|
// obrimFilesystemPermissionWrite updates filesystem permissions.
|
|
func obrimFilesystemPermissionWrite(config map[string]any) map[string]any {
|
|
path, err := obrimFilesystemResolve(config)
|
|
if err != nil {
|
|
return ObrimStatus(false, "FAILED_PATH_RESOLUTION", nil)
|
|
}
|
|
|
|
permission := strings.TrimSpace(fmt.Sprintf("%v", config["permission"]))
|
|
|
|
if err := obrimFilesystemPermissionValidate(permission); err != nil {
|
|
return ObrimStatus(false, "FAILED_VALIDATION", nil)
|
|
}
|
|
|
|
var mode os.FileMode
|
|
|
|
_, err = fmt.Sscanf(permission, "%o", &mode)
|
|
if err != nil {
|
|
return ObrimStatus(false, "FAILED_VALIDATION", nil)
|
|
}
|
|
|
|
if runtime.GOOS != "windows" {
|
|
if err := os.Chmod(path, mode); err != nil {
|
|
return ObrimStatus(false, "FAILED_EXECUTION", nil)
|
|
}
|
|
}
|
|
|
|
payload := obrimFilesystemPayload(map[string]any{
|
|
"path": path,
|
|
"permission": permission,
|
|
"mode": "write",
|
|
"updated": true,
|
|
})
|
|
|
|
return ObrimStatus(true, "SUCCESS_PERMISSION", payload)
|
|
}
|
|
|
|
// ObrimStatus returns standardized utility status responses.
|
|
func ObrimStatus(status bool, code string, payload any) map[string]any {
|
|
return map[string]any{
|
|
"status": status,
|
|
"code": code,
|
|
"payload": payload,
|
|
}
|
|
}
|
|
|
|
// getBool safely reads boolean config values.
|
|
func getBool(config map[string]any, key string) bool {
|
|
value, ok := config[key]
|
|
if !ok {
|
|
return false
|
|
}
|
|
|
|
boolean, ok := value.(bool)
|
|
if !ok {
|
|
return false
|
|
}
|
|
|
|
return boolean
|
|
}
|