obrimbaseapi/essential/visible/service/helper/filesystem/filesystem.go

693 lines
16 KiB
Go

package filesystem
import (
"os"
"os/user"
"path/filepath"
"sort"
"strconv"
"strings"
"time"
)
const (
obrimFilesystemTypeList = "list"
obrimFilesystemTypeCheck = "check"
obrimFilesystemTypeCreate = "create"
obrimFilesystemTypeDelete = "delete"
obrimFilesystemTypePermission = "permission"
obrimFilesystemEntityFile = "file"
obrimFilesystemEntityDirectory = "directory"
obrimFilesystemStrategyUser = "user"
obrimFilesystemStrategyCustom = "custom"
obrimFilesystemModeRead = "read"
obrimFilesystemModeWrite = "write"
obrimFilesystemCodeSuccessList = "SUCCESS_LIST"
obrimFilesystemCodeSuccessCheck = "SUCCESS_CHECK"
obrimFilesystemCodeSuccessCreate = "SUCCESS_CREATE"
obrimFilesystemCodeSuccessDelete = "SUCCESS_DELETE"
obrimFilesystemCodeSuccessPermission = "SUCCESS_PERMISSION"
obrimFilesystemCodeFailedUnsupportedType = "FAILED_UNSUPPORTED_TYPE"
obrimFilesystemCodeFailedMissingConfig = "FAILED_MISSING_CONFIGURATION"
obrimFilesystemCodeFailedInvalidConfig = "FAILED_INVALID_CONFIGURATION"
obrimFilesystemCodeFailedUnsupportedConfig = "FAILED_UNSUPPORTED_CONFIGURATION"
obrimFilesystemCodeFailedPathResolution = "FAILED_PATH_RESOLUTION"
obrimFilesystemCodeFailedExecution = "FAILED_EXECUTION"
obrimFilesystemCodeFailedPermission = "FAILED_PERMISSION"
obrimFilesystemCodeFailedEntityNotFound = "FAILED_ENTITY_NOT_FOUND"
obrimFilesystemCodeFailedUnsupportedEntity = "FAILED_UNSUPPORTED_ENTITY"
obrimFilesystemCodeFailedInvalidPermission = "FAILED_INVALID_PERMISSION"
)
var obrimFilesystemSupportedKeys = map[string]map[string]bool{
obrimFilesystemTypeList: {
"entity": true,
"strategy": true,
"base": true,
"name": true,
"recursive": true,
"include_hidden": true,
"sort_by": true,
"sort_order": true,
"filter_pattern": true,
"follow_symlink": true,
"absolute_path": true,
},
obrimFilesystemTypeCheck: {
"entity": true,
"strategy": true,
"base": true,
"name": true,
"readable": true,
"writable": true,
},
obrimFilesystemTypeCreate: {
"entity": true,
"strategy": true,
"base": true,
"name": true,
"hidden": true,
},
obrimFilesystemTypeDelete: {
"entity": true,
"strategy": true,
"base": true,
"name": true,
"recursive": true,
},
obrimFilesystemTypePermission: {
"strategy": true,
"base": true,
"name": true,
"mode": true,
"permission": true,
},
}
// ObrimFilesystem executes filesystem operations.
func ObrimFilesystem(operationType string, config map[string]any) map[string]any {
if code := obrimFilesystemValidate(operationType, config); code != "" {
return map[string]any{
"status": false,
"code": code,
"payload": nil,
}
}
switch operationType {
case obrimFilesystemTypeList:
return obrimFilesystemList(config)
case obrimFilesystemTypeCheck:
return obrimFilesystemCheck(config)
case obrimFilesystemTypeCreate:
return obrimFilesystemCreate(config)
case obrimFilesystemTypeDelete:
return obrimFilesystemDelete(config)
case obrimFilesystemTypePermission:
return obrimFilesystemPermission(config)
}
return map[string]any{
"status": false,
"code": obrimFilesystemCodeFailedUnsupportedType,
"payload": nil,
}
}
// obrimFilesystemValidate validates operation inputs.
func obrimFilesystemValidate(operationType string, config map[string]any) string {
if config == nil {
return obrimFilesystemCodeFailedMissingConfig
}
if _, exists := obrimFilesystemSupportedKeys[operationType]; !exists {
return obrimFilesystemCodeFailedUnsupportedType
}
for key := range config {
if !obrimFilesystemSupportedKeys[operationType][key] {
return obrimFilesystemCodeFailedUnsupportedConfig
}
}
switch operationType {
case obrimFilesystemTypeCreate,
obrimFilesystemTypeDelete:
entity, _ := config["entity"].(string)
if entity != obrimFilesystemEntityFile &&
entity != obrimFilesystemEntityDirectory {
return obrimFilesystemCodeFailedUnsupportedEntity
}
}
return ""
}
// obrimFilesystemResolve resolves and normalizes paths.
func obrimFilesystemResolve(config map[string]any) (string, error) {
var basePath string
strategy, _ := config["strategy"].(string)
switch strategy {
case "", obrimFilesystemStrategyUser:
homePath, err := os.UserHomeDir()
if err != nil {
currentUser, userErr := user.Current()
if userErr != nil {
return "", err
}
homePath = currentUser.HomeDir
}
basePath = homePath
case obrimFilesystemStrategyCustom:
basePath, _ = config["base"].(string)
default:
return "", os.ErrInvalid
}
name, _ := config["name"].(string)
resolvedPath := filepath.Clean(filepath.Join(basePath, name))
return filepath.Abs(resolvedPath)
}
// obrimFilesystemPayload builds standardized payloads.
func obrimFilesystemPayload(payload map[string]any) map[string]any {
return payload
}
// obrimFilesystemEntityType determines entity type.
func obrimFilesystemEntityType(path string) string {
info, err := os.Stat(path)
if err != nil {
return ""
}
if info.IsDir() {
return obrimFilesystemEntityDirectory
}
return obrimFilesystemEntityFile
}
// obrimFilesystemPermissionValidate validates permission values.
func obrimFilesystemPermissionValidate(permission string) bool {
if permission == "" {
return false
}
_, err := strconv.ParseUint(permission, 8, 32)
return err == nil
}
// obrimFilesystemList executes listing operations.
func obrimFilesystemList(config map[string]any) map[string]any {
basePath, err := obrimFilesystemResolve(config)
if err != nil {
return map[string]any{
"status": false,
"code": obrimFilesystemCodeFailedPathResolution,
"payload": nil,
}
}
entries, err := obrimFilesystemListTraverse(basePath, config)
if err != nil {
return map[string]any{
"status": false,
"code": obrimFilesystemCodeFailedExecution,
"payload": nil,
}
}
entries = obrimFilesystemListFilter(entries, config)
obrimFilesystemListSort(entries, config)
return map[string]any{
"status": true,
"code": obrimFilesystemCodeSuccessList,
"payload": obrimFilesystemPayload(map[string]any{
"entries": entries,
"total": len(entries),
"recursive": config["recursive"] == true,
"base_path": basePath,
}),
}
}
// obrimFilesystemListTraverse traverses filesystem entities.
func obrimFilesystemListTraverse(basePath string, config map[string]any) ([]map[string]any, error) {
var entries []map[string]any
recursive, _ := config["recursive"].(bool)
includeHidden, _ := config["include_hidden"].(bool)
absolutePath, _ := config["absolute_path"].(bool)
walkFunction := func(path string, info os.FileInfo, walkErr error) error {
if walkErr != nil {
return walkErr
}
if path == basePath {
return nil
}
if !includeHidden && strings.HasPrefix(info.Name(), ".") {
if info.IsDir() {
return filepath.SkipDir
}
return nil
}
entryPath := path
if !absolutePath {
entryPath = info.Name()
}
entries = append(entries, map[string]any{
"name": info.Name(),
"path": entryPath,
"entity": obrimFilesystemEntityType(path),
"size": info.Size(),
"modified": info.ModTime().UTC().Format(time.RFC3339),
})
if !recursive && info.IsDir() {
return filepath.SkipDir
}
return nil
}
err := filepath.Walk(basePath, walkFunction)
return entries, err
}
// obrimFilesystemListFilter filters listing results.
func obrimFilesystemListFilter(entries []map[string]any, config map[string]any) []map[string]any {
var filtered []map[string]any
entity, _ := config["entity"].(string)
pattern, _ := config["filter_pattern"].(string)
for _, entry := range entries {
if entity != "" && entry["entity"] != entity {
continue
}
if pattern != "" {
matched, _ := filepath.Match(pattern, entry["name"].(string))
if !matched {
continue
}
}
filtered = append(filtered, entry)
}
return filtered
}
// obrimFilesystemListSort sorts listing results.
func obrimFilesystemListSort(entries []map[string]any, config map[string]any) {
sortBy, _ := config["sort_by"].(string)
sortOrder, _ := config["sort_order"].(string)
sort.Slice(entries, func(i, j int) bool {
var result bool
switch sortBy {
case "size":
result = entries[i]["size"].(int64) < entries[j]["size"].(int64)
case "modified":
result = entries[i]["modified"].(string) < entries[j]["modified"].(string)
default:
result = entries[i]["name"].(string) < entries[j]["name"].(string)
}
if sortOrder == "desc" {
return !result
}
return result
})
}
// obrimFilesystemCheck executes validation operations.
func obrimFilesystemCheck(config map[string]any) map[string]any {
path, err := obrimFilesystemResolve(config)
if err != nil {
return map[string]any{
"status": false,
"code": obrimFilesystemCodeFailedPathResolution,
"payload": nil,
}
}
_, statErr := os.Stat(path)
exists := statErr == nil
entity := ""
if exists {
entity = obrimFilesystemEntityType(path)
}
readable := false
writable := false
if exists {
readable, writable = obrimFilesystemCheckAccess(path)
}
return map[string]any{
"status": true,
"code": obrimFilesystemCodeSuccessCheck,
"payload": map[string]any{
"path": path,
"exists": exists,
"entity": entity,
"readable": readable,
"writable": writable,
},
}
}
// obrimFilesystemCheckAccess verifies accessibility.
func obrimFilesystemCheckAccess(path string) (bool, bool) {
readable := true
writable := true
readFile, readErr := os.Open(path)
if readErr != nil {
readable = false
} else {
_ = readFile.Close()
}
writeFile, writeErr := os.OpenFile(path, os.O_WRONLY, 0)
if writeErr != nil {
writable = false
} else {
_ = writeFile.Close()
}
return readable, writable
}
// obrimFilesystemCreate executes creation operations.
func obrimFilesystemCreate(config map[string]any) map[string]any {
entity := config["entity"].(string)
switch entity {
case obrimFilesystemEntityFile:
return obrimFilesystemCreateFile(config)
case obrimFilesystemEntityDirectory:
return obrimFilesystemCreateDirectory(config)
}
return map[string]any{
"status": false,
"code": obrimFilesystemCodeFailedUnsupportedEntity,
"payload": nil,
}
}
// obrimFilesystemCreateFile creates a file.
func obrimFilesystemCreateFile(config map[string]any) map[string]any {
path, err := obrimFilesystemResolve(config)
if err != nil {
return map[string]any{
"status": false,
"code": obrimFilesystemCodeFailedPathResolution,
"payload": nil,
}
}
if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil {
return map[string]any{
"status": false,
"code": obrimFilesystemCodeFailedExecution,
"payload": nil,
}
}
file, err := os.Create(path)
if err != nil {
return map[string]any{
"status": false,
"code": obrimFilesystemCodeFailedExecution,
"payload": nil,
}
}
_ = file.Close()
return map[string]any{
"status": true,
"code": obrimFilesystemCodeSuccessCreate,
"payload": map[string]any{
"path": path,
"entity": obrimFilesystemEntityFile,
"hidden": config["hidden"] == true,
"created": true,
},
}
}
// obrimFilesystemCreateDirectory creates a directory.
func obrimFilesystemCreateDirectory(config map[string]any) map[string]any {
path, err := obrimFilesystemResolve(config)
if err != nil {
return map[string]any{
"status": false,
"code": obrimFilesystemCodeFailedPathResolution,
"payload": nil,
}
}
if err := os.MkdirAll(path, 0755); err != nil {
return map[string]any{
"status": false,
"code": obrimFilesystemCodeFailedExecution,
"payload": nil,
}
}
return map[string]any{
"status": true,
"code": obrimFilesystemCodeSuccessCreate,
"payload": map[string]any{
"path": path,
"entity": obrimFilesystemEntityDirectory,
"hidden": config["hidden"] == true,
"created": true,
},
}
}
// obrimFilesystemDelete executes deletion operations.
func obrimFilesystemDelete(config map[string]any) map[string]any {
entity := config["entity"].(string)
switch entity {
case obrimFilesystemEntityFile:
return obrimFilesystemDeleteFile(config)
case obrimFilesystemEntityDirectory:
return obrimFilesystemDeleteDirectory(config)
}
return map[string]any{
"status": false,
"code": obrimFilesystemCodeFailedUnsupportedEntity,
"payload": nil,
}
}
// obrimFilesystemDeleteFile deletes a file.
func obrimFilesystemDeleteFile(config map[string]any) map[string]any {
path, err := obrimFilesystemResolve(config)
if err != nil {
return map[string]any{
"status": false,
"code": obrimFilesystemCodeFailedPathResolution,
"payload": nil,
}
}
if err := os.Remove(path); err != nil {
return map[string]any{
"status": false,
"code": obrimFilesystemCodeFailedExecution,
"payload": nil,
}
}
return map[string]any{
"status": true,
"code": obrimFilesystemCodeSuccessDelete,
"payload": map[string]any{
"path": path,
"entity": obrimFilesystemEntityFile,
"deleted": true,
},
}
}
// obrimFilesystemDeleteDirectory deletes a directory.
func obrimFilesystemDeleteDirectory(config map[string]any) map[string]any {
path, err := obrimFilesystemResolve(config)
if err != nil {
return map[string]any{
"status": false,
"code": obrimFilesystemCodeFailedPathResolution,
"payload": nil,
}
}
recursive, _ := config["recursive"].(bool)
if recursive {
err = os.RemoveAll(path)
} else {
err = os.Remove(path)
}
if err != nil {
return map[string]any{
"status": false,
"code": obrimFilesystemCodeFailedExecution,
"payload": nil,
}
}
return map[string]any{
"status": true,
"code": obrimFilesystemCodeSuccessDelete,
"payload": map[string]any{
"path": path,
"entity": obrimFilesystemEntityDirectory,
"deleted": true,
},
}
}
// obrimFilesystemPermission executes permission operations.
func obrimFilesystemPermission(config map[string]any) map[string]any {
mode, _ := config["mode"].(string)
switch mode {
case "", obrimFilesystemModeRead:
return obrimFilesystemPermissionRead(config)
case obrimFilesystemModeWrite:
return obrimFilesystemPermissionWrite(config)
}
return map[string]any{
"status": false,
"code": obrimFilesystemCodeFailedInvalidConfig,
"payload": nil,
}
}
// obrimFilesystemPermissionRead retrieves permissions.
func obrimFilesystemPermissionRead(config map[string]any) map[string]any {
path, err := obrimFilesystemResolve(config)
if err != nil {
return map[string]any{
"status": false,
"code": obrimFilesystemCodeFailedPathResolution,
"payload": nil,
}
}
info, err := os.Stat(path)
if err != nil {
return map[string]any{
"status": false,
"code": obrimFilesystemCodeFailedEntityNotFound,
"payload": nil,
}
}
return map[string]any{
"status": true,
"code": obrimFilesystemCodeSuccessPermission,
"payload": map[string]any{
"path": path,
"permission": info.Mode().Perm().String(),
"mode": obrimFilesystemModeRead,
"updated": false,
},
}
}
// obrimFilesystemPermissionWrite updates permissions.
func obrimFilesystemPermissionWrite(config map[string]any) map[string]any {
path, err := obrimFilesystemResolve(config)
if err != nil {
return map[string]any{
"status": false,
"code": obrimFilesystemCodeFailedPathResolution,
"payload": nil,
}
}
permission, _ := config["permission"].(string)
if !obrimFilesystemPermissionValidate(permission) {
return map[string]any{
"status": false,
"code": obrimFilesystemCodeFailedInvalidPermission,
"payload": nil,
}
}
value, _ := strconv.ParseUint(permission, 8, 32)
if err := os.Chmod(path, os.FileMode(value)); err != nil {
return map[string]any{
"status": false,
"code": obrimFilesystemCodeFailedPermission,
"payload": nil,
}
}
return map[string]any{
"status": true,
"code": obrimFilesystemCodeSuccessPermission,
"payload": map[string]any{
"path": path,
"permission": permission,
"mode": obrimFilesystemModeWrite,
"updated": true,
},
}
}