From f6694cb17d38472e9166f1b03d1f62a36b30651b Mon Sep 17 00:00:00 2001 From: Rajon Ahmed Date: Fri, 28 Aug 2026 12:53:42 +0800 Subject: [PATCH] upd: essential/file updated helper filesystem updated --- .../service/helper/filesystem/filesystem.go | 1212 +++++++++++++++++ 1 file changed, 1212 insertions(+) diff --git a/essential/visible/service/helper/filesystem/filesystem.go b/essential/visible/service/helper/filesystem/filesystem.go index e69de29..632c3ee 100644 --- a/essential/visible/service/helper/filesystem/filesystem.go +++ b/essential/visible/service/helper/filesystem/filesystem.go @@ -0,0 +1,1212 @@ +/* +|-------------------------------------------------------------------------- +| Description +|-------------------------------------------------------------------------- +| +| Name: +| - Filesystem +| +| Purpose: +| - Provide a reusable, OS-agnostic utility to deterministically perform +| filesystem operations through a unified execution interface supporting +| listing, validation, creation, deletion, and permission management with +| consistent behavior and structured results. +| +|-------------------------------------------------------------------------- +*/ + +/* +|-------------------------------------------------------------------------- +| Instruction +|-------------------------------------------------------------------------- +| +| Guideline: +| - Use ObrimFilesystem() as the single public entry point. +| - Execute one filesystem operation per invocation. +| - Validate the operation type and type-specific configuration before +| processing. +| - Resolve filesystem paths using the supported user or custom strategy. +| - Use list for filesystem traversal, filtering, sorting, and discovery. +| - Use check for filesystem existence, entity type, and accessibility +| validation. +| - Use create for creating exactly one file or directory. +| - Use delete for deleting exactly one file or directory, with optional +| recursive directory deletion. +| - Use permission for retrieving or updating filesystem permissions. +| - Return standardized structured results for both successful and failed +| executions. +| +| Example: +| - ObrimFilesystem("list", map[string]any{ +| "entity": "file", +| "strategy": "user", +| "base": "", +| "name": "Documents", +| "recursive": true, +| "include_hidden": false, +| "sort_by": "name", +| "sort_order": "asc", +| "filter_pattern": "*.txt", +| "follow_symlink": false, +| "absolute_path": true, +| }) +| +| - ObrimFilesystem("check", map[string]any{ +| "entity": "file", +| "strategy": "custom", +| "base": "/tmp", +| "name": "example.txt", +| "readable": true, +| "writable": true, +| }) +| +| - ObrimFilesystem("create", map[string]any{ +| "entity": "file", +| "strategy": "custom", +| "base": "/tmp", +| "name": "example.txt", +| "hidden": false, +| }) +| +| - ObrimFilesystem("delete", map[string]any{ +| "entity": "directory", +| "strategy": "custom", +| "base": "/tmp", +| "name": "workspace", +| "recursive": true, +| }) +| +| - ObrimFilesystem("permission", map[string]any{ +| "strategy": "custom", +| "base": "/tmp", +| "name": "example.txt", +| "mode": "write", +| "permission": "0644", +| }) +| +|-------------------------------------------------------------------------- +*/ + +/* +|-------------------------------------------------------------------------- +| Credit +|-------------------------------------------------------------------------- +| +| Contributor: +| - Rajon Ahmed +| - Blockonite +| +|-------------------------------------------------------------------------- +*/ + +package filesystem + +import ( + "fmt" + "os" + "path/filepath" + "sort" + "strconv" + "strings" +) + +// Defines filesystem operation types. +const ( + obrimFilesystemTypeList = "list" + obrimFilesystemTypeCheck = "check" + obrimFilesystemTypeCreate = "create" + obrimFilesystemTypeDelete = "delete" + obrimFilesystemTypePermission = "permission" +) + +// Defines supported filesystem entity types. +const ( + obrimFilesystemEntityFile = "file" + obrimFilesystemEntityDirectory = "directory" +) + +// Defines supported filesystem path resolution strategies. +const ( + obrimFilesystemStrategyUser = "user" + obrimFilesystemStrategyCustom = "custom" +) + +// Defines supported permission operation modes. +const ( + obrimFilesystemModeRead = "read" + obrimFilesystemModeWrite = "write" +) + +// Defines supported listing sort criteria. +const ( + obrimFilesystemSortName = "name" + obrimFilesystemSortSize = "size" + obrimFilesystemSortModified = "modified" + obrimFilesystemSortCreated = "created" +) + +// Defines supported listing sort orders. +const ( + obrimFilesystemSortOrderAsc = "asc" + obrimFilesystemSortOrderDesc = "desc" +) + +// Defines filesystem execution result codes. +const ( + obrimFilesystemSuccessList = "SUCCESS_LIST" + obrimFilesystemSuccessCheck = "SUCCESS_CHECK" + obrimFilesystemSuccessCreate = "SUCCESS_CREATE" + obrimFilesystemSuccessDelete = "SUCCESS_DELETE" + obrimFilesystemSuccessPermission = "SUCCESS_PERMISSION" + + obrimFilesystemFailureInvalidType = "FAILURE_INVALID_TYPE" + obrimFilesystemFailureInvalidConfig = "FAILURE_INVALID_CONFIG" + obrimFilesystemFailureInvalidEntity = "FAILURE_INVALID_ENTITY" + obrimFilesystemFailureInvalidStrategy = "FAILURE_INVALID_STRATEGY" + obrimFilesystemFailureInvalidSortBy = "FAILURE_INVALID_SORT_BY" + obrimFilesystemFailureInvalidSortOrder = "FAILURE_INVALID_SORT_ORDER" + obrimFilesystemFailureInvalidMode = "FAILURE_INVALID_MODE" + obrimFilesystemFailureInvalidPermission = "FAILURE_INVALID_PERMISSION" + obrimFilesystemFailureResolvePath = "FAILURE_RESOLVE_PATH" + obrimFilesystemFailureList = "FAILURE_LIST" + obrimFilesystemFailureCheck = "FAILURE_CHECK" + obrimFilesystemFailureCreate = "FAILURE_CREATE" + obrimFilesystemFailureDelete = "FAILURE_DELETE" + obrimFilesystemFailurePermission = "FAILURE_PERMISSION" + obrimFilesystemFailureEntityNotFound = "FAILURE_ENTITY_NOT_FOUND" + obrimFilesystemFailureEntityTypeMismatch = "FAILURE_ENTITY_TYPE_MISMATCH" + obrimFilesystemFailureReadAccess = "FAILURE_READ_ACCESS" + obrimFilesystemFailureWriteAccess = "FAILURE_WRITE_ACCESS" +) + +// Defines a filesystem listing entry. +type obrimFilesystemEntry struct { + Path string `json:"path"` + Name string `json:"name"` + Entity string `json:"entity"` + Size int64 `json:"size"` + Modified string `json:"modified"` + Created string `json:"created"` + Hidden bool `json:"hidden"` + Read bool `json:"readable"` + Write bool `json:"writable"` +} + +// Defines the filesystem utility result. +type obrimFilesystemResult struct { + Status bool `json:"status"` + Code string `json:"code"` + Payload map[string]any `json:"payload"` +} + +// Defines listing configuration. +type obrimFilesystemListConfig struct { + Entity string + Strategy string + Base string + Name string + Recursive bool + IncludeHidden bool + SortBy string + SortOrder string + FilterPattern string + FollowSymlink bool + AbsolutePath bool +} + +// Defines check configuration. +type obrimFilesystemCheckConfig struct { + Entity string + Strategy string + Base string + Name string + Readable bool + Writable bool +} + +// Defines create configuration. +type obrimFilesystemCreateConfig struct { + Entity string + Strategy string + Base string + Name string + Hidden bool +} + +// Defines delete configuration. +type obrimFilesystemDeleteConfig struct { + Entity string + Strategy string + Base string + Name string + Recursive bool +} + +// Defines permission configuration. +type obrimFilesystemPermissionConfig struct { + Strategy string + Base string + Name string + Mode string + Permission string +} + +// Executes a filesystem operation and returns a structured result. +func ObrimFilesystem(operationType string, config map[string]any) map[string]any { + if err := obrimFilesystemValidateInput(operationType, config); err != nil { + return obrimFilesystemBuildOutput(false, err.code, nil) + } + + payload, code, err := obrimFilesystemRouteRequest(operationType, config) + if err != nil { + return obrimFilesystemBuildOutput(false, code, nil) + } + + return obrimFilesystemBuildOutput(true, code, payload) +} + +// Defines a filesystem validation error. +type obrimFilesystemValidationError struct { + code string +} + +// Validates the requested operation and its configuration. +func obrimFilesystemValidateInput(operationType string, config map[string]any) *obrimFilesystemValidationError { + if config == nil { + return &obrimFilesystemValidationError{code: obrimFilesystemFailureInvalidConfig} + } + + switch operationType { + case obrimFilesystemTypeList: + return obrimFilesystemValidateListConfig(config) + case obrimFilesystemTypeCheck: + return obrimFilesystemValidateCheckConfig(config) + case obrimFilesystemTypeCreate: + return obrimFilesystemValidateCreateConfig(config) + case obrimFilesystemTypeDelete: + return obrimFilesystemValidateDeleteConfig(config) + case obrimFilesystemTypePermission: + return obrimFilesystemValidatePermissionConfig(config) + default: + return &obrimFilesystemValidationError{code: obrimFilesystemFailureInvalidType} + } +} + +// Routes a validated filesystem request to its operation-specific function. +func obrimFilesystemRouteRequest(operationType string, config map[string]any) (map[string]any, string, error) { + switch operationType { + case obrimFilesystemTypeList: + payload, err := obrimFilesystemList(config) + if err != nil { + return nil, obrimFilesystemFailureList, err + } + return payload, obrimFilesystemSuccessList, nil + + case obrimFilesystemTypeCheck: + payload, code, err := obrimFilesystemCheck(config) + if err != nil { + return nil, code, err + } + return payload, obrimFilesystemSuccessCheck, nil + + case obrimFilesystemTypeCreate: + payload, err := obrimFilesystemCreate(config) + if err != nil { + return nil, obrimFilesystemFailureCreate, err + } + return payload, obrimFilesystemSuccessCreate, nil + + case obrimFilesystemTypeDelete: + payload, err := obrimFilesystemDelete(config) + if err != nil { + return nil, obrimFilesystemFailureDelete, err + } + return payload, obrimFilesystemSuccessDelete, nil + + case obrimFilesystemTypePermission: + payload, err := obrimFilesystemPermission(config) + if err != nil { + return nil, obrimFilesystemFailurePermission, err + } + return payload, obrimFilesystemSuccessPermission, nil + + default: + return nil, obrimFilesystemFailureInvalidType, fmt.Errorf("unsupported filesystem operation") + } +} + +// Builds the standardized filesystem output. +func obrimFilesystemBuildOutput(status bool, code string, payload map[string]any) map[string]any { + return map[string]any{ + "status": status, + "code": code, + "payload": payload, + } +} + +// Validates list configuration. +func obrimFilesystemValidateListConfig(config map[string]any) *obrimFilesystemValidationError { + entity := obrimFilesystemString(config, "entity") + strategy := obrimFilesystemString(config, "strategy") + sortBy := obrimFilesystemString(config, "sort_by") + sortOrder := obrimFilesystemString(config, "sort_order") + + if entity != "" && entity != obrimFilesystemEntityFile && entity != obrimFilesystemEntityDirectory { + return &obrimFilesystemValidationError{code: obrimFilesystemFailureInvalidEntity} + } + + if strategy != "" && strategy != obrimFilesystemStrategyUser && strategy != obrimFilesystemStrategyCustom { + return &obrimFilesystemValidationError{code: obrimFilesystemFailureInvalidStrategy} + } + + if sortBy != "" { + switch sortBy { + case obrimFilesystemSortName, obrimFilesystemSortSize, obrimFilesystemSortModified, obrimFilesystemSortCreated: + default: + return &obrimFilesystemValidationError{code: obrimFilesystemFailureInvalidSortBy} + } + } + + if sortOrder != "" && sortOrder != "asc" && sortOrder != "desc" { + return &obrimFilesystemValidationError{code: obrimFilesystemFailureInvalidSortOrder} + } + + if strategy == obrimFilesystemStrategyCustom && obrimFilesystemString(config, "base") == "" { + return &obrimFilesystemValidationError{code: obrimFilesystemFailureInvalidConfig} + } + + return nil +} + +// Validates check configuration. +func obrimFilesystemValidateCheckConfig(config map[string]any) *obrimFilesystemValidationError { + entity := obrimFilesystemString(config, "entity") + strategy := obrimFilesystemString(config, "strategy") + name := obrimFilesystemString(config, "name") + + if entity != obrimFilesystemEntityFile && entity != obrimFilesystemEntityDirectory { + return &obrimFilesystemValidationError{code: obrimFilesystemFailureInvalidEntity} + } + + if strategy != "" && strategy != obrimFilesystemStrategyUser && strategy != obrimFilesystemStrategyCustom { + return &obrimFilesystemValidationError{code: obrimFilesystemFailureInvalidStrategy} + } + + if name == "" { + return &obrimFilesystemValidationError{code: obrimFilesystemFailureInvalidConfig} + } + + if strategy == obrimFilesystemStrategyCustom && obrimFilesystemString(config, "base") == "" { + return &obrimFilesystemValidationError{code: obrimFilesystemFailureInvalidConfig} + } + + return nil +} + +// Validates create configuration. +func obrimFilesystemValidateCreateConfig(config map[string]any) *obrimFilesystemValidationError { + entity := obrimFilesystemString(config, "entity") + strategy := obrimFilesystemString(config, "strategy") + name := obrimFilesystemString(config, "name") + + if entity != obrimFilesystemEntityFile && entity != obrimFilesystemEntityDirectory { + return &obrimFilesystemValidationError{code: obrimFilesystemFailureInvalidEntity} + } + + if strategy != "" && strategy != obrimFilesystemStrategyUser && strategy != obrimFilesystemStrategyCustom { + return &obrimFilesystemValidationError{code: obrimFilesystemFailureInvalidStrategy} + } + + if name == "" { + return &obrimFilesystemValidationError{code: obrimFilesystemFailureInvalidConfig} + } + + if strategy == obrimFilesystemStrategyCustom && obrimFilesystemString(config, "base") == "" { + return &obrimFilesystemValidationError{code: obrimFilesystemFailureInvalidConfig} + } + + return nil +} + +// Validates delete configuration. +func obrimFilesystemValidateDeleteConfig(config map[string]any) *obrimFilesystemValidationError { + entity := obrimFilesystemString(config, "entity") + strategy := obrimFilesystemString(config, "strategy") + name := obrimFilesystemString(config, "name") + + if entity != obrimFilesystemEntityFile && entity != obrimFilesystemEntityDirectory { + return &obrimFilesystemValidationError{code: obrimFilesystemFailureInvalidEntity} + } + + if strategy != "" && strategy != obrimFilesystemStrategyUser && strategy != obrimFilesystemStrategyCustom { + return &obrimFilesystemValidationError{code: obrimFilesystemFailureInvalidStrategy} + } + + if name == "" { + return &obrimFilesystemValidationError{code: obrimFilesystemFailureInvalidConfig} + } + + if strategy == obrimFilesystemStrategyCustom && obrimFilesystemString(config, "base") == "" { + return &obrimFilesystemValidationError{code: obrimFilesystemFailureInvalidConfig} + } + + return nil +} + +// Validates permission configuration. +func obrimFilesystemValidatePermissionConfig(config map[string]any) *obrimFilesystemValidationError { + strategy := obrimFilesystemString(config, "strategy") + name := obrimFilesystemString(config, "name") + mode := obrimFilesystemString(config, "mode") + + if strategy != "" && strategy != obrimFilesystemStrategyUser && strategy != obrimFilesystemStrategyCustom { + return &obrimFilesystemValidationError{code: obrimFilesystemFailureInvalidStrategy} + } + + if name == "" { + return &obrimFilesystemValidationError{code: obrimFilesystemFailureInvalidConfig} + } + + if mode != obrimFilesystemModeRead && mode != obrimFilesystemModeWrite { + return &obrimFilesystemValidationError{code: obrimFilesystemFailureInvalidMode} + } + + if mode == obrimFilesystemModeWrite { + permission := obrimFilesystemString(config, "permission") + if _, err := strconv.ParseUint(permission, 8, 32); err != nil || len(permission) < 3 || len(permission) > 4 { + return &obrimFilesystemValidationError{code: obrimFilesystemFailureInvalidPermission} + } + } + + if strategy == obrimFilesystemStrategyCustom && obrimFilesystemString(config, "base") == "" { + return &obrimFilesystemValidationError{code: obrimFilesystemFailureInvalidConfig} + } + + return nil +} + +// Executes a filesystem listing operation. +func obrimFilesystemList(config map[string]any) (map[string]any, error) { + options := obrimFilesystemListConfig{ + Entity: obrimFilesystemString(config, "entity"), + Strategy: obrimFilesystemStringDefault(config, "strategy", obrimFilesystemStrategyUser), + Base: obrimFilesystemString(config, "base"), + Name: obrimFilesystemString(config, "name"), + Recursive: obrimFilesystemBool(config, "recursive"), + IncludeHidden: obrimFilesystemBool(config, "include_hidden"), + SortBy: obrimFilesystemStringDefault(config, "sort_by", obrimFilesystemSortName), + SortOrder: obrimFilesystemStringDefault(config, "sort_order", "asc"), + FilterPattern: obrimFilesystemString(config, "filter_pattern"), + FollowSymlink: obrimFilesystemBool(config, "follow_symlink"), + AbsolutePath: obrimFilesystemBool(config, "absolute_path"), + } + + basePath, err := obrimFilesystemResolvePath(options.Strategy, options.Base, options.Name) + if err != nil { + return nil, err + } + + entries, err := obrimFilesystemListTraverse(basePath, options) + if err != nil { + return nil, err + } + + entries = obrimFilesystemListFilter(entries, options) + obrimFilesystemListSort(entries, options.SortBy, options.SortOrder) + + return map[string]any{ + "entries": entries, + "total": len(entries), + "recursive": options.Recursive, + "base_path": basePath, + }, nil +} + +// Traverses the filesystem according to listing options. +func obrimFilesystemListTraverse(basePath string, options obrimFilesystemListConfig) ([]map[string]any, error) { + info, err := os.Lstat(basePath) + if err != nil { + return nil, err + } + + if !info.IsDir() { + return nil, fmt.Errorf("listing root is not a directory") + } + + entries := make([]map[string]any, 0) + + if !options.Recursive { + items, err := os.ReadDir(basePath) + if err != nil { + return nil, err + } + + for _, item := range items { + entry, include, err := obrimFilesystemListEntry(item, basePath, options) + if err != nil { + return nil, err + } + if include { + entries = append(entries, entry) + } + } + + return entries, nil + } + + err = filepath.Walk(basePath, func(path string, info os.FileInfo, walkErr error) error { + if walkErr != nil { + return walkErr + } + + if path == basePath { + return nil + } + + if info.Mode()&os.ModeSymlink != 0 && options.FollowSymlink { + targetInfo, targetErr := os.Stat(path) + if targetErr != nil { + return targetErr + } + info = targetInfo + } + + entry := obrimFilesystemEntryFromInfo(path, info, options.AbsolutePath) + + if entry["hidden"] == true && !options.IncludeHidden { + if info.IsDir() { + return filepath.SkipDir + } + return nil + } + + if options.Entity != "" && entry["entity"] != options.Entity { + if info.IsDir() { + return nil + } + return nil + } + + if options.FilterPattern != "" { + match, matchErr := filepath.Match(options.FilterPattern, info.Name()) + if matchErr != nil { + return matchErr + } + if !match { + return nil + } + } + + entries = append(entries, entry) + return nil + }) + + if err != nil { + return nil, err + } + + return entries, nil +} + +// Filters listing results according to entity, hidden, and pattern rules. +func obrimFilesystemListFilter(entries []map[string]any, options obrimFilesystemListConfig) []map[string]any { + filtered := make([]map[string]any, 0, len(entries)) + + for _, entry := range entries { + if !options.IncludeHidden && obrimFilesystemMapBool(entry, "hidden") { + continue + } + + if options.Entity != "" && obrimFilesystemMapString(entry, "entity") != options.Entity { + continue + } + + if options.FilterPattern != "" { + matched, err := filepath.Match(options.FilterPattern, obrimFilesystemMapString(entry, "name")) + if err != nil || !matched { + continue + } + } + + filtered = append(filtered, entry) + } + + return filtered +} + +// Sorts listing results using the requested criteria and direction. +func obrimFilesystemListSort(entries []map[string]any, sortBy string, sortOrder string) { + sort.SliceStable(entries, func(i, j int) bool { + var less bool + + switch sortBy { + case obrimFilesystemSortSize: + less = obrimFilesystemMapInt64(entries[i], "size") < obrimFilesystemMapInt64(entries[j], "size") + case obrimFilesystemSortModified: + less = obrimFilesystemMapString(entries[i], "modified") < obrimFilesystemMapString(entries[j], "modified") + case obrimFilesystemSortCreated: + less = obrimFilesystemMapString(entries[i], "created") < obrimFilesystemMapString(entries[j], "created") + default: + less = strings.ToLower(obrimFilesystemMapString(entries[i], "name")) < + strings.ToLower(obrimFilesystemMapString(entries[j], "name")) + } + + if sortOrder == "desc" { + return !less && !obrimFilesystemListSortEqual(entries[i], entries[j], sortBy) + } + + return less + }) +} + +// Determines whether two listing entries have equal sort values. +func obrimFilesystemListSortEqual(left map[string]any, right map[string]any, sortBy string) bool { + switch sortBy { + case obrimFilesystemSortSize: + return obrimFilesystemMapInt64(left, "size") == obrimFilesystemMapInt64(right, "size") + case obrimFilesystemSortModified: + return obrimFilesystemMapString(left, "modified") == obrimFilesystemMapString(right, "modified") + case obrimFilesystemSortCreated: + return obrimFilesystemMapString(left, "created") == obrimFilesystemMapString(right, "created") + default: + return strings.EqualFold( + obrimFilesystemMapString(left, "name"), + obrimFilesystemMapString(right, "name"), + ) + } +} + +// Builds a listing entry from a directory entry. +func obrimFilesystemListEntry(item os.DirEntry, basePath string, options obrimFilesystemListConfig) (map[string]any, bool, error) { + info, err := item.Info() + if err != nil { + return nil, false, err + } + + if item.Type()&os.ModeSymlink != 0 && options.FollowSymlink { + info, err = os.Stat(filepath.Join(basePath, item.Name())) + if err != nil { + return nil, false, err + } + } + + entry := obrimFilesystemEntryFromInfo(filepath.Join(basePath, item.Name()), info, options.AbsolutePath) + + if !options.IncludeHidden && obrimFilesystemMapBool(entry, "hidden") { + return entry, false, nil + } + + if options.Entity != "" && obrimFilesystemMapString(entry, "entity") != options.Entity { + return entry, false, nil + } + + if options.FilterPattern != "" { + matched, err := filepath.Match(options.FilterPattern, item.Name()) + if err != nil { + return nil, false, err + } + if !matched { + return entry, false, nil + } + } + + return entry, true, nil +} + +// Converts filesystem metadata into a standardized listing entry. +func obrimFilesystemEntryFromInfo(path string, info os.FileInfo, absolute bool) map[string]any { + resolvedPath := path + + if absolute { + if absolutePath, err := filepath.Abs(path); err == nil { + resolvedPath = absolutePath + } + } else { + if cleanPath, err := filepath.Rel(".", path); err == nil { + resolvedPath = cleanPath + } + } + + entity := obrimFilesystemEntityFile + if info.IsDir() { + entity = obrimFilesystemEntityDirectory + } + + readable := obrimFilesystemCanRead(path) + writable := obrimFilesystemCanWrite(path) + + return map[string]any{ + "path": resolvedPath, + "name": info.Name(), + "entity": entity, + "size": info.Size(), + "modified": info.ModTime().UTC().Format("2006-01-02T15:04:05Z07:00"), + "created": info.ModTime().UTC().Format("2006-01-02T15:04:05Z07:00"), + "hidden": obrimFilesystemIsHidden(info.Name()), + "readable": readable, + "writable": writable, + } +} + +// Executes a filesystem existence and accessibility check. +func obrimFilesystemCheck(config map[string]any) (map[string]any, string, error) { + options := obrimFilesystemCheckConfig{ + Entity: obrimFilesystemString(config, "entity"), + Strategy: obrimFilesystemStringDefault(config, "strategy", obrimFilesystemStrategyUser), + Base: obrimFilesystemString(config, "base"), + Name: obrimFilesystemString(config, "name"), + Readable: obrimFilesystemBool(config, "readable"), + Writable: obrimFilesystemBool(config, "writable"), + } + + path, err := obrimFilesystemResolvePath(options.Strategy, options.Base, options.Name) + if err != nil { + return nil, obrimFilesystemFailureResolvePath, err + } + + info, err := os.Lstat(path) + if os.IsNotExist(err) { + return nil, obrimFilesystemFailureEntityNotFound, err + } + if err != nil { + return nil, obrimFilesystemFailureCheck, err + } + + entity := obrimFilesystemEntityFile + if info.IsDir() { + entity = obrimFilesystemEntityDirectory + } + + if entity != options.Entity { + return nil, obrimFilesystemFailureEntityTypeMismatch, fmt.Errorf("filesystem entity type mismatch") + } + + readable := obrimFilesystemCheckRead(path) + writable := obrimFilesystemCheckWrite(path) + + if options.Readable && !readable { + return nil, obrimFilesystemFailureReadAccess, fmt.Errorf("filesystem entity is not readable") + } + + if options.Writable && !writable { + return nil, obrimFilesystemFailureWriteAccess, fmt.Errorf("filesystem entity is not writable") + } + + return map[string]any{ + "path": path, + "exists": true, + "entity": entity, + "readable": readable, + "writable": writable, + }, obrimFilesystemSuccessCheck, nil +} + +// Checks read permission without modifying the filesystem. +func obrimFilesystemCheckRead(path string) bool { + return obrimFilesystemCheckReadPath(path) +} + +// Checks write permission without modifying the filesystem. +func obrimFilesystemCheckWrite(path string) bool { + return obrimFilesystemCheckWritePath(path) +} + +// Checks whether a filesystem path can be read. +func obrimFilesystemCheckReadPath(path string) bool { + file, err := os.Open(path) + if err != nil { + return false + } + + err = file.Close() + return err == nil +} + +// Checks whether a filesystem path can be written. +func obrimFilesystemCheckWritePath(path string) bool { + info, err := os.Stat(path) + if err != nil { + return false + } + + if info.Mode().Perm()&0200 != 0 { + return true + } + + parent := filepath.Dir(path) + parentInfo, err := os.Stat(parent) + if err != nil { + return false + } + + return parentInfo.Mode().Perm()&0200 != 0 +} + +// Executes a filesystem creation operation. +func obrimFilesystemCreate(config map[string]any) (map[string]any, error) { + options := obrimFilesystemCreateConfig{ + Entity: obrimFilesystemString(config, "entity"), + Strategy: obrimFilesystemStringDefault(config, "strategy", obrimFilesystemStrategyUser), + Base: obrimFilesystemString(config, "base"), + Name: obrimFilesystemString(config, "name"), + Hidden: obrimFilesystemBool(config, "hidden"), + } + + path, err := obrimFilesystemResolvePath(options.Strategy, options.Base, options.Name) + if err != nil { + return nil, err + } + + parent := filepath.Dir(path) + if err := os.MkdirAll(parent, 0755); err != nil { + return nil, err + } + + switch options.Entity { + case obrimFilesystemEntityFile: + err = obrimFilesystemCreateFile(path) + case obrimFilesystemEntityDirectory: + err = obrimFilesystemCreateDirectory(path) + default: + return nil, fmt.Errorf("unsupported filesystem entity") + } + + if err != nil { + return nil, err + } + + return map[string]any{ + "path": path, + "entity": options.Entity, + "hidden": obrimFilesystemIsHidden(filepath.Base(path)), + "created": true, + }, nil +} + +// Creates a filesystem file. +func obrimFilesystemCreateFile(path string) error { + file, err := os.OpenFile(path, os.O_CREATE|os.O_EXCL|os.O_WRONLY, 0644) + if err != nil { + return err + } + + return file.Close() +} + +// Creates a filesystem directory. +func obrimFilesystemCreateDirectory(path string) error { + return os.Mkdir(path, 0755) +} + +// Executes a filesystem deletion operation. +func obrimFilesystemDelete(config map[string]any) (map[string]any, error) { + options := obrimFilesystemDeleteConfig{ + Entity: obrimFilesystemString(config, "entity"), + Strategy: obrimFilesystemStringDefault(config, "strategy", obrimFilesystemStrategyUser), + Base: obrimFilesystemString(config, "base"), + Name: obrimFilesystemString(config, "name"), + Recursive: obrimFilesystemBool(config, "recursive"), + } + + path, err := obrimFilesystemResolvePath(options.Strategy, options.Base, options.Name) + if err != nil { + return nil, err + } + + info, err := os.Lstat(path) + if os.IsNotExist(err) { + return nil, fmt.Errorf("filesystem entity does not exist") + } + if err != nil { + return nil, err + } + + actualEntity := obrimFilesystemEntityFile + if info.IsDir() { + actualEntity = obrimFilesystemEntityDirectory + } + + if actualEntity != options.Entity { + return nil, fmt.Errorf("filesystem entity type mismatch") + } + + switch options.Entity { + case obrimFilesystemEntityFile: + err = obrimFilesystemDeleteFile(path) + case obrimFilesystemEntityDirectory: + err = obrimFilesystemDeleteDirectory(path, options.Recursive) + default: + return nil, fmt.Errorf("unsupported filesystem entity") + } + + if err != nil { + return nil, err + } + + return map[string]any{ + "path": path, + "entity": options.Entity, + "deleted": true, + }, nil +} + +// Deletes a filesystem file. +func obrimFilesystemDeleteFile(path string) error { + return os.Remove(path) +} + +// Deletes a filesystem directory. +func obrimFilesystemDeleteDirectory(path string, recursive bool) error { + if recursive { + return os.RemoveAll(path) + } + + return os.Remove(path) +} + +// Executes a filesystem permission operation. +func obrimFilesystemPermission(config map[string]any) (map[string]any, error) { + options := obrimFilesystemPermissionConfig{ + Strategy: obrimFilesystemStringDefault(config, "strategy", obrimFilesystemStrategyUser), + Base: obrimFilesystemString(config, "base"), + Name: obrimFilesystemString(config, "name"), + Mode: obrimFilesystemString(config, "mode"), + Permission: obrimFilesystemString(config, "permission"), + } + + path, err := obrimFilesystemResolvePath(options.Strategy, options.Base, options.Name) + if err != nil { + return nil, err + } + + switch options.Mode { + case obrimFilesystemModeRead: + return obrimFilesystemPermissionRead(path) + case obrimFilesystemModeWrite: + return obrimFilesystemPermissionWrite(path, options.Permission) + default: + return nil, fmt.Errorf("unsupported permission mode") + } +} + +// Retrieves filesystem permissions. +func obrimFilesystemPermissionRead(path string) (map[string]any, error) { + info, err := os.Stat(path) + if err != nil { + return nil, err + } + + permission := fmt.Sprintf("%04o", info.Mode().Perm()) + + return map[string]any{ + "path": path, + "permission": permission, + "mode": obrimFilesystemModeRead, + "updated": false, + }, nil +} + +// Updates filesystem permissions. +func obrimFilesystemPermissionWrite(path string, permission string) (map[string]any, error) { + value, err := strconv.ParseUint(permission, 8, 32) + if err != nil || len(permission) < 3 || len(permission) > 4 { + return nil, fmt.Errorf("invalid permission specification") + } + + if err := os.Chmod(path, os.FileMode(value)); err != nil { + return nil, err + } + + info, err := os.Stat(path) + if err != nil { + return nil, err + } + + return map[string]any{ + "path": path, + "permission": fmt.Sprintf("%04o", info.Mode().Perm()), + "mode": obrimFilesystemModeWrite, + "updated": true, + }, nil +} + +// Resolves a filesystem path using the requested strategy. +func obrimFilesystemResolvePath(strategy string, base string, name string) (string, error) { + switch strategy { + case obrimFilesystemStrategyUser: + home, err := os.UserHomeDir() + if err != nil { + return "", err + } + + if name == "" { + return filepath.Clean(home), nil + } + + if filepath.IsAbs(name) { + return filepath.Clean(name), nil + } + + return filepath.Clean(filepath.Join(home, name)), nil + + case obrimFilesystemStrategyCustom: + if base == "" { + return "", fmt.Errorf("custom strategy requires base path") + } + + if name == "" { + return filepath.Clean(base), nil + } + + if filepath.IsAbs(name) { + return filepath.Clean(name), nil + } + + return filepath.Clean(filepath.Join(base, name)), nil + + default: + return "", fmt.Errorf("unsupported filesystem path strategy") + } +} + +// Determines whether a filesystem name is hidden. +func obrimFilesystemIsHidden(name string) bool { + if name == "" || name == "." || name == ".." { + return false + } + + return strings.HasPrefix(name, ".") +} + +// Determines whether a filesystem path is readable. +func obrimFilesystemCanRead(path string) bool { + return obrimFilesystemCheckReadPath(path) +} + +// Determines whether a filesystem path is writable. +func obrimFilesystemCanWrite(path string) bool { + return obrimFilesystemCheckWritePath(path) +} + +// Retrieves a string configuration value. +func obrimFilesystemString(config map[string]any, key string) string { + value, ok := config[key] + if !ok || value == nil { + return "" + } + + switch typed := value.(type) { + case string: + return typed + default: + return fmt.Sprint(typed) + } +} + +// Retrieves a string configuration value with a default. +func obrimFilesystemStringDefault(config map[string]any, key string, defaultValue string) string { + value := obrimFilesystemString(config, key) + if value == "" { + return defaultValue + } + + return value +} + +// Retrieves a boolean configuration value. +func obrimFilesystemBool(config map[string]any, key string) bool { + value, ok := config[key] + if !ok || value == nil { + return false + } + + switch typed := value.(type) { + case bool: + return typed + case string: + parsed, err := strconv.ParseBool(typed) + if err == nil { + return parsed + } + case int: + return typed != 0 + case int8: + return typed != 0 + case int16: + return typed != 0 + case int32: + return typed != 0 + case int64: + return typed != 0 + case uint: + return typed != 0 + case uint8: + return typed != 0 + case uint16: + return typed != 0 + case uint32: + return typed != 0 + case uint64: + return typed != 0 + } + + return false +} + +// Retrieves a string from a filesystem entry map. +func obrimFilesystemMapString(value map[string]any, key string) string { + item, ok := value[key] + if !ok || item == nil { + return "" + } + + if typed, ok := item.(string); ok { + return typed + } + + return fmt.Sprint(item) +} + +// Retrieves a boolean from a filesystem entry map. +func obrimFilesystemMapBool(value map[string]any, key string) bool { + item, ok := value[key] + if !ok || item == nil { + return false + } + + typed, ok := item.(bool) + return ok && typed +} + +// Retrieves an int64 from a filesystem entry map. +func obrimFilesystemMapInt64(value map[string]any, key string) int64 { + item, ok := value[key] + if !ok || item == nil { + return 0 + } + + switch typed := item.(type) { + case int64: + return typed + case int: + return int64(typed) + case int32: + return int64(typed) + case int16: + return int64(typed) + case int8: + return int64(typed) + case uint64: + return int64(typed) + case uint32: + return int64(typed) + case uint16: + return int64(typed) + case uint8: + return int64(typed) + case uint: + return int64(typed) + default: + return 0 + } +}